10

我正在尝试解析 ocamlyacc 中的语法(与常规 yacc 几乎相同),它支持没有运算符的函数应用程序(如在 Ocaml 或 Haskell 中),以及二进制和一元运算符的正常分类。我遇到了与“-”运算符的减少/减少冲突,该运算符可用于减法和求反。这是我正在使用的语法示例:

%token <int> INT
%token <string> ID
%token MINUS

%start expr
%type <expr> expr

%nonassoc INT ID
%left MINUS
%left APPLY

%%

expr: INT
    { ExprInt $1 }
| ID
    { ExprId $1 }
| expr MINUS expr
    { ExprSub($1, $3) }
| MINUS expr
    { ExprNeg $2 }
| expr expr %prec APPLY
    { ExprApply($1, $2) };

问题是当你得到一个像“a - b”这样的表达式时,解析器不知道它是否应该被简化为“a(-b)”(b的否定,然后是应用程序)或“a - b”(减法)。减法减法是正确的。我如何解决冲突以支持该规则?

4

2 回答 2

8

不幸的是,我能想出的唯一答案是增加语法的复杂性。

  1. 分为和expr_simple_exprexpr_with_prefix
  2. 仅允许simple_expr(expr_with_prefix)在 APPLY

第一步将您的 reduce/reduce 冲突转变为 shift/reduce 冲突,但括号解决了这个问题。

'ab c' 你会遇到同样的问题:是它a(b(c))还是(a(b))(c)?您还需要在语法中中断applied_expression和要求。(applied_expression)

我认为这会做到,但我不确定:

expr := INT
      | parenthesized_expr
      | expr MINUS expr

parenthesized_expr := ( expr )
                    | ( applied_expr )
                    | ( expr_with_prefix )

applied_expr := expr expr

expr_with_prefix := MINUS expr
于 2008-08-23T20:49:00.047 回答
0

好吧,这个最简单的答案就是忽略它,让默认的 reduce/reduce 解决方案处理它——减少语法中首先出现的规则。在这种情况下,这意味着减少expr MINUS expr对 的偏好MINUS expr,这正是您想要的。看到后a-b,您想将其解析为二进制减号,而不是一元减号然后再应用。

于 2011-10-06T18:06:54.203 回答