实验 6 简单中间代码生成
中间代码生成实验报告

一、实验目的1. 理解编译原理中中间代码生成的基本概念和作用。
2. 掌握中间代码生成的常用算法和策略。
3. 提高对编译器构造的理解和实际操作能力。
二、实验环境1. 操作系统:Windows 102. 编程语言:Java3. 开发工具:Eclipse三、实验内容1. 中间代码生成的基本概念2. 中间代码的表示方法3. 中间代码生成算法4. 实现一个简单的中间代码生成器四、实验步骤1. 了解中间代码生成的基本概念中间代码生成是编译过程中的一个重要环节,它将源程序转换成一种中间表示形式,便于后续的优化和目标代码生成。
中间代码生成的目的是提高编译器的灵活性和可维护性。
2. 研究中间代码的表示方法中间代码通常采用三地址代码(Three-Address Code,TAC)表示。
TAC是一种低级表示,由三个操作数和一个操作符组成,例如:(t1, t2, t3) = op,其中t1、t2、t3为临时变量,op为操作符。
3. 学习中间代码生成算法中间代码生成算法主要包括以下几种:(1)栈式中间代码生成算法(2)归约栈中间代码生成算法(3)递归下降中间代码生成算法4. 实现一个简单的中间代码生成器本实验采用递归下降中间代码生成算法,以一个简单的算术表达式为例,实现中间代码生成器。
(1)定义语法规则设表达式E由以下语法规则表示:E → E + T | E - T | TT → T F | T / F | FF → (E) | i(2)设计递归下降分析器根据语法规则,设计递归下降分析器,实现以下功能:①识别表达式E②识别项T③识别因子F(3)生成中间代码在递归下降分析器中,针对不同语法规则,生成相应的中间代码。
例如:当遇到表达式E时,生成以下中间代码:(t1, t2, t3) = op1(t1, t2) // op1表示加法或减法(t4, t5, t6) = op2(t4, t5) // op2表示乘法或除法(t7, t8, t9) = op3(t7, t8) // op3表示赋值(4)测试中间代码生成器编写测试用例,验证中间代码生成器的正确性。
中间代码生成实验报告doc

中间代码生成实验报告篇一:编译方法实验报告(中间代码生成器)编译方法实验报告XX年10月一、实验目的熟悉算术表达式的语法分析与中间代码生成原理。
实验内容二、(1)设计语法制导翻译生成表达式的四元式的算法;(2)编写代码并上机调试运行通过。
输入——算术表达式;输出——语法分析结果;相应的四元式序列。
(3)设计LL(1)分析法或LR(0)分析法的属性翻译文法,并根据这些属性翻译文法,使用扩展的语法分析器实现语法制导翻译。
三、实验原理及基本步骤●算术表达式文法:G(E):E ? E ω0 T | TT ? T ω1 F | FF ? i | (E)●文法变换:G’(E) E ? T {ω0 T(本文来自:小草范文网:中间代码生成实验报告)}T ? F {ω1 F}F ? i | (E)●属性翻译文法:E ? T {ω0 “push(SYN, w)” T “QUAT”}T ? F {ω1 “push(SYN, w)” F “QUAT”}F ? i “push(SEM, entry(w))” | (E)其中:push(SYN, w) —当前单词w入算符栈SYN;push(SEM, entry(w)) —当前w在符号表中的入口值压入语义栈SEM;QUAT —生成四元式函数i.T = newtemp;ii.QT[j] =( SYN[k], SEM[s-1], SEM[s], T); j++;iii.pop( SYN, _ ); pop( SEM, _ ); pop( SEM, _ );push( SEM, T );●递归下降子程序:数据结构:SYN —算符栈;SEM —语义栈;四、数据结构设计使用递归的结构进行四元式的设计,同时,运用堆栈结构将四元式的输出序列打印出来while ( exp[i]=='+' || exp[i]=='-'){syn[++i_syn]=exp[i];//push(SYN,w)i++; //read(w)T();quat();}while ( exp[i]=='*' || exp[i]=='/'){syn[++i_syn]=exp[i];//push(SYN,w)i++; //read(w)F();quat();}void quat(){strcpy(qt[j],"(, , , )");//QT[j]:=(SYN[k],SEM[s-1],SEM[s],temp);qt[j][1]=syn[i_syn];qt[j][3]=sem[i_sem-1];qt[j][5]=sem[i_sem];qt[j][7]=temp;j++;i_syn--;//pop(SYN);i_sem--;//pop(SEM);i_sem--;//pop(SEM);sem[++i_sem]=temp; //push(SEM,temp); temp++;}五、关键代码分析(带注释)及运行结果#include#include "string.h"#include "stdio.h"using namespace std;char syn[10]; //文法符号栈int i_syn;char sem[10]; //运算对象栈int i_sem;char exp[50]; //算术表达式区int i;char qt[30][15];//四元式区int j=0;char temp='q'; //临时变量,取值为r--z int E();int T();int F();void quat();//生成四元式函数int main(int argc, char* argv[]){printf("please input your expression:"); scanf("%s",exp); //输入四元式i=0; //read(w)E();if (exp[i]=='\0')for (i=0;i printf("%s\n",qt[i]);elseprintf("err");return 0;}int E(){T();while ( exp[i]=='+' || exp[i]=='-'){syn[++i_syn]=exp[i];//push(SYN,w)i++; //read(w)T();quat();}return 1;}int T(){F();while ( exp[i]=='*' || exp[i]=='/'){syn[++i_syn]=exp[i];//push(SYN,w)i++; //read(w)F();quat();}return 1;}int F(){if ( exp[i]=='('){i++; //read(w)E();if ( exp[i]!=')'){printf("err");return 0;}}else if ((exp[i]>='a' && exp[i]='0' && exp[i] sem[++i_sem]=exp[i]; } //push(SEM,w)else{printf("err");return 0;}i++; //read(w)return 1;}void quat(){strcpy(qt[j],"( , , , )");//QT[j]:=(SYN[k],SEM[s-1] ,SEM[s],temp);qt[j][1]=syn[i_syn];qt[j][3]=sem[i_sem-1];qt[j][5]=sem[i_sem];qt[j][7]=temp;j++;i_syn--; //pop(SYN);i_sem--; //pop(SEM);i_sem--; //pop(SEM);sem[++i_sem]=temp;//push(SEM,temp);temp++;}篇二:中间代码生成实验报告一、实验目的通过在实验二的基础上,增加中间代码生成部分,使程序能够对实验二中的识别出的赋值语句,if语句和while语句进行语义分析,生成四元式中间代码。
编写中间代码生成程序

武夷学院实验报告课程名称:编译原理项目名称:编写中间代码生成程序二、实验过程记录1:(一)实验目的:在分析理解PL/0编译程序的基础上,对其词法分析程序、语法分析程序和语义处理程序进行部分修改扩充。
(二)实验内容:对PL/0语言作如下功能扩充:(1)扩充条件语句的功能使其为:if <条件> then <语句>[else <语句>](2)增加repeat语句,格式为:repeat <语句> {; <语句>} until <条件>(三)实验过程语句语法描述图:1注:实验过程记录要包含实验目的、实验原理、实验步骤,页码不够可自行添加。
EBNF表示:<程序>::= <分程序>.<分程序>::= [<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句> <常量说明部分>::= const<常量定义>{,<常量定义>};<常量定义>::= <标识符>=<无符号整数><无符号整数>::= <数字>{<数字>}<标识符>::= <字母>{<字母>|<数字>}<变量说明部分>::= var<标识符>{, <标识符>};<过程说明部分>::= <过程首部><分程序>{;<过程说明部分>}<过程首部>::= procedure<标识符>;<语句> ::= <赋值语句>|<条件语句>|<当循环语句>|<过程调用语句><复合语句>|<读语句>|<写语句>|<空><赋值语句>::= <标识符> := <表达式><表达式> ::= [+|-]<项>{<加法运算符><项>}<项>::= <因子>{<乘法运算符><因子>}<因子>::= <标识符>|<无符号整数>| ‘ ( ’ <表达式> ‘ ) ’<加法运算符>::= +|-<乘法运算符>::= *|/<条件>::= <表达式><关系运算符><表达式>|odd<表达式>程序描述图:三、实验结果与讨论:2实验结果:实验小结:通过在PL/0的编译程序的实验中,认识了许多关于中间代码生成的知识,掌握了中间代码中的作用所谓“中间代码”是一种结构简单、含义明确的记号系统,这种记号系统复杂性介于源程序语言和机器语言之间,容易将它翻译成目标代码,产生中间代码的过程叫中间代码生成。
第6章 中间代码生成

S.c.x的中间代码:(+,S,0,t8)
(+,t8,0,t9) 假设Level(R)=2,Offset(R)=5,则有Level(S)=2, Offset(S)=7。 Arg(R)= AddrForm(2,5,dir), Arg(S)=AddrForm(2,7,dir),t8=AddrForm(-1,100, indir),t9=AddrForm(-1,101, indir)。
else C=B+5; write(2*(C-1))
1.(READI,A) 8.(LABEL,L1)
2.(READI,B)
3.(GT,A,B,t1) 4.(JUMP0,t1,L1)
9.(ADDI,addr(B),5,t3)
10.(ASSIG,t3,addr(C)) 11.(LABEL,L2)
பைடு நூலகம்
5.(ADDI,addr(A),5,t2) 12.(SUBI,addr(C),1,t4) 6.(ASSIG,t2,addr(C)) 13.(MULTI,2,t4,t5) 7.(JUMP,L2) 14.(WRITEI,t5)
(1)(MULTI,addr(b),addr(c),t1) (2)(FLOAT,addr(b),t2) (3)(MULTF,t2,addr(d),t3) (4)(FLOAT,t1,t4) (5)(ADDF,t4,t3,t5) (6)(=,t5,addr(a))
18/62
例如: read(A); read(B); if A>B then C=A+5
21/62
Level— 临时变量时取负, 源程序变量时取正; Offset — 临时变量时表 示编号,其他情形表示 偏移量;
中间代码生成实验报告

一、实验目的通过在实验二的基础上,增加中间代码生成部分,使程序能够对实验二中的识别出的赋值语句,if语句和while语句进行语义分析,生成四元式中间代码。
二、实验方法实验程序由c语言完成,在Turboc 2.0环境中调试通过。
语义分析程序的基本做法是对文法中的每个产生式分别编写一个语义分析子程序,当程序语法部分进行推倒或规约时,就分别调用各自的语义分析程序。
当语法分析结束时,语义分析也就结束了。
在本实验程序中,当语法分析部分识别出语法正确的句子时,就进入content函数(当语法分析识别出不正确的句子时,不进入content函数,也就是不进行语义分析),然后根据句子的类型进行分类,进入不同的语义处理部分。
对于赋值语句,关键是产生正确的处理算术表达式E的四元式。
程序中的ec函数的功能就是产生算术表达式的四元式,在ec函数中使用了两个栈idshed,opshed,分别是算术表达式的数据栈和符号栈。
每次提取一个数字和一个算符,然后将算符与与栈顶算符进行优先级比较,优先级高则将单前数字和算符进栈,低或者相等的话则将当前栈顶元素进行合并,产生四元式。
直至整个算术表达式结束。
其中还有一些细节问题,具体的做法可以参看程序。
对于实验给定的if语句的文法格式,条件判断式C只中可能是>或者<=两种关系,不可能是布尔表达式,这样程序就简单的多了。
通过ec函数可以产生条件判断式C中的E的四元式,然后只要加上转向四元式就可以了。
本实验程序中只给出真出口的转向四元式,没有给出假出口的转向四元式,这在实际中是不可以的,但在本实验中,实际上是对每条独立的语句进行语法分析,给出假出口转向四元式实际上意义不大,而且假出口转向语句的转移目标必须要到整个语句分析结束以后才可以知道,这样就要建立栈,然后回填,这样会使程序复杂很多,所以没有加上假出口转向四元式。
对于while语句,具体的做法和if语句差不多,所不同的是当while语句结束时,要多出一条无条件转向四元式,重新转到条件判断式C的第一条四元式。
中间代码生成实验报告

中间代码生成实验报告《中间代码生成实验报告》摘要:本实验旨在通过编写中间代码生成程序,实现将高级语言源代码转换为中间代码的功能。
通过实验,我们掌握了中间代码的生成过程和相关算法,并对编译器的工作原理有了更深入的理解。
本实验采用了C语言作为源语言,通过词法分析、语法分析和语义分析,生成了对应的中间代码。
一、实验目的1. 理解编译器的工作原理,掌握中间代码生成的基本概念和方法;2. 掌握中间代码的表示方法和生成算法;3. 通过实践,提高编程能力和对编译原理的理解。
二、实验环境1. 操作系统:Windows 10;2. 编程语言:C语言;3. 开发工具:Visual Studio 2019。
三、实验内容1. 设计并实现中间代码生成程序,将给定的C语言源代码转换为中间代码;2. 实现词法分析、语法分析和语义分析,生成对应的中间代码;3. 测试程序,验证中间代码的正确性和有效性。
四、实验步骤1. 设计中间代码的表示方法,包括四元式、三地址码等;2. 实现词法分析器,将源代码转换为词法单元序列;3. 实现语法分析器,将词法单元序列转换为语法树;4. 实现语义分析器,对语法树进行语义检查并生成中间代码;5. 测试程序,验证中间代码的正确性和有效性。
五、实验结果经过测试,中间代码生成程序能够正确地将C语言源代码转换为中间代码,并且生成的中间代码能够正确地表达源代码的语义和逻辑结构。
通过实验,我们成功地掌握了中间代码的生成过程和相关算法,加深了对编译器工作原理的理解。
六、实验总结通过本次实验,我们深入了解了编译器的工作原理和中间代码生成的基本概念和方法。
通过实践,我们提高了编程能力和对编译原理的理解,为进一步深入学习编译原理和设计编译器打下了良好的基础。
希望通过不断的实践和学习,能够更加熟练地掌握编译原理的知识,为今后的学习和工作打下坚实的基础。
中间代码生成

• •
6.1.2 后缀表示法 后缀表示是一个语法树的线性化表示。 它是树的结点直接出现在它的子结点之 后。 • 逆波兰表示法是波兰逻辑学家卢卡西 维奇(Lukasiewicz)发明的一种表示表达 式的方法,这种表示法把运算量(操作数) 写在前面,把运算符写在后面,因而又 称后缀表示法。例如,把a+b写成ab+, 把a*(b+c)写成abc+*。
中间代码生成
•
所谓中间代码,是指用中间语言改写了的程序。 当编写一个含有一遍以上扫描的编译程序,则中间 语言就已存在了。我们使用它作为编译程序的遍 与遍之间源文本载体,即作为前一遍的输出及其 随后一遍的输入。 首先,在词法分析之后有一个源文本,它是经过词 法分析处理后的源文本。词法分析程序把标识符、 变量以及语言保留字等长度不等的符号,替换为带 有不同标识的定长符号。因此,在词法分析之后, 源文本可以由一系列定长符号组成,其最简单形 式就是整数,其中某些整数对应于语言字,而其他 表示指向标识符表或常量表的指针,等等。所以, 我们这里所说的中间代码,是在分析阶段最后一遍 产生的中间语言类型。它更接近于机器代码,尽 管它本身与机器无关。
•
其中,t1和t2是编译时产生的临时变量。 三地址代码是语法树的一种线性表示, 如图8–4(a)所示的语法树用三地址代码 表示为: • t1=b*c • t2= a− t1 • x=t2
• 2.三地址语句的种类 • 作为中间语言的三地址语句非常类似 于汇编代码,它可以有符号标号和各种 控制流语句。常用的三地址语句有以下 几种: • (1) x=y op z形式的赋值语句,其中op 为二目的算术运算符或逻辑运算符。 • (2) x=op y形式的赋值语句,其中op为 一目运算符,如一目减uminus、逻辑否 定not、移位运算符以及将定点数转换成 浮点数的类型转换符。
编译原理6 语义分析和中间代码生成

波兰逻辑学家卢卡西维奇(Lukasiewicz)发明的 一种表示法。 概念 一般,若e1,e2为任意的后缀表达式,Θ 为任意 双目运算符,则用Θ作用于e1和e2所代表的结果 用后缀式e1e2 Θ表示。 推而广之, Θ 为k目运算符,则Θ作用于e1e2„ek 的结果用e1e2„ek Θ来表示。
If e then x else y
e p1 jez x p2 jump p1:y p2:
在数组POST中出现的后缀式
e x y
p1 下标 数组 e p1 jez x p2 jump y
p2
符号表
后跟冒号的p1,p2实际上并不存储
产生式所带的语义动作,由以下模式描述。
E E(1)op E(2)
引入标号,在后缀式中加入条件转移,无条件转 移算符。
存储方式 后缀式存放在一维数组POST[1..N]中,每个元素 是运算符或者分量(指向符号表)。
转移算符
p jump 转到POST[p] e1e2pjlt e1<e2时,转到POST[p]
e p jez 若e=0,转到POST[p]
T.val=4 F.val=4 F.val=5 digit.lexval=4 digit.lexval=5
T.val=15 T.val=3 F.val=3 digit.lexval=3
*
3*5+4的带注释的分析树
例2 继承属性的例子
产 生式 D TL T int T real L L1,id L id 语 义 规 则 L.in:=T.type T.type=integer T.type:=real L1.in:=L.in addtype(id.entry,L.in) addtype(id.entry,L.in)
编译原理中间代码生成实验报告

竭诚为您提供优质文档/双击可除编译原理中间代码生成实验报告篇一:编译原理-分析中间代码生成程序实验报告课程名称编译原理实验学期至学年第学期学生所在系部年级专业班级学生姓名学号任课教师实验成绩计算机学院制开课实验室:年月日篇二:编译原理实验中间代码生成实验四中间代码生成一.实验目的:掌握中间代码的四种形式(逆波兰式、语法树、三元式、四元式)。
二.实验内容:1、逆波兰式定义:将运算对象写在前面,而把运算符号写在后面。
用这种表示法表示的表达式也称做后缀式。
2、抽象(语法)树:运算对象作为叶子结点,运算符作为内部结点。
3、三元式:形式序号:(op,arg1,arg2)4、四元式:形式(op,arg1,arg2,result)三、以逆波兰式为例的实验设计思想及算法(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
(2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。
(3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。
(4)如果不是数字,该字符则是运算符,此时需比较优先关系。
做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。
如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。
倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。
(5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。
四、程序代码://这是一个由中缀式生成后缀式的程序#include#include#include#include#definemaxbuffer64voidmain(){chardisplay_out(charout_ch[maxbuffer],charch[32]);//intcaculate_array(charout_ch[32]);staticinti=0;staticintj=0;charch[maxbuffer],s[maxbuffer],out[maxbuffer];cout cin>>ch;for(i=0;i {out[i]=ch[i];}cout while(out[j]!=#)cout j++;}cout display_out(s,out);//caculate_array;}chardisplay_out(charout_ch[32],charch[]) {inttop=-1;inti=0,data[maxbuffer],n;intj=0;charsta[20];while(ch[i]!=#){if(isalnum(ch[i])){while(isalnum(ch[i])){out_ch[j]=ch[i];j++;i++;}out_ch[j]=;j++;else{switch(ch[i]){case+:case-:if(sta[top]==(||top==-1) {top++;sta[top]=ch[i];i++;}else{//j--;out_ch[j]=sta[top];j++;top--;//i++;}break;//break;case*:case/:if(sta[top]==*/) {out_ch[j]=sta[top];j++;//i++;top--;}else{top++;sta[top]=ch[i];i++;}break;//break;case(:top++;sta[top]=ch[i];i++;break;case):if(sta[top]==() {top--;i++;}if(top==-1){//cout }else{//while(sta[top]!=?(?){ out_ch[j]=sta[top];top--;j++;//}break;}break;/*case?#?:out_ch[j]=?#?; j++;break;*/default:cout ch[i]=#;j=0;break;}}}while(top!=-1){out_ch[j]=sta[top];j++;top--;}out_ch[j]=#;n=0;co(:编译原理中间代码生成实验报告)utwhile(out_ch[n]!=#){cout n++;}cout j=0;returnout_ch[maxbuffer];}五、实验结果:要求:自己给出3个测试用例,观察结果。
最新第六章-中间代码生成教学讲义ppt课件

第六章:中间代码生成
❖ 编译器分析综合模型
前端:源程序=》中间代码 (和源语言相关细节)
后端:中间代码=》目标代码 (和目标语言相关细节)
❖ 本章内容
中间代码表示
静态类型检查
中间代码生成
❖ 如何实现?描述用SDD、实现用SDT
所有翻译方案都可以通过生成并遍历抽象语法树来实现
临时名字在生成时一定要被写入符号表
❖ 图6-10:三地址代码及其四元式表示
10
6.2 三地址代码
❖ 三地址语句的实现
三元式
❖ 为了避免临时名字在生成时被写入符号表中,可以通过计算临 时值的语句的位置来引用它
❖ 带有三个域的记录结构:op,arg1,arg2
arg1,arg2指向符号表(对于程序员定义的名字或常量)的指针 或者三元组结构(对于临时变量)的指针
三地址码
❖ 可高可低(通过选择不同的运算符)
高级语言,如C语言
❖C语言灵活通用、可编译成高效机器代码
3
6.2 三地址代码(6.2)
❖ 三地址代码的一般形式
x = y op z 三地址代码是抽象语法树或DAG的线性表示
❖ 图6-8:一个DAG及其对应的三地址代码
7
6.2 三地址代码
❖ 三地址语句的类型(通用)
x = y op z
x = op y
x = y
goto L
if x goto L
if x relop y goto L
x = y[i],x[i] =y
x = &y,x = *y,*x := y
p(x1,x2…xn)
❖ param x1;param x2;…;param xn;
编译原理语义分析与中间代码生成实验报告

编译原理语义分析与中间代码生成实验报告专题6_语法制导翻译程序设计原理与实现技术***-***** 李若森计科1301一、实验目的语法制导的基本概念;目标代码结构分析的基本方法;赋值语句语法制导生成四元式的基本原理和方法;该过程包括语法分析和语义分析过程。
二、实验内容2.1 实验项目完成以下描述赋值语句和算术表达式文法的语法制导生成中间代码四元式的过程。
G[A]:A→V=EE→E+T|E-T|T T→T*F|T/F|F F→(E)|i V→i2.2 设计说明终结符号i为用户定义的简单变量,即标识符的定义。
2.3 设计要求(1) 设计语法制导翻译过程,给出每一产生式对应的语义动作;(2) 设计中间代码四元式的结构(暂不与符号表有关);(3) 输入串应是词法分析的输出二元式序列,即某算术表达式“专题1”的输出结果。
输出为输入串的四元式序列中间文件;(4) 设计两个测试用例(尽可能完备),并给出程序执行结果。
2.4 任务分析重点解决赋值语句文法的改写和语义动作的添加。
三、实现过程3.1 扩展文法G[s]:S→AA→V=EE→E+T|E-T|T T→T*F|T/F|F F→(E)|i V→i3.2 非终结符FOLLOW集FOLLOW(S) = { # } FOLLOW(A) = { # } FOLLOW(V) = { = }FOLLOW(E) = { +, -, ), # }FOLLOW(T) = { +, -, *, /, ), # } FOLLOW(F) = { +, -, *, /, ), # }3.3 LR(0)分析器的构造设DFA M的一个状态为i,该状态识别出的所有活前缀的有效项目集为Ci。
则DFA M的状态集Q={C0, C1, C2, … , Cn}=C。
C称为文法的LR(0)有效项目集规范族。
对Ci有三种操作:求文法的LR(0)有效项目集规范族C的算法:由上述算法可求得有效项目集规范族C={C0, C1, C2, … , C19}。
实验 6 简单中间代码生成

实验 6 简单中间代码生成1、实验目的:综合运用所学知识,集成词法分析、符号表管理等程序的成果,在语法分析和文法属性计算的基础上,完成中间代码的生成工作。
让学生全面了解一个编译器工作的全过程,真正全面掌握编译的思想和方法。
2、实验的基本原理对于一个给定文法,通过改写文法,使其满足LR(1)文法的要求,根据语义确定文法符号的属性,确定语义规则或翻译方案;根据文法特点构造LR(1)分析表,进而构造语法分析和属性计算程序。
分析程序在分析表的驱动下,完成对给定的句子进行语法分析和属性计算工作,最后生成三地址中间代码序列。
3、实验内容及要求a.实验所用文法如下。
statmt → id = expexp → exp addop term | termaddop →+ | -term→ term mulop factor | factormulop → * | /factor → ( exp ) | id | num其中id和num为实验二中定义的标识符和常数,因此这里还需要一个小的词法分析器来得到id和num。
b.构造文法LR(1)项目集,构造ACTION和GOTO矩阵,确认文法满足LR(1)文法要求。
c.按一般高级语言赋值语句的计算要求定义文法的属性和语义规则,属性计算的结果是将给定赋值语句翻译成三地址代码序列,并输出此序列。
d.从数据文件中读出赋值语句,并对其进行语法分析,对合法语句,输出其翻译结果。
e.实验数据文件中应该有多个语句,可能有正确的也应该有错误的语句;语句中的表达式有形式简单的也应该有复杂的。
每个表达式写在一行,以$结束。
4、实验步骤准备好用于实验的赋值语句序列,并存储在文件中。
a.编写单词分析子程序,能从源程序中分离出单词(包括标识符和常数);词法分析器以子程序形式出现,当需要进行词法分析时进行调用;b.构造分析表,确认上述文法为LR(1)文法,定义属性和语义规则。
c.确定临时变量生成方案,构造其生成程序。
中间代码生成具体实验过程含代码

实验三中间代码生成学号:;姓名:马小军实验目的1.了解并掌握中间代码的生成过程和作用2.了解并掌握四元式3.体会属性文法在中间代码生成过程中的作用。
实验环境Windows7操作系统vs2010编程环境实验内容从文件中读入表达式,输出其四元式的结果序列本程序只能生成赋值语句及算数表达式中间代码的四元式不能生成逻辑表达式及其他复杂语句中间代码的四元式实验原理三、以逆波兰式为例的实验设计思想及算法(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
(2)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符数字,则分析到该数字串的结束并将该数字存入数组。
(3)如果不是数字,该字符则是运算符,此时需比较优先关系。
做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。
如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。
倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。
(4)重复上述操作(2)-(3)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为四元式。
下面给出算法流程图实验步骤打开并运行软件根据提示输入要分析的源程序(文件目录下有写好的文件源文件1.txt输入即可)运行输出结果例如将以下源文件放入test.txt运行结果a:=b*c+b*d思考同样的思路对算法进行适当改动就可以生成其它形式的中间代码【其他部分】设计原理和算法思想参考《程序设计语言编译原理》第三版国防工业出版社作者陈火旺等附录代码#include<stdlib.h>#include<fstream>#include<iostream>#include<stdio.h>using namespace std;#define MAX 100int m=0,sum=0;//sum用®?于®¨²计?算?运?算?符¤?的Ì?个?数ºy//m用®?于®¨²标À¨º记?输º?入¨?表À¨ª达ä?式º?中D字Á?符¤?的Ì?个?数ºychar JG='A';char str[MAX];//用®?于®¨²存ä?输º?入¨?表À¨ª达ä?式º?int token=0;//左Á¨®括¤¡§号?的Ì?标À¨º志?/***********用®?于®¨²更¨¹改?计?算?后¨®数ºy组Á¨¦中D的Ì?值¦Ì**************/void change(int e){int f=e+2;char ch=str[f];if(ch>='A'&&ch<='Z'){for(int l=0;l<m+10;l++){if(str[l]==ch)str[l]=JG;}}if(str[e]>='A'&&str[e]<='Z'){for(int i=0;i<m;i++){if(str[i]==str[e])str[i]=JG;}}}void chengchuchuli(int i,int m){i++;for( ;i<=m-1;i++)//处ä|理¤¨ª乘?除y运?算?{if(str[i]=='*'||str[i]=='/'){cout<<"("<<str[i]<<" "<<str[i-1]<<" "<<str[i+1]<<" "<<JG<<")"<<endl;change(i-1);str[i-1]=str[i]=str[i+1]=JG;sum--;JG=(char)(int)JG++;}}}void jiajianchuli(int j,int m){j++;for( ;j<=m-1;j++)//处ä|理¤¨ª加¨®减?运?算?{if(str[j]=='+'||str[j]=='-'){cout<<"("<<str[j]<<" "<<str[j-1]<<" "<<str[j+1]<<" "<<JG<<")"<<endl;change(j-1);str[j-1]=str[j]=str[j+1]=JG;sum--;JG=(char)(int)JG++;}}}/*扫¦¡§描¨¨一°?遍À¨¦从䨮文?件t中D读¨¢入¨?表À¨ª达ä?式º?*/void scan(FILE *fin){int p[MAX];char ch='a';int c=-1,q=0;while(ch!=EOF){ch=getc(fin);while(ch==' '||ch=='\n'||ch=='\t') ch=getc(fin);//消?除y空?格?和¨ª换?行D 符¤?str[m++]=ch;if(ch=='='||ch=='+'||ch=='-'||ch=='*'||ch=='/') sum++;else if(ch=='('){p[++c]=m-1;}else if(ch==')'){q=m-1;chengchuchuli(p[c],q);//从䨮左Á¨®括¤¡§号?处ä|理¤¨ª到Ì?又®?括¤¡§号?jiajianchuli(p[c],q);JG=(char)(int)JG--;str[p[c]]=str[m-1]=JG;c--;JG=(char)(int)JG++;}}}void sanyuanshi(){for(int i=0;i<=m-1;i++)//处ä|理¤¨ª乘?除y运?算?{if(str[i]=='*'||str[i]=='/'){cout<<"("<<str[i]<<" "<<str[i-1]<<" "<<str[i+1]<<" "<<JG<<")"<<endl;change(i-1);str[i-1]=str[i]=str[i+1]=JG;sum--;JG=(char)(int)JG++;}}for(int j=0;j<=m-1;j++)//处ä|理¤¨ª加¨®减?运?算?{if(str[j]=='+'||str[j]=='-'){cout<<"("<<str[j]<<" "<<str[j-1]<<" "<<str[j+1]<<" "<<JG<<")"<<endl;change(j-1);str[j-1]=str[j]=str[j+1]=JG;sum--;JG=(char)(int)JG++;}}for(int k=0;k<=m-1;k++)//处ä|理¤¨ª赋3值¦Ì运?算?{if(str[k]=='='){JG=(char)(int)--JG;cout<<"("<<str[k]<<" "<<str[k+1]<<" "<<" "<<" "<<str[k-1]<<")"<<endl;sum--;change(k+1);str[k-1]=JG;}}}void main(){char in[MAX]; //用®?于®¨²接¨®收º?输º?入¨?输º?出?文?件t名?FILE *fin; //用®?于®¨²指?向¨°输º?入¨?输º?出?文?件t的Ì?指?针?cout<<"请?输º?入¨?源¡ä文?件t名?(ꡧ包㨹括¤¡§后¨®缀Áo名?)ê?"<<endl;// scanf("%s",in);cin>>in;;if ((fin=fopen(in,"r"))==NULL) //判D断?输º?入¨?文?件t名?是º?否¤?正y确¨¡¤{cout<<"打䨰开a词䨺法¤¡§分¤?析?输º?入¨?文?件t出?错䨪!"<<endl;}cout<<"*********三¨y元a式º?如¨?下?:êo*********"<<endl;scan(fin);//调Ì¡Â用®?函¡¥数ºy从䨮文?件t中D读¨¢入¨?表À¨ª达ä?式º?sanyuanshi();if(sum==0) printf("成¨¦功|!ê?");else printf("有®D错䨪误¨®!ê?");//关?闭À?文?件tfclose(fin);system("pause");}。
实验内容-编译原理及实践教程(第3版)-黄贤英-清华大学出版社

• 查找识别出的单词的种别码,将输出形式改为二元形式 • 画出该高级语言中其他单词类别的状态转换图,并编写
识别函数,并给出测试用例进行测试 • 利用可视化界面展示自己的实验结果
– (3)完成实验报告
实验二:词法分析自动生成器 (2学时+课外)
• 实验内容:利用flex词法分析自动生成工具(或者其他的 词法分析工具),生成Sample语言的词法分析程序。要求:
(含关系表达式)的文法 • 利用递归下降的方法编写判断给定的单词串能否构成一
个正确的布尔表达式的函数
– (3)完成实验报告
实验四:语句的分析(2学时+课外)
• 实验内容:根据Sample语言的语法规则判定输入的一串单 词能否构成一个正确的语句。要求: – (1)基本内容:
• 写出Sample语言(或你所选定的语言)的赋值语句的文 法
– (5)完成实验报告
实验七:运行时存储空间分配 (2学时+课外)
• 实验内容:利用VC++或者其他语言的反汇编程序查看C语 言程序生成的汇编代码,观察程序在内存中的存储情况。 – (1)基本内容:
• 分析程序运行时代码和数据是如何在内存中分配空间的 • 分析一个函数在内存中占用的空间是如何分配的 • 分析函数调用时实在参数和形式参数如何存储和传递 • 分析全局变量是如何在内存中存储的
• 编写Lex源程序,去掉给定Sample语言程序中的注释, 并将所有关键字变为小写
• 编写Lex源程序,能识别Sample语言(或者自选语言) 的所有单词,生成词法分析程序
– (3)完成实验报告
实验三:表达式的分析 (4学时+课外)
• 实验内容:根据Sample语言的语法规则判定输入的一串单 词能否构成一个正确的表达式。要求: – (1)基本内容1:
中间代码生成

陈林第六章中间代码生成本章内容中间代码表示 抽象语法树 三地址代码 中间代码生成 表达式类型检查控制流编译器前端的逻辑结构静态类型检查和中间代码生成的过程都可以用语法制导的翻译来描述和实现对于抽象语法树这种中间表示的生成,第五章已经介绍过表达式的有向无环图语法树中,公共子表达式每出现一次,就有一个对应的子树表达式的有向无环图(Directed Acyclic Graph,DAG)能够指出表达式中的公共子表达式,更简洁地表示表达式构造DAG可以用和构造抽象语法树一样的SDD来构造DAG构造不同的处理在函数Leaf和Node每次被调用时,构造新节点前先检查是否已存在同样的节点,如果已经存在,则返回这个已有的节点构造过程示例三地址代码(1)每条指令右侧最多有一个运算符一般情况可以写成x=y op z允许的运算分量名字:源程序中的名字作为三地址代码的地址 常量:源程序中出现或生成的常量编译器生成的临时变量三地址代码(2)指令集合(1)运算/赋值指令:x=y op z x=op y复制指令:x=y无条件转移指令:goto L条件转移指令:if x goto L if False x goto L 条件转移指令:if x relop y goto L三地址代码(3)•指令集合(2)–过程调用/返回•param x1//设置参数•param x2•…•param xn•call p, n//调用子过程p,n为参数个数–带下标的复制指令:x=y[i]x[i]=y•注意:i表示离开数组位置第i个字节,而不是数组的第i个元素–地址/指针赋值指令:•x=&y x=*y*x=y语句do i = i + 1; while (a[i]<v);三地址代码实例三地址指令的四元式表示方法在实现时,可以使用四元式/三元式/间接三元式来表示三地址指令四元式:可以实现为纪录(或结构)格式(字段):op arg1arg2resultop: 运算符的内部编码arg1,arg2,result是地址x=y+z+ y z x单目运算符不使用arg2param运算不使用arg2和result条件转移/非条件转移将目标标号放在result字段四元式的例子赋值语句:a=b* -c + b* -c三元式表示•三元式(triple)op arg1arg2•使用三元式的位置来引用三元式的运算结果•x[i]=y需要拆分为两个三元式–求x[i]的地址,然后再赋值•x=y op z需要拆分为(这里?是编号)–(?)op y z–=x?•问题:在优化时经常需要移动/删除/添加三元式,导致三元式的移动三元式的例子 a=b*-c + b * -c包含了一个指向三元式的指针的列表 我们可以对这个列表进行操作,完成优化功能;操作时不需要修改三元式中的参数间接三元式静态单赋值(SSA)SSA中的所有赋值都是针对不同名的变量对于同一个变量在不同路径中定值的情况,可以使用φ函数来合并不同的定值if (flag) x=-1; else x = 1;y = x*aif (flag) x1=-1; else x2= 1;x3=φ(x1,x2); y = x3*a类型和声明•类型检查(Type Checking)–利用一组规则来检查运算分量的类型和运算符的预期类型是否匹配•类型信息的用途–查错、确定名字需要的内存空间、计算数组元素的地址、类型转换、选择正确的运算符•主要内容–确定名字的类型–变量的存储空间布局(相对地址)类型表达式•类型表达式(type expression):表示类型的结构–基本类型–类名–类型构造算子作用于类型•array[数字,类型表达式]•record[字段/类型对的列表](可以用符号表表示)–函数类型构造算子→:参数类型→结果类型–笛卡尔积:s X t–可以包含取值为类型表达式的变量类型表达式的例子类型例子元素个数为3X4的二维数组数组的元素的记录类型该记录类型中包含两个字段:x和y,其类型分别是float和integer类型表达式array[3,array[4,record[(x,float),(y,integer)]]]类型等价不同的语言有不同的类型等价的定义结构等价或者它们是相同的基本类型或者是相同的构造算子作用于结构等价的类型而得到的。
第六章 中间代码生成

第六章中间代码生成在编译器的分析-综合模型中,前端对源程序进行分析并产生中间表示,后端在此基础上生成目标代码。
在理想情况下,和源语言相关的细节在前端分析中处理,而关于目标机器的细节则在后端处理。
基于一个适当定义的中间表示形式,可以把针对源语言i的前端和针对目标机器j的后端组合起来,构造得到源语言i在目标机器j上的一个编译器。
这种创建编译器组合的方法可以节约大量的工作量:只要写出m种前端和n种后端处理程序,就可以得到m×n种编译程序。
本章的内容处理中间代码表示、静态类型检查和中间代码生成。
为简单起见,我们假设一个编译程序的前端处理按照图6.1所示方式进行组织,顺序地进行语法分析、静态检查和中间代码生成。
有时候这几个过程也可以组合起来,在语法分析中一并完成。
我们将使用第二章和第五章中的语法制导定义来描述类型检查和翻译过程。
大部分的翻译方案可以基于第五章中给出的自顶向下或自底向上的技术来实现。
所有的方案都可以通过生成并遍历抽象语法树来实现。
静态检查包括类型检查,保证运算符被作用于兼容的运算分量。
静态检查还包括在语法分析之后进行的所有语法检查。
例如,静态检查保证了C语言中的一条break指令必然位于一个while/for/switch语句之内。
如果不存在这样的语句,静态检查将报告一个错误。
本章介绍的方法可以用于多种中间表示,包括抽象语法树和三地址代码。
这两种中间表示方法都在本书的2.8节中介绍过。
名为“三地址代码”的原因是这些指令的一般形式x=y op z 具有三个地址:两个运算分量y和z,一个结果变量x。
在将给定源语言的一个程序翻译成特定的目标机器代码的过程中,一个编译器可能构造出一系列的中间表示,如图6.2所示。
高层的表示接近于源语言,而低层的表示接近于目标机器。
语法树是高层的表示,它刻画了源程序的自然的层次性结构,并且很适合进行诸如静态类型检查这样的处理。
低层的表示形式适合进行机器相关的处理任务,比如寄存器分配、指令选择等。
中间代码生成实验报告

中间代码生成实验报告中间代码生成实验报告一、引言在计算机编程领域中,中间代码生成是编译器的一个重要阶段。
它将源代码转化为一种中间表示形式,以便于后续的优化和目标代码生成。
本实验旨在通过实现一个简单的中间代码生成器,深入理解编译器的工作原理和中间代码的作用。
二、实验背景中间代码是一种介于源代码和目标代码之间的表示形式。
它通常是一种抽象的、与机器无关的形式,具有较高的可读性和可维护性。
中间代码生成是编译器的一个重要阶段,它将源代码转化为中间代码,为后续的优化和目标代码生成提供基础。
三、实验目的本实验的主要目的是通过实现一个简单的中间代码生成器,加深对编译器工作原理的理解,并掌握中间代码的生成过程。
具体目标包括:1. 学习使用编程语言实现中间代码生成算法;2. 理解中间代码的数据结构和语义;3. 掌握将源代码转化为中间代码的过程;4. 分析和优化生成的中间代码。
四、实验设计与实现本实验采用C++语言实现一个简单的中间代码生成器。
具体步骤如下:1. 词法分析:使用词法分析器对输入的源代码进行扫描,将其划分为一个个的词法单元。
2. 语法分析:使用语法分析器对词法单元进行解析,构建语法树。
3. 语义分析:对语法树进行语义分析,检查语法的正确性,并生成中间代码。
4. 中间代码生成:根据语义分析的结果,生成对应的中间代码。
5. 中间代码优化:对生成的中间代码进行优化,提高执行效率和代码质量。
6. 目标代码生成:将优化后的中间代码转化为目标代码。
五、实验结果与分析经过实验,我们成功实现了一个简单的中间代码生成器,并生成了相应的中间代码。
通过对生成的中间代码进行分析,我们发现其中存在一些冗余和不必要的指令,可以进一步进行优化。
例如,可以通过常量折叠、死代码删除等技术,减少中间代码的长度和执行时间。
六、实验总结通过本次实验,我们深入理解了中间代码生成的过程和作用,并通过实践掌握了中间代码生成器的实现方法。
在实验过程中,我们遇到了一些困难和挑战,但通过不断的学习和尝试,最终取得了满意的结果。
编译原理-中间代码生成程序解析

实验报告课程名称实验学期学生所在系部编译原理至学年第学期年级专业班级学生姓名学号任课教师实验成绩计算机学院制、实验目的分析PL/O编译程序的总体结构、代码生成的方法和过程;具体写出一条语句的{参数:id:要找的符号}{返回值:要找的符号在符号表中的位置,如果找不到就返回0 }function positi on (id: alfa): in teger;vari: in teger;beg in { find ide ntifier in table }table[0].name := id; {先把id放入符号表0号位置}i := tx; {从符号表中当前位置也即最后一个符号开始找}while table[i].name <> id do {如果当前的符号与要找的不一致}i := i - 1; {找前面一个}position := i {返回找到的位置号,如果没找到则一定正好为0 }end{ positi on };(二)过程说明说明入口参数,返回值和过程的功能1、入口参数:过程体入口时的处理code[table[tx0].adr].a:=cx; (cx 为过程入口地址,填写在code中)with table[tx0] dobegi nadr:=cx;(过程的入口填写在table表的过程名中)size:=dx;(过程需要的空间填写在table中)end;cxo:=cx;(保留过程在code中的入口地址在输出目标代码时用)gen (i nt,0,dx); (生成过程入口指令)2、返回值:(*通过静态链求出数据区基地址的函数base *)(*参数说明:I:要求的数据区所在层与当前层的层差*)(*返回值:要求的数据区基址*)fun cti on base(l: in teger): in teger;varb1: in teger;beg inbl := b; (* find base 1 level down *)(* 首先从当前层开始*)while l > 0 do (*如果l大于0,循环通过静态链往前找需要的数据区基址*)beg inb1 := s[b1]; (*用当前层数据区基址中的内容(正好是静态链SL数据,为上一层的基址)的作为新的当前层,即向上找了一层*)l := l - 1 (* 向上了一层,l 减一*)end;base := b1 (*把找到的要求的数据区基址返回*)en d(* base *);(三)程序静态结构图源程序输入主程序程序运行输出出错处理程序表格管理程序退出数据段SYM 为语句后继符?PCODE 码输出结束(四)PL0文法描述在计算机科学中,文法是编译原理的基础,是描述一门程序设计语言和实现其 编译器的方法。
中间代码生成具体实验过程含代码

实验三中间代码生成学号:1152185;姓名:马小军实验目的1.了解并掌握中间代码的生成过程和作用2.了解并掌握四元式3.体会属性文法在中间代码生成过程中的作用。
实验环境Windows7操作系统vs2010编程环境实验内容从文件中读入表达式,输出其四元式的结果序列本程序只能生成赋值语句及算数表达式中间代码的四元式不能生成逻辑表达式及其他复杂语句中间代码的四元式实验原理三、以逆波兰式为例的实验设计思想及算法(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
(2)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符数字,则分析到该数字串的结束并将该数字存入数组。
(3)如果不是数字,该字符则是运算符,此时需比较优先关系。
做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。
如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。
倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。
(4)重复上述操作(2)-(3)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为四元式。
下面给出算法流程图实验步骤打开并运行软件根据提示输入要分析的源程序(文件目录下有写好的文件源文件1.txt输入即可)运行输出结果例如将以下源文件放入test.txt运行结果a:=b*c+b*d思考同样的思路对算法进行适当改动就可以生成其它形式的中间代码【其他部分】设计原理和算法思想参考《程序设计语言编译原理》第三版国防工业出版社作者陈火旺等附录代码#include<stdlib.h>#include<fstream>#include<iostream>#include<stdio.h>using namespace std;#define MAX 100int m=0,sum=0;//sum用®?于®¨²计?算?运?算?符¤?的Ì?个?数ºy//m用®?于®¨²标À¨º记?输º?入¨?表À¨ª达ä?式º?中D字Á?符¤?的Ì?个?数ºychar JG='A';char str[MAX];//用®?于®¨²存ä?输º?入¨?表À¨ª达ä?式º?int token=0;//左Á¨®括¤¡§号?的Ì?标À¨º志?/***********用®?于®¨²更¨¹改?计?算?后¨®数ºy组Á¨¦中D的Ì?值¦Ì**************/void change(int e){int f=e+2;char ch=str[f];if(ch>='A'&&ch<='Z'){for(int l=0;l<m+10;l++){if(str[l]==ch)str[l]=JG;}}if(str[e]>='A'&&str[e]<='Z'){for(int i=0;i<m;i++){if(str[i]==str[e])str[i]=JG;}}}void chengchuchuli(int i,int m){i++;for( ;i<=m-1;i++)//处ä|理¤¨ª乘?除y运?算?{if(str[i]=='*'||str[i]=='/'){cout<<"("<<str[i]<<" "<<str[i-1]<<" "<<str[i+1]<<" "<<JG<<")"<<endl;change(i-1);str[i-1]=str[i]=str[i+1]=JG;sum--;JG=(char)(int)JG++;}}}void jiajianchuli(int j,int m){j++;for( ;j<=m-1;j++)//处ä|理¤¨ª加¨®减?运?算?{if(str[j]=='+'||str[j]=='-'){cout<<"("<<str[j]<<" "<<str[j-1]<<" "<<str[j+1]<<" "<<JG<<")"<<endl;change(j-1);str[j-1]=str[j]=str[j+1]=JG;sum--;JG=(char)(int)JG++;}}}/*扫¦¡§描¨¨一°?遍À¨¦从䨮文?件t中D读¨¢入¨?表À¨ª达ä?式º?*/void scan(FILE *fin){int p[MAX];char ch='a';int c=-1,q=0;while(ch!=EOF){ch=getc(fin);while(ch==' '||ch=='\n'||ch=='\t') ch=getc(fin);//消?除y空?格?和¨ª换?行D 符¤?str[m++]=ch;if(ch=='='||ch=='+'||ch=='-'||ch=='*'||ch=='/') sum++;else if(ch=='('){p[++c]=m-1;}else if(ch==')'){q=m-1;chengchuchuli(p[c],q);//从䨮左Á¨®括¤¡§号?处ä|理¤¨ª到Ì?又®?括¤¡§号?jiajianchuli(p[c],q);JG=(char)(int)JG--;str[p[c]]=str[m-1]=JG;c--;JG=(char)(int)JG++;}}}void sanyuanshi(){for(int i=0;i<=m-1;i++)//处ä|理¤¨ª乘?除y运?算?{if(str[i]=='*'||str[i]=='/'){cout<<"("<<str[i]<<" "<<str[i-1]<<" "<<str[i+1]<<" "<<JG<<")"<<endl;change(i-1);str[i-1]=str[i]=str[i+1]=JG;sum--;JG=(char)(int)JG++;}}for(int j=0;j<=m-1;j++)//处ä|理¤¨ª加¨®减?运?算?{if(str[j]=='+'||str[j]=='-'){cout<<"("<<str[j]<<" "<<str[j-1]<<" "<<str[j+1]<<" "<<JG<<")"<<endl;change(j-1);str[j-1]=str[j]=str[j+1]=JG;sum--;JG=(char)(int)JG++;}}for(int k=0;k<=m-1;k++)//处ä|理¤¨ª赋3值¦Ì运?算?{if(str[k]=='='){JG=(char)(int)--JG;cout<<"("<<str[k]<<" "<<str[k+1]<<" "<<" "<<" "<<str[k-1]<<")"<<endl;sum--;change(k+1);str[k-1]=JG;}}}void main(){char in[MAX]; //用®?于®¨²接¨®收º?输º?入¨?输º?出?文?件t名?FILE *fin; //用®?于®¨²指?向¨°输º?入¨?输º?出?文?件t的Ì?指?针?cout<<"请?输º?入¨?源¡ä文?件t名?(ꡧ包㨹括¤¡§后¨®缀Áo名?)ê?"<<endl;// scanf("%s",in);cin>>in;;if ((fin=fopen(in,"r"))==NULL) //判D断?输º?入¨?文?件t名?是º?否¤?正y确¨¡¤{cout<<"打䨰开a词䨺法¤¡§分¤?析?输º?入¨?文?件t出?错䨪!"<<endl;}cout<<"*********三¨y元a式º?如¨?下?:êo*********"<<endl;scan(fin);//调Ì¡Â用®?函¡¥数ºy从䨮文?件t中D读¨¢入¨?表À¨ª达ä?式º?sanyuanshi();if(sum==0) printf("成¨¦功|!ê?");else printf("有®D错䨪误¨®!ê?");//关?闭À?文?件tfclose(fin);system("pause");}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验 6 简单中间代码生成1、实验目的:综合运用所学知识,集成词法分析、符号表管理等程序的成果,在语法分析和文法属性计算的基础上,完成中间代码的生成工作。
让学生全面了解一个编译器工作的全过程,真正全面掌握编译的思想和方法。
2、实验的基本原理对于一个给定文法,通过改写文法,使其满足LR(1)文法的要求,根据语义确定文法符号的属性,确定语义规则或翻译方案;根据文法特点构造LR(1)分析表,进而构造语法分析和属性计算程序。
分析程序在分析表的驱动下,完成对给定的句子进行语法分析和属性计算工作,最后生成三地址中间代码序列。
3、实验内容及要求a.实验所用文法如下。
statmt → id = expexp → exp addop term | termaddop →+ | -term→ term mulop factor | factormulop → * | /factor → ( exp ) | id | num其中id和num为实验二中定义的标识符和常数,因此这里还需要一个小的词法分析器来得到id和num。
b.构造文法LR(1)项目集,构造ACTION和GOTO矩阵,确认文法满足LR(1)文法要求。
c.按一般高级语言赋值语句的计算要求定义文法的属性和语义规则,属性计算的结果是将给定赋值语句翻译成三地址代码序列,并输出此序列。
d.从数据文件中读出赋值语句,并对其进行语法分析,对合法语句,输出其翻译结果。
e.实验数据文件中应该有多个语句,可能有正确的也应该有错误的语句;语句中的表达式有形式简单的也应该有复杂的。
每个表达式写在一行,以$结束。
4、实验步骤准备好用于实验的赋值语句序列,并存储在文件中。
a.编写单词分析子程序,能从源程序中分离出单词(包括标识符和常数);词法分析器以子程序形式出现,当需要进行词法分析时进行调用;b.构造分析表,确认上述文法为LR(1)文法,定义属性和语义规则。
c.确定临时变量生成方案,构造其生成程序。
d.编写自下而上分析程序,这个程序应该能够识别正确和错误的语句;同时进行语义计算。
e.逐个读入语句,给出正误评判,并输出正确语句翻译结果。
问题求解1.拓广方法由于文法的开始符号只在方法中出现一次,并不在产生式右部出现,所以方法可以不用扩展。
1)statmt → id = exp2)exp → exp addop term3)exp → term4)addop → +5)addop → -6)term→ term mulop factor7)term→ factor8)mulop → *9)mulop → /10)factor → ( exp )11)factor → id12)factor → num2.构造LR(1)项目集I0:statmt →·id = exp , $I1: goto( I0 , id )statmt →id·= exp , $I2: goto( I1 , = )statmt →id =·exp , $exp →·exp addop term , $|+|-exp →·term , $|+|-term→·term mulop factor , $|+|-|*|/term→·factor , $|+|-|*|/factor →·( exp ) , $|+|-|*|/factor →·id , $|+|-|*|/factor →·num , $|+|-|*|/I3: goto( I2 , exp )statmt →id = exp·, $exp →exp ·addop term , $|+|-addop →·+ ,(|id|numaddop →·- ,(|id|numI4: goto( I2 , term )exp → term· , $|+|-term→ term· mulop factor , $|+|-|*|/mulop →·* ,(|id|nummulop →·/ ,(|id|numI5: goto( I2 , factor )term→factor· , $|+|-|*|/I6: goto( I2 ,( )factor → (·exp) , $|+|-|*|/exp →·exp addop term , )|+|-exp →·term , )|+|-term→·term mulop factor , )|+|-|*|/term→·factor , )|+|-|*|/factor →·( exp ) , )|+|-|*|/factor →·id , )|+|-|*|/factor →·num , )|+|-|*|/I7: goto( I2 , id )factor →id· , $|+|-|*|/I8: goto( I2 , num )factor →num· , $|+|-|*|/I9; goto( I3 , addop )exp → exp addop· term , $|+|-term→·term mulop factor , $|+|-|*|/term→·factor , $|+|-|*|/factor →·( exp ) , $|+|-|*|/factor →·id , $|+|-|*|/factor →·num , $|+|-|*|/I10: goto(I3 , + )addop → +· ,(|id|numI11: goto(I3 , - )addop → -· ,(|id|numI12: goto(I4 , mulop )term→ term mulop· factor , $|+|-|*|/ factor →·( exp ) , $|+|-|*|/factor →·id , $|+|-|*|/factor →·num , $|+|-|*|/I13: goto( I4 , * )mulop → *· ,(|id|numI14: goto( I4 , / )mulop → /· ,(|id|numI15: goto( I6 , exp )factor → (exp·) , $|+|-|*|/exp → exp· addop term , )|+|-addop →·+ ,(|id|numaddop →·- ,(|id|numI16: goto( I6 , term )exp → term· , )|+|-term→ term· mulop factor , )|+|-|*|/ mulop →·* ,(|id|nummulop →·/ ,(|id|numI17: goto( I6 , factor )term→ factor· , )|+|-|*|/I18: goto( I6 , ( )factor → (·exp) , )|+|-|*|/exp →·exp addop term , )|+|-exp →·term , )|+|-term→·term mulop factor , )|+|-|*|/term→·factor , )|+|-|*|/factor →·( exp ) , )|+|-|*|/factor →·id , )|+|-|*|/fac tor →·num , )|+|-|*|/I19: goto( I6 , id )factor → id· , )|+|-|*|/I20: goto( I6 , num )factor → num· , )|+|-|*|/I21: goto( I9 , term )exp → exp addop term· , $|+|-term→term ·mulop factor , $|+|-|*|/mulop →·* ,(|id|nummulop →·/ ,(|id|numgoto( I9 , factor ) == I5goto( I9 , ( ) == I6goto( I9, id ) == I7goto( I9, num ) == I8I22: goto( I12 , factor )term→ term mulop factor· , $|+|-|*|/ goto( I12 , ( ) == I6goto( I12, id ) == I7goto( I12, num ) == I8I23: goto( I15 , addop )exp → exp addop· term , )|+|-term→·term mulop factor , )|+|-|*|/term→·factor , )|+|-|*|/factor →·( exp ) , )|+|-|*|/factor →·id , )|+|-|*|/factor →·num , )|+|-|*|/I24: goto( I15 , ) )factor → ( exp ) · , $|+|-|*|/goto( I15 , + ) == I10goto( I15 , - ) == I11I25: goto( I16 , mulop )term→ term mulop· factor , )|+|-|*|/ factor →·( exp ) , )|+|-|*|/factor →·id , )|+|-|*|/factor →·num , )|+|-|*|/goto( I16 , * ) == I13goto( I16 , / ) == I14I26: goto( I18 , exp )factor → (e xp·) , )|+|-|*|/exp →exp· addop term , )|+|-addop →·+ ,(|id|numaddop →·- ,(|id|numgoto( I18 , term ) == I16goto( I18 , factor ) == I17goto( I18 , ( ) == I18goto( I18 , id ) == I19goto( I18 , num ) == I20goto( I21 , mulop ) ==I12goto( I21 , * ) ==I13goto( I21 , / ) ==I14I27: goto( I23 , term )exp → exp addop term· , )|+|-term→ term· mulop factor , )|+|-|*|/ mulop →·* ,(|id|nummulop →·/ ,(|id|numgoto( I23 , factor ) == I17goto( I23 , ( ) == I18goto( I23 , id ) == I19goto( I23 , num ) == I20I28: goto( I25 , factor )term→ term mulop factor· , )|+|-|*|/goto( I25 , ( ) == I18goto( I25 , id ) == I19goto( I25 , num ) == I20I29: goto( I26 , ) )factor → ( exp )· , )|+|-|*|/goto( I26 , addop ) == I23goto( I26 , + ) == I10goto( I26 , - ) == I11goto( I27 , mulop ) == I25goto( I27 , * ) == I13goto( I27 , / ) == I143.,画出自动机5.判断是否是LR(1)文法由于按照LR(1)分析表的构造方法所构造出的分析表中,每一项至多只有一个动作,所以该文法是LR(1)的,可以用LR(1)方法分析。