如何使用JavaCC / JJTree来存储令牌?
我已经为一种 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 节点存储标识符、标题块并保留详细信息块的列表。
我的 fill .jjt 文件有数百行,但我觉得如果我能理解这两部分,那么我就能理解 JJTree 的工作原理。请让我知道如何正确使用 JJTree。
谢谢。
I have written a JJTree (JavaCC) configuration for a type of DSL and it successfully tokenizes a given format of file and will dump the AST when requested.
The problem is that each of the nodes in the tree is empty as I am not currently storing the tokens (I can't understand the examples).
Here is part of my .jjt file:
SimpleNode Start() #Root : {} {
(
( Section1() )?
( Section2() )?
( Section3() )*
) {
return jjtThis;
}
}
void Section3() #Section3 : {}
{
< SECTION_3 > Identifier() <LBRACE >
Header()
(Details() < SEMICOLON > )*
< RBRACE >
}
I would like the root node to store references to Section1, Section2 and a list of references to Section3. I would like the Section3 node to store the identifier, the header block and keep a list of the details block.
My fill .jjt file is hundreds of lines, but I feel that if I can understand it for these two sections then I can understand how JJTree works. Please let me know how to use JJTree properly.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您查看 SimpleNode 类,您会注意到它的实例自动存储对其父节点和子节点的引用(除非使用 #void 禁止创建它们)。例如,您的根节点将包含对 0..1section1 节点、0..1section2 节点和 0..*section3 节点的引用,并且可以使用返回 Node 对象的 jjtGetChild() 方法来访问它们。要确定该子节点是Section1、Section2还是Section3节点,可以调用其toString()方法(如dump())。
或者,如果您厌倦了这种朴素的 Node 迭代和 toString 检查的风格,您可以定义自己的节点类型,而不是依赖于 SimpleNode 实现。在下面的示例中,Start() 现在返回一个自定义 RootNode,而不是普通的 SimpleNode。 RootNode 包含对其子节点的特定引用(根据您认为合适的方式为这些子节点定义 getter)。请注意,我的简短片段假设Section1/2/3()都返回自定义节点,但事实并非如此......根据您所说,您需要一个自定义节点对于Section3(),但如果Section1/2很简单,您可以将它们保留为SimpleNodes。
如果您正在遍历解析树并使用节点执行复杂的操作,则将其中一些移动到 访问者类,以便您对节点所做的操作与节点类本身解耦。您最终可能会得到几个访问者类,每个访问者类在解析树上执行一个功能,并且对每种类型的节点都有访问方法重载。
如果有什么不明白的地方请告诉我。我不是 JavaCC 专家(我在大学用过一次)但我应该能够帮助你:)
If you look at the SimpleNode class, you'll notice that its instances automatically store references to their parent and children nodes (unless their creation was suppressed using #void). For example, your root node will contain references to 0..1 Section1 nodes, 0..1 Section2 nodes and 0..* Section3 nodes and they can be accessed using the jjtGetChild() method which returns a Node object. To determine whether this child node is a Section1, Section2 or Section3 node, you could call its toString() method (as dump() does).
Alternatively, if you get sick of this style of naive Node iteration and toString checking, you can define your own node types instead of relying on the SimpleNode implementation. In my example below, Start() now returns a custom RootNode instead of a plain SimpleNode. RootNode contains specific references to its children nodes (define getters for these as you see fit). Note that my brief snippet assumes Section1/2/3() all return custom nodes, but this doesn't have to be the case... from what you said, you'd want a custom node for Section3() but if Section1/2 are trivial, you might leave them as SimpleNodes.
If you're traversing your parse tree and doing complex things with your nodes, it might be a good idea to move some of it to a Visitor class so that what you're doing with your nodes is decoupled from the node classes themselves. You might end up with several visitor classes which each perform a function on the parse tree and have visit method overloads for each type of node.
Let me know if there's anything you don't understand. I'm no JavaCC expert (I used it at uni once) but I should be able to help you :)