ANTLR4 在解析过程中的变化监听器

3
我是一位有用的助手,可以为您翻译文本。
我有一个ANTLR4监听器,处理标准且格式良好的语法,但是在处理非标准实现时遇到了困难。尽管所有变体都没有问题地通过了词法分析器,但解析阶段要棘手得多。
传统的做法可能是这样的:
// Header of document
variant = STANDARD;
if (header.indexOf("microsoft") != -1) {
  variant = MICROSOFT;
} else if (header.indexOf("google") != -1) {
  variant = GOOGLE;
}

...

// Parsing a particular element
if (variant.equals(MICROSOFT)) {
  // Microsoft-specific stuff
} else if (variant.equals(GOOGLE)) {
  // Google-specific stuff
} else {
  // Standard stuff
}

但这很快就会变得难以维护。显而易见的解决方案是为标准实现创建一个ParseTreeListener,然后为每个变体创建子类,但在开始解析之前我不知道它是哪个变体。
那么,我如何在解析过程中部分切换到另一个监听器,或者一旦知道我正在处理哪个变体,就使用新的监听器重新启动解析?
1个回答

2
如果这些变体经常出现,您可能需要考虑嵌入自定义代码来处理上下文敏感的解析,使用谓词(在以下伪语法中使用{...}?结构)。
rule
 : { boolean-expression-a }? a-alternative
 | { boolean-expression-b }? b-alternative
 | /* fall through */        not-a-or-b-alternative
 ;

假设您想解析包含 chunk 的文件。一个 chunkheaderdata 行组成。在 header 中,您可以设置您的变量。普通变量的 data 包含3个 NUMBER,Google的变量包含2个 NUMBER,而Microsoft的变量包含一个单独的 NUMBER。这样一个文件的示例如下:

header: none
data: 1 2 3 
header: google
data: 4 5
header: microsoft
data: 6

以下是一个上下文敏感的 ANTLR v4 语法的演示,可以解析这个:

grammar T;

@parser::members {

  enum Variant { 

    GOOGLE, 
    MICROSOFT, 
    OTHER; 

    public static Variant tryValueOf(String name) {
      try {
        return Variant.valueOf(name.toUpperCase());
      }
      catch(Exception e) {
        return OTHER;
      }
    }
  } 

  private Variant variant = Variant.OTHER;
}

parse
 : chunk+ EOF
 ;

chunk
 : header data
 ;

header
 : K_HEADER COLON NAME {variant = Variant.tryValueOf($NAME.text);}
 ;

data
 : {variant == Variant.MICROSOFT}? K_DATA COLON NUMBER               #MicrosoftData
 | {variant == Variant.GOOGLE}?    K_DATA COLON NUMBER NUMBER        #GoogleData
 |                                 K_DATA COLON NUMBER NUMBER NUMBER #OtherData
 ;

K_DATA   : 'data';
K_HEADER : 'header';
NAME     : [a-zA-Z]+;
NUMBER   : [0-9]+;
COLON    : ':';
SPACE    : [ \t\r\n] -> skip;

导致以下解析结果:

enter image description here


这对我来说感觉就像是Java中的相同if/then/else混乱,只是被推到了一个级别。我希望有一种重置监听器并重新启动解析的方法(因为我应该在解析的早期了解变体)。 - user1596371
@jgm 我不确定你如何在Java中实现它,但我认为内联的ANTLR谓词会更简洁,并且会生成反映你的变体的解析树。我还没有研究过重置监听器和访问者,但稍后我会仔细看一下并在找到相关信息后更新答案。 - Bart Kiers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接