Если я правильно понял, ваша проблема не оставила рекурсии, это структура дерева синтаксического анализа.
Вы правильно отредактировали левую рекурсию, но, к сожалению, единственный способ избавиться от левой рекурсии - , устраняя левую рекурсию в дереве необработанного разбора. Большая часть теории для этого материала сводится к правильному набору строк. Вы по-прежнему согласуетесь с одним и тем же набором строк, поэтому теория счастлива, но вам нужно левое рекурсивное дерево разбора. Подробнее об этой проблеме on wikipedia.
AFAIK, вы не можете получить исходный вывод парсера PEG, чтобы он оставался рекурсивным. Однако вы можете делать все, что хотите, с выходом. Итак, проанализируйте его как массив, а затем postprocess, чтобы придать ему хорошую левую структуру.
Делать это с упрощенной (без пробелов, без каких-либо идентификаторов multicharacter) грамматика:
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' ]
. Я просто использовал +
вместо рекурсии, а затем пробежал результирующий массив, построив нужную нам структуру. В Википедии есть замечания по выполнению left recursion with a PEG.
Предполагается, что вам нужна структура данных. Если вы просто хотите, чтобы скобки, заменить действие с этим:
var acc = arr[0]
for (i = 1; i < arr.length; i++) {
acc = acc + '(' + arr[i] + ')'
}
return acc;
Что дает a(b)(c)(d)
.
Чтобы поместить пробелы и обратно multicharacter ID, вы можете сделать это:
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}