2013-08-28 37 views
0

我在野牛(再次)上遇到了一些问题。 我试图在我的语法文件中使用$$, 传递一个“递归规则”之间的字符串值,但是当我打印传递的值时,输出看起来像是一个错误的引用(AU ),而不是我在输入文件中写入的值。在递归野牛规则中传递字符串值

line: tok1 tok2 
    | tok1 tok2 tok3 
    { 
     int len=0; 
    len = strlen($1) + strlen($3) + 3; 
    char out[len]; 
    strcpy(out,$1); 
    strcat(out," = "); 
     strcat(out,$3); 
     printf("out -> %s;\n",out); 
    $$ = out; 
    } 
    | line tok4 
    { 
     printf("line -> %s\n",$1); 
    } 

这里我已经报道了代码的简化部分。 在输入令牌tok1 tok2 tok3时,它应该为$$ out变量赋值(使用printf我可以看到在规则的第一部分out变量具有正确的值)。 顺序匹配tok4我在规则的递归部分。但是,当我打印$ 1的值(应该等于out,因为我已经通过$ $$),我没有正确的输出。

回答

2

你不能设置:

$$ = out; 

因为out指字符串就是要尽快成为泡影,因为在其被宣布结束块。

为了摆脱这种情况,您需要为malloc存储新字符串。

此外,您需要strlen($1) + strlen($3) + 4;,因为您需要为NUL终止符留出空间。

重要的是要明白,C没有真正的字符串。它有指向charchar*),但这些都是真正的指针。它有数组(char []),但不能将数组用作聚合。例如,在您的代码中,out = $1将是非法的,因为您无法分配给数组。 (也因为$1是一个指针,而不是一个数组,但这并不重要,因为任何引用到一个数组,除了在sizeof,有效地降低到指针。)

所以,当你说$$ = out,你这是$$指向由out表示的存储,并且该存储即将消失。所以这是行不通的。你可以说$$ = $1,因为$1也是一个指向char的指针;这使得$$$1指向相同的字符。 (这是合法的,但这会使内存管理变得更加复杂,并且需要小心修改。)最后,您可以说strcpy($$, out),但依赖于$$已指向字符串,该字符串足够长以容纳out,这是不太可能的,因为它意味着将out指向的存储复制到$$指向的位置。如上所述,当你在C中使用“字符串”函数时,他们都坚持认为它们的“字符串”参数指向的字符序列(即指向字符的参数)必须是以0字符(即,其代码为0的字符,而不是字符)终止。

如果你习惯用实际上有字符串数据类型的语言进行编程,所有这些看起来有点奇怪。实践使得完美。

底线是,你需要做的是创建存储大到足以容纳你的字符串的一个新的区域,像这样(我删除out,因为它不是必需的):

$$ = malloc(len + 1); // room for NUL 
strcpy($$, $1); 
strcat($$, " = "); 
strcat($$, $3); 
// You could replace the strcpy/strcat/strcat with: 
// sprintf($$, "%s = %s", $1, $3) 

注意在解析器堆栈中存储mallocd数据(包括strdupasprintf的结果)(也就是$$)也意味着当你完成它时需要free;否则,你有内存泄漏。

+0

我不明白你的答案。变量out很难消失,这就是为什么我将它存储到$ $$这个默认变量来存储非终端(或递归)野牛规则之间的数据。通过这种方式,我可以在下一条规则中使用out值(存储在$$中)。 –

+0

@Simone:out实际上是一个指向堆栈中存储的char数组的指针。因此'$$ = out'使'$$'指向堆栈上的数据。恐怕,这就是C的工作方式。 – rici

+0

那么为什么如果我将'$$ = out'换成'$$ = $ 1'(其中$ 1是一个字符串),我在输出中在规则的递归部分中输出了$ 1表示的正确字符串? –

0

我已经解决了它改变$$ = out;行到strcpy($$,out);现在它工作正常。

+0

这几乎可以肯定是未定义的行为。我会编辑我的答案。 (但你需要更好地理解如何在C中使用字符串。) – rici

+0

感谢您的编辑。现在我明白你的观点了! –