2013-12-20 157 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語句呢?我使用字符串和長度來打印出我的令牌。