我正在尝试解析一个小的表达式语言(我没有从供应商那里定义语言),一切都很好,直到我尝试使用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; } ;
答案 0 :(得分:2)
我有2条评论:
由于您正在解析单个表达式(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")
对我而言似乎合乎逻辑。
我不太明白你的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:
(正如您所看到的,AST需要更好地形成:即您需要在skill_exists
,logged_in
和skill
规则中重写规则)
修改
如果您希望连续表达式之间隐含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: