【问题标题】:Parsing "x y z" with the precedence of multiply以乘法的优先级解析“x y z”
【发布时间】:2015-03-28 21:34:47
【问题描述】:

我正在尝试使用 FParsec 在 F# 中为 Mathematica 语言编写解析器。

我为 MiniML 编写了一个支持语法 f x y = (f(x))(y) 的函数应用程序具有高优先级。现在我需要使用相同的语法来表示f*x*y,因此,具有与乘法相同的优先级。特别是x y + 2 = x*y + 2x y ^ 2 = x * y^2

如何做到这一点?

【问题讨论】:

  • 我还没有尝试过,但我认为您可以使用OperatorPrecedenceParser 来实现这一点,方法是使您的普通空白解析器不接受标识符之间的空白并为" " 空格字符串添加一个中缀运算符如果空格后面没有标识符,则使用'after-string-parser'失败而不消耗输入。
  • 但这不会解析(x)(y) = x*y
  • 也许您可以使用 "(" 后缀运算符解析括号中的第二个术语,该运算符使用 after-string-parser 解析术语和结束括号。一种更简洁的方法,没有骇人听闻的“”和“(”运算符,会将并列的术语解析为术语序列。为了正确处理优先级,您可能需要一个单独的 OPP 实例来处理除第一个之外的序列中的所有(顶级)术语。这另一个OPP 将仅包含优先级高于乘法的运算符(并且没有前缀 +/-)。
  • 啊哈!我没有想到使用两个OPPs。我会试试看。谢谢!
  • Argh,事实证明这对我来说不太适用,因为我有一个高优先级“/”运算符和一个低优先级“/”。操作员。除非它们在同一个 OperatorPrecedenceParser 中,否则它们不会消除歧义并尝试解析“/”。失败并出现错误。

标签: f# fparsec


【解决方案1】:

正如 Stephan 在评论中指出的那样,您可以将运算符解析器拆分为两个单独的解析器,并将您自己的解析器放在中间用于空格分隔的表达式。下面的代码演示了这一点:

#I "../packages/FParsec.1.0.1/lib/net40-client"
#r "FParsec"
#r "FParsecCS"

open FParsec
open System.Numerics

type Expr =
  | Int of BigInteger
  | Add of Expr * Expr
  | Mul of Expr * Expr
  | Pow of Expr * Expr

let str s = pstring s >>. spaces
let pInt : Parser<_, unit> = many1Satisfy isDigit |>> BigInteger.Parse .>> spaces
let high = OperatorPrecedenceParser<Expr,unit,unit>()
let low = OperatorPrecedenceParser<Expr,unit,unit>()
let pHighExpr = high.ExpressionParser .>> spaces
let pLowExpr = low.ExpressionParser .>> spaces

high.TermParser <-
  choice
    [ pInt |>> Int
      between (str "(") (str ")") pLowExpr ]

low.TermParser <-
  many1 pHighExpr |>> (function [f] -> f | fs -> List.reduce (fun f g -> Mul(f, g)) fs) .>> spaces

low.AddOperator(InfixOperator("+", spaces, 10, Associativity.Left, fun f g -> Add(f, g)))
high.AddOperator(InfixOperator("^", spaces, 20, Associativity.Right, fun f g -> Pow(f, g)))

run (spaces >>. pLowExpr .>> eof) "1 2 + 3 4 ^ 5 6"

输出是:

Add (Mul (Int 1,Int 2),Mul (Mul (Int 3,Pow (Int 4,Int 5)),Int 6))

正如预期的那样代表1 * 2 + 3 * 4^5 * 6

【讨论】:

    猜你喜欢
    • 2015-09-06
    • 1970-01-01
    • 1970-01-01
    • 2016-12-28
    • 2016-12-27
    • 2013-09-16
    • 1970-01-01
    • 2014-09-25
    • 2015-07-09
    相关资源
    最近更新 更多