4

私はこの形式の文字列用のFParsecパーサーを書いています:

do[ n times]([ action] | \n([action]\n)*endDo)

言い換えると、これはオプションの時間数量詞を含む「do」ステートメントであり、単一の「action」ステートメントまたは最後に「enddo」を含む「action」のリスト(それぞれ新しい行)のいずれかです(I簡単にするためにインデント/末尾のスペースの処理を省略しました)。

有効な入力の例は次のとおりです。

do action

do 3 times action

do
endDo

do 3 times
endDo

do
action
action
endDo

do 3 times
action
action
endDo

これはそれほど複雑には見えませんが、次のようになります。

なぜこれが機能しないのですか?

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)

この式の正しいパーサーは何ですか?

4

1 に答える 1

6

関数を使用する必要がありattemptます。あなたbeginDodoExpression関数を変更しました。

これはコードです:

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

最後にを追加しeofました。このようにすると、テストが簡単になります。

値の制限を回避するために、ダミーoパラメータも追加しました。

于 2011-12-16T14:52:54.353 に答える