关于lex与yacc生成parser的错误信息提示

发表于:2007-05-26来源:作者:点击数: 标签:
以前在学校的时候弄过lex和yacc,当时抱着完成作业的心态,对于一些问题也没好好研究过。最近忙里偷闲,又玩了一把,对于如何产生parser错误信息算是有了一些了解。 用的是freebsd5.3自带的lex以及yacc,一般情况下生成的parser在遇到错误是只能报出一句简单
以前在学校的时候弄过lex和yaclearcase/" target="_blank" >cc,当时抱着完成作业的心态,对于一些问题也没好好研究过。最近忙里偷闲,又玩了一把,对于如何产生parser错误信息算是有了一些了解。

用的是freebsd5.3自带的lex以及yacc,一般情况下生成的parser在遇到错误是只能报出一句简单的“syntax error”,对于错误的位置、期待的token等均没有提示。

事实上从lex可以获得行号的信息,只要在lex源文件的头上加上,
%option yylineno
即可。

而对于yacc输出的一些处理即可以实现简单的错误信息提示。方法是修改yyerror这个函数,下面是我修改后的一个例子,
void yyerror(char* s, int state){
     fprintf(stderr, "%s\n", s);    
     if(state != -1){
         fprintf(stderr, "line %d: ", yylineno);
         fprintf(stderr, "%s expected ", yyerrmtx[state]);
         fprintf(stderr, "before \"%s\"\n", yytext);
     }//if       
}
这里通过extern int yylineno得到当前的行号;另一方面,用一个自定义的yyerrmtx字符串数组存放各个状态值下的期待的token,同时从通过extern char* yytext从lex引入当前实际输入的token。这样就可以形成一个简单的错误提示,形如,
line 3: VARIABLE expected before LEFTBRACE

这里的关键是如何得到yyerrmtx这张表。当然可以手工输入,但是有个方法可自动生成。执行yacc的时候加上-d参数可以得到一个名为y.output的文件,其内容是对parser的各个状态、所作shift或reduce动作的一个文本说明。那么就可以写一段脚本(我是用perl写的)从这个文件中取出各个状态下期待的token的信息,从而得到yyerrmtx。

此外,关于出错位置,lex只能通过yylineno提供行号(据说有很大开销),而列号即行内的字符位置是不能直接提供的,网上有一些对应的方法,不过我没有试过。


原文转自:http://www.ltesting.net

评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)