【问题标题】:Parsing rules with multiple AND and OR using ANTLR4?使用 ANTLR4 解析具有多个 AND 和 OR 的规则?
【发布时间】:2019-07-07 22:42:19
【问题描述】:

我是 ANTLR4 的新手,我正在尝试使用它来解析我们从外部规则生成器获得的规则字符串。 规则的形式为 [attribute operator value(s)] ANDed 和 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>)

【问题讨论】:

    标签: antlr4


    【解决方案1】:

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

    为此,您应该添加grouprules 作为expression 的替代,因此表达式不仅可以具有USERATTRIBUTE operator values 的形式,还可以是AND 和/或OR 的嵌套应用程序运营商。

    为此,您需要首先将EOFgrouprules 移动到start,尽管您不希望它应用于嵌套在括号内的grouprules(因为它们后面会跟着一个结束括号,而不是文件末尾,显然只出现一次)。

    【讨论】:

    • 感谢您的建议。我做了你提到的改变。现在错误已经消失,但似乎使用别名“grun”和 -tree 进行测试,它只是解析规则中表达式的第一次出现。在下一条评论中添加了结果。我会继续努力的。
    • [[divison3__c == ('AH Marketing', '资产保护解决方案')] OR [hrstatus__c == ('Active')]] AND [[hiredate__c > ('2000-01-01 ')] 或 [custom10__c == ('ABCD')]]
    • (grouprules (grouprule [ (expression (grouprules (grouprule [ (expression divison3__c (operator ==) (values ( (value 'AH Marketing', '资产保护解决方案')))] OR [hrstatus__c == ('Active')]] AND [[hiredate__c > ('2000-01-01')] OR [custom10__c == ('ABCD') ))) ]))) ]))
    • @SouvikMajumdar 我可能遗漏了一些东西,但您的输出似乎包含了您输入中的所有内容,所以对我来说它看起来是正确的。
    【解决方案2】:

    关于你的语法的几点说明:

    • 你的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 &gt; ('2000-01-01')] OR [custom10__c == ('ABCD')]] 这样:

    【讨论】:

    • 非常感谢。这确实奏效了。我只是对 ANTLR4 很着迷。在这个世界上要学习的东西太多了。我现在明白了,现在可以构建我的解析器了。太感谢了!不幸的是,我对这两个答案都投了赞成票,但由于我的票数不到 15 票,他们没有出现。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多