Parsing 用Parsec解析非二进制运算符

Parsing 用Parsec解析非二进制运算符,parsing,haskell,parsec,Parsing,Haskell,Parsec,传统上,算术运算符被认为是二进制的(左或右关联),因此大多数工具只处理二进制运算符 有没有一种简单的方法可以用Parsec解析算术运算符,它可以有任意数量的参数 例如,应将以下表达式解析到树中 (a + b) + c + d * e + f 是的!关键是首先解决一个更简单的问题,即将+和*建模为只有两个子节点的树节点。要添加四项内容,我们只需使用+三次 这是一个需要解决的大问题,因为有一个Text.Parsec.Expr模块可以解决这个问题。您的示例实际上是可由解析的。我在这里稍微简化了一下:

传统上,算术运算符被认为是二进制的(左或右关联),因此大多数工具只处理二进制运算符

有没有一种简单的方法可以用Parsec解析算术运算符,它可以有任意数量的参数

例如,应将以下表达式解析到树中

(a + b) + c + d * e + f

是的!关键是首先解决一个更简单的问题,即将
+
*
建模为只有两个子节点的树节点。要添加四项内容,我们只需使用
+
三次

这是一个需要解决的大问题,因为有一个
Text.Parsec.Expr
模块可以解决这个问题。您的示例实际上是可由解析的。我在这里稍微简化了一下:

模块库,其中
导入文本.Parsec
导入Text.Parsec.Language
将限定的Text.Parsec.Expr导入为Expr
将限定的Text.Parsec.Token作为标记导入
数据表达式=
标识符字符串
|乘法表达式
|添加Expr Expr
实例Show Expr where
显示(标识符s)=s
显示(乘以l r)=“(*”++(显示l)++”+“++(显示r)+””
显示(添加l r)=“(+”+++(显示l)++”+“++(显示r)++””
--我们可以从Haskell解析器中剽窃一些理智的解析器组合器。
parens=代币。parens haskell
标识符=令牌。标识符haskell
reserved=Tokens.reservedOp haskell
--中缀解析器。
中缀算子func=
Expr.Infix(保留运算符>>返回函数)Expr.AssocLeft
分析器=
Expr.buildExpressionParser表术语“表达式”
哪里
表=[[infix_“*”乘法],[infix_“+”加法]]
术语=
帕伦斯解析器
(标识符)
“期限”
在GHCi中运行此命令:

λ>runParser()“(a+b)+c+d*e+f”
右(+(+(+(+(++AB)c)(*DE))f)
有很多方法可以将此树转换为所需的形式。这是一个粗俗的慢镜头:

data Expr'=
标识符的字符串
|添加“[Expr]”
|乘'[Expr']
派生(显示)
收集::Expr->(Expr->Bool)->[Expr]
收集ef |(ef==False)=[e]
收集e@(添加l r)f=
收集lf++收集rf
收集e@(乘以l r)f=
收集lf++收集rf
isAdd::Expr->Bool
isAdd(添加)=真
isAdd=错误
isMultiply::Expr->Bool
isMultiply(乘法)=真
isMultiply=假
优化::Expr->Expr'
优化(标识符)=标识符的
优化e@(添加)=添加“(地图优化(收集e isAdd))
优化e@(乘法)=乘法(映射优化(收集e为乘法))

然而,我会注意到,几乎总是
Expr
就足够了™ 出于解析器或编译器的目的。

基于该示例,我认为询问者希望
(a+b)+c
a+(b+c)
a+b+c
解析到三个不同的树。