javacc

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Javacc
JavaCC是一个词法分析生成器和语法分析生成器。

词法分析和语法分析是处理输入字符序列的软件组件,编译器和解释器协同词法分析和语法分析来解码程序文件。

词法分析器可以把一连串的字符序列划分成一个一个的叫做“Token”的子序列,同时它也可以把这些Token 分类。

这些Token序列将会传送给语法分析器以供其决定程序的结构。

Javacc编写的规则都写在一个.jj的文件夹中: , javaCC用来处理语法文件(jj)生成解析代码.
1.文件基本规则:
options{
JDK_VERSION = "1.7";
STATIC = false;
}
JDK_VERSION生成代码使用的jdk版本,static指是否生成静态的解析器类. Options的参数都是它们的默认值
2.主类:
PARSER_BEGIN(ParserDemo)
com.synnex.ParserDemo;
com.synnex.*;
class ParserDemo
public static void main(String args []) throws ParseException
{
}
}
PARSER_END(ParserDemo)
在PARSER_BEGIN和PARSER_END之间定义语法解析器的主类,这是整个解析程序的入口,里面主要有一些引用的包和类以及一个main方法(其他的方法由JavaCC生成)。

3.定义词法规则
SKIP :
{ /* white space */
" "
| "\t"
| "\n"
| "\r"
}
TOKEN :
{ /* Operators and punctuation */
<PERCENT: "%">
| <AMPERSAND: "&">
| <CARET: "^">
| <VERTICAL_BAR: "|">
| <TILDE: "~">
| <QUOTE: "'">
| <LEFT_BRACE: "{">}
SKIP定义要忽略的字符串,TOKEN定义要识别的字符串。

注意,不是说先将输入中符合SKIP规则的都去掉再进行解析,是顺序处理输入串的过程中,识别尽可能长的子串。

如果词法规则有二义性,JavaCC会给出警告,不要忽略这些警告。

此外,JavaCC只对开头存在二义性的词法给出警告(一个字符可以作为两个词法规则的第一个字符),有些词法上的冲突是需要我们自己去注意的,比如要在词法解析时识别一些关键词,这些关键词同时也符合一般标识符的规则,那么在JavaCC中就要把关键词的定义写在标识符定义之前,写在前面的,JavaCC会优先识别。

4.定义语法规则:
Token subject() :
{
Token token = null;
}
{
token = < UNKNOWN >
{
return token;
}
| token = < KNOWN >
{
Token token1 = token;
}
(
"." token = < KNOWN >
{
token1.image += "."+ token.image;
}
)*
{
return token1;
}
}
开头是一个声明,包括返回值类型、规则名和一个冒号。

对于这样一条语法规则,JavaCC 就会在语法分析器类中生成一个同名的方法。

紧接着的一对花括号中写一些变量声明。

下一对花括号中写该规则的具体内容.一个语法单元中有多个规则时,用|分开。

每个规则都有一系列词法或语法单元组成,每个词法或者语法单元之后跟着一对花括号,里面写处理的代码.
使用JavaCC编译器编译*.jj文件,可以生成Java代码实现的特定语言分析器。

生成的源程序包含:*Parser.java(语法分析器)、*TokenManager.java(词法分析器)、TokenMgrError.java (错误处理程序)、Token. java (标记信息)、*Constants.java (分析器中使用的常量)、SimpleCharStream.java (字符流类)等源文件。

在token.java 里面有一个string类型的域image,用来表示此token的值.
生成代码中:方法jj_consume_token将试图从输入中读取一个指定类型的token,如果得到的token与期望的类型不符,则抛出一个异常。

表达式(jj_ntk==-1)?jj_ntk():jj_ntk计算下一个未读token的类型。

而最后一行则要求匹配EOF的token
<xx> : xx 称为非终结符, 而可以在语言中直接出现的叫终结符: [] ;
#: 以#开头的token只是在词法分析时使用,不能作为语法分析的输入,也就是说,它相对于词法分析是局部的.
[]:其中的内容是可选的。

+前面的内容出现一次或多次。

-:前后构成的闭区间。

*: 前面的内容出现0次或多次。

?:前面的内容出现0次或一次。

~:后面的内容的补。

|:前面或后面。

():改变运算的优先级,把其中的内容作为一个整体。

Bnf
BNF就是巴科特·瑙尔式的缩写,在计算机的史前时代(1950s),曾有一位大师,他奠定了现代计算机的基础在他老人家的诸多成就之中,包括了对形式语言的研究,和发明了高级语言:FORTRAN。

其实BNF很简单::=表示定义 |表示或尖括号(<>)括起来的是非终结符所谓非终结符就是语言中某些抽象的概念,终结符就是可以直接出现在语言中的符号比如:C语言的声明语句可以用BNF这样描述:
<声明语句> ::= <类型><标识符>; | <类型><标识符>[<数字>];
这一句中<声明语句>这个非终结符被定义成了两种形式(上面用|隔开的两部分)
在这里引入了三个终结符: 分号; 左右方括号[ ]
<类型> ::= <简单类型> | <指针类型> | <自定义类型>
<指针类型> ::= <简单类型> * | <自定义类型> *
<简单类型> ::= int|char|double|float|long|short|void
<自定义类型> ::= enum<标识符>|struct<标识符>|union<标识符>|<标识符>
到这里就基本上把<类型>定义清楚了.
<数字> ::= 0X<十六进制数字串> | 0<八进制数字串> | <十进制数字串>
<十六进制数字串> ::= <十六进制数字> | <十六进制数字串><十六进制数字>
<八进制数字串> ::= <八进制数字> | <八进制数字串><八进制数字>
<十进制数字串> ::= <十进制数字> | <十进制数字串><十进制数字>
<十六进制数字> ::= <十进制数字> | A | B | C | D | E | F
<十进制数字> ::= <八进制数字> | 8 | 9
<八进制数字> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
到这里就把<数字>定义清楚了.
<标识符> ::= <字母> | <标识符> <字母数字串>
<字母数字串> ::= <字母>|<十进制数字>|<字母数字串><字母>|<字母数字串><十进制数字> <字母> ::= _ | <大写字母> | <小写字母>
<小写字母> ::= a|b|c|d|e|f|g|h|i|j ……(偷个懒)
<大写字母> ::= A|B|C|D|E|F|G|H|I|J ……
到此为止整个声明语句就定义完了(就是说已经没有非终结符了),虽然看起来很繁,但前面定义的各种非终结符都可以很容易的在别的地方重用比如,函数声明
可以定义成下面的样子:
<函数声明语句> ::= <类型><标识符>(<形参表>);
<形参表> ::= <类型><标识符> | <形参表>,<形参表>
只用两句就描述完了,所以BNF实际上比用自然语言要简练得多
(整个C语言只用一二百句就可以描述清楚)
而且相当的精确,不会有自然语言中那种模棱两可的表达
如果你对BNF比较敏感的话,会发现C里面的标识符不能由数字开头
而且在C里面下划线是被当做字母看待的(也就是说能用字母的地方
都可以用下划线)比如:(最好用老一点的编译器比如PDP11上的cc)
#define ____ main
#define ___ for
typedef char* _____;
int (*______)(char *, ...) = printf; //如果这一句不灵,就用下面这句
//#define ______ printf //如果你用的是C++可以试一下下面这个
//int (*______)(const char *, ...) = printf;
____(_,char* __[]) //要是你编译器不吃,可以改成int ____(int _,char*__[])
{
___( ; _ ; _ --)
{
______("%s\n", __[_]);
}
}
另外,还有一种EBNF就没有正宗的BNF这么爽了,也有很多人在用,前面的
那些递归的定义被写成了{}
有一段时间PASCAL爱好者们喜欢用一个叫语法图的东西,画出来很难看,但
功能和BNF差不多,现在好象已经没多少人用了
近几年流行另一种东西:
digit = one of
0 1 2 3 4 5 6 7 8 9
这里非终结符digit用斜体表示,one of是这种方法里定义的一个量词(常用斜黑体)。

相关文档
最新文档