【发布时间】:2014-12-24 01:17:29
【问题描述】:
我将如何解析类似的东西
f x y
进入
APPLY (APPLY f x) y
使用快乐?现在我有一条规则说
%left APP
Expr : Expr Expr %prec APP { APPLY $1 $2 }
但这会将上面的内容解析为
APPLY f (APPLY x y)
【问题讨论】:
我将如何解析类似的东西
f x y
进入
APPLY (APPLY f x) y
使用快乐?现在我有一条规则说
%left APP
Expr : Expr Expr %prec APP { APPLY $1 $2 }
但这会将上面的内容解析为
APPLY f (APPLY x y)
【问题讨论】:
接受的答案不令人满意。
解决这个问题的正确方法是:
%nonassoc VAR LPAREN -- etc...
%nonassoc APP
Expr : Expr Expr %prec APP { APPLY $1 $2 }
即:
添加一个名为APP 的幽灵优先令牌,无需设置为left 或right,因为它不相关,因此您可以保留它nonassoc 以免出错直觉很重要
像你一样用%prec APP标记你的Expr规则
最重要且经常被遗忘,您需要为所有可能作为Expr 产生式的第一个标记出现的标记赋予低于APP 的优先级,通常通过在上面的某处列出它们来实现,对于那些不相关的,可以使用left、right 或nonassoc
您的试用失败的原因可能是您错过了最后一步。
之所以需要最后一步,是因为算法在决定是移动下一个token还是减少APP规则时,会将APP规则的优先级与传入token的优先级进行比较.默认情况下,您未提及的标记具有高优先级。所以当面对:
Expr Expr . LPAREN VAR RPAREN
例如,它将比较 APP 规则的优先级(减少)和 LPAREN 的优先级(转移),除非你设置正确,否则它会转移,并做错东西。
把你的语法分阶段是丑陋和不愉快的。
【讨论】:
您可以使用语法规则对左/右关联性进行编码。
例如,看看这个基本的 lambda 演算解析器:
https://github.com/ghulette/haskell-parser-examples/blob/master/src/HappyParser.y
有效的产品是:
Expr : let VAR '=' Expr in Expr { App (Abs $2 $6) $4 }
| '\\' VAR '->' Expr { Abs $2 $4 }
| Form { $1 }
Form : Form '+' Form { Binop Add $1 $3 }
| Juxt { $1 }
Juxt : Juxt Atom { App $1 $2 }
| Atom { $1 }
Atom : '(' Expr ')' { $2 }
| NUM { Num $1 }
| VAR { Var $1 }
【讨论】: