解决第二次前瞻的野牛冲突

时间:2015-06-04 11:44:06

标签: bison

我正在为一个项目编写一个解析器并且遇到了问题。以下是该问题的自包含示例:

%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 ...我怎样才能在野牛身上解决这个问题?

2 个答案:

答案 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的操作中,您可以确定它是常规的,常量的还是直接的,或者如果它同时包含CONSTANTAT VALUE则会发出错误。这样做的好处是,您可以为后一种情况提供自定义的明确错误消息,而不仅仅是一般的“语法错误”消息。