Compiler construction 编译器:字符串常量与动态分配的字符串对象

Compiler construction 编译器:字符串常量与动态分配的字符串对象,compiler-construction,Compiler Construction,我正在编写一个小型编译器,在处理字符串常量和字符串对象时遇到困难 以以下代码为例: s : String = "Hello world" 由于字符串在程序中,编译器将识别该字符串,并将生成一个字符串常量并将其放置在.data段中 然后,可以通过以下方式访问实际字符串: leaq string_const1(%rip), %rax addq $32, %rax 但是,如果我们要求用户输入字符串,则需要动态生成字符串对象。下面是字符串对象模板,它也位于.data段中 然后以后要访问实际字符串,我

我正在编写一个小型编译器,在处理字符串常量和字符串对象时遇到困难

以以下代码为例:

s : String = "Hello world"
由于字符串在程序中,编译器将识别该字符串,并将生成一个字符串常量并将其放置在.data段中

然后,可以通过以下方式访问实际字符串:

leaq string_const1(%rip), %rax
addq $32, %rax
但是,如果我们要求用户输入字符串,则需要动态生成字符串对象。下面是字符串对象模板,它也位于.data段中

然后以后要访问实际字符串,我必须使用

32(%rax)  # read from memory
因此,从字符串常量访问字符串和动态分配的字符串对象之间存在差异,这需要在所有函数中使用不同的句柄

显然,我可以在protoObject中添加另一个标记,以指示这是一个已分配的对象而不是常量,但这需要所有接收字符串object/constant的方法进行检查,这听起来一点也不优雅


有谁能给我一些建议,告诉我如何处理好这种情况吗?

就我个人而言,我首先要让常量看起来像字符串对象,这意味着第五个单词将包含指向第六个单词的指针。这显然是你愿意为字符串对象付出的代价

<> P>一个更有效的空间策略是大多数现代C++库使用的,其中有两个字符串布局:一个包含一个字符向量短字符串,另一个带有指针。您可以将它们与长度区分开来,这样就不需要使用不同的标记,但当然也可以使用不同的标记


实际上,大多数字符串都比较短,因此这种优化被认为是有用的。但这需要做更多的工作,需要编写更多的测试,因此您可能希望将其保存以备将来使用。

是您的字符串对象吗​ 不可变?@rici不,不是。我首先复制字符串protoObject,然后将字符串内容移动到偏移量32处,这是最后一个字段。在这种情况下,您将需要某种方法来区分常量和字符串对象,因为常量是不可变的,您不能允许它们发生变异。除非你的编译器接受了这个命令,否则给他们足够的绳子来吊死自己,并警告他们不要使用它。让常量看起来像一个字符串对象,这是非常有趣的。您是否介意在x86-64中详细说明此功能的实现细节?我怎样才能使第五个字段的指针指向第六个字段?@jackddd:你知道地址是什么,不是吗?它是字符串_const1的固定偏移量。老实说,我真的不明白字符串常量大小的值是6,应该是5,我想我可能是搞错了。因此,我可以单独定义字符串内容。比如string_content1.string Hello world。然后在第五个字段的string_constr1中,使用.asciz hello world代替.quad string_content1。你认为这是对的吗?@jackddd:是的,似乎很合理。
String_protoObj:
    .quad    2                        # tag              
    .quad    5                        # size
    .quad    String_dispatch_table    
    .quad    0                        # string length
    .quad    0                        # string content

# assume %rax contains the address of a copy of String_protoObj
# assume %rdi contains the address of user input string 

leaq String_protoObj(%rip), %rdi
callq malloc
movq user-input, %rdi
movq %rdi, 32(%rax)   # copy the new string into string content
32(%rax)  # read from memory