Antlr AST产生(可能)疯狂

时间:2010-09-26 21:25:39

标签: antlr antlr3 antlrworks

以下甚至可能吗?我想“反转”给予antlr的输入并使每个标记成为前一个标记的子标记。

因此,对于输入(假设每个标记由'。'字符分隔):

Stack.Overflow.Horse

我希望我的语法产生以下AST:

Horse
  |---Overflow
         |---Stack

到目前为止,我已经成功地扭转了节点,但我无法让他们成为彼此的孩子:

function
 : ID PERIOD function
   -> function ID
 | ID
 ;

ID  : 'a'..'z'*
    ;

1 个答案:

答案 0 :(得分:3)

我认为没有一种简单的方法可以做到这一点。你可以这样制定你的规则:

function
 : ID PERIOD function
   -> ^(function ID)
 | ID
 ;

但这只会使最后一个节点成为根,所有其他节点成为子节点。例如,以下来源:

a.b.c.d.e

将导致以下树:

    e
 / / \ \
d c   b a

我无法看到一个简单的修复方法,因为当您第一次解析a.b.c.d.e时,aIDb.c.d.e递归调用function

a.b.c.d.e
| +-----+
|    |
|    `-----> function
|
`----------> ID

导致b.c.d.ea作为其子级。当b成为ID时,它也会作为a旁边的子项添加。在您的情况下,a应该作为孩子删除,然后添加到b的孩子列表中。但是AFAIK,这在ANLTR中是不可能的(至少,在语法中不是一个干净的方式)。


修改

好吧,作为一个解决方案,我有一些优雅的想法,但这并没有像我希望的那样工作。因此,作为一个不太优雅的解决方案,您可以将last节点与重写规则中的根匹配:

function
  :  (id '.')* last=id -> ^($last)
  ;

然后使用children运算符收集List中所有可能的先前节点(+=):

function
  :  (children+=id '.')* last=id -> ^($last)
  ;

并在解析器中使用自定义成员方法将这些children“注入”到树的根目录中(在List中从右到左!):

function
  :  (children+=id '.')* last=id {reverse($children, (CommonTree)$last.tree);} -> ^($last)
  ;

一个小小的演示:

grammar ReverseTree;

options {
  output=AST;
}

tokens {
  ROOT;
}

@members {
  private void reverse(List nodes, CommonTree root) {
    if(nodes == null) return;
    for(int i = nodes.size()-1; i >= 0; i--) {
      CommonTree temp = (CommonTree)nodes.get(i);
      root.addChild(temp);
      root = temp;
    }
  }
}

parse
  :  function+ EOF -> ^(ROOT function+)
  ;

function
  :  (children+=id '.')* last=id {reverse($children, (CommonTree)$last.tree);} -> ^($last)
  ;

id 
  :  ID
  ;

ID
  :  ('a'..'z' | 'A'..'Z')+
  ;

Space
  :  ' ' {skip();}
  ;

还有一个小测试班:

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;

public class Main {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("a.b.c.d.e    Stack.Overflow.Horse    singleNode");
        ReverseTreeLexer lexer = new ReverseTreeLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        ReverseTreeParser parser = new ReverseTreeParser(tokens);
        ReverseTreeParser.parse_return returnValue = parser.parse();
        CommonTree tree = (CommonTree)returnValue.getTree();
        DOTTreeGenerator gen = new DOTTreeGenerator();
        StringTemplate st = gen.toDOT(tree);
        System.out.println(st);
    }
}

将产生一个看起来像这样的AST:

alt text

输入字符串:

"a.b.c.d.e    Stack.Overflow.Horse    singleNode"