2011-12-04 15 views
1

私はfnparseで文字列を解析しようとしています。単語の末尾にある文字は、別の方法で処理する必要があります。このため、私はルールを持っています:fnparseを使った非貪欲な構文解析

(def a-or-s 
    (rep* (alt (lit \a) (lit \s)))) 

(def ends-with-s 
    (conc a-or-s (lit \s))) 

私は文字列 "aas"にマッチしようとします。これは、rep*が貪欲であり、単語の最後の文字を呑み込んで、concルールが機能しないため、解析されません。どのようにしてこれを回り、これらの構造を適切に一致させることができますか?

答えて

1

このため、followed-byルールを使用する必要があります。基本的に 'a'または 's'を繰り返し一致させたいが、最後のトークンを消費する必要はありません。その後

(defn rep*? [subrule] 
    (rep* (conc subrule (followed-by subrule)))) 

rep*の代わりに使用し、元のコードが動作するはずです:

(def a-or-s 
    (lit-alt-seq "as")) ;; same as (alt (lit \a) (lit \s)) 

(def ends-with-s 
    (conc 
    (rep* (conc a-or-s (followed-by a-or-s))) 
    (lit \s))) 

我々はこのようなrep*の非欲張りバージョンを作成するために、そのコードをリファクタリングすることができます:ここでそれを行うためのコードです予想通り。 ...しかし

user> (rule-match (conc (rep*? a-or-s) (lit \s)) identity #(identity %2) {:remainder "aaaaaaaasss"}) 
([(\a \a) (\a \a) (\a \a) (\a \a) (\a \a) (\a \a) (\a \a) (\a \s) (\s \s) (\s \s)] \s) 

それをしようとした後...あなたは「出力に何が起こっているのか?」頼むかもしれない、それは我々が求めたものですので、うまくrep*?は私たちに、トークンのペアを与えています。これはconcの代わりにinvisi-concを使用して固定することができます。そのため

(defn rep*? [subrule] 
    (rep* (invisi-conc subrule (followed-by subrule)))) 

user> (rule-match (conc (rep*? a-or-s) (lit \s)) identity #(identity %2) {:remainder "aaaaaaaasss"}) 
([\a \a \a \a \a \a \a \a \s \s] \s) 
+0

感謝を - 私はそれをやってみると、私が乗る方法を見ていきます。 –