【问题标题】:Wrong operator precedence with HappyHappy 运算符优先级错误
【发布时间】:2014-08-14 07:32:11
【问题描述】:

在 Haskell 中探索解析库我遇到了这个项目:haskell-parser-examples。运行一些示例,我发现运算符优先级存在问题。使用 Parsec 时效果很好:

$ echo "3*2+1" | dist/build/lambda-parsec/lambda-parsec
Op Add (Op Mul (Num 3) (Num 2)) (Num 1)
Num 7

但与 Happy/Alex 不同:

$ echo "3*2+1" | dist/build/lambda-happy-alex/lambda-happy-alex
Op Mul (Num 3) (Op Add (Num 2) (Num 1))
Num 9

即使运算符的优先级看起来定义明确。摘自parser

%left '+' '-'
%left '*' '/'

%%

Exprs : Expr                             { $1 }
      | Exprs Expr                       { App $1 $2 }

Expr : Exprs                             { $1 }
     | let var '=' Expr in Expr end      { App (Abs $2 $6) $4 }
     | '\\' var '->' Expr                { Abs $2 $4 }
     | Expr op Expr                      { Op (opEnc $2) $1 $3 }
     | '(' Expr ')'                      { $2 }
     | int                               { Num $1 }

有什么提示吗? (前段时间我开了一个bug report,但没有回应)。

[使用 gch 7.6.3,alex 3.1.3,happy 1.19.4]

【问题讨论】:

  • 我认为问题在于,即使为+-*/ 定义了优先级,它们根本不会影响生成的解析器。唯一适用的规则是Expr op Expr,因此基本上所有操作都具有相同的优先级。这可以通过在Expr 中使用运算符作为标记来解决,而不是使用单独的opEnc 规则。
  • @JohnL 您应该将其发布为答案。

标签: parsing haskell operator-precedence happy


【解决方案1】:

这似乎是 haskell-parser-examples 使用令牌优先级的错误。 Happy 的运算符优先级仅影响直接使用令牌的规则。在解析器中,我们希望将优先级应用于Expr 规则,但唯一适用的规则,

| Expr op Expr { Op (opEnc $2) $1 $3 }

不使用令牌本身,而是依靠opEnc 来扩展它们。如果opEnc 内联到Expr

| Expr '*' Expr { Op Mul $1 $3 }
| Expr '+' Expr { Op Add $1 $3 }
| Expr '-' Expr { Op Sub $1 $3 }

它应该可以正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 2011-06-21
    • 2013-02-24
    • 2012-08-10
    • 2020-03-05
    相关资源
    最近更新 更多