编译原理 实验三 LL(1)语法分析器的构造
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
七、实验结果
六、实验小结 1、在本次实验中,通过设计、编制、调试一个递归下降语法分析 程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分 析,掌握LL(1)分析法的基本原理、掌握LL(1)分析表的构造方法、掌握 LL(1)驱动程序的构造方法;
2、通过本次实验,对LL(1)递归下降分析程序的构造和设计有了更 为全面的认识,对LL(1)文法分析程序的实现有了进一步了解; 3、实验输入串以‘$’结束,才用栈的形式,依次弹出进行处理;
sk.push('i'); c=sk.pop(); } else if(a[i]=='('){ System.out.println("F->(E)"); sk.push(')'); sk.push('E'); sk.push('('); c=sk.pop(); } else error(); } } private static void error() { System.out.println((i+1)+":"+a[i]+" error!"); i++; } }
步骤 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 分析栈 $E $EˊT $EˊTˊF $EˊTˊi $EˊTˊ $Eˊ $EˊT+ $EˊT $EˊTˊF $EˊTˊi $EˊTˊ $EˊTˊF $EˊTˊi $EˊTˊ $Eˊ $ (栈顶符号,当前输入 符) (E,i)查表 (T,i)查表 (F,i)查表 (i,i) i匹配 (Tˊ,+)查表 (Eˊ,+)查表 (+,+)+匹配 (T,i)查表 (F,i)查表 (i,i)i匹配 (Tˊ,*)查表 (F,i)查表 (i,i)i匹配 (Tˊ,$)查表 (Eˊ,$)查表 $ 剩余串 i+i*i$ i+i*i$ i+i*i$ i+i*i$ +i*i$ +i*i$ +i*i$ i*i$ i*i$ i*i$ *i$ *i$ i$ i$ $ $ $ Tˊ->ε Eˊ->ε F->i Tˊ->*F Tˊ T->FTˊ F->i Tˊ->ε Eˊ->+T Eˊ 所用产生式 E->TEˊ T->FTˊ F->i
} n++; a[n]='$'; } sk.push('$'); sk.push('E'); c=sk.pop(); do{ if(c==a[i]){ i++;c=sk.pop();} else if(a[i]=='$') break; else ll1(); } while(c!='$'); } private static void ll1() { if(c=='E'){ if(a[i]=='i'||a[i]=='('){ System.out.println("E->TE'"); sk.push('e'); sk.push('T'); c=sk.pop(); } else error(); } else if(c=='e'){ if(a[i]=='+'){ System.out.println("E'->+TE'"); sk.push('e'); sk.push('T'); sk.push('+'); c=sk.pop(); }
$EˊTˊF* (*,*)*匹配
2.数据结构 LL(1)语法分析程序共用到个栈,分别称为:符号栈,语法树栈, 操作符栈和操作数栈。其中,符号栈用于进行LL(1)语法分析;其它的 栈是为了在语法分析的过程中同时生成与源程序结构对应的语法树而 设。语法树栈用于生成声明部分和语句部分的语法树;操作符栈和操作 数栈用于生成表达式部分的语法树。
LL(1)分析法属于自顶向下分析方法,因此需要预测匹配的产生式。即在LL(1)分析法中, 每当在符号栈的栈顶出现非终结符时,要预测用哪个产生式的右部去替换该非终结符。LL(1)分 析方法要求文法满足如下条件:对于任一非终结符A,其任意两个产生式A,A,都要满足下面条 件:First(A)∩First(A)= 2、分析表构造 LL(1)分析表的作用是对当前非终结符和输入符号确定应该选择用哪个产生式进行推导。它 的行对应文法的非终结符,列对应终结符,表中的值有两种:一是产生式的编号,一是错误编 号。若用T表示LL(1)分析表,则T可表示如下: T: VN×VTP∪{Error} T(A, t) = Aα,当tFirst(Aα) T(A, t) = Error,否则 其中P表示所有产生式的集合。显然,一个文法G是LL(1)文法,当且仅当T的元素包含唯一 的一个产生式或Error。 3、驱动程序构造 LL(1)分析主要包括以下四个动作,其中X为符号栈栈顶元素,a为输入流当前字符。 替换:当XVN时选相应产生式的右部去替换X。 匹配:当XVT时它与a进行匹配,其结果可能成功,也可能失败,如果成功则符号栈 中将X退栈并将输入流指针向前移动一位,否则报错。 成功:当格局为(空,空)时报告分析成功。 报错:出错后,停止分析。
FOLLOW(F)=FIRST 1、构造LL(1)分析表 采用手工操作构造LL(1)分析表。LL(1)分析表用一个二维矩阵表 示,其中每个非终结符对应一行,每个终结符对应一列,一个非终结符 和一个终结符可以确定矩阵中的一个元素,元素的值表示该非终结符和 该终结符对应的产生式。每个矩阵元素都是一个符号串,所有元素初始 化为””;构造LL(1)表时,根据文法和各个产生式的First集,填写LL(1) 分析表的内容。各产生式只要降右端填入到对应的表项中即可,用空串 表示Error。在根据LL(1)分析表选择产生式进行推导时,若查到的产生 式为空串表示无相应的产生式可选,不匹配错误;否则根据符号串得到 相应的产生式进行推导,即进行压栈操作。
3. 构造驱动程序
构造LL(1)驱动程序的算法: (1). 分析开始时,首先将标志符号#和文法开始符号S依次压入符号栈;输入流指针指向 第一个输入符号,即由符号栈和输入流构成的初始格局为: (#S, a1a2...an#) 然后,反复执行第2步所列的工作。 (2). 设在分析的某一步,符号栈及剩余的输入流处于如下的格局 (#X1X2...Xm-1Xm, aiai+1...an#) 其中,X1X2...Xm-1Xm为分析过程中所得的文法符号,此时,可视栈顶符号Xm的不同情况,分 别作如下动作: 若XmVN,则以Xm及ai组成的符号对(Xm,ai)查分析表T。设T(Xm,ai)为一产生 式,假设是XmUVW,此时将Xm从分析栈中退出,并将UVW压入栈中,从而得到新 的格局 (#X1X2...Xm-1WVU, aiai+1...an#) 但若T(Xm,ai)=Error,则调用出错处理程序进行处理; 若Xm=ai#,则表明栈顶符号已经与当前扫描的输入符号得到匹配,此时应将Xm(即 ai)从栈中退出,并将输入流指针向前移动一个位置。 若Xm=ai=#,则表明输入串已经完全得到匹配,此时即可宣告分析成功而结束分析。 其它情形,转错误处理程序。 程序见附录
附录:程序代码: import java.io.IOException; import java.util.Scanner; import java.util.Stack; public class test3{ static char[] a=new char[20]; static int n=0,i=0; static char c; static String s; static Stack<Character> sk = new Stack<Character>(); public static void main(String[] args){ System.out.println("input:"); Scanner in = new Scanner(System.in); char z = 0; try { z = (char)System.in.read(); } catch (IOException e) { e.printStackTrace(); } while(z!='$'){ a[n]=z; try { z=(char)System.in.read(); } catch (IOException e) { e.printStackTrace();
else if(a[i]==')'||a[i]=='$'){ System.out.println("E'->&"); c=sk.pop(); } else error(); } else if(c=='T'){ if(a[i]=='i'||a[i]=='('){ System.out.println("T->FT'"); sk.push('t'); sk.push('F'); c=sk.pop(); } else error(); } else if(c=='t'){ if(a[i]=='+'||a[i]==')'||a[i]=='$'){ System.out.println("T'->&"); c=sk.pop(); } else if(a[i]=='*'){ System.out.println("T'->*FT'"); sk.push('t'); sk.push('F'); sk.push('*'); c=sk.pop(); } else error(); } else if(c=='F'){ if(a[i]=='i'){ System.out.println("F->i");
Biblioteka Baidu
四、实验内容 已知文法G[E]: E→E+T|T
T→T*F|F F→(E)|i 说明:终结符号i为用户定义的简单变量, 即标识符的定义。 1、消除文法的左递归,构造对应文法的预测分析表; 2、根据构造的预测分析表,实现LL(1)分析中控制程序(表驱动程 序),并完成整个的LL(1)分析程序的界面设计、运行; 3、P104中,3.36写一个Yacc程序,把输入的算术表达式翻译成对 应的后缀表达式输出。要求转换正确,同时对于简单错误能够识别。 4、P104中,3.37,写一个Yacc“台式计算器”程序,它计算布尔表 达式,其中的词法分析器用Lex写。要求转换正确,同时对于简单错误 能够识别。 五、实验要求 1、输入串应是词法分析的输出二元式序列,即某算术表达式“实验 项目一”的输出结果。输出为输入串是否为该文法定义的算术表达式的 判断结果。 2、LL(1)分析过程应能发现输入串中的错误。 3、设计至少两个测试用例(尽可能完备,正确和出错),并给出测 试结果。 六、实验步骤、 1、分析文法 (1)E=>E+T=>E+T*F=>E+T*(E)即有E=>E+T*(E)存在左递归。用 直接改写法消除左递归,得到如下文法:G[E]: E→TE’ E’→+TE’|ε T→FT’ T’→*FT’|ε F→(E)|i (2)对于以上改进的文法,可以得到: FIRST(E’)=FIRST(+TE’)∪FIRST(-TE’)∪{ε}={+,ε} FIRST(T’)=FIRST(*FT’)∪FIRST(/FT’)∪{ε}={*,ε} FIRST(E)= FIRST( T ) = FIRST( F )=FIRST((E))∪FIRST(i)={(,i } 由此得到各非终结符的FOLLOW集合: FOLLOW(E)={ ),$} FOLLOW(E’)=FOLLOW(E)={),$} FOLLOW(T)=FIRST(E’)∪FOLLOW(E’)={ +,),$} FOLLOW(T’)=FOLLOW(T)={ +,),$}
集美大学计算机工程学院实验报告
课程名称:编译原理 实验编号: 实验三 班级:计算12 上机实践日期: 2014.12 指导教师:付永钢 姓名: 上机实践时间: 6学 时 实验成绩: 学号: 实验名称:LL(1)语法分析器的构造
一、实验目的 1、掌握LL(1)分析法的基本原理; 2、掌握LL(1)分析表的构造方法; 3、掌握LL(1)驱动程序的构造方法。 二、实验环境 Windows7 x64、VC6.0 三、实验原理 1、对文法要求