我在使用(可重入)Flex + Lemon进行解析时遇到问题。我正在使用简单的语法和词法分析器here。当我运行它时,我会输入一个数字后跟一个EOF标记(Ctrl-D)。打印输出将显示为:
89
found int of .
AST=0.
第一行是我输入的数字。从理论上讲,AST值应该是我输入的所有内容的总和。
编辑:当我手动调用Parse()时,它正确运行。
此外,即使令牌为0(停止令牌),柠檬似乎也会运行atom ::= INT
规则。为什么是这样?我对这种行为非常困惑,我找不到任何好的文档。
答案 0 :(得分:5)
好的,我明白了。原因是在flex和lemon之间存在一种特别令人讨厌(并且文档记录很少)的交互。
为了节省内存,lemon会保留一个令牌而不复制,然后将其推送到内部令牌堆栈。但是,flex还会尝试通过更改yyget_text
指向的值来节省内存,因为它会使输入变为lexes。我的例子中的违规行是:
// in the do loop of main.c...
Parse(parser, token, yyget_text(lexer));
这应该是:
Parse(parser, token, strdup(yyget_text(lexer)));
这将确保柠檬在以后减少令牌堆栈时指向的值与您最初传入的值相同。
(注意:不要忘记,strdup
意味着你必须在某个时候释放那个记忆。柠檬会让你写出可以做到这一点的令牌“破坏者”,或者如果你正在建造AST树,你应该等到AST生命周期结束。)
答案 1 :(得分:0)
您也可以尝试创建一个包含指向字符串和字符串长度的指针的标记类型。我已经成功了。
token.h
#ifndef Token_h
#define Token_h
typedef struct Token {
int code;
char * string;
int string_length;
} Token;
#endif // Token_h
的main.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;
}
language.y(摘录)
class_interface ::= INTERFACE IDENTIFIER(A) class_inheritance END.
{
printf("defined class %.*s\n", A.string_length, A.string);
}
请看我的printf声明吗?我正在使用字符串和长度来打印我的令牌。