解析在函数参数中没有参数的函数调用 - 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)
我正在尝试使用 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)