この質問は、まず、私の質問と重複していません。実は3つ質問があります。
以下のコードでは、入れ子になっている可能性のある複数行のブロック コメントを解析するパーサーを作成しようとしています。引用された他の質問とは対照的に、再帰関数を使用せずに簡単な方法で問題を解決しようとします(他の投稿への受け入れられた回答を参照してください)。
私が遭遇した最初の問題は、FParsec の skipManyTill パーサーもストリームから end パーサーを消費することでした。そこで、skipManyTillEx (「endp を除く」の Ex ;) ) を作成しました。skipManyTillEx は機能しているようです-少なくとも、fsxスクリプトにも追加した1つのテストケースでは。
しかし、示されているコードでは、「消費せずに成功するパーサーにコンビネーター 'many' が適用されました...」というエラーが表示されます。私の理論は、commentContent
パーサーがこのエラーを生成する行であるということです。
ここで、私の質問:
- 私が選択したアプローチが機能しない理由はありますか? 1のソリューションは、残念ながら私のシステムではコンパイルできないようで、(ネストされた) 複数行のコメントに対して再帰的な低レベルのパーサーを使用します。
- 私が実装した方法に問題がある人はいます
skipManyTillEx
か?skipManyTill
私がそれを実装した方法は、主に解析フローを制御する方法の面で、実装されている方法とはある程度異なります。元skipManyTill
の では、Reply<_>
p および endp の が とともに追跡され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 */"