javacc例子:加法器

来源:百度文库 编辑:神马文学网 时间:2024/05/02 02:10:02
1.2  第一个例子:加法器
作为第一个例子,我们把以下的一些数相加:
99 + 42 + 0 + 15
除了阿拉伯数字之间外,所有的地方都可以有空格和换行,剩余的字符必须是10进制数或加号”+”。
这段示例代码是”adder.jj”文件的一部分,adder.jj包含JavaCC规则的词法分析和语法分析代码,它处理上面的加法算式。
1.2.1         选项和类声明
文件的第一部分是:
/* adder.jj Adding up numbers */
options {
STATIC = false ;
}
PARSER BEGIN(Adder)
class Adder {
static void main( String[] args )
throws ParseException, TokenMgrError {
Adder parser = new Adder( System.in ) ;
parser.Start() ;
}
}
PARSER END(Adder)
在开头的注释之后,是选项部分,本例除了STATIC选项把默认值true改为false外,其它的都是使用的JavaCC的选项默认值,关于选项更多的信息可以参考JavaCC文档,本书的后续部分或者FAQ。接下来是一个称为Adder的Java类,这里看到的不是完整的Adder类,JavaCC会在生成Java代码的过程中添加该类的声明。这个main方法会抛出ParseException和TokenMgrError这两个异常,JavaCC会自动生成这两个异常类。
1.2.2         指定一个词法分析器
在返回到这个main方法前,先看看词法分析规则。在这个简单的例子中,词法限定在如下的四行中:
SKIP : { ” ” }
SKIP : { ”\n” | ”\r” | ”\r\n” }
TOKEN : { < PLUS : ”+” > }
TOKEN : { < NUMBER : ([”0”-”9”])+ > }
第一行是说空格虽然是标识符,但要跳过,就是说,不传给语法分析器。第二行是换行,和空格一样处理。不同的操作系统的换行符是不一样的,在Unix和Linux系统中使用”\n”,在DOS和Windows下使用”\r\n”,在老的Macintoshes系统(Darwine内核之前,新的Macintoshes系统采用的是Unix方式的换行。译者注)中使用的是单一的”\r”。我们告诉JavaCC所有的这些可能,使用一个垂线”|”来分开它们。第三行告诉JavaCC加号是一个标识符,用PLUS符号表示。最后是第四行,告诉JavaCC数字的语法,用NUMBER符号表示这一类型的标识符。如果你对Perl或者Java的正则表达式包熟悉的话,就容易看懂前面的NUMBER符号了。我们看看正则表达式([”0”-”9”])+,[”0”-”9”]表示任意阿拉伯数字,就是说,是0和9之间的任何unicode字符。形如(x)+的正则式匹配一个或者多个字符串,其中每个字符串又匹配正则式x。所以([”0”-”9”])+匹配一个或多个阿拉伯数字组成的任意序列。这四行都被称为正则表达产生式。
还有一种标识符,被称为EOF,代表输入序列的结束,没必要用正则表达式产生EOF,JavaCC自动把文件的末尾作为EOF。
考虑包含如下字符的一个输入文件:
“123 + 456\n”
词法分析器找到7个标识符:NUMBER,空格,加号,空格,NUMBER,新行,EOF。被标记为SKIP的正则产生式不传给语法分析器,所以语法分析器得到的是:
NUMBER, PLUS, NUMBER, EOF
假设不是合法的输入文件,包含未知的字符,比如:
“123 - 456\n”
在发现第一个空格后,词法分析器会找到一个减号。由于没有减号这个标识符,词法分析器会抛出一个TokenMgrError异常。
如果是下面这个字符序列呢?
“123 ++ 456\n”
这次词法分析也可以把这个序列解析为如下的标识符:
NUMBER, PLUS, PLUS, NUMBER, EOF
词法分析器判断不出这个标识符序列是否正确,会把这些交给语法分析器。语法分析器会在词法分析器传送过来第二个PLUS符号时发现一个错误,那么,它就不再继续处理剩余的部分了。所以实际传送给语法分析器标识符序列是:
NUMBER, PLUS, PLUS
跳过一个字符或字符序列并不等同于忽略它。考虑一个输入序列:
“123 456\n”
词法分析识别出三个标识符:两个NUMBER和中间的一个空格,语法分析器会再次报错。
1.2.3         指定一个语法分析器
JavaCC语法规范由NBF产生式构成,看起来有些象Java方法定义。
void Start() :
{}
{

(


)*

}
BNF产生式定义合法的标识符序列,本例中,序列由NUMBER符号开头,以EOF结尾,中间包含0个或多个子序列,这个子序列为PLUS符号后面紧跟一个NUMBER标识符。
前面说的语法分析器只检查输入序列是否含有错误,并不真正的计算数的加法。接下来我们修改这个语法分析器来修正这一点。首先,生成Java代码并运行看看。
1.2.4         生成词法分析器与语法分析器
前面已经构造了adder.jj文件,下面用JavaCC来处理它。怎样处理其实是依赖于不同的操作系统的。在Windows NT,2000,XP下面,用“命令提示符”程序(CMD.exe)来运行JavaCC:
D:\home\JavaCC-Book\adder>javacc adder.jj
Java Compiler Compiler Version 2.1 (Parser Generator)
Copyright (c) 1996-2001 Sun Microsystems, Inc.
Copyright (c) 1997-2001 WebGain, Inc.
(type "javacc" 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 generated successfully.
会产生7个Java类,每个都在自身的文件中:
• TokenMgrError  一个简单的错误定义类,用于词法分析中遇到的错误,是Throwable的子类。
• ParseException  另一个错误定义类,用于语法分析中遇到的错误,是Exception进而是Throwable的子类。
• Token  标识符定义类。每个标识符都用一个整型的变量kind和一个字符串类型的变脸image,kind表示标识符(PLUS,NUMBER后者EOF)的类型,image是标识符表示的字符序列。
• SimpleCharStream  适配器类,把字符串传给词法分析器。
• AdderConstants  定义了词法分析和句法分析用到的一些类的接口。
• AdderTokenManager  词法分析器。
• Adder is the parser  语法分析器。
现在可以用Java编译器来编译这些类了:
D:\home\JavaCC-Book\adder>javac *.java
注意:本blog中含源代码的文章推荐使用firefox阅读,可以获得较佳的效果。