用于布尔逻辑的Antlr4解析器

时间:2017-08-02 19:05:58

标签: parsing antlr grammar antlr4 context-free-grammar

我是Antlr4 / CFG的新手,我正在尝试为表格的布尔查询DSL编写解析器

  

(id AND id AND ID(OR id OR id或id))

逻辑也可采用

形式
  

(id OR id OR(id AND id AND id))

更复杂的例子可能是:

  

(((id AND id AND(id OR id OR(id AND id)))))   (括在任意数量的括号中)

我尝试了两件事。首先,我做了一个非常简单的解析器,它最终解析了从左到右的所有内容:

grammar filter;

filter: expression EOF;

expression
    : LPAREN expression RPAREN
    | expression (AND expression)+
    | expression (OR expression)+
    | atom;

atom 
    : INT;

我输入了以下解析树:

  

(60)AND(55)AND(53)AND(3337 OR 2830 OR 23)

Attempt 1

这"工作",但理想情况下我希望能够分离我的AND和OR块。试图将这些块分成单独的语法会导致左递归。其次,我希望将我的AND和OR块组合在一起,而不是从左到右阅读,例如,输入(id AND id AND id), 我想要:

  

(和id id id)

不是

  

(和id(和id(和id)))

目前是这样的。

我尝试的第二件事是将OR块直接作为AND块的后代(即第一种情况)。

grammar filter;

filter: expression EOF;

expression
    : LPAREN expression RPAREN
    | and_expr;

and_expr
    : term (AND term)* ;

term
    : LPAREN or_expr RPAREN
    | LPAREN atom RPAREN ;

or_expr
    : atom (OR atom)+;

atom: INT ;

对于相同的输入,我得到以下解析树,这更符合我所寻找的但有一个主要问题:没有OR的实际层次结构和AND块在DSL中,所以这对第二种情况不起作用。对于我正在尝试做的事情,这种方法看起来也有些苛刻。

Attempt 2

最好的方法是什么?同样,我对解析和CFG不太熟悉,所以一些指导会很棒。

1 个答案:

答案 0 :(得分:1)

两者都具有解析样本输入的能力。如果通过删除不必要的括号来简化输入,那么这个语法的输出看起来也很不错:

grammar filter;
filter: expression EOF;
expression
    : LPAREN expression RPAREN
    | expression (AND expression)+
    | expression (OR expression)+
    | atom;
atom : INT;
INT: DIGITS;
DIGITS : [0-9]+;
AND : 'AND';
OR : 'OR';
LPAREN : '(';
RPAREN : ')';
WS: [ \t\r\n]+ -> skip;

我怀疑你的第一个语法是完整的。

你的第二个需要太多括号(主要是term),并且将AND和OR分解为单独的规则而不是替代方案对我来说似乎并不干净。

你可以更简化:

grammar filter;
filter: expression EOF;
expression
    : LPAREN expression RPAREN   # ParenExp
    | expression AND expression  # AndBlock
    | expression OR expression   # OrBlock
    | atom                       # AtomExp
    ;
atom : INT;
INT: DIGITS;
DIGITS : [0-9]+;
AND : 'AND';
OR : 'OR';
LPAREN : '(';
RPAREN : ')';
WS: [ \t\r\n]+ -> skip;

这使得树具有不同的形状但仍然相同。请注意使用# AndBlock# OrBlock标签......这些“替代标签”会使您生成的侦听器或访问者为每个标签分别设置单独的方法,从而可以在代码中将这两者完全分开在语义上和语法上。也许这就是你要找的东西?

我最喜欢这个,因为它是最简单和更清晰的递归,并提供AND和OR的特定代码替代。