ANTLR4在解析期间更改侦听器

时间:2013-07-19 08:52:22

标签: antlr antlr4

我有一个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 个答案:

答案 0 :(得分: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