5

(注:このような他の質問を読みましが、これを理解できませんでした)。

私はこの文法を書きました:

start = call

ident = [a-z]+
spaces = [ ]+

call = f:ident spaces g:(call / ident) {
    return f + "(" + g + ")";
}

この入力で

a b c d

戻ります

"a(b(c(d)))"

そして、私はしたいです

"a(b)(c)(d)"

この左再帰ルールはそのようなものを与えることができると思いますが、PEG.js は左再帰をサポートしていません。

call = f:(call / ident) spaces g:ident {
    return f + "(" + g + ")";
}

この場合、左再帰を削除するにはどうすればよいですか?

PS: これは、オンラインの PEG.js デモでテストできます。

4

3 に答える 3

8

良い質問。ident特別な扱いを受けるため (括弧なし)、最初のものを他のすべてのものから分離することから始めます。spaces ident次に、括弧内の値を収集する再帰を処理するルールに従います。ループはテキストをラップし、ident再帰的に収集された新しいテキストを追加します。

ルールの簡略版を次に示します (tail別のルールであることに注意してください)。

head: ident tail?;        //the "head" ident is separated
tail: spaces ident tail?; //each "tail" ident is looped over

PEG スクリプトは次のとおりです。

start = head

ident = [a-z]+
spaces = [ ]+

head = head:ident tail:tail? {
    return head + tail;
}

tail = spaces next:ident tail:tail? {
    return "(" + next + ")" + tail
}

編集:これは、1つのルールで機能し、あなたのものに似た代替手段です。

start = head

ident = [a-z]+
spaces = [ ]+

head = head:ident tail:(spaces next:ident{return "(" + next + ")" })* {
    return head + tail.join("")
}

の出力a b c d"a(b)(c)(d)"両方のスクリプトのものです。

于 2012-11-23T03:26:05.407 に答える
0

次のように、呼び出しの非終端記号を再構成し、その繰り返し部分を+演算子を使用して別のルールに入れることができます。

start = call

ident = i:[a-z]+ { return i.join(''); }
spaces = [ ]+

call = f:ident g:args+ {
    return f + g.join('');
}

args = spaces a:ident { return "(" + a + ")"; }
于 2016-09-01T11:30:59.350 に答える