ANTLR语法没有正确处理我的“非”操作符

时间:2011-09-07 16:29:56

标签: parsing antlr antlr3

我正在尝试解析一个小的表达式语言(我没有从供应商那里定义语言),一切都很好,直到我尝试使用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。我无法弄清楚为什么。我已经将我的语法与codeproject.com链接中的ECalc.g进行了比较,它们似乎匹配,必须有一些我看不到的细微差别。失败:

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 个答案:

答案 0 :(得分:2)

我有2条评论:

1

由于您正在解析单个表达式(expression : orexpression EOF!;),因此输入"Skill("somename") < 10 ~ SkillExists("othername")"不仅在语法中无效,而且在任何表达式解析器(我知道)方面都是无效的。 notexpression仅采用“右侧”表达式,因此~ SkillExists("othername")是单个表达式,Skill("somename") < 10也是单个表达式。但是在这两个单个表达式之间,没有ORAND运算符。这与评估表达式true false而不是true | falsetrue 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_existslogged_inskill规则中重写规则)


修改

如果您希望连续表达式之间隐含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