递归FParsec表达式错误定位不直观,求语法/配置优化方法
问题:FParsec嵌套表达式错误位置不直观
我的语法包含一类表达式,特征是标识符后可选择性跟随带括号的表达式列表。但当错误发生在嵌套表达式中时,FParsec显示的语法错误位置非常不直观,嵌套层数越多,定位实际错误位置越困难。
示例解析器代码
type Node = | X | Y | Expr of Node * Node list 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
期望的直观错误提示
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. 移除不必要的attempt包裹
原代码中choice [ attempt exprWithArgs ; xOrY ]的attempt会导致解析exprWithArgs失败时直接回溯到最外层选择分支,错误位置被重置到表达式开头。去掉attempt后,解析器会在出错的嵌套位置停止,保留正确的错误定位:
exprRef.Value <- choice [ exprWithArgs ; xOrY ]
2. 为基础解析器添加明确错误提示
使用<?>操作符给x、y解析器添加提示,让错误信息更精准:
let x = skipChar 'x' .>> spaces >>% Node.X <?> "'x'" let y = skipChar 'y' .>> spaces >>% Node.Y <?> "'y'"
修改后的完整代码
type Node = | X | Y | Expr of Node * Node list let x = skipChar 'x' .>> spaces >>% Node.X <?> "'x'" let y = skipChar 'y' .>> spaces >>% Node.Y <?> "'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 // 移除attempt,避免错误回溯 exprRef.Value <- choice [ 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: 21 x(y, y, y(x, y, y(x,z)) ) ^ Expecting: 'x' or 'y'
内容的提问来源于stack exchange,提问作者bookofproofs
相关产品推荐
相关产品推荐

