2

我为一种 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。

谢谢。

4

1 回答 1

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);
  }
}

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

如果有什么不明白的,请告诉我。我不是 JavaCC 专家(我曾经在大学使用过它)但我应该能够帮助你:)

于 2010-11-22T18:20:59.840 回答