在尝试添加可选规则时,切换/减少Bison中的冲突

我正试图解决Bison中的转移/减少冲突。 我有遵循语法规则

new_expr: T_NEW class_name_reference optional_generics_list ctor_arguments { $$ = zend_ast_create(ZEND_AST_NEW, $2, $4, $3); } | T_NEW anonymous_class { $$ = $2; } optional_generics_list: /* empty */ { $$ = NULL; } | generics_list { $$ = $1; } ctor_arguments: /* empty */ { $$ = zend_ast_create_list(0, ZEND_AST_ARG_LIST); } | argument_list { $$ = $1; } 

这里的问题在于,optional_generics_list和ctor_arguments都可以为空。 我如何指定(如果可以的话)如果optional_generics_list和ctor_arguments都为空,则ctor_arguments应具有更高的优先级。 或许我的问题不正确,如何解决这个冲突。

一些更新的信息:生成的.output文件的输出可能会有所帮助:

  State 156 conflicts: 1 shift/reduce State 156: 303 new_expr: "new (T_NEW)" class_name_reference . optional_generics_list ctor_arguments '<' shift, and go to state 304 '<' [reduce using rule 168 (optional_generics_list)] $default reduce using rule 168 (optional_generics_list) optional_generics_list go to state 305 generics_list go to state 306 State 305 303 new_expr: "new (T_NEW)" class_name_reference optional_generics_list . ctor_arguments '(' shift, and go to state 229 $default reduce using rule 405 (ctor_arguments) argument_list go to state 546 ctor_arguments go to state 552 State 306 169 optional_generics_list: generics_list . $default reduce using rule 169 (optional_generics_list) 

bison输出文件指出的问题是new_expr可能后跟一个<不属于generics_list< 。 例如,如果语法也包含如下产品,那就是这种情况:

 term: new_expr comparison: term '<' term 

(当然,人们会期望真正的语法有更多的可能性,但那些是必不可少的。)

换句话说,如果您的语法允许您比较两个新构造的对象,那么解析器无法判断它看到的<generics_list的开头,还是new_expr之后的简单比较运算符,其中generics_listctor_arguments已被省略:

 if new Foo < oldFoo then... myFoo = new Foo(42) 

最简单的解决方法是坚持将new_expr括在括号中,如果它将在表达式中使用。

对于它的价值,C ++通过知道名称是否是模板化来处理这个问题。 如果名称可以采用模板参数,则<名称后面的<解释为启动模板参数列表; 否则它是一个小于运营商。 因此,如果v是模板化的,那么你必须写(new v) < ... ,但如果v只是一个简单的类型名,你可以省略括号: new int < ... 实施这很棘手; 您需要某种词汇反馈,并且需要对可以放置模板声明的位置施加一些限制。 C ++具有一些其他独特的解析挑战,具有相似的分辨率。 例如, new int * i是一个错误,因为*被解析为指针类型修饰符,使用的规则表明new表达式中的类型是可解析为类型的最长令牌序列。

new被用作任何运算符的左参数时,我会选择强制括号,因为它不会让读者感到困惑。 它还简化了语法,这是一件好事,因为语法不仅仅用于解析; 它们是语言文档的重要组成部分,不必要的复杂语法使语言不必要地学习和理解。

有趣的是,在编写上述关于C ++的注释的过程中,我发现了一个主要C ++编译器的解析器中的一个错误。 (至少,我想我知道哪个编译器是错误的;更准确的说我发现两个流行的编译器具有不一致的行为,因此其中一个必定是错误的。)一个更简单的规则对任何一个都没有影响非人为的程序,并且会使错误的可能性大大降低(并且更容易validation)。 因此,对于我来说,在表达式中间允许无表达式new操作的附加值并不是很清楚。