编译原理-课程设计报告-简单编译器实现-精品
编译原理课程设计报告

《编译原理》课程设计报告一、课程设计目的通过课程设计进一步理解高级语言在计算机中的执行过程,了解现代编译器的运作机制,加深对编译原理中重点算法和编译技术的理解,提高自己自学和理解的能力。
学会如何利用已有软件JFLex、Java_cup对词法分析器及语法分析器的构造。
二、设计概述本tiger语言编译器的编译过程涉及到编译五个阶段中的二个,即词法分析器、语法分析器。
其中语法分析后还完成了语法树的打印的构造以及类型检查。
词法分析器由JFLex编译正则式生成,词法分析器编译产生式生成,语法分析器由CUP生成。
结果通过GUI界面呈现在使用者面前。
编译程序需要在单词级别上来分析和翻译源程序,所以首先要识别出单词,而词法分析部分的任务是:从左至右扫描源程序的字符串,按照词法规则(正则文法规则)识别出一个个正确的单词,并转换成该单词相应的二元式(种别码、属性值)交给语法分析使用。
因此,词法分析是编译的基础。
执行词法分析的程序称为词法分析器。
语法分析是编译程序的核心部分,其主要任务是确定语法结构,检查语法错误,报告错误的性质和位置,并进行适当的纠错工作。
三、设计过程(一)设计构思程序主要完成三大功能模块:词法分析器、语法分析器、GUI人机交互界面。
词法分析器由JFLex编译正则式生成,其中必须为外界提供一个获取记号流的接口,实验中定为java_cup.runtime.Symbol next_token。
语法分析器是建立在词法分析器上的,故必须包含词法分析器以便获得记号流,next_token为语法分析器提供TOKEN,语法分析器的对外接口是:java_cup.runtime.Symbol debug_parse(),同时返回语法树的根节点。
GUI 界面是提供人机交互的,它能够依次显示词法分析阶段分析得到的所有TOKEN 的信息,语法阶段生成的语法树,另外对于词法和语法阶段出现的错误在“错误提示”文本框中一一列举出来,提供用户改进代码的信息。
编译原理编译器课程设计

编译原理编译器课程设计一、课程目标知识目标:1. 理解编译原理的基本概念,掌握编译器各阶段的工作原理和实现方法;2. 学会使用一种编程语言(如C、Java等)编写简单的编译器程序;3. 掌握词法分析、语法分析、语义分析及目标代码生成的基本技术和策略;4. 了解优化技术在编译器中的应用,提高程序运行效率。
技能目标:1. 能够运用所学知识独立设计并实现一个简单的编译器;2. 培养学生运用编译原理知识解决实际问题的能力;3. 提高学生的编程实践能力和团队协作能力;4. 培养学生查阅资料、分析问题、总结归纳的能力。
情感态度价值观目标:1. 培养学生对编译原理和编译器开发工作的兴趣,激发学生的学习热情;2. 培养学生勇于探索、积极创新的精神,增强克服困难的信心和毅力;3. 培养学生具备良好的编程习惯,遵循职业道德,为我国软件产业的发展贡献自己的力量。
本课程旨在通过编译原理编译器课程设计,使学生掌握编译器的基本原理和技术,提高编程实践能力,培养团队协作精神,激发学生的学习兴趣和创新精神。
课程性质为理论与实践相结合,注重培养学生的实际操作能力。
针对学生的年级特点,课程内容将逐步深入,从基本概念到实际应用,引导学生由浅入深地掌握编译器相关知识。
在教学过程中,教师需关注学生的学习进度,及时调整教学策略,确保课程目标的实现。
通过本课程的学习,学生将具备独立设计和实现简单编译器的能力,为后续相关课程的学习打下坚实基础。
二、教学内容1. 编译原理概述:介绍编译器的基本概念、发展阶段和组成部分,使学生了解编译器在整个软件开发过程中的地位和作用。
教材章节:第一章2. 词法分析:讲解词法分析器的功能、设计方法,以及正则表达式和有限自动机等基本概念。
教材章节:第二章3. 语法分析:介绍语法分析器的作用、设计方法,以及上下文无关文法、LL(1)、LR(1)等分析方法。
教材章节:第三章4. 语义分析:讲解语义分析器的任务、属性文法、语法制导翻译等概念,以及类型检查和符号表管理方法。
编译原理课程设计---编译器的实现

编译原理课程设计编译器的实现学院(系):学生姓名:学号:班级:同组人:目录1 课设要求1.1. 实现原理1.2. 单词符号及种别表1.3. 语法结构的定义2 运行环境3 总体设计思想4 详细设计思想4.1. 词法分析主要算法4.2. 语法分析主要算法4.3. 语义分析主要算法5 流程框图6 函数相关说明7 程序用例及运行结果8 小组分工与合作9 心得与体会1课设要求用C++语言对下述文法和单词表定义的语言做一个编译器,实现了LL(1)词法分析,语法分析,中间代码生成功能。
1.1.实现原理编译程序的工作过程一般可以分为五个阶段:词法分析、语法分析、语义分析与中间代码产生、优化、目标代码生成。
每一个阶段在功能上是相对独立的,它一方面从上一个阶段获取分析的结果来进行分析,另一方面由将结果传递给下一个阶段。
由编译程序的五个阶段就对应了编译系统的结构。
1.2.单词符号及种别表1.3.语法结构定义P →{DS}D →int ID ;{int ID;}S→if (B) then S [else S ] | while (B) do S | { L } | ID=EL→SL’L’→; L |B→T’ {∨T’}T’→F’ {∧F’}F’→ID relop ID | IDE→T{+T| -T}T→F{* F | /F }F→(E) | NUM | ID//红颜色的{}是终极符.黑颜色的{}和[]不是终极符.2 运行环境Windows 系统Visual C++ 6.03 总体设计思想采用递归下降子程序法和语法制导翻译及回填拉链技术4 详细设计思想词法分析程序——》语义分析程序——》四元式4.1.词法分析主要算法这部分对源文件进行分析,允许/* */注释。
从源文件依次读取字符,对字符进行分析,组成字符串、数字、关系符等固定含义的token符,并把它们添加到token链中,如果遇到非法字符报错并退出程序。
4.2.语法分析主要算法这部分对Token链进行分析,利用递归下降子程序法的分析方法。
编译原理课程设计与报告

课程设计课程名称__ 编译原理_ 题目名称PL/0语言的扩充学生学院___ 计算机学院______ 专业班级_ 软件工程07级4班__ 学号学生姓名指导教师____ 李小妹________ 2008 年 1 月 5 日课程设计实验报告一、概述:源语言: PL/0目标语言: 目标代码(生成的文件后缀为*.COD)实验工具: Borland C++Builder 6运行平台: WindowsXP目的:在分析理解一个教学型编译程序(如PL/0)的基础上,对其词法分析程序、语法分析程序和语义处理程序进行部分修改扩充。
达到进一步了解程序编译过程的基本原理和基本实现方法的目的。
要求:对PL/0作以下修改扩充:基本内容(1)扩充赋值运算:+= 和-=(2)扩充语句(Pascal的FOR语句):①FOR <变量>:=<表达式> TO <表达式> DO <语句>②FOR <变量>:=<表达式> DOWNTO <表达式> DO <语句>其中,语句①的循环变量的步长为1,语句②的循环变量的步长为-1。
选做内容(1)增加运算:++ 和--。
(2)增加类型:①字符类型;②实数类型。
(3)扩充函数:①有返回值和返回语句;②有参数函数。
(4)增加一维数组类型(可增加指令)。
(5)其他典型语言设施。
二、结构设计说明:各功能模块描述Error()出错处理,打印出错位置和错误编码GetCh()漏掉空格,读取一个字符GetSym()词法分析,读取一个单词GEN()目标代码生成过程,本过程用于把生成的目标代码写入目标代码数组,供后面的解释器解释执行TEST()测试当前单词是否合法过程testENTER()登陆符号表过程enterPOSITION()在符号表中查找指定符号所在位置的函数position V ARDECLARATION()变量声明处理LISTCODE()输出目标代码清单;FACTOR()因子处理过程factorTERM()项处理过程term;EXPRESSION()表达式处理过程CONDITION()条件处理过程STA TEMENT()语句处理过程BLOCK()编译程序主体,语法分析过程BASE()通过静态链求出数据区基地址的函数,INTERPRET ()对目标代码解释运行过程Pl0编译程序的结构目标程序编译程序的总体流程图词法分析状态转换图.○表示状态,对应每个状态编一段程序,每个状态调用取字符程序,根据当前字符转到不同的状态,并做相应操作。
《编译原理》设计方案报告

《编译原理》课程设计报告设计题目:pl0编译器设计一、PL0程序的文法及,指令及属性翻译简化c语言文法定义(LL(1)文法)C程序::=void main(){函数体}函数体::=变量定义部分语句列变量定义部分::=变量定义变量定义部分| ɛ变量定义::=int 变量表变量表::=标识符|标识符,变量表语句列::=语句语句列| ɛ语句::=条件语句| 循环语句| 读语句| 写语句| 复合语句| 表达式语句| 空语句条件语句::=if(表达式)语句循环语句::=while(表达式)语句读语句::=read(变量表);写语句::=write(表达式表);复合语句::={语句列};表达式语句::=表达式;空语句::=;表达式定义(算符优先文法)表达式::=变量=表达式| 变量+=表达式| 变量-=表达式| 变量*=表达式| 变量/=表达式| 变量%=表达式| 表达式1表达式1::=表达式1 || 表达式2 | 表达式2表达式2::=表达式2&&表达式3 | 表达式3表达式3::=表达式3==表达式4 | 表达式3!=表达式4 | 表达式3>=表达式4 | 表达式3>表达式4 | 表达式3<=表达式4 | 表达式3<表达式4 | 表达式4表达式4::=表达式4+表达式5 | 表达式4-表达式5 | 表达式5表达式5::=表达式5*表达式6 | 表达式5/表达式6 |表达式5/表达式6 |表达式6表达式6::=!表达式7表达式7::=(表达式) | 变量| 常量PL0文法定义《程序》::=《分程序》.《分程序》::=《常量定义》;《常后分程序》|《常后分程序》《常后分程序》::=《变量定义》;《变后分程序》|《变后分程序》《变后分程序》::=《过程定义》;《变后分程序》|《语句》《常量定义》::=const 《常量定义表》《常量定义表》::=id = number | id = number,《常量定义表》《变量定义》::= var 《变量表》《变量表》::=id | id,《变量表》《过程定义》::=procedure id ;《分程序》《语句》::=《赋值语句》|《条件语句》|《循环语句》|《读语句》|《写语名》|《复合语句》| 《过程调用语句》|ε《赋值语句》::=id := 《表达式》《读语句》::=read(《变量表》)《写语句》::=write(《表达式表》)《表达式表》::=《表达式》| 《表达式》,《表达式表》《条件语句》::=if 《条件表达式》then 《语句》《循环语句》::=while 《条件表达式》do 《语句》《复合语句》::=begin 《语句列》end《过程调用语句》::=call id《参量表》::=《有参表》|ε《有参表》::=《表达式》,《有参表》|《表达式》《表达式》::=+《表达式1》|-《表达式1》|《表达式1》《表达式1》::=《表达式1》+《表达式2》|《表达式1》-《表达式2》|《表达式2》《表达式2》::=《表达式2》*《表达式3》|《表达式2》/《表达式3》| 《表达式2》mod 《表达式3》|《表达式3》《表达式3》::=id | number | (《表达式》)《条件表达式》::=《条件表达式》or 《条件表达式1》|《条件表达式1》《条件表达式1》::=《条件表达式1》and 《条件表达式2》| 《条件表达式2》《条件表达式2》::=not 《条件表达式3》|《条件表达式3》《条件表达式3》::=(《条件表达式》)|《关系表达式》《关系表达式》::=《表达式》>《表达式》《关系表达式》::=《表达式》>=《表达式》《关系表达式》::=《表达式》<《表达式》《关系表达式》::=《表达式》<=《表达式》《关系表达式》::=《表达式》=《表达式》《关系表达式》::=《表达式》#《表达式》PL0栈式机指令指令格式:指令码(f) 所在层数差(l),操作数(a)PL0栈式机指令:LIT:将常数a取到栈顶LOD:将位于(当前层-l)层处的变量a取到栈顶STO:将栈顶处值存储到指定位置,l,a同上CALL 调用当前-l层处的过程aINT:为调用过程在栈中开辟数据区,a为单元个数JMP:无条件转移指令,a目标地址JPC:条件转移指令,栈顶值的布尔值为非真时转移到a处,否则执行下面语句OPR:关系运算或算术运算PL0属性翻译MCONST(const:常量定义开始), V AR(var:变量定义开始), PROCEDURE(procedure:过程定义开始),CALL(call:过程调用语句),BEGIN(begon:复合语句开始),END(end:复合语句结束),IF(if:条件语句开始),THEN(then:条件结束),WHILE(while:循环语句开始), DO(do:循环条件结束), READ(read:读语句),WRITE(write:输出语句), ODD(odd:判奇运算),//分隔符、运算符号DOT(点:.),COMMA(逗号:,), SEMICOLON(分号:;), LPAREN(左括号:(), RPAREN(右括号:)), ASSIGNOP(赋值::=), PLUSOP(加法运算符号:+), MINUSOP(减法运算符:-), MULTOP(乘法运算符:*), DIVOP(除法运算符:/),GT(大于:>),GE(大于等于:>=),LT(小于:<),LE(小于等于:<=),EQ(等于:=),NE(不等:#),ENDF(输入结束符),//分析过程中需要的非终结符号SERVERKEY(保留字), FACTOR(因子),ROP(关系运算), CONSTANT(常量部份定义), V ARIABLE(变量部份定义), IDENT(自定义标识符), NUMBER(常数)二、符号表的结构,组织,填写及查找1、符号表结构const char *pName; //符号名称int kind; //符号类别,由上面单词分类确定int val; //符号表中的位置值int level; //符号的层数int parent; //符号的作用域int size; //过程长度char strBuff[MAXLENSTR]; //符号堆2、符号表的组织符号表的组织方式有:线性表、散列表、树结构等,其必须维持源程序中的作用域信息。
编译原理课程设计报告

武汉纺织大学编译原理课程设计实验报告学院:数学及计算机专业:计算机姓名:班级:学号:编译原理编译原理课设报告一、实验目的加强对编译程序的整体认识和了解,巩固《编译原理》课程所学知识。
通过本次课程设计掌握编译程序调试技巧和设计编译程序一般的原则,加深对词法分析、语法分析、语义分析等编译阶段及实用编译系统的认识。
使学生能将编译理论及实际应用结合起来,提高学生软件开发的能力。
二、实验内容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编译程序自动调用解释执行程序,对目标代码进行解释执行,并按用户程序的要求输入数据和输出运行结果。
计算机编译原理课程设计报告编译器

《编译技术》课程设计实验报告实验名称:编译器程序姓名:学号:班级:年月日一、课设要求模仿上学期给定的程序,根据下面具体的内容,用C++语言对下述文法和单词表定义的语言设计编制一个编译器。
设计报告格式撰写报告(1)单词符号及种别表(2)语法结构定义<程序> ::= main()<语句块><语句块> ::= ‘{‘<语句串>’}’ //程序用括号括起来<语句串>::=<语句>{;<语句>};<语句>::=<赋值语句>|<条件语句>|<循环语句><赋值语句>::=ID=<表达式> //赋值语句用”=”号<条件语句>::=if<条件><语句块><循环语句>::=do <语句块>while <条件><条件>::=<表达式><关系运算符><表达式><表达式> ::= <项>{+<项>|-<项>}<项> ::= <因子>{*<因子>|/<因子>}<因子> ::=ID|num|(<表达式>)num::=( +|-|ε ) 数字*(.数字数字* | ε)( e ( +|-|ε ) 数字数字*|ε) ID::=字母(字母|d数字)*字母::=a|b|c…|z|A|B|C…|Z数字::=0|1|2…|9<关系运算符> ::= <|<=|>|>=|==|!=二、总体设计思想采用递归下降(自上而下)的语法制导翻译法。
三、详细算法设计词法分析程序→语法分析程序→语义分析程序→编译器。
不断完善,不断改进。
编译原理课程设计报告

实验1:用Lex设计词法分析器1实验目的:学会用lex设计一个词法分析器。
实验内容:使用lex为下述文法语言写一个词法分析器。
实验要求:输入为用该语言所写的源程序文件;输出为记号序列,每个记号显示为二元组(记号名,记号属性值)的形式。
输出可以在屏幕上,也可以输出到文件中。
不要求建立符号表。
在cygwin下用flex和gcc工具将实验调试通过,并能通过例子parser0中testcases 目录下的测试例的测试。
实验参考:和。
语言文法:<程序> PROGRAM <标识符> ; <分程序><分程序> <变量说明> BEGIN <语句表> END.<变量说明> VAR <变量说明表>;<变量说明表><变量表>: <类型> | <变量表>: <类型>; <变量说明表><类型> INTEGER | REAL<变量表> <变量> | <变量>, <变量表><语句表> <语句> | <语句>; <语句表><语句> <赋值语句> | <条件语句> | <WHILE语句> | <复合语句><赋值语句><变量> := <算术表达式><条件语句> IF <关系表达式> THEN <语句> ELSE <语句><WHILE语句> WHILE <关系表达式> DO <语句><复合语句> BEGIN <语句表> END<算术表达式> <项> | <算术表达式> + <项> | <算术表达式> - <项><项> <因式> | <项> * <因式> | <项> / <因式><因式> <变量> | <常数> | (<算术表达式>)<关系表达式> <算术表达式> <关系符> <算术表达式><变量> <标识符><标识符> <标识符><字母> | <标识符><数字> | <字母><常数> <整数> | <浮点数><整数> <数字> | <数字> <整数><浮点数> .<整数> | <整数>.<整数><关系符> < | <= | = | > | >=| <><字母> A | B | …| X | Y | Z | a | b | …| x | y | z<数字>0|1|2|…|9程序代码:%{#include <>#define LT 1#define LE 2#define GT 3#define GE 4#define EQ 5#define NE 6#define PROGRAM 7#define END 13#define VAR 9#define IF 10#define THEN 11#define ELSE 12#define WHILE 18#define DO 19#define ID 20#define NUMBER 21#define RELOP 22#define NEWLINE 23#define ERRORCHAR 24%}delim [ \t \n]ws {delim}+letter [A-Za-z]digit [0-9]id _|{letter}({letter}|{digit})*number {digit}+(\.{digit}+)?(E[+-]?{digit}+)?int1 {digit}|{digit}{int1}*/%s COMMENT%%<INITIAL>"/*" {BEGIN COMMENT;ECHO;} <COMMENT>"*/" {BEGIN INITIAL;ECHO;} <COMMENT>.|\n {ECHO;}/* ECHO是一个宏,相当于 fprintf(yyout, "%s", yytext)*/ <INITIAL>{ws} {;}<INITIAL>while {return (WHILE);}<INITIAL>do {return (DO);}<INITIAL>PROGRAM {return (PROGRAM);}<INITIAL>end {return (END);}<INITIAL>VAR {return (VAR);}<INITIAL>if {return (IF);}<INITIAL>then {return (THEN);}<INITIAL>else {return (ELSE);}<INITIAL>{id} {return (ID);}<INITIAL>{number} {return (NUMBER);}<INITIAL>"<" {return (RELOP);}<INITIAL>"<=" {return (RELOP);}<INITIAL>"=" {return (RELOP);}<INITIAL>"<>" {return (RELOP);}<INITIAL>">" {return (RELOP);}<INITIAL>">=" {return (RELOP);}<INITIAL>"+" {return (RELOP);}<INITIAL>"-" {return (RELOP);}<INITIAL>"*" {return (RELOP);}<INITIAL>"/" {return (RELOP);}<INITIAL>":=" {return (RELOP);}<INITIAL>";" {return (RELOP);}<INITIAL>"." {return (RELOP);}<INITIAL>"," {return (RELOP);}<INITIAL>. {return ERRORCHAR;}%%int yywrap (){return 1;}void writeout(int c){switch(c){case ERRORCHAR: fprintf(yyout, "(ERRORCHAR, \"%s\") ", yytext);break;case RELOP: fprintf(yyout, "(RELOP, \"%s\") ", yytext);break;case WHILE: fprintf(yyout, "(WHILE, \"%s\") ", yytext);break;case DO: fprintf(yyout, "(DO, \"%s\") ", yytext);break;case NUMBER: fprintf(yyout, "(NUM, \"%s\") ", yytext);break;case ID: fprintf(yyout, "(ID, \"%s\") ", yytext);break;case NEWLINE: fprintf(yyout, "\n");break;case PROGRAM: fprintf(yyout, "(PROGRAM, \"%s\") ", yytext);break;case END: fprintf(yyout, "(END, \"%s\") ", yytext);break;case VAR: fprintf(yyout, "(VAR, \"%s\") ", yytext);break;case IF: fprintf(yyout, "(IF, \"%s\") ", yytext);break;case THEN: fprintf(yyout, "(THEN, \"%s\") ", yytext);break;case ELSE: fprintf(yyout, "(ELSE, \"%s\") ", yytext);break;default:break;}return;}int main (int argc, char ** argv){int c,j=0;if (argc>=2){if ((yyin = fopen(argv[1], "r")) == NULL){printf("Can't open file %s\n", argv[1]);return 1;}if (argc>=3){yyout=fopen(argv[2], "w");}}while (c = yylex()){writeout(c);j++;if (j%5 == 0) writeout(NEWLINE);}if(argc>=2){fclose(yyin);if (argc>=3) fclose(yyout);}return 0;}测试文件为:PROGRAM test;VAR i, j, k: INTEGER;f0: REAL;BEGINi := 1;j := 1;k := 0;f0 := ;WHILE k<=100 DOBEGINIF j <20 THENBEGINj := i;k := k+1;f0 := f0*ENDELSEBEGINj := k;k := k-2;f0 := f0/.2ENDENDEND.运行结果:实验2:用Lex设计词法分析器2实验目的:学会用lex设计一个词法分析器,并考虑其与后续语法分析器的链接问题。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
课程设计题目:简单编译器实现学院:信息工程学院计算机系专业:计算机科学与技术班级:计科1103班组长:小组成员:指导教师:2014 年12 月19 日目录1 概述 (3)1.1源、目标语言简介 (3)1.2实现平台与运行平台简介 (3)1.3其它 (4)2简单词法分析器的设计与实现 (4)2.1 基础理论说明 (4)2.2 需求分析 (4)2.3 概要设计 (5)2.4 详细设计 (5)2.5 测试数据与结果 (7)2.6 心得体会 (7)3 简单语法分析器设计与实现 (8)3.1 基础理论说明 (8)3.2 需求分析 (8)3.3 概要设计 (8)3.4 详细设计 (8)3.5 测试数据与结果 (9)3.6 心得体会 (10)4 中间代码产生器的设计与实现 (10)4.1 基础理论说明 (10)4.2 需求分析 (10)4.3 概要设计 (10)4.4 详细设计 (11)4.5 测试数据与结果 (12)4.6 心得体会 (12)附录: (14)附录A:主要源程序与系统截图 (14)附录B:任务分配表及个人完成的程序模块 (33)附录C:小组讨论与研发记录 (34)编译程序的工作过程一般可以分为五个阶段:词法分析、语法分析、语义分析与中间代码产生、优化、目标代码生成。
每一个阶段在功能上是相对独立的,它一方面从上一个阶段获取分析的结果来进行分析,另一方面由将结果传递给下一个阶段。
由编译程序的五个阶段就对应了编译系统的结构。
其中词法分析器利用超前搜索、状态转换等方法,将源程序转化成为一个一个的单词符号二元式。
一般程序语言的单词符号包括关键字、运算符、常数、标识符和界符。
语法分析器将这些单词符号作为输入,对它进行语法分析。
语法分析分为两种方法:自上而下分析法和自下而上分析法。
针对不同程序语言的语法规则可以采取不同的分析方法,当然两种方法也可以同时使用。
语法分析器把语法单元作为输入供语义分析器使用。
一般的语义分析器主要采用的是语法制导方法,即在语法分析的同时进行语法分析,并产生一定的语义动作,来生成中间代码。
上面三个过程可以与硬件无关,而接下来的优化器和目标代码生成器是针对某一种处理器而言的。
代码优化是将语义分析生成的中间代码进行优化,产生执行效率更高的代码。
目标代码生成器最终生成可以在某种机器上运行的机器语言或者汇编语言。
在整个编译过程中还包括对表格的操作和对错误的处理,这些也都是非常重要的环节。
1.1源、目标语言简介使用C语言做简单语法分析器,C语言是一门高级计算机编程语言,设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言1.2实现平台与运行平台简介在win32环境下进行编译,Win32是指Microsoft Windows操作系统的32位环境,是目前使用最多的操作系统。
实验环境:需要TC、VC++ 6.0等开发工具作为本次试验的环境。
通过实现一个可以把类似c语言的源代码转变为中间代码的编译器,更好地理解编译的过程,锻炼我们组的编程能力。
2简单词法分析器的设计与实现2.1 基础理论说明词法分析负责对源程序的字符串进行扫描和分解,根据构词法将字符流(Character Stream)转化成单词流(Token Stream)。
2.2 需求分析词法分析器产生下述小语言的单词序列这个小语言的所有的单词符号,以及它们的种别编码和内部值[1]如下表:2.3 概要设计首先,所有的关键字(如IF﹑WHILE等)都是“保留字”。
所谓的保留字的意思是,用户不得使用它们作为自己定义的标示符。
例如,下面的写法是绝对禁止的:IF(5)=x其次,由于把关键字作为保留字,故可以把关键字作为一类特殊标示符来处理。
也就是说,对于关键字不专设对应的转换图。
但把它们(及其种别编码)预先安排在一张表格中(此表叫作保留字表)。
当转换图识别出一个标识符时,就去查对这张表,确定它是否为一个关键字。
再次,如果关键字、标识符和常数之间没有确定的运算符或界符作间隔,则必须至少用一个空白符作间隔(此时,空白符不再是完全没有意义的了)。
例如,一个条件语句应写为 IF i>0 i= 1;而绝对不要写成IFi>0 i=1;因为对于后者,我们的分析器将无条件地将IFI看成一个标识符。
2.4 详细设计状态转换图[2]词法分析器的流程图[3]2.5 测试数据与结果2.6 心得体会设计该词法分析器的过程中虽然没有实际将所有的状态转移表建立出来,但是所用的思想是根据状态转移表实现对单词的识别。
首先构造一个保留字表,然后,每输入一个字符就检测应该进入什么状态,并将该字符连接到d串后继续输入,如此循环,最后根据所在的接受状态以及保留字表识别单词3 简单语法分析器设计与实现3.1 基础理论说明在计算机科学和语言学中,语法分析(英:Syntacticanalysis,也叫Parsing)是根据某种给定的形式文法对由单词序列(如英语单词序列)构成的输入文本进行分析并确定其语法结构的一种过程。
语法分析器(Parser)通常是作为编译器或解释器的组件出现的,它的作用是进行语法检查、并构建由输入的单词组成的数据结构(一般是语法分析树、抽象语法树等层次化的数据结构)。
语法分析器通常使用一个独立的词法分析器从输入字符流中分离出一个个的“单词”,并将单词流作为其输入。
实际开发中,语法分析器可以手工编写,也可以使用工具(半)自动生成。
3.2 需求分析语法分析是编译过程的核心部分。
它的任务是在词法分析识别出单词符号串的基础上,分析并判定程序的语法结构是否符合语法规则。
语法分析器的工作本质上是按文法的产生式,识别输入串是否是一个句子。
自上而下分析法的主旨是,对任何输入串,试图用一切可能的方法,从文法开始符号出发,自上而下地为输入串建立一棵语法树。
这种方法本质上是一种试探过程,是反复使用不同产生式谋求匹配输入串的过程。
3.3 概要设计语法分析器能识别由加+ 减- 乘* 除/ 乘方^ 括号()操作数所组成的算术表达式,其文法如下:E→E+T|E-T|TT→T*F|T/F|FF→P^F|Pp→(E)|i使用的算法可以是:预测分析法;递归下降分析法;算符优先分析法;LR分析法等3.4 详细设计语法分析器主程序图[4]3.5 测试数据与结果3.6 心得体会此次实验,让我们组对编译原理的基本知识有了深入的了解,加强了对语法分析的认识。
代码的编写过程中用到了一些以前从未用过的函数,都是现学现用,掌握还不是很深。
在代码调试过程中结果出现许多无法解释的错误,但仍旧坚持下来了,最终调试出了结果。
通过这次实验,我们组的动手实践能力得到很大的提高。
4 中间代码产生器的设计与实现4.1 基础理论说明在进行了语法分析和语义分析阶段的工作之后,有的编译程序将源程序变成一种内部表示形式,这种内部表示形式叫做中间语言或中间表示或中间代码。
所谓“中间代码”是一种结构简单、含义明确的记号系统,这种记号系统复杂性介于源程序语言和机器语言之间,容易将它翻译成目标代码。
另外,还可以在中间代码一级进行与机器无关的优化。
产生中间代码的过程叫中间代码生成。
4.2 需求分析定义一种语言除了要求定义语法外,还要求定义语义,即对语言的各种语法单位赋予具体的意义。
语义分析的任务是首先对每种语法单位进行静态的语义审查,然后分析其含义,并用另一种语言形式,即比源语言更加接近于目标语言的一种中间代码来进行描述这种语言。
因此,中间代码就显得十分重要,它关系着整个程序语言的正确编译与否,同时也是进行下一步编译的重要先决条件。
4.3 概要设计产生上述算术表达式的中间代码(四元式序列)递归下降子程序:数据结构:SYN —算符栈;SEM —语义栈;4.4 详细设计中间代码生成器流程图[5]:4.5 测试数据与结果4.6 心得体会我们知道,定义一种语言除了要求定义语法外,还要求定义语义,即对语言的各种语法单位赋予具体的意义。
语义分析的任务是首先对每种语法单位进行静态的语义审查,然后分析其含义,并用另一种语言形式,即比源语言更加接近于目标语言的一种中间代码来进行描述这种语言。
因此,中间代码就显得十分重要,它关系着整个程序语言的正确编译与否,同时也是进行下一步编译的重要先决条件。
参考文献[1]Alfred pilers: Principles,Techniques,and Tools:4页[2] zjbujs.百度文库.编译原理词法语法语义分析器设计.2013-07-23:5页[3] zjbujs.百度文库.编译原理词法语法语义分析器设计.2013-07-23:6页[4] 线性大树.百度文库. 编译原理词法语法语义设计实现.2014-06-06:8页[5] LWH1989216.百度文库.编译原理词法分析和语法分析 (C语言版)2011-05-11:10页附录:附录A:主要源程序与系统截图/*******************************词法分析器源代码******************************/ #include<stdio.h>#include<iostream.h>#include<string.h>#define MAX 150 //词法分析表的最大容量#define MAXBUF 255//缓冲区的最大缓冲量char prog[MAXBUF],token[MAX];char ch;int syn,p,m,n,sum;char *rwtab[6]={"begin","if","then","while","do","end"};/////////////////////////////////////////////////词法分析程序///////////////////////////////////////////////void scaner(){for(m=0;m<MAX;m++)token[m]=NULL;m=0;sum=0;ch=prog[p++];while(ch==' ')ch=prog[p++];//读取下一个字符;if(ch>=65&&ch<=122 /*是字母字符*/){while(ch>=65&&ch<=122||ch>=48&&ch<=57)/*为字母字符或数字字符*/{token[m++]=ch;ch=prog[p++];//读取下一个字符;}token[m++]='\0';p=p-1;syn=10;for(n=0;n<6;n++)if(strcmp(token,rwtab[n])==0){syn=n+1;//给出syn值;break;}}else if(ch>=48&&ch<=57/*ch为数字字符*/){while(ch>=48&&ch<=57/*ch为数字字符*/){sum=sum*10+ch-'0';ch=prog[p++];//读取下一个字符;}p=p-1;//回退一个字符;syn=11;}else switch(ch){case '<': m=0;token[m++]=ch;ch=prog[p++];//读取下一个字符;if(ch=='>'){syn=21;token[m++]=ch;}else if(ch=='='){syn=22;token[m++]=ch;}else{syn=20;p=p-1;//回退一个字符;}break;case'>': token[m++]=ch;;ch=prog[p++];//读取下一个字符;if(ch=='='){syn=24;//将>=的中别码=>syn;token[m++]=ch;;}else{syn=23;p=p-1;//回退一个字符;}break;case':': token[m++]=ch;;ch=prog[p++];//读取下一个字符;if(ch=='='){syn=18;token[m++]=ch;;}else{syn=17;p=p-1;//回退一个字符;}break;case'+': syn=13;token[0]=ch;break;case'-': syn=14;token[0]=ch;break;case'*': syn=15;token[0]=ch;break;case'/': syn=16;token[0]=ch;break;case'=': syn=25;token[0]=ch;break;case';': syn=26;token[0]=ch;break;case'(': syn=27;token[0]=ch;break;case')': syn=28;token[0]=ch;break;case'#': syn=0;token[0]=ch;break;default: syn=-1;break;}}/////////////////////////////////////////////主函数///////////////////////////////////////////void main(){char A;cout<<"*****************************************"<<endl;loop:p=0;cout<<"*****************************************"<<endl;printf("please input string (以#结束):\n");do{scanf("%c",&ch);prog[p++]=ch;//输入源程序字符串,送到缓冲区prog[p++]中;}while(ch!='#');p=0;do{scaner();switch(syn){case 11:cout<<"( "<<syn<<","<<sum<<" )"<<endl;//输出(数的二元组);break;case -1:cout<<"error"<<endl;break;default:cout<<"( "<<syn<<","<<token<<" )"<<endl;//输出(其他单词二元组);}}while(syn!=0);cout<<"*****************************************"<<endl;cout<<"请确定是否继续使用程序:S为继续;其它为退出;"<<endl;cout<<"是否继续:";cin>>A;switch(A){case 'S': goto loop;default: cout<<"*****************************************"<<endl;cout<<"Thank you ! Bye Bye !"<<endl;cout<<"*****************************************"<<endl;break;}}结果:/*******************************语法分析器源代码******************************/#include <stdio.h>#include<dos.h>#include<stdlib.h>#include<string.h>char a[50] ,b[50],d[200],e[10];char ch;int n1,i1=0,flag=1,n=5;int total=0;int E();int E1();int T();int G();int S();int F();void input();void input1();void output();void main() /*递归分析*/{int f,p,j=0;char x;d[0]='E';d[1]='=';d[2]='>';d[3]='T';d[4]='G';d[5]='#';printf("Please input character string(length<50,end of '#'):\n");do{scanf("%c",&ch);a[j]=ch;j++;}while(ch!='#');n1=j;ch=b[0]=a[0];printf("步骤\t文法\t分析串\t\t分析字符\t剩余串\n");f=E1();if (f==0) return;if (ch=='#'){ printf("\nAccept! Right Expression!\n\n");p=0;x=d[p];while(x!='#') {printf("%c",x);p=p+1;x=d[p]; /*输出推导式*/ }}else {printf("\nError\n");printf("回车返回\n");getchar();getchar();return;}printf("\n");printf("回车返回\n");getchar();getchar();}int E1(){ int f,t;printf("%d\tE-->TG\t",total);total++;flag=1;input();input1();f=T();if (f==0) return(0);t=G();if (t==0) return(0);else return(1);}int E(){ int f,t;printf("%d\tE-->TG\t",total);total++;e[0]='E';e[1]='=';e[2]='>';e[3]='T';e[4]='G';e[5]='#';output();flag=1;input();input1();f=T();if (f==0) return(0);t=G();if (t==0) return(0);else return(1);}int T(){ int f,t;printf("%d\tT-->FS\t",total);total++;e[0]='T';e[1]='=';e[2]='>';e[3]='F';e[4]='S';e[5]='#';output();flag=1;input();input1();f=F();if (f==0) return(0);t=S();if (t==0) return(0);else return(1);}int G(){ int f;if(ch=='+') {b[i1]=ch;printf("%d\tG-->+TG\t",total);total++;e[0]='G';e[1]='=';e[2]='>';e[3]='+';e[4]='T';e[5]='G';e[6]='#';output();flag=0;input();input1();ch=a[++i1];f=T();if (f==0) return(0);G();return(1);}printf("%d\tG-->^\t",total);total++;e[0]='G';e[1]='=';e[2]='>';e[3]='^';e[4]='#';output();flag=1;input();input1();return(1);}int S(){int f,t;if(ch=='*') {b[i1]=ch;printf("%d\tS-->*FS\t",total);total++;e[0]='S';e[1]='=';e[2]='>';e[3]='*';e[4]='F';e[5]='S';e[6]='#';output();flag=0;input();input1();ch=a[++i1];f=F();if (f==0) return(0);t=S();if (t==0) return(0);else return(1);}printf("%d\tS-->^\t",total);total++;e[0]='S';e[1]='=';e[2]='>';e[3]='^';e[4]='#';output();flag=1;a[i1]=ch;input();input1();return(1);}int F(){ int f;if(ch=='(') {b[i1]=ch;printf("%d\tF-->(E)\t",total);total++;e[0]='F';e[1]='=';e[2]='>';e[3]='(';e[4]='E';e[5]=')';e[6]='#';output();flag=0;input();input1();ch=a[++i1];f=E();if (f==0) return(0);if(ch==')') {b[i1]=ch;printf("%d\tF-->(E)\t",total);total++;flag=0;input();input1();ch=a[++i1];}else {printf("\nError\n");return(0);}}else if(ch=='i') {b[i1]=ch;printf("%d\tF-->i\t",total);total++;e[0]='F';e[1]='=';e[2]='>';e[3]='i';e[4]='#';output();flag=0;input();input1();ch=a[++i1];}else {printf("\nError\n");return(0);}return(1);}void input(){int j=0;for (;j<=i1-flag;j++)printf("%c",b[j]); /*输出分析串*/printf("\t\t");printf("%c\t\t",ch); /*输出分析字符*/ }void input1(){int j;for (j=i1+1-flag;j<n1;j++)printf("%c",a[j]); /*输出剩余字符*/printf("\n");}void output(){ /*推导式计算*/int m,k,j,q;int i=0;m=0;k=0;q=0;i=n;d[n]='=';d[n+1]='>';d[n+2]='#';n=n+2;i=n;i=i-2;while(d[i]!='>'&&i!=0) i=i-1;i=i+1;while(d[i]!=e[0]) i=i+1;q=i;m=q;k=q;while(d[m]!='>') m=m-1;m=m+1;while(m!=q) {d[n]=d[m];m=m+1;n=n+1;}d[n]='#';for(j=3;e[j]!='#';j++){d[n]=e[j];n=n+1;}k=k+1;while(d[k]!='=') {d[n]=d[k];n=n+1;k=k+1;}d[n]='#';}结果:/****************************中间代码生成器源代码******************************/ #include<string>#include <iostream>using namespace std;#define DEFAULT_SIZE 100char EMachine(char w); //表达式E的自动机char TMachine(char w); //表达式T的自动机char FMachine(char w); //表达式F的自动机bool ZMachine(); //表达式Z的自动机string intToString(int a); //整形变成字符串形函数class stack //栈类定义{private:int top;string *stacka;int maxsize;public:stack(int size=DEFAULT_SIZE);~stack(){ delete [] stacka; }void push(const string &item);string pop(void);string gettop(void) const ;bool empty(void) const { return (top==-1); }bool full(void) const { return (top==maxsize-1); }void clear(void) { top=-1; }};stack::stack(int size) //栈类的构造函数{top=-1;maxsize=size;stacka=new string[maxsize];if(!stacka){cerr<<"allocate memory failed."<<endl;exit(1);}}void stack::push(const string &item) //压栈操作{if(full()){cerr<<"stack full, cannot push."<<endl;return;}top++;stacka[top]=item;}string stack::pop(void) //出栈操作{if(empty()){cerr<<"stack empty, cannot pop."<<endl;exit(1) ;}string item=stacka[top];top--;return item;}string stack::gettop(void) const //取栈顶操作{if(empty()){cerr<<"stack empty, cannot gettop."<<endl;exit(1) ;}return stacka[top];}static stack wordStack; //符号栈static int noOfQuet=0; //静态四元式个数记录static int noOfT = 1; //静态状态个数记录void main(){ //主函数char yesOrNo; //进行一个循环操作控制do{cout<<"请输入算术表达式:"<<endl;noOfT = 1; //每次结束询问ZMachine();cout<<endl<<"Continue?Yes or Not:";cin>>yesOrNo; //输入“Y”则继续}while(yesOrNo=='y'); //否则程序结束}bool ZMachine(){ //Z自动机char w;cin>>w;w = EMachine(w); //调用E自动机if(w=='#'){ //遇到“#”则结束return true;}else{return false;}}char EMachine(char w){ //E自动机string operate,a,b,c;string state[5];w = TMachine(w); //调用T自动机while(w=='+'||w=='-'){ //是加或减符号operate = w;cin>>w; //读入下一字符w = TMachine(w); //调用T自动机b = wordStack.pop(); //字符栈弹出a = wordStack.pop(); //两个操作字符cout<<"(\""<<operate<<"\","<<a<<","<<b<<",t"<<noOfT<<")"<<endl;c = "t"+intToString(noOfT); //输出四元式wordStack.push(c); //新状态压栈noOfT++; //状态计数加一}return w;}char TMachine(char w){string operate,a,b,c;string state[5];w = FMachine(w); //调用F自动机while(w=='*'||w=='/'){ //是乘除号operate = w;cin>>w; //读取下一字符w = FMachine(w); //调用F自动机b = wordStack.pop(); //符号栈弹出a = wordStack.pop(); //两个操作字符cout<<"(\""<<operate<<"\","<<a<<","<<b<<",t"<<noOfT<<")"<<endl;c = "t"+intToString(noOfT); //输出四元式wordStack.push(c); //新状态压栈noOfT++; //状态计数加1}return w;}char FMachine(char w){ //F自动机string theWord;if(w>='a'&&w<='z'||w>='A'&&w<='Z'){theWord = w; //当前字符是字母wordStack.push(theWord); //则压栈}else if(w == '('){ //是左括号cin>>w; //则读取下一字符w = EMachine(w); //调用E自动机if(w!=')'){ //不是右括号则输入有误,报错cerr<<"the input is wrong!"<<endl;exit(0);}}else{ //否则有误,报错cerr<<"the input is wrong!"<<endl;exit(0);}cin>>w; //读取下一字符return w;}string intToString(int a){ //整形变字符串形函数string d;char b='0',c;int i;while(a!=0){i = a%10;a = a/10;c = (int)b + i;d = c + d;}return d;}结果://y=a+b//Y=a+b*(c-d)附录B:任务分配表及个人完成的程序模块附录C:小组讨论与研发记录2014-12-16 9:00-11:00 讨论课程设计需求,明确分工2014-12-16 13:00-16:00 搜集相关资料,编写word文档2014-12-17 11:00 整理word文档,讨论ppt演示内容2014-12-17 15:00 讨论修改ppt。