我是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)
这"工作",但理想情况下我希望能够分离我的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中,所以这对第二种情况不起作用。对于我正在尝试做的事情,这种方法看起来也有些苛刻。
最好的方法是什么?同样,我对解析和CFG不太熟悉,所以一些指导会很棒。
答案 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的特定代码替代。