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

时间:2017-01-21 22:47:50

标签: c parsing 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)

1 个答案:

答案 0 :(得分:0)

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

term: new_expr
comparison: term '<' term

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

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

if new Foo < oldFoo then...

myFoo = new Foo<int>(42)

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

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

new用作任何运算符的左参数时,我会选择强制括号,因为它对读者来说不那么容易混淆。它还简化了语法,这是一件好事,因为语法不仅仅用于解析;它们是语言文档的重要组成部分,不必要的复杂语法使语言难以学习和理解。

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