1.2 第一个例子:加法器 作为第一个例子,我们把以下的一些数相加:
除了阿拉伯数字之间外,所有的地方都可以有空格和换行,剩余的字符必须是10进制数或加号”+”。 这段示例代码是”adder.jj”文件的一部分,adder.jj包含JavaCC规则的词法分析和语法分析代码,它处理上面的加法算式。 1.2.1 选项和类声明 文件的第一部分是:
在开头的注释之后,是选项部分,本例除了STATIC选项把默认值true改为false外,其它的都是使用的JavaCC的选项默认值,关于选项更多的信息可以参考JavaCC文档,本书的后续部分或者FAQ。接下来是一个称为Adder的Java类,这里看到的不是完整的Adder类,JavaCC会在生成Java代码的过程中添加该类的声明。这个main方法会抛出ParseException和TokenMgrError这两个异常,JavaCC会自动生成这两个异常类。
1.2.2 指定一个词法分析器 在返回到这个main方法前,先看看词法分析规则。在这个简单的例子中,词法限定在如下的四行中:
第一行是说空格虽然是标识符,但要跳过,就是说,不传给语法分析器。第二行是换行,和空格一样处理。不同的操作系统的换行符是不一样的,在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。 考虑包含如下字符的一个输入文件:
词法分析器找到7个标识符:NUMBER,空格,加号,空格,NUMBER,新行,EOF。被标记为SKIP的正则产生式不传给语法分析器,所以语法分析器得到的是:
假设不是合法的输入文件,包含未知的字符,比如:
在发现第一个空格后,词法分析器会找到一个减号。由于没有减号这个标识符,词法分析器会抛出一个TokenMgrError异常。 如果是下面这个字符序列呢?
这次词法分析也可以把这个序列解析为如下的标识符:
词法分析器判断不出这个标识符序列是否正确,会把这些交给语法分析器。语法分析器会在词法分析器传送过来第二个PLUS符号时发现一个错误,那么,它就不再继续处理剩余的部分了。所以实际传送给语法分析器标识符序列是:
跳过一个字符或字符序列并不等同于忽略它。考虑一个输入序列:
词法分析识别出三个标识符:两个NUMBER和中间的一个空格,语法分析器会再次报错。
1.2.3 指定一个语法分析器 JavaCC语法规范由NBF产生式构成,看起来有些象Java方法定义。
BNF产生式定义合法的标识符序列,本例中,序列由NUMBER符号开头,以EOF结尾,中间包含0个或多个子序列,这个子序列为PLUS符号后面紧跟一个NUMBER标识符。 前面说的语法分析器只检查输入序列是否含有错误,并不真正的计算数的加法。接下来我们修改这个语法分析器来修正这一点。首先,生成Java代码并运行看看。
1.2.4 生成词法分析器与语法分析器 前面已经构造了adder.jj文件,下面用JavaCC来处理它。怎样处理其实是依赖于不同的操作系统的。在Windows NT,2000,XP下面,用“命令提示符”程序(CMD.exe)来运行JavaCC:
会产生7个Java类,每个都在自身的文件中: • TokenMgrError 一个简单的错误定义类,用于词法分析中遇到的错误,是Throwable的子类。 • ParseException 另一个错误定义类,用于语法分析中遇到的错误,是Exception进而是Throwable的子类。 • Token 标识符定义类。每个标识符都用一个整型的变量kind和一个字符串类型的变脸image,kind表示标识符(PLUS,NUMBER后者EOF)的类型,image是标识符表示的字符序列。 • SimpleCharStream 适配器类,把字符串传给词法分析器。 • AdderConstants 定义了词法分析和句法分析用到的一些类的接口。 • AdderTokenManager 词法分析器。 • Adder is the parser 语法分析器。 现在可以用Java编译器来编译这些类了:
注意:本blog中含源代码的文章推荐使用firefox阅读,可以获得较佳的效果。 |
|