ANTLR грамматика неправильно обрабатывает мой оператор "not" - PullRequest
1 голос
/ 07 сентября 2011

Я пытаюсь разобрать язык небольших выражений (я не определил язык от поставщика), и все в порядке, пока я не попытаюсь использовать оператор not, который является тильдой в этом языке.

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

http://www.codeproject.com/KB/recipes/sota_expression_evaluator.aspx http://www.alittlemadness.com/2006/06/05/antlr-by-example-part-1-the-language

Язык состоит из трех типов выражений, которые могутбыть использованы с и, или, не операторы и скобки изменить приоритет.Выражения:

Skill("name") > some_number (can also be <, >=, <=,  =, !=)
SkillExists("name")
LoggedIn("name") (this one can also have name@name)

Этот ввод работает нормально:

Skill("somename") > 1 | (LoggedIn("somename") & SkillExists("othername"))

Однако, как только я пытаюсь использовать оператор not, я получаю NoViableAltException.Я не могу понять, почему.Я сравнил мою грамматику с ECalc.g по ссылке codeproject.com, и они, кажется, совпадают, должно быть, есть небольшая разница, которую я не вижу.Ошибка:

Skill("somename") < 10 ~ SkillExists("othername")

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

grammar UserAttribute;

options {
output=AST;
ASTLabelType=CommonTree;
}

tokens {
SKILL = 'Skill' ;
SKILL_EXISTS = 'SkillExists' ;
LOGGED_IN = 'LoggedIn';
GT = '>';
LT = '<';
LTE = '<=';
GTE = '>=';
EQUALS = '=';
NOT_EQUALS = '!=';  
AND = '&';
OR = '|' ;
NOT = '~';
LPAREN   = '(';
RPAREN = ')';
QUOTE = '"';
AT = '@';       
}

/*------------------------------------------------------------------
 * PARSER RULES
 *------------------------------------------------------------------*/  
expression : orexpression EOF!; 
orexpression    : andexpression (OR^ andexpression)*;
andexpression   : notexpression (AND^ notexpression)*;  
notexpression : primaryexpression | NOT^ primaryexpression;
primaryexpression : term | LPAREN! orexpression RPAREN!;
term    : skill_exists | skill | logged_in;
skill_exists    : SKILL_EXISTS LPAREN QUOTE NAME QUOTE RPAREN;
logged_in : LOGGED_IN LPAREN QUOTE NAME (AT NAME)? QUOTE RPAREN;
skill:  SKILL LPAREN QUOTE NAME QUOTE RPAREN ((GT | LT| LTE | GTE | EQUALS | NOT_EQUALS)? NUMBER*)?;

/*------------------------------------------------------------------
 * LEXER RULES
 *------------------------------------------------------------------*/
NAME    : ('a'..'z' | 'A'..'Z' | '_')+;
NUMBER  : ('0'..'9')+ ;
WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+    { $channel = HIDDEN; } ;

1 Ответ

2 голосов
/ 07 сентября 2011

У меня есть 2 замечания:

1

Поскольку вы анализируете отдельные выражения (expression : orexpression EOF!;), ввод "Skill("somename") < 10 ~ SkillExists("othername")" не только недопустим в вашей грамматике, но и недопустим с точки зрения любого синтаксического анализатора выражений (который я знаю). notexpression принимает только выражение "с правой стороны", поэтому ~ SkillExists("othername") - это одно выражение, а Skill("somename") < 10 - это тоже одно выражение. Но между этими двумя отдельными выражениями нет оператора OR или AND. Это было бы то же самое, что вычисление выражения true false вместо true | false или true and false.

Короче говоря, ваша грамматика запрещает:

Skill("somename") < 10 ~ SkillExists("othername")

но допускает:

Skill("somename") < 10 & SkillExists("othername")

что мне кажется логичным.

2

Я не совсем понимаю ваше skill правило (которое неоднозначно, кстати):

skill
 : SKILL LPAREN QUOTE NAME QUOTE RPAREN 
     ((GT | LT| LTE | GTE | EQUALS | NOT_EQUALS)? NUMBER*)?
 ;

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

  • Skill("foo") = 10 20
  • Skill("foo") 10 20 30
  • Skill("foo") <

Возможно, вы имели в виду:

skill
 : SKILL LPAREN QUOTE NAME QUOTE RPAREN 
     ((GT | LT| LTE | GTE | EQUALS | NOT_EQUALS)^ NUMBER)?
 ;

вместо этого? (? становится ^, а * удаляется)

Если я только изменю это правило и проанализирую ввод:

Skill("somename") < 10 & SkillExists("othername")

создается следующий AST:

enter image description here

(как вы можете видеть, AST должен быть лучше сформирован: то есть вам нужны некоторые правила перезаписи в ваших skill_exists, logged_in и skill правилах)


EDIT

и если вы хотите, чтобы между последовательными выражениями подразумевались токены AND, сделайте что-то вроде этого:

grammar UserAttribute;

...
tokens {
...
I_AND;     // <- added a token without any text (imaginary token)
AND = '&';
...
}

andexpression
  :  (notexpression -> notexpression) (AND? notexpression -> ^(I_AND $andexpression notexpression))*
  ;  

...

Как видите, поскольку AND теперь является необязательным, его нельзя использовать внутри правила перезаписи, но вам придется использовать воображаемый токен I_AND.

Если вы сейчас анализируете ввод:

Skill("somename") < 10 ~ SkillExists("othername")

вы получите следующее AST:

enter image description here

...