Пользовательская грамматика ANTLR не работает для каждого ввода - PullRequest
1 голос
/ 21 февраля 2012

Я пытаюсь написать грамматику для нашего пользовательского механизма правил, который использует ANTLR (для анализа) и Pentaho Kettle (для выполнения правил)

Допустимые входные данные для синтаксического анализатора будут иметь тип:
(<Attribute_name> <Relational_Operator> <Value>) AND/OR (<Attribute_name> <Relational_Operator> <Value>)
т.е. PERSON_PHONE = 123456789

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

grammar RuleGrammar;
options{
language=Java;
}

prog                : condition;

condition
                                :  LHSOPERAND RELATIONOPERATOR RHSOPERAND
                                ;

LHSOPERAND
                                :  STRINGVALUE
                                ;

RHSOPERAND
                                :  NUMBERVALUE    |
                                   STRINGVALUE
                                ;


RELATIONOPERATOR
                                :   '>'    |
                                     '=>'  |
                                     '<'   |
                                     '<='  |
                                     '='   |
                                     '<>'
                                ;

fragment NUMBERVALUE
                              : '0'..'9'+
                              ;

fragment STRINGVALUE
                              :  ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_')*
                              ;


fragment LOGICALOPERATOR
                              :  'AND' |
                                 'OR'  |
                                 'NOT'
                              ;

Проблема, с которой я сталкиваюсь, сравнивается со строковым значением, т.е. PERSON_NAME = 1 передаст грамматику,но значение PERSON_NAME=BATMAN не работает.Я использую ANTLRWorks и при отладке для PERSON_NAME=BATMAN я получаю MismatchTokenException для значения RHS.

Может кто-нибудь подсказать мне, где я иду не так?

1 Ответ

3 голосов
/ 21 февраля 2012

BATMAN токенизируется как токен LHSOPERAND.Вы должны понимать, что лексер не учитывает то, что "парсеру" нужно в конкретный момент времени.Лексер просто пытается найти максимально возможное совпадение, и в случае, если 2 (или более) правила соответствуют одинаковому количеству символов (LHSOPERAND и RHSOPERAND в вашем случае), правило, определенное первым, будет «выигрывать», чтоLHSOPERAND правило.

EDIT

Посмотрите на это так: сначала лексер получает поток символов, который он конвертирует в поток токенов.После того, как все токены были созданы, парсер получает эти токены, которые он затем пытается понять.Токены не создаются во время синтаксического анализа (в правилах синтаксического анализа), но перед ним.

Небольшая демонстрация того, как вы могли бы сделать это:

grammar RuleGrammar;

prog
 : condition EOF
 ;

condition
 : logical
 ;

logical
 : relational ((AND | OR) relational)*
 ;

relational
 : STRINGVALUE ((GT | GTEQ | LT | LTEQ | EQ | NEQ) term)?
 ;

term
 : STRINGVALUE
 | NUMBERVALUE
 | '(' condition ')'
 ;

GT          : '>';
GTEQ        : '>=';
LT          : '<';
LTEQ        : '<=';
EQ          : '=';
NEQ         : '<>';
NUMBERVALUE : '0'..'9'+;
AND         : 'AND';
OR          : 'OR';
STRINGVALUE : ('a'..'z' | 'A'..'Z' | '_')+;
SPACE       : ' ' {skip();};

(обратите внимание, что EQ и NEQ на самом деле не являются реляционными операторами ...)

Синтаксический анализ ввода, например:

PERSON_NAME = BATMAN OR age <> 42

теперь приведет к следующему синтаксическому анализу:

enter image description here

...