洛阳网站建设,制作公司主页网站,网站没续费会怎样,江门市住房和城乡建设部网站文章目录 一、 设计目的及要求1.1 设计目的1.2 设计要求1.2.1 要求一1.2.2 要求二1.2.3 要求三 二、程序设计2.1 程序的组织结构2.1.1 PL/0编译程序函数定义层次结构2.1.2 PL/0编译程序函数过程或函数功能表2.1.3 PL/0指令功能表2.1.4 PL/0语言的出错信息表 2.2程序流程图2.2.1… 文章目录 一、 设计目的及要求1.1 设计目的1.2 设计要求1.2.1 要求一1.2.2 要求二1.2.3 要求三 二、程序设计2.1 程序的组织结构2.1.1 PL/0编译程序函数定义层次结构2.1.2 PL/0编译程序函数过程或函数功能表2.1.3 PL/0指令功能表2.1.4 PL/0语言的出错信息表 2.2程序流程图2.2.1 PL/0编译程序和解释执行过程2.2.2 PL/0程序语法分析2.2.3 else语句流程图2.2.4 do-while-until语句流程图2.2.5 for语句流程图 2.3 目标代码生成模式2.3.1 if-then-else2.3.2 do while-until2.3.3 for-to/downto-do 三、系统实现3.1 else语句扩充3.2 do-while-until语句扩充3.3 for语句扩充3.3.1 downto-do-end3.3.2 to-do-end 四、程序源代码4.1 else语句扩充4.2 do-while- until语句扩充4.3 for语句扩充4.3.1 “变量初值”部分代码4.3.2 “downto-do-end”部分代码4.3.3 “to-do-end”部分代码 五、系统测试5.1 else语句扩充5.2 do-while-until语句扩充5.3 for语句扩充 六、设计总结七、致谢源码与测试用例下载 一、 设计目的及要求
1.1 设计目的
根据所学的编译原理理论知识在符合 PL/0 语言基本词法、语法规则的前提下以原PL/0 编译程序C语言版本代码为基础对 PL/0 语言的功能进行扩充。使理论与实践相结合加深对编译原理的理解。
1.2 设计要求
1.2.1 要求一
1扩充语言成份“if 条件 then 语句系列1 else 语句系列2”。 2写出相应的编译程序。
1.2.2 要求二
1扩充语言成份“do while 语句系列 until 条件”即循环执行循环体内的语句系列直到条件为真为止。 2写出相应的编译程序
1.2.3 要求三
1扩充语言成份 ①“for 变量 初值 to 终值 do begin 语句系列 end” ②“for 变量 初值 downto 终值 do begin 语句系列 end” 其中语句①中循环变量的步长为1语句②中循环变量的步长为-1。 2写出相应的编译程序
二、程序设计
2.1 程序的组织结构
2.1.1 PL/0编译程序函数定义层次结构
表1 层次结构图
2.1.2 PL/0编译程序函数过程或函数功能表
表 2函数功能表
2.1.3 PL/0指令功能表
表 3指令功能表
2.1.4 PL/0语言的出错信息表
表 4 出错信息表 2.2程序流程图
2.2.1 PL/0编译程序和解释执行过程 图 1 解释执行过程
2.2.2 PL/0程序语法分析 图 2 语法分析流程图
2.2.3 else语句流程图 图 3 else语句流程
表 5 else语句四元式序列
2.2.4 do-while-until语句流程图 图 4 do-while-until 语句流程
表 6 do-while-until 语句四元式序列
2.2.5 for语句流程图 图 5 for语句流程
表 7 for语句四元式序列
2.3 目标代码生成模式
2.3.1 if-then-else 2.3.2 do while-until 2.3.3 for-to/downto-do 三、系统实现
3.1 else语句扩充
本部分程序首先判断then语句块的最后一个单词是否为“”。如果then最后一个字符是“”则需要跳过该符号之后再执行else及之后的语句。接下来的符号是else时先记录当前jmp指令的位置并为jpc指令赋值使if为false时能直接跳转到else语句之后进行代码执行然后调用函数处理else之后的语句最后为jmp指令赋值使if执行结束时能直接跳转到if-else结束位置。
图 6 else语句执行流程和代码结构
3.2 do-while-until语句扩充
本部分程序首先判断当前符号是否为do然后读取下一个字符并判断是否为while。接着记录当前位置此时为while循环体开始位置。接下来允许while后能接的字符为until然后执行while循环体内的语句。接着判断while的最后一个字符是否是“”是则跳过该符号执行until及之后的语句。当下一个符号是until时执行判断语句。当判断条件为false时执行条件跳转跳转到while循环体的开始位置继续运行。
图 7 do-while-until执行流程和代码结构
3.3 for语句扩充
首先识别当前符号为for然后执行变量定位与赋值语句。
3.3.1 downto-do-end
识别当前符号为downto记录当前位置即判断当前变量与终值大小关系的位置。将循环判断变量取出并放到栈顶后判断循环变量条件并生成比较指令判断此战顶是否大于等于栈顶往后退两个栈元素结果值进栈。再次记录当前位置即do循环开始的位置。识别当前符号是否为do并在成立的情况下运行do内循环体。然后将循环变量取出放到栈顶再将步长1取出放到栈顶执行指令次栈顶减去栈顶退两个栈元素结果值进栈最后将栈顶的值存入循环变量。这就完成了变量的自减。然后执行无条件跳转语句跳转到比较变量与终值大小关系的位置。最后地址回填将jpc的目的地址赋值为do执行完后的位置即当次栈顶小于栈顶时,结束for循环语句。
图 8 do-while-until语句执行流程和代码结构
3.3.2 to-do-end
与上述downto-do-end基本逻辑一致只是将判断的大于等于改为了小于等于将变量的自减改为了自增。 图 9 for语句执行流程和代码流程
四、程序源代码
4.1 else语句扩充
解决对编译程序if-else的扩展补充了代码中缺失的else语句块
//添加处理else语句
cx2cx; /*记录jmp指令的位置执行完then语句后需要无条件转移出发地址为cx2 */
gendo(jmp,0,0); /*执行完if为真后无条件转移,将来会直接跳转到else后 */
bool isSemifalse; //分号;跳过
code[cx1]a cx; /* 经statement处理后cx为else语句执行开始的位置它正是前面未定的跳转地址 (回填cx1的地址即if执行为假) 为jpc指令赋值 */
if(symsemicolon) //如果then语句块的最后一个单词为“”则跳过{getsymdo; //取下一个单词 isSemitrue; //有; }//接下来的符号是else
if(symelsesym) //若为else执行其中的语句{getsymdo;statementdo(fsys,ptx,lev); //处理else后的语句 code[cx2]acx; /*当前是else后语句的结束位置,判断正式结束回填if执行结束时的地址,为jmp指令赋值,if语句执行后应跳转至此*/
}
//上述为添加的else语句处理过程 4.2 do-while- until语句扩充
解决了do while until 语句的扩充在程序中添加了do while until语句块。
//添加do while until 语句
if (sym dosym) //此时识别的符号是do
{getsymdo;if (sym whilesym) //do while 语句 {cx1 cx; //记录当前的位置,即while循环体开始位置 getsymdo;memcpy(nxtlev, fsys, sizeof(bool)* symnum);nxtlev[untilsym] true; //后跟符号为until statementdo(fsys, ptx, lev); //执行while循环体 if (sym semicolon) //分号,跳过 {getsymdo;}if (sym untilsym) //为until 执行条件语句 {getsymdo;conditiondo(nxtlev, ptx, lev); //执行条件判断 gendo(jpc, 0, cx1); //条件跳转,为flase是跳转到while循环体内 }}
//以上为添加的do while until 语句 4.3 for语句扩充
解决对编译程序for语句的扩展补充了for-to和for-downto语句块
4.3.1 “变量初值”部分代码
找到变量位置并为变量赋初值
if(symforsym) //准备按照for语句处理
{getsymdo;if(symident) //准备按照赋值语句处理 {iposition(id,*ptx);if(i0){error(11); //变量未找到 }else{if(table[i]kind!variable){error(12); //赋值语句格式错误i0; }else{getsymdo;if(symbecomes) //变量赋初始值{getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlev[tosym]true;nxtlev[downtosym]true;nxtlev[dosym]true;expressiondo(nxtlev,ptx,lev);}else{error(13); //没有检测到赋值符号 }if(i!0){gen(sto,lev-table[i]level,table[i]adr);}4.3.2 “downto-do-end”部分代码
if(symdowntosym)
{cx1cx; //记录当前位置,即downto后开始判断当前变量与终值大小关系的位置 getsymdo; gendo(lod,lev-table[i]level,table[i]adr); //将循环判断变量取出放到栈顶 nxtlev[beginsym]true; //接下来识别的符号为begin expressiondo(nxtlev,ptx,lev); //判断循环变量条件 gen(opr,0,11); //生成比较指令 次栈顶是否大于等于栈顶退两个栈元素结果值进栈 cx2cx; //记录循环开始地址gen(jpc,0,0); //条件跳转,暂时未知目的地址 ,用0代替 if(symdosym){getsymdo ;statementdo ( fsys, ptx, lev) ; //运行do内代码 gen (lod, lev - table [i] level, table[i]adr); //将循环变量取出放在栈顶 gen (lit, 0, 1); //常数1添加到栈顶 即将步长取到栈顶 gen (opr, 0, 3); //循环变量减少1 次栈顶减去栈顶退两个栈元素结果值进栈gendo (sto, lev - table[i] level, table[i]adr); //将栈顶的值存入循环变量 gendo(jmp , 0, cx1); //无条件跳转,到判断变量与终值大小关系的位置 code[cx2]acx; /*地址回填, jpc的目的地址时do执行完后的位置
即当次栈顶小于栈顶时,结束for循环语句*/ } else{error(18);}
}
4.3.3 “to-do-end”部分代码
if(symtosym)
{cx1cx; //记录比较地址getsymdo;gendo(lod,lev-table[i]level,table[i]adr); memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[beginsym]true;expressiondo(nxtlev,ptx,lev); //处理循环边界表达式gen(opr,0,13); //生成条件比较表达式cx2cx; //记录条件跳转地址gen(jpc,0,0);if(symdosym){getsymdo;statementdo(nxtlev,ptx,lev);gen(lod,lev-table[i]level,table[i]adr); //变量提到栈顶gen(lit,0,1); //常数1加到栈顶gen(opr,0,2); //循环变量增加到1gendo(sto,lev-table[i]level,table[i]adr); //赋值gen(jmp,0,cx1); //回条件判断code[cx2]acx; //跳出循环 } else{error(18); /* 缺少do */}
}五、系统测试
5.1 else语句扩充 5.2 do-while-until语句扩充 5.3 for语句扩充 六、设计总结
经历了长达一周的课程设计工作,我们小组终于完成了本次课程设计的代码编写及论文编撰任务。我们在确认合作意向之后,很快就确定下来了各自的任务分工,在独立完成各自任务的同时,我们也常常合作工作,指出对方的不足并解决对方的一些问题很庆幸能与默契地搭档一起进行本次课程设计。
在课程设计的过程中,我们首先遇到的问题是庞大源代码的阅读我们需要先初步阅读并理解老师给出的基础代码之后,再在此基础上进行代码的扩充基础代码的行数已经多达上千行,我们采取分工的方式,一人读懂一部分函数的功能,然后再以口述的方式给对方讲解,节省理解代码的时间。
接下来,我们先进行的是if-else语句的扩充这一部分的难点是理清jpc和jmp的跳转以及地址的回填如何进行。我们根据老师给出的指导,仔细分析了代码执行流程和结构,确定了jpc和jmp的地址并根据网上查找到的资料,确定了地址回填的编写方式在编写过程中,我们起初将cx2cx语句写在了if(symelsesym)语句内部,后来检查的时候,我们经过讨论,认为应该放到if前,因为then的语句执行完之后即可跳转到else语句末尾,而不必先识别else再跳转。最后我们还是放在了外部因为如果放在外部在编译时无需再编译else语句能节省时间
dowhile语句的扩充因为有else的语句扩充作为基础,写代码并不困难,基本的逻辑思路是一致的但是我们犯了一个逻辑上的错误,我们把题目的do-while-until理解成了do-while的结构,导致地址的跳转逻辑错误。
for语句的难点是变量和终值大小的比较如何实现,以及变量的自增与自减如何实现我们首先确定了for语句的代码大致执行顺序与结构,但是接着的代码编写部分有些无从下笔我们决定先整理出函数表以及指令功能表,以便接下来的编写能更清晰地调用相关函数实现目标功能。for后的“变量初值”部分的代码直接使用的base代码中已给出的赋值代码并未做修改。变量与终值的比较及变量的自增自减我们在查找了相关的资料之后,才确定了gen的函数调用方式。
通过本次课设我们进一步巩固了编译原理的理论知识在课设过程中以实践的方式进一步加深了对相关知识的理解与应用。
七、致谢
在本次课程设计中首先我们由衷地感谢台安老师对于编译原理课程的教授与指导。从课程设计正式开始到后期的完成都离不开台老师的悉心指导。台老师严谨求时的治学态度踏实坚韧的工作精神平易近人的待人方式给我们许多启发和帮助。也正是因为老师的认真负责为我们编译原理的课设奠定了坚实的理论基础。在此我们再次向台老师致以诚挚的谢意和崇高的敬意。
其次在本次课设中还要感谢我亲爱的搭档我们两个人分工明确在确定了思路后就立刻开始完成自己的部分在不理解的地方一起进行讨论最终在规定的时间内完成。
最后再次感谢所有在本次课程设计中帮助过我们的老师和同学们
源码与测试用例下载
https://download.csdn.net/download/weixin_47500703/85901408