如何避免使用ANTLR3构建中间体和无用的AST节点?

时间:2011-05-17 12:08:56

标签: parsing antlr antlr3 abstract-syntax-tree

我写了一个ANTLR3语法,细分为较小的规则以提高可读性。 例如:

messageSequenceChart:
  'msc' mscHead bmsc 'endmsc' end
;

# Where mscHead is a shortcut to :
mscHead:
  mscName mscParameterDecl? timeOffset? end
  mscInstInterface? mscGateInterface
;

我知道内置的ANTLR AST构建功能允许用户声明不在最终AST中的中间AST节点。但是如果你手工构建AST呢?

messageSequenceChart returns [msc::MessageSequenceChart* n = 0]:
  'msc' mscHead bmsc'endmsc' end
  {
    $n = new msc::MessageSequenceChart(/* mscHead subrules accessors like $mscHead.mscName.n ? */
                                       $bmsc.n);
  }
;

mscHead:
  mscName mscParameterDecl? timeOffset? end
;

文档没有谈论这样的事情。所以看起来我必须为每个中间规则创建节点才能访问它们的子规则结果。

有谁知道更好的解决方案?

谢谢。

1 个答案:

答案 0 :(得分:2)

您可以通过让您的子规则返回多个值并仅访问您感兴趣的值来解决此问题。

以下演示说明了如何执行此操作。虽然它不在C中,但我相信你能够调整它以满足你的需求:

grammar Test;

parse
  :  sub EOF {System.out.printf("second=\%s\n", $sub.second);}
  ;

sub returns [String first, String second, String third]
  :  a=INT b=INT c=INT
     {
       $first = $a.text;
       $second = $b.text;
       $third = $c.text;
     }
  ;

INT
  :  '0'..'9'+
  ;

SPACE
  :  ' ' {$channel=HIDDEN;}
  ;

如果使用生成的解析器解析输入"12 34 56",则会在控制台上打印second=34,如运行后所示:

import org.antlr.runtime.*;

public class Main {
  public static void main(String[] args) throws Exception {
    TestLexer lex = new TestLexer(new ANTLRStringStream("12 34 56"));
    TokenStream tokens = new TokenRewriteStream(lex);
    TestParser parser = new TestParser(tokens);
    parser.parse();
  }
}

因此,来自parse规则的快捷方式,例如$sub.INT$sub.$a来访问中的三个INT代币之一可能,不幸的是。