Грамматика парсера Lark работает с Эрли, но не с LALR - PullRequest
1 голос
/ 23 мая 2019

Рассмотрим этот простой тест анализатора Python Lark :

GRAMMAR = '''
start: container*

container: string ":" "{" (container | attribute | attribute_value)* "}"
attribute: attribute_name "=" (attribute_value | container)
attribute_value: string ":" _value ("," _value)*
_value: number | string

attribute_name: /[A-Za-z_][A-Za-z_#0-9]*/

string: /[A-Za-z_#0-9]+/
number: /[0-9]+/

    %import common.WS
    %ignore WS
'''

data = '''outer : {
 inner : {
 }
}'''

parser = Lark(GRAMMAR, parser='lalr')
parser.parse(data)

Это работает с parser='earley', но не с parser='lalr'.Я не понимаю почему.Сообщение об ошибке:

Неожиданные символы: нет терминала, определенного для '{' в строке 2, столбец 12

inner: {

Это простоMWE.Моя настоящая грамматика страдает от той же проблемы.

1 Ответ

1 голос
/ 26 июня 2019

Причина, по которой это терпит неудачу с LALR, заключается в том, что он имеет предвидение 1 (в отличие от Эрли, у которого неограниченное предвидение), и это путается между attribute_name и string.Как только он совпадает с другим (в данном случае attribute_name), он не может откатиться назад и сопоставить другое правило.

Если вы используете более низкий приоритет для терминала attribute_name, он будет работать.Например:

attribute_name: ATTR

ATTR.0: /[A-Za-z_][A-Za-z_#0-9]*/

Но рекомендуется использовать один и тот же терминал для обоих, если это возможно, чтобы синтаксический анализатор мог думать за вас, а не лексера.Вы можете добавить дополнительную проверку, если это необходимо, после выполнения анализа.

Оба подхода (изменение приоритета или объединение терминалов) решат вашу проблему.

...