编译原理-递归下降子程序-课程设计报告
- 格式:doc
- 大小:138.50 KB
- 文档页数:8
武汉工程大学计算机科学与工程学院《编译原理》实验报告一、实验目的(1)掌握自上而下语法分析的要求与特点。
(2)掌握递归下降语法分析的基本原理和方法。
(3)掌握相应数据结构的设计方法。
二、实验内容编程实现给定算术表达式的递归下降分析器。
算术表达式文法如下: E E+T | TT T*F | FF(E) | i设计说明:首先改写文法为LL(1)文法;然后为每一个非终结符,构造相应的递归函数,函数的名字表示规则左部的非终结符;函数体按规则右部符号串的顺序编写。
三、设计分析(1)消去该文法左递归,得到文法:E TE1E1+TE1|εT FT1T1*FT1|εF(E)| I(2)根据LL(1)文法的判断条件,计算这个文法的每个非终结符的FIRST 集和FOLLOW集,经验证,改后的文法已经是LL(1)文法。
(3)最后构造递归下降分析程序,每个函数名是相应的非终结符,函数体则是根据右部符号串的结构编写。
a.当遇到非终结符时,如:+。
则编写语句 if(当读来的输入符号 == +) 读下一个输入符号b.当遇到非终结符时,例如:T。
则编写语句调用T()。
c.当遇到非终结符ε规则时,例如:Tε。
则编写语句 if(当前读来的输入字符不属于FOLLOW(T)) error()d.当某个非终结符的规则有很多个候选式时。
按LL(1)文法的条件能唯一的选择一个候选式进行推导。
(4)递归下降分析法是确定的自上而下分析法,基本思想是,对文法中的每个非终结符编写一个函数,每个函数的功能是识别由该非终结符所表示的语法成分。
因此需要分别构造E,E1,T,T1,F函数来执行自己的识别功能,根据文法的内容顺序决定函数的识别功能。
Scaner函数用于字符串的推进,input函数用于字符串的输入。
四、程序代码#include <>#include <>#include <iostream>using namespace std;char a[80];char sym;int i=0;void E();void E1();void T();elseError();}else if (sym =='i')Scaner();elseError();}五、测试用例1.输入的字符串只含有一个字符时:输入 i#a#2.输入的字符串含有 + 时:输入 ++#输入 i++#输入 i+i#3.输入的字符串含有 * 时:输入 **#输入 **i#输入 *i*#输入 i*i#i*i*#3.输入的字符串含有()时:输入()#(i)#4.输入的字符串含有多种字符:输入i+i*i#(i+i)*i#(i+i)*(i+i)#(i+*#。
递归下降分析器设计一、实验/实习过程内容:利用JavaCC生成一个MiniC的语法分析器;要求:1. 用流的形式读入要分析的C语言程序,或者通过命令行输入源程序。
2. 具有错误检查的能力,如果有能力可以输出错误所在的行号,并简单提示3. 如果输入的源程序符合MiniC的语法规范,输出该程序的层次结构的语法树具体实施步骤如下:1.把MiniC转换为文法如下<程序〉→ main()〈语句块〉〈语句块〉→{〈语句串〉}〈语句串〉→〈语句〉〈语句串〉|〈语句〉〈语句〉→〈赋值语句〉|〈条件语句〉|〈循环语句〉〈赋值语句〉→ ID =〈表达式〉;〈条件语句〉→ if〈条件〉〈语句块〉〈循环语句〉→ while〈条件〉〈语句块〉〈条件〉→(〈表达式〉〈关系符〉〈表达式〉)〈表达式〉→〈表达式〉〈运算符〉〈表达式〉|(〈表达式〉)|ID|NUM〈运算符〉→+|-|*|/〈关系符〉→<|<=|>|>=|==|!=2.消除语句中的回溯与左递归3.在eclipse环境下完成JavaCC的插件安装后,写一个JavaCC文法规范文件(扩展名为jj)4.完成的功能包括词法分析,语法分析二、代码:options {JDK_VERSION = "1.5";}PARSER_BEGIN(eg1)public class eg1 {public static void main(String args[]) throws ParseException { eg1 parser = new eg1(System.in);parser.start();}}PARSER_END(eg1)SKIP :{" "| "\r"| "\t"| "\n"}TOKEN : /* OPERATORS */{< PLUS: "+" >| < MINUS: "-" >| < MULTIPLY: "*" >| < DIVIDE: "/" >}TOKEN :{<BIGGER:">"> |<SMALLER:"<"> |<NOTVOLUTION:"!="> |<SMALLEREQDD:"<="> |<BIGGEREE:">=" > |<DOUBLE:"==">TOKEN: //关键字{<MAIN:"main"> |<VOID:"void"> |<IF:"if"> |<INT:"int"> | <WHILE:"while"> |<CHAR:"char"> | <VOLUTION:"="> }TOKEN : //定义整型数{< INTEGER: ["0" - "9"]( <DIGIT> )+ >| < #DIGIT: ["0" - "9"] >}TOKEN : //数字{<NUMBER:(<DIGIT>)+ | (<DIGIT>)+"."| (<DIGIT>)+"."(<DIGIT>)+| "."(<DIGIT>)+>}TOKEN : //标记{<COMMA:","> | <SEMICOLON:";"> | <COLON:":"> | <LEFTPARENTHESES:"("> |<RIGHTPARENTHESES:")"> | <LEFTBRACE:"{"> | <RIGHTBRACE:"}"> }TOKEN : //标识符{<IDENTIFIER:<LETTER> |<LETTER>(<LETTER> | <DIGIT> )* >|<#LETTER:["a"-"z", "A"-"Z"]>}void start():{}{<MAIN> <LEFTPARENTHESES> <RIGHTPARENTHESES> block() }void block():{}{<LEFTBRACE> string() <RIGHTBRACE>}void string():{}{yuju() (string())?}void yuju():{}{fuzhiyuju() | tiaojianyuju() | xunhuanyuju()}void fuzhiyuju():{}{<IDENTIFIER> <VOLUTION> biaodashi() <SEMICOLON>}void tiaojianyuju():{}{<IF> tiaojian() block()}void xunhuanyuju():{}<WHILE> tiaojian() block()}void tiaojian():{}{<LEFTPARENTHESES> biaodashi() guanxifu() biaodashi()<RIGHTPARENTHESES>}void biaodashi():{}{( <LEFTPARENTHESES> biaodashi() <RIGHTPARENTHESES> biaodashi2()) |(<IDENTIFIER> biaodashi2() ) | ( <NUMBER> biaodashi2() )}void biaodashi2():{}{(yunsuanfu() biaodashi() biaodashi2() )?}void yunsuanfu():{}{< PLUS > | < MINUS > |< MULTIPLY> | < DIVIDE >}void guanxifu() :{}{<BIGGER> | <SMALLER> | <NOTVOLUTION><SMALLEREQDD> | <BIGGEREE> | <DOUBLE>}三、实验/实习总结本次实习,我使用javacc完成了包括词法分析,语法分析(输出语法树),能够读文件的功能,总的来说比较满意,通过本次实习掌握了javacc基本的使用。
北华航天工业学院《编译原理》课程实验报告课程实验题目:递归下降子程序实验作者所在系部:计算机科学与工程系作者所在专业:计算机科学与技术作者所在班级:xxxx作者学号:xxxxx _ 作者姓名:xxxx指导教师姓名:xxxxx完成时间:2011年3月28日一、实验目的通过本实验,了解递归下降预测分析的原理和过程以及可能存在的回溯问题,探讨解决方法,为预测分析表方法的学习奠定基础。
分析递归下降子程序的优缺点。
二、实验内容及要求1.针对算术表达式文法:E→TE’E’→ +TE’|εT→FT’T’→*FT’ |εF→(E) |i为其编写递归下降子程序,判定某个算术表达式是否正确:如j+k*m,j*k+m输入:其输入数据应该为词法分析器输出的记号形式:i+i*i,i*i+i输出:分析结果:算术表达式结构正确或结构错误。
三、实验程序设计说明1.实验方案设计各个函数之间的调用关系如下图所示:2.程序源代码源代码如下:#include<stdio.h>#include<iostream>#include<fstream>#include<string>char a[10];int lookahead=0;void E1();void T();void T1();void F();void E(){printf("E->TE'\n");T();E1();}void E1(){if(a[lookahead]=='+'){printf("E'->+TE'\n");lookahead++;T();E1();}elseprintf("T'->ε\n"); }void T(){printf("T->FT'\n");F();T1();}void T1(){if(a[lookahead]=='*'){printf("T'->*FT'\n");lookahead++;F();T1();}elseprintf("T'->ε\n"); }void F(){if(a[lookahead]=='i'){printf("F->i\n");lookahead++;}else if (a[lookahead]=='('){lookahead++;E();if(a[lookahead]==')'){printf("F->(E)\n");lookahead++;}else{printf("\n括号不匹配分析失败!\n");exit (0);}}else{printf("括号不匹配,分析失败!\n");exit(0);}}int main(){while(1){printf("请输入算数表达式(以#键结束):");scanf("%s",a);E();if((a[lookahead]=='#'))printf("句子结构正确\n");elseprintf("无结束标志,分析失败\n");}return 0;}3.程序的执行结果程序运行结果如下所示:四、实验中出现的问题及解决方法1.错误处理:最初程序只是将所有的错误都简单的显示为句子结构错误,并没有进行具体详细的说明和解释,最后通过修改程序,细化错误类型,使用了对if语句的嵌套,将错误分为三种类型。
编译原理-实验⼆-递归下降分析程序构造集美⼤学计算机⼯程学院实验报告课程名称:编译原理指导教师:付永钢实验成绩:实验编号:实验⼆实验名称:递归下降分析程序构造班级:计算12姓名:学号:上机实践⽇期:2014.11上机实践时间: 4学时⼀、实验⽬的通过设计、编制、调试⼀个递归下降语法分析程序,实现对词法分析程序所提供的单词序列进⾏语法检查和结构分析,掌握常⽤的语法分析⽅法。
通过本实验,应达到以下⽬标:(1) 掌握从源程序⽂件中读取有效字符的⽅法和产⽣源程序内部表⽰⽂件的⽅法;(2)掌握语法分析的实现⽅法;(3)上机调试编出的语法分析程序。
⼆、实验环境Windows7 x64、VC6.0三、实验原理递归下降法是语法分析中最易懂的⼀种⽅法。
它的主要原理是,对每个⾮终结符按其产⽣式结构构造相应语法分析⼦程序,其中终结符产⽣匹配命令,⽽⾮终结符则产⽣过程调⽤命令。
因为⽂法递归相应⼦程序也递归,所以称这种⽅法为递归⼦程序下降法或递归下降法。
其中⼦程序的结构与产⽣式结构⼏乎是⼀致的。
递归下降分析程序的实现思想是:识别程序由⼀组⼦程序组成。
每个⼦程序对应于⼀个⾮终结符号。
每⼀个⼦程序的功能是:选择正确的右部,扫描完相应的字。
在右部中有⾮终结符号时,调⽤该⾮终结符号对应的⼦程序来完成。
⾃上向下分析过程中,如果带回溯,则分析过程是穷举所有可能的推导,看是否能推导出待检查的符号串。
分析速度慢。
⽽⽆回溯的⾃上向下分析技术,可根据输⼊串的当前符号以及各产⽣式右部⾸符,选择某⾮终结符的产⽣式,效率⾼,且不易出错。
⽆回溯的⾃上向下分析技术可⽤的先决条件是:⽆左递归和⽆回溯。
即:假设A 的全部产⽣式为A →α1|α2|……|αn ,则必须满⾜如下条件才能保证可以唯⼀的选择合适的产⽣式First(A →αi )∩First (A →αj )=Φ,当i≠j.⽆左递归:既没有直接左递归,也没有间接左递归。
⽆回溯:对于⼈以⾮中介符号U 的产⽣式右部n x x x |...||21,其对应的字的⾸终结符号两两不相交。
编译原理语法分析递归下降子程序实验报告编译课程设计-递归下降语法分析课程名称编译原理设计题目递归下降语法分析一、设计目的通过设计、编制、调试一个具体的语法分析程序,加深对语法分析原理的理解,加深对语法及语义分析原理的理解,并实现对文法的判断,是算符优先文法的对其进行FirstVT集及LastVT集的分析,并对输入的字符串进行规约输出规约结果成功或失败。
二、设计内容及步骤内容:在C++ 6.0中编写程序代码实现语法分析功能,调试得到相应文法的判断结果:是算符优先或不是。
若是,则输出各非终结符的FirstVT与LastVT集的结果,还可进行字符串的规约,输出详细的规约步骤,程序自动判别规约成功与失败。
步骤:1.看书,找资料,了解语法分析器的工作过程与原理2.分析题目,列出基本的设计思路1定义栈,进栈,出栈函数○2栈为空时的处理○3构造函数判断文法是否是算符文法,算符优先文法○4构造FirstVT和LastVT函数对文法的非终结符进行分析○5是算符优先文法时,构造函数对其可以进行输入待规约○串,输出规约结果○6构造主函数,对过程进行分析3.上机实践编码,将设计的思路转换成C++语言编码,编译运行4.测试,输入不同的文法,观察运行结果详细的算法描述详细设计伪代码如下:首先要声明变量,然后定义各个函数1.void Initstack(charstack &s){//定义栈s.base=new charLode[20];s.top=-1; }2. void push(charstack&s,charLode w){//字符进栈s.top++;s.base[s.top].E=w.E;s.base[s.top].e=w.e;}3. void pop(charstack&s,charLode &w){//字符出栈w.E=s.base[s.top].E; 三、w.e=s.base[s.top].e;s.top--;}4. int IsEmpty(charstack s){//判断栈是否为空if(s.top==-1)return 1;else return 0;}5.int IsLetter(char ch){//判断是否为非终结符if(ch='A'&&ch= 'Z')return 1;else return 0;}6.int judge1(int n){ //judge1是判断是否是算符文法:若产生式中含有两个相继的非终结符则不是算符文法}7. void judge2(int n){//judge2是判断文法G是否为算符优先文法:若不是算符文法或若文法中含空字或终结符的优先级不唯一则不是算符优先文法8.int search1(char r[],int kk,char a){ //search1是查看存放终结符的数组r中是否含有重复的终结符}9.void createF(int n){ //createF函数是用F数组存放每个终结符与非终结符和组合,并且值每队的标志位为0;F数组是一个结构体}10.void search(charLode w){ //search函数是将在F数组中寻找到的终结符与非终结符对的标志位值为1 }分情况讨论://产生式的后选式的第一个字符就是终结符的情况//产生式的后选式的第一个字符是非终结符的情况11.void LastVT(int n){//求LastVT}12.void FirstVT(int n){//求FirstVT}13.void createYXB(int n){//构造优先表分情况讨论://优先级等于的情况,用1值表示等于}//优先级小于的情况,用2值表示小于//优先级大于的情况,用3值表示大于}14.int judge3(char s,char a){//judge3是用来返回在归约过程中两个非终结符相比较的值}15.void print(char s[],charSTR[][20],int q,int u,int ii,int k){//打印归约的过程}16. void process(char STR[][20],int ii){//对输入的字符串进行归约的过程}四、设计结果分两大类,四种不同的情况第一类情况:产生式的候选式以终结符开始候选式以终结符开始经过存在递归式的非终结符后再以终结符结束篇二:编译原理递归下降子程序北华航天工业学院《编译原理》课程实验报告课程实验题目:递归下降子程序实验作者所在系部:计算机科学与工程系作者所在专业:计算机科学与技术作者所在班级:xxxx作者学号:xxxxx_作者姓名:xxxx指导教师姓名:xxxxx完成时间:2011年3月28日一、实验目的通过本实验,了解递归下降预测分析的原理和过程以及可能存在的回溯问题,探讨解决方法,为预测分析表方法的学习奠定基础。
根据某一文法编制调试递归下降分析程序,以便对任意输入的符号串进行分析。
#include<stdio.h>#include<stdlib.h>#define N 20char Str[N]; /* 用于存放输入的字符串 */int i=0;int max=0; /* 输入字符串的长度下标 */int curr=0; /* 当前字符的下标 */int flag=0; /* 用于标记判断过程中是否出现错误 */void inputString(); /* 输入要分析的字符串 */void nextChar(); /* 分析下一个字符 */void E();void G();void T();void S();void F();void outputResult(); /* 输出分析结果 */void inputString(){printf("\n实验名:递归下降分析程序\n\n");printf("姓名:汪茁\t学号:0904011035\t班级:09计本(4)班\n\n");printf("文法如下:\n");printf("(1) E->TG\n(2) G->+TG|-TG\n(3) G->ε\n(4) T->FS\n");printf("(5) S->*FS|/FS\n(6) S->ε\n(7) F->(E)\n(8) F->i\n\n");printf("请输入要分析的字符串(以'#'号结束):\n");for(i=0;i<N;i++){scanf_s("%c",&Str[i]);if(Str[i]=='#'){max=i;break;}}printf("\n");}void nextChar(){if(curr==max){exit(0);}else{curr++;}}void E(){T();}void G(){if(Str[curr]=='+'){nextChar();T();G();}else if(Str[curr]=='-'){nextChar();T();G();}}void T(){F();S();}void S(){if(Str[curr]=='*'){nextChar();F();S();}else if(Str[curr]=='/'){nextChar();F();S();}}void F(){if(Str[curr]=='('){nextChar();E();if(Str[curr]==')'){nextChar();}else{flag=1;}}else if(Str[curr]=='i'){nextChar();}{flag=1;}}void outputResult(){printf("分析结果:符号串");for(i=0;i<max;i++){printf("%c",Str[i]);}if(flag==0){printf("是合法的符号串!\n\n");}else{printf("是非法的符号串!\n\n");}}void main(){inputString();E();outputResult();}图 1 合法符号串[i*i+i-i/i]图 2 非法符号串[i*i+i-i/i-]图 3 带括号的合法符号串[i*(i+i)-i]图 4 带括号的非法符号串[i*(i+i-i]。
一、实验目的1. 理解递归下降分析法的原理和实现方法。
2. 掌握递归下降分析程序的设计和调试。
3. 加深对编译原理中语法分析部分的理解。
二、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发环境:Visual Studio 2019三、实验内容1. 递归下降分析法原理介绍2. 递归下降分析程序的设计与实现3. 递归下降分析程序的调试与测试四、实验步骤1. 递归下降分析法原理介绍递归下降分析法是一种自顶向下的语法分析方法,它将文法中的非终结符对应为分析过程中的递归子程序。
当遇到一个非终结符时,程序将调用对应的递归子程序,直到处理完整个输入串。
2. 递归下降分析程序的设计与实现(1)定义文法以一个简单的算术表达式文法为例,文法如下:E -> E + T| TT -> T F| FF -> ( E )| id(2)消除左递归由于文法中存在左递归,我们需要对其进行消除,消除后的文法如下:E -> T + E'E' -> + T E' | εT -> F T'T' -> F T' | εF -> ( E ) | id(3)设计递归下降分析程序根据消除左递归后的文法,设计递归下降分析程序如下:```cpp#include <iostream>#include <string>using namespace std;// 定义终结符const char PLUS = '+';const char MUL = '';const char LPAREN = '(';const char RPAREN = ')';const char ID = 'i'; // 假设id为'i'// 分析器状态int index = 0;string input;// 非终结符E的分析程序void E() {T();while (input[index] == PLUS) {index++;T();}}// 非终结符T的分析程序void T() {F();while (input[index] == MUL) {index++;F();}}// 非终结符F的分析程序void F() {if (input[index] == LPAREN) {index++; // 跳过左括号E();if (input[index] != RPAREN) {cout << "Error: Missing right parenthesis" << endl; return;}index++; // 跳过右括号} else if (input[index] == ID) {index++; // 跳过标识符} else {cout << "Error: Invalid character" << endl;return;}}// 主函数int main() {cout << "Enter an arithmetic expression: ";cin >> input;index = 0; // 初始化分析器状态E();if (index == input.size()) {cout << "The expression is valid." << endl;} else {cout << "The expression is invalid." << endl;}return 0;}```3. 递归下降分析程序的调试与测试将以上代码编译并运行,输入以下表达式进行测试:```2 +3 (4 - 5) / 6```程序输出结果为:```The expression is valid.```五、实验总结通过本次实验,我们了解了递归下降分析法的原理和实现方法,掌握了递归下降分析程序的设计与调试。
编译原理实验报告实验名称:编写递归下降语法分析程序实验类型:验证型实验指导教师:专业班级:姓名:学号:电子邮件:实验地点:实验成绩:日期:201 年 5 月 25 日一、实验目的通过设计、调试递归下降语法分析程序,实现用词法分析从源程序中分出各种单词并对词法分析程序提供的单词序列进行语法检查和结构分析,熟悉并掌握常用的语法分析方法。
明确语法分析器的功能,在词法分析的基础上进一步分析程序;加深对课堂教学的理解;提高语法分析方法的实践能力;通过本实验,应达到以下目标:1、掌握递归下降的结构模型。
2、掌握语法分析的实现方法。
3、上机调试编出的语法分析程序。
二、实验过程有了第一次的经验,这次还是先画出流程图。
流程图如下:三、实验结果语法分析实验成功。
赋值时少写数字:缺少括号时:附(txt文档内容):程序运行后写入的:四、讨论与分析这个程序是在实验一的基础上写的,用的递归下降的方法。
不止能识别,还能判断一些语法的正误。
刚看书上附录的代码时,头都大了,觉得自己完成不了。
但是真正一步一步看下去,画出了流程图,就很清晰明白了。
一个函数嵌套一个函数,一步一步往细处走,刚开始是大体轮廓,然后就深入,直到最低层的判断。
书上的程序还是有一些漏洞,比如要写多个语句时,if,for,while在语句内不能加括号,不然只能分析至第一个,遇到“}”就结束了,所以在txt文件里写程序代码的时候要注意不能加{},这样才可以全部printf出来。
五、附录:关键代码(给出适当注释,可读性高)全部代码附vc++,这里粘贴主程序,以及各类函数。
int TESTparse();int TESTscan();int program();int compound_stat();int statement();int expression_stat();int expression();int bool_expr();int additive_expr();int term();int factor();int if_stat();int while_stat();int for_stat();int write_stat();int read_stat();int declaration_stat();int declaration_list();int statement_list();int compound_stat();#include<stdio.h>#include<ctype.h>int TESTscan();int TESTparse();FILE *fin,*fout;void main(){int es=0;es=TESTscan();if(es>0)printf("词法分析有错!编译停止!\n");else{printf("词法分析成功!\n");}if(es==0){es=TESTparse();if(es==0)printf("语法分析成功!\n");elseprintf("语法分析错误!\n");}}六、实验者自评这个实验比第一个有难度,是在第一个完成的基础上进行的。
编译原理课程设计报告2011 年 12 月 2 日设计题目 递归下降分析程序的实现 学号专业班级 计算机科学与技术学生姓名指导教师一、实验目的:(1)掌握自上而下语法分析的要求与特点。
(2)掌握递归下降语法分析的基本原理和方法。
(3)掌握相应数据结构的设计方法。
二、实验内容:递归下降分析程序的实现设计内容及要求:对文法 G: E→E+T|T构造出G的递归下降分析程序。
程序显示输出T→T*F|F匹配过程(即自上而下生成语法分析树的步骤,F→(E)|i 输出各匹配产生式序号即可)。
三、设计思路:(1)语法分析:语法分析是编译程序的核心部分,任务是分析一个文法的句子结构。
递归下降分析程序的实现的功能:按照文法的产生式(语言的语法规则),识别输入符号串是否为一个句子(合式程序)。
(2)自上而下分析:从文法的开始符号出发,向下推导,推出句子。
可分为带“回溯”的和不带回溯的递归子程序(递归下降)分析方法。
它的主旨是对任何输入串,试图用一切可能的办法,从文法开始符号(根结点)出发,自上而下地为输入串建立一棵语法树。
或者说,为输入串寻找一个最左推导。
也即从文法的开始符号出发,反复使用各种产生式,寻找"匹配"的推导。
(3)递归下降分析法:对每一语法变量(非终结符)构造一个相应的子程序,每个子程序识别一定的语法单位,通过子程序间的信息反馈和联合作用实现对输入串的识别。
(4)分析过程中遇到的问题:a. 分析过程中,当一个非终结符用某一个候选匹配成功时,这种匹配可能是暂时的。
出错时,不得不“回溯”。
b.文法左递归问题。
含有左递归的文法将使自上而下的分析陷入无限循环。
(5)构造不带回溯的自上而下分析算法:a.要消除文法的左递归性:一个文法可以消除左递归的条件是①不含以 为右部的产生式②不含回路。
b.克服回溯,构造不带回溯的自上而下分析的文法条件(6)满足LL(1)文法的三个条件:①. 文法不含左递归,②. 对于文法中每一个非终结符A的各个产生式的候选首符集两两不相交。
即,若A→α 1|α2|…|α n 则 FIRST(αi)∩FIRST(αj)=f(i≠j)③. 对文法中的每个非终结符A,若它存在某个候选首符集包含ε,则FIRST(α i)∩FOLLOW(A)=f i=1,2,...,n(7)因此我们可以把设计要求的文法首先改写为LL(1)文法E→TE'E'→+TE' | εT→FT'T'→*FT' | εF→(E) | iﻩ然后构造每个非终结符的FIRST和FOLLOW集合:FIRST(E) ={ ( ,i } FIRST(E')={ + , e }FIRST(T)={ ( ,I }FIRST(T')={ * ,ε} FIRST(F) ={ ( , I } FOLLOW(E)={ ) ,# }FOLLOW(E')={) , # }FOLLOW(T) ={ + , ) , # }FOLLOW(T')={+, ) , # } FOLLOW(F) ={ *, + , ) , # }确定改写后的文法为LL(1)文法;然后为每一个非终结符,构造相应的递归过程,过程的名字表示规则左部的非终结符;过程体按规则右部符号串的顺序编写。
然后再为每个非终结符设计一个对应的函数,通过各函数之间的递归调用从而实现递归下降语法分析的功能。
(8)编写C++代码用到的变量和几个功能识别函数:①.advance=0; //字符串小标,表示使IP指向下一输入符号。
②. void E(); // 功能识别函数,表示规则E->TE'void E1(); // 功能识别函数,表示规则E'->+TE'/εvoid T(); // 功能识别函数,表示规则T->FT'void T1(); //功能识别函数,表示规则T'->*FT'/εvoidF(); // 功能识别函数,表示规则F->(E)/i 因为每个非终结符有对应的子程序的定义,功能识别函数的编写过程中,当需要从某个非终结符出发进行展开(推导)时,就调用这个非终结符对应的子程序。
功能识别函数的设计与编写:(1)当遇到终结符a时,则编写语句If(当前读到的输入符号==a)读入下一个输入符号(2)当遇到非终结符A时,则编写语句调用A()。
(3)当遇到A-->ε规则时,则编写语句If(当前读到的输入符号不属于Follow(A))error()(4)当某个非终结符的规则有多个候选式时,按LL(1)文法的条件能唯一地选择一个候选式进行推导.四、结果截图:1、输入一个正确的句子:2、输入一个错误句子3、输入一个无#结束的错误句子:五、代码:#include<iostream>#include<fstream>usingnamespace std;ifstream import("input sentence.txt");ofstream export("output rule.txt");#include<string>chara[10]; // 字符串的存入int advance=0; // 字符串小标,表示使IP指向下一输入符号void E(); // 功能识别函数,表示规则E->TE'void E1(); //功能识别函数,表示规则E'->+TE'/εvoid T(); // 功能识别函数,表示规则T->FT'void T1(); //功能识别函数,表示规则T'->*FT'/εvoid F(); // 功能识别函数,表示规则F->(E)/iint main() // 主函数{ﻩﻩexport<<"please input theright sentence(end with #):";//输入提示import>>a;E(); //从首个推导式E开始if((a[advance]=='#'))export<<"The sentence isright,success!\n";elseexport<<"No the signal of #,fail!\n";ﻩﻩreturn 0;}void E() // 功能识别函数{export<<"E->TE'\n";T();E1();}void E1(){if(a[advance]=='+'){export<<"E'->+TE'\n";//输出使用E'规则ﻩ advance++; //如果是“+”,则读取下一字符T(); //根据E'->+TE规则右部符号串的顺序,调用其他非终结符的规则ﻩE1();ﻩ}elseexport<<"E'->ε\n";}void T(){export<<"T->FT'\n";F(); //根据T->FT'规则右部符号串的顺序,调用其他非终结符的规则T1();}void T1(){if(a[advance]=='*') //如果是“*”,则读取下一字符{export<<"T'->*FT'\n";advance++;F();//根据T'->*FT'规则右部符号串的顺序,调用其他非终结符的规则ﻩﻩT1();}elseexport<<"T'->ε\n";}voidF(){if(a[advance]=='i') //如果是“i”,则读取下一字符{export<<"F->i\n";advance++;}else if(a[advance]=='(') //如果是“(”,则读取下一字符{ﻩadvance++;E(); //根据F->(E)规则右部符号串的顺序,调用非终结符E的规则if(a[advance]==')'){ﻩ export<<"F->(E)\n";advance++;ﻩﻩﻩ}ﻩﻩﻩelse{ﻩexport<<"\n ()isnot matching,error! \n";exit (0); //正常结束程序运行}}else{export<<"\n ()is not matching, error!\n";exit(0);//正常结束程序运行}}六、心得体会:(1)一个星期的课程设计,当中有苦也有乐,但从苦乐中我学到了很多东西。
通过这次课程设计我看到了自己的与别人的差距,有很多我自己不明白的地方别人都会。
当我自己一开始进行递归下降分析程序的课程设计时,我发现我有好多相关的小知识点还不太熟悉,于是我在结合书本和图书馆相关资料基础上,将课堂学习的知识予以真正的吸收和应用,功夫不负有心人,我最终琢磨出了解决该设计题的基本思路和方法。
(2)这次课程设计,不仅巩固了课堂知识,很好的复习了一下编译原理所学的内容,而且提高了自己的上机实践能力,有效的和实际结合在了一起,加强了我的动手、思考、解决问题的能力,并扩展了所学知识。
同时在设计过程中也发现了我的许多不足之处,比如对以前所学的知识理解的不够深刻,掌握的不够牢固。
此外,因为设计程序的各项流程需要心静下来慢慢思考,所以克服了最近比较浮躁的心态,同时也让自己充实了很多。
(3)在设计过程中也遇到了一些问题,比如编写程序时,每读入一个字符,要执行相应的递归函数,因为调用过程中有再次调用,我有好几次把函数的调用搞混,导致得出的结果不是我想要的。
所以要在草稿纸上先画出程序的流程图,理顺各子程序之间的调用关系,才能避免程序出错。
还有不仅要知道文法要改为LL(1)文法,还要明白为什么要改,修改后有哪些好处以及LL(1)文法的具体定义与判定方法。
在最后进行程序的功能和结果的测试当中,我采用了文件输入输出流,把文件作为输入输出对象的流,实现结果的可视化,从而告别黑白屏界面,但如果能用MFC平台实现可视化界面就更好了,那样更有技术含量,更简洁美观。
(4)既然是上机实践就会遇到各种问题,不畏艰难,不怕繁复,就是我们解决问题的方法。
通过这次的设计,我发现只要不放弃,在最困难的时候坚持下去,那么所有的事情都能迎刃而解。