
编译原理实习_JavaCC - 副本.ppt
38页JavaCC基础西北农林科技大学本科实习材料 学 期:2014年春季时 间:*信息工程学院软件工程系主讲:赵建邦 JavaCC基础l1 JavaCC概述lJavaCC源文件(.jjt)的结构l2 JavaCC所生成的类l3 词法规则注意事项l4 语法规则注意事项l5 添加语义规则l6 四元式示例(switch-case和函数调用)1 JavaCC概述JavaCC是一个词法分析器和语法分析器的生成器int main() { return 0 ; }MiniC源代码JavaCCMiniC词法规则+语法规则MiniC词法分析器 (TokenManager) MiniC语法分析器 (Parser)“int” “main” “(” “)” ” {“ “return” “0” “;” “}”词法分析语法分析函数类型函数名(参数 )?函数体return语句intmainreturn 0;{}1 JavaCC概述uJavaCC 本身并不是一个词法分析器或是语法分析器,而是一个分析程序生成器它可以根据输入的语言规范输出一个词法和语法分析器。
u输入: (满足JavaCC格式: .jjt文件)u输出: ( .java 文件)JavaCC工具包MiniC词法规则+语法规则MiniC词法分析器 (TokenManager) MiniC语法分析器 (Parser)1 JavaCC概述u生成好的词法、语法分析器带有一个main( )方法,可以接收键盘输入的句子(默认)或者写在文件里的句子u新建一个jjt文件的步骤:u1.建立java项目u2.建立一个语法分析包(例如:parser)u3.“新建”-“其它”-“JavaCC Template File”u4.创建一个“.jjt”文件包名jjt 文件名1.1 jjt文件的结构/*第一部分*/语法分析器的属性设置/*第二部分*/语法分析器的类声明/*第三部分*/词法规则声明/*第四部分*/语法规则实现81.2 声明一个词法分析器SKIP : { “ “ } SKIP : { “\n“ | “\r“ | “\r\n“ } TOKEN : { } TOKEN : { } TOKEN : { | “.“ | “.“ | “.“ > } TOKEN : { }在词法声明部分,以#开头的token只是在词法分析时使 用,不能作为语法分析的输入,也就是说,它相对词 法分析是局部的举例91.2 声明一个词法分析器Javacc中的语法表示吸收了UNIX中正规文法的一些 记号l []: 其中的内容是可选的 2+:前面的内容出现一次或多次 3*: 前面的内容出现0次或多次 4?: 前面的内容出现0次或一次 5|: 前面或后面 6():改变运算的优先级,把其中的内容作为一个整 体1.2 声明一个词法分析器jjt文件自动生成的对标识符的定义: 1.2 声明一个词法分析器自定义词法规则: 手动添加关键字规则, 确保关键字先于标识符定义u如果被分析的源程序中有不符合语言规范的地方,词法和语法分析器会将错误输出在Eclipse控制台。
运行程序2 JavaCC所生成的类ujj文件和jjt文件都可以被JavaCC编译,生成词法和语法分析器 .jj文件的语法声明部分AAA是将要生成的语法分析器类名, 可以由用户设定JavaCC编译2 JavaCC所生成的类ujj文件和jjt文件都可以被JavaCC编译,生成词法和语法分析器AAA是将要生成的语法分析器类名, 可以由用户设定jjt文件的语法声明部分JavaCC编译2 JavaCC所生成的类uToken.java /*词法分析器的构造方法*/public AAATokenManager(SimpleCharStream stream) {}/*浏览下一个单词*/public static Token getNextToken(){}实习要求1:可以通过上面几个类和对应的方法得到MiniC程序的单词序列2 JavaCC所生成的类uAAA.java /* SimpleNode的dump()可以输出语法树*/n.dump(““);实习要求2:可以修改dump( )方法将语法树输出到文本TOKEN:{ | “.“ | “.“ >} TOKEN:{}在词法声明部分,以#开头的token只是在词法分析时使用,不 能作为语法分析的输入,也就是说,它相对词法分析是局部的3 词法规则注意事项(举例)JavaCC中的语法表示吸收了UNIX中正规文法的一些记号: l [] : 其中的内容是可选的 2+ :前面的内容出现一次或多次 3* : 前面的内容出现0次或多次 4? :前面的内容出现0次或一次 5| : 前面或后面 6(): 改变运算的优先级,把其中的内容作为一个整体TOKEN:{ /* KEY */| | }3 词法规则注意事项(举例)TOKEN: /* IDENTIFIERS */ { ( |)*> | | }具有包含关系的词法定义,必须防止失效情况: KEY的声明必须在IDENTIFIER的声明之前4 语法规则注意事项u语法部分决定了编译器的功能是否强大。
u文法中的每个非终结符对应一个函数,函数调用表示非终结符之间的组成关系uJavaCC默认生成的“AAA.jjt”文件是一个简单的表达式分析器Ø能够表达带括号的五则(+、-、*、/、%)混合运算;Ø优先级: () > *、/、% > +、-Ø例如:“a+b*3;”、“a*(b-d % 5);”是合法的句子SimpleNode Start() : {} {Expression() “;“{return jjtThis;} }4 语法规则注意事项Start → Expression ;void UnaryExpression() : {} {“(“ Expression() “)“ | Identifier() | Integer() }Unary → ( Expression )| id | integer4 语法规则注意事项u“AAA.jjt”的文法决定了该语法分析器无法识别如下语句:Ø“a+ -b;”、“a++;”、“-a ++ +5;”等u修改文法:Ø可以识别“a+ -b;”、“-a - -5;”等Ø但仍然不能识别自增自减运算void UnaryExpression() : {} {“(“ Expression() “)“ | (“-“ | “+“ )? ( Identifier() | Integer() ) }Type → + | - | ε Unary → ( Expression )| Type ( id| integer)4 语法规则注意事项u在语法分析阶段需要注意的主要问题是:Ø明确编译器的主要功能。
Ø根据C语言的语法和实习要求提取MiniC的文法ü程序→ (函数)+ü函数→ 类型 函数名 (参数列表) 函数体ü…ü表达式 → …ü…ü常量→ 整型常量 | 字符常量 | …ü标识符→ | 整型常量此处的简易文法仅作参考! 部分产生式需要修改才能使 用4 语法规则注意事项u在语法分析阶段,可能会遇到冲突:(代码左侧有黄色小三角)/*原因:二义义性或者文法非LL(1)*/if E if E S e Sif Eif ESe Sif Eif ES e S4 语法规则注意事项u个别冲突可以借助LOOKAHEAD(K)关键字解决/*语语法分析器执执行完if-S 之 后先找“else”,找到则则匹配最近的if,否则执则执 行后面的语语句*/ if E if E S e S if Eif ESe Sif Eif ES e S5 添加语义规则uJavaCC采用自顶向下语法分析,可以在文法的任意位置添加语义 子程序u只需要在需要添加语义子程序的地方使用花括号即可添加 void MultiplicativeExpression() : // 乘除表达式 { } { UnaryExpression()((“*“ // op是Token对对象| “/“)UnaryExpression())* }{2 }{3 }{4 } {5 }1注意:在1处添加的语义子程序往往用来实例化变量 ,这些变量在语法分析过程中被使用;只有语法结构的方法语义子程序写在花括号里面String MultiplicativeExpression() : // 乘除表达式,注意返回值类值类 型 { String first; String middle;String newTemp; Token op; } { first = UnaryExpression() // first是返回的字符串{ newTemp = first; }((op = “*“ // op是Token对对象| op = “/“| op = “%“)middle = UnaryExpression() // middle是返回的字符串{ newTemp = variableNameGenerator.genVariableName();QTInfo qt = new QTInfo(op.image, first, middle, newTemp);qtTable.addQTInfo(qt);})*{return newTemp; //返回临时变临时变 量字符串 “T1”,“T2”} }对于之前的方法添加 了语义子程序。
6 四元式示例uJavaCC能够根据jjt文件得到语法分析所用的类,但是为了编写 一个合格的编译器,开发者需要额外添加一些类,以完成四元式 的翻译、符号表的存储、差错处理等u建议将jjt的类放置到一个包内,开发者新建的类放到另一个包 内parser包GUI包用户类包6 四元式示例(switch-case)void main() { switch(ts) { case 0: a =23; break; case 1: switch(lts) {case 'a': a1 = 6; break; default: a2 = 9; } case 3: d = 34; default: e = 34; } }1:(case, ts,0,3) 2:(J,_,_,5) 3:(=,23,_,a) 4:(Jbr,_,_,16) 5:(case, ts,1,7) 6:(J,_,_,12) 7:(case, lts,'a',9) 8:(J,_,_,11) 9:(=,6,_,a1) 10:(Jbr,_,_,12) 11:(=,9,_,a2) 12:(case, ts,3,14) 13:(J,_,_,15) 14:(=,34,_,d) 15:(=,34,_,e)6 四元式示例(函数调用)void f(double d){double x = 3.0;return; } int f(int d){d = d*d;return d; } double f(int x, double b){return b; }void main(){double c,b,d[5];int x,y,z[3];c = f(x,b) + z[1]++; }1:(=,3.0,_,x) 2:(Jr,_,_,3) 3:(*,d,d,T1) 4:(=,T1,_,d) 5:(Jr,_,_,6) 6:(Jr,_,_,7) 7:(para, x,_,_) 8:(para, b,_,_) 9:(call, f,_,T2) 10:(=,1,_,T3) 11:(-,z,0,T4) 12:(=[],T4[T3], _,T5) 13:(+,T4[。
