广东工业大学编译原理实验报告
编译原理实验报告(C语言)
编译原理实验报告实验项目1:词法分析程序实验一、实验的目的与任务:编译原理是计算机类专业特别是计算机软件专业的一门重要专业课。
设置该课程的目的在于系统地向学生讲述编译系统的结构、工作流程及编译程序各组成部分的设计原理和实现方法,使学生通过学习既掌握编译理论和方法方面的基本知识,也具有设计、实现、分析和维护编译程序等方面的初步能力。
编译原理是一门理论性和实践性都比较强的课程。
进行上机实验的目的是使学生通过完成上机实验题目加深对课堂教学内容的理解。
同时培养学生实际动手能力。
编译实验由三个独立实验组成,按照由浅入深进行排列,希望通过本实验使学生更深学习并理解编译的主要过程和相关方法。
词法分析的目的是将输入的源程序进行划分,给出基本符号(token)的序列,并掠过注解和空格等分隔符号。
基本符号是与输入的语言定义的词法所规定的终结符。
本实验要求学生编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。
并依次输出各个单词的内部编码及单词符号自身值。
(遇到错误时可显示“Error”,然后跳过错误部分继续进行)二、题目分析1.这里采用C语言编写的源程序作为词法分析程序的输入数据,输入数据保存在“in.txt”记事本中,将分析结果存在“out.txt”记事本中。
词法分析器的源代码使用C语言编写。
2.下面就词法分析程序中的主要变量进行说明:主函数main():打开要分析的C语言源程序,若不能正确打开,则报错。
先从源程序中读入一个字符ch,然后进行如下处理:1、cp消耗掉空格,制表符,换行符后,cp数组复位,开始检测cp;2、数字检测,对照符号表输出,若匹配成功,则返回序号;3、字符串检测, 对照符号表输出,若匹配成功,则返回序号;4、基本保留字检测,对照符号表输出,若匹配成功,则返回序号;5、运算符检测,对照符号表输出,若匹配成功,则返回序号;注意这里碰到‘/’时,要判断后面是否跟着是注释语句。
编译原理实验报告(C语言)
else if(strcmp(word,"if")==0) fprintf(out,"%c%c%s%c,%d%c\n",'(','"',word,'"',12,')'); else if(strcmp(word,"else")==0) fprintf(out,"%c%c%s%c,%d%c\n",'(','"',word,'"',13,')'); else if(strcmp(word,"switch")==0) fprintf(out,"%c%c%s%c,%d%c\n",'(','"',word,'"',14,')'); else if(strcmp(word,"case")==0) fprintf(out,"%c%c%s%c,%d%c\n",'(','"',word,'"',15,')'); else if(strcmp(word,"for")==0) fprintf(out,"%c%c%s%c,%d%c\n",'(','"',word,'"',16,')'); else if(strcmp(word,"do")==0) fprintf(out,"%c%c%s%c,%d%c\n",'(','"',word,'"',17,')'); else if(strcmp(word,"while")==0) fprintf(out,"%c%c%s%c,%d%c\n",'(','"',word,'"',18,')'); else if(strcmp(word,"goto")==0) fprintf(out,"%c%c%s%c,%d%c\n",'(','"',word,'"',19,')'); else if(strcmp(word,"continue")==0) fprintf(out,"%c%c%s%c,%d%c\n",'(','"',word,'"',20,')'); else if(strcmp(word,"break")==0) fprintf(out,"%c%c%s%c,%d%c\n",'(','"',word,'"',21,')');
编译原理实验报告
编译原理实验报告实验⼀词法分析⼀、实验⽬的设计、编制并调试⼀个词法分析程序,加深对词法分析原理的理解。
⼆、实验要求2.1 待分析的简单的词法(1)关键字:begin if then while do end所有的关键字都是⼩写。
(2)运算符和界符:= + - * / < <= <> > >= = ; ( ) #(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:ID = letter (letter | digit)*NUM = digit digit*(4)空格有空⽩、制表符和换⾏符组成。
空格⼀般⽤来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。
2.2 各种单词符号对应的种别码:表2.1 各种单词符号对应的种别码单词符号种别码单词符号种别码bgin 1 :17If 2 := 18Then 3 < 20wile 4 <> 21do 5 <= 22end 6 > 23lettet(letter|digit)* 10 >= 24 dight dight* 11 = 25 + 13 ;26—14 ( 27* 15 ) 28/ 16 # 02.3 词法分析程序的功能:输⼊:所给⽂法的源程序字符串。
输出:⼆元组(syn,token或sum)构成的序列。
其中:syn为单词种别码;token为存放的单词⾃⾝字符串;(1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)……三、词法分析程序的算法思想:算法的基本任务是从字符串表⽰的源程序中识别出具有独⽴意义的单词符号,其基本思想是根据扫描到单词符号的第⼀个字符的种类,拼出相应的单词符号。
3.1 主程序⽰意图:主程序⽰意图如图3-1所⽰。
其中初始包括以下两个⽅⾯:⑴关键字表的初值。
关键字作为特殊标识符处理,把它们预先安排在⼀张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。
编译原理实验报告
编译原理实验报告一、实验目的本次编译原理实验的主要目的是通过实践加深对编译原理中词法分析、语法分析、语义分析和代码生成等关键环节的理解,并提高实际动手能力和问题解决能力。
二、实验环境本次实验使用的编程语言为 C/C++,开发工具为 Visual Studio 2019,操作系统为 Windows 10。
三、实验内容(一)词法分析器的设计与实现词法分析是编译过程的第一个阶段,其任务是从输入的源程序中识别出一个个具有独立意义的单词符号。
在本次实验中,我们使用有限自动机的理论来设计词法分析器。
首先,我们定义了单词的种类,包括关键字、标识符、常量、运算符和分隔符等。
然后,根据这些定义,构建了相应的状态转换图,并将其转换为程序代码。
在实现过程中,我们使用了字符扫描和状态转移的方法,逐步读取输入的字符,判断其所属的单词类型,并将其输出。
(二)语法分析器的设计与实现语法分析是编译过程的核心环节之一,其任务是在词法分析的基础上,根据给定的语法规则,判断输入的单词序列是否构成一个合法的句子。
在本次实验中,我们采用了自顶向下的递归下降分析法来实现语法分析器。
首先,我们根据给定的语法规则,编写了相应的递归函数。
每个函数对应一种语法结构,通过对输入单词的判断和递归调用,来确定语法的正确性。
在实现过程中,我们遇到了一些语法歧义的问题,通过仔细分析语法规则和调整函数的实现逻辑,最终解决了这些问题。
(三)语义分析与中间代码生成语义分析的任务是对语法分析所产生的语法树进行语义检查,并生成中间代码。
在本次实验中,我们使用了四元式作为中间代码的表示形式。
在语义分析过程中,我们检查了变量的定义和使用是否合法,类型是否匹配等问题。
同时,根据语法树的结构,生成相应的四元式中间代码。
(四)代码优化代码优化的目的是提高生成代码的质量和效率。
在本次实验中,我们实现了一些基本的代码优化算法,如常量折叠、公共子表达式消除等。
通过对中间代码进行分析和转换,减少了代码的冗余和计算量,提高了代码的执行效率。
(精选)广工2014编译原理实验报告
实验报告课程名称编译原理题目名称 PL/0编译器的扩充学生学院计算机学院专业班级计算机科学与技术12(4)学号 3112005901学生姓名柏石先指导教师李杨程序功能完成情况测试用例全面程度学生对所编程序熟悉程度报告格式是否与要求相符报告内容是否准确、全面2014 年 12 月 20日一、实验目的与要求对PL/0作以下修改扩充:(1)增加单词:保留字 ELSE,FOR,STEP,UNTIL,DO,RETURN运算符 *=,/=,&,||,!(2)修改单词:不等号# 改为 <>(3)增加条件语句的ELSE子句,要求:写出相关文法,语法描述图,语义描述图。
二、实验环境与工具1、源语言:PL/0语言,PL/0语言是PASCAL语言的子集,它的编译程序是一个编译解析执行系统,后缀名为.PL0;2、目标语言:生成文件后缀为*.COD的目标代码3、实现平台:Borland C++Builder 64、运行平台:Windows 8.1三、结构流程1、结构设计说明(1)PL/0 语言编译器PL/0语言可看成是PASCAL语言的子集,它的编译程序是一个编译解释执行系统。
PL/0的目标程序为假想栈式计算机的汇编语言,与具体计算机无关。
2、词法分析程序的设计四、开发过程(一)增加单词:保留字 ELSE,FOR,STEP,UNTIL,DO , RETURN运算符 *=,/=,&,||,!新增6个保留字和5个运算符,合计11个单词。
其中保留字ELSE,FOR,STEP,UNTIL,DO, RETURN分别对应ELSESYM,FORSYM, STEPSYM, UNTILSYM,DOSYM,RETURNSYM;运算符 *= ,/= ,& ,|| ,!分别对应TIMESBECOMES, SLASHBECOMES, ANDSYM, ORSYM, NOTSYM。
注:要求只做词法分析部分,不做语义分析处理,实验的结果只是识别新增的保留字和运算1.首先考虑需要增加保留字的个数,以及如何命名,再将新增的保留字添加对应的保留字的集合中。
编译原理实验报告
编译原理实验报告一、实验概述本次实验旨在设计并实现一个简单的词法分析器,即实现编译器的第一个阶段,词法分析。
词法分析器将一段源程序代码作为输入,将其划分为一个个的词法单元,并将其作为输出。
二、实验过程1.设计词法规则根据编程语言的规范和所需实现的功能,设计词法规则,以明确规定如何将源程序代码分解为一系列的词法单元。
2.实现词法分析器采用合适的编程语言,根据所设计的词法规则,实现词法分析器。
词法分析器的主要任务是读入源程序代码,并将其根据词法规则进行分解,生成对应的词法单元。
3.测试词法分析器设计测试用例,用于检验词法分析器的正确性和性能。
测试用例应包含各种情况下的源程序代码。
4.分析和修正错误根据测试过程中发现的问题,分析产生错误的原因,并进行修正。
重复测试和修正的过程,直到词法分析器能够正确处理所有测试用例。
三、实验结果我们设计了一个简单的词法分析器,并进行了测试。
测试用例涵盖了各种情况下的源程序代码,包括正确的代码和错误的代码。
经过测试,词法分析器能够正确处理所有的测试用例。
词法分析器将源程序代码分解为一系列的词法单元,每个词法单元包含了单词的种类和对应的值。
通过对词法单元的分析,可以进一步进行语法分析和语义分析,从而完成编译过程。
四、实验总结通过本次实验,我深入了解了编译原理的词法分析阶段。
词法分析是编译器的第一个重要阶段,它将源程序代码分解为一个个的词法单元,为后续的语法分析和语义分析提供基础。
在实现词法分析器的过程中,我学会了如何根据词法规则设计词法分析器的算法,并使用编程语言实现词法分析器。
通过测试和修正,我掌握了调试和错误修复的技巧。
本次实验的经验对我今后的编程工作有很大帮助。
编译原理是计算机科学与技术专业的核心课程之一,通过实践能够更好地理解和掌握其中的概念和技术。
我相信通过进一步的学习和实践,我能够在编译原理领域取得更大的成果。
编译原理实验报告
编译原理实验报告一、实验目的编译原理是计算机科学中的重要学科,它涉及到将高级编程语言转换为计算机能够理解和执行的机器语言。
本次实验的目的是通过实际操作和编程实践,深入理解编译原理中的词法分析、语法分析、语义分析以及中间代码生成等关键环节,提高我们对编译过程的认识和编程能力。
二、实验环境本次实验使用的编程语言为C++,开发环境为Visual Studio 2019。
此外,还使用了一些相关的编译工具和调试工具,如 GDB 等。
三、实验内容(一)词法分析器的实现词法分析是编译过程的第一步,其任务是将输入的源程序分解为一个个单词符号。
在本次实验中,我们使用有限自动机的理论来设计和实现词法分析器。
首先,定义了各种单词符号的类别,如标识符、关键字、常量、运算符等。
然后,根据这些类别设计了相应的状态转换图,并将其转换为代码实现。
在实现过程中,使用了正则表达式来匹配输入字符串中的单词符号。
对于标识符和常量等需要进一步处理的单词符号,使用了相应的规则进行解析和转换。
(二)语法分析器的实现语法分析是编译过程的核心环节之一,其任务是根据给定的语法规则,分析输入的单词符号序列是否符合语法结构。
在本次实验中,我们使用了递归下降的语法分析方法。
首先,根据实验要求定义了语法规则,并将其转换为相应的递归函数。
在递归函数中,通过对输入单词符号的判断和处理,逐步分析语法结构。
为了处理语法错误,在分析过程中添加了错误检测和处理机制。
当遇到不符合语法规则的输入时,能够输出相应的错误信息,并尝试进行恢复。
(三)语义分析及中间代码生成语义分析的目的是对语法分析得到的语法树进行语义检查和语义处理,生成中间代码。
在本次实验中,我们使用了三地址码作为中间代码的表示形式。
在语义分析过程中,对变量的定义和使用、表达式的计算、控制流语句等进行了语义检查和处理。
对于符合语义规则的语法结构,生成相应的三地址码指令。
四、实验步骤(一)词法分析器的实现步骤1、定义单词符号的类别和对应的正则表达式。
编译原理课程实验报告
五、实验体会
指导教师评语:
日期:
编译原理课程实验报告实验2语法分析院系姓名任课教师实验地点实验课表现学号出勤表现得分操作结果得分指导教师实验时间实验报告得分实验总分一实验目的要求需分析本次实验的基本目的并综述你是如何实现这些目的的二实验内容要求对如下工作进行展开描述1给出如下语言成分的文法描述函数定义或过程定义变量说明赋值表达式循环分支2语法分析程序的总体结构及物理实现3语法分析表及其数据结构和查找算法4语法分析表的生成算法5错误处理错误的位置及类型等三实验结果要求将实验获得的结果进行描述基本内容包括1针对一测试程序输出其语法分析结果2输出针对此测试程序对应的语法错误报告注其中的测试样例需先用已编写的词法分析程序进行处理
变量说明
赋值
表达式
循环
分支
(2)语法分析程序的总体结构及物理实现
(3)语法分析表及其数据结构和查找算法
(4)语法分析表的生成算法
(5)错误处理
错误的位置及类型等
三、实验结果
要求:将实验获得的结果进行描述,基本内容包括:
(1)针对一测试程序输出其语法分析结果;
(2)输出针对此测试程序对应的语法错误报告;
编译原理课程实验报告
实验2:语法分析
姓名
院系
学号
任课教师
指导教师
实验地点
实验时间
实验课表现
出勤、表现得分
实验报告
得分
实验总分
操作结果得分
一、实验目的
要求:需分析本次实验的基本目的,并综述你是如何实现这些目的的?
二、实验内容
要求:对如下工作进行展开描述
编译原理实验报告(手打)
《编译原理》实验报告班级:计C104姓名:李云霄学号:108490实验一词法分析程序实现一、实验目的与要求通过编写和调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将字符形式的源程序流转化为一个由各类单词符号组成的流的词法分析方法。
二、实验内容选取无符号数的算术四则运算中的各类单词为识别对象,要求将其中的各个单词识别出来。
输入:由无符号数和+,-,*,/, ( , ) 构成的算术表达式,如1.5E+2-100。
输出:对识别出的每一单词均单行输出其类别码(无符号数的值暂不要求计算)。
三、实现方法与环境1、首先设计识别各类单词的状态转换图。
描述无符号常数的确定、最小化状态转换图如图1所示。
其中编号0,1,2,…,6代表非终结符号<无符号数>、<余留无符号数>、<十进小数>、<小数部分>、<指数部分>、<整指数>及<余留整指数>, 1,2和6为终态,分别代表整数、小数和科学计数的识别结束状态。
图1 文法G[<无符号数>]的状态转换图其中编号0,1,2,…,6代表非终结符号<无符号数>、<余留无符号数>、<十进小数>、<小数部分>、<指数部分>、<整指数>及<余留整指数>, 1,2和6为终态,分别代表整数、小数和科学计数的识别结束状态。
在一个程序设计语言中,一般都含有若干类单词符号,为此可首先为每类单词建立一张状态转换图,然后将这些状态转换图合并成一张统一的状态图,即得到了一个有限自动机,再进行必要的确定化和状态数最小化处理,最后据此构造词法分析程序。
四则运算算术符号的识别很简单,直接在状态图的0状态分别引出相应标记的矢根据描述语言中各类单词的文法状态转换图或状态矩阵,利用某种语言(C语言或JAVA语言)直接编写词法分析程序。
广工编译原理实验报告
<<编译原理>>课内实验报告项目名称 PL/0编译器学院____ 计算机学院_______专业_ _年级班别________学号 _学生姓名_______ ___辅导教师_______成绩_______ _______目录一、课内实验的内容------------------------------------------4二、实验修改部分--------------------------------------------4三、概述-------------------------------------------------11四、结构设计说明-------------------------------------------11五、各功能模块描述-----------------------------------------14六、主要成份描述------------------------------------------14七、测试用例----------------------------------------------16八、开发过程和完成情况--------------------------------------21一、课内实验的内容对PL/0作以下修改扩充:(1)增加单词:保留字 ELSE,FOR, STEP,RETURN运算符 +=,-=,++,--,&,|,~(2)修改单词:不等号# 改为 <>(3)增加条件语句的ELSE子句二、实验修改部分:1、增加四个保留字和七个运算符,共十一个单词。
修改部分:#define symnum 43 //保留字从32增加到43个2、增加五个保留字:ELSE,FOR,STEP,RETURN○1头文件pl0.henum symbol { 新增加单词: elsesym, forsym, stepsym,returnsym, pluseq/* += */,plusone/* ++ */,plus/* + */,minuseq/* -= */,minusone/* -- */,minus/* - */,and,or,not}○2头文件pl0.h#define norw 24 //关键字从13增加到24个○3PL0.cppinit();新增加:(增加后数组的内容要再次根据字母顺序重新排列)strcpy(&(word[0][0]),"begin");strcpy(&(word[1][0]),"call");strcpy(&(word[2][0]),"const");strcpy(&(word[3][0]),"do");strcpy(&(word[4][0]),"else"); /*增加单词:保留字else*/strcpy(&(word[5][0]),"end");strcpy(&(word[6][0]),"for"); /*增加单词:保留字 for*/strcpy(&(word[7][0]),"if");strcpy(&(word[8][0]),"odd");strcpy(&(word[9][0]),"procedure");strcpy(&(word[10][0]),"read");strcpy(&(word[11][0]),"return");/*增加单词:保留字 return*/strcpy(&(word[12][0]),"step"); /*增加单词:保留字step*/strcpy(&(word[13][0]),"then");strcpy(&(word[14][0]),"while");strcpy(&(word[15][0]),"write");wsym[0]=beginsym;wsym[1]=callsym;wsym[2]=constsym;wsym[3]=dosym;wsym[4]=elsesym; /*else*/wsym[5]=endsym;wsym[6]=forsym; /*for*/wsym[7]=ifsym;wsym[8]=oddsym;wsym[9]=procsym;wsym[10]=readsym;wsym[11]=returnsym; /*return*/wsym[12]=stepsym; /*step*/wsym[13]=thensym;wsym[14]=whilesym;wsym[15]=writesym;3、增加四个运算符:+=,-=,++,-- ,∧,∨,┓PL0.cppgetsym();增加对+,-,++,--,+=,-=的识别;Statement();增加对+,-,++,--,-=的语句的处理;○1Init()中改动:ssym[‘&’]=and;ssym[‘|’]=or;ssym[‘~’]=not;facbegsys[plusone]=true; // 添加前自加运算facbegsys[minusone]=true;// 添加前自减运算○2Getsym()增加的内容:int getsym() {int i,j,k;while( ch==' '||ch==10||ch==9){getchdo;}if(ch>='a'&&ch<='z'){k=0;do{if(k<al){a[k]=ch;k++;}getchdo;}while(ch>='a'&&ch<='z'||ch >='0'&&ch<='9');a[k]=0;strcpy(id,a);i=0;j=norw-1;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(ch>='0'&&ch<='9'){k=0;num=0;sym=number;do{num=10*num+ch-'0';k++;getchdo;}while(ch>='0'&&ch<='9'); /*获取数字的值*/k--;if(k>nmax){error(30);}}else{if(ch==':')/*检测赋值符号*/{getchdo;if(ch=='='){sym=becomes;getchdo;}else{sym=nul; /*不能识别的符号*/}}else{if(ch=='<')/*检测小于或小于等于符号*/{getchdo;if(ch=='='){sym=leq;getchdo;}else{sym=lss;}}else if(ch=='>') /*检测大于或大于等于符号*/{getchdo;if(ch=='='){sym=geq;getchdo;}else{sym=gtr;}}/*这里之间为添加的内容*/else if(ch=='+'){ /*检测+,+=,++符号*/getchdo;if(ch=='='){sym=pluseq;getchdo;}elseif(ch=='+'){sym=plusone;getchdo;}else{sym=plus;}}elseif(ch=='-'){/*检测-,-=,--符号*/getchdo;if(ch=='='){sym=minuseq;getchdo;}elseif(ch=='-'){sym=minusone;getchdo;}else{sym=minus;}}/*这里之间为添加的内容*/else{sym=ssym[ch];/* 当符号不满足上述条件时,全部按照单字符号处理*///getchdo;//richardif(sym!=period){getchdo;}//end richard}}}}return 0; }○3Statement()增加的内容:(将本来“if(sym==becomes)……”部分的内容修改为处理++,+=,--,-=),并在Statement()中定义变量int sym2;if(sym==becomes||sym==pluseq||sy m==minuseq||sym==plusone||sym==minusone){sym2=sym;getsymdo;gendo(lod,lev-table[i].level,tab le[i].adr);}else{error(13);}if(sym2==plusone||sym2==minusone )/* 准备按照a++、a--语句处理,与read类似*/{if(i!=0){if(sym2==plusone){gendo(lit,0,1);gendo(opr,0,2);gendo(sto,lev-table[i].level,table[ i].adr);}if(sym2==minusone){gendo(lit,0,1);gendo(opr,0,3);gendo(sto,lev-table[i].level,table[ i].adr);}}}else{memcpy(nxtlev,fsys,sizeof(bool)* symnum);expressiondo(nxtlev,ptx,lev);if(i!=0){if(sym2==becomes)gendo(sto,lev-table[i].level,tab le[i].adr);if(sym2==pluseq){gendo(opr,0,2);gendo(sto,lev-table[i].level,tab le[i].adr);}if(sym2==minuseq){gendo(opr,0,3);gendo(sto,lev-table[i].level,tab le[i].adr);}}}//else}}}4、修改单词:不等号# 改为 <>●PL0.cppinit();移除: ssym['#']=neq;○1在getsym()里增加对<>的识别(在<或<=基础上修改)。
编译原理实验报告
编译方法实验报告实验1:扫描器的设计一、实验目的熟悉并实现一个扫描器(词法分析程序)。
二、实验要求(1) 设计扫描器的有限自动机(识别器);(2) 设计翻译、生成Token的算法(翻译器);(3) 编写代码并上机调试运行通过。
·输入——源程序文件或源程序字符串;·输出——相应的Token序列;关键字表和界符表;符号表和常数表;三、实验步骤流程:初始化;打开用户源程序文件;while (文件未结束){ 读入一行到w[i],i=0;do //处理一行,每次处理一个单词{ 滤空格,直到第一个非空的w[i];i--;s=1; //处理一个单词开始while (s!=0)//拼单词并生成相应Token{act(s); //执行q sif (s>=11 && s<=14)//一个单词处理结束break;i++; //getchar()s=find(s, w[i]);}if (s==0)词法错误;}while (w[i]!=换行符);}关闭用户源程序文件;生成Token文件;输出关键字表;输出Token序列;输出符号表;输出常数表;有限自动机的状态转换图: ed d d+|- -1/+/-+① d ② . ③ d ④ e ⑤ ⑥ d ⑦ d --1/+/-l/d -1/+/--1l ⑧ --1b ⑨ b ⑩ --1--1-其中:d 为数字,l 为字母,b 为界符,-1代表其它符号(如在状态8处遇到了非字母或数字的其它符号,会变换到状态12)。
关键字表和界符表:Program; Begin: End( Var) While, Do:= Repeat+ Until- For* To/ If> Then>= Else==< <=四、 主要数据结构①状态转换矩阵:int aut[10][7]={ 2, 0, 0, 0, 8, 9, 15,2, 3, 5,11, 0, 0, 11,4, 0, 0, 0, 0, 0, 0,4, 0, 5,11, 0, 0, 11,7, 0, 0, 6, 0, 0, 0,7, 0, 0, 0, 0, 0, 0,7, 0, 0,11, 0, 0, 11,8, 0, 0, 0, 8, 0, 12,0, 0, 0, 0, 0, 10, 14,0, 0, 0, 0, 0, 0, 13};12 11 13 14 15②关键字表:char keywords[30][12]={“program”,”begin”,”end”,”var”,”while”,”do”,”repeat”,”until”,”for”,”to”,”if”,”then”,”else”,“;”, ”:”, ”(“, ”)”, ”,”, ”:=”, ”+”, ”-“, ”*”, ”/”,”>”, ”>=”, ”==”, “<”, “<=”};③符号表:char ID[50][12]; //表中存有源程序中的标识符④常数表:float C[20];⑤其它变量:struct token{ int code;int value}; //Token结构struct token tok[100]; //Token数组int s; //当前状态int n,p,m,e,t; //尾数值,指数值,小数位数,指数符号,类型float num; //常数值char w[50]; //源程序缓冲区int i; //源程序指针,当前字符为w[i]char strTOKEN[12]; //当前已经识别出的单词五、实验核心代码int main(int argc, char* argv[]){FILE *fp;int s; //当前状态 *有限自动机中的状态fp=fopen("exa.txt","r");while (!feof(fp)){fgets(w,50,fp);i=0;//*处理一行do{printf("%c ",w[i]); //测试显示每个token的首字母//*处理一个tokenwhile (w[i]==' ') //滤空格i++;if (w[i]>='a' && w[i]<='z') //判定单词类别*是字母(关键字或标识符){ptr=col2; num_map=2;}else if (w[i]>='0' && w[i]<='9') //*是数字(常量的开头){ptr=col1; num_map=4;}else if (strchr(col3[0].str,w[i])==NULL) //*其他字符算为非法字符{printf("非法字符%c\n",w[i]);i++;continue;}else //界符{ptr=col3; num_map=1;}i--; //*向后退一个字符s=1; //开始处理一个单词while (s!=0){act(s);if (s>=11 && s<=14) //*判断是否是终止状态 *是终止状态,则形成一个tokenbreak;i++; //getchar() *读取下一个字符s=find(s,w[i]); //状态转换}if (s==0){strTOKEN[i_str]='\0';printf("词法错误:%s\n",strTOKEN);}}while (w[i]!=10);}printf("关键字表:"); //输出结果for (i=0;i<30;i++)printf("%s ",keywords[i]);printf("\n");printf("Token序列:");for (i=0;i<num_token;i++)printf("(%d,%d)",tok[i].code,tok[i].value);printf("\n");printf("符号表:");for (i=0;i<num_ID;i++)printf("%s ",ID[i]);printf("\n");printf("常数表:");for (i=0;i<num_C;i++)printf("%d ",C[i]);printf("\n");fclose(fp);printf("Hello World!\n");return 0;}//*状态转换后,达到新的状态之后,记录的变化void act(int s){int code;switch (s){case 1:n=0;m=0;p=0;t=0;e=1;num=0;i_str=0;strTOKEN[i_str]='\0'; //其它变量初始化break;case 2:n=10*n+w[i]-48;break;case 3:t=1;break;case 4:n=10*n+w[i]-48; m++;break;case 5:t=1;break;case 6:if (w[i]=='-') e=-1;break;case 7:p=10*p+w[i]-48;break;case 8:strTOKEN[i_str++]=w[i]; //将ch中的符号拼接到strTOKEN的尾部;break;case 9:strTOKEN[i_str++]=w[i]; //将ch中的符号拼接到strTOKEN的尾部;break;case 10:strTOKEN[i_str++]=w[i]; //将ch中的符号拼接到strTOKEN的尾部;break;case 11:num=n*pow(10,e*p-m); //计算常数值tok[i_token].code=2; tok[i_token++].value=InsertConst(num); //生成常数Tokennum_token++;break;case 12:strTOKEN[i_str]='\0';code=Reserve(strTOKEN); //查关键字表if (code){ tok[i_token].code=code; tok[i_token++].value=0; } //生成关键字Token else{ tok[i_token].code=1;tok[i_token++].value=InsertID(strTOKEN); } //生成标识符Token num_token++;break;case 13:strTOKEN[i_str]='\0';code=Reserve(strTOKEN); //查界符表if (code){ tok[i_token].code=code; tok[i_token++].value=0; } //生成界符Token else{strTOKEN[strlen(strTOKEN)-1]='\0'; //单界符i--;code=Reserve(strTOKEN); //查界符表tok[i_token].code=code; tok[i_token++].value=0; //生成界符Token }num_token++;break;case 14:strTOKEN[i_str]='\0';code=Reserve(strTOKEN); //查界符表tok[i_token].code=code; tok[i_token++].value=0; //生成界符Token num_token++;break;}}//*状态转换int find(int s,char ch){int i,col=7;struct map *p;p=ptr;for (i=0;i<num_map;i++)if (strchr((p+i)->str,ch)){col=(p+i)->col;break;}return aut[s][col];}//*向常量表中插入常量int InsertConst(double num){int i;for (i=0;i<num_C;i++)if (num==C[i])return i;C[i]= (int)num;num_C++;return i;}int Reserve(char *str){int i;for (i=0;i<num_key;i++)if (!strcmp(keywords[i],str))return (i+3);return 0;}//*向符号表中插入新的符号int InsertID(char *str){int i;for (i=0;i<num_ID;i++)if (!strcmp(ID[i],str)) //*符号已经存在,则返回地址return i;strcpy(ID[i],str);num_ID++;return i;}六、实验结果实验思考题:1.扫描器的任务是什么?答:词法分析程序又称扫描器,任务有:(1) 识别单词——从用户的源程序中把单词分离出来;(2) 翻译单词——把单词转换成机内表示,便于后续处理。
《编译原理》课程实验报告
华东交大理工学院《编译原理》课程实验报告题目:词法分析器实验专业:计算机科学与技术班级:1班学号:* * * *****姓名:* * *一、实验目的通过本实验的编程实践,使学生了解词法分析的任务,掌握词法分析程序设计的原理和构造方法,使学生对编译的基本概念、原理和方法有完整的和清楚的理解,并能正确地、熟练地运用。
二、实验内容及要求用VC++/VB/JA V A语言实现对C语言子集的源程序进行词法分析。
通过输入源程序从左到右对字符串进行扫描和分解,依次输出各个单词的内部编码及单词符号自身值;若遇到错误则显示“Error”,然后跳过错误部分继续显示;同时进行标识符登记符号表的管理。
以下是实现词法分析设计的主要工作:(1)从源程序文件中读入字符。
(2)统计行数和列数用于错误单词的定位。
(3)删除空格类字符,包括回车、制表符空格。
(4)按拼写单词,并用(内码,属性)二元式表示。
(属性值——token的机内表示)(5)如果发现错误则报告出错(6)根据需要是否填写标识符表供以后各阶段使用。
单词的基本分类:关键字:由程序语言定义的具有固定意义的标识符。
也称为保留字例如if、for、while、printf ;单词种别码为1。
标识符:用以表示各种名字,如变量名、数组名、函数名;常数:任何数值常数。
如125, 1,0.5,3.1416;运算符:+、-、*、/;关系运算符:<、<=、= 、>、>=、<>;分界符:;、,、(、)、[、];三、实验程序设计说明1.实验方案设计1、主程序设计考虑:程序的说明部分为各种表格和变量安排空间。
在具体实现时,将各类单词设计成结构和长度均相同的形式,较短的关键字后面补空。
k数组------关键字表,每个数组元素存放一个关键字(事先构造好关键字表)。
s 数组------存放分界符表(可事先构造好分界符表)。
为了简单起见,分界符、算术运算符和关系运算符都放在s表中(编程时,应建立算术运算符表和关系运算符表,并且各有类号),合并成一类。
编译原理实验报告
编译原理实验报告一、实验目的本次实验的目的是了解编译原理的基本知识,并运用所学知识实现一个简单的词法分析器。
二、实验内容1.设计一个词法分析器,能够识别并输出源程序中的关键字、标识符、常数和运算符等。
2.设计并实现一个词法分析器的算法。
3.对编写的词法分析器进行测试。
三、实验过程1.设计词法分析器的算法在设计词法分析器的时候,需要先了解源程序的基本构成,了解关键字、标识符、常数和运算符等的特点,以及它们在源程序中的表示形式。
然后,根据这些特点,设计一个适合的算法来进行词法分析。
2.实现词法分析器根据设计好的算法,在编程语言中实现词法分析器。
在实现过程中,需要根据不同的词法单元,设计相应的正则表达式来进行匹配和识别。
3.测试词法分析器编写几个简单的测试用例,对词法分析器进行测试。
检查输出结果是否正确,并根据实际情况对词法分析器进行调试和优化。
四、实验结果经过测试,词法分析器能够正确识别并输出源程序中的关键字、标识符、常数和运算符等。
测试用例的输出结果与预期结果一致。
五、实验总结通过本次实验,我学习了编译原理的基本知识,掌握了词法分析器的设计和实现方法。
在实验过程中,我遇到了一些困难和问题,但通过仔细思考和查阅文献资料,最终成功地完成了实验任务。
这次实验不仅帮助我巩固了所学知识,还提高了我的编程能力和解决问题的能力。
通过实践,我深刻体会到了编译原理在软件开发中的重要性和作用,并对将来的学习和工作有了更好的规划和方向。
通过本次实验,我对编译原理的相关知识有了更深入的理解和掌握,对词法分析器的设计和实现方法有了更加清晰的认识。
同时,我还学会了如何进行实验报告的撰写,提高了我的文档写作能力。
通过本次实验,我不仅实现了实验的目标,还提高了自己的综合素质和能力。
编译原理实验报告
实验一词法分析一、实验目的通过设计、编写和调试词法分析程序,了解词法分析程序的作用,组成结构,不同种类单词的识别方法,掌握由单词的词法规则出发,画出识别单词的状态转换图,然后在用程序实现词法分析程序设计方法。
二、词法规则1、注释用{和}括起来。
注释体中不能有{。
注释可以出现在任何记号的后面。
2、记号间的空格可有可无,但关键字前后必须有空格、换行、程序的开头或者结尾的原点。
3、标识符的记号id 与以字母开头的字母数字串相匹配:Letter->[a-zA-Z]Digit->[0-9]Id->letter (letter | digit)*4、记号num与无符号整数相匹配:Digits->digit digit*Optional_fraction -> . Digits | ɛOptional_exponent->(E(+ | - | ɛ ) digits) | ɛNum ->digits optional_fraction optional_exponent5、关键字要被保留且在文法中以黑体出现6、关系运算符(relop)指:=、<、<>、<=、>=、>7、Addop: + 、 - 、or8、Mulop:*、/ 、div、mod、and9、Assignop: :=三、词法分析程序详细设计及判别状态图1、无符号数(可带小数和指数)的状态转换图:2、标识符/关键字的状态转换图:字母或数程序详细设计:四、开发环境本程序在Microsoft Visual C++ 6.0环境中编写,无特殊编译要求。
五、函数清单void LexcialAnalysis(FILE *fp);//词法分析主函数int JudgeFirstLetter(char ch);//判断单词的第一个字符int IsDigit(char ch);//判断是否为数字int IsLetter(char ch);//判断是否为字母int IsSpecialPunc(char ch);//判断是否为特殊标点void RecogDigit(char StrLine[]);//用状态图识别无符号数字void RecogIdentifier(char strLine[]);//用状态图识别标识符void RecogPunc(char strLine[]);//识别特殊标点int IsKeyWord(string str);//判断标识符是否为关键字void error();//出错处理六、测试程序program example(input, output);{comments goes here!}var x, y: integer;function gcd(a, b: integer): integer;beginif b =1.2e3 then gcd := aelse gcd := gcd(b, a mod b)end;beginread(x, y);write(gcd(x, y));end.七、运行效果八、实验总结通过这次编译器词法分析程序的编写,我更好地了解了词法分析的作用及工作原理,讲课本中的知识融入到程序编写过程中,理论结合了实际。
编译原理课设实验报告
《编译技术》课程设计报告实验名称编译器设计学号班级本课设的任务是达成一个完好的编译器,办理用户提交的切合所定文法的源程序代码,生成四元式中间代码,从而翻译成等价的X86 平台上汇编语言的目标程序。
编译程序的工作过程区分为以下 5 个过程:词法剖析,语法剖析,语义剖析和中间代码生成,代码优化,目标代码生成。
此中,词法剖析阶段的基本任务是从以字符串表示的源程序中辨别出拥有独立意义的单词符号,并以二元组的形式输出,以作为语法剖析阶段的输入。
语法剖析阶段的基本任务是将词法剖析阶段产生的二元组作为输入,依据语言的语法例则,辨别出各样语法成分,并判断该单词符号序列是不是该语言的一个句子。
语义剖析的任务是第一对每种语法单位进行静态的语义审察,而后剖析其含义,并用另一种语言形式(本课设采纳四元式 ) 来描绘这类语义。
代码优化的任务是对前阶段产生的中间代码进行等价变换或改造,以期获取更为高效即省时间和空间的目标代码。
目标代码生成的任务是将中间代码变换成特定机器上的绝对指令代码或可重定位的指令代码或汇编指令代码(本课设生成汇编指令代码)。
在词法剖析阶段,经过 DOS环境手动输入字符串序列(以’#’作为结束标记)作为带剖析的源程序,调用词法扫描子程序将字符串以二元组的形式输出(如有不属于该语言单词符号出现,则进行犯错办理),词法扫描子程序包含了对源程序的预办理(忽视多余空格、回车换行符等空白字符),以及对单词的辨别和分类,以形成(单词种别,单词自己的值)形式的二元组,并将用户自定义变量信息存入程序变量信息表。
在语法剖析阶段,采纳自上而下的递归降落剖析法,从文法的开始符号出发,依据文法例则正向推导出给定句子。
依据递归降落剖析函数编写规则来编写相应的函数,在各个函数的剖析过程中调用词法剖析程序中的扫描程序,发出“取下一个单词符号”的命令,以获得下一个单词符号作语法剖析。
单词符号词语字符法法字符串表示的源程序分分析析器器取一下个单词符号在语义剖析和中间代码生成阶段,采纳语法制导翻译法,使用属性文法为工具来描绘程序设计语言的语义。
编译原理教程实验报告
一、实验目的本次实验旨在使学生通过编译原理的学习,了解编译程序的设计原理及实现技术,掌握编译程序的各个阶段,并能将所学知识应用于实际编程中。
二、实验内容1. 词法分析2. 语法分析3. 语义分析4. 中间代码生成5. 代码优化6. 目标代码生成三、实验步骤1. 词法分析(1)设计词法分析器,识别输入源代码中的各种词法单元;(2)使用C语言实现词法分析器,并进行测试。
2. 语法分析(1)根据文法规则设计语法分析器,识别输入源代码的语法结构;(2)使用C语言实现语法分析器,并进行测试。
3. 语义分析(1)设计语义分析器,检查语法分析后的语法树,确保语义正确;(2)使用C语言实现语义分析器,并进行测试。
4. 中间代码生成(1)设计中间代码生成器,将语义分析后的语法树转换为中间代码;(2)使用C语言实现中间代码生成器,并进行测试。
5. 代码优化(1)设计代码优化器,对中间代码进行优化,提高程序性能;(2)使用C语言实现代码优化器,并进行测试。
6. 目标代码生成(1)设计目标代码生成器,将优化后的中间代码转换为特定目标机的汇编语言;(2)使用C语言实现目标代码生成器,并进行测试。
四、实验结果与分析1. 词法分析实验结果:成功识别输入源代码中的各种词法单元,包括标识符、关键字、运算符、常量等。
2. 语法分析实验结果:成功识别输入源代码的语法结构,包括表达式、语句、程序等。
3. 语义分析实验结果:成功检查语法分析后的语法树,确保语义正确。
4. 中间代码生成实验结果:成功将语义分析后的语法树转换为中间代码,为后续优化和目标代码生成提供基础。
5. 代码优化实验结果:成功对中间代码进行优化,提高程序性能。
6. 目标代码生成实验结果:成功将优化后的中间代码转换为特定目标机的汇编语言,为程序在目标机上运行做准备。
五、实验心得1. 编译原理是一门理论与实践相结合的课程,通过本次实验,我对编译程序的设计原理及实现技术有了更深入的了解。
编译原理实验报告(一)
编译原理实验报告(一)一、实验题目:简单词法分析器的设计二、实验目的:熟悉并实现一个简单的扫描器三、实验内容:1.设计扫描器的自动机;2.设计翻译、生成Token的算法;3.编写代码并上机调试运行通过。
要求:输入——源程序文件;输出——(1)相应的Token序列;(2)关键字、界符表,符号表,常数表。
四、扫描器设计:自动机:关键字表和界符表单词编码program 3procedure 4④-begin 5end 6while 7do 8+ 9* 10⑧-:11:= 12⑨-= 13,14;15五、概要设计:(1)各模块概要设计1.判断当前读入的字符是字母还是数字int IsLetter(char ch) //判断ch是否为字母 { if (ch是A~Z或a~z) return 1;else return 0;}int IsDigit(char ch) //判断ch是否为数字{ if (ch是0~9) return 1;else return 0;}2.将读入的字符连接成单词或数while (IsLetter(ch)||IsDigit(ch)){ Concat(); //将ch中的字符拼接到strToken中ch=GetChar();}3.查表判断当前的独立串是关键字、标示符还是常数4.求出当前的独立串的code 和value(2)程序说明:1、关键字表、界符表和常数表中初始化后都有元素,即都不是空表。
而符号表则是空的。
它用来存放用户自己定义的变量名,按输入的被识别串中的顺序依次标识其value的值的1,2,3,……,n。
2、value=-1用来标识它是一个关键字;value=1用来标识它是一个界符常数的code值一定为2六、程序源代码及注释:#include "stdio.h"#include "string.h"#define N 15struct TokenType{ int code,value; };char*keywords[]={"program","procedure","begin","end","while","do","+","*",":",":=","=",",",";","(",")",}; //关键字表、界符表char ID[10][10]; //符号表int m;int Cons[10]; //常数表int n;void print(struct TokenTykpe token) //输出Token{ printf("( %d %d)\n",token.code,token.value);}void ProcError(){ printf("Error! You haven't defined it!");}int IsLetter(char ch) //判断ch是否为字母¸{ if (ch>='A' && ch<='Z' || ch>='a' && ch<='z')return 1; else return 0;}int IsDigit(char ch) //判断ch是否为数字{ if (ch>='0' && ch<='9') return 1;else return 0;}int Reserve(char *strToken) //用strToken中的单词去查关键字表。
广东工业大学编译原理实验报告
实验报告课程名称____ 编译原理__________ 题目名称_ PL/0编译程序的修改扩充_ 学生学院______计算机学院__ 专业班级_______ ________ 学号学生姓名______ ________ 指导教师____ _________ __20年月日一、课内实验要求对PL/0作以下修改扩充:增加单词:保留字ELSE,FOR,TO,DOWNTO,RETURN运算符*=,/=,++,--,&,||,!修改单词:不等号# 改为<>增加条件语句的ELSE子句,要求:写出相关文法,语法图,语义规则。
二、实验环境与工具计算机及操作系统:PC机,Windows2000,WindowsXP程序设计语言:C教学型编译程序:PL/0设计方案概述:源、目标语言,实现工具(平台),运行平台源语言:PASCAL目标语言:假想栈式计算机的汇编语言,可称为类PCODE指令代码实现工具:Visual C++ 6.0运行平台:Windows 7三、设计方案1.结构设计说明(1)PL/0 语言编译器PL/0语言可看成是PASCAL语言的子集,它的编译程序是一个编译解释执行系统。
PL/0的目标程序为假想栈式计算机的汇编语言,与具体计算机无关。
(2)PL/0编译程序的语法分析过程BLOCK是整个编译过程的核心。
这里根据编译程序的总体流程图,来弄清BLOCK 过程在整个编译程序中的作用。
总流程图如下图所示:PL/0 的编译程序采用一趟扫描方式,以语法分析程序为核心,词法分析程序和代码生 成程序都作为一个独立的过程,当语法分析需要读单词时就用词法分析程序,而当语法分析 正确需生成相应的目标代码时,则调用代码生成程序。
此外,用表格管理程序建立变量,常 量和过程标识符的说明与引用之间的信息联系。
用出错处理程序对词法和语法分析遇到的错 误给出在源程序中出错的位置和错误性质。
PL/0语法调用关系图2、主要成分描述○1符号表为了组成一条指令,编译程序必须知道其操作码及其参数(数或地址)。
编译原理实验报告
编译原理实验报告--------总体组装姓名:李楠学号:1030310207任课教师:辛明影指导教师:实验地点:D01实验时间:周二9——10节一、设计思想1.1整体思想描述制作一个简易的编译器,能够对于给出的符合文法规则程序代码能进行词法分析、语法分析、语义分析并最终生成汇编代码。
1.2具体模块的功能实验由四部分组成:①词法分析,②语法分析,③语义分析,④生成汇编语言代码。
1.3实现方案的确定根据试验的步骤与编译器的结构实现分为:1、词法分析,生成源程序的token流,2、语法分析,根据token流生成产生式序列,3、语义分析,根据产生式序列生成中间代码四元式,4、根据四元式序列生成汇编代码。
二、类高级语言2.1文法描述K -> main P procedure L .P -> int D ; P'P -> char D ; P'P -> const G ; P'P -> boolean D ; P'P' -> P P'P' -> epsilonD -> id D'D' -> , id D'D' -> epsilonL -> S L'L' -> ; S L'L' -> epsilonS -> id = ES -> if B then S else SS -> begin ( num ) S endS -> { L }S -> while B do SE -> T E'E' -> + T E'E' -> - T E'E' -> epsilonT -> F T'T' -> * F T'T' -> / F T'T' -> epsilonF -> ( E )F -> idF -> numB -> R B'B' -> & R B'B' -> || R B'R -> ! ZZ -> ( B )Z -> trueZ -> falseZ -> id relop Erelop -> <relop -> <=relop -> ==relop -> !=2.2变量说明变量说明必须在过程体之前(procedure之前)声明支持整形变量的列表形式说明,即:int 变量名,变量名,…….;支持字符型变量的列表形式说明,即:char 变量名,变量名,…….;支持常数字符声明,即const 标识符=数字;支持布尔型变量列表声明,即boolean 变量名,变量名,…….;2.3 过程体部分过程提示由多个不同结构的语句组成的一个语句序列,每个语句之间有分号隔开,每行可以写多个语句,注释用“#”表示2.4顺序结构语句(赋值语句)变量名=算术表达式/字符常数/字符=左右两端类型要匹配2.5选择结构表达式即if 语句,形式为if 条件then 语句其中当条件值为布尔型ture,执行后面的语句大于零的整数时不执行2.6循环结构本语言支持两种循环结构之一为:Begin(常数){语句;语句;….语句}end为无条件循环,无条件循环n次;之二为while 条件do {语句;语句…;}其中当条件值为布尔型ture,大于零的整数时不执行,只有一句时也要写{}2.7算术表达式算术表达式由+,—,*,/,(),变量和常数组成,其中优先级为(),*和/,+和-,并满足左结合律2.8关系表达式支持4 种关系运算,<,==,!=,<=关系表达式如满足时,产生值为随即的大于等于零的数2.9布尔表达式布尔表达式支持&,|| ,!(即与或非运算),并支持布尔型变量和常量(ture,false)参加运算,其中f优先级最高,&,or优先级相同,满足左结合律三、具体实现3.1词法分析a.分类函数的算法:void sort(ch,token){If ch是字母调用识别字母函数;else if(ch=='/')调用识别注释或除号的函数;else if ch是数字调用识别数字函数;else 其他调用识别界符函数;}b.识别标识符算法:void recogId(){将存储字符串的数组变量word置空;do{读下一个字符存入ch;If c是字母或者数字word = word || ch;}while ch不是字母或者数字;If ch 是非法字符输出提示;列计数值-1;else文件指针回退一个字节;列计数值-1;查找单词编码表,判断是否为关键字;if 是关键字建立相应的token节点;else查填符号表;建立相应的token节点;}c.查填符号表算法:repeat{遍历符号表,检查是否有与当前符号匹配的符号If 不存在{在符号表后增添新的符号表节点;将新符号属性存入;写TOKEN表;}else{写TOKEN表;}}3.2语法分析函数自顶向下的语法分析:while(!kinput.equals("$")){kLine=(String)dealStack.peek(); // System.out.println("kLineΪ"+kLine);String dealString=(String)storageTable.get(kLine+" "+kinput);if(dealString.charAt(0)=='S'){dealString=dealString.substring(1);dealStack.push(kinput);dealStack.push(dealString);ods.writeChars("S"+dealString);ods.writeChar(10);tokenStack.push(atoken[0]+" "+atoken[1]);atoken=(String[])tokenset.firstElement();tokenset.removeElementAt(0);kinput=atoken[0];}if(dealString.charAt(0)=='r'){dealString=dealString.substring(1);int dealNum=Integer.parseInt(dealString);String geneString=generationArray[dealNum][1];bw.write("action: "+generationArray[dealNum][2]);bw.newLine();StringTokenizer stempt=new StringTokenizer(geneString);Vector temptvec=new Vector();temptvec.clear();while(stempt.hasMoreTokens())temptvec.addElement(stempt.nextToken());Iterator itv=temptvec.iterator();while(itv.hasNext())while(!temptvec.isEmpty()){ String ch=(String)stElement();temptvec.removeElementAt(temptvec.size()-1);if(ch.equals("epsilon"))break;if(ch.matches("[A-Z]")){dealStack.pop();if(dealStack.peek().equals(ch)){dealStack.pop();}else{dealStack.pop();}}else {dealStack.pop();if(dealStack.peek().equals((String)storageSymbol.get(ch))){dealStack.pop();String tokenbuf=(String)tokenStack.pop();bw.write("token: "+tokenbuf);bw.newLine();}else{dealStack.pop(); }} }kLine=(String)dealStack.peek();geneString=generationArray[dealNum][0];ods.writeChars(generationArray[dealNum][0]+" -> "+generationArray[dealNum][1]);ods.writeChar(10);dealStack.push(geneString);String input=(String)dealStack.peek();if(!atoken[0].equals("$"))dealString=(String)storageTable.get(kLine+" "+input+""+atoken[0]);if(dealString==null){dealString=(String)storageTable.get(kLine+" "+input+" "+"#");}dealStack.push(dealString);} }. 3.3语义分析函数K -> main P procedure L .(1) {backpatch(L.nextlist,nextquad);emit(end, , ,0);}P -> int (2){D.type="int",D.width=4}D ;(3){tablefill(D.list,D.type,D.width)} P'P -> char(4){D.type="char",D.width=2} D ;(5){tablefill(D.list,D.type,D.width)} P'P -> const G ;(6){tablefill(G.place,G.value,)} P'P -> boolean(7){D.type="boolean",D.width=1} D ;(8){tablefill(D.list,D.type,D.width)} P'P' -> P P'P' -> epsilonD -> id (9){while(!D.list.empty()) D.list.pop();D.list.push(id.address)} D'D' -> , id (10){D.list.push(id.address)} D'D' -> epsilonG -> id (11){G.place=id.address}= num (12){G.value=num}L -> S (13){backpatch(s.nextlist,nextquad);} L' (16){L.nextlist=-1}L' -> S (14){backpatch(s.nextlist,nextquad)} L'L' -> epsilonS -> id (18){p_right=lookup();} = E (19){emit(=,E.place, ,p_right)} ;(17){s.nextlist=null;}S -> if B then (45){backpatch(B.turelist,nextquad);C.nextlist=B.falselist;}S else (46){q=nextquad;emit("j", , , );T.nextlist=merge(s.nextlist,q);backpatch(C.nextlist,nextquad);}S (47){s.nextlist=merge(T.nextlist,S.nextlist);}S -> begin ( num )(52){S.counter=num;S.head=nextquad;emit(=,S.counter, ,C);} S (53){emit(-,1,C,C);emit("jz", , ,S.head);backpatch(S.nextlist,nextquad);}endS -> { L } (51){S.nextlist=L.nextlist;}S -> while (48){W.head=nextquad;}B do (49){backpatch(B.turelist,nextquad); U.nextlist=B.falselist;U.head=W.head;}S (50){backpatch(S.nextlist,U.head);emit("j", , ,U.head);S.nextlist=U.nextlist;}E -> T (27){E'.place=T.place;} E'(30){E.place=E'.place;}E' -> + T (28){t=newtempt;emit(+,E'.place,T.place,t);E'.place=t;} E'E' -> - T (29){t=newtempt;emit(-,E'.place,T.place,t);E'.place=t;} E'E' -> epsilonT -> F (23){T'.place=F.place;} T' (26){T.place=T'.place;}T' -> * F (24){t=newtempt;emit(*,T'.place,F.place,t);T'.place=t} T'T' -> / F (25){t=newtempt;emit(/,T'.place,F.place,t);T'.place=t} T'T' -> epsilonF -> ( E ) (21){F.place=E.place;}F -> id (20){p_left=lookup();F.place=p_left;}F -> num (22){t=lookup(num);F.place=t;}B -> R (41){B'.quad=nextquad;B'.turelist=R.turelist;B'.falselist=R.falselist}B'(44){B.turelist=B'.turelist;B.falselist=B'.falselist;}B' -> & R (42){backpatch(B'.turelist,B'.quad);B'.quad=nextquad;B'.turelist=R.turelist;B'.falselist=merge(B'.falselist,R.falselist);} B'B' -> || R (43){backpatch(B'.falselist.B'.quad);B'.quad=nextquad;B'.turelist=merge(B'.turelist,R.turelist);B'.falselist=R.falselist;}B'B'-> epsilonR -> ! Z (40){R.turelist=Z.falselist;R.falselist=Z.turelist;}R -> Z (39){R.turelist=Z.turelist;R.falselist=Z.falselist;}Z -> ( B ) (38){Z.turelist=B.turelist;Z.falselist=B.falselist;}Z -> ture (36){Z.turelist=makelist(nextquad); emit("j", , , );}Z -> false (37){Z.falselist=makelist(nextquad); emit("j", , , );}Z -> id (15){q=id.place;} relop E (35){Z.turelist=makelist(nextquad);Z.falselist=makelist(nextquad+1);emit("j"+relop.place,q,E.place, );emit("j", , , );}relop -> < (31){relop.place="<";}relop -> <= (32){relop.place="<=";}relop -> == (33){relop.place="==";}relop -> != (34){relop.place="!=";}3.4生成汇编代码函数生成汇编代码主要是对四元式的识别分析,根据对四元式可能情况的分析,发现四元式主要是赋值、跳转、比较跳转、乘法、加法这几个操作、于是便对于不同种类的四元式生成不同的汇编序列,并写入汇编文件。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验报告课程名称____ 编译原理__________ 题目名称_ PL/0编译程序的修改扩充_ 学生学院______计算机学院__专业班级_______ ________学号学生姓名______ ________指导教师____ _________ __20 年月日一、课内实验要求对PL/0作以下修改扩充:增加单词:保留字ELSE,FOR,TO,DOWNTO,RETURN运算符*=,/=,++,--,&,||,!修改单词:不等号# 改为<>增加条件语句的ELSE子句,要求:写出相关文法,语法图,语义规则。
二、实验环境与工具计算机及操作系统:PC机,Windows2000,WindowsXP程序设计语言:C教学型编译程序:PL/0设计方案概述:源、目标语言,实现工具(平台),运行平台源语言:PASCAL目标语言:假想栈式计算机的汇编语言,可称为类PCODE指令代码实现工具:Visual C++ 6.0运行平台:Windows 7三、设计方案1.结构设计说明(1)PL/0 语言编译器PL/0语言可看成是PASCAL语言的子集,它的编译程序是一个编译解释执行系统。
PL/0的目标程序为假想栈式计算机的汇编语言,与具体计算机无关。
(2)PL/0编译程序的语法分析过程BLOCK是整个编译过程的核心。
这里根据编译程序的总体流程图,来弄清BLOCK过程在整个编译程序中的作用。
总流程图如下图所示:PL/0语法调用关系图PL/0 的编译程序采用一趟扫描方式,以语法分析程序为核心,词法分析程序和代码生成程序都作为一个独立的过程,当语法分析需要读单词时就用词法分析程序,而当语法分析正确需生成相应的目标代码时,则调用代码生成程序。
此外,用表格管理程序建立变量,常量和过程标识符的说明与引用之间的信息联系。
用出错处理程序对词法和语法分析遇到的错误给出在源程序中出错的位置和错误性质。
(3)各功能模块描述2、主要成分描述○1符号表为了组成一条指令,编译程序必须知道其操作码及其参数(数或地址)。
这些值是由编译程序本身联系到相应标识符上去的。
这种联系是在处理常数、变量和过程说明完成的。
为此,标识符表应包含每一标识符所联系的属性;如果标识符被说明为常数,其属性值为常数值;如果标识符被说明成变量,其属性就是由层次和修正量(偏移量)组成的地址;如果标识符被说明为过程,其属性就是过程的入口地址及层次。
常数的值由程序正文提供,编译的任务就是确定存放该值的地址。
我们选择顺序分配变量和代码的方法;每遇到一个变量说明,就将数据单元的下标加一(PL/0 机中,每个变量占一个存贮单元)。
开始编译一个过程时,要对数据单元的下标dx 赋初值,表示新开辟一个数据区。
dx 的初值为3,因为每个数据区包含三个内部变量RA,DL 和SL。
○2运行时存储组织和管理对于源程序的每一个过程(包括主程序),在被调用时,首先在数据段中开辟三个空间,存放静态链SL、动态链DL和返回地址RA。
静态链记录了定义该过程的直接外过程(或主程序)运行时最新数据段的基地址。
动态链记录调用该过程前正在运行的过程的数据段基址。
返回地址记录了调用该过程时程序运行的断点位置。
对于主程序来说,SL、DL和RA的值均置为0。
静态链的功能是在一个子过程要引用它的直接或间接父过程(这里的父过程是按定义过程时的嵌套情况来定的,而不是按执行时的调用顺序定的)的变量时,可以通过静态链,跳过个数为层差的数据段,找到包含要引用的变量所在的数据段基址,然后通过偏移地址访问它。
在过程返回时,解释程序通过返回地址恢复指令指针的值到调用前的地址,通过当前段基址恢复数据段分配指针,通过动态链恢复局部段基址指针。
实现子过程的返回。
对于主程序来说,解释程序会遇到返回地址为0的情况,这时就认为程序运行结束。
解释程序过程中的base函数的功能,就是用于沿着静态链,向前查找相差指定层数的局部数据段基址。
这在使用sto、lod、stoArr、lodArr等访问局部变量的指令中会经常用到。
类PCODE代码解释执行的部分通过循环和简单的case判断不同的指令,做出相应的动作。
当遇到主程序中的返回指令时,指令指针会指到0位置,把这样一个条件作为终至循环的条件,保证程序运行可以正常的结束。
○3语法分析方法语法分析子程序采用了自顶向下的递归子程序法,语法分析同时也根据程序的语义生成相应三元代码,并提供了出错处理的机制。
语法分析主要由分程序分析过程(BLOCK)、参数变量分析过程(ParaDeclaration)、参数变量处理过程(ParaGetSub)、数组处理过程(ParaGetSub)、常量定义分析过程(ConstDeclaration)、变量定义分析过程(Vardeclaration)、语句分析过程(Statement)、表达式处理过程(Expression)、项处理过程(Term)、因子处理过程(Factor)和条件处理过程(Condition)构成。
这些过程在结构上构成一个嵌套的层次结构。
除此之外,还有出错报告过程(Error)、代码生成过程(Gen)、测试单词合法性及出错恢复过程(Test)、登录名字表过程(Enter)、查询名字表函数(Position)以及列出类PCODE代码过程(Listcode)作过语法分析的辅助过程。
○4中间代码表示目标代码类pcode是一种假想栈式计算机的汇编语言。
四、测试用例1测试所有功能代码:PROGRAM EX01;PROGRAM EX01;VAR A,B,C;BEGINA:=9;B:=6;IF A<>b THENWRITE(A)READ(B);C=A+B*(3+B);WRITE(C)END.截图:五、开发过程和完成情况1.增加单词:保留字ELSE,FOR,STEP,UNTIL,DO,RETURN运算符*=,/=,&,||,!增加5个保留字和5个运算符,合计10个单词。
其中保留字ELSE,FOR,TO,DOWNTO,RETURN 分别对应ELSESYM, FORSYM, STEPSYM, UNTILSYM, RETURNSYM,运算符*= ,/= ,& ,|| ,!对应TIMESBECOMES, SLASHBECOMES, ANDSYM, ORSYM, NOTSYM。
增加保留字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, PROGSYM,ELSESYM, FORSYM, STEPSYM, UNTILSYM, RETURNSYM,TIMESBECOMES, SLASHBECOMES, ANDSYM, ORSYM, NOTSYM} SYMBOL;char *SYMOUT[] = {"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", "PROGSYM","ELSESYM","FORSYM","STEPSYM","UNTILSYM","RETURNSYM","TIMESBECOMES", "SLASHBECOMES", "ANDSYM", "ORSYM", "NOTSYM" };for (CH=' '; CH<='^'; CH++) SSYM[CH]=NUL;strcpy(KWORD[ 1],"BEGIN"); strcpy(KWORD[ 2],"CALL");strcpy(KWORD[ 3],"CONST"); strcpy(KWORD[ 4],"DO");strcpy(KWORD[ 5],"ELSE");strcpy(KWORD[ 6],"END");strcpy(KWORD[ 7],"FOR");strcpy(KWORD[ 8],"IF");strcpy(KWORD[ 9],"ODD"); strcpy(KWORD[ 10],"PROCEDURE");strcpy(KWORD[11],"PROGRAM"); strcpy(KWORD[12],"READ");strcpy(KWORD[13],"RETURN"); strcpy(KWORD[14],"STEP");strcpy(KWORD[15],"THEN"); strcpy(KWORD[16],"UNTIL");strcpy(KWORD[17],"VAR"); strcpy(KWORD[18],"WHILE");strcpy(KWORD[19],"WRITE");WSYM[ 1]=BEGINSYM; WSYM[ 2]=CALLSYM;WSYM[ 3]=CONSTSYM; WSYM[ 4]=DOSYM;WSYM[ 5]=ELSESYM;WSYM[ 6]=ENDSYM;WSYM[ 7]=FORSYM;WSYM[ 8]=IFSYM;WSYM[ 9]=ODDSYM; WSYM[10]=PROCSYM;WSYM[11]=PROGSYM; WSYM[12]=READSYM;WSYM[13]=RETURNSYM;WSYM[14]=STEPSYM; WSYM[15]=THENSYM; WSYM[16]=UNTILSYM;WSYM[17]=VARSYM; WSYM[18]=WHILESYM;WSYM[19]=WRITESYM;SSYM['+']=PLUS; SSYM['-']=MINUS;SSYM['*']=TIMES; SSYM['/']=SLASH;SSYM['(']=LPAREN; SSYM[')']=RPAREN;SSYM['=']=EQL; SSYM[',']=COMMA;SSYM['.']=PERIOD; //SSYM['#']=NEQ; 注释掉SSYM[';']=SEMICOLON; SSYM['&']=ANDSYM;SSYM['!']=NOTSYM;然后在STATEMENT(SYMSET FSYS,int LEV,int &TX)函数中增加:case FORSYM:GetSym();break;case TOSYM:GetSym();break;case DOWNTOSYM:GetSym();break;case RETURNSYM:GetSym();break;增加运算符在GetSym()函数中增加:elseif (CH=='*') {GetCh();if (CH=='=') {SYM=TIMESBECOMES;GetCh();}else SYM=TIMES;}elseif (CH=='/') {GetCh();if (CH=='=') {SYM=SLASHBECOMES;GetCh();}else SYM=SLASH;}elseif (CH=='&') {SYM=ANDSYM;GetCh();}elseif (CH=='|') {GetCh();if (CH=='|') {SYM=ORSYM;GetCh();}else Error(19);}elseif (CH=='!') {SYM=NOTSYM;GetCh();}在void STATEMENT(SYMSET FSYS,int LEV,int &TX){}函数中增加:case TIMESBECOMES:GetSym();Form1->printfs("~~~~ *= ~~~~");break;case SLASHBECOMES:GetSym();Form1->printfs("~~~~ /= ~~~~");break;case ANDSYM:GetSym();Form1->printfs("~~~~ & ~~~~");break;case ORSYM:GetSym();Form1->printfs("~~~~ || ~~~~");break;case NOTSYM:GetSym();Form1->printfs("~~~~ ! ~~~~");break;保留字和单词的个数原保留字个数是14,因为新增加保留字5个,故const NORW = 14;应改为:const NORW = 19;原单词总数是33,因为新增加单词10个,故应将所有的33改为43就行了(Error(33)除外)。