luence语法解析器 javacc详解
JavaCC是一个词法分析器和语法分析器的生成器。
第一个实例——正整数相加
下面我们来看第一个例子,即能够解析正整数相加的表达式,例如99+42+0+15。
(1) 生成一个adder.jj文件
此文件中写入的即生成词法分析器和语法分析器的规则。
(2) 设定选项,并声明类
/* 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,使得生成的函数不是static的。
PARSER_BEGIN和PARSER_END之间的java代码部分,此部分不需要通过JavaCC根据规则生成java代码,而是直接拷贝到生成的java代码中的。
(3) 声明一个词法分析器
SKIP : { " " } SKIP : { "\n" | "\r" | "\r\n" } TOKEN : { < PLUS : "+" > } TOKEN : { < NUMBER : (["0"-"9"])+ > } |
第一二行表示空格和回车换行是不会传给语法分析器的。
第三行声明了一个Token,名称为PLUS,符号为“+”。
第四行声明了一个Token,名称为NUMBER,符号位一个或多个0-9的数的组合。
如果词法分析器分析的表达式如下:
- “123 + 456\n”,则分析为NUMBER, PLUS, NUMBER, EOF
- “123 - 456\n”,则报TokenMgrError,因为“-”不是一个有效的Token.
- “123 ++ 456\n”,则分析为NUMBER, PLUS, PLUS, NUMBER, EOF,词法分析正确,后面的语法分析将会错误。
(4) 声明一个语法分析器
void Start() : {} { <NUMBER> ( <PLUS> <NUMBER> )* <EOF> } |
语法分析器使用BNF表达式。
上述声明将生成start函数,称为Adder类的一个成员函数
语法分析器要求输入的语句必须以NUMBER开始,以EOF结尾,中间是零到多个PLUS和NUMBER的组合。
(5) 用javacc编译adder.jj来生成语法分析器和词法分析器
/** * JavaCC file */ options{ STATIC = false; } PARSER_BEGIN(AddParser) package add; public class AddParser{ public static void main(String args[])throws ParseException{ AddParser parser = new AddParser(System.in); try { switch (parser.start()){ case 0:System.out.println("ok"); break ; case 1:System.out.println("Goodbye."); break ; default :break ; } } catch (Exception e){ System.out.println("NOK."); System.out.println(e.getMessage()); } catch (Error e){ System.out.println("Oops."); System.out.println(e.getMessage()); } } } PARSER_END(AddParser) SKIP:{ " " | "\n" | "\r" | "\t" } TOKEN:{ <PLUS:"+"> } TOKEN:{ <NUMBER:(["0"-"9"])+> } int start():{}{ add()";"{ return 0; } | ""{ return 1; } } void add():{}{ <NUMBER>(<PLUS><NUMBER>)* }
用JavaCC编译adder.jj生成如下文件:
- Adder.java:语法分析器。其中的main函数是完全从adder.jj中拷贝的,而start函数是被javacc由adder.jj描述的规则生成的。
- AdderConstants.java:一些常量,如PLUS, NUMBER, EOF等。
- AdderTokenManager.java:词法分析器。
- ParseException.java:用于在语法分析错误的时候抛出。
- SimpleCharStream.java:用于将一系列字符串传入词法分析器。
- Token.java:代表词法分析后的一个个Token。Token对象有一个整型域kind,来表示此Token的类型(PLUS, NUMBER, EOF),有一个String类型的域image,来表示此Token的值。
- TokenMgrError.java:用于在词法分析错误的时候抛出。
/** * JavaCC file */ options{ STATIC = false; } PARSER_BEGIN(AddParser) package add; public class AddParser{ public static void main(String args[])throws ParseException{ AddParser parser = new AddParser(System.in); try { System.out.println(parser.add()); } catch (Exception e){ System.out.println("NOK."); System.out.println(e.getMessage()); } catch (Error e){ System.out.println("Oops."); System.out.println(e.getMessage()); } } } PARSER_END(AddParser) SKIP:{ " " } TOKEN:{ <PLUS:"+"> } TOKEN:{ <EOL:"\n" | "\r" | "\r\n"> } TOKEN:{ <NUMBER:(["0"-"9"])+> } int add():{ int a; //函数的参数值 int b; } { a = getNumberValue()//必须用a ( <PLUS> b = getNumberValue() { a+=b; } )* <EOL> //此处输入EOL才会执行return,如果没有EOL则一直不会执行return结果 { return a; } } /** *获取输入数字的值 */ int getNumberValue():{ Token t; } { t = <NUMBER>{ return Integer.parseInt(t.image); //t.image获取string值 } }