You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

递归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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 03:22:39