В вашей грамматике у вас есть:
argument <- variable / lowercase /number / string
function <- {|lowercase {|(open argument (separator (argument / function))* close)?|}|}
Имейте в виду, что lpeg пытается сопоставить шаблоны/предикаты в правиле в том порядке, в котором они у вас есть. Как только он находит совпадение, lpeg не будет рассматривать дальнейшие возможные совпадения в этом правиле грамматики, даже если позже может быть «лучшее» совпадение.
Здесь ему не удается сопоставить вложенные вызовы функций, потому что он видит, что c
может соответствовать
`argument <- variable`
Поскольку ваш нетерминал variable
указан перед function
, lpeg не учитывает последний и поэтому прекращает синтаксический анализ токенов, которые идут после.
В качестве эксперимента я немного изменил вашу грамматику и добавил несколько захватов таблиц и имен для большинства интересующих вас нетерминалов.
local pattern = re.compile
[=[
term <- {| {:type: '' -> "term" :} term_t |}
term_t <- func / var
func <- {| {:type: '' -> "func":} {:name: func_id:} "(" arg(separator arg)* ")" |}
func_id <- lower / upper
arg <- number / string / term_t
var <- {| {:type: '' -> "var" :} {:name: lower / upper:} |}
string <- '"' {~ [^"]* ~} '"'
lower <- {%l%w*}
upper <- {%u%w*}
number <- {%d+}
separator <- blank "," blank
blank <- " "*
]=]
С помощью быстрого теста шаблона:
local test = [[fun(A, b, c(d(42), "e", f, 7))]]
dump( pattern:match(test) )
Что дает следующий вывод на моей машине:
{
{
{
type = "var",
name = "A"
},
{
type = "var",
name = "b"
},
{
{
"42",
type = "func",
name = "d"
},
"e",
{
type = "var",
name = "f"
},
"7",
type = "func",
name = "c"
},
type = "func",
name = "fun"
},
type = "term"
}
Внимательно изучив приведенное выше, вы заметите, что аргументы функции появляются в индексной части таблицы в том порядке, в котором они были переданы. OTOH type
и name
могут появляться в любом порядке, поскольку они находятся в ассоциативной части таблицы. . Вы можете обернуть эти «атрибуты» в другую таблицу и поместить эту внутреннюю таблицу атрибутов в индексную часть внешней таблицы.
Редактировать. Здесь изменена грамматика, чтобы сделать синтаксический анализ более однородным. Я удалил захват term
, чтобы избавиться от ненужных ветвей.
local pattern2 = re.compile
[=[
term <- term_t
term_t <- func / var
func <- {| {:type: '' -> "func":} {:name: func_id:} "(" args? ")" |}
func_id <- lower / upper
arg <- number / string / term_t
args <- arg (separator args)?
var <- {| {:type: '' -> "var" :} {:name: lower / upper:} |}
string <- {| {:type: '' -> "string" :}'"' {:value: [^"]* :} '"' |}
lower <- {%l%w*}
upper <- {%u%w*}
number <- {| {:type: '' -> "number":} {:value: %d+:} |}
separator <- blank "," blank
blank <- " "*
]=]
Что дает следующее:
{
{
type = "var",
name = "A"
},
{
type = "var",
name = "b"
},
{
{
{
type = "number",
value = "42"
},
type = "func",
name = "d"
},
{
type = "string",
value = "e"
},
{
type = "var",
name = "f"
},
{
type = "number",
value = "7"
},
type = "func",
name = "c"
},
type = "func",
name = "fun"
}
person
greatwolf
schedule
26.07.2013