解析C ++模板参数时yacc shift / reduce冲突

时间:2013-06-14 18:03:18

标签: parsing compiler-construction bison yacc

我有一个YACC语法用于在C ++中解析表达式。这是精简版:

// yacc.y
%token IDENT

%%

expr:
    call_expr
    | expr '<' call_expr
    | expr '>' call_expr
    ;

call_expr:
    IDENT
    | '(' expr ')'
    | IDENT '<' args '>' '(' args ')'
    ;

args:
    IDENT
    | args ',' IDENT
    ;

%%

当我想支持带模板参数的函数调用时,我遇到了shift/reduce冲突。

当我们输入IDENT '<' IDENT时,yacc不知道我们是应该转移还是减少。

我希望IDENT '<' args '>' '(' args ')'的优先级高于expr '<' call_expr,因此我可以解析以下的exprs。

x < y
f<x>(a,b)
f<x,y>(a,b) < g<x,y>(c,d)

我看到C ++ / C#都支持这种语法。有没有办法用yacc解决这个问题?

如何修改.y文件?

谢谢!

1 个答案:

答案 0 :(得分:1)

您想要yacc / bison的-v选项。它将为您提供一个.output文件,其中包含有关生成的shift / reduce解析器的所有信息。用你的语法,野牛给你:

State 1 conflicts: 1 shift/reduce
      :
state 1

    4 call_expr: IDENT .
    6          | IDENT . '<' args '>' '(' args ')'

    '<'  shift, and go to state 5

    '<'       [reduce using rule 4 (call_expr)]
    $default  reduce using rule 4 (call_expr)

显示问题所在。看到IDENT后,当下一个标记为<时,它不知道是否应减少call_expr(最终匹配规则expr: expr '<' call_expr)或是否应该转移到匹配规则6。

仅使用1个令牌前瞻解析这个很难,因为你有两个不同的令牌<(小于或打开角括号),这意味着取决于后来的令牌。

这种情况实际上更糟糕,因为它是模棱两可的,像

这样的输入
a < b > ( c )

可能是一个模板调用,两个args列表都是单例,但它也可能是

( a < b ) > ( c )

所以只是解构语法也无济于事。您最好的选择是使用更强大的解析方法,例如bison的%glr-parser选项或btyacc