Antlr4 语法 - 识别语法的麻烦

Antlr4 grammar - trouble identifying grammar

我正在使用 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 ("works",但它非常笨拙,只适用于我正好有三个类别的特定情况。再多了,它又坏了。)

NOT expression # NotExpr 这样的 "alternative labels" 不会对您的解析树产生影响。它们是纯语义的。它们将导致代码生成过程创建特定的签名,您可以在访问者或侦听器中覆盖这些签名。

这背后的基本原理是,例如,您将获得多个替代标签,而不是只获得一个 expression 的访问者覆盖。这样,您就不必在对它采取行动之前检查 expression 并确定它是什么类型。相反,例如,您将获得 # OrExpr 的覆盖,一旦进入该覆盖代码,您就会知道您正在处理 OR,在 OR 标记的每一侧都有一个表达式。

解析树很有用,但很多语义只有在编写监听器或访问器代码时才会变得明显。