2017-05-27 35 views
0

我創建了一個野牛/ flex編譯器,並且遇到了問題。我加了%glr-parser但問題依然存在。我有:野牛意想不到的標記

有一個簡單的例子,它代表我的問題

.Y文件:

%{ 
    #include <stdio.h> 
    #include <stdlib.h> 
    extern FILE *yyin; 
    extern int yylex(); 
    int line=1; 
    int error=0; 
    #define YYERROR_VERBOSE 

    void yyerror(const char *msg) 
    { 
     error = 1; 
     printf("ERROR in line %d : %s.\n", line, msg); 
    } 
%} 

%start programme 
%token SP 
%token CRLF 
%token LETTER 
%% 

programme : id CRLF; 

id : LETTER; 

%% 

int main(int argc, char *argv[]) 
{ 
    if(argc == 2) yyin = fopen(argv[1], "r"); 
    else if(argc < 2){ 
     printf("No file found.\n"); 
     return 0; 
    } else printf("Only one file is permitted.\n"); 

    yyparse(); 
    if(error == 0) printf("Finished at %d line.\nNo errors!\n",line); 
    return 0; 
} 

.L文件

%{ 
     #include <stdio.h> 
     #include <string.h> 
     #include <stdlib.h> 
     #include "myParser.h" 
     extern int line; 
    %} 

    %% 

    "\n" {line++; return CRLF;} 

    " " {return SP;} 

    [a-zA-Z] {return LETTER;} 

%% 

.h文件中

enum yytokentype { 
    SP = 259, 
LETTER = 260, 
CRLF = 261 
} 

我的程序得到一個。 txt文件:

file_correct.txt包含:A 在我的終端,我寫的:

bison -d bison.y 
flex myParser.l 
gcc bison.tab.c lex.yy.c -lfl -o a 
./a file_correct.txt 

- >在第1行錯誤:語法錯誤,意想不到的$不確定的,期待的信。

輸入A\n應該是正確的。相反,我有這個信息。你能幫我嗎?

+0

您沒有顯示'rest_dec',這似乎是相關的。 (野牛報告解析衝突嗎?爲什麼添加'%glr-parser'?如果沒有衝突,GLR解析器不會改變任何東西。) – rici

+0

您也不會顯示您的flex描述,儘管您錯誤地標記了問題[tag:flex](flex scanner生成器的正確標籤是[tag:flex-lexer];我修正了它)。當然,錯誤可能在您的掃描儀中。您是否確認了正確的令牌被掃描? – rici

+0

對不起,我編輯了我的帖子:) 有2個移位/減少衝突,但我還在%gls-parser中添加了%expect 2,並沒有發生任何事情。我相信它會讀取正確的令牌......我爲示例創建了一個手寫分析樹(例如int A;),並且它看起來正確。我不知道...這是我第一次這樣做.. –

回答

2

您必須使用由bison生成的頭文件。你可以把它寫入你自己的頭文件中(儘管這沒什麼實際價值),但是你不能試圖自己寫它,並希望它永遠是正確的。

在這種情況下,myparser.h包含

enum yytokentype { 
    SP = 259, 
    LETTER = 260, 
    CRLF = 261 
}; 

,而這些都是tokentype號這yylex將在Flex的文件返回,因爲你#include <myParser.h>

但是,文件bison.tab.h,野牛生成(和在bison.tab.c包括文本方式)具有不同的值:

enum yytokentype 
    { 
    SP = 258, 
    CRLF = 259, 
    LETTER = 260 
    }; 

碰巧,LETTER具有兩個文件中的相同的代碼,但其他兩個代碼不同。特別是,掃描儀將返回261時,看到一個換行符,但是解析器將有望同類型號259的令牌當它接收到261,它抱怨:

ERROR in line 2 : syntax error, unexpected $undefined, expecting CRLF. 

(野牛,代碼261個沒有按因爲它報告爲$undefined。)

這是與您在問題中報告的錯誤消息不同的錯誤消息,這可能是由不同命令中不同的野牛版本編號令牌造成的,也可能是隻是一個複製和粘貼問題。

底線是,你應該始終把

#include "bison.tab.h" 

到您的.l文件(改名爲適合您的項目,但總是用野牛生成的文件),而不是(或除了到)你自己的頭文件。 (如果你還插入自己的頭文件,當然不應該試圖定義標記值。包含您自己的頭文件的原因是爲您自己的外部函數聲明原型,這些函數正在被掃描程序操作使用。)

總的來說,很少有空白(空格和換行符)被傳遞給解析器。 (例外的情況是語句中的語句必須由換行符而不是以分號結束,例如,即使這樣,您也不希望將空格傳遞給解析器。)在解析器中處理空白可以創建更多工作比必要;混淆語法;並可能導致不必要的減少衝突。

考慮簡化的語法產生:

decl: type SP id SEMICOLON 

,將匹配int a;,符合市場預期。但是,這不符合任何以下內容:

int a; 
int a ; 
    int a; 

上述所有的有可能在有效的方案,以展現出來,所以對空白的pickiness將被視爲您的用戶的一個問題。 (並且使語法更靈活的將是一個真正的痛苦。)

此外,你可能會認爲將在更大範圍內的:

program: %empty 
     | program decl CRLF 

但現在解析器將拒絕空行,再煩你用戶。它也會拒絕

int a; int b; 

這可能會讓一些人想知道爲什麼需要分號。

,並留意以下錯誤,改編自編輯歷史:

prog: stmt 
stmt: decl more 
more: %empty | stmt CRLF more 

這可能永遠不會成功的解析程序,因爲所有的程序文本以換行符結束,但語法只允許換行陳述之間的。因此,文件末尾的換行符會導致語法錯誤,因爲解析器拼命嘗試查找另一個語句。 (上面的代碼片段最初是根據錯誤的理解寫的,即消除左遞歸是一個好主意,至少如果你使用的是LR解析器,比如野牛,Bison喜歡左遞歸,在遞歸遞歸遞歸時,許多語法也更具可讀性。)

+0

非常感謝你!你的文章真的很有用!!!!! = D = D –