使用 ANTLR4 解析具有多个 AND 和 OR 的规则?

Parsing rules with multiple AND and OR using ANTLR4?

我是 ANTLR4 的新手,我正在尝试使用它来解析我们从外部规则生成器获得的规则字符串。 规则的形式为 [属性运算符值] AND 和 ORed 多次。

我能够解析更简单的,例如:-

[divison3__c == ('AH Marketing', 'Asset Protection Solutions')]  OR  [hrstatus__c == ('Active')]

但是,一旦我遇到那些具有复合 AND 和 OR 的问题,例如:-

[[divison3__c == ('AH Marketing', 'Asset Protection Solutions')] OR  [hrstatus__c == ('Active')]] AND [[hiredate__c > ('2000-01-01')] OR [custom10__c == ('ABCD')]]

下面提到了我的适用于简单规则的语法。我真的很感激任何关于在解析由复合 AND 和 OR 组成的规则方面需要做什么的指示。

// Our grammar is called Rules.
grammar Rules;

// Rules
start: grouprules;

grouprules: grouprule (andor grouprule)* EOF;

grouprule: L_SB expression R_SB;

expression: USERATTRIBUTE operator values;

operator: EQ | NE | GE | GT | LE | LT;

values: '(' value  (','  value )* ')';

value: STRING | date;

date: '\'' DATE '\'';

andor: AND | OR;

// Tokens
EQ: '==';
NE: '!=';
GT:  '>';
GE: '>=';
LT:  '<';
LE: '<=';
L_SB: '[';
R_SB: ']';
AND: [aA][nN][dD];
OR: [oO][rR];
NUMBER: [0-9]+;

USERATTRIBUTE: [a-zA-Z][a-zA-Z0-9_]*;

STRING:  '\'' ~('"')* '\'' ;

// Not perfect
DATE: [0-9][0-9][0-9][0-9][-][0-1][0-9][-][0-3][0-9] ;

// WS represents a whitespace, which is ignored entirely by skip.
WS: [ \t\u000C\r\n]+ -> skip;

规则:

[divison3__c == ('AH Marketing', 'Asset Protection Solutions')]  OR  [hrstatus__c == ('Active')]

成功结果:

(grouprules (grouprule [ [ hiredate__c (operator >) (values ( (value '2000-01-01')] AND [divison3__c == ('AH Marketing', 'Asset Protection Solutions') )) ]) ] <EOF>)

复合规则:

[[divison3__c == ('AH Marketing', 'Asset Protection Solutions')] OR  [hrstatus__c == ('Active')]] AND [[hiredate__c > ('2000-01-01')] OR [custom10__c == ('ABCD')]]

不成功的结果:

line 1:1 extraneous input '[' expecting USERATTRIBUTE
line 1:162 extraneous input ']' expecting {<EOF>, AND, OR}
(grouprules (grouprule [ (expression [ divison3__c (operator ==) (values ( (value 'AH Marketing', 'Asset Protection Solutions')] OR  [hrstatus__c == ('Active')]] AND [[hiredate__c > ('2000-01-01')] OR [custom10__c == ('ABCD') ))) ]) ] <EOF>)

您的问题不在于您有多个 and/or 运算符(像 [...] AND [...] OR [...] 这样的东西可以很好地解析),而是存在嵌套的括号 ([[)。目前你的语法只允许 USERATTRIBUTE operator values 在括号内,而不是其他括号或 AND/OR.

要实现这一点,您应该添加 grouprules 作为 expression 的替代项,因此表达式不仅可以具有 USERATTRIBUTE operator values 的形式,还可以是 USERATTRIBUTE operator values 的嵌套应用=13=] and/or OR 运算符.

为此,您需要先将 EOFgrouprules 移动到 start,因为您不希望它应用于嵌套的 grouprules 内部方括号(因为那些后面会跟一个右括号,而不是文件结尾,这显然只出现一次)。

关于你的语法的几点评论:

  • 你的 STRING 可能应该包含 ~('\'')* 而不是 ~('"')*
  • '2018-12-31' 这样的输入不会(部分)匹配您的 DATE 规则:因为它有引号,所以您的 STRING 规则会匹配它。 DATE 可能应该被删除
  • 由于之前的评论,您的 date 应该被删除

这应该可以解决问题:

grammar Grammar;

start
 : expr EOF
 ;

expr
 : USERATTRIBUTE ( EQ | NE | GE | GT | LE | LT ) expr
 | expr ( AND | OR ) expr
 | '[' expr ']'
 | list
 ;

list
 : '(' STRING  (','  STRING )* ')'
 ;

EQ : '==';
NE : '!=';
GT :  '>';
GE : '>=';
LT :  '<';
LE : '<=';
L_SB : '[';
R_SB : ']';
AND : [aA][nN][dD];
OR : [oO][rR];
NUMBER : [0-9]+;
USERATTRIBUTE : [a-zA-Z][a-zA-Z0-9_]*;
STRING : '\'' ~('\'')* '\'' ;
WS : [ \t\u000C\r\n]+ -> skip;

您的输入 [divison3__c == ('AH Marketing', 'Asset Protection Solutions')] OR [hrstatus__c == ('Active')] 会像这样解析:

[[divison3__c == ('AH Marketing', 'Asset Protection Solutions')] OR [hrstatus__c == ('Active')]] AND [[hiredate__c > ('2000-01-01')] OR [custom10__c == ('ABCD')]] 像这样: