解析在函数参数中没有参数的函数调用 - FParsec

Parsing the calling of a function without an argument in the parameters of a function - FParsec

我正在尝试使用 FParsec 通过单子解析器组合来实现分析器。我也用了一个缩进模块,不过对于目前的问题来说并不重要

所以我正在尝试解析我的小 AST 的这个分支:

type Identifier = string

type Expression =
    ...
    | Call of Identifier * Expression list
    ...
type Program = Program of Expression list

我有这个实现:

// Identifier parser
let private identifier =
    many1Satisfy2L isLetter
        (fun c -> isLetter c || isDigit c) "identifier"

// Monadic parser
let call = parse {
        let! id = identifier
        let! parameters = sepBy parameter spaces1
        return Call(id, parameters)
    }

and expression =
    ... // <|>
    attempt call // <|>
    ...

parameter表示函数调用中所有可接受的表达式作为参数:

// All possible parameter
let parameter =
    attempt pint32 <|> // A number, for example.
    attempt (identifier |>> fun callid -> Call(callid, [])) <|>
    attempt (between (pstring "(") (pstring ")") call)

如您所见,有两个使用 "C/call" 的解析器元素。它们对应于此,顺序和例如:

add x 1  // Call the function `add` and passing it another call (`x`) and the simple literal `1`
add (add 8 2) 10 // Call the function `add` and passing it another call (`add 8 2`) and the simple literal `10`

当然,这些元素也可以交织在一起:

add (add x 1) 7

这个问题,我显然无法解决,否则我不会问这个问题,就是生成的树看起来不像预期的那样:

add x 1 给出:

Success: Program [Call ("add",[Call ("x",[]); Literal (Int 1)])]

换句话说,解析器似乎将以下 x 识别为 x.

的参数

但是,第二种方法可行。 add (add 8 2) 10 给出:

Success: Program
  [Call
     ("add",[Call ("add",[Literal (Int 8); Literal (Int 2)]); Literal (Int 10)])]

你能让我走上正轨吗?

对我来说,下面这行似乎匹配 x:

attempt (identifier |>> fun callid -> Call(callid, [])) <|>

单个标识符被视为 call

因此您得到:[Call ("add",[Call ("x",[]); Literal (Int 1)])

也就不足为奇了

正如您认为这是错误的,您的预期结果是什么?我原以为这是一个标识符取消引用表达式。

还有一个提示,您似乎选择了像这样调用函数的 OCaml 样式:f x y

也许您还应该采用 OCaml 风格,即函数始终采用单个参数和 returns 单个值。

add x 1 然后会被解析为: Apply (Apply (Identifier "add", Identifier "x"), Literal 1)