收藏 分享(赏)

javacc学习心得.doc

上传人:gnk289057 文档编号:6103021 上传时间:2019-03-27 格式:DOC 页数:24 大小:134KB
下载 相关 举报
javacc学习心得.doc_第1页
第1页 / 共24页
javacc学习心得.doc_第2页
第2页 / 共24页
javacc学习心得.doc_第3页
第3页 / 共24页
javacc学习心得.doc_第4页
第4页 / 共24页
javacc学习心得.doc_第5页
第5页 / 共24页
点击查看更多>>
资源描述

1、简介:JavaCC 是一个词法分析生成器和语法分析生成器。词法分析和语法分析是处理输入字符序列的软件构件,编译器和解释器协同词法分析和语法分析来“解密”程序文件,不仅如此,词法分析和语法分析有更广泛的用途,我希望在本书列举的例子中能阐明这一点。那么什么是词法分析器和语法分析呢?词法分析器可以将字符串解析为一个一个的标识符(Token),并且可以把这些标识符归类。看一段 C 语言代码:int main() return 0 ;C 语言的词法分析器会把这段代码分解为如下的一些标识符:“int”, “ ”, “main”, “(”, “)”,“ ”, “”, “n”,“t”, “return”“ ”

2、, “0”, “ ”, “;”, “n”,“”, “n”, “”。还会把这些标识符归类,在我们的例子中,这些标识符的类别为:KWINT, SPACE, ID, OPAR, CPAR,SPACE, OBRACE, SPACE, SPACE, KWRETURN,SPACE, OCTALCONST, SPACE, SEMICOLON, SPACE,CBRACE, SPACE, EOF。其中 EOF 类别的标识符代表源文件的结束。这些标识符出传送给语法分析器。在 C 语言中,语法分析不需要所有的这些类别,在本例中 SPACE 类别的标识符不传送给语法分析器。语法分析器会分析这些标识符,判断程序的结构。

3、在许多编译程序中,语法分析器用语法树来表示程序的结构。编译器通过这棵树来产生代码。看一个表达式:fahrenheit = 32.0 + 9.0 * celcius / 5.0 ;语法分析器基于语言规则分析这个表达式产生一棵树:DIAGRAM TBD(表示作者未完成)如果输入没有语言的词法或语法,词法分析器或语法分析器都能产生错误信息。JavaCC 并不是一个词法分析器或者语法分析器,它只是一个生成器。就是说,它读取文本后,基于一定的规则产生词法分析器和语法分析器的 Java 代码。见图:DIAGRAM TBD词法分析和语法分析变的越来越复杂,软件工程师直接用 Java 进行词法分析和语法分析时

4、必须要充分考虑各规则间的相互作用。例如,在对 C 语言的词法分析中,处理整型常量和浮点常量的代码是不能分开的,因为浮点数和整数的前面部分是一样的。使用诸如 JavaCC 语法分析产生器,对整型常量 和浮点常量是可以区分的,它们的共同点可在代码生成过程中提取出来。这种模块性意味着 JavaCC 文件比直接的 Java 程序更容易写,更容易读,也更容易 修改。通过 JavaCC 语法分析生成器的使用,软件工程师可以节省大量的时间,并且软件的质量也更高。javaCC 有三 个工具:javaCC 用来处理语法文件(jj )生成解析代码;jjTree 用来处理 jjt 文件,生成 树节点代码和 jj 文

5、件,然后再通 过 javaCC 生成解析代码;jjDoc 根据 jj 文件生成 bnf 范式文档(html) 。这三个工具都十分重要,分别贯穿着编写时的过程。其中具体阐述一下 jjTree 方面( 查考资料) ,JJTree 定义了 Java 接口节点,所有分析树节点都必须执行。该接口提供的方法操作,如母公司设置的节点,新增的儿童和检索它们。JJTree 经营 有两种 模式,简单 的和多(由于缺乏更好的条 件) 。在简单模式剖析每个树节点的具体类型 SimpleNode ;在多模式的类型分析树节 点是源自名称节点。如果您没有提供实现的节点班 JJTree 将产生 样本的基础上实现 Simple

6、Node 你。然后,您就可以修改,以适应实施。 虽然 JavaCC 是一个自上而下分析器, JJTree 构造解析树自下而上。要做到这一点它使用堆栈的地方后,把他们的节点已经建立。当它发现了他们父母,它的持久性有机污染物的儿童从堆栈,并增加了他们的父母,并最终推动新的父节点本身。堆栈是开放的,这意味着你有机会获得它从语法行动:你可以推,流行和其他操纵其内容但是你觉得合适的。见节点范围和使用者的动作,下面的更重要的信息。 JJTree 提供装 饰两个 基本品种 的节点,和一些语法速记,使 它们的使用便利然后简单介绍一下 javaCC 的安装过程,1. 安装 jdk,安装完成后设置 环境变量 PA

7、TH 路径。 (这个不用多说了吧,学过 java 的人早已会)2.下载 javacc,直接在其官方网站上下载,地址 https:/。我有的是老师给的压缩包 javacc-4.0.zip,就更方便了。3.解压缩 javacc-4.0.zip 到任意目录,将其 bin 目录设置为环 境变量 PATH 路径。4.打开 dos,进入 javacc 的解压目录,然后进入其 examplesMailProcessing 目录。按照readme 上面的指示运行:javacc Digest.jjjavacc Faq.jjjavac *.javajava Digest digestFilejava Faq 5.

8、打开新生成的 digestFile 和 sampleMailFile 查看效果。包中自带了许多 javaCC 的相关例子,方便于我们编写自己的程序。现在就可以开始 javaCC 的旅行啦。通过上学期编译原理的学习我们知道了编译代码需要词法分析和语法分析,但是JavaCC 并不是一 个词法分析器或者语法分析器,它只是一 个生成器,所以对应这两方面,它就相似于 Lex 和 Yacc,但是是属于 java 下的 Lex 和 Yacc,它们分工执行,简单的说它们目的就是用来写 Parser,功能上大致相似于 Yacc,但如今的 词法分析语法分析变的越来越复杂,所以进行分析的时候又必须考虑到它们之间的相

9、互作用,使用 javaCC 可以更灵活的处理词法分析和语法分析。解析器(Parser)和词法分析器 (Lex)往往是长期和复杂的组成部分。系数词法分析器分析仪或直接在 Java 已经仔细考 虑之间的互动规则。例如在一个词汇分析器的 C ,代码处理整 数常量和浮点常量不能分 开,因为浮点常数和整数是类似的。使用分析器发生器如 JavaCC ,规则的整数常量和浮点 常量分别与它们之间的共同点是在提取生成过程。这增加了模块化意味着规范文件更容易编写,阅读,以及修改与手写 Java程序。通过使用 JavaCC ,软件工程师可以节省大量的 时间和生产软件的组成部分使质量更好。接下来我们来了解一下刚刚一直

10、在提到的 Lex 和 Yacc。Lex 是一种生成扫描器的工具。扫描器是一种识别文本中的词汇模式的程序。一种匹配的常规表达式可能会包含相关的动作。这一动作可能还包括返回一个标记。当 Lex 接收到文件或文本形式的输入时,它试图将文本与常规表达式进行匹配。它一次读入一个输入字符,直到找到一个匹配的模式。如果能够找到一个匹配的模式,Lex 就执行相关的动作(可能包括返回一个标记) 。另一方面,如果没有可以匹配的常规表达式,将会停止进一步的处理,Lex 将显 示一个错误 消息。Lex 和 C 是强耦合的。一个 .lex 文件(Lex 文件具有 .lex 的扩展名)通 过 lex 公用程序来传递,并生

11、成 C 的输出文件。这些文件被编译为词法分析器的可执行版本。而我们这次是为 CMM 语言构造编译器,则比 C 要更加简洁一些。既然 Lex 是生成 词法分析的工具,而 词法分析是对代 码中所读到的信息进行分析提炼,所以在 Lex 中必然要指明 这些字符 标记,下面这个表格定 义了 Lex 中的一些标记从而定义一些常规表达式。Lex 中的一些标记字符字符 含义 A-Z, 0-9, a-z 构成了部分模式的字符和数字。. 匹配任意字符,除了 n。- 用来指定范围。例如:A-Z 指 从 A 到 Z 之间的所有字符。 一个字符集合。匹配括号内的 任意 字符。如果第一个字符是 那么它表示否定模式。例如:

12、 abC 匹配 a, b, 和 C 中的任何一个。 * 匹配 0 个 或者多 个上述的模式。 + 匹配 1 个 或者多 个上述模式。 ? 匹配 0 个 或 1 个 上述模式。 $ 作为模式的最后一个字符匹配一行的结尾。 指出一个模式可能出现的次数。 例如: A1,3 表示 A 可能出现 1 次或 3 次。 用来转义元字符。同样用来覆盖字符在此表中定义的特殊意义,只取字符的本意。 否定。| 表达式间的逻辑或。“ 字符的字面含义。元字符具有。/ 向前匹配。如果在匹配的模版中的“/”后跟有后续表达式,只匹配模版中“/”前面的部分。如:如果输入 A01,那么在模版 A0/1 中的 A0 是匹配的。(

13、) 将一系列常规表达式分组。知道了 Lex 的基本的 标记字符,那 怎么用 Lex 进行基本的 编程而得到词法分析器呢?主要概括为三步:1 以 Lex 可以理解的格式指定模式相 关的动作。2 在这一文件上 运行 Lex,生成 扫描器的代码。3 编译和链接代 码,生成可 执行的扫描器。 (如果本来机器上没有任何编译工具怎么办?) 如今知道了词法分析产生的方法,让我们来看看语法分析吧,提到语法分析就要说到我们刚刚说到的 Yacc,即 Yet Another Compiler Compiler。它是一种工具,将任何一种编程语言的所有语法翻译成针对此种语言的 Yacc 语法解析器。它用巴科斯范式(BN

14、F, Backus Naur Form)来书写。Lex 和 Yacc 本来是 UNIX 中的强大工具,但如今已经被广泛的应用在了 Windows 的平台下。我们看到,Lex 是从我们的输入序列中 识别标记,而当你看到这个序列时可能会想这个序列出现是要执行什么样的动作,而语法指的就是有效序列的规范,而 Yacc 的语法文件恰好包括这一语法规范,它包含了序列匹配是 你想做的事。一句话来概括就是:标记本身来自语言(Lex) ,并且标记序列允许用 Yacc 来指定这些标记 。安装:1、JavaCC2.1 的安装: (此处假定你已正确安装 Java2 JDK 1.4 或更新的版本。 ) JavaCC2.

15、1 是以一个 .class 文件的方式提供的,下载并执行如下命令 c:java $JAVACC_DIRJavaCC_1 ($JAVACC_DIR 指 JavaCC在你的系统中的目录) 稍等片刻,系统便会弹出 GUI 安装界面,之后当然就十分简单了。 2、JavaCC3.2 的安装: 哈哈,这就更简单了,只需要将 ZIP 包解压缩即可。官方文档中是这样说的: Depending on which you downloaded, you should go to the Directory where the file was installed and type something like:

16、unzip javacc-3.0.zip or gunzip javacc-3.0.tar.gz tar xvf javacc-3.0.tar That completes your installation. Javacc 的输入文件Javacc 的输入文件格式做得比较简单.每个非终结符产生式对应一个 Class 中的函数,函数中可以嵌入相应的识别出该终结符文法时候的处理代码(也叫动作).这个与 YACC 中是一致的.Javacc 的输入文件中,有一系列的系统参数,比如其中 lookahead 可以设置成大于 1 的整数,那么就是说,它可以为我们生成 LL(k)算法(k=1),而不是简单的递

17、归下降那样的 LL(1)算法了.要知道,LL(2)文法比起前面讨论的 LL(1)文法判断每个非终结符时候需要看前面两个记号而不是一个,那么对于文法形式的限制就更少.不过 LL(2)的算法当然也比 LL(1)算法慢了不少.作为一般的计算机程序设计语言,LL(1)算法已经是足够了.就算不是 LL(1)算法,我们也可以通过前面讲的左提公因式把它变成一个 LL(1)文法来处理.不过既然 javacc 都把 lookahead 选择做出来了,那么在某些特定的情况下,我们可以直接调整一个 lookahead 的参数就可以,而不必纠正我们的文法.下面我们来看看 Javacc 中自带的 example 中的例

18、子.例 1这个例子可以在 javacc-3.2/doc/examples/SimpleExamples/Simple1.jj 看到PARSER_BEGIN(Simple1)public class Simple1 public static void main(String args) throws ParseException Simple1 parser = new Simple1(System.in);parser.Input();PARSER_END(Simple1)void Input() :MatchedBraces() (“n“|“r“)* void MatchedBraces(

19、) :“ MatchedBraces() “设置好 javacc 的 bin 目录后,在命令提示符下输入javacc Simple1.jj然后 javacc 就会为你生成下面几个 java 源代码文件Simple1.javaSimple1TokenManager.javaSimple1Constants.javaSimpleCharStream.javaToken.javaTokenMgrError.java其中 Simple1 就是你的语法分析器的对象,它的构造函数参数就是要分析的输入流,这里的是 System.in. class Simple1 就定义在标记 PARSER_BEGIN(Si

20、mple1)PARSER_END(Simple1)之间.但是必须清楚的是,PARSER_BEGIN 和 PARSER_END 中的名字必须是词法分析器的名字(这里是 Simple1).PARSER_END 下面的定义就是文法非终结符号的定义了.Simple1 的文法基本就是:Input - MatchedBraces (“n“|“r“)* MatchedBraces - “ MatchedBraces “”从它的定义我们可以看到,每个非终结符号对于一个过程.比如 Input 的过程void Input() :MatchedBraces() (“n“|“r“)* 在定义 void Input 后

21、面记住需要加上一个冒号”:”,然后接下来是两个块的定义.第一个中的代码是定义数据,初试化数据的代码.第二个中的部分就是真正定义 Input 的产生式了.每个产生式之间用”|”符号连接.注意: 这里的产生式并非需要严格 BNF 范式文法,它的文法既可以是 BNF,同时还可以是混合了正则表达式中的定义方法.比如上面的 Input - MatchedBraces (“n“|“r“)* 中(“n”|”r”)* 就是个正则表达式,表示的是n 或者r 的 0 个到无限个的重复的记号.而是 javacc 系统定义的记号(TOKEN),表示文件结束符号.除了,无论是系统定义的 TOKEN,还是自定义的 TOK

22、EN, 里面的 TOKEN 都是以的方式表示.每个非终结符号(Input 和 MatchedBraces)都会在 javacc 生成的 Simple1.java 中形成 Class Simple1 的成员函数.当你在外部调用 Simple1 的 Input,那么语法分析器就会开始进行语法分析了. 例 2在 javacc 提供的 example 里面没有.javacc 提供的 example 里面提供的例子中 SimpleExamples 过于简单,而其它例子又过于庞大.下面我以我们最常见的数学四则混合运算的文法来构造一个 javacc 的文法识别器.这个例子是我自己写的,十分简单,.其中还包括

23、了文法识别同时嵌入的构建语法树 Parse-Tree 的代码.不过由于篇幅的原因,我并没有给出全部的代码,这里只给了 javacc 输入部分相关的代码.而 Parse-tree 就是一个普通的 4 叉树,3个 child,1 个 next(平行结点),相信大家在学习数据结构的时候应该都是学过的.所以这里就省略过去了.在大家看这些输入代码之前,我先给出它所使用的文法定义,好让大家有个清楚的框架.Expression - Term Addop Term Addop - “+“ | “-“Term - Factor Mulop Factor Mulop - “*“ | “/“Factor - ID

24、| NUM | “(“ Expression “)“这里的文法可能和 BNF 范式有点不同.的意思就是 0 次到无限次重复,它跟我们在学习正则表达式的时候的”*”符号相同,所以,在 Javacc 中的文法表示的时候, 部分的就是用()*来表示.为了让词法分析做得更简单,我们通常都不会在文法分析的时候,使用”(”,”)“等字符号串来表示终结符号,而需要转而使用 LPAREN, RPAREN 这样的整型符号来表示.PARSER_BEGIN(Grammar)public class Grammar implements NodeType public ParseTreeNode GetParseTr

25、ee(InputStream in) throws ParseExceptionGrammar parser =new Grammar(in);return parser.Expression();PARSER_END(Grammar)SKIP :“ “ | “t“ | “n“ | “r“TOKEN :| | | | | | | ParseTreeNode Expression() :ParseTreeNode ParseTree = null;ParseTreeNode node; ( node=Simple_Expression()if(ParseTree = null)ParseTree

26、 =node;elseParseTreeNode t;t= ParseTree;while(t.next != null)t=t.next;t.next = node;)* return ParseTree;ParseTreeNode Simple_Expression() :ParseTreeNode node;ParseTreeNode t;int op;node=Term()(op=addop() t=Term()ParseTreeNode newNode = new ParseTreeNode();newNode.nodetype = op;newNode.child0 = node;

27、newNode.child1 = t;switch(op)case PlusOP:newNode.name = “Operator: +“;break;case MinusOP:newNode.name = “Operator: -“;break;node = newNode;)* return node; int addop() : return PlusOP; | return MinusOP; ParseTreeNode Term() :ParseTreeNode node;ParseTreeNode t;int op;node=Factor()(op=mulop() t=Factor(

28、)ParseTreeNode newNode = new ParseTreeNode();newNode.nodetype = op;newNode.child0 = node;newNode.child1 = t;switch(op)case TimersOP:newNode.name = “Operator: *“;break;case OverOP:newNode.name = “Operator: /“;break;node = newNode;)*return node;int mulop() : return TimersOP; | return OverOP; ParseTree

29、Node Factor() :ParseTreeNode node;Token t;t=node=new ParseTreeNode();node.nodetype= IDstmt;node.name = t.image;return node;|t=node=new ParseTreeNode();node.nodetype= NUMstmt;node.name = t.image;node.value= Integer.parseInt(t.image);return node;| node=Simple_Expression() return node;其中 SKIP 中的定义就是在进行

30、词法分析的同时,忽略掉的记号.TOKEN 中的,就是需要在做词法分析的时候,识别的词法记号.当然,这一切都是以正则表达式来表示的.这个例子就有多个非终结符号,可以看出,我们需要为每个非终结符号写出一个过程.不同的非终结符号的识别过程中可以互相调用. 以 Simple_Expression()过程为例,它的产生式是 Expression - Term addop Term ,而在 javacc 的输入文件格式是,它的识别是这样写的 node=Term() ( op=addop() t=Term() )* 前面说过,这里的”*”符号和正则表达式是一样的,就是 0 次到无限次的重复.那么Simple

31、_Expression 等于文法 Term Addop Term Addop Term Addop Term 而 Addop 也就相当于 PLUS 和 MINUS 两个运算符号.这里我们在写 Expression 的文法的时候,同时还使用了赋值表达式,因为这个和 Yacc 不同的时候,Javacc 把文法识别完全地做到了函数过程中,那么如果我们要识别 Simple_Expression 的文法,就相当于按顺序识别 Term 和 Addop 两个文法,而识别那个文法,就相当于调用那两个非终结符的识别函数.正是这一点,我觉得 Javacc 的文法识别处理上就很接近程序的操作过程,我们不需要像 YA

32、CC 那样使用严格的文法表示格式,复杂的系统参数了.关于 Yacc 的使用,其实比 Javacc 要复杂,还需要考虑到和词法分析器接口的问题,这个我会在以后细细讲到.至于其它的文法操作解释我就不再多说了,如果要说,就是再写上十篇这样的文章也写不完.本文只能给读者们一个方向,至于深入的研究,还是请大家看 javacc 提供的官方文档资料.javaCC 的使用 javaCC 生成的文件中,最主要的是Grammar.java 这个就是解析器的主程序了了,Grammar名由 jj 中定义。 现在根据例子说明 jj 文件的定义: BNF 范式为: EXPression := ( ( )* Simple_

33、Expression )* Simple_Expression := Term ( addop Term )* addop := Term := Factor ( mulop Factor )* mulop := Factor := Simple_Expression /*这是一个整数的四则运算的例子 */ /* 运行 javaCC Grammar.jj javac *.java java Grammar 1+1*(1+1) 3 Z */ PARSER_BEGIN(Grammar) /*解析代码的入口*/ public class Grammar public static final int

34、 PlusOP=1; public static final int MinusOP=2; public static final int TimersOP=3; public static final int OverOP=4; public static void main(String args) throws ParseException Grammar parser = new Grammar(System.in); parser.Expression(); PARSER_END(Grammar) SKIP : /* 不处理的字符*/ “ “ “t“ TOKEN : /*生成 tok

35、en 的字符定义*/ 例子:一个十进制的加法表达式,比如1+1呵呵,我知道等于 2,可这个小程序不是算结果的, 是检验表达式合法不, 基本就这样了,得先写个什么.jj 文件规范 JavaCC 的解析器和词法分析器,将会作为 JavaCC 处理文件的输入 .就叫“Adder.jj“吧,跟教程上一样.PARSER_BEGIN(Adder)public class Adderpublic static void main(String args) throws ParseException,TokenMgrErrorAdder adder = new Adder(System.in);adder.s

36、tart();PARSER_END(Adder)SKIP:“ “|“t“|“n“|“r“|“rn“TOKEN:|void start():()*1.PARSER_BEGIN(Adder)与 PARSER_END(Adder)之间的代码是 Java 语法,这里生成 Adder.java 的主程序入口,基本就是这种格式,其中要抛出两个异常:1.1 ParseException : 解析错误, 解析器负责检查,Exception 的子类.比如输入“1+1“,这种就是解析错误,因为它里面的分割符都是我们在 TOKEN:中定义的,没有其它字符.1.2 TokenMgrError : 分割符错误,词法分析

37、器负责检查,Error 的子类.比如输入“1-1“ 就是这种错误,因为TOKEN:中没有定义“-“.这两个类都会自动生成,现在刚研究还不知道为啥一个来之 Exception,一个来自 Error,以后会明白的.2.new Adder(System.in),这个构造子这还不是很明白,不知道为啥默认成这型的 ,就知道是自动产生的,以后再说.3.start() 方法是解析的主体 ,是下面需要实现的.4.SKIP:“ “|“n“|“r“|“rn“ 这个定义的是忽略的字符,它们虽然构成分割符但不被送给解析器,就是你在输入的时候有这些字符不会发生错误,但它们不会被解析出来. 这里定义了 5 个,基本上就是

38、空格, 跳格,回车换行什么的,以为各个操作系统间的回车换行什么的据说不一样, 我也不知道都咋回事, 都写上吧.各个元素之间用“|“分开,格式就是这样了.5.TOKEN:|这个是说分割符了,就是把一个句子里的什么字符取出来, 也就是你这句子里只能有这些规定好的字符, 别的不行,这里就是“+“号和 0-9 十个数字. 两着用“|“分开.每个分割符是这样规定的,用括上,代号和符号用“:“ 隔开,就是用前面的代号代替后面在句子中会出现的元素或元素的集合.这些代号在下面会用到. 其中数字用了正则式,就是 1 个或 1 个以上的由 0-9 之间的数字组成的串.4 和 5 两个部分如果用不到可以没有.6.v

39、oid start():()*这个就是传说中的解析器了,说是符合什么 BNF 产生式,基本就这形状了 ,以后漫漫弄明白吧.里面看起来还像是正则式,就是用符号替换了,是以数字开头,中间跟 0 个或 0 个以上的由+和数字组成的序列, 这个顺序不能变,最后是结束符,自带定义的.程序基本上就这么回事了,因为简单, 也形式上也没什么.然后编译吧,设好环境变量什么的, 在控制台切换到在 Adder.jj 所在文件夹 :javacc Adder.jj成功就会出现提示:Java Compiler Compiler Version 4.0beta1 (Parser Generator)(type “javac

40、c“ with no arguments for help)Reading from file Adder.jj . . .File “TokenMgrError.java“ does not exist. Will create one.File “ParseException.java“ does not exist. Will create one.File “Token.java“ does not exist. Will create one.File “SimpleCharStream.java“ does not exist. Will create one.Parser gen

41、erated successfully.一共生成了 7 个.java 文件, 干嘛的都下回再说吧 .编译了这些文件:javac *.java运行 Adder :java Adder这时候控制台等待输入,可以试试拉:1+1没提示就是合法,ctrl + c 结束输入可以试着弄点错误什么的,看看异常类型跟错误的情况是怎么对应的.都完事了,还挺简单的,呵呵!问题:1 不能动态调用.这个问题是由于在写 JJ 文件的时候, 并没有设置生成的 JAVA 类为非静态的,那么在 JAVACC 生成类的时候会默认生成静态类. 如果是静态类的话,在调用的时候就只能用静态方法调用.静态调用,我一直都没有调用成功,最后

42、无奈之下,还是修改了 JJ 文件,重新生成.在 JJ 文件的开头, 加上 option,设置其生成非静态类, 如下:options FORCE_LA_CHECK=true;DEBUG_PARSER = true;/以 debug 形式生成,便于调试.STATIC=false; /生成非静态类.LOOKAHEAD=3; /向前看三个字母,消除歧义用的2 Lexical error出现这个问题是由于在解析的句子中遇到了 JAVACC 中保留字,例如单引号 ,双引号“如果要解析此类字符 ,在定义 TOKEN 时得表明,例如:/双引号, 即用转义3 Encountered “not ( employe

43、e“ at line 3, column 43.Was expecting one of:.“not“ “(“ .“not“ “(“ .这种错误,不知道应该用什么名称来表述,但绝对是 JAVACC 中出现最多的问题,也是让人最郁闷的问题.明明输入的内容就是按语法要求来的,但是就是不能被正确解析. 遇到这个问题,可能是以下几种情况(1) TOKEN 定义导致的,例如:看上去, 刚才那个句子遇到 not 应该解析成 TOKEN not,其实不然,它会被解析 TOKEN string.因为字符串 not 是符合 TOKEN string 的定义的, 并且在顺序上 TOKEN string 在前,所以先被匹配成 TOKEN string.如果将两者的顺序更换一下, 就能正确的解析成 TOKEN not 了.(2) 自定义的变量导致的, 例如:void test(): int not=0; key= not=1; 在这里,有一个自定义的变量名和 TOKEN not 名称一样.将 JJ 文件生成JAVA 类之后,你会发现,对于 TOKEN not显示的颜色, 会跟其它的 TOKEN 不一样.这就是由于在 JAVA 类中,这个变量not 和 TOKEN not 二者冲突了 .如果将这个变量名改为 no 或者其它的,TOKEN not 就能被正常解析了.学习是一个过程!一个痛并快乐着的过程!

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 网络科技 > Java

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报