2011-12-16 10 views
3

と、必要に応じて、複数行の式を解析:これはオプションのタイム数量詞との声明を「行う」である他の言葉で私はこのフォームで文字列をFParsecパーサを書いてFParsec

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

、および最後に "end do"が付いた単一の "action"文か "action"のリスト(それぞれが新しい行にある)のいずれかを指定します(簡単にするためにインデント/

これらは、有効な入力の例です:

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) 

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

答えて

5

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も追加しました。

+0

作品!だから基本的に私は2つの '試行'を欠いていた?私はまだ彼らがなぜ必要なのか理解できません。 –

+0

はい、最初のパーサー(p1 <|> p2式内)に障害が発生し、入力が消費された場合、バックトラックする方法が必要なためです。それは基本的に試行関数がするものです。 – Gustavo

+0

よろしくお願いします。しかし、いつ試みても<|>をいつ使うことができますか? <|> bを行うたびに、bを選ぶために失敗しなければなりませんか? –

関連する問題