【发布时间】:2014-06-03 17:36:31
【问题描述】:
This question,首先,不是我的问题的重复。 其实我有 3 个问题。
在下面的代码中,我尝试创建一个解析器来解析可能嵌套的多行块 cmets。与引用的其他问题相比,我尝试以直接的方式解决问题,而不使用任何递归函数(请参阅其他帖子的已接受答案)。
我遇到的第一个问题是 FParsec 的 skipManyTill 解析器也使用流中的结束解析器。所以我创建了skipManyTillEx(Ex for ' exclude endp' ;))。 skipManyTillEx 似乎工作 - 至少对于我也添加到 fsx 脚本的一个测试用例。
然而,在代码中,如图所示,现在我得到“组合子'many'被应用到一个成功但不消耗...的解析器”错误。我的理论是,commentContent 解析器是产生此错误的行。
在这里,我的问题:
- 有什么原因,为什么我选择的方法不起作用? 1 中的解决方案,不幸的是,它似乎无法在我的系统上编译,它为(嵌套的)多行 cmets 使用递归低级解析器。
- 谁能看出我实现
skipManyTillEx的方式有问题?我实现它的方式与skipManyTill的实现方式有些不同,主要是在如何控制解析流方面。在原始skipManyTill中,p 和endp 的Reply<_>与stream.StateTag一起被跟踪。在我的实现中,相比之下我没有看到需要使用stream.StateTag,只依赖Reply<_>状态码。如果解析不成功,skipManyTillEx会回溯到流初始状态并报告错误。回溯代码可能会导致“许多”错误吗?我应该怎么做? - (这是主要问题) - 有没有人看到,如何修复解析器,这样“许多...”错误消息消失了?
代码如下:
#r @"C:\hgprojects\fparsec\Build\VS11\bin\Debug\FParsecCS.dll"
#r @"C:\hgprojects\fparsec\Build\VS11\bin\Debug\FParsec.dll"
open FParsec
let testParser p input =
match run p input with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> printfn "Failure %s" errorMsg
input
let Show (s : string) : string =
printfn "%s" s
s
let test p i =
i |> Show |> testParser p |> ignore
////////////////////////////////////////////////////////////////////////////////////////////////
let skipManyTillEx (p : Parser<_,_>) (endp : Parser<_,_>) : Parser<unit,unit> =
fun stream ->
let tryParse (p : Parser<_,_>) (stm : CharStream<unit>) : bool =
let spre = stm.State
let reply = p stream
match reply.Status with
| ReplyStatus.Ok ->
stream.BacktrackTo spre
true
| _ ->
stream.BacktrackTo spre
false
let initialState = stream.State
let mutable preply = preturn () stream
let mutable looping = true
while (not (tryParse endp stream)) && looping do
preply <- p stream
match preply.Status with
| ReplyStatus.Ok -> ()
| _ -> looping <- false
match preply.Status with
| ReplyStatus.Ok -> preply
| _ ->
let myReply = Reply(Error, mergeErrors preply.Error (messageError "skipManyTillEx failed") )
stream.BacktrackTo initialState
myReply
let ublockComment, ublockCommentImpl = createParserForwardedToRef()
let bcopenTag = "/*"
let bccloseTag = "*/"
let pbcopen = pstring bcopenTag
let pbcclose = pstring bccloseTag
let ignoreCommentContent : Parser<unit,unit> = skipManyTillEx (skipAnyChar) (choice [pbcopen; pbcclose] |>> fun x -> ())
let ignoreSubComment : Parser<unit,unit> = ublockComment
let commentContent : Parser<unit,unit> = skipMany (choice [ignoreCommentContent; ignoreSubComment])
do ublockCommentImpl := between (pbcopen) (pbcclose) (commentContent) |>> fun c -> ()
do test (skipManyTillEx (pchar 'a' |>> fun c -> ()) (pchar 'b') >>. (restOfLine true)) "aaaabcccc"
// do test ublockComment "/**/"
//do test ublockComment "/* This is a comment \n With multiple lines. */"
do test ublockComment "/* Bla bla bla /* nested bla bla */ more outer bla bla */"
【问题讨论】:
标签: parsing f# comments multiline fparsec