JavaCC(Java Compiler Compiler)是一个用JAVA开发的最受欢迎的语法分析生成器。这个分析生成器工具可以读取上下文无关且有着特殊意义的语法并把它转换成可以识别且匹配该语法的JAVA程序。JavaCC可以在Java虚拟机(JVM) V1.2或更高的版本上使用,它是100%的纯Java代码,可以在多种平台上运行,与Sun当时推出Java的口号"Write Once Run Anywhere"相一致。JavaCC还提供JJTree工具来帮助我们建立语法树,JJDoc工具为我们的源文件生成BNF范式(巴科斯-诺尔范式)文档(Html);
我们下载了javacc的开发包,只要把里面的例子全部读懂就可以深入了解javacc的语法过程;现在来看第一个例子
options { LOOKAHEAD = 1; CHOICE_AMBIGUITY_CHECK = 2; OTHER_AMBIGUITY_CHECK = 1; STATIC = true; DEBUG_PARSER = false; DEBUG_LOOKAHEAD = false; DEBUG_TOKEN_MANAGER = false; ERROR_REPORTING = true; JAVA_UNICODE_ESCAPE = false; UNICODE_INPUT = false; IGNORE_CASE = false; USER_TOKEN_MANAGER = false; USER_CHAR_STREAM = false; BUILD_PARSER = true; BUILD_TOKEN_MANAGER = true; SANITY_CHECK = true; FORCE_LA_CHECK = false; } PARSER_BEGIN(Simple1) /** Simple brace matcher. */ public class Simple1 { /** Main entry point. */ public static void main(String args[]) throws ParseException { //这里system.in使用的是键盘输入 Simple1 parser = new Simple1(System.in); parser.Input(); } } PARSER_END(Simple1) /** Root production. */ void Input() : {} {//("\n"|"\r")* 表示若干个换行<EOF>为最后终止符号 MatchedBraces() ("\n"|"\r")* <EOF> } /** 这里是包含匹配的,如果熟悉正则表达式就很容易了解,这里MatchedBraces匹配的是多个{}*/ void MatchedBraces() : {} { "{" [ MatchedBraces() ] "}" }
我们看到这个是个simple1.jj的简单例子,这个javacc是由jj或者jjt描述文件组成的,他一般分为option部分,主体部分就是class定义的相当一个java的类,还有就是token部分,上面的函数主要是匹配数个{}
如:"{}", "{{{{{}}}}}"
第二个例子simple2.jj
PARSER_BEGIN(Simple2) /** Simple brace matcher. */ public class Simple2 { /** Main entry point. */ public static void main(String args[]) throws ParseException { Simple2 parser = new Simple2(System.in); parser.Input(); } } PARSER_END(Simple2) //skip属于系统的关键字表示将会忽略里面描述的字符 SKIP : { //忽略空格和换行符号 " " | "\t" | "\n" | "\r" } /** Root production. */ void Input() : {} {//EOF是个固有文本流输入终止符号 MatchedBraces() <EOF> } /** Brace matching production. */ void MatchedBraces() : {} { "{" [ MatchedBraces() ] "}" }
这个例子也是匹配若干个{} 但是跟第一个例子不同的是,它可以匹配输入的的{和}之间有换行或者空格
第三个例子simple3.jj
PARSER_BEGIN(Simple3) /** Simple brace matcher. */ public class Simple3 { /** Main entry point. */ public static void main(String args[]) throws ParseException { Simple3 parser = new Simple3(System.in); parser.Input(); } } PARSER_END(Simple3) SKIP : { " " | "\t" | "\n" | "\r" } //TOKEN是一个系统关键词,它是用户可以自定义自己的描述,并且由系统识别然后传递用户处理 TOKEN : {//如我们定义一个LBRACE 是{字符 定义一个token形式是<字符变量:用户定义的字符串或常量> <LBRACE: "{"> | <RBRACE: "}"> } /** Root production. */ void Input() : //放在这行表示自定义变量count { int count; } { //count存放的是MatchedBraces函数返回的数值,并在java代码片段打印出来 count=MatchedBraces() <EOF> //后面跟的是java代码片段,用户可以自己定义 { System.out.println("The levels of nesting is " + count); } } /** Brace counting production. */ int MatchedBraces() : //nested_count定义变量 { int nested_count=0; } { //这里匹配{}*然后nested_count递增 作用是算出输入文本流含有多少个{}串 <LBRACE> [ nested_count=MatchedBraces() ] <RBRACE> //插入java代码片段 { return ++nested_count; } }
simple3.jj计算出的是一个输入文本流含有多少个{}串
第四个例子:
PARSER_BEGIN(IdList) /** ID lister. */ public class IdList { /** Main entry point. */ public static void main(String args[]) throws ParseException { IdList parser = new IdList(System.in); parser.Input(); } } PARSER_END(IdList) //忽略空格和换行符号 SKIP : { " " | "\t" | "\n" | "\r" } //定义一个id为字符开头,后面带着字符串或者数字组成的TOKEN字符串 TOKEN : { < Id: ["a"-"z","A"-"Z"] ( ["a"-"z","A"-"Z","0"-"9"] )* > } /** Top level production. */ void Input() : {} {//匹配输入多个字符串并且以EOF结束 ( <Id> )+ <EOF> }
第五个例子
PARSER_BEGIN(NL_Xlator) /** New line translator. */ public class NL_Xlator { /** Main entry point. */ public static void main(String args[]) throws ParseException { NL_Xlator parser = new NL_Xlator(System.in); parser.ExpressionList(); } } PARSER_END(NL_Xlator) SKIP : { " " | "\t" | "\n" | "\r" } TOKEN : { //ID为字母和数字组成的字符串 < ID: ["a"-"z","A"-"Z","_"] ( ["a"-"z","A"-"Z","_","0"-"9"] )* > | //NUM为数字串 < NUM: ( ["0"-"9"] )+ > } /** Top level production. */ void ExpressionList() : {//定义一个字符串s String s; } { //这里插入一个java代码段,打印输出字符串 { System.out.println("Please type in an expression followed by a \";\" or ^D to quit:"); System.out.println(""); } //开始匹配一段表达式以";"作为结尾 ( s=Expression() ";" {//插入java代码段 System.out.println(s); System.out.println(""); System.out.println("Please type in another expression followed by a \";\" or ^D to quit:"); System.out.println(""); } )* <EOF> } /** An Expression. */ String Expression() : {//定义vector和s变量 java.util.Vector termimage = new java.util.Vector(); String s; } { s=Term() {//java代码段 termimage.addElement(s); } ( "+" s=Term() { termimage.addElement(s); } )* { if (termimage.size() == 1) { return (String)termimage.elementAt(0); } else { s = "the sum of " + (String)termimage.elementAt(0); for (int i = 1; i < termimage.size()-1; i++) { s += ", " + (String)termimage.elementAt(i); } if (termimage.size() > 2) { s += ","; } s += " and " + (String)termimage.elementAt(termimage.size()-1); return s; } } } /** A Term. */ String Term() : { java.util.Vector factorimage = new java.util.Vector(); String s; } { //s获取到Factor的token返回的内容,并使用factorimage存放 s=Factor() { factorimage.addElement(s); } ( "*" s=Factor() { factorimage.addElement(s); } )* { if (factorimage.size() == 1) { return (String)factorimage.elementAt(0); } else { s = "the product of " + (String)factorimage.elementAt(0); for (int i = 1; i < factorimage.size()-1; i++) { s += ", " + (String)factorimage.elementAt(i); } if (factorimage.size() > 2) { s += ","; } s += " and " + (String)factorimage.elementAt(factorimage.size()-1); return s; } } } /** Factor作用是返回TOKEN的变量内容 */ String Factor() : { Token t; String s; } { t=<ID> { //t.image表示获取到t的内容,假如t匹配<ID>的字符串是“ABCD” 则t.image内容是“ABCD” return t.image; } | t=<NUM> { return t.image; } | "(" s=Expression() ")" { return s; } }