【问题标题】:ANTLR grammar not handling my "not" operator correctlyANTLR 语法未正确处理我的“非”运算符
【发布时间】:2011-09-08 04:01:22
【问题描述】:

我正在尝试解析一种小型表达式语言(我没有定义来自供应商的语言),一切都很好,直到我尝试使用 not 运算符,这是该语言中的波浪号。

我的语法深受这两个链接的影响(又名无耻的剪切和粘贴):

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

该语言由三种表达式类型组成,可以与 and、or、not 运算符和括号更改优先级一起使用。表达式是:

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; } ;

【问题讨论】:

  • 但是Skill("somename") &lt; 10 ~ SkillExists("othername")应该怎么解析呢?我假设Skill("somename") &lt; 10skill 表达式,~ SkillExists("othername")notexpression。但是没有规则匹配 skill 后跟 notexpression,对吧?
  • Skill("somename")
  • 不,不是真的,你想知道为什么Skill("somename") &lt; 10 ~ SkillExists("othername") 失败了,这对我来说并不奇怪:它应该失败。我试图在我回答的第一句话中解释这一点。

标签: parsing antlr antlr3


【解决方案1】:

我有两条评论:

1

由于您正在解析单个表达式 (expression : orexpression EOF!;),因此输入 "Skill("somename") &lt; 10 ~ SkillExists("othername")" 不仅在您的语法中无效,而且在任何表达式解析器(我知道)中都无效。 notexpression 只接受“右手边”表达式,因此 ~ SkillExists("othername") 是单个表达式,Skill("somename") &lt; 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") &lt;

也许你的意思是:

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

相反? (? 变为 ^ 并且 * 被删除)

如果我只更改该规则并解析输入:

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

创建了以下 AST:

(如您所见,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:

【讨论】:

  • 好吧,你给了我很多信息,到目前为止一切都说得通!谢谢!我知道供应商而不是运营商有一些奇怪的地方,但我无法指出它,你说得很好。他们的表达语言允许“true ~false”,而对于任何其他语言,你会写这个“true && !false”。所以我的语法实际上确实需要支持“true ~false”,中间没有其他运算符。 (在旁注中,这让我想知道如何解释它,它是一个隐含的“和”......嗯)。
  • 另外,?在技​​能规则中是重构出错的残余。你是对的,我不需要那个,谢谢指出! (与*后的数字相同,我确实有技能,技能存在,并且几天前作为一条规则登录,但将它们重构为自己的规则,并且重构后没有充分检查我的规则)
  • 我从未听说过重写规则(这里是新手),但我在 antler wiki 上找到了关于它们的 wiki 页面...现在阅读它们
  • 重写规则类似于您已经使用的内联 ^(AST 根)和 !(从 AST 中排除)运算符。
  • @Michael,我添加了一个小例子来说明如何处理“隐含的AND's”。请参阅编辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-15
  • 2012-01-18
  • 1970-01-01
相关资源
最近更新 更多