我正在为这种形式的字符串编写一个FParsec解析器:
do[ n times]([ action] | \n([action]\n)*endDo)
Run Code Online (Sandbox Code Playgroud)
换句话说,这是一个带有可选时间量词的"do"语句,以及一个"action"语句或"action"列表(每个都在新行上),末尾有"end do"(I为简单起见省略了缩进/尾随空格处理.
这些是有效输入的示例:
do action
do 3 times action
do
endDo
do 3 times
endDo
do
action
action
endDo
do 3 times
action
action
endDo
Run Code Online (Sandbox Code Playgroud)
这看起来并不复杂,但是:
为什么这不起作用?
let statement = pstring "action"
let beginDo = pstring "do"
>>. opt (spaces1 >>. pint32 .>> spaces1 .>> pstring "times")
let inlineDo = tuple2 beginDo (spaces >>. statement |>> fun w -> [w])
let expandedDo = (tuple2 (beginDo .>> newline)
(many (statement .>> newline)))
.>> pstring "endDo"
let doExpression = (expandedDo <|> inlineDo)
Run Code Online (Sandbox Code Playgroud)
这个表达式的正确解析器是什么?
您需要使用该attempt
功能.我只是修改了beginDo
和doExpression
功能.
这是代码:
let statement o=o|> pstring "action"
let beginDo o=
attempt (pstring "do"
>>. opt (spaces1 >>. pint32 .>> spaces1 .>> pstring "times")) <|>
(pstring "do" >>% None) <|o
let inlineDo o= tuple2 beginDo (spaces >>. statement |>> fun w -> [w]) <|o
let expandedDo o= (tuple2 (beginDo .>> newline) (many (statement .>> newline)))
.>> pstring "endDo" <|o
let doExpression o= ((attempt expandedDo) <|> inlineDo) .>> eof <|o
Run Code Online (Sandbox Code Playgroud)
我eof
在最后加了一个.这样,它将更容易测试.
我还添加了虚拟o
参数以避免值限制.