6

通常の PEG (構文解析式文法) では、これは有効な文法です。

values <- number (comma values)*
number <- [0-9]+
comma  <- ','

ただし、LPeg を使用してこれを記述しようとすると、そのルールの再帰的な性質が失敗します。

local lpeg   = require'lpeg'

local comma  = lpeg.P(',')
local number = lpeg.R('09')^1
local values = number * (comma * values)^-1
--> bad argument #2 to '?' (lpeg-pattern expected, got nil)

この単純な例では、再帰を使用しないようにルールを書き直すことができますが、書き直したくない既存の文法がいくつかあります。

LPeg で自己参照ルールを作成するにはどうすればよいですか?

4

2 に答える 2

5

文法を使用します。

Lua 変数を使用すると、以前に定義されたパターンを使用して新しいパターンごとに段階的にパターンを定義することができます。ただし、この手法では再帰的なパターンを定義できません。再帰パターンの場合、実際の文法が必要です。

LPeg は、各エントリがルールであるテーブルで文法を表します。

呼び出し lpeg.V(v) は、文法でインデックス v を持つ非終端記号 (または変数) を表すパターンを作成します。この関数が評価されるとき、文法はまだ存在しないため、結果はそれぞれのルールへのオープン参照になります。

テーブルがパターンに変換されると (lpeg.P を呼び出すか、パターンが予期される場所でそれを使用することによって)、テーブルは固定されます。次に、lpeg.V(v) によって作成されたすべての開いている参照は、テーブル内で v によってインデックス付けされたルールを参照するように修正されます。

テーブルが修正されると、結果は最初のルールに一致するパターンになります。テーブル内のインデックス 1 のエントリは、その初期ルールを定義します。そのエントリが文字列の場合、最初のルールの名前であると見なされます。それ以外の場合、LPeg はエントリ 1 自体が初期ルールであると想定します。

例として、次の文法は、a と b の数が同じ a と b の文字列に一致します。

equalcount = lpeg.P{
  "S";   -- initial rule name
  S = "a" * lpeg.V"B" + "b" * lpeg.V"A" + "",
  A = "a" * lpeg.V"S" + "b" * lpeg.V"A" * lpeg.V"A",
  B = "b" * lpeg.V"S" + "a" * lpeg.V"B" * lpeg.V"B",
} * -1

これは、標準の PEG 表記の次の文法と同等です。

  S <- 'a' B / 'b' A / ''
  A <- 'a' S / 'b' A A
  B <- 'b' S / 'a' B B
于 2014-10-01T20:24:17.100 に答える