编译原理课设实验报告

编译原理课设实验报告
编译原理课设实验报告

《编译技术》

课程设计报告

实验名称编译器设计

姓名

学号

班级

本课设的任务是完成一个完整的编译器,处理用户提交的符合所定文法的源程序代码,生成四元式中间代码,进而翻译成等价的X86平台上汇编语言的目标程序。

编译程序的工作过程划分为下列5个过程:词法分析,语法分析,语义分析和中间代码生成,代码优化,目标代码生成。

其中,词法分析阶段的基本任务是从以字符串表示的源程序中识别出具有独立意义的单词符号,并以二元组的形式输出,以作为语法分析阶段的输入。语法分析阶段的基本任务是将词法分析阶段产生的二元组作为输入,根据语言的语法规则,识别出各种语法成分,并判断该单词符号序列是否是该语言的一个句子。语义分析的任务是首先对每种语法单位进行静态的语义审查,然后分析其含义,并用另一种语言形式(本课设采用四元式) 来描述这种语义。代码优化的任务是对前阶段产生的中间代码进行等价变换或改造,以期获得更为高效即省时间和空间的目标代码。目标代码生成的任务是将中间代码变换成特定机器上的绝对指令代码或可重定位的指令代码或汇编指令代码(本课设生成汇编指令代码)。

在词法分析阶段,通过DOS环境手动输入字符串序列(以’#’作为结束标志)作为带分析的源程序,调用词法扫描子程序将字符串以二元组的形式输出(若有不属于该语言单词符号出现,则进行出错处理),词法扫描子程序包括了对源程序的预处理(忽略多余空格、回车换行符等空白字符),以及对单词的识别和分类,以形成(单词种别,单词自身的值)形式的二元组,并将用户自定义变量信息存入程序变量信息表。

在语法分析阶段,采用自上而下的递归下降分析法,从文法的开始符号出发,根据文法规则正向推导出给定句子。根据递归下降分析函数编写规则来编写相应的函数,在

各个函数的分析过程中调用词法分析程序中的扫描程序,发出“取下一个单词符号”的命令,以取得下一个单词符号作语法分析。

在语义分析和中间代码生成阶段,采用语法制导翻译法,使用属性文法为工具来描述程序设计语言的语义。首先审查词法分析得到的每个语法结构的静态语义,如果静态语义正确再生成中间代码(本课设中采用四元式)。使用属性文法作为描述程序设计语言语义的工具,采用语法制导翻译法完成对语法成分的翻译工作,即在语法分析过程中,依随分析的过程,根据每个产生式所对应的语义子程序(或语义规则描述的语义处理的加工动作)进行翻译。

目标代码生成是编译程序的最后一个阶段,根据符号表等信息,将中间代码转化为等价的目标代码。为减少访问计算机内存的次数,应尽可能把基本块内还要被引用的变量放到寄存器中,而把基本块内不用的变量所占的寄存器释放。为了随时掌握寄存器的使用情况和变量的存放情况,以便生成适当地目标代码,可以建立寄存器描述表和变量地址描述表。

在编译程序的各个阶段中都要涉及到表格管理和错误处理。编译程序在工作过程中需要建立一些表格,以登记源程序中所提供的或在编译过程中所产生的一些信息,编译各个阶段的工作都涉及到构造、查找、修改或存取有关表格中的信息(本课设中建立了程序变量信息表,变量地址描述表,寄存器描述表)。一个好的编译程序在编译过程中,应具有广泛的程序查错能力,并能准确地报告错误的种类及出错位置,以便用户查找和纠正,因此,在编译程序中还必须有一个出错处理程序。

实验的整体设计思想可由以下图示表示:

编译器基本模块设计

词法分析的任务是对字符串表示的源程序从左到右地进行扫描和分解,根据语言

的词法规则识别出一个一个具有独立意义的单词符号,包括关键字,标识符,常数,运算

为每个非终结符编制一个递归下降分析函数,每个函数名是相应的非终结符,函数体则是根据规则右部符号串的结构和顺序编写,完成相应非终结符匹配,通过所有子程序的相互调用,完成整个终结符号串的分析。

(1)当遇到终结符a时,则编写语句

if (当前读来的输入符号==a) 读下一个输入符号;

(2)当遇到非终结符A时,则编写语句调用A( );

(3)当遇到规则A→ε时,则编写语句

if (当前读来的输入符号 FOLLOW(A))

error( );

递归下降分析法是确定的自上而下分析法,这种分析法要求文法是LL(1)文法。

语法结构定义采用扩充的BNF表示法,避免了直接左递归规则,并且也没有公共左因子。对于非终结符E→T { +T },函数T( )用while语句描述如下:

T ( )

{

F ( );

while ( sym = =‘*’)

{

Scanner ( );

F ( );

}

}

b)语义分析和中间代码生成器(语法制导翻译法)

1 语义分析的任务:

1)静态语义审查:

审查每个语法结构的静态语义,即验证语法结构合法的程序,是否真正有意义。

2)执行真正的翻译:

如果静态语义正确, 语义处理则要执行真正的翻译, 即生成程序的某种中间代码的形式或直接生成目标代码。

2语法制导翻译法的基本思想

为文法的每个产生式都配备一个语义动作或语义子程序。

在语法分析的过程中,每当使用一条产生式进行推导或归约时,就执行相应产生式的语义动作, 从而实现语义处理。在语法分析过程中,依随分析的过程,根据每个产生式所对应的语义子程序(或语义规则描述的语义处理的加工动作)进行翻译。

3 属性文法和语义规则

语法制导翻译法使用属性文法为工具来描述程序设计语言的语义。属性文法包含一个上下文无关文法和一系列语义规则(为文法的每一个规则配备的计算属性的计算规则)。这些语义规则附在文法的每个产生式上,在语法分析过程中, 执行语义规则描述的动作, 从而实现语义处理。也就是说, 附在文法的每个产生式上语义规则描述了语义处理的加工动作。

4 四元式中间代码结构

四元式主要由四部分组成:

(OP,arg1, arg2, result)

其中OP是运算符;arg1,arg2分别是第一和第二两个运算对象(当OP是一目运算时,常常将运算对象定义为arg1);result是编译程序为存放中间运算结果而临时引进的变量,常称为临时变量,如Ti,也可以是用户自定义变量,如X。

5 采用自下而上的语法制导翻译法语义动作的设计

(1)自下而上的语法制导翻译特点:栈顶形成句柄,归约时执行相应语义动作

文法翻译到四元式的语义描述:

1) 语义变量place

表示存放非终结符E值的变量名或其数值。

2) 语义函数gen(op,argv1,argv2,result)

功能是生成一个四元式。

3) 语义函数NewTemp()

功能是产生一个新的临时变量名字,如T1,T2等。

4) 语义变量index为四元式序列指针。

5) 语义变量真出口etc和假出口efc

真(假)出口表示布尔表达式C为真(假)时控制流向的转移目标,布尔表达式的真(假)出口不能在产生其四元式的同时得知,因此设置两个语义变量

C.etc:记录表达式C 所对应的四元式需回填真出口的四元式的地址所构成的链

C.efc:记录表达式C 所对应的四元式需回填假出口的四元式的地址所构成的链

6) 语义变量语句出口chain

在翻译语句时,其出口的转向点通常不能确定,用链表记录这些出口的位置,以便在适当的时机回填。S.chain表示语句S全部出口组成的链即出口链,以待一次性回填。

7) 语义变量语句入口head

使用语义变量LS.head 记录while语句首地址,即对应的第一个四元式语句序号,以回填转移地址,。

8) 链接函数merg(p1,p2)

功能是把以p1, p2为链首的两条链合并为一, 返回合并后的链首;

9) 回填函数bp(p,t)

功能是将p 所链结的每个四元式的第四区分量都回填t ;

(2) 非终结符语义动作:

1)<项> ::= <因子>{*<因子>|/<因子>}

即T→F|T*F|T/F

T→F

{T.place=F.place}

T→T*F

{T.place=NewTemp();

gen("*",T1.place,F.place,T.place)}

T→T/F

{T.place=NewTemp();

gen("/",T1.place,F.place,T.place)}

2)<表达式> ::= <项>{ +<项>|-<项>}

即E→T|E+T|E+T

同1)

3)<条件>::=<表达式><关系运算符><表达式>,<关系运算符> ::=

<|<=|>|>=|==|!=

即C→E op E,op→<|<=|>|>=|==|!=

{ C.etc=index;

C.efc=index+1;

gen("goto "+op,E1.place1,E2.place2,"0");

gen("goto","","","0");}

4)<赋值语句>::=ID=<表达式>

即AS→ID=E

{gen("=",E.place,"",ID);

bp(AS.chain,index);}

5)<条件语句>::=if<条件><语句块>[else <语句块>]

即CS→if C B |if C B else B

{bp(C.etc,index);

CS.Chain=C.efc;

...(B())

CS.chain=merge(B1.chain,index);

gen("goto","","","0");

bp(C.efc,index);

...(B())

CS.chain=merge(B2.chain,CS.chain)}

6)<循环语句>::=do <语句块>while <条件>

即LS→do B while C

{LS.head=index;

...(B())

...(C())

bp(C.etc,LS.head);

bp(C.efc,index);

CS.chain=merge(B.chain,C.efc)}

bp(CS.chain,index);}

c)目标代码生成

采用汇编语言代码作为目标代码生成器的输出,

在四元式序列中有3类量,常量,程序变量和临时变量。一般地,常量对应立即数出现在目标指令中;程序变量是程序中用户自定义变量,通常是存放在存储单元中的存储器变量,在数据段定义为同名字变量(使用伪指令DW);而临时变量则是在生成四元式时由编译程序引进的,因为寄存器变量的存取比存储变量的存取快得多,因此,为临时变量安排寄存器。

1 寄存器描述表和地址描述表

为了反映寄存器使用情况及变量值的存放情况,引进寄存器描述表registerStatus与地址描述表registerT。

寄存器描述表动态反映了寄存器的使用状态,即寄存器是处于空闲状态还是被临时变量占用,以便分配寄存器给临时变量。由于本课设中程序变量存储在内存中,源代码

单语句内所有临时变量都为语句出口后的非活跃变量,因此,每执行完一条源代码语句,可视作寄存器中内容不再使用,描述符清零。

地址描述表指明临时变量所在的寄存器,寄存器描述符为字符串数组,索引为临时变量编号,可能多个临时变量同存在一寄存器。

2 目标指令与四元式编号对照表

控制转移指令分两种:条件控制转移("goto "+op,argv1,argv2,Lable)和无条件控制转移("goto","","",Lable)。往往在生成目标代码的时候还不了解控制转移到的目标指令的编号,因此需要回填。为此,引进目标指令与四元式编号对照表lable,lable[i]反应了四元式i对应的若干目标指令中第一条的编号,在生成目标代码时在第四分量中只填入四元式编号i,待所有目标指令完全生成后再统一回填lable[i]。

3 寄存器分配函数

寄存器的分配由函数char* GetfreeR() 实现。为当前值不在寄存器的临时变量分配空闲寄存器。

4 四元式对应目标代码

根据四元式生成规则,1中argv2为程序变量,2,3,4,5中res为首次出现的临时变量

一般传送指令MOV OPD,OPS

将字转换成双字指令(将AX中的符号扩展至DX中):CBW

加指令:ADD OPD,OPS

减指令:SUB OPD,OPS

有符号乘指令:IMUL OPD,OPS

有符号除指令:IDIV OPS(字除法:(DX,AX)/(OPS) AX(商),DX(余数))

比较指令:CMP OPD,OPS

转移指令:JE 相等转移

JNE 不相等转移

JG 大于转移

JGE 大于或等于转移

JL 小于转移

JLE 小于或等于转移

JMP 无条件转移

指令限制:

(1)目的操作数不能是立即操作数;

(2)操作结束后,运算结果送人目的地址中;

(3)源操作数和目的操作数不能同时为存储器操作数;

(4)IMUL OPD,OPS中OPD为寄存器

(5)IDIV OPS中OPS不能是立即操作数

1.流程框图

1)词法分析器

scaner()函数流程图

2)语法分析器(递归下降法)

P()函数流程图

B()函数流程图

SS()函数流程图

3)语义分析及中间代码生成

初始化:flag,nVar,index,nSuffix置0

Parse()函数流程图4)目标代码生成

2.函数相关说明

1)词法分析部分

函数Scaner( );识别源程序的一个单词符号

词法分析程序所用的全局变量如下:

rwtab[] 关键字对应到编码值的映射表。

prog[] 字符数组,存放源程序

ch 字符变量,存放当前读进的源程序字符。

syn 整型,当前单词种别编码

token[] 字符数组, 存放当前构成单词符号的字符串。

sum 双精度型,存放当前常量的数值。

variable[] 用户自定义变量信息表。

flag 1表示刚读取一个变量或常数,"+/-"为运算符;

0反之,"+/-"可能为数值符号

将从键盘输入的字符串存储到prog[]数组,用scaner()函数从prog[]中取出有独立意义的字符串存到token[]中:

1、首字符为字母,且其后为字母与数字的组合,syn对应到码值10,进一步

检查此组合字符串是否在关键字表中,若在其中,则修改syn对应到相应码值;

2、数字串的组合中:整数数字串、小数数字串码值、(含有字母e)指数数

字串,将其二进制数值存入sum;

3、其他符号先判断是否为符号组合一部分,若为符号组合,则继续扫描,syn

应到相应码值;若为单个符号,则回退,syn对应到相应码值。

main():先从键盘输入待编码字符串,存入prog[]中,用#判断是否输入结束,然后调用scaner()函数,得到对应码值,有print函数显示输出。

d)语法分析部分(递归下降法)

(1)函数Scaner( )

功能: 读进源程序的下一个单词符号

并将它放在全程变量sym。

(2) 函数error( )

功能: 出错处理程序。

数组prog[]、token[]、rwtab[],函数scanner()作用同上。

递归下降算法分析:调用scaner()函数,对应出码值若不为0,则报错;然后调用语句串分析函数;判断是否含有end;若含有则再次调用scaner()函数,对应得相应码值;判断是否由#提示结束;若是,则打印分析成功,若否则转报错处理。

3.输入与输出(包括出错处理)

a)词法分析程序

词法分析程序的输入是字符串形式的源程序,词和词之间可以用空白字符(空格、

回车、制表符)隔开。

词法分析程序的输入是一个二元组,形式为:(单词种别码,单词自身的值)。

若输入的字符串带有不合法的字符,则对应的字符(串)在输出中不以二元组的形

式显示,而以“error!!”表示出错。

例如:输入main while if 123.455e+123#

输出:(1,main)

(9,while)

(6,if)

(20,1.23455e+125)

(0,#)

b)语法分析程序

语法分析程序的输入与词法分析的输入一致,即字符串形式的源程序,词和词之间

可以用空白字符(空格、回车、制表符)隔开。

语法程序的输出是判断所输入字符串是否是该语言的句子的结果,也即“success!”

或者“fail!”,分别表示所输入的字符串是该语言的一个句子和字符串不是该语言的一

个句子。

出错时结果为“fail!”。

例如:输入123.345e+123+(1*3+(2+4)/212)+12#

结果为“success!”

4.程序运行结果(屏幕截图)

5.编译器使用说明

语法分析器的输入为字符串形式的源程序,词与词之间可以用空白字符(空格、回车、制表符)隔开;

语法程序的输出是判断所输入字符串是否是该语言的句子的结果,也即“success!”

或者“fail!”,分别表示所输入的字符串是该语言的一个句子和字符串不是该语言的一个句子。是则输出“success”,出错则输出“fail”。

6.心得与体会

大部分系统软件和应用软件的开发,通常要用到编译的原理和技术。设计词法分析器的串匹配技术已用于正文编辑器、信息检索系统和模式识别程序; 上下文无关文法和语法制导定义已用于创建诸如排版、绘图系统和语言结构化编辑器中,代码优化技术已用于程序验证器和从非结构化的程序产生结构化程序的编程之中。

通过动手编写程序对词法语法的分析有了更加深入的体会,巩固了编译原理的基本知识,亲自动手实践编译程序,使我对编译更加感兴趣。此次实验只是实现了编译器最基本的功能,不由得感叹实际的编译器实在太强大了!继续认真学习,勤于思考,学习编译中的精妙思想,做好课设!

7.源程序清单

#include"stdafx.h"

#include

#include

#include

#include

#include

#include

/************************************************************************/ /* 词法分析*/ /************************************************************************/ #define max 10

char *rwtab[9] = {"main","int","float","double","char","if","else","do","while"};

char prog[100];//源程序

int p;//当前处理字符位置

char ch; //当前处理字符

int flag; //1表示刚读取一个变量或常数,"+/-"为运算符;0反之,"+/-"可能为数值符号int syn; //种别编码

char token[max]; //保留字、内部字符串或操作符

double sum; //数值

char** variable;//变量信息表

int nVar;

/************************************************************************/ void scaner()

{

int i;

for(i=0;i

sum=0;

int m=0;

int e=0;//数值指数

ch=prog[p++];

while(isspace(ch)) ch=prog[p++];//预处理,去除注释、多余空格、回车换行符等if(isalpha(ch))//保留字、内部字符串

{

while(isalnum(ch))

{

token[m++]=ch;

ch=prog[p++];

}

token[m++]='\0';

p--;

syn=10;

for(i=0;i<9;i++)

if(strcmp(token,rwtab[i])==0)

{

syn=i+1;

flag=0;

break;

}

if(syn==10)

{

flag=1;

for (i=1;i<=nVar;i++)

{

if (!strcmp(token,variable[i])) return;

}

strcpy(variable[++nVar],token);

}

}

else if (ch == '+'|| ch == '-' || isdigit(ch))//数值、"+"、"-" {

if (!isdigit(ch)&&(flag == 1||!isdigit(prog[p])))

{

token[m++]=ch;

if (ch == '+') syn =22;

else syn = 23;

flag = 0;

}

else

{

int flag1 = 0;

int flag2 = 0;

if(ch == '+'|| ch == '-')

{

ch=prog[p++];

if(ch == '-') flag1=1;

}

while(isdigit(ch))

{

sum=sum*10+ch-'0';

ch=prog[p++];

}

int k=10;

if(ch=='.' && isdigit(prog[p]))

{

ch=prog[p++];

while(isdigit(ch))

{

double d=ch-'0';

sum=sum+d/k;

k=k*10;

ch=prog[p++];

}

}

if(ch=='e' || ch=='E')

{

char ch_tmp=prog[p];

if(((ch_tmp=='+' || ch_tmp=='-') && isdigit(prog[p+1])) || isdigit(ch_tmp))

{

ch=prog[p++];

if(!isdigit(ch))

{

if(ch=='+')

flag2=0;

else

flag2=1;

ch=prog[p++];

}

while(isdigit(ch))

{

e=e*10+ch-'0';

ch=prog[p++];

}

if(flag2)

sum=sum*pow(10.0,-e);

else

sum=sum*pow(10.0,e);

}

}

if(flag1) sum*=(-1);

p--;

syn=20;

flag=1;

}

}

else//运算符、分隔符

{

flag = 0;

m=0;

switch(ch)

{

case'<':

token[m++]=ch;

ch=prog[p++];

if(ch=='=')

{

syn=35;

token[m++]=ch;

}

else

{

syn=34;

p--;

}

break;

case'>':

token[m++]=ch;

ch=prog[p++];

if(ch=='=')

{

syn=33;

token[m++]=ch;

}

else

{

syn=32;

p--;

}

break;

case'=':

token[m++]=ch;

ch=prog[p++];

if(ch=='=')

{

syn=36;

token[m++]=ch;

}

else

{

syn=21;

p--;

}

break;

case'!':

token[m++]=ch;

ch=prog[p++];

if(ch=='=')

{

syn=37;

token[m++]=ch;

}

else

{

syn=-1;

}

break;

case'*': syn=24; 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=29; token[0]=ch; break;

case',': syn=30; token[0]=ch; break;

case';': syn=31; token[0]=ch; break;

case'#': syn=0; token[0]=ch; break;

default: syn=-1; printf("illegal character %c/n",ch);

}

}

return ;

}

/************************************************************************/ /* 语法语义分析*/ /************************************************************************/ ////////////////////////////////////////////////////////////////////////////////////////////// // 递归下降法// ///////////////////////////////////////////////////////////////////////////////////////////// void P (); //程序

void B (int *nChain); //语句块

void SS(int *nChain); //语句串

void S (int *nChain); //语句

void AS(int *nChain); //赋值语句

void CS(int *nChain); //条件语句

void LS(int *nChain); //循环语句

void C (int *etc,int *efc); //条件

char * E (); //表达式

char * T (); //项

char * F (); //因子

void error(); //出错处理

////////////////////////////////////////////////////////////////////////////////////////////// // 语法制导翻译// ///////////////////////////////////////////////////////////////////////////////////////////// typedef struct quaternion{

char op[max];

char argv1[max];

char argv2[max];

char res[max];

}quad;//四元式

quad *pQuad;//四元式组指针

int index,nSuffix;//四元式编号,临时变量编号

/************************************************************************/ void gen(char *op,char *argv1,char *argv2,char *result);

char *NewTemp();

int merg(int p1,int p2);

void bp(int p,int t);

void printQuad();

void Parse();

/************************************************************************/ void error()

{

if (syn==20) printf("Syntax error before %g",sum);

else printf("Syntax error before %g",token);

syn=50;

}

//<程序> ::= main()<语句块>

void P()

{

int nChain;

scaner();

if (syn == 1)

{

scaner();

if(syn == 26)

{

scaner();

if (syn == 27)

{

scaner();

B(&nChain);

}

else error();

}

else error();

}

else error();

}

//<语句块> ::= ‘{‘<语句串>’}’

void B(int *nChain)

{

if (syn==28)

{

scaner();

SS(nChain);

if (syn == 29) scaner();

else error();

}

else error();

}

//<语句串>::=<语句>{;<语句>};

void SS(int *nChain)

{

S(nChain);

if (syn==31) scaner();

else error();

while (syn != 29)

{

S(nChain);

if (syn==31) scaner();

else error();

}

}

//<语句>::=<赋值语句>|<条件语句>|<循环语句> void S(int *nChain)

{

if(syn==10) AS(nChain);

else if(syn==6) CS(nChain);

else if(syn==8) LS(nChain);

else error();

}

//<赋值语句>::=ID=<表达式>

void AS(int *nChain)

{

char stemp[max];

char *place;

if (syn==10)

{

strcpy(stemp,token);

scaner();

if (syn==21)

{

scaner();

place=E();

gen("=",place,"",stemp);

*nChain = 0;

}

else error();

}

else error();

bp(*nChain,index);

}

//<条件语句>::=if<条件><语句块>[else <语句块>] void CS(int *nChain)

{

int nChaintmp,ntc,nfc;

if (syn==6)

{

scaner();

C(&ntc,&nfc);

bp(ntc,index);

B(&nChaintmp);

*nChain=merg(nChaintmp,nfc);

if (syn==7)

{

int nfc1;

scaner();

nfc1=index;

gen("goto","","","0");

bp(*nChain,index);

B(&nChaintmp);

*nChain=merg(nChaintmp,nfc1);

bp(*nChain,index);

}else

{

*nChain=merg(nChaintmp,nfc);

bp(*nChain,index);

}

}

else error();

}

//<循环语句>::=do <语句块>while <条件>

void LS(int *nChain)

{

int ntc,nfc;

if (syn == 8)

{

int nChaintmp;

scaner();

int indextmp=index;

B(&nChaintmp);

if (syn == 9)

{

scaner();

C(&ntc,&nfc);

bp(ntc,indextmp);

bp(nfc,index);

*nChain=merg(nChaintmp,nfc);

bp(*nChain,index);

}

else error();

}

else error();

}

//<条件>::=<表达式><关系运算符><表达式> void C(int *etc,int *efc)

{

char op[max],optmp[max],*place1,*place2;

place1=E();

if (syn>31 && syn<38)

{

sprintf(op,"%s",token);

scaner();

place2=E();

*etc=index;

*efc=index+1;

sprintf(optmp,"goto %s",op);

gen(optmp,place1,place2,"0");

gen("goto","","","0");

}

else error();

}

//<表达式> ::= <项>{ +<项>|-<项>}

char * E()

{

char op[max],*place1,*place2;

char *place = (char *)malloc(max);

place=place1=T();

while (syn == 22 ||syn == 23)

{

sprintf(op,"%s",token);

scaner();

place2=T();

place=NewTemp();

gen(op,place1,place2,place);

place1=place;

}

return place;

}

//<项> ::= <因子>{*<因子>|/<因子>} char * T()

{

char op[max],*place1,*place2;

char *place ;

place=place1=F();

while (syn == 24 ||syn == 25)

{

sprintf(op,"%s",token);

scaner();

place2=F();

place=NewTemp();

gen(op,place1,place2,place);

place1=place;

}

return place;

}

//<因子> ::=ID|num|(<表达式>)

char * F()

{

char *place = (char *)malloc(max);

if (syn == 10)

{

sprintf(place,"%s",token);

scaner();

}

else if(syn == 20)

{

sprintf(place,"%g",sum);

scaner();

}

else if(syn == 26)

{

scaner();

place=E();

if(syn == 27) scaner();

else error();

}

else error();

编译原理课程设计

<PL0编译器-PCompiler> 软件需求说明书 作者:刁诗云、麻汉华、潘彦荃、周津、李程完成日期:2009年6月7日 签收人: 签收日期: 修改情况记录:

目录 软件需求说明书 (1) 1 引言 (1) 1.1 编写目的 (1) 1.2 项目背景 (1) 2 项目概述 (2) 2.1 产品描述 (2) 2.2 产品功能 (2) 2.3 用户特点 (2) 3 具体需求 (3) 3.1 EBNF定义的PL/0文法 (3) 3.2 语法图 (4) 3.3 功能需求 (6) 3.4 系统概要设计 (15)

1 引言 1.1 编写目的 为了清楚表达客户提出的需求,便于用户理解和确认项目所包含的具体功能需求、性能需求以及非公能性需求,因此以文件化的形式,把系统整体及其部分的业务流程、系统功能进行了详细的说明。同时,此文也对开发人员起到引导的作用,请认真阅读。 1.2 项目背景 PL/0是由世界著名计算机科学家、PASCAL语言的创始人N.Wirth教授选择提供的。在选择PL/0语言的过程中,Wirth很费了一番脑筋。一方面他希望借助这个语言,能尽可能把程序设计语言和编译技术一些最重要的内容都讲到;但另一方面又不希望内容太多,太杂,而希望尽可能简单一些,以便与有限的课时和课程范围相适应。于是他精心选择提供了这个PL/0语言。事实证明,它非常适合于编译技术的教学,目前已被国内越来越多的编译教材所采用。 PL/0语言的语句类型比较丰富,能适应各种可能的程序结构。最进本的是赋值语句。组合结构语句有语句串、条件语句和循环语句。还有重要的子程序概念,是通过过程说明和过程调用两部分实现的。至于数据类型和数据结构,PL/0则特别简单,只有整数类型一种,没有数据结构,因此只允许有整常数和整数变量的说明以及相应的算术运算表达式。PL/0允许在一个过程范围内说明常数、变量和过程。这些常数、变量和过程只在它们被说明的过程范围内有效。PL/0语言也允许递归调用,既可以间接递归,也可以直接递归。

编译原理课程设计

《编译原理》课程设计大纲 课程编号: 课程名称:编译原理/Compiler Principles 周数/学分:1周/1学分 先修课程:高级程序设计语言、汇编语言、离散数学、数据结构 适用专业:计算机科学与技术专业、软件工程专业 开课学院,系或教研室:计算机科学与技术学院 一、课程设计的目的 课程设计是对学生的一种全面综合训练,是与课堂听讲、自学和练习相辅相成的必不可少的一个教学环节。通常,设计题中的问题比平时的练习题要复杂,也更接近实际。编译原理这门课程安排的课程设计的目的是旨在要求学生进一步巩固课堂上所学的理论知识,深化理解和灵活掌握教学内容,选择合适的数据逻辑结构表示问题,然后编制算法和程序完成设计要求,从而进一步培养学生独立思考问题、分析问题、解决实际问题的动手能力。 要求学生在上机前应认真做好各种准备工作,熟悉机器的操作系统和语言的集成环境,独立完成算法编制和程序代码的编写。 设计时间: 开发工具: (1) DOS环境下使用Turbo C; (2) Windows环境下使用Visual C++ 。 (3) 其它熟悉语言。 二、课程设计的内容和要求 设计题一:算术表达式的语法分析及语义分析程序设计。 1.目的

通过设计、编制、调试一个算术表达式的语法及语义分析程序,加深对语法及语义分析原理的理解,并实现词法分析程序对单词序列的词 法检查和分析。 2.设计内容及要求: 算术表达式的文法: 〈无符号整数〉∷= 〈数字〉{〈数字〉} 〈标志符〉∷= 〈字母〉{〈字母〉|〈数字〉} 〈表达式〉∷= [+|-]〈项〉{〈加法运算符〉〈项〉} 〈项〉∷= 〈因子〉{〈乘法运算符〉〈因子〉} 〈因子〉∷= 〈标志符〉|〈无符号整数〉|‘(’〈表达式〉‘)’ 〈加法运算符〉∷= +|- 〈乘法运算符〉∷= *|/ (1) 分别选择递归下降法、算符优先分析法(或简单优 先法)完成以上任务,中间代码选用逆波兰式。 (2) 分别选择LL(1)、LR法完成以上任务,中间代码选 用四元式。 (3) 写出算术表达式的符合分析方法要求的文法,给出 分析方法的思想,完成分析程序设计。 (4) 编制好分析程序后,设计若干用例,上机测试并通 过所设计的分析程序。 设计题二:简单计算器的设计 1.目的 通过设计、编制、调试一个简单计算器程序,加深对语法及语 义分析原理的理解,并实现词法分析程序对单词序列的词法检 查和分析。 2.设计内容及要求 算术表达式的文法:

编译原理语义分析实验报告——免费!

语义分析实验报告 一、实验目的: 通过上机实习,加深对语法制导翻译原理的理解,掌握将语法分析所识别的语法成分变换为中间代码的语义翻译方法。 二、实验要求: 采用递归下降语法制导翻译法,对算术表达式、赋值语句进行语义分析并生成四元式序列。 三、算法思想: 1、设置语义过程。 (1)emit(char *result,char *ag1,char *op,char *ag2) 该函数的功能是生成一个三地址语句送到四元式表中。 四元式表的结构如下: struct { char result[8]; char ag1[8]; char op[8]; char ag2[8]; }quad[20]; (2) char *newtemp() 该函数回送一个新的临时变量名,临时变量名产生的顺序为T1,T2,… char *newtemp(void) { char *p; char m[8]; p=(char *)malloc(8); k++; itoa(k,m,10); strcpy(p+1,m); p[0]=’t’; return(p); } 2、函数lrparser 在原来语法分析的基础上插入相应的语义动作:将输入串翻译成四元式序列。在实验中我们只对表达式、赋值语句进行翻译。

四、源程序代码: #include #include #include #include struct { char result[12]; char ag1[12]; char op[12]; char ag2[12]; }quad; char prog[80],token[12]; char ch; int syn,p,m=0,n,sum=0,kk; //p是缓冲区prog的指针,m是token的指针char *rwtab[6]={"begin","if","then","while","do","end"}; void scaner(); char *factor(void); char *term(void); char *expression(void); int yucu(); void emit(char *result,char *ag1,char *op,char *ag2); char *newtemp(); int statement(); int k=0; void emit(char *result,char *ag1,char *op,char *ag2) { strcpy(quad.result,result); strcpy(quad.ag1,ag1); strcpy(quad.op,op); strcpy(quad.ag2,ag2);

编译原理课程设计

编译原理课程设计报告 课题名称: C-语言编译器设计(scanner和parser) 提交文档学生姓名: 提交文档学生学号: 同组成员名单:无 指导教师姓名:金军 指导教师评阅成绩: 指导教师评阅意见: . . 提交报告时间: 2011年 6 月 17 日

1.课程设计目标 设计C-Minus编译器分为scanner和parser两个部分。scanner主要作用是对目标代码进行扫描,列出关键字,变量等内容;parser主要对语法进行分析并生成语法树。 2.分析与设计 ●实现方法:代码用C语言编译而成。其中scanner为手工实现,主要采用switch-case结构实现 状态转换;parser部分采用递归下降分析方法实现。 ●扫描器:C-的词法如下: 1、语言的关键字:i f el se i nt return void while 2、专用符号:+ - * /< <= > >= == != =; , ( ) [ ] { } /* */ 3、其他标记是变量(ID)和数字(NUM),通过下列正则表达式定义: ID = letter letter* NUM = di git digi t* letter = a|..|z|A|..|Z digi t = 0|..|9 4、空格由空白、换行符和制表符组成。空格通常被忽略,除了它必须分开ID、NUM关键字 5. 注释用通常的C语言符号/ * . . . * /围起来。注释可以放在任何空白出现的位置(即注释不能放在 标记内)上,且可以超过一行。注释不能嵌套 其DFA图如下:

分析器:以下为C-的语法规则BNF:

编译原理实验报告

编译原理实验报告 姓名: 学号: 班级: 学院: 南昌大学信息工程学院计算机系 2014年6月

目录 实验一 (3) 实验二 (8) 实验三 (15)

实验1 词法分析程序的设计 学生姓名:学号:专业班级: 实验类型:□验证□综合□设计□创新实验日期:实验成绩: 一、实验目的 掌握计算机语言的词法分析程序的开发方法。 二、实验内容 编制一个能够分析三种整数、标识符、主要运算符和主要关键字的词法分析程序。 三、实验要求 1、根据以下的正规式,编制正规文法,画出状态图; 标识符<字母>(<字母>|<数字字符>)* 十进制整数0 |(1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)* 如有余力,则进一步分析八进制和十六进制整数,其正规式如下: 八进制整数0(1|2|3|4|5|6|7)(0|1|2|3|4|5|6|7)* 十六进制整数0x(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)* 运算符和界符+ - * / > < =<= >=( ) ;{ } 关键字main if then else while do int (可根据需要添加) 2、根据状态图,设计词法分析函数int scan( ),完成以下功能: 1)从文本文件中读入测试源代码,根据状态转换图,分析出一个单词, 2)以二元式形式输出单词<单词种类,单词属性> 其中单词种类用整数表示: 0:标识符 1:十进制整数 2:八进制整数 3:十六进制整数 运算符和界符,关键字采用一字一符,不编码 其中单词属性表示如下: 标识符,整数由于采用一类一符,属性用单词表示 运算符和界符,关键字采用一字一符,属性为空 3、编写测试程序,反复调用函数scan( ),输出单词种别和属性。 四、实验环境 PC微机 DOS操作系统或Windows 操作系统 Turbo C 程序集成环境或Visual C++ 程序集成环境

编译原理课程设计报告_LL(1)分析过程模拟

课程设计(论文)任务书 软件学院学院软件工程专业07-1班 一、课程设计(论文)题目LL(1)分析过程模拟 二、课程设计(论文)工作自 2010 年 6 月 22日起至 2010 年 6月 28 日止。 三、课程设计(论文) 地点: 四、课程设计(论文)内容要求: 1.本课程设计的目的 (1)使学生掌握LL(1)模块的基本工作原理; (2)培养学生基本掌握LL(1)分析的基本思路和方法; (3)使学生掌握LL(1)的调试; (4)培养学生分析、解决问题的能力; (5)提高学生的科技论文写作能力。 2.课程设计的任务及要求 1)基本要求: (1)分析LL(1)模块的工作原理; (2)提出程序的设计方案; (3)对所设计程序进行调试。 2)创新要求: 在基本要求达到后,可进行创新设计,如改算法效率。 3)课程设计论文编写要求 (1)要按照书稿的规格打印誊写课程设计论文 (2)论文包括目录、绪论、正文、小结、参考文献、附录等 (3)课程设计论文装订按学校的统一要求完成 4)答辩与评分标准: (1)完成原理分析:20分; (2)完成设计过程(含翻译):40分; (3)完成调试:20分;

(4)回答问题:20分。 5)参考文献: (1)张素琴,吕映芝,蒋维杜,戴桂兰.编译原理(第2版).清华大学出版社 (2)丁振凡.《Java语言实用教程》北京邮电大学出版社 6)课程设计进度安排 内容天数地点 构思及收集资料2图书馆 编程与调试4实验室 撰写论文1图书馆、实验室 学生签名: 2009 年6 月22 日 课程设计(论文)评审意见 (1)完成原理分析(20分):优()、良()、中()、一般()、差();(2)设计分析(20分):优()、良()、中()、一般()、差();(3)完成调试(20分):优()、良()、中()、一般()、差();(4)翻译能力(20分):优()、良()、中()、一般()、差();(5)回答问题(20分):优()、良()、中()、一般()、差();(6)格式规范性及考勤是否降等级:是()、否() 评阅人:职称: 年月日

编译原理课程设计报告(一个完整的编译器)

编译原理程序设计报告 一个简单文法的编译器的设计与实现专业班级:计算机1406班 组长姓名:宋世波 组长学号: 20143753 指导教师:肖桐 2016年12月

设计分工 组长学号及姓名:宋世波20143753 分工:文法及数据结构设计 词法分析 语法分析(LL1) 基于DAG的中间代码优化 部分目标代码生成 组员1学号及姓名:黄润华20143740 分工:中间代码生成(LR0) 部分目标代码生成 组员2学号及姓名:孙何奇20143754 分工:符号表组织 部分目标代码生成

摘要 编译器是将便于人编写,阅读,维护的高级计算机语言翻译为计算机能解读、运行的低阶机器语言的程序。编译是从源代码(通常为高阶语言)到能直接被计算机或虚拟机执行的目标代码(通常为低阶语言或机器语言)的翻译过程。 一.编译器的概述 1.编译器的概念 编译器是将便于人编写,阅读,维护的高级计算机语言翻译为计算机能解读、运行的低阶机器语言的程序。编译器将原始程序作为输入,翻译产生使用目标语言的等价程序。源代码一般为高阶语言如Pascal、C++、Java 等,而目标语言则是汇编语言或目标机器的目标代码,有时也称作机器代码。 2.编译器的种类 编译器可以生成用来在与编译器本身所在的计算机和操作系统(平台)相同的环境下运行的目标代码,这种编译器又叫做“本地”编译器。另外,编译器也可以生成用来在其它平台上运行的目标代码,这种编译器又叫做交叉编译器。交叉编译器在生成新的硬件平台时非常有用。“源码到源码编译器”是指用一种高阶语言作为输入,输出也是高阶语言的编译器。例如: 自动并行化编译器经常采用一种高阶语言作为输入,转换其中的代码,并用并行代码注释对它进行注释(如OpenMP)或者用语

编译原理实验报告

编译原理实验报告 班级 姓名: 学号: 自我评定:

实验一词法分析程序实现 一、实验目的与要求 通过编写和调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将字符形式的源程序流转化为一个由各类单词符号组成的流的词法分析方法。 二、实验内容 根据教学要求并结合学生自己的兴趣和具体情况,从具有代表性的高级程序设计语言的各类典型单词中,选取一个适当大小的子集。例如,可以完成无符号常数这一类典型单词的识别后,再完成一个尽可能兼顾到各种常数、关键字、标识符和各种运算符的扫描器的设计和实现。 输入:由符合或不符合所规定的单词类别结构的各类单词组成的源程序。 输出:把单词的字符形式的表示翻译成编译器的内部表示,即确定单词串的输出形式。例如,所输出的每一单词均按形如(CLASS,VALUE)的二元式编码。对于变量和常数,CLASS字段为相应的类别码;VALUE字段则是该标识符、常数的具体值或在其符号表中登记项的序号(要求在变量名表登记项中存放该标识符的字符串;常数表登记项中则存放该常数的二进制形式)。对于关键字和运算符,采用一词一类的编码形式;由于采用一词一类的编码方式,所以仅需在二元式的CLASS字段上放置相应的单词的类别码,VALUE字段则为“空”。另外,为便于查看由词法分析程序所输出的单词串,要求在CLASS字段上放置单词类别的助记符。 三、实现方法与环境 词法分析是编译程序的第一个处理阶段,可以通过两种途径来构造词法分析程序。其一是根据对语言中各类单词的某种描述或定义(如BNF),用手工的方式(例如可用C语言)构造词法分析程序。一般地,可以根据文法或状态转换图构造相应的状态矩阵,该状态矩阵同控制程序便组成了编译器的词法分析程序;也可以根据文法或状态转换图直接编写词法分析程序。构造词法分析程序的另外一种途径是所谓的词法分析程序的自动生成,即首先用正规式对语言中的各类单词符号进行词型描述,并分别指出在识别单词时,词法分析程序所应进行的语义处理工作,然后由一个所谓词法分析程序的构造程序对上述信息进行加工。如美国BELL实验室研制的LEX就是一个被广泛使用的词法分析程序的自动生成工具。 总的来说,开发一种新语言时,由于它的单词符号在不停地修改,采用LEX等工具生成的词法分析程序比较易于修改和维护。一旦一种语言确定了,则采用手工编写词法分析程序效率更高。 四、实验设计 1)题目1:试用手工编码方式构造识别以下给定单词的某一语言的词法分析程序。 语言中具有的单词包括五个有代表性的关键字begin、end、if、then、else;标识符;整型常数;六种关系运算符;一个赋值符和四个算术运算符。参考实现方法简述如下。 单词的分类:构造上述语言中的各类单词符号及其分类码表。 表I 语言中的各类单词符号及其分类码表 单词符号类别编码类别码的助记符单词值

编译原理报告 (2)

课程实验报告课程名称:《编译原理》 专业班级:信息安全1302 学号: 姓名: 指导教师: 报告日期:2015年11月6日 计算机科学与技术学院

目录 目录 (2) 1 实验一词法分析 (3) 1.1实验目的 (3) 1.2实验要求 (3) 1.3算法思想 (4) 1.4实验程序设计说明 (5) 1.5词法分析实现 (6) 1.6词法实验结果及结果分析 (11) 2 实验二语法分析 (12) 2.1 实验目的 (12) 2.2 实验要求 (12) 2.3 算法思想 (12) 2.4 实验程序设计说明 (14) 2.5 语法分析实现 (14) 4 实验中遇到的问题及解决 (22) 参考资料 (23)

1 实验一词法分析 1.1 实验目的 设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。 1.2 实验要求 1、待分析的简单的词法 (1)关键字: main int char if else for while 所有的关键字都是小写。 (2)运算符和界符 := + -* / < <= <> > >= = == != ; ( ) [ ] { } #(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义: ID = letter (letter | digit)* NUM = digit digit* (4)空格有空白、制表符和换行符组成。空格一般用来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。 2、各种单词符号对应的种别码: 表1 各种单词符号对应的种别码

3、词法分析程序的功能: 输入:所给文法的源程序字符串。 输出:二元组(syn,token或sum)构成的序列。 其中:syn为单词种别码; token为存放的单词自身字符串; sum为整型常数。 例如:对源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件,经过词法分析后输出如下序列: (1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)…… 1.3 算法思想 算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。 1、主程序示意图: 主程序示意图如图1所示。其中初始包括以下两个方面: ⑴关键字表的初值。 关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。如能查到匹配的单词,则该单词为关键字,否则为一般标识符。关键字表为一个字符串数组,其描述如下: Char *rwtab[6] = {“begin”, “if”, “then”, “while”, “do”, “end”,}; 开始 置初值 调用扫描子程序 输出单词二元组 否 输入串结束? 是 结束 图1 主程序示意图

(重庆理工大学计算机学院)编译原理课程设计报告

编译原理课程设计报告 实验名称编译原理课程设计 班级 学号 姓名 指导教师 实验成绩 2013 年06月

一、实验目的 通过设计、编写和调试,将正规式转换为不确定的有穷自动机,再将不确定的有穷自动机转换为与之等价的确定的有穷自动机,最后再将确定有穷自动机进行简化。 通过设计、编写和调试构造LR(0)项目集规范簇和LR分析表、对给定的符号串进行LR分析的程序,了解构造LR(0)分析表的步骤,对文法的要求,能够从文法G出发生成LR(0)分析表,并对给定的符号串进行分析。 二、实验内容 正规式——>NFA——>DFA——>MFA 1.正规式转化为不确定的有穷自动机 (1)目的与要求 通过设计、编写和调试将正规式转换为不确定的有穷自动机的程序,使学生了解Thompson算法,掌握转换过程中的相关概念和方法,NFA的表现形式可以是表格或图形。 (2)问题描述 任意给定一个正规式r(包括连接、或、闭包运算),根据Thompson算法设计一个程序,生成与该正规式等价的NFA N。 (3)算法描述 对于Σ上的每个正规式R,可以构造一个Σ上的NFA M,使得L(M)=L(R)。 步骤1:首先构造基本符号的有穷自动机。 步骤2:其次构造连接、或和闭包运算的有穷自动机。

(4)基本要求 算法实现的基本要求是: (1) 输入一个正规式r; (2) 输出与正规式r等价的NFA。(5)测试数据 输入正规式:(a|b)*(aa|bb)(a|b)* 得到与之等价的NFA N

(6)输出结果 2.不确定的有穷自动机的确定化 (1)目的与要求 通过设计、编写和调试将不确定的有穷自动机转换为与之等价的确定的有穷自动机的程序,使学生了解子集法,掌握转换过程中的相关概念和方法。DFA的表现形式可以是表格或图形。(2)问题描述 任意给定一个不确定的有穷自动机N,根据算法设计一个程序,将该NFA N变换为与之等价的DFA D。 (3)算法描述 用子集法将NFA转换成接受同样语言的DFA。 步骤一:对状态图进行改造 (1) 增加状态X,Y,使之成为新的唯一的初态和终态。从X引ε弧到原初态结点, 从原终态结 点引ε弧到Y结点。 (2) 对状态图进一步进行如下形式的改变

大学编译原理课程复习试题及答案

编译原理复习材料 选择题 1. 文法S→0S | S1 | 0的语言是( )。 A. { 0 m1m| m >=0 } B. { 0 m1m| m >=1 } C. { 0 m1n | m>=1,n>=0 } D. { 0 m1n | m>=0,n>=1 } 2. 描述程序语言所采用的Ⅲ型文法是( )。 A. 短语文法 B.正规文法 C.上下文无关文法 D.上下文有关文法 3. 状态转换图实现的简单方法是使每个状态结对应( )。 A.一个终结符 B.一个非终结符 C.一段小程序 D.一个函数 4. 规范归约的关键问题是寻找( )。 A. 最左素短语 B.句柄 C.直接短语 D.短语 5. 一个算符文法的任何产生式的右部都不含有两个相继的( )。 A.终结符 B.非终结符 C.终结符和非终结符 D.空字 6. 算符优先分析法的关键在于规定( )。 A.算符优先顺序和结合性质 B.算符优先顺序 C.结合性质 D.终结符和非终结符之间关系 7. 优先函数的优点是( )。 A.形象直观 B.便于进行比较运算 C.语法分析速度快 D.语法分析方法简单 8. 文法符号的属性通常分为( )两类。 A. 共用属性和私有属性 B.固有属性和可变属性 C.语法属性和语义属性 D.综合属性和继承属性 9. 在程序流图中,组成循环的结点序列应满足( ) A. 它们是强连通的 B.它们中间有唯一的入口结点 C.它们中间有一条回边 D.它们是强连通的且有唯一的入 口结点 10. 在利用寄存器R生成T1:=C/B的目标代码同时,还应记录信息( )。 A. C/B在T1中 B. T1在C/B中 C. R含有T1, T1在R中 D. R含有C/B, C/B在R中 1.D 2.B 3.C 4.B 5.B 6.A 7.B 8.D 9.D 10.C

编译原理实验报告总结

学年第学期《编译原理》实验报告 学院(系):计算机科学与工程学院 班级:11303070A 学号:11303070*** 姓名:无名氏 指导教师:保密式 时间:2016 年7 月

目录 1.实验目的 (1) 2.实验内容及要求 (1) 3.实验方案设计 (1) 3.1 编译系统原理介绍 (1) 3.1.1 编译程序介绍 (2) 3.1.2 对所写编译程序的源语言的描述 (2) 3.2 词法分析程序的设计 (3) 3.3 语法分析程序设计 (4) 3.4 语义分析和中间代码生成程序的设计 (4) 4. 结果及测试分析 (4) 4.1软件运行环境及限制 (4) 4.2测试数据说明 (5) 4.3运行结果及功能说明 (5) 5.总结及心得体会 (7)

1.实验目的 根据Sample语言或者自定义的某种语言,设计该语言的编译前端。包括词法分析,语法分析、语义分析及中间代码生成部分。 2.实验内容及要求 (1)词法分析器 输入源程序,输出对应的token表,符号表和词法错误信息。按规则拼单词,并转换成二元形式;滤掉空白符,跳过注释、换行符及一些无用的符号;进行行列计数,用于指出出错的行列号,并复制出错部分;列表打印源程序;发现并定位词法错误; (2)语法分析器 输入token串,通过语法分析,寻找其中的语法错误。要求能实现Sample 语言或自定义语言中几种最常见的、基本的语法单位的分析:算术表达式、布尔表达式、赋值语句、if语句、for语句、while语句、do while语句等。 (3)语义分析和中间代码生成 输入token串,进行语义分析,修改符号表,寻找其中的语义错误,并生 成中间代码。要求能实现Sample语言或自定义语言中几种最常见的、基本的语法单位的分析:算术表达式、布尔表达式、赋值语句、if语句、for语句、while 语句、do while语句等。 实验要求:功能相对完善,有输入、输出描述,有测试数据,并介绍不足。3.实验方案设计 3.1 编译系统原理介绍 编译器逐行扫描高级语言程序源程序,编译的过程如下: (1).词法分析 识别关键字、字面量、标识符(变量名、数据名)、运算符、注释行(给人看的,一般不处理)、特殊符号(续行、语句结束、数组)等六类符号,分别归类等待处理。 (2).语法分析 一个语句看作一串记号(Token)流,由语法分析器进行处理。按照语言的文法检查判定是否是合乎语法的句子。如果是合法句子就以内部格式保存,否则报错。直至检查完整个程序。 (3).语义分析 语义分析器对各句子的语法做检查:运算符两边类型是否相兼容;该做哪些类型转换(例如,实数向整数赋值要"取整");控制转移是否到不该去的地方;是

CMinus词法分析和语法分析设计编译器编译原理课程设计报告书

编译原理课程设计报告 课题名称:C- Minus词法分析和语法分析设计 提交文档学生姓名:X X X 提交文档学生学号:XXXXXXXXXX 同组成员名单:X X X 指导教师姓名:X X 指导教师评阅成绩: 指导教师评阅意见: . . 提交报告时间:2015年6月10日

1.课程设计目标 实验建立C-编译器。只含有扫描程序(scanner)和语法分析(parser)部分。 2.分析与设计 C-编译器设计的整体框架,本实验实现扫描处理和语法分析程序(图中粗黑部分)。 2.1 、扫描程序scanner部分 2.1.1系统设计思想 设计思想:根据DFA图用switch-case结构实现状态转换。 惯用词法:

①语言的关键字:else if int return void while ②专用符号:+ - * / < <= > >= == != = ; , ( ) [ ] { } /* */ ③其他标记是ID和NUM,通过下列正则表达式定义: ID = letter letter* NUM = digit digit* letter = a|..|z|A|..|Z digit = 0|..|9 大写和小写字母是有区别的 ④空格由空白、换行符和制表符组成。空格通常被忽略,除了它必须分开ID、NUM 关键字。 ⑤注释用通常的C语言符号/ * . . . * /围起来。注释可以放在任何空白出现的位置(即注释不能放在标记内)上,且可以超过一行。注释不能嵌套 scanner的DFA

说明:当输入的字符使DFA到达接受状态的时候,则可以确定一个单词了。初始状态设置为START,当需要得到下一个token时,取得次token的第一个字符,并且按照DFA与对此字符的类型分析,转换状态。重复此步骤,直到DONE为止,输出token类型。当字符为“/”时,状态转换为SLAH再判断下一个字符,如果为“*”则继续转到INCOMMENT,最后以“*”时转到ENDCOMMENT状态,表明是注释,如果其他的则是字符停滞于当前字符,并且输出“/”。 2.1.2程序流程图

编译原理课设报告2

编译原理课程设计题目:pl/0编译程序的改进与完善 学生所在学院:信息科学与工程学院 学生所在班级:06级计算机软件1班 学生姓名: 学生学号: 指导教师:张世辉

一、课设目的: 1.阅读、研究、改进、设计和调试一个简单的编译程序; 2.加深对编译程序理论和编译过程的理解。 二、课设内容: 1扩充语句for(<语句>;<条件>;<语句>)<语句>; 2扩充语句if <条件> then <语句> else <语句>; 3扩充语句repeat <语句>;until <条件>; 4增加自增自减运算++和—和+=,-=运算; 5修改不等号#,为!=; 6增加一维数组 声明格式:[/:/]; 赋值格式:[]:=<表达式>; 调用格式:[] 三、程序结构: PL/0源程序 图1 编译程序结构图2功能模块调用

1.各功能模块的作用: Pl0.c:主程序 Error:出错处理,打印出错位置和错误编码 Getsym:词法分析,读取一个单词 Getch:漏掉空格,读取一个字符 Gen:生成目标代码,并送入目标程序区 Test:测试当前当前符号是否合法 Block:分程序分析处理过程,词法语法分析 Enter:登陆名字表 Position:查找标识符在名字表中的位置 Constdeclaration:常量定义处理 Vardeclaraction:变量说明处理 Listcode:列出目标代码清单 Statement:语句处理 Expression:表达式处理 Term:项处理 Factor:因子处理 Condition:条件处理 Interpret:对目标代码的解释执行程序 Base:通过静态链求出数据取得基地址 增加两个功能: Arraydeclaration:数组声明处理 Arraycoef:数组索引计算和“虚拟机”动作生成 2.保留字: enum symbol {nul, ident, number, plus, minus, times, slash, oddsym, eql, neq, lss, leq, gtr, geq, lparen, rparen, comma, semicolon, period, becomes, beginsym, endsym, ifsym, thensym,elsesym, forsym, inc, dec, whilesym, writesym, readsym, dosym, callsym, constsym,varsym, procsym, repeatsym, untilsym, plusbk, minusbk, lbrack, rbrack, colon,} 共43个,其中补充保留字为:else, for, repeat, until, plusbk, minusbk,

编 译 原 理 实 验 报 告

编译原理实验报告 课程:编译原理 系别:计算机系 班级:11网络 姓名:王佳明 学号:110912049 教师:刘老师 实验小组:第二组 1

实验一熟悉C程序开发环境、进行简单程序的调试 实验目的: 1、初步了解vc++6.0环境; 2、熟悉掌握调试c程序的步骤: 实验内容: 1、输入下列程序,练习Turbo C 程序的编辑、编译、运行。 #include main() { printf(“Programming is fun.\n”); } 2、分析程序,预测其运行结果,并上机检测你的预测。 #include main() { printf(“*\n”); printf(“* * *\n”); printf(“* * * * *\n”); printf(“* * * * * * *\n”); } 3、下面是一个加法程序,程序运行时等待用户从键盘输入两个整数,然后求出它们的和并输出。观察运行结果(程序输出),上机验证该程序。 #include main() { int a,b,c; printf(“Please input a,b:”); scanf(“%d,%d”,&a,&b); c=a+b; printf(“%d+%d=%d\n”,a,b,c); } 2

实验二词法分析器 一、实验目的: 设计、编制、调试一个词法分析子程序-识别单词,加深对词法分析原理的理解。 二、实验要求: 1.对给定的程序通过词法分析器弄够识别一个个单词符号,并以二元式(单词种别码,单词符号的属性值)显示。而本程序则是通过对给定路径的文件的分析后以单词符号和文字提示显示。 2.本程序自行规定: (1)关键字"begin","end","if","then","else","while","write","read", "do", "call","const","char","until","procedure","repeat" (2)运算符:"+","-","*","/","=" (3)界符:"{","}","[","]",";",",",".","(",")",":" (4)其他标记如字符串,表示以字母开头的标识符。 (5)空格、回车、换行符跳过。 在屏幕上显示如下: ( 1 , 无符号整数) ( begin , 关键字) ( if , 关键字) ( +, 运算符) ( ;, 界符) ( a , 普通标识符) 三、使用环境: Windows下的visual c++6.0; 四、调试程序: 1.举例说明文件位置:f:、、11.txt目标程序如下: begin x:=9 if x>0 then x:=x+1; while a:=0 do 3

编译原理课程设计

先简要分析一下语法分析的大致流程: 当有句子要进行处理时,首先要对其进行词法分析来分解出该句子中的每个符号,然后将该句子按照算符优先算法压入归约栈中,如果可以顺利归约,则说明这是一个合法的句子,否则该句子非法。 这里有一个需要考虑的地方,就是如何进行归约。由于文法已经给定,所以我们考虑设计一个文法表,文法表中的内容就是可归约串的种别码的顺序,比如v=E可以表示为9,1,13。这样的话当我们要进行一次归约时,只用按顺序存储最左素短语中符号的种别码,然后拿这个种别码序列与文法表进行匹配,就可知道当前归约需要执行哪些操作。 还有一点需要注意,就是如何对一个表达式进行求值。这里需要我们设计一个二元组的变量名表,这个变量名表可以根据变量的名称来返回变量的数据。变量名表的具体设计见详细设计部分。 由于是简化分析,所以这个程序只考虑整数的处理。 有了上面的分析,可以构造出算符优先分析算法的流程图,如下图所示。

详细设计 (1)词法分析部分 由于词法分析的内容在课程设计1中已经介绍,并且这次的状态转换图与课程设计1中的非常相似,所以这里就不过多介绍。(2)优先关系表 在程序中我们用一个二维数组priTable[][]来存储算符间的优先关系。priTable[a][b]=1表示a>b; 。priTable[a][b]=0表示a=b; 。priTable[a][b]=-1表示a

编译原理实验报告一

实验一词法分析程序实现 一、实验目得与要求 通过编写与调试一个词法分析程序,掌握在对程序设计语言得源程序进行扫描得过程中,将字符流形式得源程序转化为一个由各类单词符号组成得流得词法分析方法 二、实验内容 基本实验题目:若某一程序设计语言中得单词包括五个关键字begin、end、if、then、else;标识符;无符号常数;六种关系运算符;一个赋值符与四个算术运算符,试构造能识别这些单词得词法分析程序(各类单词得分类码参见表I)。 表I语言中得各类单词符号及其分类码表 输入:由符合与不符合所规定得单词类别结构得各类单词组成得源程序文件。 输出:把所识别出得每一单词均按形如(CLASS,VALUE)得二元式形式输出,并将结果放到某个文件中。对于标识符与无符号常数,CLASS字段为相应得类别码得助记符;V AL UE字段则就是该标识符、常数得具体值;对于关键字与运算符,采用一词一类得编码形式,仅需在二元式得CLASS字段上放置相应单词得类别码得助记符,V ALUE字段则为“空". 三、实现方法与环境 词法分析就是编译程序得第一个处理阶段,可以通过两种途径来构造词法分析程序.其一就是根据对语言中各类单词得某种描述或定义(如BNF),用手工得方式(例如可用C语言)构造词法分析程序。一般地,可以根据文法或状态转换图构造相应得状态矩阵,该状态矩阵连同控制程序一起便组成了编译器得词法分析程序;也可以根据文法或状态转换图直接编写词法分析程序。构造词法分析程序得另外一种途径就是所谓得词法分析程序得自动生成,即首先用正规式对语言中得各类单词符号进行词型描述,并分别指出在识别单词时,词法分析程

编译原理标准实验报告

电子科技大学 实验报告 学生姓名:学号:指导教师: 实验地点:实验时间: 一、实验室名称:计算机学院软件工程实验室 二、实验项目名称:词法分析器的设计与实现 三、实验学时:4学时 四、实验原理 1.编译程序要求对高级语言编写的源程序进行分析和合成,生成目标程序。词法分析是对源程序进行的首次分析,实现词法分析的程序为词法分析程序。 2.词法分析的功能是从左到右逐个地扫描源程序字符串,按照词法规则识别出单词符号作为输出,对识别过程中发现的词法错误,输出相关信息。 3.状态转换图是有限有向图,是设计词法分析器的有效工具。 五、实验目的 通过设计词法分析器的实验,使同学们了解和掌握词法分析程序设计的原理及相应的程序设计方法,同时提高编程能力。 六、实验内容 实现求n!的极小语言的词法分析程序,返回二元式作为输出。 七、实验器材(设备、元器件) 1.操作系统:Windows XP

2.开发工具:VC6.0 3.普通PC即可 八、实验步骤 (1)启动VC6.0,创建空白工程项目。选择菜单中的“文件”->“新建”->“项目”,在弹出的对话框中,左边的“项目类型”框中,选择“Visual C++ 项目”,在右边框中,选择“空项目(.Net)”,在对话框下边,选择工程文件存放目录及输入名称,如Example1,单击“确定”。 (2)建立相应的单词符号与种别对照表; (3)根据状态转换图编写相应的处理函数; (4)完成词法分析器; (5)编译与调试以上程序; (6)生成相应的*.dyd文件,作为后面语法分析的输入文件。 九、实验数据及结果分析

可以对源程序进行词法分析,如果有错给出出错信息和所在行数,如果无错则生成二元式文件。 十、实验结论 本实验程序较好地完成了词法分析程序的设计与实现,能够对所给文法的程序进行词法分析,在没有词法错误的时候生成相应的二元式文件。该实验程序可一次性给出源程序中的词法错误。 十一、总结及心得体会 通过该实验,对词法分析程序的设计,以及运用C语言进行编程有了更深刻的理解,同时加深了自己对词法分析程序的原理的理解与掌握,提高了自己的动手能力。 十二、对本实验过程及方法、手段的改进建议 程序设计合理,代码可进一步优化。 报告评分: 指导教师签字:

编译原理实验报告

《编译原理》实验报告软件131 陈万全132852

一、需求分析 通过对一个常用高级程序设计语言的简单语言子集编译系统中词法分析、语法分析、语义处理模块的设计、开发,掌握实际编译系统的核心结构、工作流程及其实现技术,获得分析、设计、实现编译程序等方面的实际操作能力,增强设计、编写和调试程序的能力。 通过开源编译器分析、编译过程可视化等扩展实验,促进学生增强复杂系统分析、设计和实现能力,鼓励学生创新意识和能力。 1、词法分析程序设计与实现 假定一种高级程序设计语言中的单词主要包括五个关键字begin、end、if、then、else;标识符;无符号常数;六种关系运算符;一个赋值符和四个算术运算符,试构造能识别这些单词的词法分析程序。 输入:由符合和不符合所规定的单词类别结构的各类单词组成的源程序文件。 输出:把所识别出的每一单词均按形如(CLASS,VALUE)的二元式形式输出,并将结果放到某个文件中。对于标识符和无符号常数,CLASS字段为相应的类别码的助记符;VALUE字段则是该标识符、常数的具体值;对于关键字和运算符,采用一词一类的编码形式,仅需在二元式的CLASS字段上放置相应单词的类别码的助记符,VALUE字段则为“空”。 2、语法分析程序设计与实现 选择对各种常见高级程序设计语言都较为通用的语法结构——算术表达式的

一个简化子集——作为分析对象,根据如下描述其语法结构的BNF定义G2[<算术表达式>],任选一种学过的语法分析方法,针对运算对象为无符号常数和变量的四则运算,设计并实现一个语法分析程序。 G2[<算术表达式>]: <算术表达式>→<项> | <算术表达式>+<项> | <算术表达式>-<项> <项>→<因式>|<项>*<因式>|<项>/<因式> <因式>→<运算对象> | (<算术表达式>) 若将语法范畴<算术表达式>、<项>、<因式>和<运算对象>分别用E、T、F和i 代表,则G2可写成: G2[E]:E → T | E+T | E-T T → F | T*F | T/F F → i | (E) 输入:由实验一输出的单词串,例如:UCON,PL,UCON,MU,ID······输出:若输入源程序中的符号串是给定文法的句子,则输出“RIGHT”,并且给出每一步分析过程;若不是句子,即输入串有错误,则输出“ERROR”,并且显示分析至此所得的中间结果,如分析栈、符号栈中的信息等,以及必要的出错说明信息。 3、语义分析程序设计与实现 对文法G2[<算术表达式>]中的产生式添加语义处理子程序,完成运算对象是简单变量(标识符)和无符号数的四则运算的计值处理,将输入的四则运算转换为四元式形式的中间代码。 输入:包含测试用例(由标识符、无符号数和+、?、*、/、(、)构成的算术表达式)的源程序文件。 输出:将源程序转换为中间代码形式表示,并将中间代码序列输出到文件中。 若源程序中有错误,应指出错误信息 二、设计思路 1、词法分析程序设计与实现 1)单词分类 为了编程的实现。我们假定要编译的语言中,全部关键字都是保留字,程序员不得将它们作为源程序中的标识符;作了这些限制以后,就可以把关键字和标识符的识别统一进行处理。即每当开始识别一个单词时,若扫视到的第一个字符为字母,则把后续输入的字母或数字字符依次进行拼接,直至扫视到非字母、数字字符为止,以期获得一个尽可能长的字母数字字符串,然后以此字符串查所谓保留字表(此保留字表要事先造好),若查到此字符串,则取出相应的类别码;反之,则表明该字符串应为一标识符。

相关文档
最新文档