Оценка правила ANTLR3 имеет решение, отличное от LL (*)

Вот мой грамматик:

grammar esi_exp;

/* This will be the entry point of our parser. */
eval
    :    booleanExp
    ;

/* Addition and subtraction have the lowest precedence. */
booleanExp
    :  orExp
    ;

orExp
    :  andExpr (OR andExpr)*
    ;

andExpr
    :  notExpr (AND notExpr)*
    ;

notExpr
    :  NOT comparisonExpr
    |  comparisonExpr
    ;

comparisonExpr
    :   varOrLiteral ('==' varOrLiteral)*
    ;

varOrLiteral
    :   functionExpr
    |   literalExpr
    |   variableExpr
    ;

literalExpr : QUOTE VAR_ID QUOTE ;
variableExpr
    : OPEN_VAR VAR_ID CLOSE_PAREN           // $(HTTP_HOST)
    | OPEN_VAR varWithArg CLOSE_PAREN    // $(QUERY_STRING{param})
    | OPEN_VAR varWithArgQuoted CLOSE_PAREN    // $(QUERY_STRING{'param'})
    | OPEN_PAREN booleanExp CLOSE_PAREN
    ;

varWithArg : VAR_ID OPEN_ARG VAR_ID CLOSE_ARG ;
varWithArgQuoted : VAR_ID OPEN_QUOTED_ARG VAR_ID CLOSE_QUOTED_ARG ;

matchValue : MATCH_VALUE_REGEX ;

functionExpr
    : '$' FunctionName functionArgs;


FunctionName :
    'exists'
     | 'is_empty'
     ;

functionArgs
    :   '()'
    |  OPEN_PAREN VAR_ID CLOSE_PAREN
    |  OPEN_PAREN variableExpr CLOSE_PAREN
    ;

EQUALS  :    '==' ;
MATCH_FUNC     : 'matches' ;
TRIPLE_QUOTE : '\'\'\'' ;
QUOTE       : '\'' ;
OPEN_VAR  : '$(' ;
OPEN_PAREN : '(' ;
CLOSE_PAREN : ')' ;
OPEN_ARG : '{' ;
CLOSE_ARG : '}' ;
OPEN_QUOTED_ARG : '{\'' ;
CLOSE_QUOTED_ARG : '\'}' ;
VAR_ID      : ('a'..'z'|'A'..'Z'|'_')+ ;      // match identifiers

AND : '&&' | '&' ;
OR : '|' | '||' ;
NOT : '!' ;

/* A number: can be an integer value */
Number
    :    ('0'..'9')+
    ;

WS
    :   (
             ' '
        |    '\r'
        |    '\t'
        |    '\u000C'
        |    '\n'
        )
            {
                skip();
            }
    ;

MATCH_VALUE_REGEX : TRIPLE_QUOTE ~(QUOTE)* TRIPLE_QUOTE;

который отлично подходит для тестового случая:

$exists($(id)) && (($(pagetype) == 'roster') || ($(pagetype) == 'cheerleaders') || ($(pagetype) == 'coaches') || ($(pagetype) == 'staff'))

Однако мне также нужно, чтобы он мог распознавать:

$(REQUEST_PATH) matches '''(matchup)/([^/]*)/([^/]*)/([^/]*)/([^/]*)'''

Правило грамматики, например:

varOrLiteral MATCH_FUNC matchValue

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

Я читал, что включение поиска с возвратом должно помочь в таких ситуациях, однако в документации, похоже, указано, что в целом следует избегать возврата.

Как добавить это без проблем с LL и/или левой рекурсией?


person nflearl    schedule 09.10.2014    source источник


Ответы (2)


Вы можете предвидеть то, что вы ожидаете, как начало правила, чтобы указать способ.

Почему бы тебе не попробовать это?

varOrLiteral
    :  
    (QUOTE QUOTE) => matchValue
    |(QUOTE) => literalExpr
    | variableExpr
    |functionExpr
    ;

Этим вы сообщаете грамматике, что только если varOrLiteral начинается с QUOTE, это literalExpr. И т.п.

Вы можете предвидеть, сколько вы хотите.

Последнее правило, опция по умолчанию.

Удачи!

person Juan Aguilar Guisado    schedule 09.10.2014
comment
Как это помогает реализовать/интегрировать MATCH_FUNC matchValue в грамматику? - person nflearl; 10.10.2014
comment
Только что попробовал этот рефакторинг, получив исключение FailedPredicateException. Это не передает регрессии в существующем рабочем случае. - person nflearl; 10.10.2014
comment
Я отредактировал свой ответ. Я пытался помочь вам, но я пропустил информацию. Очень жаль. Попробуй это. Компилировать грамматики только с умом сложно, но у меня сейчас нет под рукой моего комплекта разработчика :p - person Juan Aguilar Guisado; 10.10.2014
comment
Я очень ценю помощь. Это имеет больше смысла для моего первого вопроса. Тем не менее, это не регрессия с FailedPredicateException. Любые идеи о FailedPredicate? - person nflearl; 10.10.2014
comment
Я исправил одну вещь. matchValue должен быть в стиле верблюда, как ваше правило: ') - person Juan Aguilar Guisado; 10.10.2014
comment
Я уже уловил проблему с верблюжьим случаем, прежде чем пытаться регрессировать. Используя Interpreter в AntlrWorks, он не генерирует результирующее дерево синтаксического анализа, вместо этого я вижу исключение FailedPredicateException как часть дерева. - person nflearl; 10.10.2014
comment
Еще одно уточнение: AntlrWorks плохо с этим справляется. Я провел регрессию с помощью другого инструмента и получил ожидаемые результаты регрессии. С помощью этой подсказки я вижу свой путь к финишу. Мне просто нужно настроить compareExpr, чтобы получить новое поведение. - person nflearl; 10.10.2014
comment
Было не так просто, как я думал, добраться до финиша, сняв галочку на данный момент, так как нужно больше, а я еще не там. - person nflearl; 10.10.2014

Наконец-то понял это и смог достичь цели, просто изменив выражение сравнения на:

:   varOrLiteral (EQUALS varOrLiteral | MATCH_FUNC matchValue)*

Достаточно хорошо на данный момент.

person nflearl    schedule 03.11.2014