允许空白部分ANTLR4

Cor*_*onA 1 java antlr antlr4

我有一个antlr4语法,专门用于嵌入到文本模板中的特定于域的语言.

有两种模式:

  • 文本(应保留空格)
  • 代码(应忽略空格)

示例语法部分:

template
  :  '{' templateBody '}'
  ;

templateBody
  : templateChunk*
  ;

templateChunk
  : code # codeChunk // dsl code, ignore whitespace
  | text # textChunk // any text, preserve whitespace
  ;
Run Code Online (Sandbox Code Playgroud)

规则code可以包含对template规则的嵌套引用.因此解析器必须支持嵌套空白/非空白部分.

也许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]
    ;
Run Code Online (Sandbox Code Playgroud)

在这个例子中code有一个虚拟实现,指出它可以包含嵌套的代码/模板部分.其实code应该支持

  • 多个参数
  • 原始类型参数(整数,字符串,......)
  • 地图和清单
  • 功能评估
  • ...

Cor*_*onA 5

这就是我最后解决问题的方法:

想法是在解析器规则中启用/禁用空格:

 templateBody : {enableWs();} templateChunk* {disableWs();};
Run Code Online (Sandbox Code Playgroud)

因此,我们必须定义enableWsdisableWs在我们的解析器基类:

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

public void disableWs() {
    if (_input instanceof MultiChannelTokenStream) {
        ((MultiChannelTokenStream) _input).disable(HIDDEN);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在这是什么MultiChannelTokenStream

  • Antlr4定义了CommonTokenStream一个只能从一个通道读取的令牌流.
  • MultiChannelTokenStream是从已启用的通道读取的令牌流.为了实现,我采用了CommonTokenStream的源代码并将每个引用替换为channelby channels(等式比较得到包含比较)

上面的语法示例实现可以在antlr4multichannel找到