PegKit: грамматический синтаксис, который по-разному обрабатывает одну и ту же работу

Я работаю над кодом, который использует PegKit, и я наткнулся на что-то, я не уверен, как это выяснить. У меня есть синтаксис, который выглядит следующим образом (упрощенно):

expr = runtimeExpr | objectExpr;
runtimeExpr = is? runtimeObject;
objectExpr = runtimeObject keyPath;
runtimeObject = '[' string ']';
is = 'is';
keyPath = string;

Я ищу следующие результаты:

[abc] -> runtime expr.
is [abc] -> runtime expr.
[abc].def -> object expr.

Однако то, что происходит, - то, что сгенерированный код парсера выглядит следующим образом:

if ([self predicts:STLOGEXPRESSIONPARSER_TOKEN_KIND_IS, 0]) {
    [self runtimeExpr_]; 
} else if ([self predicts:STLOGEXPRESSIONPARSER_TOKEN_KIND_OPEN_BRACKET, 0]) {
    [self objectExpr_]; 
}

Это говорит о том, что для анализа выражения во время выполнения он должен начинаться с "is". Который означает, что [abc] вместо этого передается как объект expr.

Так что мне нужна помощь в понимании того, как выразить эту логику в синтаксисе грамматики:

  1. Если строка начинается с "is", за которым следует runtimeObject, или является только runtimeObject, обработайте ее как runtimeExpr.

  2. В противном случае обработайте его как objectExpr.

1 ответ

Решение

Создатель PEGKit здесь.

Я считаю, что проблема здесь является ведущим необязательным is?, Любое правило, которое начинается с необязательного префикса, подобного этому, а затем впоследствии соответствует чему-то похожему или идентичному другому правилу (runtimeObject в этом случае) может вызвать проблемы.

Но решение легко. Просто измените порядок вещей. PEGKit является детерминированным, что означает, что он будет пытаться использовать альтернативы OR в порядке, указанном в грамматике. Так что в этом случае просто поместите более длинное альтернативное правило (objectExpr) сначала (до runtimeExpr в expr правило).

Попробуйте это, я верю, что все получится

expr = objectExpr | runtimeExpr;
objectExpr = runtimeObject keyPath;
runtimeExpr = is runtimeObject | runtimeObject;
runtimeObject = '[' string ']';
is = 'is';
keyPath = string;

Обратите внимание на изменения, которые я внес в оба expr а также runtimeExpr правила. Я подозреваю только изменение в expr необходимо решить эту проблему, но изменение на runtimeExpr безвреден Эксперимент должен сказать вам, является ли runtimeExpr изменение действительно необходимо.

Другие вопросы по тегам