2017-05-27 56 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 –