允许空白部分 ANTLR4

Allow Whitespace sections ANTLR4

我有一个 antlr4 语法,专为嵌入到文本模板中的领域特定语言而设计。

有两种模式:

示例语法部分:

template
  :  '{' templateBody '}'
  ;

templateBody
  : templateChunk*
  ;

templateChunk
  : code # codeChunk // dsl code, ignore whitespace
  | text # textChunk // any text, preserve whitespace
  ;

code 的规则可能包含对 template 规则的嵌套引用。所以解析器必须支持嵌套 whitespace/non-whitespace 部分。

也许 lexer 模式 可以提供帮助 - 但有一些缺点:

然而,最有前途的方法似乎是操纵隐藏通道

我的问题:是否有满足这些要求的最佳实践?有没有例子语法,已经解决了类似的问题?

附录:

其余语法如下所示:

code
  : '@' function
  ;

function
  : Identifier '(' argument ')'
  ;

argument
  : function
  | template
  ;

text
  : Whitespace+
  | Identifier
  | .+
  ;

Identifier
  : LETTER (LETTER|DIGIT)*
  ;

Whitespace
  : [ \t\n\r] -> channel(HIDDEN)
  ;

fragment LETTER
    : [a-zA-Z]
    ;

fragment DIGIT
    : [0-9]
    ;

在此示例中,code 有一个虚拟实现,指出它可以包含嵌套的 code/template 部分。其实code应该支持

最后我是这样解决问题的:

想法是 enable/disable 解析器规则中的空格:

 templateBody : {enableWs();} templateChunk* {disableWs();};

所以我们必须在我们的解析器基础中定义 enableWsdisableWs class:

public void enableWs() {
    if (_input instanceof MultiChannelTokenStream) {
        ((MultiChannelTokenStream) _input).enable(HIDDEN);
    }
}

public void disableWs() {
    if (_input instanceof MultiChannelTokenStream) {
        ((MultiChannelTokenStream) _input).disable(HIDDEN);
    }
}

现在这是什么MultiChannelTokenStream

  • Antlr4 定义了一个 CommonTokenStream,它是一个仅从 一个频道 读取的令牌流。
  • MultiChannelTokenStream 是从 启用的频道 读取的令牌流。为了实现,我获取了 CommonTokenStream 的源代码,并将每个对 channel 的引用替换为 channels(相等比较包含比较)

可以在 antlr4multichannel

找到使用上述语法的示例实现