提问人:Chechy Levas 提问时间:3/3/2022 更新时间:3/3/2022 访问量:138
如何在 FParsec 中解析 recusrive 语法
How to parse recusrive grammar in FParsec
问:
以前的问题,我无法用它来让它工作
- 似乎是一个在添加到FParsec之前被问到的老问题
createParserForwardedToRef
- AST 似乎不像我的那么可怕的递归。
- 语法依赖于特殊字符来指示另一个嵌套级别。我没有这种奢侈
'['
我想为我最近发现自己在写的语言构建一种 Lexer 和项目系统。该语言称为 q。它是一种相当简单的语言,没有运算符优先级。例如,与 相同。它的工作原理有点像反向抛光符号计算器,评估是从右到左的。1*2+3
(1*(2+3))
我在 FParsec 中表达这一点时遇到麻烦。我整理了以下简化的演示
open FParsec
type BinaryOperator = BinaryOperator of string
type Number = Number of string
type Element =
|Number of Number
and Expression =
|Element of Element
|BinaryExpression of Element * BinaryOperator * Expression
let number = regex "\d+\.?\d*" |>> Number.Number
let element = [ number ] |> choice |>> Element.Number
let binaryOperator = ["+"; "-"; "*"; "%"] |> Seq.map pstring |> choice |>> BinaryOperator
let binaryExpression expression = pipe3 element binaryOperator expression (fun l o r -> (l,o,r))
let expression =
let exprDummy, expRef = createParserForwardedToRef()
let elemExpr = element |>> Element
let binExpr = binaryExpression exprDummy |>> BinaryExpression
expRef.Value <- [binExpr; elemExpr; ] |> choice
expRef
let statement = expression.Value .>> eof
let parseString s =
printfn "Parsing input: '%s'" s
match run statement s with
| Success(result, _, _) -> printfn "Ok: %A" result
| Failure(errorMsg, _, _) -> printfn "Error: %A" errorMsg
//tests
parseString "1.23"
parseString "1+1"
parseString "1*2+3" // equivalent to (1*(2+3))
到目前为止,我还没有想出一种方法来满足所有 3 个测试用例。在上面,它首先尝试解析,意识到它不能,但随后必须消耗输入,因为它不会尝试接下来进行评估。不知道该怎么办。如何满足 3 项测试?binExpr
elemExpr
答:
3赞
Chechy Levas
3/3/2022
#1
沉思着托马斯的回答,我想出了以下可行的方法
let expr, expRef = createParserForwardedToRef()
let binRightExpr = binaryOperator .>>. expr
expRef.Value <- parse{
let! first = element
return! choice [
binRightExpr |>> (fun (o, r) -> (first, o, r) |> BinaryExpression)
preturn (first |> Element)
]
}
let statement = expRef.Value .>> eof
FParsec 文档中给出了第一个解析器失败的原因
<|> 组合器的行为有两个重要特征:
<|> 仅在左侧的解析器在左侧时尝试右侧的解析器 侧失败。它不实现最长匹配规则。 但是,仅当左解析器失败而不消耗输入时,它才会尝试右解析器。
可能需要清理一些东西,比如 AST 的结构,但我认为我很好。
评论