所以我正在实现C编译器的子集,有一个特性让我头疼。所以我想要一些如何解决它的想法。
在我的节目中。语言是由值传递的所有参数,包括字符串,其声明如下:
string str;
我的问题是,正如你所看到的,我不知道字符串在声明过程中的大小(与C不同),所以当我生成程序集时,我不清楚在堆栈上为它创建多大的空间。如果我有这样的代码:
string str;
int number;
str = something;
我不知道如何为字符串str分配正确的空间,因为以后可以实际分配。最后一个条件是,我不能使用堆。
谢谢,很抱歉我英语不好。
编辑:
谢谢你的回答。在我看来,从回应来看,如果字符串在堆栈上变得更大,最大的问题将是重新分配字符串,以防这个字符串后面已经有东西了,我认为最简单的解决方案是在堆栈上创建新的空间,旧的空间一直保留,直到本地作用域被处理。。。这将是浪费,是的
我假设您有某种dup_string
例程,它在新的内存块中复制字符串。这个dup例程必须知道源字符串有一个未知的长度,只有在执行复制时才能确定,比如:
char *dup_string (char *s)
{
char *d = realloc(strlen(s)+1);
memcpy (d, s, strlen(s)+1);
return d;
}
因此,您可以通过在调用方代码和被调用方epilog中使用它来透明地使用此函数,如下所示。。。
/* Source code: your programming language */
str s;
s = "whatever...";
func (s);
生成的汇编代码如下(例如使用IA32代码和C调用约定):
[Caller: this block repeated for every string passed as parameter to a function]
push offset s
call dup_string ;string copy pointed by EAX
add esp,4 ;get rid of parameter
push eax
call func
add esp,4 ;get rid of parameter
...
...
[Callee]
push ebp
mov ebp,esp
mov esi,[ebp+8] ; ESI = pointer to string
...use string in ESI...
...
...
EPILOG
(this block repeated for every string passed as argument):
mov esi,[ebp+8] ;8 because in this example, it's the first argument.
call free /* standard free() function */
mov esp,ebp
ret
您可以从零长度的字符串开始。
由于您事先不知道大小,一旦执行分配,或者字符串被连接、重新分配、离开作用域等时,您将不得不在运行时动态分配和解除分配字符串存储。
由于它是您自己的语言,我假设您也可以控制代码的生成方式。因此,您可以分配足够的堆栈空间并将字符串复制到那里。我在自己的函数中使用了这样一种方法,它附加了两个未知长度的路径部分(basepath和filename作为参数),因为我不想使用malloc和free。你唯一需要注意的是堆栈的对齐,因为它必须保持均匀。
当然,这取决于你的程序有多大,因为对于足够复杂的程序,堆栈可能很快就会变大。