2013-12-20 111 views
5

我有一个问题,使用(可重入)Flex +柠檬解析。我使用简单的语法和词法分析器here。当我运行它时,我会输入一个数字后跟一个EOF标记(Ctrl-D)。打印输出结果将改为:柠檬分析器解析0令牌

89 

found int of . 
AST=0. 

其中第一行是我放的数量从理论上讲,AST值应该是一切,我把总和

编辑:。当我打电话解析( )手动它运行正确。

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

回答

5

好的,我想通了。原因是Flex和柠檬之间存在一个特别令人讨厌的(并且记录不完善)的交互。

为了节省内存,柠檬将保持一个令牌而不复制,并将其推送到内部令牌堆栈。但是,flex还会尝试通过更改yyget_text指向的值来节省内存,因为它会使输入变混淆。在我的例子中的违规行为:

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

这应该是:

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

,这将确保值柠檬点时,它降低了令牌堆栈后是一样的,你原来是什么(注意:不要忘记,strdup意味着你将不得不在稍后的某个时间释放内存,柠檬会让你编写可以做到这一点的令牌“析构函数”,或者如果你正在构建AST树,你应该等到AST生命周期结束。)

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语句呢?我使用字符串和长度来打印出我的令牌。