不知道大家了解Lucence这个项目么,一个开源的搜索引擎。不过想看懂很难,因为需要很多相关的知识,我这里就翻译了一篇文档,JavaCC技术手册之JJTree参考文档,Lucence在一些主要的文法分析中用到了JavaCC,而JJTree是JavaCC的一个预处理。下面就是翻译:
JavaCC技术手册:JJTree参考文档 [翻译:Kevin Wang]
简洁<o:p></o:p>
JJTree在JavaCC源代码的不同地方嵌入语法树构建动作,可以理解为JavaCC的预处理工具。通过运行JavaCC创建解析器生成JJTree输出文件。这篇文档描述了如何使用JJTree,以及如何从中分离你的解析器。
JJTree默认为每个非终结符生成代码来创建语法分析树节点。这种行为可以被修改以便于一些非终结符不生成节点或者因为一部分内容扩充而生成一个节点。
JJTree已经定义了一个所有语法分析树节点必须实现的接口Node,这个接口定义诸如:设置节点的父节点、增加子节点、重新获得子节点 等操作方法。
JJTree(为想要更多条件)可以设置 “simple” 和 “multi”两种模式之一。在“simple”[单一]模式下语法分析树节点都是“SimpleNode”这个具体类型。而在“multi”[多个]模式下语法分析树节点类型取决于节点的名字。如果你不为“Node”接口提供实现JJTree会为你生成一些基于“SimpleNode”的样品实现,你可以修改这个实现以适应需求。
虽然JavaCC是一个从顶至下的解析器(即LL(K) 通常我们只要用LL(1)即可 ),但是JJTree构造语法树过程却是从底至上构建的。为此使用堆栈,当他们被创建后它可以把节点压入堆栈中。当它找到一个父节点时,从堆栈中弹出子节点并且将其添加到父节点下,最后把新的父节点压入堆栈。堆栈是开放的意味着你可以使用内部语法行为对其访问:入堆栈,出堆栈,另外不管你有多么的适应请熟练使用它的内容。更多的重要信息请参看下面“节点作用域和用户行为”章节的介绍。
JJTree提供2种基本节点种类定义,可以依据造句法的缩写使其使用起来更方便。
1、 明确节点:一个以指定子节点数创建的节点。其中许多节点可以被弹出堆栈成为新节点的子节点,然后把这个新节点压入栈。你可以像这样定义一个明确节点:
#ADefiniteNode(INTEGER EXPRESSION)<o:p></o:p>
虽然INTEGER是目前为止使用最多的表达式,但明确节点参数“EXPRESSION”可以使用任何INTEGER 表达式。
2、 条件节点:当且仅当条件值为True时,带着所有被压入节点区域内部的子节点创建条件节点。如果条件值为False节点不会被创建,所有的子节点将残留在节点堆栈中。你可以像这样定义一个条件节点:
#ConditionalNode(BOOLEAN EXPRESSION)
一个条件节点描述符“EXPRESSION
”可以使用任何BOOLEAN
表达式。下边有2个常用的条件节点内容需要记忆:
1、不确定节点
#IndefiniteNode
是 #IndefiniteNode(true) 的简写
2、大节点
#GTNode(>1)
是 #GTNode(jjtree.arity() > 1) 的简写
在JJTree源代码中,当简写的不确定节点表达跟着一个括号表达式时,可能导致歧义。在那种情况下简写必须用完全写法替代。例如:
( ... ) #N ( a() )
上面表达式逻辑不清,你必须明确的使用条件式:
( ... ) #N(true) ( a() )
注意:节点描述符表达式不能有副作用,JJTree并没有指定表达式将被计算多少次。
默认情况下JJTree把每一个非终结符作为一个不确定节点对待,从它的产生式的名
字衍生出节点名字。也可以用下面的语法给他一个不同的名字:
void P1() #MyNode : { ... } { ... }
当解析器识别出了一个P1非终结符,它先定义一个节点,并在堆栈中进行标记,以便于一些由扩展P1非终结符而构建和入栈的分析树节点被弹出并成为 MyNode节点的子节点。
如果想要使某个产生式禁止创建节点,你可以使用下面的语法:
void P2() #void : { ... } { ... }
这样,一些根据非终结符入栈作为P2扩展的语法分析树节点会留在堆栈中,会被将来的产生式弹出作为其子节点,对
non-decorated[非包装]
节点
你也可以通过使用NODE_DEFAULT_VOID
选项使之成为默认行为。
void P3() : {}
{
P4() ( P5() )+ P6()
}
这个例子中,一个不确定的节点P3被启动并标记堆栈,然后是1个P4节点,1个或多个P5节点和1个P6节点被解析。被入堆栈的任何节点都会被弹出成为P3的子节点。你可以更深一步的定制生成树:
void P3() : {}
{
P4() ( P5() )+ #ListOfP5s P6()
我认为这里是P4() ( P5() ) #ListOfP5s + P6()<o:p></o:p>
}
现在P3节点会有一个P4节点、一个ListOfP5s节点和一个P6节点作为子节点。#Name结构表示一个后缀操作符,它的区域直接就是前面的扩展单元。
<o:p> </o:p>
节点作用域和用户行为<o:p></o:p>
每个节点都有其作用域。这个作用域内的用户行为可以通过使用特殊标志符“jjtThis
”来访问已被创建的节点。这个标志符被隐含的声明为节点的正确类型,这样此节点的一些字段、方法可以轻易的被访问。
一个作用域就是前面一个节点定义的扩展单位。这可能是一个括号表达式。当产生式符号被定义(或者是隐含定义的默认节点),它的作用域就是包括声明块在内的整个产生式的右侧。
你可以使用一个包括“jjtThis”扩展引用左侧的表达式。例如:
... ( jjtThis.my_foo = foo() ) #Baz ...
这里“jjtThis”引用了一个含有“my_foo
”字段的“Baz
”节点。foo()
产生式解析的结果是被赋给“my_foo
”。
节点作用域内用户的最终行为不同于所有的其他行为。当代码执行过程中,子节点已经被从堆栈中弹出并被添加给这个被压入堆栈的节点。这些孩子节点可以通过诸如这个节点的方法jjtGetChild()
.进行访问。除了最终用户行为之外的用户行为仅能访问堆栈中的子节点。此节点的方法对那些没有被赋给这个节点的孩子节点是无效的。
一个条件计算结果为False的条件表达式条件节点既不能被得到以添加到堆栈中,其孩子节点也不能被添加。条件节点作用域内的最终用户行为可以通过调用方法nodeCreated()
来
决定此节点是否被创建。如果节点条件被满足、节点被创建、并且被压入堆栈的话结果返回True,否则返回False。
<o:p> </o:p>
异常处理<o:p></o:p>
一个由节点作用域内扩展抛出却没有在节点作用域内捕获的异常将由JJTree自行处理。当这种情况发生时,那些再节点作用域内被压入堆栈的节点会被弹出堆栈并被抛弃。之后一个异常会被重新抛出。
这样做的意图是使分析其可以进行错误校验并且使节点堆栈继续处于一个可知的状态。
注意:一般JJTree 不能识别出此异常是否由节点作用于内用户行为抛出的。这样的异常有可能被不正确的处理。
<o:p> </o:p>
节点范围钩子<o:p></o:p>
如果NODE_SCOPE_HOOK
选项被置为True,JJTree会在每个节点作用域的入口和出口处调用用户自定义的2个解析器方法。这些方法必须有下面的形式:
void jjtreeOpenNodeScope(Node n)
void jjtreeCloseNodeScope(Node n)
如果解析器是静态的,那么这些方法也必须被声明成静态的。他们都以当前节点作为被调用的参数。
一种用途是这些功能将用来存储节点的首尾标记符以便于输入可以很容易的被重现。例如:
void jjtreeOpenNodeScope(Node n)
{
((MySimpleNode)n).first_token = getToken(1);
}
<o:p> </o:p>
void jjtreeCloseNodeScope(Node n)
{
((MySimpleNode)n).last_token = getToken(0);
}
基于SimpleNode
的MySimpleNode类中有下面2个额外的字段:<o:p></o:p>
Token first_token, last_token;
另外一个用途是用于将解析器对象自身存储于节点以便于状态可以被解析器提供的所有节点所共享。
节点的生存周期<o:p></o:p>
一个节点的建立经历了一个很好被确定的序列步骤。下面是从节点自身的透视图观察的序列。
1、创建节点需要一个独特的整形参量。这个参数确定了节点的种类,这在单一模式中有其有用。JJTree自动生成了一个声明了有效常量的类 parserTreeConstants.java 。 常量的名字取决于JJT前缀加文件中节点名字的大写字符串。用字符“.”代替字符“_” 。为方便起见,在同一个文件中维护了一个被称为jjtNodeName[]
的字符串数组,它遍历了节点的未修改名字的常量。<o:p></o:p>
2、节点的方法jjtOpen()
被调用<o:p></o:p>
3
、如果NODE_SCOPE_HOOK选项被设置为True,那么用户自定义的方openNodeScope()将被调用并且以此节点为参数。这个方法可以初始化节点的字段或者调用节点的方法。例如,他可以存储节点的首标记符。<o:p></o:p>
4
、如果一个节点被解析时抛出了一个未捕获的异常,节点将被抛弃。
JJTree将不再对其进行引用。虽然用户自定义的节点作用域钩子closeNodeHook()
将不再调用此节点作为参数,但
节点不会被关闭。<o:p></o:p>
5
、另外,如果一个条件节点的条件计算值为False,节点将被抛弃。虽然用户自定义节点作用域钩子closeNodeHook()可能调用此节点作为参数,但节点不会被关闭。<o:p></o:p>
6
、另外,一个明确节点通过整形表达式制定的所有孩子节点或者在一个条件节点作用域内被压入堆栈的所有节点被赋给此节点。他们的添加次序并没有被确定。<o:p></o:p>
7
、节点的方法jjtClose()被调用。<o:p></o:p>
8
、节点被压入堆栈。<o:p></o:p>
9
、如果NODE_SCOPE_HOOK选项被设置为True,则用户自定义方法closenNodeScope()将被调用并且以此节点作为参数。<o:p></o:p>
10
、如果节点不是根节点,他将作为其他节点的字节点被添加并且它的jjtSetParent()方法被调用。
<o:p> </o:p>
访问者支持<o:p></o:p>
JJTree为访问者提供了一些基本的设计模式。如果VISITOR
选项被设置为True,
JJTree将会在生成所有节点类时插入jjtAccept()
方法,并且生成一个以此节点为参数而被实现的访问者接口。[public Object visit(具体Node类,Object)]
访问者接口的名字由解析器名字加Visitor来构造。每当JJTree运行时接口会被生成,以便于他可以准确地表现解析其所使用的那些节点。如果实现类不能被新节点更新将会产生编译时错误。只是一个特性。
<o:p> </o:p>
选项<o:p></o:p>
JJTree在命令行或者JavaCC选项声明中提供了下面这些选项:
BUILD_NODE_FILES
(default: true
)<o:p></o:p>
为SimpleNode以及语法中使用的其它节点创建样本实现。
MULTI (default: false) <o:p></o:p>
创建多模式解析树。此选项默认为False,生成一个单一模式解析树。
NODE_DEFAULT_VOID
(default: false
)<o:p></o:p>
此选项设置为True时,不在使每个非包装产生式定义一个节点,取而代之为空。
NODE_FACTORY
(default: false
)<o:p></o:p>
用下面的方式使用一个工厂方法创建一个节点:
public static Node jjtCreate(int id)<o:p></o:p>
分享到:
相关推荐
JavaCC和JJTree是用于构建解析器和抽象语法树(AST)的工具,常用于编译器设计和解析复杂语法的场景。它们是Java语言的版本,类似于其他编程语言中的YACC和LEX。 1. **JavaCC**: - JavaCC(Java Compiler ...
NULL 博文链接:https://nemogu.iteye.com/blog/1508996
javacc学习手册 javacc是一款功能强大的编译器生成工具,可以生成词法分析器和语法分析器。下面是javacc的详细知识点: javacc安装 1. 安装JDK,并设置环境变量PATH路径。 2. 下载javacc,例如下载4.0版本的zip包...
- **语法树生成**: 新版本的JavaCC提供了如JJTree等工具,帮助开发者构建语法树,这对于理解和处理复杂的文本结构非常有用。 - **人性化的输入格式**: JavaCC的输入文件格式设计得更为直观易懂,使得开发者能够更...
1. **用户手册**:这份文档通常会阐述如何创建一个基本的JavaCC输入文件,即JJ文件,其中定义了语言的语法。它会讲解语法元素,如非终结符、终结符、选择、序列、重复等,并演示如何在JJ文件中使用它们。 2. **API...
相一致 JavaCC还提供JJTree工具来帮助我们建立语法树 JJDoc工具为我们的源文件生成BNF范式 巴科斯 诺尔范式 文档 Html ">JavaCC JavaCompilerCompiler 是一个用JAVA开发的最受欢迎的语法分析生成器 这个分析生成器...
这个工具基于经典的LL(k)和LR(1)解析技术,并且支持自定义语法和语义动作。在JavaCC 5.0版本中,用户可以构建复杂、高性能的解析器来处理特定的语言或协议。 JavaCC的工作原理是通过读取一个名为JavaCC语法规范(....
8. **JJTree工具**:JavaCC附带的JJTree工具用于生成AST节点类,使得用户可以自定义AST的结构和行为。 9. **可扩展性**:JavaCC允许用户插入自定义的Java代码,可以在解析过程中执行任意的Java逻辑,增强了工具的...
这100个示例覆盖了JavaCC的广泛应用,不仅适合初学者用来学习,也对经验丰富的开发者具有参考价值,可以帮助他们更好地利用JavaCC解决实际问题。通过逐一分析和实践,你可以逐步提升在编译原理和解析技术方面的技能...
2. **文档**:可能包含插件的用户手册、API参考文档或者快速入门指南,帮助开发者了解如何使用插件以及其功能。 3. **示例**:可能包含一些示例项目或测试用例,展示如何利用插件创建和测试词法分析器和解析器。 4. ...
4. `docs`目录:可能包含JavaCC的用户手册、API文档或其他帮助文档。 5. `samples`目录:可能包含一些示例文法文件和对应的解析器代码,供学习和参考。 安装JavaCC后,开发者可以通过命令行调用`javacc`工具,传入...
除了解析器生成器本身之外,JavaCC还提供了与解析器生成相关的其他标准功能,例如树构建(通过JavaCC附带的称为JJTree的工具),操作和调试。 一旦生成,运行JavaCC解析器所需的全部就是Java运行时环境(JRE)。 本...
- **辅助工具**:JavaCC配套提供了JJTree工具,用于生成语法树;JJDoc工具用于生成BNF范式的文档(HTML格式)。 #### 二、作业要求及实现细节 ##### 2.1 设计要求概述 - **目标**:设计一个类Pascal语言的语法分析...
10. **社区支持**:JavaCC有一个活跃的开发者社区,提供丰富的文档、示例和问题解答,帮助用户解决在使用过程中遇到的问题。 总之,JavaCC4.1源码对于学习编译原理、解析技术,或者构建自己的解析器和编译器的...
除了解析器生成器本身之外,JavaCC还提供其他与解析器生成相关的标准功能,例如树构建(通过JavaCC附带的称为JJTree的工具),操作和调试。 一旦生成,运行JavaCC解析器所需的全部就是Java运行时环境(JRE)。 本...
下载JavaCC的相应版本后,你可以根据提供的文档和示例学习如何使用它来创建自己的解析器。 总的来说,JavaCC-4.0和JavaCC-5.0是Java语言中用于生成解析器的重要工具,它们帮助开发者解析和理解结构化的输入数据,...
JavaCC(Java Compiler Compiler)是一种强大的词法和语法解析工具,用于生成Java源代码的解析器和词法分析器。这个工具广泛应用于处理结构化文本输入,如编程语言、配置文件或者任何需要解析的定制语言。JavaCC的...
由于其强大的能力和广泛的社区支持,JavaCC成为了Java开发人员构建自定义解析解决方案的首选工具之一。 总结起来,JavaCC是一个功能强大且灵活的Java语法分析工具,它允许开发者通过定义文法来生成解析器和词法分析...
这个版本可能包含了JavaCC的源代码、文档、示例以及相关的可执行文件。 JavaCC基于Java编程语言,它允许开发者使用BNF(巴科斯范式)语法来定义语言或数据格式的解析规则。在JavaCC中,你可以定义词法规则和语法...