2016-10-19 15 views
0

在嘗試重新創建由縮進定義的Python塊時,我在開始時偶然發現了這個問題。處理Flex啓動條件時Bison分析器上的標記錯誤

當我單獨嘗試我的詞法分析器/掃描儀時,它會返回我預期的結果,正確使用我所做的開始條件。但是,當它與Bison解析器耦合時,正確的狀態不會保留,並且我從意外狀態接收到令牌。

對於我來說,預期的行爲是返回一行開始處的製表符/空格的「INDENT」標記,並在找到另一個符號(而不是製表符/空格)後爲每個符號返回「OTHER」標記,直到開始新隊。

第一種情況,詞法分析器歸國預期結果

scanner.l

%{ 
    #include <iostream> 
%} 

%option noyywrap 

%x INDENT 
%% 

    BEGIN(INDENT); 

<INDENT>[ \t] { std::cout << "INDENT "; } 
<INDENT>.|\n { yyless(0); BEGIN(INITIAL); } 

\n { std::cout << std::endl; BEGIN(INDENT); } 
. { std::cout << "OTHER "; } 

%% 

int main(){ 
    yylex(); 
    return 0; 
} 

進入 「   測試   」(兩個空格之前和 「測試」)之後返回「INDENT INDENT OTHER OTHER OTHER OTHER OTHER OTHER OTHER「。

第二種情況下,解析器返回意想不到的結果

scanner.l

%{ 
    #include <iostream> 

    #include "parser.h" 
%} 

%option noyywrap 

%x INDENT 
%% 

    BEGIN(INDENT); 

<INDENT>[ \t] { return T_INDENT; } 
<INDENT>.|\n { yyless(0); BEGIN(INITIAL); } 

\n { BEGIN(INDENT); return T_NEWLINE; } 
. { return T_OTHER; } 

%% 

parser.y

%{ 
    #include <iostream> 

    extern int yylex(); 

    void yyerror(const char *s); 
%} 

%define parse.error verbose 

%token T_INDENT T_OTHER T_NEWLINE 

%% 

program : program symbol 
     | %empty 
     ; 

symbol : T_INDENT { std::cout << "INDENT "; } 
     | T_NEWLINE { std::cout << std::endl; } 
     | T_OTHER { std::cout << "OTHER "; } 
     ; 

%% 

void yyerror(const char *s){ 
    std::cout << s; 
} 

int main(){ 
    yyparse(); 
    return 0; 
} 

進入「   測試   「(與以前相同)返回」INDENT INDENT OTHER OTHER OTHER OTHER INDENT INDENT「。雖然預期的結果與上述相同。

Bison解析器似乎收到錯誤的標記,就好像它不遵守開始條件。我已經閱讀了一些關於解析器由於前瞻行爲而搞亂了開始條件的問題,但我不確定問題出在這個範圍之內,也不知道我會如何解決它。

+0

這是一個非常奇怪的方式來做到這一點。我會''[\ t] BEGIN INDENT;',而不是從那個狀態開始。 – EJP

回答

0

因爲你有

BEGIN(INDENT) 

在規則部分沒有模式,這是逐字複製到函數yylex函數的頂部,所以它運行的每個函數yylex被調用時。所以每當野牛叫yylex得到一個新的令牌時,狀態就會重置爲INDENT,你會得到T_INDENT令牌。

在你的「第一種情況」的例子中,詞法分析器不會返回到EOF,所以你只能調用它一次,它只設置INDENT狀態一次。

如果您希望此代碼僅在您第一次調用yylex時運行,則需要將其設置爲只運行一次。例如:

 { static bool not_first_time; 
      if (!not_first_time) { 
      BEGIN(INDENT); 
      not_first_time = true; } } 

或者,設置事件以便INITIAL是預期的初始狀態。

+0

謝謝,就是這樣:)我完全忽略了這個細節 –