3

私は、次のような (非常に) 単純な言語のパーサーを作成しようとしています。

block{you are a cow too blkA{ but maybe not} and so is he} hear me moo blockZ{moooooo}

正規表現を使用して分解できます。

.*?[^ ]*?\\{
.*?\\}

これは、ブロックの開始または終了に[^ ]*?\\{一致するものが見つかるまで、基本的に文字を食べ続け ます。\\}私の質問は、Scala のパーサー コンビネーターを使用してそれを行いたい場合、どうすればよいですか? 私は現在持っています:

   def expr: Parser[Any] = (block | text)+
   def text = ".+?".r
   def block = "[^ ]*?\\{".r ~ expr ~ "}"

しかし、これは機能しません:

parsed: List(b, l, o, c, k, {, y, o, u, a, r, e, a, c, o, w, t, o, o, b, l, k, A, {, b, u, t, m, a, y, b, e, n, o, t, }, a, n, d, s, o, i, s, h, e, }, h, e, a, r, m, e, m, o, o)

blockパーサーが起動していないようで、textパーサーが繰り返し起動されています。しかし、textパーサーを削除すると:

   def expr: Parser[Any] = (block)+

私は得る:

failure: string matching regex `[^ ]*?\{' expected but `y' found

block{you are a cow too blkA{ but maybe not} and so is he} hear me moo  
      ^

したがって、パーサーが存在する場合を除いて、明らかにblockパーサーtext機能します。何が起こっていますか?とても基本的な文法のために、これを行う「適切な」方法はありますか?

編集: タイトルを変更しました。これは、問題を解決するだけでなく、気が進まないためです。

編集:私は今これを持っています:

def expr: Parser[Any] = (block | text)+

def text = "[^\\}]".r

def block = "[^ ]*?\\{".r ~ expr ~ "}"

この背後にあるロジックは、文字ごとに、それがブロックの開始であるかどうかをテストすることです。そうでない場合は、次の文字に移動します。これは私に与えます:

parsed: List(((block{~List(y, o, u, a, r, e, a, c, o, w, t, o, o, ((blkA{~List(b, u, t, m, a, y, b, e, n, o, t))~}), a, n, d, s, o, i, s, h, e))~}), h, e, a, r, m, e, m, o, o)

これは一種の正しいです。ただし、非ブロック文字を 1 つずつ解析していますが、これはおそらくパフォーマンスの問題です (私は思いますか?)。これらの非ブロック文字をすべて一度に解析し、それらを 1 つの大きな文字列に残す方法はありますか?

4

1 に答える 1

2

問題は、text閉じ中括弧 ( }) をすべて消費していることです。こんなふうになります:

expr -> block -> expr -> text.+ (until all input is consumed)

この時点で終了し、存在しないexprを解析しようとしますが、これは失敗し、最初の にフォールバックします。}textexpr

log解析時に何が起こっているかを確認するために使用できます。

于 2012-01-31T12:57:17.107 に答える