第一篇:编译实习报告(范文)
篇一:编译原理实习报告
实习报告
【实习目的】
1.了解编译器的工作原理
2.掌握并加深本学期所学的编译原理的理论知识 3.加强自己的动手能力 【实习内容】
1.编译并运行老师所给的编译器参考代码
2.在第一步的基础上进一步改进编译器,增加输入输出功能 【开发平台】
window系统,free pascal编译器 【实习过程】
本次实习过程根据实习内容共分两大部分,第一部分,编译运行参考代码;第二部分,进一步改进编译器。本人在上面的基础上又增加了第三部分的额外修改。下面便总结这三部 分的实习过程:
一、增加读写语句前pl0编译程序
由于最原始的pl0编译程序所用的pascal版本较老,有些和当前使用版本不兼容,必须作相应修改,具体是:“object”和“procedure”为pascal的保留字,现分别改成“obj” 和“proc”。此外,原始程序中的“≠”、“≤”和“≥”,不能用ascii码表示出来,现将其 替换成“<>”、“<=”和“>=”。
作为一个编译程序,支持批量处理和永久保存是其应具备的基本功能。为此,本程序加 入了文件读写功能,即从文件读入pl0源程序,在将中间代码和运行结果写入文件。由于源程序和原始差别很小,为节省篇幅,不将其打印出来。
二、增加读写语句前pl0调试程序
下面是增加读写语句前的pl0程序,包含了乘、除法和寻找两个自然数的最大公因数 的过程和主过程,很好的说明了增加读写语句前的pl0语言的使用方法。const var x,y,z,q,r;procedure multiply;var a,b;a:=x;begin m=7,n=85;procedure divide;var end;b:=y;z:=0;while b>0 do begin end if odd b then z:=z+a;a:=2*a;b:=b/2;w;begin r:=x;q:=0;w:=y;while w<=r do w:=2*w;while w>y do begin q:=2*q;w:=w/2;if w<=r then begin r:=r-w;q:=q+1 end end end;procedure gcd;var f,g;begin f:=x;g:=y;while f<>g do begin if f 下面所给清单是用 (一)中增加读写语句前pl0编译程序对 (二)中的pl0程序编译 生成的中间代码。其中,第一部分是pl0程序和对应的中间代码,第二部分(“start pl/0” 到“end pl/0”之间编译程序对生成中间代码的模拟解释执行结果,打印出来的是sto(存 数)指令产生的。 0 const 1 m=7,n=85;1 var1 x,y,z,q,r;1 procedure multiply;1 var2a,b;2 begin 3a:=x;5b:=y;7z:=0;9while b>0 do 13begin 13 if odd b then z:=z+a;20 a:=2*a;24 b:=b/2;28end 28 end;2 int 0 5 3 lod 1 3 4 sto 0 3 5 lod 1 4 6 sto 0 4 7 lit 0 0 8 sto 1 5 9 lod 0 410 lit 0 0 11 opr 012 12 jpc 029 13 lod 0 4 14 opr 0 6 15 jpc 020 16 lod 1 5 17 lod 0 3 18 opr 0 2 19 sto 1 5 20 lit 0 2 21 lod 0 3 22 opr 0 4 23 sto 0 3 24 lod 0 4 25 lit 0 2 26 opr 0 5 27 sto 0 4 28 jmp 0 9 29 opr 0 0 30 30 procedure divide;30 var 31w;31 begin 32r:=x;34q:=0;36w:=y;38while w<=r do w:=2*w;47while w>y do 51begin q:=2*q;w:=w/2;59 if w<=r then 62 begin 63 r:=r-w;67 q:=q+1 69 end 71end 71 end;31 int 0 4 32 lod 1 3 33 sto 1 7 34 lit 0 0 35 sto 1 6 36 lod 1 4篇二:实习报告 目 录 1、前言 1.1实习单位简介 1 2、实习目的 2.1实习内容简要提纲??2 3、操作具体过程 3.1学习安装altium designer 9运行环境? ??3 3.2学习运用altium designer 9,设计并绘制avr单片机系统的pcb电路板 ???4 3.3实现pcb电路板的生成及手工布线 ???5 3.4熟悉tq2440开发板的硬件和基本用法 ??7 3.5编译mp3播放器及移植?8 4、实习总结 4.1实习收获?? 16 4.2个人小结?? 16 一、前言 本次昆山实习作为我们电子信息工程专业的毕业设计意义很大。这次实习的主要内容是在linux操作系统环境下实现mp3播放器的嵌入式设计。围绕此项内容我们实习开展设计环境的搭建,再到嵌入式系统的熟悉、移植和mp3播放器的实现,进行了一系列学习和实践。我们的团队达到了预期的目的,并较好的完成了这次实习的任务。这次实习于我于我们的团队都是受益匪浅的。1.1实习单位简介 杰普软件科技有限公司(briup technology,inc.)是一家专注于高端it培训、软件外包、研发咨询的高新技术企业。公司在电信、金融、电子商务等方面有着丰富的专业开发、管理和培训经验。公司核心成员由海外留学人员和来自sybase、亚信、sun等国际大公司的资深技术人员组成。在电信、金融、电子商务等方面有着丰富的专业开发、管理和培训经验。是上海市人事局许可的高级人才培训中心。同时也是上海是紧缺人才办公室培训基地。 杰普软件着重解决软件企业用人难的问题,在高校毕业生及企业之间搭建一个供需桥梁。公司依托拥有丰富开发及培训经验的师资团队,培养企业紧缺的中高端开发人才。推出的解决大学生就业问题的dsp方案,已成功向各大软件企业输送了数千名人才,也确保了杰普软件外包业务的高效性和扩展性。公司与高校深度合作,为解决大学生的就业问题,提出多种合作方案。 杰普公司的培训师均来自各大it公司一线研发团队,平均具有7年的项目研发经验,是中国内地最优秀的培训讲师。他们不仅承担着杰普公司的学员培养工作,同时带领杰普公司的工程师及学员团队实施由政府及相关事业单位资助和委托的、杰普公司所承担的新产品研发和项目开发工作。他们随时把杰普公司最新的研发成果转化到对学员的培养中,确保了杰普每一位学员的技术研发能力以及优秀学员的创新能力、团队管理能力,保证了杰普学员在人才市场上竞争力及未来职业发展的广阔空间。 昆山校区位于有着“镶嵌在苏州与上海之间的一颗明珠之称”历史文化名城昆山市巴城镇,风景优美,环境典雅,教室与宿舍设置更是位于阳澄湖畔,凭窗而望,斜阳染湖,登高展臂,山水怀中,春夏有巴城鱼美,秋冬有阳澄蟹肥,是学习生活的好地方。昆山浦东软件园是国家级软件产业基地出口基地,上海浦东软件园和昆山市政府合作共建的项目,园区位于昆山巴城阳澄湖畔,拥有70万平方米工作生活环境,是一个与自然生态协调,符合高科技研发产业从业人员工作生活习惯的生态产业园区,2011年,杰普软件受昆山浦东软件园的邀请,入驻园区,作为软件园产业链重要的人才供应点。 二、实习目的本次赴昆山实习,主要是通过杰普集团给我们提供的实习和实训,学习嵌入式系统熟悉嵌入式系统的一些基本的理论概念和实践操作。一方面,通过学习专业知识,增强实践观念和能力;另一方面,通过杰普的实训进一步的对项目进行一次深度的了解,为未来就业提供必要的经验。 本次实习目标是对嵌入式系统有一定的了解,这次实习的主要内容是在linux操作系统环境下实现mp3播放器的嵌入式设计。从熟悉linux到shell命令,再到嵌入式系统的搭建、移植和mp3播放器的实现,进行了一系列学习和实践。杰普为我们提供了以下进程: 2.1实习内容简要提纲: ①学习安装altium designer 9运行环境。 ②学习运用altium designer 9,设计并绘制avr单片机系统的pcb电路板。 ③实现pcb电路板的生成及手工布线。 ④熟悉tq2440开发板的硬件和基本用法。 ⑤编译mp3播放器及移植。 三、操作具体过程 3.1学习安装altium designer 9运行环境 安装步骤如下:软件激活:在原文件altium.designer.v6.9.0.12759下找到文件夹ad_6.9_cr,将altium.alf和dxp.exe可执行文件拷贝到安装文件下,替换即可,然后重新打开就可以自动生成)若要想每次使用的话可以使用快捷方式,发送到桌面上即可。3.2学习运用altium designer 9,设计并绘制avr单片机系统的pcb电路板 电路板的设计是指一个电子产品从功能分析、设计思路、可行性验证到电路原理图设计、印制电路板制作、调试测试一直到最后产品成形的全过程。整个电路板设计过程可以分为以下几个主要步骤,如下所示: atmega16 单片机最小系统的硬件电路图如下: 篇三:编译实习-语法分析 编号: 《编译原理》课程 实习报告 编 号: 3 实习题目: 语法分析器 专业(班): 计科六班 学生学号: 2011301500204 学生姓名:何子龙 任课教师: 1.问题定义与分析 1.1 实习目的 构造一个小语言的语法分析程序。1.2 实习要求((1)输入属性字文件,输出源程序是否符合语法要求的结果: 正确——该程序符合语法要求。错误——指出错误位置。(2)运行实例: 例 1: 输入 i:=1+;输出表达式错误。 例2: 输入 program ex1;begin i:=1 end.输出该程序是正确的。1.3 要求分析 1.3.1 输入部分 输入为文法源程序,定义cstring 类型变量 m_enterstring,用于获取 编辑框1的输入,将其转换为char类型的数组,用s 保存,即char *s=m_enterstring.getbuffer()。1.3.2 输出部分 对于错误的程序,输出相应错误类型;对于正确的程序,输出该程序是正确的。定义cstring 类型变量m_outputstring,用于输出词法分析结果到编辑框2,用如下函数给m_outputstring 添加输出内容,如程序正确时代码:m_outputstring.insert(m_outputstring.getlength(),该程序是正确的);如图所示: 1.3.3 待分析的简单语言的语法 用扩充的bnf表示如下: ⑴<程序>::=program begin<语句串>end|begin<语句串>end ⑵<语句串>::=<语句>{;<语句>} ⑶<语句>::=<赋值语句> ⑷<赋值语句>::=id:=<表达式> ⑸<表达式>::=<项>{+<项> |-<项>} ⑹<项>::=<因子>{*<因子> | /<因子> ⑺<因子>::=id | num |(<表达式>)1.3.4 语法中的各种单词符号对应的类别码其中对应于在词法分析程序中,变化的是将关键字do改为program,和begin两者至少出现一个作为程序的开始标志。2.设计 2.1 数据结构 定义了以下字符串类型数据: cstringm_enterstring :用于接受编辑框1输入的源程序 cstringm_outputstring;:用于保存输出到编辑框2的内容,即输出源程序是正确的还是错误的,对于错误的程序还需要说明错误类型 char *s=m_enterstring.getbuffer():用于将输入的cstring类型转换为字符数组类型界面数据结构:(仅在词法分析程序的基础上改变了以下组件的位置与大小) idc_static1(group-box control)放输入框的框 idc_static2(group-box control)放输出框的框 idc_edit1(edit control)输入编辑框 idc_edit2(edit control)输出编辑框 idok(button control)确定按钮 idcancel(button control)取消按钮 idd_cifa_dialog(dialog)整个界面框 界面如下图所示: 2.2.算法及程序流程图 2.2.1算法设计: 算法的基本任务是在已完成的词法分析程序的基础上,对源程序的语法的正确性进行判断,编制一个递归下降分析程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析,对于输入的程序无语法错误的源程序,则输出该程序是正确的,若输入的源程序有语法错误,则输出相应的错误类型,具体见流程图。2.2.1程序流程图如下: a.主程序示意图如下图所示: 武 汉 纺 织 大 学 编译原理课程设计实验报告 学院:数学与计算机 专业:计算机 姓名: 班级: 学号: 编译原理 编译原理课设报告 一、实验目的 加强对编译程序的整体认识和了解,巩固《编译原理》课程所学知识。通过本次课程设计掌握编译程序调试技巧和设计编译程序一般的原则,加深对词法分析、语法分析、语义分析等编译阶段及实用编译系统的认识。使学生能将编译理论与实际应用结合起来,提高学生软件开发的能力。 二、实验内容 1)仔细阅读PL/0编译程序文本(编译原理(第二版)张素琴 吕映芝 蒋维杜 戴桂兰 主编 清华大学出版社),并上机调试通过。 2)对PL/0语言进行下列扩充(1)扩充一维整型数组。 扩充var数组:VAR <数组标识名>(<下界>:<上界>)〈下界〉和〈上界〉可用常量标识名。 (2)扩充条件语句的功能使其为:IF<条件>THEN<语句>[ELSE<语句>](3)增加repeat重复语句: REPEAT<语句>{;<语句>}UNTIL<条件> 可根据自己具体情况从中选择2个以上题目进行扩充。 三、实验原理 PL/0语言可以看成PASCAL语言的子集,它的编译程序是一个编译解释执行系统。PL/0的目标程序为假想栈式计算机的汇编语言,与具体计算机无关。 PL/0的编译程序和目标程序的解释执行程序都是用PASCAL语言书写的,因此PL/0语言可在配备PASCAL语言的任何机器上实现。其编译过程采用一趟扫描方式,以语法分析程序为核心,词法分析和代码生成程序都作为一个独立的过程,当语法分析需要读单词时就调用词法分析程序,而当语法分析正确需要生成相应的目标代码时,则调用代码生成程序。 用表格管理程序建立变量、常量和过程表示符的说明与引用之间的信息联系。 当源程序编译正确时,PL/0编译程序自动调用解释执行程序,对目标代码进行解释执行,并按用户程序的要求输入数据和输出运行结果。 四、实验分析 PL/0语言编译程序采用以语法分析为核心、一遍扫描的编译方法。词法分析和代码生成作为独立的子程序供语法分析程序调用。语法分析的同时,提供了出错报告和出错恢复的功能。在源程序没有错误编译通过的情况下,调用类PCODE解释程序解释执行生成的类PCODE代码。 词法分析子程序分析: 词法分析子程序名为GETSYM,功能是从源程序中读出一个单词符号(TOTAKEN),把它的信息放入全局变量 SYM、ID和NUM中,字符变量放入CH中,语法分析器需要单词时,直接从这三个变量中获得。Getch过程通过反复调用Getch子过程从源程序过获取字符,并把它们拼成单词。GETCH过程中使用了行缓冲区技术以提高程序运行效率。 词法分析器的分析过程:调用GETSYM时,它通过GETCH过程从源程序中获得一个字符。如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把SYM变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把SYM置为IDENT,把这个单词存入ID变量。查保留字表时使用了二分法查找以提高效率。如果Getch获得的字符是数字,则继续用Getch获取数字,并把它们拼成一个整数或实数,然后把SYM置为 INTEGER或REAL,并把拼成的数值放入NUM变量。如果识别出其它合法的符号(比如:赋值号、大于号、小于等于号等),则把SYM则成相应的类型。如果遇到不合法的字符,把SYM置成NUL。 语法分析子程序分析: 语法分析子程序采用了自顶向下的递归子程序法,语法分析同时也根据程序的语义生成相应三元代码,并提供了出错处理的机制。语法分析主要由分程序分析过程(BLOCK)、参数变量分析过程(ParaDeclaration)、参数变量处理过程(ParaGetSub)、数组处理过程(ParaGetSub)、常量定义分析过程(ConstDeclaration)、变量定义分析过程(Vardeclaration)、语句分析过程(Statement)、表达式处理过程(Expression)、项处理过程(Term)、因子处理过程(Factor)和条件处理过程(Condition)构成。这些过程在结构上构成一个嵌套的层次结构。除此之外,还有出错报告过程(Error)、代码生成过程(Gen)、测试单词合法性及出错恢复过程(Test)、登录名字表过程(Enter)、查询名字表函数(Position)以及列出类 PCODE代码过程(Listcode)作过语法分析的辅助过程。 由PL/0的语法图可知:一个完整的PL/0程序是由分程序和句号构成的。因此,本编译程序在运行的时候,通过主程序中调用分程序处理过程block来分析分程序部分(分程序分析过程中还可能会递归调用block过程),然后,判断最后读入的符号是否为句号。如果是句号且分程序分析中未出错,则是一个合法的PL/0程序,可以运行生成的代码,否则就说明源PL/0程序是不合法的,输出出错提示即可。 if-then-else语句的处理: 按if语句的语法,首先调用逻辑表达式处理过程处理if语句的条件,把相应的真假值放到数据栈顶。接下去记录下代码段分配位置(即下面生成的jpc指令的位置),然后生成 条件转移jpc指令(遇0或遇假转移),转移地址未知暂时填0。然后调用语句处理过程处理 then语句后面的语句或语句块。then后的语句处理完后,如果遇到else,就调用语句处理过程处理else语句后面的语句或语句块,这时当前代码段分配指针的位置就应该是上面的jpc指令的转移位置。通过前面记录下的jpc指令的位置,把它的跳转位置改成当前的代码段指针位置,否则没遇到else,那么此时的当前代码段分配指针的位置也是上面jpc指令的转移位置,也是通过前面记录下的jpc位置指令的位置,把它的跳转到当前的代码段指针位置。 Repeat语句的处理: 首先用CX1变量记下当前代码段分配位置,作为循环的开始位置。然后通过递归调用语句分析过程分析,直到遇到until保留字,如果未对应until则出错。调用条件表达式处理过程生成相应代码把结果放在数据栈顶,再生成条件转移指令,转移位置为上面记录的CX1。 五、相关代码及运行结果 实验代码; PL0.h代码: #include #ifndef WIRTH_ZYC_ #define WIRTH_ZYC_ using namespace std; const int norw = 16; // no.of reserved words 保留字的个数 const int txmax = 100; // length of identifier table 标示符表的长度(容量)const int al = 10; // length of identifiers 标示符的最大长度 const int nmax = 14; // max.no.of digits in numbers 数字的最大长度 const int amax = 2047; // maximum address 寻址空间 const int levmax = 3; // maximum depth of block nesting 最大允许的块嵌套层数 const int cxmax = 200; // size of code array 类PCODE目标代码数组长度(可容纳代码行数) const int lineLength = 82;// 行缓冲区长度 typedef enum {NUL,IDENT,NUMBER,PLUS,MINUS,TIMES,SLASH,ODDSYM,EQL,NEQ,LSS,LEQ,GTR,GEQ,LPAREN,RPAREN,COMMA,SEMICOLON,PERIOD,BECOMES,BEGINSYM,ENDSYM,IFSYM,THENSYM,WHILESYM,WRITESYM,READSYM,DOSYM,CALLSYM,CONSTSYM,VARSYM,PROCSYM,ELSESYM,REPEATSYM,UNTILSYM} symbol;// symobl类型标识了不同类型的词汇 typedef char alfa[al+1]; // alfa类型用于标识符 typedef enum {CONSTANT,VARIABLE,PROCEDURE,ARRAY} obj0; // 三种标识符的类型 typedef enum {LIT,OPR,LOD,STO,CAL,INT,JMP,JPC} fct; // functions typedef set struct instruction{ fct f;// function code int l;// level,cann't big than levmax int a;// displacement address,cann't big than amax }; // 类PCODE指令类型,包含三个字段:指令f、层差l和另一个操作数a /******************************************* * lit 0,a: load constant a * * opr 0,a: execute operation a * * lod l,a: load variable l,a * * sto l,a: store variable l,a * * cal l,a: call procedure a at level l * * int 0,a: increment t-register by a * * jmp 0,a: jump to a * * jpc 0,a: jump conditional to a * *******************************************/ typedef struct{ alfa name;obj0 kind;union { struct{int level,adr,size;}inOther; int val;}other;} Table; class PL0 { protected: bool listswitch,sourceEnd;char ch; // last character read symbol sym; // last symbol read alfa id; // last identifier read int num; // last number read int cc; // character count int ll; // line length int kk,err;int cx; // code allocation index int codeNo; // code line no.static string errStr[]; // error string char line[lineLength]; // code line vector // error array alfa a; // 词法分析器中用于临时存放正在分析的词 instruction code[cxmax+1]; // destination code array alfa word[norw+1]; // 保留字表 symbol wsym[norw+1]; // 保留字表中每一个保留字对应的symbol类型 symbol ssym[100]; // 一些符号对应的symbol类型表 合 char mnemonic[8][6]; // 类PCODE指令助记符表 symset declbegsys,statbegsys,facbegsys;// 声明开始、表达式开始和项开始符号集 Table table[txmax+1]; // 符号表 FILE* fin,*fout; public: PL0(char* source,char*destination); ~PL0(){fclose(fin),fclose(fout);} void error(int n); 位置和出错代码 void getsym(); 个单词 void getch(); 个字符 void gen(fct x,int y,int z); 程序区 void test(symset s1,symset s2,int n); 合法 void block(int lev,int tx,symset fsys); void enter(obj0 k,int &tx,int &dx,int lev); int position(alfa id,int tx);的位置 void constdeclaration(int&tx,int&dx,int lev); void vardeclaration(int&tx,int&dx,int lev); void listcode(int cx0); void statement(symset fsys,int tx,int lev); void expression(symset fsys,int tx,int lev); void term(symset fsys,int tx,int lev); void factor(symset fsys,int tx,int lev); void condition(symset fsys,int tx,int lev); void arraydeclaration(int& tx,int& dx,int lev); void interpret(); 执行程序 int base(int l,int b,int s[]); 基地址 void SaveCode(); // 构造函数 // 析构函数 // 出错处理,打印出错 // 词法分析,读取一 // 漏掉空格,读取一// 生成目标代码,并送入目标 // 测试当前单词符号是否 // 分程序分析处理过程 // 登入名字表 // 查找标示符在名字表中 // 常量定义处理 // 变量说明处理 // 列出目标代码清单 // 语句部分处理 // 表达式处理 // 项处理 // 因子处理 // 条件处理 // 数组说明处理 // 对目标代码的解释 // 通过静态链求出数据区的 // 保存代码 };#endif PL0.cpp代码: #include “pl0.h” // 错误字符串数组 string PL0::errStr[]={“",”error 0001: 常数说明中“=”写成“:=”“, ”error 0002: 常数说明中的“=”后应为数字“, ”error 0003: 常数说明中的标识符后应是“=”“, ”error 0004: const,var,procedure后应为标识符“, ”error 0005: 漏掉了‘,’或‘;’“, ”error 0006: 过程说明后的符号不正确(应是语句开始符或过程开始符)“, ”error 0007: 应是语句开始符“, ”error 0008: 过程体内语句部分的后跟符不正确“, ”error 0009: 程序皆为丢了句号‘.’“, ”error 0010: 语句之间漏了‘;’“, ”error 0011: 标识符没说明“, ”error 0012: 赋值语句中,赋值号左部标识符属性应是变量“, ”error 0013: 赋值语句左部标识符应是赋值号:=“, ”error 0014: call后应为标识符“, ”error 0015: call后标识符属性应为过程“, ”error 0016: 条件语句中丢了then“, ”error 0017: 丢了end或;“, ”error 0018: while型循环语句中丢了do“, ”error 0019: 语句后的标识符不正确“, ”error 0020: 应为关系运算符“, ”error 0021: 表达式内标识符属性不能是过程“, ”error 0022: 表达式中漏掉了右括号‘)’“, ”error 0023: 因子后的非法符号“, ”error 0024: 表达式开始符不能是此符号“, ”error 0025: 文件在不该结束的地方结束了“, ”error 0026: 结束符出现在不该结束的地方“, ”error 0027: “,”error 0028: “,”error 0029: “,”error 0030: “, ”error 0031: 数越界“, ”error 0032: read语句括号中标识符不是变量“, ”error 0033: else附近错误“ , ”error 0034: repeat附近错误“}; // PL0构造函数 PL0::PL0(char* source,char*destination){ listswitch=true,sourceEnd=false; strcpy(word[1],”begin“); // 初始化存储保留字 strcpy(word[2],”call“);strcpy(word[3],”const“); strcpy(word[4],”do“);strcpy(word[5],”else“);strcpy(word[6],”end“);strcpy(word[7],”if“);strcpy(word[8],”odd“);strcpy(word[9],”procedure“);strcpy(word[10],”read“); strcpy(word[11],”repeat“);strcpy(word[12],”then“);strcpy(word[13],”until“);strcpy(word[14],”var“); strcpy(word[15],”while“);strcpy(word[16],”write“); wsym[1]= BEGINSYM; wsym[2]= CALLSYM;留字对应的symbol类型 wsym[3]= CONSTSYM; wsym[4]= DOSYM;wsym[5]= ELSESYM; wsym[6]= ENDSYM;wsym[7]= IFSYM; wsym[8]= ODDSYM;wsym[9]= PROCSYM; wsym[10]= READSYM; wsym[11]= REPEATSYM;wsym[12]= THENSYM;wsym[13]= UNTILSYM;wsym[14]= VARSYM; wsym[15]= WHILESYM;wsym[16]= WRITESYM; memset(code,0,sizeof(code));memset(ssym,0,100*sizeof(symbol));memset(table,0,sizeof(table));memset(line,0,sizeof(line)); ssym['+']= PLUS; 类型表 ssym['-']= MINUS;ssym['*']= TIMES;ssym['/']= SLASH;ssym['(']= LPAREN;ssym[')']= RPAREN;ssym['=']= EQL;ssym[',']= COMMA;ssym['.']= PERIOD; // 初始化保留字表中每一个保 // 初始化一些符号对应的symbol ssym['#']= NEQ;ssym['<']= LSS;ssym['>']= GTR;ssym[';']= SEMICOLON; strcpy(mnemonic[LIT],” lit “); // 初始化类PCODE指令助记符表 strcpy(mnemonic[OPR],” opr “);strcpy(mnemonic[LOD],” lod “);strcpy(mnemonic[STO],” sto “);strcpy(mnemonic[CAL],” cal “);strcpy(mnemonic[INT],” int “);strcpy(mnemonic[JMP],” jmp “);strcpy(mnemonic[JPC],” jpc “); declbegsys.insert(CONSTSYM),declbegsys.insert(VARSYM),declbegsys.insert(PROCSYM);// 初始化声明开始符号集合 statbegsys.insert(BEGINSYM),statbegsys.insert(CALLSYM),statbegsys.insert(IFSYM),statbegsys.insert(WHILESYM);// 初始化表达式开始符号集合facbegsys.insert(IDENT),facbegsys.insert(NUMBER),facbegsys.insert(LPAREN);// 初始化项开始符号集合 err= 0;cc= 0; // 行缓冲区指针 cx= 0; // 代码分配指针,代码生成模块总在cx所指位置生成新的代码 ll= 0; // 行缓冲区长度 ch= ' '; // last character read } kk= al; // 引入此变量是出于程序性能考虑 codeNo=0; // code line no.fin=fopen(source,”r“);fout=fopen(destination,”w“);// 出错处理,打印出错位置和出错代码 void PL0::error(int n){ char s[10];sprintf(s,”第 %d 行:“,codeNo);errorString.push_back(s+errStr[n]);err= err+1;//error count }//error end // 词法分析,读取一个单词 void PL0::getsym(){ if(sourceEnd) return;int i,j,k;while(ch ==' '||ch==9) getch(); // cls space and tab if(isalpha(ch))// id or reserved word { k=0; memset(a,0,al+1); // 检测一个单词长度 do{ if(k < al){ a[k]= ch; k= k+1;} getch();if(sourceEnd) return;}while(isalpha(ch)||isdigit(ch));if(k >= kk)kk = k;else { do{ a[kk]= ' '; kk= kk-1;}while(kk > k);} strcpy(id,a);i= 1;j= norw;// 判断是否是关键字(二分搜索)do{ k=(i+j)/ 2;if(strcmp(id, word[k])<=0) j= k-1;if(strcmp(id,word[k])>=0) i= k+1;}while(i<=j);if(i-1 > j) sym= wsym[k];else sym= IDENT;} else if(isdigit(ch))// number { k= 0;num= 0;sym= NUMBER;do{ num= 10 * num + ch-'0'; k= k+1; getch();}while(isdigit(ch));if(k > nmax) error(30);} else if(ch == ':'){ getch();if(ch == '='){ sym= BECOMES; getch();} else sym= NUL;} else if(ch == '<') // extra stuff added to support <= { getch();if(ch== '='){ sym= LEQ; getch();} else sym= LSS;} else if(ch == '>'){ getch();if(ch == '='){ sym= GEQ; getch();} else sym= GTR;} else // end of extra stuff { sym= ssym[ch];// 其它符号的赋值 getch();} } // 漏掉空格,读取一个字符 void PL0::getch(){ if(cc == ll){ if(feof(fin)) { if(sym!=PERIOD) error(25); sourceEnd=true; return; } cc= 0; fgets(line,lineLength,fin); codeNo++; ll=strlen(line); if(line[ll-1]==10)ll--;} ch= line[cc];cc= cc+1;} // 生成目标代码,并送入目标程序区void PL0::gen(fct x,int y,int z){ if(cx > cxmax){ cout<<”Program too longn“; return;} code[cx].f= x;code[cx].l= y;code[cx].a= z; cx= cx+1;}//gen end // 测试当前单词符号是否合法 void PL0::test(symset s1,symset s2,int n){ if(sourceEnd) return;if(s1.find(sym)==s1.end()){ error(n); symset::iterator it; for(it=s2.begin();it!=s2.end();it++) s1.insert(*it);//s1=s1+s2 while(s1.find(sym)==s1.end()) getsym();} }//test end // 分程序分析处理过程 void PL0::block(int lev,int tx,symset fsys){ if(sourceEnd) return;int dx;// data allocation index int tx0;// initial table index int cx0;// initial code index dx= 3; // 变量的个数 tx0= tx;// 表指针 table[tx].other.inOther.adr= cx;gen(JMP,0,0);if(lev>levmax)error(32);do{ if(sym == CONSTSYM) // 处理常量声明 { getsym(); do{ constdeclaration(tx,dx,lev); while(sym == COMMA) { } getsym(); constdeclaration(tx,dx,lev);} if(sym ==SEMICOLON) getsym();else error(5);}while(sym==IDENT);if(sym == VARSYM) // 处理变量声明 { getsym();do{ vardeclaration(tx,dx,lev); while(sym == COMMA){ getsym(); vardeclaration(tx,dx,lev); } if(sym ==SEMICOLON) getsym(); else error(5);}while(sym==IDENT);} while(sym ==PROCSYM) // 处理过程的声明 { getsym();if(sym ==IDENT){ enter(PROCEDURE,tx,dx,lev); getsym();} else error(4);if(sym ==SEMICOLON) getsym();else error(5);symset tmp = fsys;tmp.insert(SEMICOLON);block(lev+1,tx,tmp);if(sym == SEMICOLON){ getsym(); symset tmp = statbegsys; for(int i= IDENT;i<=PROCSYM;i++) tmp.insert((symbol)i); test(tmp,fsys,6); } else error(5); } symset tmp=statbegsys; tmp.insert(IDENT); test(tmp,declbegsys,7);}while(declbegsys.find(sym)!=declbegsys.end()); code[table[tx0].other.inOther.adr].a= cx;table[tx0].other.inOther.adr= cx;// start adr of code table[tx0].other.inOther.size=dx; cx0= cx;gen(INT,0,dx);symset tmp=statbegsys;for(int i=SEMICOLON;i <= ENDSYM;i++) tmp.insert((symbol)i);statement(tmp,tx,lev);gen(OPR,0,0);// return symset s2;test(fsys,s2,8);listcode(cx0);}// block end // 登入名字表 void PL0::enter(obj0 k,int &tx,int &dx,int lev){ tx= tx+1;strcpy(table[tx].name,id);table[tx].kind=k;switch(k){ case CONSTANT: if(num>amax) { error(31); num=0; } table[tx].other.val=num; break;case VARIABLE: table[tx].other.inOther.level=lev; table[tx].other.inOther.adr=dx; dx++; break;case PROCEDURE: table[tx].other.inOther.level=lev; break;case ARRAY: table[tx].other.inOther.size = lev; break;} }//enter end // 查找标示符在名字表中的位置 int PL0::position(alfa id,int tx)//find identifier id in table { int i;strcpy(table[0].name, id);i= tx;while(strcmp(table[i].name,id)!=0)i--;return i;}//position end // 常量定义处理 void PL0::constdeclaration(int&tx,int&dx,int lev){ if(sym == IDENT){ getsym(); if(sym>=EQL&&sym<=BECOMES) { if(sym ==BECOMES) error(1); getsym(); if(sym == NUMBER) { enter(CONSTANT,tx,dx,lev); getsym(); } else error(2); } else error(3);} else error(4);}// constdeclaration end // 变量说明处理 void PL0::vardeclaration(int&tx,int&dx,int lev){ if(sym == IDENT){ enter(VARIABLE,tx,dx,lev); getsym();} else error(4);}//vardeclaration end // 数组说明处理 void PL0::arraydeclaration(int&tx,int&dx,int lev){ int upscript=0,downscript=0;getsym();if(sym == NUMBER || sym == CONSTSYM){ if(num == 0) { upscript = num; getsym(); } else error(32);} if(sym == COMMA) getsym();else error(32);if(sym == NUMBER || sym == CONSTSYM){ downscript = num; getsym();} if(sym!= RPAREN) } error(32);else { enter(ARRAY,tx,dx,downscript+1);getsym();} // 列出目标代码清单 void PL0::listcode(int cx0)//list code generated for this block { int i;if(listswitch) for(i= cx0;i cout<<”“< <<”“< // 语句部分处理 void PL0::statement(symset fsys,int tx,int lev){ if(sourceEnd) return;int i,cx1,cx2;if(sym ==IDENT){ i= position(id,tx); if(i == 0) error(11); else if(table[i].kind!=VARIABLE) { error(12); i= 0; } getsym(); if(sym ==BECOMES) getsym(); else error(13); expression(fsys,tx,lev); if(sym!= SEMICOLON) error(10); if(i!= 0) gen(STO,lev-table[i].other.inOther.level,table[i].other.inOther.adr); } else if(sym == READSYM){ getsym();if(sym!=LPAREN) error(34);else do{ getsym(); if(sym==IDENT) i=position(id,tx); else i=0; if(i==0) error(35); else { gen(OPR,0,16); gen(STO,lev-table[i].other.inOther.level,table[i].other.inOther.adr); } getsym(); }while(sym == COMMA); if(sym!= RPAREN) { error(33); while(fsys.find(sym)!=fsys.end())getsym(); } else getsym();} else if(sym == WRITESYM){ getsym();if(sym==LPAREN){ do{ getsym(); symset tmp=fsys; for(int t=RPAREN;t<=COMMA;t++) tmp.insert((symbol)t); expression(tmp,tx,lev); gen(OPR,0,14); }while(sym==COMMA); if(sym!=RPAREN) error(33); else getsym();} gen(OPR,0,15);} else if(sym ==CALLSYM){ getsym();if(sym!=IDENT) error(14);else { i= position(id,tx); if(i == 0) error(11); else if(table[i].kind = PROCEDURE) gen(CAL,lev-table[i].other.inOther.level,table[i].other.inOther.adr); else error(15); getsym();} } else if(sym ==IFSYM){ getsym();symset tmp=fsys;for(int i = THENSYM;i<= DOSYM;i++) tmp.insert((symbol)i);condition(tmp,tx,lev);if(sym == THENSYM) getsym();else error(16);cx1= cx;gen(JPC,0,0);tmp.insert(ELSESYM);statement(tmp,tx,lev);getsym(); code[cx1].a= cx; if(sym == ELSESYM){ getsym(); cx2=cx; gen(JMP,0,0); code[cx1].a=cx; statement(fsys,tx,lev); code[cx2].a=cx;} } else if(sym ==BEGINSYM){ getsym();symset tmp=fsys;for(int i=SEMICOLON;i<=ENDSYM;i++) tmp.insert((symbol)i);statement(tmp,tx,lev);tmp=statbegsys;tmp.insert(SEMICOLON);while(tmp.find(sym)!=tmp.end()){ if(sourceEnd)return; if(sym ==SEMICOLON||sym ==ENDSYM) getsym(); else if(sym=PERIOD) { error(26); getsym(); } else error(10); tmp=fsys; for(i=SEMICOLON;i<=ENDSYM;i++) tmp.insert((symbol)i); if(sourceEnd)return; if(sym==ENDSYM) break; statement(tmp,tx,lev);} if(sym ==ENDSYM) getsym();else if(!sourceEnd) error(17);} else if(sym ==WHILESYM){ cx1= cx; // 记下当前代码分配位置,这是while循环的开始位置 getsym();symset tmp=fsys;tmp.insert(DOSYM);condition(tmp,tx,lev); cx2= cx; // 记下当前代码分配位置,这是while的do中的语句的开始位置 gen(JPC,0,0); if(sym ==DOSYM) getsym(); else error(18); statement(fsys,tx,lev); gen(JMP,0,cx1); code[cx2].a= cx;} else if(sym == REPEATSYM){ symset temp1, temp2; temp1= fsys,temp1.insert(SEMICOLON),temp1.insert(UNTILSYM); cx1= cx; getsym(); statement(temp1,tx,lev); temp2 = statbegsys; temp2.insert(SEMICOLON); while(temp2.find(sym)!= temp2.end()) { if(sym == SEMICOLON) getsym(); else error(34); statement(temp1,tx,lev); } if(sym == UNTILSYM) { getsym(); condition(fsys,tx,lev); gen(JPC,0,cx1); } else error(34); } symset setT;test(fsys,setT,19);}//statement end // 表达式处理 void PL0::expression(symset fsys,int tx,int lev){ symbol addop;symset tmp=fsys;for(int t=PLUS;t<=MINUS;t++) tmp.insert((symbol)t);if(sym>=PLUS&&sym<=MINUS){ addop= sym; getsym(); term(tmp,tx,lev); if(addop ==MINUS) gen(OPR,0,1);} else term(tmp,tx,lev);while(sym >=PLUS&&sym<=MINUS){ addop= sym; getsym(); term(tmp,tx,lev); if(addop ==PLUS) gen(OPR,0,2); else gen(OPR,0,3);} }// expression end // 项处理 void PL0::term(symset fsys,int tx,int lev){ if(sourceEnd) return;symbol mulop;symset tmp=fsys;for(int t=TIMES;t<=SLASH;t++) tmp.insert((symbol)t);factor(tmp,tx,lev);while(sym>=TIMES && sym<=SLASH){ mulop= sym; getsym(); factor(tmp,tx,lev); if(mulop ==TIMES) gen(OPR,0,4); else gen(OPR,0,5);} }// term end // 因子处理 void PL0:: factor(symset fsys,int tx,int lev){ int i;test(facbegsys,fsys,24);while(facbegsys.find(sym)!=facbegsys.end()){ if(sym ==IDENT) { i= position(id,tx); if(i == 0) error(11); else switch(table[i].kind) { case CONSTANT: gen(LIT,0,table[i].other.val); break; case VARIABLE: gen(LOD,lev-table[i].other.inOther.level,table[i].other.inOther.adr); break; case PROCEDURE: error(21); break; } getsym(); } else if(sym ==NUMBER) { if(num>amax) { error(31); num= 0; } gen(LIT,0,num); getsym(); } else if(sym ==LPAREN) { getsym(); symset tmp=fsys; tmp.insert(RPAREN); expression(tmp,tx,lev); if(sym == RPAREN) getsym(); else error(22); } test(fsys,facbegsys,23);} }//factor end // 条件处理 void PL0::condition(symset fsys,int tx,int lev){ symbol relop;symset tmp=fsys;tmp.insert(EQL),tmp.insert(NEQ),tmp.insert(LSS),tmp.insert(LEQ),tmp.insert(GTR),tmp.insert(GEQ); if(sym == ODDSYM){ getsym(); expression(fsys,tx,lev); gen(OPR,0,6);} else { expression(tmp,tx,lev); if(tmp.find(sym)==tmp.end()) error(20); else { relop= sym; getsym(); expression(fsys,tx,lev); switch(relop) { case EQL: gen(OPR,0,8); break; case NEQ: gen(OPR,0,9); break; case LSS: gen(OPR,0,10); break; case GEQ: gen(OPR,0,11); break; case GTR: gen(OPR,0,12); break; case LEQ: gen(OPR,0,13); break; } } } }//condition end // 对目标代码的解释执行程序 void PL0::interpret(){ int err1=errorString.size();if(err1>0){ cout<<”存在%d个错误:“< cout< t= t+1; s[t]= i.a; break;case OPR: switch(i.a)//operator { case 0:// return t= b-1; p= s[t+3]; b= s[t+2];break;case 1: s[t]=-s[t];break;case 2: t= t-1;s[t]= s[t]+s[t+1];break;case 3: t= t-1;s[t]= s[t]-s[t+1];break;case 4: t= t-1;s[t]= s[t]*s[t+1];break;case 5: t= t-1;s[t]= s[t] / s[t+1];break;case 6: if(s[t]%2) s[t]=1;else s[t]=0;break;case 8: t= t-1;if(s[t]==s[t+1]) s[t]=1;else s[t]=0;break;case 9: t= t-1;if(s[t]==s[t+1]) s[t]=0;else s[t]=1;break; case 10: t= t-1;if(s[t] s[t]=1;else s[t]=0;break;case 11: t= t-1;if(s[t]>=s[t+1]) s[t]= 1;else s[t]=0;break;case 12: t= t-1;if(s[t]>s[t+1]) s[t]= 1;else s[t]=0;break;case 13: t= t-1;if(s[t]<=s[t+1]) s[t]= 1;else s[t]=0;break;case 14: cout<<”“< t= t+1; s[t]= s[base(i.l,b,s)+i.a]; break; case STO: s[base(i.l,b,s)+i.a]= s[t]; t= t-1; break; case CAL:// generate new block mark s[t+1]= base(i.l,b,s); s[t+2]= b; s[t+3]= p; b= t+1; p=i.a; break; case INT: t= t+i.a; break; case JMP: p= i.a; break; case JPC: if(s[t] == 0) p= i.a; t= t-1; break; }//switch end }while(p!=0); cout<<” End PL/0n“;} // interpret end // 通过静态链求出数据区的基地址 int PL0::base(int l,int b,int s[]){ int b1;b1= b;//find base l levels down while(l>0){ b1= s[b1]; l= l-1;} return b1;} // 保存代码 void PL0::SaveCode(){ if(fout) for(int i=0;i fprintf(fout,”%d %s %d %dn “,i,mnemonic[code[i].f],code[i].l,code[i].a);} TestPL0.cpp代码: #include ”pl0.h“ void main(){ PL0 cp(”testPas2.txt“,”nasm.txt"); symset fsys; fsys.insert(PERIOD);fsys.insert(CONSTSYM),fsys.insert(VARSYM),fsys.insert(PROCSYM);fsys.insert(BEGINSYM),fsys.insert(CALLSYM),fsys.insert(IFSYM),fsys.insert(WHILESYM);cp.getsym(); // 词法分析,分析一个词 cp.block(0,0,fsys); // 分程序分析处理功能 cp.SaveCode(); // 保存代码 cp.interpret(); // 对目标代码的解释执行程序 } 实验运行结果: 运行的的文件见下图右侧:实验中我是固定了文件名的,可以是改写成动态输入,由于在测试中我把所有的测试语句都放在同一个文件中了,没有太多的必要。 六、心得体会 在编译程序实现的过程中反复使用了递归调用的思想,且也使用了模块化处理问题的思想,使用模块化的思想关键是在抽象阶段要抽象出对应的模块,且模块的层次必须是清晰的。 在实现此程序中,由于要实现关键字和符号表中字段的搜索,实现中就必须注意快速查找的方法,而在实现的过程中多次用到了二分搜索的方法,这是个比较快的搜索方法。 由于此程序的实现相对比较复杂,且不方便调试,改进时可以把此程序的词法分析,语法分析和执行原代码作为单独的测试程序来测试,这样也方便大家来调试。 通过本次的课设我知道了一个算法的设计是需要静下心来仔细的研究的,且实现中必须先了解程序的整个流程,也就是说在编程中首先必须看懂那些对应的UML图,只有在图的指导下,编程中才不会盲目,也有一定的方向性。同样在编程中必须注意代码的规范,多写一些对应的注释是很必要的,要时刻想这代码并不是给你自己看的,而是必须要给别人看,因此我觉得代码的规范是相当重要的。 编译原理课程设计报告 课题名称: 提交文档学生姓名:提交文档学生学号:同组 成 员 名 单:无指导 教 师 姓 名: 指导教师评阅成绩:指导教师评阅意见: 提交报告时间:年月日 1.课程设计目标 构造的编译器的组成部分,能实现的功能。 2.分析与设计 实现方法:编程语言、编程方法 系统总图,各部分的实现原理、方法、中间结果、最后输出 扫描器:各单词的状态转换图、转换表 分析器:分析表 代码设计说明:程序结构图,文件和函数的设计说明,关键数据结构 3.程序代码实现 按文件列出主要程序代码, 添加必要的注释。 4.测试结果 标准测试程序的分析结果 修改后的测试程序分析结果(正确和错误)词法分析和语法分析的结果输出(P79,P182) 5.总结 收获 不足 编译原理课程报告 学院: 信息工程学院专业: 软件工程 姓名: 赖杰学号: 09927212 指导老师: 朱文华完成时间: 2012.5.19 编译原理是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法,在计算机本科教学中占有十分重要的地位。 编译程序是现代计算机系统的基本组成部分之一,而且多数计算机系统都配有不止一个高级语言的编译程序,对有些高级语言甚至配置了几个不同性能的编译程序。从功能上讲,一个编译程序就是一个语言翻译程序。语言翻译程序把一种源语言书写的程序翻译成另一种目标语言的等价程序,所以总的说编译程序是一种翻译程序,其源程序是高级语言,目标语言程序是低级语言。 编译程序完成从源程序到目标程序的翻译工作,是一个复杂的整体的过程。从概念上来讲,一个编译程序的整个工作过程是划分成几个阶段进行的,每个阶段将源程序的一种表示形式转换成另一种表示形式,各个阶段进行的操作在逻辑上是紧密连接在一起的。一般一个编译过程是词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成。 编写编译器的原理和技术具有十分普遍的意义,以至于在每个计算机工作者的职业生涯中,本书中的原理和技术都会反复用到。在这本书中,向我们介绍了文法的概念,在讲词法分析的章节中讲述了构造一个有穷自动机的方法,以及如何将一个不确定的有穷自动机转化成确定的有穷自动机和有穷自动机的最小化等方法。 该门课中主要讲述的是两种分析方法,即自上而下分析的方法和自下而上分析的方法。自上而下分析法是从文法的开始符号出发,反复使用各种产生式,寻找“匹配”于输入符号串的推导。自下而上的分析方法是从输入符号串开始,逐步进行“归约”到文法的开始符号。 1.自上而下的分析法主要的就是LL(1)文法,首先要判断某个文法是否是 LL(1)文法,如果是就可以按照LL(1)文法分析的方法去判断某一个输入串是否为该文法的句子。LL(1)f分析方法是,首先根据判断是否为LL(1)文法求出每一个非终结符的SELECTE集合来构造该文法的预测分析表,然后根据预测分析表去分析输入串得出结果;如果不是LL(1)文法,比如说文法产生式中含有左递归和相同的因子,就要消去左递归或公共因子,再根据每一个非终结符的SELECT集合来判断是否为LL(1)文法。利用LL(1)文法分析一个输入串是不是某一个文法的句子,根据预测分析表是比较直观的,而且分析的效率也是比较高的。 2.自下而上的分析方法主要是算符优先分析方法。算符优先分析的基本思 想是只规定算符之间的优先关系,也就是只考虑终结符之间的优先关系,由于算符优先分析不考虑非终结符之间的优先关系,在归约的过程中只要找到可归约串就归约,没有考虑非终结符之间的优先关系,所以说算符优先归约不是规范规约。算符优先分析首先是要构造算符 优先关系矩阵;然后就是分析输入串,根据关系矩阵进行移进或归约操作;最后分析得出判断的结果。 3.算符优先分析是有缺点的,由于算符优先分析方法在分析的过程中不知 道如何确定句柄。下面要说的就是LR(0)文法,这种方法能够根据当前分析栈中的符号串就可以惟一的确定分析器的动作是移进还是归约,并且是用哪一个产生式。根据规则写出LR(0)的分析的项目集,再由项目集构造LR(0)的分析表,其次根据分析栈的元素和状态,查看分析表,找出相关的句柄,是归约还是移进,最后就是分析得出结果了。SLR(0)文法是以LR(0)文法为基础的文法,是为了解决程序设计语言的文法不能够满足LR(0)文法条件的另一种文法分析的方法,大致的与LR(0)的分析过程相似,只是在项目集的组合上有些区别。 该课程理论性与实践性都很强,我在学习时普遍感到内容非常抽象,不易理解,内容多且繁琐,难以完整、全面地掌握编译原理的有关知识,更不用说灵活运用编译原理知识从事相关设计或应用于其他领域。虽然只有少数人从事编译方面的工作,但是这门课在理论、技术、方法上都对我提供了系统而有效的训练,有利于提高软件人员的素质和能力。 在我学习编译原理以前,都认为编译原理只能应用在写程序语言的编译器上,觉得用处不大,学习兴趣不高。而在后来的学习中,我逐渐认识到计算机专业的学生,除了要会编写程序语言之外,还应该了解它是如何被计算机所识别,这才是真正并且透彻地学习软件。另外,编译器中每一个模块的编写,都能对我的编程能力的提高有很大帮助。在今后若从事软件工程,这门课程也能够对编写程序有所帮助。 为了能够系统掌握这门专业课,我把编译原理分为以下几个模块:①语言和文法;②词法分析;③语法分析;④语义分析和中间代码生成;⑤代码优化和目标代码生成。 在学习的开始,我需要掌握什么是编译,编译分为哪些阶段,编译程序和解释程序的区别等等。在做好了这些方面的准备后,开始了系统的学习。 语言和文法部分的知识包括文法基本概念及文法的二义性。基本概念有文法定义、推导、句型、句子等等。二义性文法是通过画语法树的方法来证明。 词法分析中的重点是有穷自动机DFA的生成以及DFA和正规式与正规文法的关系。还要熟练掌握NFA转换为DFA的方法及DFA的化简。 语法分析包括自上而下和自下而上分析。自上而下分析着重掌握LL(1)文法,自下而上分析重点掌握算符优先文法和LR(0)、SLR(1)文法。 语义分析重点是其功能,中间代码生成和语法制导翻译定义与方法。 最后,优化分为局部优化和循环优化,重点理解一些关键词,如基本块、流图等,要学会自己画出程序流图。用DAG图进行局部优化是重点。 在学习文法时,对文法的组成,用法都较为明了,而在真正做题时却感到十分吃力。例如给出了一个语言,要求写出它的上下文无关文法,就感到十分棘手,所以今后在这方面要加大练习量,以熟练掌握。 而在之后的词法分析和语法分析中,我感到在看基本原理时十分困难,通常要长时间钻研才能够有所了解,而一旦掌握了基本原理,做题时就感到十分顺畅了。例如,在刚接触到LR(0)文法时,我用了大量的时间去学习它的原理,掌 握之后,在列LR(0)分析表和写分析过程时,只要思路清晰,就会比较顺畅,而且不会犯错。 通过这学期的对编译原理课程的学习,这么课程让我学会了如何去编译程序的一个理论知识,知道编译程序是通过怎样的方法把程序员编写的源程序翻译成计算机能够执行的机器语言的,我觉得主要的是大大加深了我对程序设计的理解,也对计算机的理论和软件编译有了深一步的理解。这学期的编译原理的实验使我知道了编译程序的工作的基本过程及其各阶段的基本任务,了解了 编译程序流程框图,编译程序的生成过程、构造工具及其相关的技术对课本上的知识有了更深的理解,可以说这是将书本上的理论知识的应用,是对理论知识的更深一步的理解和掌握。 201X-201X学年第x学期 《编译原理》课程设计报告 院 系: 计算机科学与技术 班 级: XX级XX 班 学生姓名: XXXXXX 学 号: XXXXXXXX 指导老师: XXXXXX 计算机科学与技术学院监制 20XX年X月 目录 1.课程设计的目的 2.课程设计的内容和要求 3.问题分析和相关知识介绍 4.设计思路和关键问题及其解决方案 5.测试和结果分析 6.总结和心得体会 附件1:参考文献 附件2:核心源代码 1.课程设计的目的(1)编写词法分析器 (2)加深对词法分析器工作原理的了解和认识 2.课程设计的内容和要求 编写词法分析器,词法分析器能够识别关系算符,词法分析器能够识别标识符和关键字,词法分析器能够识别无符号数。 3.问题分析和相关知识介绍 构成词法分析器的一种简单方法是用状态转换图来描述源语言词法记号的结构,然后手工把这种状态转换图翻译成为识别词法记号的程序。词法分析器的任务是把构成源程序的字符流翻译成词法记号流。 4.设计思路和关键问题及其解决方案 把自然语言构造成正规式,把正规式构造成有限自动机NFA,然后根据子集构造法把有限自动机构造成无限自动机DFA,根据极小化DFA状态数算法把DFA构造成最简DFA,其次根据最简DFA画出转换表,根据转换表画出装换图,最后根据装换图就可以编写词法分析器。 5.测试和结果分析 6.总结和心得体会 通过本次试验,不仅仅是我学会了C#基础知识,而且还是我对词法分析器有了更深入的认识,虽然在编写词法分析器过程中遇到了很多困难,例如:C#语言不熟悉,对此法分析器的工作原理分析的不透彻,但在老师和同学的帮助下,我有了很大的提高,通过不断的努力最终顺利的完成了课程设计,很感谢帮助我的XX同学和XX老师。附件1:参考文献 《编译原理(第2版)》 高等教育出版社; 《C#程序设计及应用教程(第2版)》 人民教育出版社。附件2: 1.Code文档截图 2.程序源代码 using System;using System.Collections.Generic;using System.Text;using System.IO; namespace LexicalAnalysis { class Program { static string[] keys = { “static”, “true”, “return”, “string”, “Length”, “break”, “Console”, “WriteLine”, “bool”, “false”, “ture”, “void”, “if”, “else”, “while”, “int”, “float”, “for”, “enum”, “default”, “case”, “double”, “do” }; static List static List static List static List static List //数字,标识符,空白,关系符,运算符 static void Main(string[] args){ string[] date = File.ReadAllLines(@“d:code.txt”);//路径,并存入data for(int i = 0;i < date.Length;i++){ Console.WriteLine(“第” +(i + 1)+ “行code: ” + date.GetValue(i));analysisByLine(date[i]); } //分别输出存储在四个List中的String Console.WriteLine(“关键字,输入回车”);//输出所有的关键字 Console.ReadLine(); foreach(string id in key){ Console.WriteLine(id); } Console.WriteLine(“标识符,输入回车”);//输出所有的标识符 Console.ReadLine();foreach(string id in bsf){ Console.WriteLine(id); } Console.WriteLine(“数字,输入回车”);Console.ReadLine();foreach(string id in sz){ Console.WriteLine(id); } Console.WriteLine(“关系运算符,输入回车”);Console.ReadLine();foreach(string id in gx){ Console.WriteLine(id); } Console.WriteLine(“算数运算符,输入回车”);Console.ReadLine();foreach(string id in ys){ Console.WriteLine(id); } Console.WriteLine(“输入回车退出”); Console.ReadLine(); } static void analysisByLine(string code) //输出所有的数字 //输出所有的关系运算符//输出所有的算数运算符 { char a = ' ';string temp = “";int j = 0;while(j < code.Length){ a = code[j];temp = ”“;if(Char.IsLetter(a)|| a == '_')//是否为标识符 { temp = temp + a.ToString();j++;a = code[j];while(Char.IsLetterOrDigit(a)){ temp = temp + a.ToString();j++;a = code[j];} if(isKey(temp)){ //Console.WriteLine(”保留字:“+temp); if(!key.Contains(temp)){ // Console.WriteLine(”添加成功“);key.Add(temp);} } else { //Console.WriteLine(”标识符:“+temp); if(!bsf.Contains(temp)){ //Console.WriteLine(”添加成功标识符==“);bsf.Add(temp);} } } else if(Char.IsDigit(a)){ temp = temp + a.ToString();j++;a = code[j];while(Char.IsDigit(a)){ temp = temp + a.ToString();j++;a = code[j]; } //判断是否是小数 if(a.Equals('.')){ temp = temp + a.ToString();j++;a = code[j];while(Char.IsDigit(a)){ temp = temp + a.ToString();j++;a = code[j];} //判读是否是科学记数法 if(a.Equals('E')|| a.Equals('e')){ temp = temp + a.ToString();j++;a = code[j];while(Char.IsDigit(a)){ temp = temp + a.ToString();j++;a = code[j];} } } // Console.WriteLine(”数字:“+temp);if(!sz.Contains(temp)){ //Console.WriteLine(”添加成功标识符==“);sz.Add(temp);} } else if(a == '<'){ temp = temp + a.ToString();j++;a = code[j];if(a == '='){ temp = temp + a.ToString();j++;a = code[j];} else if(a == '>'){ temp = temp + a.ToString();j++;a = code[j];} //Console.WriteLine(”关系符“+temp);if(!gx.Contains(temp)){ //Console.WriteLine(”添加成功标识符==“);gx.Add(temp);} } else if(a == '='){ temp = temp + a.ToString();j++; a = code[j];// Console.WriteLine(”关系符“+temp);if(!gx.Contains(temp)){ //Console.WriteLine(”添加成功关系==“);gx.Add(temp);} } else if(a == '>'){ temp = temp + a.ToString();j++;a = code[j];if(a == '='){ temp = temp + a.ToString();j++;a = code[j];} // Console.WriteLine(”关系符“+temp);if(!gx.Contains(temp)){ //Console.WriteLine(”添加成功标识符==“);gx.Add(temp);} } else { if(a == '+' || a == '-' || a == '/' || a == '*'){ temp = temp + a.ToString();j++;a = code[j];//Console.WriteLine(”运算符“+temp);if(!ys.Contains(temp)){ //Console.WriteLine(”添加成功标识符==“);ys.Add(temp);} } else { j++;} } } } //判断是不是保留字的IsKey方法 static bool isKey(string key){ bool flag = false;for(int i = 0;i < keys.Length;i++) if(keys[i] == key){ flag = true;//Console.WriteLine(key+”是不是key“+flag);break;} else { flag = false; } //Console.WriteLine(key+”是不是key“);// Console.WriteLine(flag+”是不是key");return flag; } } }第二篇:编译原理课程设计报告
>s[t];break;};break;case LOD:第三篇:编译原理课程设计报告(格式)
第四篇:编译原理课程报告(共)
第五篇:《编译原理》课程设计报告--词法分析器