我在使用(可重入)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 声明了吗?我正在使用字符串和长度来打印我的令牌。