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为标准实现提供一个,然后为每个变体对其进行子类化,但在开始解析之前我不知道它是哪个变体。

那么,如何在解析过程中从一个侦听器切换到另一个侦听器,或者一旦我知道我正在处理哪个变体,就使用新侦听器重新启动解析?

4

1 回答 1

2

如果这些变体频繁出现,您可能需要考虑嵌入自定义代码以使用谓词({...}?以下伪语法中的构造)来处理上下文相关解析:

rule
 : { boolean-expression-a }? a-alternative
 | { boolean-expression-b }? b-alternative
 | /* fall through */        not-a-or-b-alternative
 ;

假设您要解析包含chunks 的文件。Achunk由 aheaderdata一行组成。在header您可以设置您的变体。data正常变体的 包含 3 s NUMBER,Google 的变体包含 2 NUMBERs,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;

导致以下解析:

在此处输入图像描述

于 2013-07-19T09:51:13.987 回答