我正在为一个项目编写一个解析器并且遇到了问题。以下是该问题的自包含示例:
%error-verbose
%token ID
%token VAR
%token END_VAR
%token CONSTANT
%token AT
%token VALUE
%%
unit: regular_var_decl
| direct_var_decl;
regular_var_decl: VAR constant_opt ID ':' VALUE ';' END_VAR;
constant_opt: /* empty */ | CONSTANT;
direct_var_decl: VAR ID AT VALUE ':' VALUE ';' END_VAR;
%%
#include <stdlib.h>
#include <stdio.h>
yylex() {
static int i = 0;
static int tokens[] = {
VAR,
ID, ':', VALUE, ';',
END_VAR,
0
};
return tokens[i++];
};
yyerror(str) char *str; {
printf("fail: %s\n", str);
};
main() {
yyparse();
return 0;
};
可以构建它bison test.y && cc test.tab.c && ./a.out
。
它警告我constant_opt
因冲突而无用。
这种歧义可以通过使用LALR(2)来解决,因为在ID
之后它可以找到':'或AT
...我怎样才能在野牛身上解决这个问题?
答案 0 :(得分:1)
一个简单的解决方案是不缩写可选的CONSTANT:
regular_var_decl: VAR ID ':' VALUE ';' END_VAR;
constant_var_decl: VAR CONSTANT ID ':' VALUE ';' END_VAR;
direct_var_decl: VAR ID AT VALUE ':' VALUE ';' END_VAR;
这允许推迟减少决定,直到知道足够的信息。 (如果有用,可以将':' VALUE ';' END_VAR
计入非终端因素。)
另一种可能性是保留语法,并要求bison生成GLR解析器(%glr-parser
)。 GLR解析器将有效地保留两个(或更多)并行解析,直到可以解决歧义,这肯定会解决constant_opt
问题。 (请注意,bison仍会报告转换/减少冲突;在运行时发现含糊不清的句子之前,它无法判断语言是否真的含糊不清。)大多数情况下,语法不需要进行其他更改,但是它确实减慢了解析速度。
最终的可能性,可能在这里不太有用,是接受语言的超集然后在动作中发出错误消息:
var_decl: VAR const_opt ID at_value_opt ':' VALUE ';' END_VAR {
if (/* pseudocode */ $2 && $4) { /* flag a syntax error */ }
}
这取决于两个opt
终端返回一个语义值,可以以某种方式查询为空。
答案 1 :(得分:1)
另一个解决方案是进一步考虑它:
var_decl: VAR constant_opt ID direct_opt ':' VALUE ';' END_VAR;
constant_opt: /* empty */ | CONSTANT;
direct_opt: /* empty */ | AT VALUE;
然后在您对var_decl
的操作中,您可以确定它是常规的,常量的还是直接的,或者如果它同时包含CONSTANT
和AT VALUE
则会发出错误。这样做的好处是,您可以为后一种情况提供自定义的明确错误消息,而不仅仅是一般的“语法错误”消息。