嗨,我刚刚开始研究lex和yacc工具。
我意识到yyerror仅从yacc接收字符串“语法错误”。 我想知道是否可以自定义此字符串。
哦,我还能区分不同类型的错误吗? (试图将丢失的令牌和其他令牌作为不同的错误。) 如果是这样,我应该如何..
非常感谢。
答案 0 :(得分:2)
您可以在yyerror
中随意打印任何想要的消息(甚至根本不打印任何消息),因此可以根据需要自定义消息。常见的自定义方法是添加触发错误的令牌的行号(可能还有列号)。当然,您可以根据需要更改文本,但是如果您只想将其更改为其他语言,则可能应该使用gettext机制。您可以在源分发的.po
子目录中找到runtime-po
个文件。如果启用了此功能,则bison会在将字符串传递给yyerror
之前安排要翻译的字符串,但是当然,如果这样更方便,您可以自己在yyerror
中进行翻译。< / p>
我怀疑您真正想要的是让野牛产生更多信息的错误消息。野牛只有一种可选的错误消息格式,其中包括“期望的”令牌列表。您可以通过添加
,要求Bison产生此类错误消息。%define parse.error verbose
在您的序言中。与the manual indicates一样,野牛解析算法有时可能会产生不正确的预期标记列表(因为它不是为特定目的而设计的);您还可以通过以下方式启用lookahead correction,以获得更精确的列表:
%define parse.lac full
这确实有轻微的性能损失。有关详细信息,请参见链接的手册部分。
此功能生成的令牌列表使用野牛文件中提供的令牌名称。这些名称通常不是很友好,因此您可能会发现自己生成错误消息,例如臭名昭著的PHP错误
syntax error, unexpected T_CONSTANT_ENCAPSED_STRING
(注意:最新的PHP版本会产生不同但同样神秘的消息。)
为避免这种情况,请为令牌定义双引号别名。这也可以使您的语法更具可读性:
%type <string> TOK_ID "identifier"
%token TOK_IF "if" TOK_ELSE "else" TOK_WHILE "while"
%token TOK_LSH "<<"
/* Etc. */
%%
stmt: expr ';'
| while
| if
| /* ... */
while: "while" '(' expr ')' stmt
expr: "identifier"
| expr "<<" expr
/* ... */
引用的名称将不会通过gettext传递。这适合作为关键字的名称,但是可能需要翻译描述性令牌别名。 this answer中概述了这样做的过程。