Если я правильно понимаю, ваша проблема не в левой рекурсии, а в структуре дерева разбора.
Вы правильно устранили левую рекурсию, но, к сожалению, единственный способ избавиться от левой рекурсии — это устранить левую рекурсию в необработанном дереве синтаксического анализа. Большая часть теории для этого материала сводится к сопоставлению правильного набора строк. Вы по-прежнему сопоставляете один и тот же набор строк, так что теория хороша, но вам нужно леворекурсивное дерево синтаксического анализа. Подробнее об этой проблеме в Википедии.
Насколько я знаю, вы не можете сделать необработанный вывод парсера PEG леворекурсивным. Однако вы можете делать с выводом все, что хотите. Так что разберите его как массив, а затем постобработайте, чтобы придать ему красивую левую структуру.
Делаем это с упрощенной (без пробелов, без многосимвольных идентификаторов) грамматикой:
start = call
id = [a-z]
call
= arr:id+ {
var acc = arr[0]
for (i = 1; i < arr.length; i++) {
acc = [acc, arr[i]]
}
return acc;
}
Это анализирует abcd
до [ [ [ 'a', 'b' ], 'c' ], 'd' ]
. Я просто использовал +
вместо рекурсии, а затем пробежался по результирующему массиву, создав нужную нам структуру. В Википедии есть несколько заметок о выполнении левой рекурсии с PEG.
Это предполагает, что вам нужна структура данных. Если вам нужны только скобки, замените действие следующим:
var acc = arr[0]
for (i = 1; i < arr.length; i++) {
acc = acc + '(' + arr[i] + ')'
}
return acc;
Что дает a(b)(c)(d)
.
Чтобы вернуть пробелы и многосимвольные идентификаторы, вы можете сделать это:
start = call
id = [a-z]+
_ = [ ]+
call
= a:id as:arg* {
arr = [a].concat(as)
var acc = arr[0]
for (i = 1; i < arr.length; i++) {
acc = acc + '(' + arr[i] + ')'
}
return acc;
}
arg = _ a:id {return a}
person
WolfTivy
schedule
13.11.2013