提问人:bookofproofs 提问时间:10/10/2023 更新时间:10/10/2023 访问量:56
递归 FParsec 表达式中的错误位置
Error position in recursive FParsec expressions
问:
我的语法包含以标识符为特征的表达式,该标识符仅可选地后跟带括号的表达式列表。
我的问题是,当错误发生在嵌套表达式中时,Fparsec 将在语法错误上显示“不直观”的位置。
例如,请考虑这个简单的解析器
let x = skipChar 'x' .>> spaces >>% Node.X
let y = skipChar 'y' .>> spaces >>% Node.Y
let c = skipChar ',' .>> spaces
let left = pchar '(' .>> spaces
let right = pchar ')' .>> spaces
let expr, exprRef = createParserForwardedToRef()
let paramList, paramListRef = createParserForwardedToRef()
let paramTuple = left >>. paramList .>> right
let xOrY = choice [x ; y]
let exprWithArgs = xOrY .>>. paramTuple |>> Node.Expr
exprRef.Value <- choice [ attempt exprWithArgs ; xOrY ]
paramListRef.Value <- sepBy1 expr c
let parser = expr .>> eof
let result = run parser "x(y, y, y(x, y, y(x,y)) )"
printf "\nParsing correct:\n%O" result
let resultWithError = run parser "x(y, y, y(x, y, y(x,z)) )"
printf "\n\nParsing error:\n%O" resultWithError
程序的输出为:
Parsing correct:
Success: Expr (X, [Y; Y; Expr (Y, [X; Y; Expr (Y, [X; Y])])])
Parsing error:
Failure:
Error in Ln: 1 Col: 2
x(y, y, y(x, y, y(x,z)) )
^
Expecting: end of input
我拥有的嵌套表达式越多,就越难找到实际的错误位置。
有没有办法改变我的语法(或使用/配置)FParsec,以便更好地发现错误?我希望,我会得到这样的直观错误消息:
Parsing correct:
Success: Expr (X, [Y; Y; Expr (Y, [X; Y; Expr (Y, [X; Y])])])
Parsing error:
Failure:
Error in Ln: 1 Col: 21
x(y, y, y(x, y, y(x,z)) )
^
Expecting: 'x' or 'y'
答:
1赞
Brian Berns
10/10/2023
#1
让我们以输入为例。问题出现在 / 解析器中。首先,它尝试解析 ,由于 .解析器回溯(因为 ),并尝试改为解析,这在 .但是下一个 char 不是 ,所以在该位置失败,并显示无用的消息。"y(x,z)"
expr
exprRef
exprWithArgs
z
attempt
xOrY
y
(
eof
parser
由于从解析开始,我们可以将其分解出来,从而得出以下解决方案:exprWithArgs
xOrY
exprRef.Value <-
parse {
let! xy = xOrY
match! opt paramTuple with
| Some args -> return Node.Expr (xy, args)
| None -> return xy
}
这样做的优点是不回溯,因此解析器始终向前移动,直到无法继续,从而产生更清晰的错误消息。请注意,不再使用。exprWithArgs
如果你不喜欢计算构建器,你可以改为这样做:
exprRef.Value <-
pipe2
xOrY
(opt paramTuple)
(fun xy argsOpt ->
match argsOpt with
| Some args -> Node.Expr (xy, args)
| None -> xy)
现在的输出是:
Parsing correct:
Success: Expr (X, [Y; Y; Expr (Y, [X; Y; Expr (Y, [X; Y])])])
Parsing error:
Failure:
Error in Ln: 1 Col: 21
x(y, y, y(x, y, y(x,z)) )
^
Expecting: 'x' or 'y'
可能还有更简单的解决方案,但我认为这符合您的要求。
评论
1赞
bookofproofs
10/10/2023
这是一个很好的解决方案,谢谢。经过一番试验后,如果您愿意将类型 Node.Expr 更改为 Node *(节点列表)选项,则简单的 exprRef.Value <- xOrY .>>。opt paramTuple |>> Node.Expr 也可以解决问题。它也比我的原始版本快了大约 15%。我猜是因为现在,解析器不需要做任何回溯。
评论