【问题标题】:Pass a string value in a recursive bison rule在递归野牛规则中传递字符串值
【发布时间】:2013-08-31 20:01:39
【问题描述】:

我在野牛上遇到了一些问题(再次)。 我正在尝试使用 $$ 在我的语法文件中的“递归规则”之间传递一个字符串值, 但是当我打印我传递的值时,输出看起来像是一个错误的引用 (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,因为我已经通过 $$ 传递了它),我没有正确的输出。

【问题讨论】:

    标签: recursion token grammar bison flex-lexer


    【解决方案1】:

    你不能设置:

    $$ = out;
    

    因为out 所指的字符串即将在其声明的块结束时消失得无影无踪。

    为了避免这种情况,您需要malloc 新字符串的存储空间。

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

    了解 C 语言实际上没有字符串是很重要的。它有指向char (char*) 的指针,但这些确实是指针。它有数组 (char []),但不能将数组用作聚合。例如,在您的代码中,out = $1 将是非法的,因为您不能分配给数组。 (也因为$1 是一个指针,而不是一个数组,但这并不重要,因为任何对数组的引用,除了sizeof,实际上都被简化为一个指针。)

    所以当你说$$ = out 时,你是在让$$ 指向out 所代表的存储空间,而那个存储空间即将消失。所以这行不通。你可以说$$ = $1,因为$1也是一个指向char的指针;这使得$$$1 指向同一个字符。 (这是合法的,但它使内存管理更加复杂。此外,您需要小心修改。)最后,您可以说strcpy($$, out),但这依赖于$$ 已经指向一个足够长的字符串持有out,这是极不可能的事情,因为这意味着将out指向的存储复制到$$指向的位置。

    此外,正如我上面提到的,当您在 C 中使用“字符串”函数时,它们都坚持必须终止由它们的“字符串”参数(即指向字符的参数)指向的字符序列带有0 字符(即代码为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完成它;否则,你有内存泄漏。

    【讨论】:

    • 我不明白你回答的重点。变量 out 很明显会消失,这就是为什么我将它存储到 $$ 中,它是在非终端(或递归)野牛规则之间存储数据的默认变量。这样我就可以在下一条规则中使用输出值(存储在 $$ 中)。
    • @Simone:out 实际上是指向存储在堆栈中的 char 数组的指针。所以$$ = out 使$$ 指向堆栈上的数据。恐怕这就是 C 的工作方式。
    • 那么为什么如果我将$$ = out 更改为$$ = $1(其中$1 是一个字符串),我在规则的递归部分输出了由$1 表示的正确字符串?
    【解决方案2】:

    我已经解决了它,将$$ = out; 行更改为strcpy($$,out);,现在它可以正常工作了。

    【讨论】:

    • 这几乎可以肯定是未定义的行为。我会稍微修改一下我的答案。 (但您需要更好地了解如何在 C 中使用字符串。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多