有偿请人帮忙完成简单的编译原理为什么叫龙书作业

编译原理网上作业_中华文本库
第1页/共3页
预算成绩情况
--------------------------------------------------------------------------------
作业名称:编译原理2012秋第四套作业
客观题预算成绩:100 分
注意:客观题是指单选题、多选题、是非题等能自动判分的题!
详细信息:
题型:单选题(请在以下几个选项中选择唯一正确答案)
本题分数:3.95
内容:
设 G 是一个给定的文法, S 是文法的开始符号,如果 S-&x( 其中 x∈V*), 则称 x 是文法 G 的一个_____。
A、候选式
B、句型
C、单词
D、产生式
学员答案:B
正确性:正确
题型:单选题(请在以下几个选项中选择唯一正确答案)
本题分数:3.95
内容:
文法 G 产生的_____的全体是该文法描述的语言。
A、句型
B、终结符集
C、非终结符集
学员答案:D
正确性:正确
题型:单选题(请在以下几个选项中选择唯一正确答案)
本题分数:3.95
内容:
文法 G 产生的()的全体是该文法描述的语言。
A、句型
B、终结符集
C、非终结符集
学员答案:D
正确性:正确
题型:单选题(请在以下几个选项中选择唯一正确答案)
本题分数:3.95
内容:
Chomsky 定义的四种形式语言文法中,0 型文法又称为_____
A、短语结构文法
B、前后文无关文法
C、前后文有关文法
D、正规文法
学员答案:A
正确性:正确
题型:单选题(请在以下几个选项中选择唯一正确答案)
本题分数:3.95
内容:
文法G[A]:A→bH H→BA B→Ab H→a 不是()
A、2型文法
B、正规文法
C、0型文法
D、1型文法
学员答案:B
正确性:正确
题型:单选题(请在以下几个选项中选择唯一正确答案)
本题分数:3.95
内容:
若文法 G 定义的语言是无限集,则文法必然是_____:
A、递归的
B、前后文无关的
C、二义性的
D、无二义性的
学员答案:A
正确性:正确
题型:单选题(请在以下几个选项中选择唯一正确答案)
本题分数:3.95
内容:
一个上下文无关文法 G 包括四个组成部分,它们是:一组非终结符号,一组终结符号,一个开始符号,以及一组 _____。
A、句子
B、句型
C、 单词
D、产生式
学员答案:D
正确性:正确
题型:单选题(请在以下几个选项中选择唯一正确答案)
本题分数:3.95
内容:
文法分为四种类型,即0型、1型、2型、3型。其中3型文法是_____。
A、短语文法
B、正则文法
C、上下文有关文法
D、上下文无关文法
学员答案:B
正确性:正确
题型:单选题(请在以下几个选项中选择唯一正确答案)
本题分数:3.95
内容:
如果文法G是无二义的,则它的任何句子α_____
第1页/共3页
寻找更多 ""编译原理作业_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
赠送免券下载特权
10W篇文档免费专享
部分付费文档8折起
每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
编译原理作业
&&兰州大学网络教育学院编译原理网上作业
你可能喜欢12345 随便看看
关于博主 博主系本科在校大学生(大三),计算机科学与技术专业,19年毕业,将是一名 Java 后端er,梦想进入一线互联网公司。感恩您的关注!长期求内推和实习机会 QQ交流群(交流或求助):
捐赠与支持 为了维持本站运营,博主提供有偿服务和广告投放,需要的可以扫右侧微信二维码或加 QQ寻人帮做编译原理作业:TINYC语言的扫描程序等
寻人帮做编译原理作业:TINYC语言的扫描程序等
RT,大概5、6号之前完成,报酬可议,有意的同学请联系QQ:7014770
《编译原理》作业(一)
完成扫描程序的设计与实现,具体要求为:
o 设计并实现TINYC语言的扫描程序;
o 完成并提交实验报告,扫描程序的源程序,编译后的可执行程序,例子和运行结果.
实验报告至少要包含如下内容:
1 实验目的;
2&&TINYC语言的词法说明,扫描器的输入和输出;
3 实验原理(所采用的过程);
3.1 记号种类及各记号所代表的字符串集合;
3.2 各记号对应的正则表达式及所有记号对应的正则表达式;
3.3 各记号对应的DFA及所有记号对应的DFA;
4 扫描程序的功能说明和程序说明,程序模块等;
5 输入示例及其运行结果;
6 总结: 获得的经验,遇到的问题,改进方案等.
回复 主楼 的帖子
提示: 作者被禁止或删除 内容自动屏蔽当前位置: >>
编译原理大作业
2017 届课程设计扫描器设计姓 学 学 专 班名: 号: 院: 业: 级:库尔班江.阿瓦克日
信息工程学院 计算机科学与技术 计算机 17-1 班塔里木大学教务处制 实验一 词法扫描器设计一 实验目的通过设计调试词法分析程序,实现从源程序中分出各种单词的方法;加深对课堂教学 的理解;提高词法分析方法的实践能力。二 实验内容设计一个简单的类 C 语言的词法扫描器。三 实验要求(一) 程序设计要求 (1) 根据附录给定的文法,从输入的类 C 语言源程序中,识别出各个具有独立意 义的单词,即关键字、标识符、常数、运算符、分隔符五大类;文法见最后 附录。 (2) 提供源程序输入界面; (3) 词法分析后可查看符号表和 TOKEN 串表; (4) 保存符号表和 TOKEN 串表(如:文本文件) ; (5) 遇到错误时可显示提示信息,然后跳过错误部分继续进行分析。 (二)实验报告撰写要求 (1) 系统功能(包括各个子功能模块的功能说明) ; (2) 开发平台(操作系统、设计语言) ; (3) 设计方案; 1) 主数据流图; 2) 主要子程序的流程框图(若有必要) ; 3) 模块结构图; 4) 主要数据结构:符号表、TOKEN 串表等。 (4) 具体设计过程(包括主控程序、各个功能模块的具体实现) 。四 实验总结 附录:类 C 语言的词法文法id? Letter &temp& int10? Num int10 | Num OP? +| - |* |/ |&| & | = | ( | ) | ; | ‘ | == | &= |&= | != Keyword?if | then | else | while | do Letter?a|b|c|d|e|f|g|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T| U|V|W|X|Y|Z Num?0|1|2|3|4|5|6|7|8|9 |ε &temp&? Letter &temp& | Num &temp& |ε一.设计内容1.根据附录给定的文法, 从输入的类 C 语言源程序中,识别出各个具有独立 意义的单词,即关键字、标识符、常数、运算符、分隔符五大类;文法见最后附 录。 2.源程序保存在文件中。 3.词法分析后可查看符号表和 TOKEN 串表; 4.保存符号表和 TOKEN 串表(如:文本文件) ;二.详细设计1.首先根据题目要求对要进行词法分析的单词符号进行编码。单词符号 main int char if else for while ID NUM = + * 种别编码 1 2 3 4 5 6 7 8 9 10 11 12 13 单词符号 [ ] { } , : ; > < >= <= == != 种别编码 17 18 19 20 21 22 23 24 25 26 27 28 29 / ( )14 15 162.在本实验中,将需要出来的文法符号分为几类: (1)关键字:在本实验中对关键字分别进行存储,在判断是否为标识符前首 先对关键字进行识别。 (2)标识符:标识符处理函数识别标识符。 正则定义为:(3)运算符:运算符包括 = + - * / ( ) [ ]{ 写函数进行识别。} , ;&&&=&===!= 等,需单独关系运算符需根据下图进行识别:(4)数字:在本例中仅识别整数。 digit = 1|2|3|4|5|6|7|8|9 Digit = 0|1|2|3|4|5|6|7|8|9 Digit = digit Digit* 3.扫描器 扫描器作为独立的子程序,首先进行扫描剔除无用的换行和连续的空格,对 处理后的代码进行分析。三.模块划分和实现1.数据结构 (1)ModulClass存储划分好的词法单元的分类,存储有单元的名称和单元的标 号,与上面的表格中的信息一致。 在程序开始时需要首先将分类信息读取然后填充表格class ModulClass //存储词法单元的分类 { public: string strID; //单元名字 //单元编号 }; ModulClass modulclass[ModulClass_size];(2)Codeclass存储在程序识别过程中识别到的词法单元class CodeClass //存储识别过程中识别的词法单元 { public: //名字 //编号 }; CodeClass codeclass[CodeClasss_size];2.预处理模块 readcode()函数 (1)代码存储在code.txt中,用C++流读取文件内容,相关代码如下。ifstream infile(&code.txt&,ios::in); if (!infile) { cout&&&无法打开代码文件!&&& exit(-1); } infile.getline(temp,1000,EOF); temp[strlen(temp)] = '\0'; (2)去除换行符号for(i = 0;i & strlen(temp);i++) { if(temp[i] == '\n') strtemp += & &; else strtemp += temp[i]; }(3)去除多余的空格符号,将多个空格连续的压缩成一个for(j = 0;j &= strtemp.length();) { if(strtemp[j] == ' ') { while(strtemp[++j] == ' ') {} strcode += ' '; //处理空格,将多个连续的空格压缩成一个 } else { strcode += strtemp[j]; j++; } } cout&&&消去空格和换行符处理结果&&&endl&&strcode&&3.文法输入模块 init_class() 该模块将表格中的文法符号通过文件读取的方式读取到实现建立好的对象 数组中,方便以后进行查询操作。 核心代码如下: while(!(in_class.eof())) { in_class&&modulclass[i].strID; in_class&&modulclass[i]. i++; } 4. 判断是否为标识符int is_key_ID(int forward,int back) //判断是否是标识符该函数判断读入的是否为标识符,根据标识符判断的正则表达式进行识别, 若非标识符则输出错误,若识别则将该标识符的字符串和种别码进行保存。 需建立两个指针, forwawrd 指针和 back指针, 首先forward指针移动, back 指针则指向标识符的第一个字符的位置,直到识别完毕。关键代码如下: while(++forward) //扫描字符串,返回 idtemp,保存forward { if(((strcode[forward] &= 65)&&(strcode[forward] &= 89)) || ((strcode[forward] &= 97)&&(strcode[forward] &= 122))) //下一个是字母 temp[++len] = strcode[forward]; else if((strcode[forward] &= 48)&&(strcode[forward] &= 57)) // 下一个是数字 temp[++len] = strcode[forward]; else { forward--; } }5.判断匹配关键字 判断该字符串符合标识符的文法之后, 需事先判断该标识符是否是系统预留 的关键字。bool iskey = //判断是否是key codeclass[num_class].code = //保存词法单元code属性 for(int i = 0;i & ModulClass_i++) //在表中查找当前词法单元的编号 { if(idtemp == modulclass[i].strID)//完全匹配:是关键字 { codeclass[num_class].number = modulclass[i]. iskey = } } if(!iskey) //如果不是关键字,即为ID { codeclass[num_class].number = 8; } num_class++; //ID的编号为86.判断是否是数字 函数:is_number(int forward,int back) 需建立两个指针, forwawrd 指针和 back指针, 首先forward指针移动, back 指针则指向标识符的第一个字符的位置,直到识别完毕。 若是数字则保存,指针回退一个字符。否则宣布错误信息。while(++forward) //扫描字符串,返回 idtemp,保存forward { if((strcode[forward] &= 48)&&(strcode[forward] &= 57))//下一个是数字 temp[++len] = strcode[forward]; else { forward--; } }7.判断是否是relop符号 分为两种情况:由一个字符组成和由两个字符组成 (1)仅有一个字符组成 if(temp[1] != '=' ) //该运算符仅有一个字符 { forward--; //回退指针 //保存词法单元 switch(temp[0]) { case '&': codeclass[num_class].code = &L&; //保存词法单元code属性 codeclass[num_class].number = 25; //ID的编号 case '&': codeclass[num_class].code = &G&; //保存词法单元code属性 codeclass[num_class].number = 24; //ID的编号 case '=': codeclass[num_class].code = &=&; //保存词法单元code属性 codeclass[num_class].number = 10; //ID的编号 } num_class++; } (2)由两个字符组成else //由两个字符构成,第二个为‘=’ { //保存词法单元 switch(temp[0]) { case '&': codeclass[num_class].code = &LE&; codeclass[num_class].number = 27; case '&': codeclass[num_class].code = &GE&; codeclass[num_class].number = 26; case '=': codeclass[num_class].code = &EQ&; codeclass[num_class].number = 28; case '!': codeclass[num_class].code = &NE&; codeclass[num_class].number = 29; } num_class++; } //返回当前扫描的位置 }//保存词法单元code属性 //relop的编号//保存词法单元code属性 //relop的编号//保存词法单元code属性 //relop的编号//保存词法单元code属性 //relop的编号8.词法单元扫描器 扫描器维持两个指针,forward指针和back指针,同时获取扫描区域的总长 度。根据back指针指向的字符的属性,判断该词法单元的种类,然后根据种类跳 转到相应的识别函数中去, 观察该函数能否被识别,若能够被识别则保存该词法 单元,跳转道下一个词法单元,否则输出错误信息。void scanner() { int forward = 0,back = 0; //维持两个指针 int lenth = strcode.length(); //扫描区域的总长度 num_class = 0; //记录识别出词法单元的个数方便存储 while(forward &= strcode.length()-1) //开始扫描 { temp = strcode[forward]; if(((temp &= 65)&&(temp &= 89)) || ((temp &= 97)&&(temp &= 122)))// 判断是 否是标识符或关键字 { back = forward = is_key_ID(forward,back); //识别该标识符或ID,存入相应的词 法单元,返回当前扫描位置forward指针 forward ++; back = //继续扫描下一个字符 } else if((temp &= 48)&&(temp &= 57)) //判断是否是数字 { back = forward = is_number(forward,back); forward++; back = } else if( (temp == '+') || (temp == '-') ||(temp == '*') ||(temp == '/') ||(temp == '(') ||(temp == ')') || (temp == '[') || (temp == ']') ||(temp == '{') ||(temp == '}') ||(temp == ',') ||(temp == ':') ||(temp == ';') )//判断是否是符号 { back = for(i = 0;i & ModulClass_i++) //在表中查找当前词法单元的编号 { if(modulclass[i].strID[0] == temp) { codeclass[num_class].number = modulclass[i]. codeclass[num_class].code = modulclass[i].strID; } } num_class++; //增加词法单元个数 forward++; back =
} else if((temp == '&') || (temp == '=') ||(temp == '&') ||(temp == '!') ) //判断是否 是relop比较运算符 { back = forward = is_relop(forward,back); forward++; back = } else if(temp == ' ') //空格 { forward++; back = } else { forward++; back = } }//while }9. 将产生的词法单元写入文件 依次将生成的对象写入文件即可。 outfile.open(&词法分析结果.txt&); for(i = 0;i & num_i++) { outfile&&codeclass[i].code&&& &; outfile&&codeclass[i].number&& cout&&codeclass[i].code&&& &; cout&&codeclass[i].number&& } outfile.close();四.实验结果 1.class文件的内容如下,存放预先设定好的词法单元2.code文件代码如下,存放要识别的程序源代码3.图为程序运行结果,为识别后的词法单元 五.实验总结本次实验中词法分析相关代码均由我一人独立编写。 理论联系实际的过程中比较坎坷,首先必须明白词法分析的过程,明白词法 单元的识别过程, 然后才能设计自己的程序。但书本知识和程序仍然有一定的差 距,在设计过程中必须按照步骤一步一步进行设计,按照标准的模块进行划分。 同时模块的划分必须合理, 尽量减少模块间的联系, 对今后调试程序有很大帮助。 同时通过这次实验我明白了正则文法的作用, 在学习形式语言的时候一直疑 惑文法的体系和正规文法的用处,在本次实验中我体会到了正则文法的威力,正 则文法可以很好的被计算机高级语言编程识别,而其他文法则没有这种优势。 附录:源代码//词法分析器 BaiChenjia #include &iostream& #include &string& #include &math.h& #include &fstream& #define ModulClass_size 29 #define CodeClasss_size 100 //存储处理过后的代码 int num_class = 0; //记录识别出的词法单元的个数 class ModulClass //存储词法单元的分类 { public: string strID; //单元名字 //单元编号 }; ModulClass modulclass[ModulClass_size]; class CodeClass //存储识别过程中识别的词法单元 { public: //名字 //编号 }; CodeClass codeclass[CodeClasss_size]; int readcode() //读取要处理的代码 { int i,j; char temp[1000]; strcode = &&; string strtemp = &&; //存储代码 ifstream infile(&code.txt&,ios::in); if (!infile) { cout&&&无法打开代码文件!&&& exit(-1); } infile.getline(temp,1000,EOF); temp[strlen(temp)] = '\0'; infile.close(); for(i = 0;i & strlen(temp);i++) { if(temp[i] == '\n') strtemp += & &; else strtemp += temp[i]; } strtemp[i] = '\0'; for(j = 0;j &= strtemp.length();) { if(strtemp[j] == ' ') { while(strtemp[++j] == ' ') {} strcode += ' '; //处理空格,将多个连续的空格压缩成一个 } else { strcode += strtemp[j]; j++; } } cout&&&消去空格和换行符处理结果&&&endl&&strcode&& return 0; } void init_class() //对文法规定的标识符、数字、符号等进行分类,写入 modulclass对象中 { ifstream in_ in_class.open(&class.txt&); if (!in_class) { cout&&&无法打开代码文件!&&& exit(-1); } i = 0; while(!(in_class.eof())) { in_class&&modulclass[i].strID; in_class&&modulclass[i]. i++; } in_class.close(); /*for(i = 0;i & ModulClass_i++) cout&&modulclass[i].strID&&& &&&modulclass[i].number&&*/ } int is_key_ID(int forward,int back) //判断是否是标识符 { string idtemp = &&; char temp[100]; memset(temp,0,100); int len = 0; //记录该标识符或ID的长度-1 temp[0] = strcode[back]; while(++forward) //扫描字符串,返回 idtemp,保存forward { if(((strcode[forward] &= 65)&&(strcode[forward] &= 89)) || ((strcode[forward] &= 97)&&(strcode[forward] &= 122))) //下一个是字 母 temp[++len] = strcode[forward]; else if((strcode[forward] &= 48)&&(strcode[forward] &= 57)) //下一个是数字 temp[++len] = strcode[forward]; else { forward--; } 号} idtemp = //保存词法单元 bool iskey = //判断是否是key codeclass[num_class].code = //保存词法单元code属性 for(int i = 0;i & ModulClass_i++) //在表中查找当前词法单元的编 { if(idtemp == modulclass[i].strID)//完全匹配:是关键字 { codeclass[num_class].number = modulclass[i]. iskey = }} if(!iskey) //如果不是关键字,即为ID { codeclass[num_class].number = 8; } num_class++; //返回当前扫描的位置 }//ID的编号为8int is_number(int forward,int back) { char temp[100]; memset(temp,0,100); int len = 0; //记录该标识符或ID的长度-1 temp[len] = strcode[back]; while(++forward) //扫描字符串,返回 idtemp,保存forward { if((strcode[forward] &= 48)&&(strcode[forward] &= 57)) //下 一个是数字 temp[++len] = strcode[forward]; else { forward--; } } numtemp = //保存词法单元 codeclass[num_class].code = //保存词法单元code属性 codeclass[num_class].number = 9; //ID的编号为8 num_class++; //返回当前扫描的位置 } int is_relop(int forward,int back) //识别relop符号 { int len = 0; //记录该标识符或ID的长度-1 char temp[2]; temp[0] = strcode[back]; //第一个字符 temp[1] = strcode[++forward]; //第二个字符 if(temp[1] != '=' ) //该运算符仅有一个字符 { forward--; //回退指针 //保存词法单元 switch(temp[0]) { case '&': codeclass[num_class].code = codeclass[num_class]. case '&': codeclass[num_class].code = codeclass[num_class]. case '=': codeclass[num_class].code = codeclass[num_class].number } num_class++; } else //由两个字符构成,第二个为‘=’ { //保存词法单元 switch(temp[0]) { case '&': codeclass[num_class].code = codeclass[num_class]. case '&': codeclass[num_class].code = codeclass[num_class]. case '=': codeclass[num_class].code = codeclass[num_class]. case '!': codeclass[num_class].code = codeclass[num_class].number } num_class++; } //返回当前扫描的位置 }&L&; //保存词法单元code属性 = 25; //ID的编号 &G&; //保存词法单元code属性 = 24; //ID的编号 &=&; //保存词法单元code属性 = 10; //ID的编号&LE&; //保存词法单元code属性 = 27; //relop的编号 &GE&; //保存词法单元code属性 = 26; //relop的编号 &EQ&; //保存词法单元code属性 = 28; //relop的编号 &NE&; //保存词法单元code属性 = 29; //relop的编号void scanner() { int forward = 0,back = 0; //维持两个指针 int lenth = strcode.length(); //扫描区域的总长度 num_class = 0; //记录识别出词法单元的个数方便存储 while(forward &= strcode.length()-1) //开始扫描 { temp = strcode[forward]; if(((temp &= 65)&&(temp &= 89)) || ((temp &= 97)&&(temp &= 122)))//判断是否是标识符或关键字 { back = forward = is_key_ID(forward,back); //识别该标识符或ID,存入 相应的词法单元,返回当前扫描位置forward指针 forward ++; back = //继续扫描下一个字符 } else if((temp &= 48)&&(temp &= 57)) //判断是否是数字 { back = forward = is_number(forward,back); forward++; back = } else if( (temp == '+') || (temp == '-') ||(temp == '*') ||(temp == '/') ||(temp == '(') ||(temp == ')') || (temp == '[') || (temp == ']') ||(temp == '{') ||(temp == '}') ||(temp == ',') ||(temp == ':') ||(temp == ';') )//判断是否是符号 { back = for(i = 0;i & ModulClass_i++) //在表中查找当前词法单元 的编号 { if(modulclass[i].strID[0] == temp) { codeclass[num_class].number = modulclass[i]. codeclass[num_class].code = modulclass[i].strID; } } num_class++; //增加词法单元个数 forward++; back = } else if((temp == '&') || (temp == '=') ||(temp == '&') ||(temp == '!') ) //判断是否是relop比较运算符 { back = forward = is_relop(forward,back); forward++; back = } else if(temp == ' ') //空格 { forward++; back = } else { forward++; back = } }//while } void printFile() //将产生的词法单元写入文件 { outfile.open(&词法分析结果.txt&); for(i = 0;i & num_i++) { outfile&&codeclass[i].code&&& &; outfile&&codeclass[i].number&& cout&&codeclass[i].code&&& &; cout&&codeclass[i].number&& } outfile.close(); } int main() { readcode(); //读取代码文件并进行初步处理 init_class(); //读取对词法单元的分类信息 scanner(); //依次扫描识别词法单元 printFile(); //将识别结果存入文件中 getchar(); return 0; } 实验二 LR语法分析器设计一 实验目的通过设计调试 LR 语法分析程序,实现根据词法分析的输入 TOKEN 字,进行文法的 语法分析;加深对课堂教学的理解;提高语法分析方法的实践能力。二 实验内容使用附录中的文法,可以对类似下面的程序语句进行语法分析: a=2; b=1; if (a&b) c=a+b; else c=a-b;三 实验要求(一) 程序设计要求 (1)给出主要数据结构:分析栈、符号表; (2)将扫描器作为一个子程序,每次调用返回一个 TOKEN; (3)程序界面:表达式输入、语法分析的表示结果(文件或者图形方式) ; (二)实验报告撰写要求 (1)系统功能分析与设计(包括各个子功能模块的功能说明) ; (2)开发平台(操作系统、设计语言) ; (3)设计方案:包括功能模块结构图、主要函数的流程图; (4)主要数据结构:分析栈、分析表、符号表; (5)具体设计实现过程(包括主控程序、各个功能模块的具体实现) 。四 实验总结 附录:简单类 c 语言文法产生式 语义规则 注:P为文法的开始符号 说明语句部分文法: P→DS D →L D |ε L → int | float 程序语句部分文法: S → id = E; S.code = E.code || gen(id.place’:=’E.place) S → if (C) S1 C.true = C.false = S. S1.next = S. S.code = C.code || gen(C.true’:’) || S1.code S → if (C) S1 else S2 S → while (C) S1 do S2 C.true = C.false = S1.next = S2.next =S. S.code = C.code || gen(C.true’:’) || S1.code || gen(‘goto’S.next)|| gen(C.false’:’)|| S2. S → S ;S C → E1 & E2 C.code = E1.code || E2.code || gen(‘if’E1.place’&’E2.place’goto’C.true) || gen(‘goto’C.false) C → E1 & E2 C.code = E1.code || E2.code || gen(‘if’E1.place’&’E2.place’goto’C.true) || gen(‘goto’C.false) C → E1 == E2 C.code = E1.code || E2.code || gen(‘if’E1.place’=’E2.place’goto’C.true) || gen(‘goto’C.false) E → E1 + T E.place = E.code = E1.code||T.code|| gen(E.place’:=’E1.place’+’T.place) E → E1 C T E.place = E.code = E1.code || T.code || gen(E.place’:=’E1.place’-’T.place) E→T E.place = T. E.code = T.code T→F T.place = F. T.code = F.code T → T1 * F T.place = T.code = T1.code || F.code || gen(T.place’:=’T1.place’*’F.place) T → T1 / F T.place = T.code = T1.code || F.code || gen(T.place’:=’T1.place’/’F.place) F→(E) F → id F → int10F.place = E. F.code = E.code F.place = id. F.code = ‘ ‘ F.place = int10. F.code = ‘ ‘ 实验报告注:我编写的语法分析程序没有调试通,所以先实现了课本上的简单 文法的例子,即 E’―& E E ―& E+T | T T ―& T*F | F F ―& (E) | id 的文法的语法分析,并未完全实现本实验的要求。一.实验要求1.对已给语言文法,构造 LR(1)分析表,编制语法分析程序,要求将错误信息输 出到语法错误文件中,并输出分析句子的过程(显示栈的内容) ; 2.给出主要数据结构:分析栈、符号表。 3.将扫描器作为一个子程序,每次调用返回一个 TOKEN; 4.程序界面:表达式输入、语法分析的表示结果(文件或者图形方式) ;二.详细设计1.此次所写程序是以词法分析器为基础编写的。 2.考虑以下输入为合法: 数字 自定义变量 + * ( ) $作为句尾结束符。 其它符号都判定为非法。 3.首先我们构造状态转换图状action goto态Id0 S5+*(S4)$E1T2F3 1 2 3 4 5 6 7 8 9 10 11 S5 S5 S5S6 R2 R4 R7 R4 S4 R6 R6 S4 S4 S6 R1 R3 R5 S7 R3 R5 S11 R1 R3 R5 R6 R2 R4acc R2 R4 8 R6 9 3 10 2 3R1 R3 R54.根据状态转换图写出移入和规约关系。程序结构示意图 开始词法分析器符号入栈否 能否归约 否 是 归约状态转移否句尾或报错是 输出结 果三、程序结构描述:1.数据结构数据结构为两个栈和一个结构体。其中栈来存放符号和状态,结构体表示规 约中的项目的长度和字符, 方便栈来进行判断规约时弹出多少元素。均作为全局 变量进行申明。struct Current_node{}; int state[100]; //状态栈 //符号栈 char statename[100]=& &; //表示当前规约项目的长度和字符 2.状态转移函数int action(int a,char b): 其中 a 代表现在的状态编号,b 代表下一个输入的字符。 在形成的表中查找状态的转移情况,有状态的转移则表明执行的是移入操 作,返回值为移入后进入的状态的编号。 否则执行的是规约操作返回值为-2,下面转由 goto 函数执行规约操作并打 印规约结果。 关键代码如下:int action(int a,char b) //状态查找 返回值-1:acc -2:归约 -3:失败 它:状态转移 { if (a==0) { switch (b) { case 'E': return 1; case 'T': return 2; case 'i': return 5; case '(': return 4; case 'F': return 3; } } if (a==1) { switch (b) { case '+': return 6; case '$': return -1; //接受状态 } } if (a==2) { switch (b) { case '*': return 7; } return -2; } if (a==3) return -2; if (a==4) { switch (b) { case 'E': return 8; case '(': return 4; case 'T': return 2; case 'i': return 5; case 'F': return 3; } } if (a==5) return -2; if (a==6) { switch (b) { 其 case case case case }'T': 'F': '(': 'i':return return return return9; 3; 4; 5;} if (a==7) { switch (b) { case 'F': return 10; case '(': return 4; case 'i': return 5; } } if (a==8) { switch (b) { case ')': return 11; case '+': return 6; } } if (a==9) { switch (b) { case '*': return 7; } return -2; } if (a==10) return -2; if (a==11) return -2; return -3; }3.go_to 函数,进行规约node2 go(int a);//代入当前状态,返回归约结果和长度。该函数通过判断现在的状态和 follow 集中的规约状态进行规约,返回规约 后的规约项的长度和内容,同时变更栈中内容,进行下一步操作。//goto 函数代表规约的方向 Current_node go_to(int a) //当前项目为规约项目,则进行规约并进行输出 { Current_ if (a==3) { cout&&&根据T-&F 归约&&& b.c='T'; b.len=1; } if (a==5) { cout&&&根据F-&id 归约&&& b.c='F'; b.len=1; } if (a==2) { cout&&&根据E-&T 归约&&& b.c='E'; b.len=1; } if (a==10) { cout&&&根据T-&T*F 归约&&& b.c='T'; b.len=3; } if (a==11) { cout&&&根据F-&(E) 归约&&& b.c='T'; b.len=3; } if (a==9) { cout&&&根据E-&E+T 归约&&& b.c='E'; b.len=3; } }4.打印栈中的内容,输出符号栈和状态栈void printstack():5.读入下一个字符,进行下一步操作 int push(char b)(1)若输入为终结符号则显示接受成功。if (t == -1) { printf(&接受\n合法语句\n&); now=0; return 1; } //表示接受该语句,语法分析完成(2)返回值大于 1 进行移入操作,同时压入堆栈if (t & 0) { //进行移入操作 if (b == 'i') printf(&移入 id&); else printf(&移入 %c&,b); state[++now] = //状态栈深度加1 statename[now] = //符号栈进行更新 printstack(); //打印现在栈中的内容 return 1; }(3)返回值等于-2 进行规约操作,同时弹出堆栈while (t == -2) //表明将采取规约操作 { t2 = go_to(state[now]); //返回规约结果和函数 now -= t2. //进行弹出栈的操作,重新计算栈的深度 d = action(state[now],t2.c);//规约后进入的下一个状态 state[++now] = //将该状态入状态栈 statename[now] = t2.c; //符号栈进行更新 printstack(); //进行打印 t = action(state[now],b); //进行下一步操作 }(4)返回值为-3 则报错if (t==-3) //报错 { printf(&移入 %c 报错!\n&,b); return (result=0); }四.运行效果1.数据 2+*4*3$ 2.数据:asdf+12*123+(232*es+234)$五.实验总结语法分析过程较词法分析过程复杂, 而且是在词法分析的基础上 进行的,语法分析是编译程序的最重要的环节,通过本次实验我深刻 的理解了LR文法和移入―规约方法的内涵。首先构造状态集合,然 后根据状态集合写出状态转移表,分别进行移入和规约操作。 语法分析的核心在于栈的操作,包括状态栈和符号栈的操作,通 过状态栈动态的显示语法分析的进程,可以方便的看到分析的每一 步。同时我意识到了数据结构的重要性。 附录:程序源代码#include &iostream& #include &stdio.h& #include &stdlib.h& //首先申明全局变量 FILE * struct Current_node{}; //表示当前规约项目的长度和字符 int state[100]; //状态栈 char statename[100]=& &; //符号栈 int now=0; //表示栈顶指针 int result=1; //全局变量申明完毕//action函数代表状态转移的方向 int action(int a,char b) //状态查找 返回值-1:acc -2:归约 -3:失败 它:状态转移 { if (a==0) { switch (b) { case 'E': return 1; case 'T': return 2; case 'i': return 5; case '(': return 4; case 'F': return 3; } } if (a==1) { switch (b) { case '+': return 6; case '$': return -1; } } if (a==2) { //接受状态其 switch (b) { case '*': return 7; } return -2; } if (a==3) return -2; if (a==4) { switch (b) { case 'E': return 8; case '(': return 4; case 'T': return 2; case 'i': return 5; case 'F': return 3; } } if (a==5) return -2; if (a==6) { switch (b) { case 'T': return case 'F': return case '(': return case 'i': return }9; 3; 4; 5;} if (a==7) { switch (b) { case 'F': return 10; case '(': return 4; case 'i': return 5; } } if (a==8) { switch (b) { case ')': return 11; case '+': return 6; } } if (a==9) { switch (b) { case '*': return 7; } return -2; } if (a==10) return -2; if (a==11) return -2; return -3; }//goto 函数代表规约的方向 Current_node go_to(int a) //当前项目为规约项目,则进行规约并进行输出 { Current_ if (a==3) { cout&&&根据T-&F 归约&; b.c='T'; b.len=1; } if (a==5) { cout&&&根据F-&id 归约&; b.c='F'; b.len=1; } if (a==2) { cout&&&根据E-&T 归约&; b.c='E'; b.len=1; } if (a==10) { cout&&&根据T-&T*F 归约&; b.c='T'; b.len=3; } if (a==11) { cout&&&根据F-&(E) 归约&; b.c='T'; b.len=3; } if (a==9) { cout&&&根据E-&E+T 归约&; b.c='E'; b.len=3; } }//打印栈中的内容 void printstack() //打印栈 { printf(&\n&); for (int i=0;i&=i++) printf(&%2d &,state[i]); for (int i=0;i&=25-now*3;i++) printf(& &); for (int i=0;i&=i++) { printf(&%c&,statename[i]); if (statename[i]=='i') printf(&d&); else printf(& &); } for (int i=0;i&=25-now*2;i++) printf(& &); }//符号入栈,确定下一步操作 int push(char b) { int d,t; if (!result) { if (b=='$') { now=0; return (result=1); } else return 0; } if (now==0) { printf(& 栈 \n&); state[now]=0; printstack(); } t = action(state[now],b); //决定语法分析下一步操作并返回 if (t & 0) //进行移入操作 { if (b == 'i') printf(&移入 id&); else printf(&移入 %c&,b); state[++now] = //状态栈深度加1 statename[now] = //符号栈进行更新 printstack(); //打印现在栈中的内容 return 1; } Current_node t2; while (t == -2) { //表明将采取规约操作 符号 动作t2 = go_to(state[now]); //返回规约结果和函数 now -= t2. //进行弹出栈的操作,重新计算栈的深度 d = action(state[now],t2.c);//规约后进入的下一个状态 state[++now] = //将该状态入状态栈 statename[now] = t2.c; //符号栈进行更新 printstack(); //进行打印 t = action(state[now],b); //进行下一步操作 } if (t == -1) { //表示接受该语句,语法分析完成printf(&接受\n合法语句\n&); now=0; return 1; } if (t==-3) //报错 { printf(&移入 %c 报错!\n&,b); return (result=0); } }int main() { fp = fopen(&词法分析结果.txt&,&r&); if(fp == NULL) { cout&&&打开词法分析结果文件失败!&&& return 0; } while(!feof(fp)) { fscanf(fp,&%c%d&,&temp,&num); if(num == 9) key = 'i'; else key = push(key); } getchar(); return 0; } 实验三一 实验目的语义分析及中间代码生成通过上机实习,加深对语法制导翻译原理的理解,掌握将语法分析所识别的语法范畴 变换为某种中间代码的语义翻译方法。二 实验内容实现简单的高级语言源程序的语义处理过程。三 实验要求(一) 程序设计要求 (1) 目 标 机:8086 及其兼容处理器 (2) 中间代码:三地址码 (3) 设计结果:语法分析树(节点具有属性) 、三地址码表、符号表、TOKEN 串表 (4) 语义分析内容要求: 1) 变量说明语句 2) 赋值语句 3) 控制语句(任选一种) (5) 其它要求: 1) 将词法分析(扫描器)作为子程序,供语法语义程序调用; 2) 使用语法制导的语义翻译方法; 3) 编程语言自定; 4) 最好提供源程序输入界面; 5) 目标代码生成暂不做; 6) 编译后,可查看 TOKEN 串、符号表、三地址码表; 7) 主要数据结构:产生式表、符号表、三地址码表。 所用文法使用实验 2 中的文法。 附录:语义分析源程序范例 a=2; b=1; if (a&b) c=a+b; else c=a-b; (二)实验报告撰写要求 (1) 系统功能分析与设计(包括各个子功能模块的功能说明) ; (2) 开发平台(开发软硬件环境) ; (3) 语义翻译中使用的数据结构; (4) 程序具体设计实现过程(包括主要功能模块的具体实现) 。四 实验总结 一、实验目的1.设计结果:语法分析树(节点具有属性) 、三地址码表、符号表、TOKEN 串表。 2.语义分析内容要求:变量说明语句,赋值语句,控制语句。 3.编译后,可查看 TOKEN 串、符号表、三地址码表。二、详细设计采用递归下降语法制导翻译法,对算术表达式、赋值语句进行语义分析并生成四 元式序列。1 设置语义过程(1)emit(char *result,char *arg1,char *op,char *ag2) 该函数功能是生成一个三地址语句送到四元式表中。 数据结构:四元式表 结构如下: struct {char result[8]; char ag1[8]; char op[8]; char ag2[8]; }quad[20]; (2) char *newtemp() 该函数回送一个新的临时变量名,临时变量名产生的顺序为 T1,T2,…. Char *newtemp(void) { char *p; char m[8]; p=(char *)malloc(8); k++; itoa(k,m,10); strcpy(p+1,m); p[0]=’t’; return(p); } 2. 函数 lrparser 在原来语法分析的基础上插入相应的语义动作: 将输入串翻译 成四元式序列。只对表达式、赋值语句进行翻译。 3.步骤: 置处置、调用scanner扫描、调用Irparser进行翻译 三、运行效果四、实验总结 本次实验难度, 我参考了部分网上代码, 基本读懂了程序的意思。 再经过自己的理解,基本明白了中间代码生成的过程,加深了对语法 制导翻译原理的理解,掌握将语法分析所识别的语法成分变换为中间 代码的语义翻译方法。 附:程序源代码#include &stdio.h& #include &string.h& #include &stdlib.h& char prog[100],token[8], char *rwtab[6]={&begin&,&if&,&then&,&while&,&do&,&end&}; int syn,p,m,n,sum,q; struct { char result1[8]; char ag11[8]; char op1[8]; char ag21[8]; } quad[20]; char *factor(); char *expression(); int yucu(); char *term(); int statement(); int lrparser(); char *newtemp(); scaner(); emit(char *result,char *ag1,char *op,char *ag2); main() { q=p=kk=0; printf(&\nplease input a string (end with '#'): &); do { scanf(&%c&,&ch); prog[p++]= }while(ch!='#'); p=0; scaner(); lrparser(); for (j=0;j&q;j++) printf(& %s = %s %s %s \n\n&,quad[j].result1,quad[j].ag11,quad[j].op1,quad[j].ag21); //getch(); } int lrparser() { int schain=0; kk=0; if (syn==1) { scaner(); schain = yucu(); if(syn==6) { scaner(); if((syn==0)&&(kk==0)) printf(&Success!\n&); } else { if(kk!=1) printf(&short of 'end' !\n&); kk=1; //getch(); exit(0); } } else { printf(&short of 'begin' !\n&); kk=1; // getch(); exit(0); } return (schain); } int yucu() { int schain=0; schain=statement(); while(syn==26) { scaner(); schain=statement(); } return (schain); } int statement() { char tt[8],eplace[8]; int schain = 0; if (syn == 10) { strcpy(tt,token); scaner(); if(syn==18) { scaner(); strcpy(eplace,expression()); emit(tt,eplace,&&,&&); schain=0; } else { printf(&short of sign ':=' !\n&); kk=1; exit(0); } return (schain); } } char *expression() { char *tp,*ep2,*eplace,* tp = (char *)malloc(12); ep2 = (char *)malloc(12); eplace=(char *)malloc(12); tt=(char *)malloc(12); strcpy(eplace,term()); while((syn==13)||(syn==14)) { if (syn==13)strcpy(tt,&+&); else strcpy(tt,&-&); scaner(); strcpy(ep2,term()); strcpy(tp,newtemp()); emit(tp,eplace,tt,ep2); strcpy(eplace,tp); } return (eplace); } char *term() { char *tp,*ep2,*eplace,* tp = (char *)malloc(12); ep2 = (char *)malloc(12); eplace = (char *)malloc(12); tt = (char *)malloc(12); strcpy(eplace,factor()); while((syn==15)||(syn==16)) { if (syn==15)strcpy(tt,&*&); else strcpy(tt,&/&); scaner(); strcpy(ep2,factor()); strcpy(tp,newtemp()); emit(tp,eplace,tt,ep2); strcpy(eplace,tp); } return (eplace); } char *factor() { char * fplace=(char *)malloc(12); strcpy(fplace,&&); if(syn==10) { strcpy(fplace,token); scaner(); } else if(syn==11) { itoa(sum,fplace,10); scaner(); } else if(syn==27) { scaner(); fplace=expression(); if(syn==28) scaner(); else { printf(&error on ')' !\n&); kk=1; exit(0); } } else { printf(&error on '(' !\n&); kk=1; exit(0); } return (fplace); }char *newtemp() { char *p; char m[8]; p=(char *)malloc(8); kk++; itoa(kk,m,10); strcpy(p+1,m); p[0]='t'; return(p); } scaner() { sum=0; for(m=0;m&8;m++)token[m++]=NULL; m=0; ch=prog[p++]; while(ch==' ')ch=prog[p++]; if(((ch&='z')&&(ch&='a'))||((ch&='Z')&&(ch&='A'))) { while(((ch&='z')&&(ch&='a'))||((ch&='Z')&&(ch&='A'))||((ch&='0')&&(ch&='9'))) { token[m++]= ch=prog[p++]; } p--; syn=10; token[m++]='\0'; for(n=0;n&6;n++) if(strcmp(token,rwtab[n])==0) { syn=n+1; } } else if((ch&='0')&&(ch&='9')) { while((ch&='0')&&(ch&='9')) { sum=sum*10+ch-'0'; ch=prog[p++]; } p--; syn=11; } else switch(ch) { case '&':m=0; ch=prog[p++]; if(ch=='&') { syn=21; } else if(ch=='=') { syn=22; } else { syn=20; p--; } case '&':m=0; ch=prog[p++]; if(ch=='=') { syn=24; } else { syn=23; p--; } case ':':m=0; ch=prog[p++]; if(ch=='=') { syn=18; } else { syn=17; p--; } case '+': syn=13; case '-': syn=14; case '*': syn=15; case '/': syn=16; case '(': syn=27; case ')': syn=28; case '=': syn=25; case ';': syn=26; case '#': syn=0; default: syn=-1; } } emit(char *result,char *ag1,char *op,char *ag2) { strcpy(quad[q].result1,result); strcpy(quad[q].ag11,ag1); strcpy(quad[q].op1,op); strcpy(quad[q].ag21,ag2); q++; }
更多搜索:
All rights reserved Powered by
文档资料库内容来自网络,如有侵犯请联系客服。

我要回帖

更多关于 编译原理实验报告 的文章

 

随机推荐