中间代码生成-四元式设计

合集下载

中间代码生成

中间代码生成

:
T integer
T.type=integer T.width=4
enter(x,real,0)
enter(i,integer,8)
例 8-4 x:real; i:integer 的翻译
P{offset:=0}D {offset:=0}D;D {offset:=0}x:T{enter(x,T.type,offset);offset:=offset+T. width};D {offset:=0}x:real{T.type:=real;T.width:=8} {enter(x,T.type,offset);offset:=offset+T.width};D x:real{(x,real,0);offset:=8};D x:real{(x,real,0);offset:=8};i:T{enter(,T.type,o ffset); offset:=offset+T.width} x:real{(x,real,0);offset:=8};i:integer{T.type:=integer; T.width:=4}{enter(i,T.type,offset);offset:=offset+T.wid th} x:real{(x,real,0)};i:integer{(i,integer,8);offset:=12}

全局变量表示为静态数据区的偏移值(offset) 局部变量表示为局部数据区(活动记录部分)的偏移值 两种数据区
例 8-3:相对地址举例
begin real x[8]; integer i, j; …… end 名字 相对地址 x 0 i 64 j 68
0 8 X[1] X[2]
作用域信息的保存

中间代码生成

中间代码生成

• •
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、移位运算符以及将定点数转换成 浮点数的类型转换符。

编译原理实验 中间代码生成

编译原理实验 中间代码生成

实验四中间代码生成一.实验目的:掌握中间代码的四种形式(逆波兰式、语法树、三元式、四元式)。

二.实验内容:1、逆波兰式定义:将运算对象写在前面,而把运算符号写在后面。

用这种表示法表示的表达式也称做后缀式。

2、抽象(语法)树:运算对象作为叶子结点,运算符作为内部结点。

3、三元式:形式序号:(op,arg1,arg2)4、四元式:形式(op,arg1,arg2,result)三、以逆波兰式为例的实验设计思想及算法(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。

(2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。

(3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。

(4)如果不是数字,该字符则是运算符,此时需比较优先关系。

做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。

如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。

倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。

(5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。

四、程序代码://这是一个由中缀式生成后缀式的程序#include<iostream.h>#include<string.h>#include<math.h>#include<ctype.h>#define maxbuffer 64void main(){char display_out(char out_ch[maxbuffer], char ch[32]);//int caculate_array(char out_ch[32]);static int i=0;static int j=0;char ch[maxbuffer],s[maxbuffer],out[maxbuffer];cout<<"请输入中缀表达式: ";cin>>ch;for(i=0;i<maxbuffer;i++){out[i]=ch[i];}cout<<"请确认您输入的表达式:"; while(out[j]!='#'){cout<<out[j];j++;}cout<<'#'<<endl;display_out(s,out);//caculate_array;}char display_out(char out_ch[32],char ch[]) {int top=-1;int i=0,data[maxbuffer],n;int j=0;char sta[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]=='*'&&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<<"错误: 第"<<j<<"个位置的")"没有找到与之匹配的"(""; ch[i]='#';j=0;}else{//while(sta[top]!=‘(‘){out_ch[j]=sta[top];top--;j++;//}break;}break;/*case ‘#‘: out_ch[j]=‘#‘;j++;break;*/default:cout<<" your input is error"<<endl; ch[i]='#';j=0;break;}}}while(top!=-1){out_ch[j]=sta[top];j++;top--;}out_ch[j]='#';n=0;cout<<"逆波兰表达式为: ";while(out_ch[n]!='#'){cout<<out_ch[n];n++;}cout<<endl;j=0;return out_ch[maxbuffer];}五、实验结果:要求:自己给出3个测试用例,观察结果。

编译原理中的中间代码生成

编译原理中的中间代码生成

编译原理中的中间代码生成编译原理是计算机科学的一门重要课程。

在编译器的构造过程中,中间代码生成是其核心部分之一。

它是将源代码翻译为目标代码的重要中间阶段。

中间代码生成的过程涉及到链表、树,生成三元式、四元式等多种中间形式。

本文将介绍中间代码生成的过程和其在编译中的作用。

一、中间代码的概念中间代码是指在源程序和目标程序之间所生成的一系列指令的集合。

目标代码是指机器可执行的二进制代码,而中间代码则是一种可传递、可处理和可修改的编译代码形式。

中间代码属于一种中间状态,它不是源代码也不是目标代码,但可以被转换成目标代码。

中间代码可以基于语法树、语法分析栈、语法分析表进行生成,生成的中间代码需要满足语言语法结构和语义规则。

二、中间代码生成的流程在编译过程中,中间代码生成是指将源代码转换成中间代码的过程。

它是在词法分析、语法分析和语义分析阶段之后完成的。

下面介绍一下中间代码生成的流程。

1.源代码转换为语法树编译器通过词法分析和语法分析将源代码转换成语法树。

语法树是一种树形结构,它记录了源代码中各个语句的组成情况。

2.语法树进行语义分析在语法分析之后,编译器进行语义分析,检查语法树的合法性,然后根据语言的语义规则对语法树进行标注。

标注的内容包括符号表信息、数据类型等。

3.中间代码的生成在语义分析后,编译器进入中间代码的生成阶段,生成语句的中间代码。

中间代码通常采用三元式或四元式等形式。

三元式包含操作符、操作数以及结果的地址,四元式中还包括了类型信息。

4.中间代码优化在中间代码生成的过程中,编译器会尽可能地优化中间代码。

可以对中间代码进行多种优化,如常量合并、变量替换、公共子表达式消除等。

5.中间代码转换为目标代码在中间代码生成后,编译器将中间代码转换为目标代码。

目标代码可以是汇编代码或机器代码等不同形式的二进制代码。

三、中间代码生成优化的意义编译器中间代码优化的目标是提高程序的执行效率和降低其资源消耗。

执行效率的提高可以通过以下方式实现:1.减少内存使用编译器可以通过删除冗余代码、去除死代码和不必要的变量等方式来减少中间代码的内存使用。

中间代码生成实验报告

中间代码生成实验报告

一、实验目的通过在实验二的基础上,增加中间代码生成部分,使程序能够对实验二中的识别出的赋值语句,if语句和while语句进行语义分析,生成四元式中间代码。

二、实验方法实验程序由c语言完成,在Turboc 2.0环境中调试通过。

语义分析程序的基本做法是对文法中的每个产生式分别编写一个语义分析子程序,当程序语法部分进行推倒或规约时,就分别调用各自的语义分析程序。

当语法分析结束时,语义分析也就结束了。

在本实验程序中,当语法分析部分识别出语法正确的句子时,就进入content函数(当语法分析识别出不正确的句子时,不进入content函数,也就是不进行语义分析),然后根据句子的类型进行分类,进入不同的语义处理部分。

对于赋值语句,关键是产生正确的处理算术表达式E的四元式。

程序中的ec函数的功能就是产生算术表达式的四元式,在ec函数中使用了两个栈idshed,opshed,分别是算术表达式的数据栈和符号栈。

每次提取一个数字和一个算符,然后将算符与与栈顶算符进行优先级比较,优先级高则将单前数字和算符进栈,低或者相等的话则将当前栈顶元素进行合并,产生四元式。

直至整个算术表达式结束。

其中还有一些细节问题,具体的做法可以参看程序。

对于实验给定的if语句的文法格式,条件判断式C只中可能是>或者<=两种关系,不可能是布尔表达式,这样程序就简单的多了。

通过ec函数可以产生条件判断式C中的E的四元式,然后只要加上转向四元式就可以了。

本实验程序中只给出真出口的转向四元式,没有给出假出口的转向四元式,这在实际中是不可以的,但在本实验中,实际上是对每条独立的语句进行语法分析,给出假出口转向四元式实际上意义不大,而且假出口转向语句的转移目标必须要到整个语句分析结束以后才可以知道,这样就要建立栈,然后回填,这样会使程序复杂很多,所以没有加上假出口转向四元式。

对于while语句,具体的做法和if语句差不多,所不同的是当while语句结束时,要多出一条无条件转向四元式,重新转到条件判断式C的第一条四元式。

补充-中间代码生成及其优化

补充-中间代码生成及其优化
第7章 章
中间代码及其优化
7.1 中间代码的形式 7.2 逆波兰式 7.3 三元式 7.4 四元式 7.5 中间代码优化
7.1 中间代码的形式
中间代码:结构简单、 中间代码:结构简单、含义明确的记号系统 中间代码的设计原则:容易生成, 中间代码的设计原则:容易生成,容易翻译成 目标代码 常见的中间代码形式: 常见的中间代码形式: – 逆波兰式 – 三元式 – 四元式
7.4 四元式
二、条件语句 例: if a<b then x:=a+b else x:=a-b; (<, a, b, T1) (5) (RJ, 8, /, /) (FJ, 6, T1, /) (6) (-, a, b, T3) (+, a, b, T2) (7) (:=, T3, /, x) (:=, T2, , x) (8) (……)
17:27:13
16
7.6 优化
7.6.3 优化处理概述
一、合并常量运算 例: 优化前 优化后 (1) 3.14*2 6.28 (2) i:=10; i:=10; j:=2*i+5 j:=25; 二、消除基本块中的公共子表达式 (1) (*, b, c) 例: x:= x + b*c; y:= x + b*c; (2) (+, x, (1)) (3) (:=, (2), x) b*c为公共子表达式 (4) (+, x, (1)) 为公共子表达式 (5) (:=, (4), y)
17:27:13 14
7.6 优化
7.6.2 有关概念 一、变量的定义点和使用点 1、使用点:使用变量的值参加运算 、使用点:使用变量的值参加运算——引用 引用 2、定义点:给变量赋值 、定义点: 例: x := x + 1 定义点 引用点 (1)赋值语句左边的变量 ) (2)输入语句的输入变量表中的变量 ) (3)过程 函数调用时形参和实参结合 )过程/函数调用时形参和实参结合 例: if a<b then x:= a+b else x:= a-b

编译方法实验报告(中间代码生成器的设计)

编译方法实验报告(中间代码生成器的设计)

编译方法实验报告2011年10月word文档可自由复制编辑实验目的熟悉算术表达式的语法分析与中间代码生成原理。

实验内容1)2)(3) 法,设计语法制导翻译生成表达式的四元式的算法;编写代码并上机调试运行通过。

输入——算术表达式;输出——语法分析结果;相应的四元式序列。

设计LL(1)分析法或LR(0)分析法的属性翻译文法,并根据这些属性翻译文使用扩展的语法分析器实现语法制导翻译。

实验原理及基本步骤•算术表达式文法:G(E):o0T | T T•文法变换:T { F co•属性翻译文法:o0 “push(SYNw, )” TE “QUAT”}•递归下降子程序:数据结构: SYN —算符栈;SEM —语义栈;E:入口FrF T:入口1F1四、数据结构设计QUAT QUATF使用递归的结构进行四元式的设计,同时,运用堆栈结构将四元式的输出序列打印出来while ( exp [i]=='+'|| exp[ i]=='-'){syn[++i_s yn]=ex p[i];i++; T();quatO;}while ( ex p[i]=='*' || exp[ i]==7'){ syn[++i_s yn]=ex p[i];i++; F();quat();}void quat(){strcpy(qt[j],"(,//push(SYN,w)//read(w)//push(SYN,w)//read(w))");//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--;i_sem--;i_sem--;sem[++i_sem]=temp; temp++;} //pop(SYN);//pop(SEM);//pop(SEM);//push(SEM,temp);五、关键代码分析(带注释)及运行结果#include <iostream>#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';int E();int T();int F();void quat();int main(int argc, char* argv[]){ printf("please input yourexpression:"); scanf("%s",exp);i=0;E();if (exp[i]=='\0')for (i=0;i<j;i++)printf("%s\n",qt[i]);//文法符号栈//运算对象栈//算术表达式区//四元式区//临时变量,取值为 r--z//生成四元式函数//输入四元式//read(w)//输出四元式序列elseprintf("err");return 0;}int E(){T();while ( exp[i]=='+' || exp[i]=='-'){ syn[++i_syn]=exp[i]; i++; T(); quat();} return 1;} int T(){ F(); while ( exp[i]=='*' ||exp[i]=='/'){ syn[++i_syn]=exp[i]; i++; F(); quat();} return 1;} int F(){ if ( exp[i]=='('){ i++; E(); if( exp[i]!=')'){ printf("err"); return 0;}}else if ((exp[i]>='a' && exp[i]<='p')||(exp[i]>='0' &&exp[i]<='9')){ sem[++i_sem]=exp[i]; } else{ printf("err"); return 0;} i++; 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--; i_sem--; i_sem--; sem[++i_sem]=temp; temp++;}//push(SYN,w)//read(w) //push(SYN,w) //read(w) //read(w)//push(SEM,w) //read(w))");//pop(SYN); //pop(SEM);//pop(SEM);//push(SEM,temp);■ ■ *QAProgfflm 百fe貞Ptugrarnmablc Pnogroms\WorkSpjcc\'CMk「*Q:\PmgraTn fites\Ptagr*mrT>ablc Pnc>groms\WorkSpflcc\<™fc blocks\'sryuons>ii\b!'n\DrtMjg-..〔_■n '"GAProgra-m rile^\Prograrnmable PrDgrami5\WairtSpac<\cQde blocksXsiybianshi^binyDebug.^.邑_)*<j;\Program Fiks\Progrflmfnabk PrDgrams\WorkSpacc\todc bloci£5\^!yuan4hi\bin\Debug- _旦J 邑 '我们知道,定义一种语言除了要求定义语法外, 还要求定义语义,即对语言 的各种语法单位赋予具体的意义。

编译原理第七章中间代码生成

编译原理第七章中间代码生成

7.2 声 明 语 句
7.2.2 作用域信息的保存
• 所讨论语言的文法
PDS D D ; D | id : T | proc id ; Dktable(previous) enter(table, name, type, offset) addwidth(table, width) enterproc(table, name, newtable)
四元式
• 一个四元式是带有四个域的记录结构,这四个 域分别称为op, arg1, arg2及result。
– 域op包含一个代表运算符的内部码
– 三地址语句x=y op z通过将y放入arg1,z放入arg2 ,并且将x放入result,=为算符。
– 像x=y或x=-y这样的一元操作符语句不使用arg2 – 像param这样的运算符仅使用arg1域。 – 条件和无条件语句将目标标号存入result域。
7.2 声 明 语 句
7.2.1 过程中的声明
计算被声明名字的类型和相对地址 P {offset = 0} D S DD;D D id : T {enter ( , T.type, offset); offset = offset + T.width } T integer {T.type = integer; T.width = 4 } T real {T.type = real; T.width = 8 } T array [ num ] of T1 {T.type = array (num.val, T1.type); T.width = num.val T1.width} T T1 {T.type = pointer (T1.type); T.width = 4 }
uminus
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

中间代码生成-四元式设计文档实验任务:在实验4的基础上,完成以下描述赋值语句和算数表达式文法G[A]的语法制导生成中间代码四元式的过程。

A-->V:=E V--><标识符> E,E+T|E-T|TT,T*F|T/F|F F,(E)|<标识符> 说明:标识符的定义参见实验一程序的功能描述从文件中读入表达式,输出其四元式的结果序列本程序只能生成赋值语句及算数表达式中间代码的四元式不能生成逻辑表达式及其他复杂语句中间代码的四元式,其功能还需要进一步完善。

程序结构描述打开文件成功 NY 结束调用scan()函数从文件读入表达式输出所读入的表达式调用生成四元式函数siyuanshi()表达式中是否有括号 NY处理括号内的处理乘除加减和赋值运算sum=0NY输出成功输出错误提示结束程序测试方案测试用例一:d=a+b*(3*n)/(b-a)测试用例二:x=x*(x+y-(x-y)/(z+x)-y)实验总结此程序基本达到了实验要求,能够生成简单的赋值及算数表达式中间代码的四元式,但其功能实在是过于简单。

第一次调试通过后程序还存在以下不足:(1) 此程序只能从文件中读入一个表达式,读入多个则会出错;(2) 所读入的表达式中若含有多于一个括号,程序会出错;(3) 括号内若多于一个表达式则会出错;(4) 在测试用例二中的分析过程明显是错误的,这足以看出程序的漏洞很多但经过进一步优化算法,以上问题基本解决,但程序中仍然存在很多不足,例如时间效率和空间效率方面做的还不够好,要改善这些不足还需要进一步完善程序,在以后的学习生活中我会根据所学知识的不断深入而不断完善此程序,争取使其功能更加强大。

经过这次实验我更加深刻的理解了生成中间代码的算法思想,及时的将所学知识用于实践,更加深刻的掌握了所学知识。

附录#include<stdlib.h> #include<fstream> #include<iostream> using namespace std;#define MAX 100int m=0,sum=0;//sum用于计算运算符的个数//m用于标记输入表达式中字符的个数char JG='A';char str[MAX];//用于存输入表达式int token=0;//左括号的标志/***********用于更改计算后数组中的值**************/ 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++)//处理乘除运算{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++;}}}/*扫描一遍从文件中读入表达式*/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);//消除空格和换行符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 siyuanshi(){for(int i=0;i<=m-1;i++)//处理乘除运算{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++)//处理赋值运算{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]; //用于接收输入输出文件名FILE *fin; //用于指向输入输出文件的指针cout<<"请输入源程序文件名(例如ceshi.txt):";cin>>in;cout<<endl;if ((fin=fopen(in,"r"))==NULL) //判断输入文件名是否正确{cout<<endl<<"打开词法分析输入文件出错!"<<endl;}cout<<"四元式如下:"<<endl;scan(fin);//调用函数从文件中读入表达式/********调用生成四元式的函数********/siyuanshi();/*********判断是否成功**********/if(sum==0) cout<<"成功~"<<endl;else cout<<"有错误~"<<endl;//关闭文件fclose(fin);}。

相关文档
最新文档