我正在使用Antlr4来解析类似布尔的DSL。
这是我的语法:
grammar filter;
filter: overall EOF;
overall
: LPAREN overall RPAREN
| category
;
category
: expression # InferenceCategory
| category AND category # CategoryAndBlock
| label COLON expression # CategoryBlock
| LPAREN category RPAREN # NestedCategory
;
expression
: NOT expression # NotExpr
| expression AND expression # AndExpr
| expression OR expression # OrExpr
| atom # AtomExpr
| LPAREN expression RPAREN # NestedExpression
;
label
: ALPHANUM
;
atom
: ALPHANUM
;
以下是要解析的示例输入字符串:
(cat1:(1 OR 2)AND cat2:(4))
这个语法可以正常输入;它产生了以下完全符合我需要的解析树:
然而,DSL存在奇怪的情况,其中当没有指定其他类别时,“cat1”标签是隐含的。这是InferenceCategory标记捕获的内容,此表达式将在稍后的代码中作为类别处理。
例如,使用
((1 OR 2)AND cat2:(4))
我得到(正如预期的那样):
但是,在以下实例中:
cat2 :( 4)AND(1 OR 2)
我明白了:
请注意,第二个块未标识为InferenceCategory,而是在第一个类别下标识为普通表达式。这是因为语法在cat2之后解析(4):作为正常表达式,并且过去的所有内容都被解析为正常表达式。
有什么方法可以解决这个问题吗?我试过了:
label COLON expression (AND category)* # CategoryBlock
(这不起作用)
和
category AND category AND category
(“工作”,但是非常hacky,只适用于我只有三个类别的特定情况。再来一次,它再次破坏。)
答案 0 :(得分:1)
NOT expression # NotExpr
之类的“替代标签”在您的解析树中没有任何区别。它们只是语义的。它们将导致代码生成过程创建您可以在访问者或监听器中覆盖的特定签名。
这背后的基本原理是,例如,不是只为expression
获取一个访问者覆盖,而是为每个替代标签获得几个,一个。这样,您就不必检查expression
并确定它在采取行动之前的类型。相反,您将获得# OrExpr
的覆盖,例如,当您进入覆盖代码时,您知道您正在处理OR,并在OR令牌的每一侧都有一个表达式。
解析树非常有用,但是当您对Listener或Visitor进行编码时,许多语义才会变得明显。