C - 柠檬解析器解析 0 令牌



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

89
found int of .
AST=0.

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

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

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

好吧,我想通了。原因是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)));

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

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

还可以尝试创建一个令牌类型,其中包含指向字符串的指针字符串的长度。我在这方面取得了成功。

令牌.h

#ifndef Token_h
#define Token_h
typedef struct Token {
    int code;
    char * string;
    int string_length;
} Token;
#endif // Token_h

主.c

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;
}

语言(节选)

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

语言.l(节选)

...
%option reentrant
...
%%
...
%%
...

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

相关内容

  • 没有找到相关文章

最新更新