文档库 最新最全的文档下载
当前位置:文档库 › 编译原理pl0课本代码

编译原理pl0课本代码

编译原理pl0课本代码
编译原理pl0课本代码

//////////////////////////////////////

/////////Page 429

#include

//#include "pl0.h"

//typedef enum{

// false,

// true

//}bool;

#define norw 13 //关键字个数

#define txmax 100 //名字表容量

#define nmax 14 //number的最大位数

#define al 10 //符号的最大长度

#define amax 2047 //地址上界

#define levmax 3 //最大允许过程嵌套声名层数[0,levmax] #define cxmax 200 //最多的虚拟机代码数

//符号

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,whilesym,

writesym,readsym,dosym,callsym,constsym,

varsym,procsym,

};

#define symnum 32 //名字表中的类型

enum object{

constant,

variable,

procedur,

}; //虚拟机代码

enum fct

{

lit,opr,lod,

sto,cal,inte,

jmp,jpc,

};

#define fctnum 8

//虚拟机代码结构

struct instruction

{

enum fct f; //虚拟机代码指令

int l, //引用层与声明层的层次差

int a; //根据f的不同而不同

};

FILE *fas; //输出名字表

FILE *fa; //输出虚拟机代码

FILE *fa1; //输出源文件及其各行对应的首地址

FILE *fa2; //输出结果

bool listswitch; //显示虚拟机代码与否

bool tableswitch; //显示名字表与否

char ch; //获取字符的缓冲区,getch使用

enum symbol sym ; //当前的符号

char id[al+1]; //当前ident,多出的一个字节用于存放0

int num ; //当前number

int cc,ll; //getch使用的计数器,cc表示当前字符(ch)的位置int cx; //虚拟机代码指针,取值范围[0,cxmax-1]

char line[81]; //读取行缓冲区

char a[al+1]; //临时符号,多出的一个字节用于存放0 struct instruction code[cxmax]; //存放虚拟机代码的数组char word[norw][al]; //保留字

enum symbol wsym[norw]; //保留字对应的符号值

enum symbol ssym[256]; //单字符的符号值

char mnemonic[fctnum][5]; //虚拟机代码指令名称

bool declbegsys[symnum]; //表示声明开始的符号集合

bool statbegsys[symnum];//表示语句开始的符号集合

bool facbegsys[symnum];//表示因子开始的符号集合

////////////////////////////

////////Page 455

//名字表结构

struct tablestruct

{

char name[al];//名字

enum object kind; // 类型:const,var,array or procedure

int val; //数值,仅const使用

int level;//所处层,仅const不使用

int adr; //地址,仅const不使用

int size; //需要分配的数据区空间,仅procedure使用

};

struct tablestruct table[txmax];//名字表

FILE *fin;

FILE *fout;

char fname[al];

int err;

//当函数中会发生fatal error时,返回-1告知调用它的函数,最终退出程序

#define getsymdo if(-1==getsym())return -1

#define getchdo if(-1==getch())return -1

#define testdo(a,b,c) if(-1==test(a,b,c))return -1

#define gendo(a,b,c) if(-1==gen(a,b,c))return -1

#define expressiondo(a,b,c) if(-1==expression(a,b,c))return -1

#define factordo(a,b,c) if(-1==factor(a,b,c))return -1

#define termdo(a,b,c) if(-1==term(a,b,c))return -1

#define conditiondo(a,b,c) if(-1==condition(a,b,c))return -1

#define statementdo(a,b,c) if(-1==statement(a,b,c))return -1

#define constdeclarationdo(a,b,c) if(-1==constdeclaration(a,b,c))return -1

#define vardeclarationdo(a,b,c) if(-1==vardeclaration(a,b,c))return -1

void error(int n);

int getsym();

int getch();

void init();

int gen(enum fct x,int y,int z);

int test(bool *s1,bool *s2,int n);

int inset(int e,bool *s);

int addset(bool *sr,bool *s1,bool *s2,int n);

int subset(bool *sr,bool *s1,bool *s2,int n);

int mulset(bool *sr,bool *s1,bool *s2,int n);

int block(int lev,int tx,bool *fsys);

void interpret();

int factor(bool *fsys,int *ptx,int lev);

int term(bool *fsys,int *ptx,int lev);

int condition(bool *fsys,int *ptx,int lev);

int expression(bool *fsys,int *ptx,int lev);

int statement(bool *fsys,int *ptx,int lev);

void listcode(int cx0);

int vardeclaration(int *ptx,int lev,int *pdx);

int constdeclaration(int *ptx,int lev,int *pdx);

int position(char*idt,int tx);

void enter(enum object k,int *ptx,int lev,int *pdx);

int base(int l,int *s,int b);

#include "string.h"

#define stacksize 500

int main()

{

bool nxtlev[symnum];

printf("Input pl/0 file?");

scanf("%s",fname); //输入文件名以后恢复

// strcpy(fname,"begin");

fin=fopen(fname,"r");

if(fin)

{

printf("List object code?(Y/N)");//是否输入虚拟机代码

scanf("%s",fname);

listswitch=(fname[0]=='y'||fname[0]=='Y');

printf("List symbol table?(Y/N)"); //是否输出名字表

scanf("%s",fname);

tableswitch=(fname[0]=='y'||fname[0]=='Y');

fa1=fopen("fa1.tmp","w");

fprintf(fa1,"Input pl/0 file?");

fprintf(fa1,"%s\n",fname);

init(); //初始化

err=0;

cc=cx=ll=0;

ch=' ';

if(-1!=getsym())

{

fa=fopen("fa.tmp","w");

fas=fopen("fas.tmp","w");

//////////////////////////////////////////////

//////Page 430

addset(nxtlev,declbegsys,statbegsys,symnum);

nxtlev[period]=true;

if(-1==block(0,0,nxtlev)) //调用编译程序

{

fclose(fa);

fclose(fa1);

fclose(fas);

fclose(fin);

printf("\n");

return 0;

}

fclose(fa);

fclose(fa1);

fclose(fas);

if(sym!=period)

{

error(9);

}

if(err==0)

{

fa2=fopen("fa2.tmp","w");

interpret(); //调用解释执行程序

fclose(fa2);

}

else

{

printf("Errors in pl/0 program");

}

}

fclose(fin);

}

else

{

printf("Can't open file!\n");

}

printf("\n");

return 0;

}

void init()

{

int i;

//设置单字符符号

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

{

ssym[i]=nul;

}

ssym['+']=plus;

ssym['-']=minus;

ssym['*']=times;

ssym['/']=slash;

ssym['(']=lparen;

ssym[')']=rparen;

ssym['=']=eql;

ssym[',']=comma;

ssym['.']=period;

ssym['#']=neq;

ssym[';']=semicolon;

//设置保留字名字,按照字母顺序,便于折半查找strcpy(&(word[0][0]),"begin");

strcpy(&(word[1][0]),"call");

strcpy(&(word[2][0]),"const");

strcpy(&(word[3][0]),"do");

strcpy(&(word[4][0]),"end");

strcpy(&(word[5][0]),"if");

strcpy(&(word[6][0]),"odd");

strcpy(&(word[7][0]),"procedure");

strcpy(&(word[8][0]),"read");

strcpy(&(word[9][0]),"then");

strcpy(&(word[10][0]),"var");

strcpy(&(word[11][0]),"while");

strcpy(&(word[12][0]),"write");

//设置保留字符号

wsym[0]=beginsym;

wsym[1]=callsym;

wsym[2]=constsym;

wsym[3]=dosym;

wsym[4]=endsym;

wsym[5]=ifsym;

wsym[6]=oddsym;

wsym[7]=procsym;

wsym[8]=readsym;

wsym[9]=thensym;

wsym[10]=varsym;

wsym[11]=whilesym;

wsym[12]=writesym;

//设置指令名称

strcpy(&(mnemonic[lit][0]),"lit");

strcpy(&(mnemonic[opr][0]),"opr");

strcpy(&(mnemonic[lod][0]),"lod");

strcpy(&(mnemonic[sto][0]),"sto");

strcpy(&(mnemonic[cal][0]),"cal");

strcpy(&(mnemonic[inte][0]),"inte");

strcpy(&(mnemonic[jmp][0]),"jmp");

strcpy(&(mnemonic[jpc][0]),"jpc");

//设置符号集

for(i=0;i

{

declbegsys[i]=false;

statbegsys[i]=false;

facbegsys[i]=false;

}

//设置声明开始符号集

declbegsys[constsym]=true;

declbegsys[varsym]=true;

declbegsys[procsym]=true;

//设置语句开始符号集

statbegsys[beginsym]=true;

statbegsys[callsym]=true;

statbegsys[ifsym]=true;

//设置因子开始符号集

facbegsys[ident]=true;

facbegsys[number]=true;

facbegsys[lparen]=true;

}

//用数组实现集合的集合运算

int inset(int e,bool *s)

{

return s[e];

}

int addset(bool *sr,bool *s1,bool *s2,int n)

{

int i;

for(i=0;i

{

sr[i]=s1[i]||s2[i];

}

return 0;

}

int subset(bool *sr,bool *s1,bool *s2,int n)

{

int i;

for(i=0;i

{

sr[i]=s1[i]&&(!s2[i]);

}

return 0;

}

int mulset(bool *sr,bool *s1,bool *s2,int n)

{

int i;

for(i=0;i

{

sr[i]=s1[i]&&s2[i];

}

return 0;

}

void error(int n)

{

char space[81];

memset(space,32,81);

space[cc-1]=0; //出错时当前符号已经读完,所以cc-1

printf("****%s!%d\n",space,n);

fprintf(fa1,"****%s!%d\n",space,n);

err++;

}

int getch()

{

if(cc==ll)

{

if(feof(fin))

{

printf("program incomplete");

return -1;

}

ll=0;

cc=0;

printf("%d",cx);

fprintf(fa1,"%d",cx);

ch=' ';

while(ch!=10)

{

//fscanf(fin,"%c",&ch)

if(EOF==fscanf(fin,"%c",&ch))

{

line[ll]=0;

break;

}

printf("%c",ch);

fprintf(fa1,"%c",ch);

line[ll]=ch;

ll++;

}

printf("\n");

fprintf(fa1,"\n");

}

ch=line[cc];

cc++;

return 0;

}

//////////////////////////////////////////

//////////词法分析,获取一个符号

int getsym()

{

int i,j,k;

while(ch==' '||ch==10||ch==9) //忽略空格,换行和tab {

getchdo;

}

if(ch>='a'&&ch<='z')

{

k=0;

do

{

if(k

{

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')

{ //检测是否为数字:以0...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=='<') //检测i小于或小于等于符号

{

getchdo;

if(ch=='=')

{

sym=leq;

getchdo;

}

else

{

sym=lss;

}

}

else

{

if(ch=='>') //检测大于或大于等于符号

{

getchdo;

if(ch=='=')

{

sym=geq;

getchdo;

}

else

{

sym=gtr;

}

}

else

{

sym=ssym[ch];//当符号不满足上述条件时,全部按照单字符符号处理

//getchdo

//rechjard

if(sym!=period)

{

getchdo;

}

//end richard

}

}

}

}

}

return 0;

}

int gen(enum fct x,int y,int z)

{

if(cx>=cxmax)

{

printf("Program too long"); //程序过长

return -1;

}

code[cx].f=x;

code[cx].l=y;

code[cx].a=z;

cx++;

return 0;

}

////////////////////////////////////////////////

//测试当前符号是否合法

//在某一部分(如一条语句,一个表达式)将要结束时,我们希望下一个符号属于某集合//(该部分的后跟符号),test负责这项检测,并且负责当检测不通过时的补救措施

//程序在需要检测时指定当前需要的符号集合和补救用的集合(如之前未完成部分的后跟符号),以及检测不通过时的错误符号

//s1:我们需要的符号

//s2:如果不是我们需要的,则需要一个补救用的集合

//n:错误号

int test(bool *s1,bool *s2,int n)

{

if(!inset(sym,s1))

{

error(n);

//当检测不通过时,不停获取符号,直到它属于需要的集合或补救的集合

while((!inset(sym,s1))&&(!inset(sym,s2)))

{

getsymdo;

}

}

return 0;

}

///////////////////////////////

//编译程序主体

//lev:当前分程序所在层

//tx:名字表当前尾指针

//fsys:当前模块后跟符号集合

int block(int lev,int tx,bool *fsys)

{

int i;

int dx; //名字分配到的相对地址

int tx0; //保留初始tx

int cx0;//保留初始cx

bool nxtlev[symnum];//在下级函数的参数中,符号集合均为值参,但由于使用数组实现,

//传递进来的是指针,为防止下级函数改变上级函数的集合,

//开辟新的空间传递给下级函数

dx=3;

tx0=tx; //记录本层名字的初始位置

table[tx].adr=cx;

gendo(jmp,0,0);

if(lev>levmax)

{

error(32);

}

do

{

if(sym==constsym) //收到常量声明符号,开始处理常量声明

{

getsymdo;

do

{

constdeclarationdo(&tx,lev,&dx);//dx的值会被constdeclaration改变,使用指针

while(sym==comma)

{

getsymdo;

constdeclarationdo(&tx,lev,&dx);

}

if(sym==semicolon)

{

getsymdo;

}

else

{

error(5); //漏掉了逗号或者分号

}

}while(sym==ident);

}

if(sym==varsym) //收到变量声明符号,开始处理变量声明

{

getsymdo;

do

{

vardeclarationdo(&tx,lev,&dx);

while(sym==comma)

{

getsymdo;

vardeclarationdo(&tx,lev,&dx);

}

if(sym==semicolon)

{

getsymdo;

}

else

{

error(5);

}

}while(sym==ident);

}

while(sym==procsym) //收到过程声明符号,开始处理过程声明{

getsymdo;

if(sym==ident)

{

enter(procedur,&tx,lev,&dx);//记录过程名字

getsymdo;

}

else

{

error(4); //procedure后应为标识符

}

if(sym==semicolon)

{

getsymdo;

}

else

{

error(5); //漏掉分号

}

memcpy(nxtlev,fsys,sizeof(bool)*symnum);

nxtlev[semicolon]=true;

if(-1==block(lev+1,tx,nxtlev))

{

return -1; //递归调用

}

if(sym==semicolon)

{

getsymdo;

memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);

nxtlev[ident]=true;

nxtlev[procsym]=true;

testdo(nxtlev,fsys,6);

}

else

{

error(5); //漏掉分号

}

}

memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);

nxtlev[ident]=true;

nxtlev[period]=true;

testdo(nxtlev,declbegsys,7);

}while(inset(sym,declbegsys)); //直到没有声明符号

code[table[tx0].adr].a=cx;//开始生成当前过程代码

table[tx0].adr=cx; //当前过程代码地址

table[tx0].size=dx;//声明部分中每增加一条声明都会给dx增加1,声明部分已经结束,dx就是当前过程数据的size

cx0=cx;

gendo(inte,0,dx); //生成分配内存代码

if(tableswitch) //输出名字表

{

printf("TABLE:\n");

if(tx0+1>tx)

{

printf("NULL\n");

}

for(i=tx0+1;i<=tx;i++)

{

switch(table[i].kind)

{

case constant:

printf("%d const %s ",i,table[i].name);

printf("val=%d\n",table[i].val);

fprintf(fas,"%d const %s ",i,table[i].name);

fprintf(fas,"val=%d\n",table[i].val);

break;

case variable:

printf("%d var %s ",i,table[i].name);

printf("lev=%d addr=%d\n",table[i].level,table[i].adr);

fprintf(fas,"%d var %s ",i,table[i].name);

fprintf(fas,"lev=%d addr=%d\n",table[i].level,table[i].adr);

break;

case procedur:

printf("%d proc%s ",i,table[i].name);

printf("lev=%d addr=%d size=%d\n",table[i].level,table[i].adr,table[i].size);

fprintf(fas,"%d proc %s ",i,table[i].name);

fprintf(fas,"lev=%d addr=%d size=%d\n",table[i].level,table[i].adr,table[i].size);

break;

}

}

printf("\n");

}

//语句后跟符号为分号或end

memcpy(nxtlev,fsys,sizeof(bool)*symnum);//每个后跟符号集和都包含上层后跟符号集合,以便补救

nxtlev[semicolon]=true;

nxtlev[endsym]=true;

statementdo(nxtlev,&tx,lev);

gendo(opr,0,0);//每个过程出口都要使用的释放数据段指令

memset(nxtlev,0,sizeof(bool)*symnum);//分程序没有补救集合

testdo(fsys,nxtlev,8);//检测后跟符号正确性

listcode(cx0);// 输出代码

return 0;

}

void enter(enum object k,int *ptx,int lev,int *pdx)

{

(*ptx)++;

strcpy(table[(*ptx)].name,id); //全局变量id中已存有当前名字的名字

table[(*ptx)].kind=k;

switch(k)

{

case constant: //常量名字

if(num>amax)

{

error(31);

num=0;//数越界

}

table[(*ptx)].val=num;

break;

case variable: //变量名字

table[(*ptx)].level=lev;

table[(*ptx)].adr=(*pdx);

(*pdx)++;

break;

case procedur: //过程名字

table[(*ptx)].level=lev;

break;

}

}

/////////////////////////////////////////

//查找名字的位置

//找到则返回在名字表中的位置,否则返回0 //idt:要查找的名字

//tx:当前名字表尾指针

int position(char *idt,int tx)

{

int i;

strcpy(table[0].name,idt);

i=tx;

while(strcmp(table[i].name,idt)!=0)

{

i--;

}

return i;

}

///////////////

//常量声明处理

int constdeclaration(int *ptx,int lev,int *pdx) {

if(sym==ident)

{

getsymdo;

if(sym==eql||sym==becomes)

{

if(sym==becomes)

{

error(1); //把=写成了:=

}

getsymdo;

if(sym==number)

{

enter(constant,ptx,lev,pdx);

getsymdo;

}

else

{

error(2); //常量说明=后应是数字

}

}

else

{

error(3); //常量说明标识后应是=

}

}

else

{

error(4);//const后应是标识

}

return 0;

}

///////////////////////////////////////////

//变量声明处理

int vardeclaration(int *ptx,int lev,int *pdx)

{

if(sym==ident)

{

enter(variable,ptx,lev,pdx); //填写名字表

getsymdo;

}

else

{

error(4); //var后应是标识

}

return 0;

}

//////////////////////////////////////////

//输出目标代码清单

void listcode(int cx0)

{

int i;

if(listswitch)

{

for(i=cx0;i

{

printf("****%d %s %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);

// printf("****%d %s %d %d\n",i,code[i].f,code[i].l,code[i].a);

fprintf(fa,"%d %s %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);

}

}

}

int statement(bool *fsys,int *ptx,int lev)

{

int i,cx1,cx2;

bool nxtlev[symnum];

if(sym==ident) //准备按照赋值语句处理

{

i=position(id,*ptx);

if(i==0)

{

error(11); //变量未找到

}

else

{

if(table[i].kind!=variable)

{

error(12); //赋值语句格式错误

i=0;

}

else

{

getsymdo;

if(sym==becomes)

编译原理课程设计

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

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

编译原理实验指导

编译原理实验指导 实验安排: 上机实践按小组完成实验任务。每小组三人,分别完成TEST语言的词法分析、语法分析、语义分析和中间代码生成三个题目,语法分析部分可任意选择一种语法分析方法。先各自调试运行,然后每小组将程序连接在一起调试,构成一个相对完整的编译器。 实验报告: 上机结束后提交实验报告,报告内容: 1.小组成员; 2.个人完成的任务; 3.分析及设计的过程; 4.程序的连接; 5.设计中遇到的问题及解决方案; 6.总结。

实验一词法分析 一、实验目的 通过设计编制调试TEST语言的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。 编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。 二、实验预习提示 1.词法分析器的功能和输出格式 词法分析器的功能是输入源程序,输出单词符号。词法分析器的单词符号常常表示 成以下的二元式(单词种别码,单词符号的属性值)。 2.TEST语言的词法规则 |ID|ID |NUM →a|b|…|z|A|B|…|Z →1|2|…|9|0 →+|-|*|/|=|(|)|{|}|:|,|;|<|>|! →>=|<=|!=|== →/* →*/ 三、实验过程和指导 1.阅读课本有关章节,明确语言的语法,画出状态图和词法分析算法流程图。 2.编制好程序。 3.准备好多组测试数据。 4.程序要求 程序输入/输出示例:

编译原理实验代码

[实验任务] 完成以下正则文法所描述的Pascal语言子集单词符号的词法分析程序。 <标识符>→字母︱<标识符>字母︱<标识符>数字 <无符号整数>→数字︱<无符号整数>数字 <单字符分界符> →+ ︱-︱* ︱; ︱(︱) <双字符分界符>→<大于>=︱<小于>=︱<小于>>︱<冒号>=︱<斜竖>* <小于>→< <等于>→= <大于>→> <冒号> →: <斜竖> →/ 该语言的保留字:begin end if then else for do while and or not 说明:1 该语言大小写不敏感。 2 字母为a-z A-Z,数字为0-9。 3可以对上述文法进行扩充和改造。 4 ‘/*……*/’为程序的注释部分。 [设计要求] 1、给出各单词符号的类别编码。 2、词法分析程序应能发现输入串中的错误。 3、词法分析作为单独一遍编写,词法分析结果为二元式序列组成的中间文件。 4、设计两个测试用例(尽可能完备),并给出测试结果。 demo.cpp #include #include #include #include "demo.h" char token[20]; int lookup(char *token) { for (int i = 0; i < 11; i++) { if (strcmp(token, KEY_WORDS[i]) == 0) { return i+1; } } return 0; } char getletter(FILE *fp) { return tolower(fgetc(fp)); } void out(FILE *fp, int c, char *value) {

编译原理课程设计报告_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)格式规范性及考勤是否降等级:是()、否() 评阅人:职称: 年月日

编译原理实验报告一

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

编译原理课程设计

编译原理课程设计报告 课题名称: 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:

实验1-3 《编译原理》词法分析程序设计方案

实验1-3 《编译原理》S语言词法分析程序设计方案 一、实验目的 了解词法分析程序的两种设计方法之一:根据状态转换图直接编程的方式; 二、实验内容 1.根据状态转换图直接编程 编写一个词法分析程序,它从左到右逐个字符的对源程序进行扫描,产生一个个的单词的二元式,形成二元式(记号)流文件输出。在此,词法分析程序作为单独的一遍,如下图所示。 具体任务有: (1)组织源程序的输入 (2)拼出单词并查找其类别编号,形成二元式输出,得到单词流文件 (3)删除注释、空格和无用符号 (4)发现并定位词法错误,需要输出错误的位置在源程序中的第几行。将错误信息输出到屏幕上。 (5)对于普通标识符和常量,分别建立标识符表和常量表(使用线性表存储),当遇到一个标识符或常量时,查找标识符表或常量表,若存在,则返回位置,否则返回0并且填写符号表或常量表。 标识符表结构:变量名,类型(整型、实型、字符型),分配的数据区地址 注:词法分析阶段只填写变量名,其它部分在语法分析、语义分析、代码生成等阶段逐步填入。 常量表结构:常量名,常量值 三、实验要求 1.能对任何S语言源程序进行分析 在运行词法分析程序时,应该用问答形式输入要被分析的S源语言程序的文件名,然后对该程序完成词法分析任务。 2.能检查并处理某些词法分析错误 词法分析程序能给出的错误信息包括:总的出错个数,每个错误所在的行号,错误的编号及错误信息。 本实验要求处理以下两种错误(编号分别为1,2): 1:非法字符:单词表中不存在的字符处理为非法字符,处理方式是删除该字符,给出错误信息,“某某字符非法”。 2:源程序文件结束而注释未结束。注释格式为:/* …… */ 四、保留字和特殊符号表

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

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

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

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

编译原理实验指导书

编译原理实验指导 书

《编译原理》实验指导书 太原科技大学计算机学院 -3-1

序 《编译原理》是国内外各高等院校计算机科学技术类专业,特别是计算机软件专业的一门重要专业课程。该课程系统地向学生介绍编译程序的结构、工作流程及编译程序各组成部分的设计原理和实现技术。由于该课程理论性和实践性都比较强,内容较为抽象复杂,涉及到大量的软件设计和算法,因此,一直是一门比较难学的课程。为了使学生更好地理解和掌握编译原理和技术的基本概念、基本原理和实现方法,实践环节非常重要,只有经过上机进行程序设计,才能使学生对比较抽象的教学内容产生具体的感性认识,增强学生综合分析问题、解决问题的能力,并对提高学生软件设计水平大有益处。 为了配合《编译原理》课程的教学,考虑到本课程的内容和特点,本指导书设置了七个综合性实验,分别侧重于词法分析、NFA的确定化、非递归预测分析、算符优先分析器的构造、LR分析、语义分析和中间代码的生成、基于DAG的基本块优化,以支持编译程序的各个阶段,基本涵盖了《编译原理》课程的主要内容。 本指导书可作为《编译原理》课程的实验或课程设计内容,在课程教学的同时,安排学生进行相关的实验。实验平台可选择在MS-DOS或Windows操作系统环境,使用C/C++的任何版本作为开发工具。学生在做完试验后,应认真撰写实验报告,内容应

包括实验名称、实验目的、实验要求、实验内容、测试或运行结果等。

目录 实验一词法分析 ........................................................... 错误!未定义书签。实验二 NFA的确定化.................................................... 错误!未定义书签。实验三非递归预测分析 ............................................... 错误!未定义书签。实验四算符优先分析器的构造................................... 错误!未定义书签。实验五 LR分析 .............................................................. 错误!未定义书签。实验六语义分析和中间代码生成................................ 错误!未定义书签。实验七基于DAG的基本块优化................................... 错误!未定义书签。

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程序流程图

编译原理实验题目及报告要求

编译原理上机实验试题 一、实验目的 通过本实验使学生进一步熟悉和掌握程序设计语言的词法分析程序的设计原理及相关的设计技术, 如何针对确定的有限状态自动机进行编程序;熟悉和 掌握程序设计语言的语法分析程序的设计原理、熟悉 和掌握算符优先分析方法。 二、实验要求 本实验要求:①要求能熟练使用程序设计语言编程;②在上机之前要有详细的设计报告(预习报告); ③要编写出完成相应任务的程序并在计算机上准确 地运行;④实验结束后要写出上机实验报告。 三、实验题目 针对下面文法G(S): S→v = E E→E+E│E-E│E*E│E/E│(E)│v │i 其中,v为标识符,i为整型或实型数。要求完成 ①使用自动机技术实现一个词法分析程序; ②使用算符优先分析方法实现其语法分析程序,在 语法分析过程中同时完成常量表达式的计算。

1、题目(见“编译原理---实验题目.doc,“实验题目”中的第一项) 2、目的与要求(见“编译原理---实验题目.doc”) 3、设计原理: (1)单词分类:标识符,保留字,常数,运算符,分隔符等等 (2)单词类型编码 (3)自动机 4、程序流程框图 5、函数原型(参数,返回值) 6、关键代码(可打印,只打印关键代码) 7、调试: (1)调试过程中遇到的错误,如何改进的; (2)需要准备测试用例(至少3个,包含输入和输出)——(可打印) 8、思考: (1)你编写的程序有哪些要求是没有完成的,你觉得该采用什么方法去完成; (2)或者是你觉得程序有哪些地方可以进一步完善,简述你的完善方案。

1、题目(见“编译原理---实验题目.doc,“实验题目”中的第二项) 2、目的与要求(见“编译原理---实验题目.doc”) 3、设计原理:构造出算法优先关系表 4、程序流程框图 5、函数原型(参数,返回值) 6、关键代码(可打印,只打印关键代码) 7、调试: (1)调试过程中遇到的错误,如何改进的; (2)需要准备测试用例(至少3个,包含输入和输出)——(可打印) 8、思考: (1)你编写的程序有哪些要求是没有完成的,你觉得该采用什么方法去完成; (2)或者是你觉得程序有哪些地方可以进一步完善,简述你的完善方案。

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

编译原理课程设计报告 实验名称编译原理课程设计 班级 学号 姓名 指导教师 实验成绩 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) 对状态图进一步进行如下形式的改变

编译原理实验报告2

学生学号实验课成绩 武汉理工大学 学生实验报告书 实验课程名称编译原理 开课学院计算机科学与技术学院 指导老师姓名饶文碧 学生姓名 学生专业班级

—学年第学期 实验课程名称:编译原理 实验项目名称单词的词法分析实验成绩 实验者专业班级组别 同组者实验日期 第一部分:实验分析与设计(可加页) 一、实验内容描述(问题域描述) 完成对某一种常用高级语言(如Pascal、C语言、PL/0语言)的各类单词进行词法分析,即对源程序从左到右进行扫描,对组成源程序的字符串拼接成为单词;并把其转换成属性字输出。 实验要求: (1)选择常用高级程序设计语言(如 Pascal、C语言、PL/0语言)的源程序作为词法分析对象。 (2)根据教学要求和学生具体情况,从上列语言之一中选取它的一个适当大小的子集,可以选取一类典型单词,也可以尽可能使各种类型的单词都能兼顾到。其基本要求是:对源程序从左到右进行扫描,对组成源程序的字符串拼接成为单词,并把其转换成属性字输出。

二、实验基本原理与设计(包括实验方案设计,实验手段的确定,试验步骤等,用硬件逻辑或者算法描述) #include #include #include #include char *table[7]={" ","main","int","if","then","else","return"},TOKEN[20],ch; //定义关键字 int lookup(char *TOKEN){ //关键字匹配函数 int m,i; for(i=1;i<6;i++){ if((m=strcmp(TOKEN,table[i]))==0) return(i); } return(0); } void out(int c,char *TOKEN){ //输出函数 printf("(%d,%s)\n",c,TOKEN); } void scanner(FILE *fp){ //扫描函数

编译原理课程设计

编译原理课程设计 自顶向下语法分析器 学院(系):计算机科学与技术学院学生姓名:xxxxxxxxx 学号:xxxxxxxxx 班级:电计1102 大连理工大学 Dalian University of Technology

目录

1 系统概论 语法分析是编译过程的核心部分。它的任务是在词法分析识别出单词符号串的基础上,分析并判定程序的语法结构是否符合语法规则。语法分析器在编译程序中的地位如图1所示: 图1 语法分析器在编译程序中的地位 语言的语法结构是用上下文无关文法描述的。因此,语法分析器的工作本质上就是按文法的产生式,识别输入符号串是否为一个句子。这里所说的输入串是指由单词符号(文法的终结符)组成的有限序列。对一个文法,当给你一串(终结)符号时,怎样知道它是不是该文法的一个句子呢?这就要判断,看是否能从文法的开始符号出发推导出这个输入串。或者,从概念上讲,就是要建立一棵与输入串相匹配的语法分析树。 自顶向下分析法就是语法分析办法中的一类。顾名思义,自顶向下就是从文法的开始符号出发,向下推导,推出句子。这种方法是带“回溯”的。 自顶向下分析的主旨是,对任何输入串,试图用一切可能的办法,从文法开始符号(根结)出发,自上而下地为输入串建立一棵语法树。或者说,为输入串寻找一个最左推导。这种分析过程本质上是一种试探过程,是反复使用不同产生式谋求匹配输入串的过程。 实现这种自顶向下的带回溯试探法的一个简单途径是让每个非终结符对应一个递归子程序。每个这种子程序可作为一个布尔过程。一旦发现它的某个候选与输入串相匹配,就用这个候选去扩展语法树,并返回“真”值;否则,保持原来的语法树和IP值不变,并返回“假”值。 2 需求分析 以前,人们对语法的分析都建立在人工的基础上,人工分析虽然能够做到侧类旁推,但终究人力有限,再精密的分析都会出现或多或少的错误。为减少因人为产生的错误,并加快

编译原理实验:目标代码的生成

5. 目标代码生成 本章实验为实验四,是最后一次实验,其任务是在词法分析、语法分析、语义分析和中间代码生成程序的基础上,将C 源代码翻译为MIPS32指令序列(可以包含伪指令),并在SPIM Simulator上运行。当你完成实验四之后,你就拥有了一个自己独立编写、可以实际运行的编译器。 选择MIPS作为目标体系结构是因为它属于RISC范畴,与x86等体系结构相比形式简单便于我们处理。如果你对于MIPS体系结构或汇编语言不熟悉并不要紧,我们会提供详细的参考资料。 需要注意的是,由于本次实验的代码会与之前实验中你已经写好的代码进行对接,因此保持一个良好的代码风格、系统地设计代码结构和各模块之间的接口对于整个实验来讲相当重要。 5.1 实验内容 5.1.1 实验要求 为了完成实验四,我们建议你首先下载并安装SPIM Simulator用于对生成的目标代码进行检查和调试,SPIM Simulator的官方下载地址为:https://www.wendangku.net/doc/8a18627888.html,/~larus/spim.html。这是由原Wisconsin-Madison的Jame Larus教授(现在在微软)领导编写的一个功能强大的MIPS32汇编语言的汇编器和模拟器,其最新的图形界面版本QtSPIM由于使用了Qt组件因而可以在各大操作系统平台如Windows、Linux、Mac等上运行,推荐安装。我们会在后面介绍有关SPIM Simulator的使用方法。 你需要做的就是将实验三中得到的中间代码经过与具体体系结构相关的指令选择、寄存器选择以及栈管理之后,转换为MIPS32汇编代码。我们要求你的程序能输出正确的汇编代码。“正确”是指该汇编代码在SPIM Simulator(命令行或Qt版本均可)上运行结果正确。因此,以下几个方面不属于检查范围: 1)寄存器的使用与指派可以不必遵循MIPS32的约定。只要不影响在SPIM Simulator中的 正常运行,你可以随意分配MIPS体系结构中的32个通用寄存器,而不必在意哪些寄存器应该存放参数、哪些存放返回值、哪些由调用者负责保存、哪些由被调用者负责保存,等等。 2)栈的管理(包括栈帧中的内容及存放顺序)也不必遵循MIPS32的约定。你甚至可以使 用栈以外的方式对过程调用间各种数据的传递进行管理,前提是你输出的目标代码(即MIPS32汇编代码)能运行正确。

编译原理课程设计报告

2011-2012学年第二学期 《编译原理》课程设计报告 学院:计算机科学与工程学院 班级: 学生姓名:学号: 成绩: 指导教师: 时间:2012年5 月

目录 一、课程设计的目的 ---------------------------------------------------------------- - 1 - 二、课堂实验及课程设计的内容 -------------------------------------------------- - 1 - 2.1、课堂实验内容-------------------------------------------------------------- - 1 - 2.2、课程设计内容-------------------------------------------------------------- - 1 - 三、visual studio 2008 简介------------------------------------------------------- - 2 - 四、问题分析及相关原理介绍 ----------------------------------------------------- - 3 - 4.1、实验部分问题分析及相关原理介绍 ---------------------------------- - 3 - 4.1.1、词法分析功能介绍及分析------------------------------------- - 3 - 4.1.2、语法分析功能介绍及分析------------------------------------- - 3 - 4.1.3、语义分析功能介绍及分析------------------------------------- - 4 - 4.2、课程设计部分问题分析及相关原理介绍 ---------------------------- - 5 - 4.2.1、编译程序介绍 ----------------------------------------------------- - 5 - 4.2.2、对所写编译程序的源语言的描述(C语言) -------------- - 6 - 4.2.3、各部分的功能介绍及分析 -------------------------------------- - 7 - 4.3、关键算法:单词的识别-------------------------------------------------- - 8 - 4.3.1、算法思想介绍 ----------------------------------------------------- - 8 - 4.3.2、算法功能及分析 -------------------------------------------------- - 8 - 五、设计思路及关键问题的解决方法 ------------------------------------------ - 10 - 5.1、编译系统------------------------------------------------------------------ - 10 - 5.1.1、设计思路 --------------------------------------------------------- - 10 - 5.2、词法分析器总控算法--------------------------------------------------- - 12 - 5.2.1、设计思路 --------------------------------------------------------- - 12 - 5.2.2、关键问题及其解决方法 --------------------------------------- - 13 - 六、结果及测试分析-------------------------------------------------------------- - 14 - 6.1、软件运行环境及限制--------------------------------------------------- - 14 - 6.2、测试数据说明------------------------------------------------------------ - 14 - 6.3、运行结果及功能说明--------------------------------------------------- - 16 - 6.4、测试及分析说明--------------------------------------------------------- - 16 - 七、总结及心得体会 --------------------------------------------------------------- - 17 - 7.1、设计过程------------------------------------------------------------------ - 17 - 7.2、困难与收获 ------------------------------------------------------------- - 17 - 八、参考文献 ------------------------------------------------------------------------ - 18 -

编译原理实验报告:实验一编写词法分析程序

( 编译原理实验报告 , 实验名称:实验一编写词法分析程序 实验类型:验证型实验 指导教师:何中胜 专业班级:( 13软件四 姓名:丁越 学号: 实验地点:) 秋白楼B720

实验成绩: 日期:2016年 3 月 18 日

一、实验目的 通过设计、调试词法分析程序,实现从源程序中分出各种单词的方法;熟悉词法分析程序所用的工具自动机,进一步理解自动机理论。掌握文法转换成自动机的技术及有穷自动机实现的方法。确定词法分析器的输出形式及标识符与关键字的区分方法。加深对课堂教学的理解;提高词法分析方法的实践能力。通过本实验,应达到以下目标:[ 1、掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文件的方法。 2、掌握词法分析的实现方法。 3、上机调试编出的词法分析程序。 二、实验过程 以编写PASCAL子集的词法分析程序为例 1.理论部分 > (1)主程序设计考虑 主程序的说明部分为各种表格和变量安排空间。 数组 k为关键字表,每个数组元素存放一个关键字。采用定长的方式,较短的关键字后面补空格。 P数组存放分界符。为了简单起见,分界符、算术运算符和关系运算符都放在 p表中(编程时,还应建立算术运算符表和关系运算符表,并且各有类号),合并成一类。 id和ci数组分别存放标识符和常数。 instring数组为输入源程序的单词缓存。 ¥ outtoken记录为输出内部表示缓存。 还有一些为造表填表设置的变量。 主程序开始后,先以人工方式输入关键字,造 k表;再输入分界符等造p表。 主程序的工作部分设计成便于调试的循环结构。每个循环处理一个单词;接收键盘上送来的一个单词;调用词法分析过程;输出每个单词的内部码。 ⑵词法分析过程考虑 将词法分析程序设计成独立一遍扫描源程序的结构。其流程图见图 1-1。 …

编译原理课程设计

编译原理: 编译原理是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。编译原理是计算机专业设置的一门重要的专业课程。编译原理课程是计算机相关专业学生的必修课程和高等学校培养计算机专业人才的基础及核心课程,同时也是计算机专业课程中最难及最挑战学习能力的课程之一。编译原理课程内容主要是原理性质,高度抽象。 编译原理课程设计: 《编译原理课程设计》是2007年11月浙江大学出版社出版的图书,作者是冯雁、鲁东明、李莹。 内容简介: 本书围绕着编译技术的基本原理和方法,以模拟程序设计语言SPL的编译器的设计和实现为主线,结合词法分析、语法分析、语义分析、代码生成、代码优化、错误处理等各个基本模块,对原理和实现方法进行了详细分析。该编译器可接受SPL的程序,并将其翻译成汇编语言程序,最终实现汇编语言到8086/8088机器语言的翻译。本书为编译技术等相关课程的实验提供了参考。在附件中还提供了三类不同类型和难度的实验题,可供课程实验选择。 第1章引论: 1.1本书介绍 1.2SPL语言的特点及实验安排

1.2.1SPL语言的特点 1.2.2SPL语言编译器的主要结构1.2.3实验安排 1.3平台的选择和介绍 1.3.1LEX简介 1.3.2YACC简介 第2章词法分析: 2.1词法分析器的基本框架 2.2词法分析器的基本原理 2.2.1DFA的构造和实现 2.2.2词法分析的预处理 2.2.3实现词法分析器的注意要点2.3词法分析器的实现 2.3.1SPL语言单词属性字 2.3.2SPL词法分析器的输入和输出2.3.3SPL词法分析器的分析识别第3章语法分析: 3.1语法分析的基本框架 3.1.1上下文无关文法 3.1.2语法分析过程 3.1.3语法分析过程中的数据结构3.2语法分析的基本方法

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

实验四中间代码生成 一.实验目的: 掌握中间代码的四种形式(逆波兰式、语法树、三元式、四元式)。 二.实验内容: 1、逆波兰式定义:将运算对象写在前面,而把运算符号写在后面。用这种表示法表示的表 达式也称做后缀式。 2、抽象(语法)树:运算对象作为叶子结点,运算符作为内部结点。 3、三元式:形式序号:(op,arg1,arg2) 4、四元式:形式(op,arg1,arg2,result) 三、以逆波兰式为例的实验设计思想及算法 (1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。 (2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。 (3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。 (4)如果不是数字,该字符则是运算符,此时需比较优先关系。 做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。 (5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。 四、程序代码: //这是一个由中缀式生成后缀式的程序 #include<> #include<> #include<> #include<> #define maxbuffer 64 void 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<<"请输入中缀表达式: ";

编译原理课程设计

先简要分析一下语法分析的大致流程: 当有句子要进行处理时,首先要对其进行词法分析来分解出该句子中的每个符号,然后将该句子按照算符优先算法压入归约栈中,如果可以顺利归约,则说明这是一个合法的句子,否则该句子非法。 这里有一个需要考虑的地方,就是如何进行归约。由于文法已经给定,所以我们考虑设计一个文法表,文法表中的内容就是可归约串的种别码的顺序,比如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

相关文档
相关文档 最新文档