5

我在使用(可重入)Flex + Lemon 进行解析时遇到问题。我在这里使用了一个简单的语法和词法分析器。当我运行它时,我会输入一个数字,后跟一个 EOF 标记 (Ctrl-D)。打印输出将显示:

89

found int of .
AST=0.

第一行是我输入的数字。理论上,AST 值应该是我输入的所有内容的总和。

编辑:当我手动调用 Parse() 时,它运行正确。

atom ::= INT此外,即使标记为 0(停止标记),柠檬似乎也会运行规则。为什么是这样?我对这种行为感到非常困惑,我找不到任何好的文档。

4

2 回答 2

5

好吧,我想通了。原因是 flex 和 lemon 之间发生了特别讨厌的(并且记录不充分)的交互。

为了节省内存,柠檬将保留一个令牌而不复制,并将其推送到内部令牌堆栈。然而,flex 也试图通过改变yyget_text它在对输入进行词法分析时指向的值来节省内存。我的示例中的违规行是:

// in the do loop of main.c...
Parse(parser, token, yyget_text(lexer));

这应该是:

Parse(parser, token, strdup(yyget_text(lexer)));

这将确保柠檬在稍后减少令牌堆栈时指向的值与您最初传入的值相同。

(注意:不要忘记,strdup这意味着您必须在稍后的某个时间释放该内存。Lemon 会让您编写可以执行此操作的令牌“析构函数”,或者如果您正在构建 AST 树,您应该等到AST 生命周期结束。)

于 2013-12-21T00:07:39.547 回答
0

您也可以尝试创建一个包含指向字符串的指针和字符串长度的标记类型。我在这方面取得了成功。

令牌.h

#ifndef Token_h
#define Token_h

typedef struct Token {
  int code;
  char * string;
  int string_length;
} Token;

#endif // Token_h

主程序

int main(int argc, char** argv) {
    // Set up the scanner
    yyscan_t scanner;
    yylex_init(&scanner);
    yyset_in(stdin, scanner);

    // Set up the parser
    void* parser = ParseAlloc(malloc);

    // Do it!
    Token t;
    do {
        t.code = yylex(scanner);
        t.string = yyget_text(scanner);
        t.string_length = yyget_leng(scanner);
        Parse(parser, t.code, t);
    } while (t.code > 0);

    if (-1 == t.code) {
        fprintf(stderr, "The scanner encountered an error.\n");
    }

    // Cleanup the scanner and parser
    yylex_destroy(scanner);
    ParseFree(parser, free);
    return 0;
}

语言.y(摘录)

class_interface   ::= INTERFACE IDENTIFIER(A) class_inheritance END.
{
    printf("defined class %.*s\n", A.string_length, A.string);
}

看到我的 printf 声明了吗?我正在使用字符串和长度来打印我的令牌。

于 2014-10-17T02:34:31.117 回答