我正在努力通过fparsec和联盟实现以下目标 (1 +(2 * 3))// DSL样本输入(递归)
type AirthmeticExpression =
| Constant of float
| AddNumber of AirthmeticExpression * AirthmeticExpression
| Mul of AirthmeticExpression * AirthmeticExpression
在fparsec中我为Add和Mul创建了createParserForwardedToRef
let parseExpression, implementation = createParserForwardedToRef<AirthmeticExpression, unit>();;
let parseAdd = between pstring"(" pstring ")" (tuple2 (parseExpression .>> pstring " + ") parseExpression) |>> AddNumber
let parseMul = between pstring"(" pstring ")" (tuple2 (parseExpression .>> pstring " * ") parseExpression) |>> Mul
implementation := parseConstant <|> parseAdd <|> parseMull
但是fparsec doc说如果解析器p1消耗输入并且失败则不会尝试p2。
在我的情况下,Add和Mul在操作符之前具有相同的模式,因此只有p1正在工作。我怎么能重构它所以我可以解析我的输入?在fparsec doc解决方案示例中,它起作用,因为它只是解析而不是构造被区分的联合实例。在我的情况下,我必须知道哪个模式匹配,以便我可以创建添加或Mul
答案 0 :(得分:1)
编辑:正如@FyodorSoikin指出的那样,我的原始评论同样有缺陷。
你在昨天的评论中走的正确,通过为运算符创建一个公共解析器,然后为使用它的操作提供单个解析器。为了使其更具功能性,您可以让运算符解析器返回要应用的union case。这样,在解析完整操作时,您可以将其称为函数。
count
原始评论:
一种可能性是在评论中使用count.ToString()
,但该功能通常应作为最后的手段使用。更好的解决方案是分解包装:
let parseExpression, implementation = createParserForwardedToRef<AirthmeticExpression, unit>();;
let parseOperator = // : Parser<AirthmeticExpression * AirthmeticExpression -> AirthmeticExpression>
(pstring " + " |>> AddNumber)
<|> (pstring " * " |>> Mul)
let parseOperation =
pipe3 parseConstant parseOperator parseConstant
(fun x op y -> op (x, y)) // Here, op is either AddNumber or Mul
|> between (pstring "(") (pstring ")")
implementation := parseConstant <|> parseOperation