Yacc库
每个实现都需要有用的例程库,在UNIX系统中,可以通过cc命令行尾端给出-ly标志(或通过其他系统下的等价物)来包含库。
库的内容在不同的实现之间是不同的,但总是包括main()和yyerror()
main()
yacc的所有版本都带有最小的主程序,该程序对于简短程序和测试有时是很有用的,它非常简单,如下所示:
main(argc,argv)
{
yyparse();
return 0;
}
和具有任何库例程一样,可以提供自己的main()。在几乎所有有用的应用软件中都可以提供main()用来接受命令参数和标志、打开文件和检查错误。
yyerror()
所有版本也都提供简单的错误报告例程,它也是非常简单:
yyerror(char *errmsg)
{
printf("%s\n",errmsg);
}
这有时能够满足要求,但是一个好的错误报告例程至少能报告行号和最近的标记(如果词法分析程序是用lex写的,那么会在yytext中),这将会对语法分析程序更有用。
YYABORT
特殊语句
YYABORT
在动作中使得语法分析例程yyparse()以一个非零值立即返回,显示失败。
当动作例程探测到错误非常严重以致于没有继续分析的点时是很有用的。
由于语法分析程序可以向前查看一个标记,所以在语法分析程序读到另一个标记前,包括YYABORT的规则动作尅不被归约。
YYACCEPT
特殊语句
YYACCEPT
在动作中使得语法分析例程yyparse()以一个零值立即返回,显示成功。
在词法分析程序不能告知输入数据何时结束而语法分析程序能告知的情况下是很有用的。
由于语法分析程序可以向前查看一个标记,所以在语法分析程序读到另一个标记前,包括YYACCEPT的规则动作尅不被归约。
YYBACKUP
宏YYBACKUP使得你可以移出当前记号并把它替换为另一个记号,该语法为:
sym: TOKEN {YYBACKUP(newtok,newval);}
它放弃已经被归约的符号sym,并且假装词法分析器刚刚读到记号newtok,其值为newval。如果此时存在一个向前查看的记号或者该规则在右部的符号超过一个的话,这个规则将通过调用yyerror()来宣告失败。
正确使用YYBACKUP非常困难,一般不用。
YYDEBUG
由于跟踪代码又大又慢,所以不能自动编译到目标程序中。为了包含跟踪代码,使用yacc命令行上的-t标志,或者要么在C编译程序命令行上,或者通过在定义段包含类似下面的句式,来定义C预处理程序符号YYDEBUG为非零值:
%{
#define YYDEBUG 1
%}
YYERROR
有时动作代码能探测到上下文相关的而语法分析程序本身却不能检测到的语法错误。如果代码检测到一个语法错误,就可以调用宏YYERROR,生成的效果与语法分析程序读到一个被语法禁止的标记时完全一样。一调用YYERROR,语法分析程序就访问yyerror(),进入错误恢复模式,寻找可以移进error标记的状态。
yyerror()
只要yacc语法分析程序探测到语法错误就调用yyerror()函数,将错误报告给用户。传递单个参数即描述这个错误的字符串,yacc库中的yyerror的默认版本仅仅是在标准输出文件中打印参数。
下面是返回更多信息的版本:
yyerror(const char *msg)
{
printf("%d: %s at '%s' \n",yylineno,msg,yytext);
}
yylineno是当前行号,yytext是包含当前标记的lex标记缓冲器。
yyparse()
yacc生成的语法分析程序的入口点是yyparse(),当程序调用yyparse()时,语法分析程序就试图分析输入流。如果分析成功,语法分析程序就返回一个零值,反之,则返回一个非零值。
每次调用该函数,语法分析程序就重新开始进行分析,而忘记上次返回的状态,这与lex扫描程序十分不同,它能够获得调用后的每一次状态。