Parsing 解决yacc/ocamlyacc中的reduce/reduce冲突

Parsing 解决yacc/ocamlyacc中的reduce/reduce冲突,parsing,ocaml,grammar,yacc,Parsing,Ocaml,Grammar,Yacc,我试图在ocamlyacc中解析一个语法(与常规的yacc几乎相同),它支持没有运算符的函数应用程序(如Ocaml或Haskell),以及二进制和一元运算符的正常组合。我得到了一个与“-”操作符的reduce/reduce冲突,它可以用于减法和求反。下面是我使用的语法示例: %token <int> INT %token <string> ID %token MINUS %start expr %type <expr> expr %nonassoc INT

我试图在ocamlyacc中解析一个语法(与常规的yacc几乎相同),它支持没有运算符的函数应用程序(如Ocaml或Haskell),以及二进制和一元运算符的正常组合。我得到了一个与“-”操作符的reduce/reduce冲突,它可以用于减法和求反。下面是我使用的语法示例:

%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) };
%token INT
%令牌ID
%代币负号
%启动表达式
%类型表达式
%非对称整数ID
%左减
%左应用
%%
表达式:INT
{ExprInt$1}
|身份证
{ExprId$1}
|expr减去expr
{ExprSub($1,$3)}
|负表达式
{解释$2}
|expr expr%prec应用
{ExprApply($1,$2)};

问题是,当您得到一个像“a-b”这样的表达式时,解析器不知道应该将其缩减为“a(-b)”(b的求反,后跟application)还是“a-b”(减法)。减法是正确的。如何解决冲突以支持该规则?

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

  • expr
    拆分为
    simple\u expr
    expr\u加前缀
  • 在应用程序中仅允许
    简单表达式
    (带前缀的表达式)
  • 第一步将reduce/reduce冲突转换为shift/reduce冲突,但括号解决了这一问题

    “abc”也会有同样的问题:是
    a(b(c))
    还是
    (a(b))(c)
    ?您还需要在语法中断开
    应用的表达式
    和required
    (应用的表达式)

    我想这样可以,但我不确定:

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

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

    左apply/
    %prec apply
    解决了
    a-b-c
    的歧义——它的左关联性(因此它的(a-b)c)和比其他任何东西都低的优先级。问题在于,优先规则对于表现为reduce/reduce冲突的歧义不起作用。