如何使用JavaCC / JJTree存储令牌?

时间:2010-11-22 16:05:11

标签: java parsing compiler-construction javacc

我为一种DSL编写了一个JJTree(JavaCC)配置,它成功地对给定格式的文件进行了标记,并在请求时转储AST。

问题是树中的每个节点都是空的,因为我目前没有存储令牌(我无法理解这些示例)。

这是我的.jjt文件的一部分:

SimpleNode Start() #Root : {} {
  (
    ( Section1() )?
    ( Section2() )?
    ( Section3() )*
  )  {
    return jjtThis;
  }
}

void Section3() #Section3 : {}
{
  < SECTION_3 > Identifier() <LBRACE >
    Header()
        (Details() < SEMICOLON > )*
  < RBRACE >
}

我希望根节点存储对Section1,Section2的引用以及对Section3的引用列表。我希望Section3节点存储标识符,标题块并保留详细信息块的列表。

我的填充.jjt文件是数百行,但我觉得如果我能理解这两个部分,那么我就能理解JJTree是如何工作的。请让我知道如何正确使用JJTree。

感谢。

1 个答案:

答案 0 :(得分:2)

如果查看SimpleNode类,您会注意到它的实例会自动存储对其父节点和子节点的引用(除非使用#void抑制它们的创建)。例如,您的根节点将包含对0..1 Section1节点,0..1 Section2节点和0 .. * Section3节点的引用,并且可以使用返回Node对象的jjtGetChild()方法访问它们。要确定此子节点是Section1,Section2还是Section3节点,可以调用其toString()方法(如dump()那样)。

或者,如果您厌倦了这种天真的Node迭代和toString检查,您可以定义自己的节点类型,而不是依赖于SimpleNode实现。在下面的示例中,Start()现在返回自定义RootNode而不是简单的SimpleNode。 RootNode包含对其子节点的特定引用(根据需要为这些节点定义getter)。请注意,我的简短代码段假定Section1 / 2/3()都返回自定义节点,但这不是 的情况......从你所说的,你想要一个自定义节点对于Section3()但如果Section1 / 2很简单,您可以将它们保留为SimpleNodes。

RootNode Start() : 
{
  Section1Node s1Node = null;
  Section2Node s2Node = null;

  List s3Nodes = new LinkedList();
  Section3Node s3Node = null;
} 
{
  (
    ( s1Node = Section1() )?
    ( s2Node = Section2() )?
    ( s3Node = Section3() {s3Nodes.add(s3Node); } )*
  )  {

    return new RootNode(s1Node, s2Node, s3Nodes);
  }
}

如果您正在遍历解析树并对节点执行复杂的操作,那么将其中的一些移动到Visitor class可能是个好主意,这样您对节点执行的操作就会脱离节点类本身。最终可能会有几个访问者类,每个访问者类在解析树上执行一个函数,并且对每种类型的节点都有访问方法重载。

让我知道你有什么不明白的地方。我不是JavaCC专家(我在大学曾经使用它一次)但我应该能够帮助你:)