如何用FParsec解析左递归语法规则?数组访问场景求解
解决FParsec中数组访问的左递归与嵌套/连续访问问题
核心思路:用表达式层级消解左递归
你的问题本质是数组访问的直接左递归(Expr → Expr .[ Expr ]),LL文法不直接支持这种结构,但可以将其转换为基础表达式 + 可选重复后缀的等价结构,同时确保后缀里的索引部分是完整表达式(而非受限子集),就能同时解决嵌套访问和连续访问的问题。
具体实现步骤
拆分表达式层级:
- 定义
primaryExpr:最基础的表达式单元,包含带点限定的标识符、整数、括号包裹的表达式、方括号形式的函数调用。 - 定义
postfixExpr:以primaryExpr为起点,允许重复追加数组访问后缀。 - 最终
expr直接指向postfixExpr,连续数组访问(如my2DArray.[x].[y])会被解析为((my2DArray.[x]).[y]),符合语义逻辑。
- 定义
修正索引表达式的解析:
之前的限制源于将索引部分的表达式限定为不含数组访问的子集,现在让索引里的indexExpr直接复用完整的expr,即可支持嵌套的数组访问(如a.[b.[c]])。
示例代码片段
open FParsec type Expr = | Ident of string | ArrayAccess of Expr * Expr | Call of Expr * Expr list | Int of int let ws = spaces let str s = pstring s >>. ws let expr, exprRef = createParserForwardedToRef<Expr, unit>() // 基础表达式:标识符(含点限定)、整数、括号表达式、函数调用 let primaryExpr = choice [ // 带点的标识符,如std.fold many1Satisfy2L isLetter (fun c -> isLetter c || isDigit c || c = '.') "identifier" |>> Ident >>. ws pint32 |>> Int >>. ws // 括号包裹的表达式 str "(" >>. expr .>> str ")" // 函数调用:expr[arg1, arg2, ...] expr .>> str "[" .>>. sepBy expr (str ",") .>> str "]" |>> (fun (f, args) -> Call(f, args)) ] // 后缀表达式:基础表达式 + 任意次数的数组访问后缀 let postfixExpr = primaryExpr .>>. many ( str "." >>. str "[" >>. expr .>> str "]" |>> (fun index -> index) ) |>> fun (baseExpr, suffixes) -> // 把所有后缀依次应用到基础表达式上 suffixes |> List.fold (fun acc idx -> ArrayAccess(acc, idx)) baseExpr // 把最终表达式指向postfixExpr do exprRef := postfixExpr // 测试解析 let test str = match run expr str with | Success(result, _, _) -> printfn "Success: %A" result | Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg // 测试用例 test "my2DArray.[x].[y]" // 连续数组访问 test "std.fold[fn, f[myArray.[0]], std.tail[myArray]]" // 嵌套数组访问+函数调用 test "a.[b.[c.[5]]]" // 多层嵌套数组访问
关键说明
- 消解左递归:通过
primaryExpr + many 后缀的结构,将左递归的Expr → Expr .[Expr]转换为LL文法可处理的右递归+循环形式,完全保留原有语义。 - 支持嵌套访问:索引部分直接使用完整的
expr,括号内可以包含任何合法表达式,包括其他数组访问。 - 支持连续访问:
many操作符会收集所有后续的数组访问后缀,再通过List.fold依次组合成嵌套的ArrayAccess节点,实现连续访问的解析。
关于文法修改的问题
这是对原有左递归文法的等价转换,并未改变文法的表达能力——只是将LL解析器不支持的左递归形式,调整为适配LL规则的写法,不算修改文法的核心语义。
内容的提问来源于stack exchange,提问作者Foxy
相关产品推荐
相关产品推荐

