PL000编译程序

合集下载

第二章PLO编译程序的实现

第二章PLO编译程序的实现

W.Backus与丹麦的Peter Naur来命名的,它从语法上描 述程序设计语言的元语言。采用BNF就可说明哪些符号 序列是对于某给定语言在语法上有效的程序
12
BNF引入的符号:
< > 用左右尖括号括起来的中文字表示语法构造成分,
或称语法单位,为非终结符
盛 威 网 : 专 业 的 计 算 机 学 习 网 站
图 2.2(b) PL/0的解释执行结构
24
PL/O编译程序(包括主程序)是由18个嵌套及并列的过程 或函数组成:
盛 威 网 : 专 业 的 计 算 机 学 习 网 站
25
盛 威 网 : 专 业 的 计 算 机 学 习 网 站
26
PL/O编译程序的过程与函数定义层次结构图
盛 威 网 : 专 业 的 计 算 机 学 习 网 站
界符:
如‘,’、‘.’ 、‘;’ 、‘(’ 、‘)’等
33
词法分析程序GETSYM所要完成的任务:
滤空格、识别保留字 识别标识符、拼数
盛 威 网 : 专 业 的 计 算 机 学 习 网 站
拼复合词、输出源程序
34
取字符过程GETCH:
盛 威 网 : 专 业 的 计 算 机 学 习 网 站
43
(2)过程体的处理: 程序的主体是由语句构成的
盛 威 网 : 专 业 的 计 算 机 学 习 网 站
处理完过程的说明后就处理由语句组成的过程体,从语法 上对语句逐句分析 当语法正确时就生成相应语句功能的目标代码
图 2.6 取字符过程GETCH
35
§2.4 PL/O编译程序的语法语义分析
语法分析的任务:识别单词符号序列是否符合给定的语法
盛 威 网 : 专 业 的 计 算 机 学 习 网 站

编译原理(PL0编译程序源代码)

编译原理(PL0编译程序源代码)

/*PL/0编译程序(C语言版)*编译和运行环境:*Visual C++6.0*WinXP/7*使用方法:*运行后输入PL/0源程序文件名*回答是否将虚拟机代码写入文件*回答是否将符号表写入文件*执行成功会产生四个文件(词法分析结果.txt符号表.txt虚拟代码.txt源程序和地址.txt)*/#include <stdio.h>#include"pl0.h"#include"string"#define stacksize 500//解释执行时使用的栈int main(){bool nxtlev[symnum];printf("请输入源程序文件名:");scanf("%s",fname);fin=fopen(fname,"r");//以只读方式打开pl0源程序文件cifa=fopen("词法分析结果.txt","w");fa1=fopen("源程序和地址.txt","w");//输出源文件及各行对应的首地址fprintf(fa1,"输入pl0源程序文件名:");fprintf(fa1,"%s\n",fname);if(fin){printf("是否将虚拟机代码写入文件?(Y/N)");//是否输出虚拟机代码scanf("%s",fname);listswitch=(fname[0]=='y'||fname[0]=='Y');printf("是否将符号表写入文件?(Y/N)");//是否输出符号表scanf("%s",fname);tableswitch=(fname[0]=='y'||fname[0]=='Y');init();//初始化err=0;cc=cx=ll=0;ch=' ';if(-1!=getsym()){fa=fopen("虚拟代码.txt","w");fas=fopen("符号表.txt","w");addset(nxtlev,declbegsys,statbegsys,symnum);nxtlev[period]=true;if(-1==block(0,0,nxtlev)){//调用编译程序fclose(fa);fclose(fa1);fclose(fas);fclose(fin);return 0;}if(sym!=period){error(9);//结尾丢失了句号}if(err!=0){printf("pl0源程序出现错误,退出编译!!!请从第一个错误处开始修改.\n\n");fprintf(cifa,"源程序出现错误,请检查!!!");fprintf(fa1,"源程序出现错误,请检查!!!");fprintf(fa,"源程序出现错误,请检查!!!");fprintf(fas,"源程序出现错误,请检查!!!");}fclose(fa);fclose(fa1);fclose(fas);}fclose(fin);}else{printf("Can't open file!\n");}fclose(cifa);//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]),"int");strcpy(&(mnemonic[jmp][0]),"jmp");strcpy(&(mnemonic[jpc][0]),"jpc");for(i=0;i<symnum;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;statbegsys[whilesym]=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<n;i++)sr[i]=s1[i]||s2[i];return 0;}void error(int n){//出错处理,打印出错位置和错误编码char space[81];memset(space, 32,81);space[cc-1]=0;printf("error(%d)",n);fprintf(fa1,"error(%d)",n);switch(n){case 1:printf("\t\t常量说明中的“=”写成“:=”\n");fprintf(fa1,"\t\t常量说明中的“=”写成“:=”\n");break;case 2:printf("\t\t常量说明中的=后应该是数字\n");fprintf(fa1,"\t\t常量说明中的=后应该是数字\n");break;case 3:printf("\t\t常量说明符中的表示符应该是=\n" );fprintf(fa1,"\t\t常量说明符中的表示符应该是=\n");break;case 4:printf("\t\tconst,var,procedure后应为标识符\n" );fprintf(fa1,"\t\tconst,var,procedure后应为标识符\n");break;case 5:printf("\t\t漏掉了“,”或“;”\n" );fprintf(fa1,"\t\t漏掉了“,”或“;”\n" );break;case 6:printf("\t\t过程说明后的符号不正确\n" );fprintf(fa1,"\t\t过程说明后的符号不正确\n");break;case 7:printf("\t\t应是语句开始符\n" );fprintf(fa1,"\t\t应是语句开始符\n" );break;case 8:printf("\t\t程序体语句部分的后跟符不正确\n" );fprintf(fa1,"\t\t程序体语句部分的后跟符不正确\n" );break;case 9:printf("\t\t程序结尾丢了句号“.”\n\n" );fprintf(fa1,"\t\t程序结尾丢了句号“.”\n");break;case 10:printf("\t\t语句之间漏了“;”\n" );fprintf(fa1,"\t\t语句之间漏了“;”\n");break;case 11:printf("\t\t标识符拼写错误或未说明\n" );fprintf(fa1,"\t\t标识符拼写错误或未说明\n");break;case 12:printf("\t\t赋值语句中,赋值号左部标识符属性应是变量\n" );fprintf(fa1,"\t\t赋值语句中,赋值号左部标识符属性应是变量\n");break;case 13:printf("\t\t赋值语句左部标识符后应是复制号“:=”\n" );fprintf(fa1,"\t\t赋值语句左部标识符后应是复制号“:=”\n");break;case 14:printf("\t\tcall后应为标识符\n" );fprintf(fa1,"\t\tcall后应为标识符\n");break;case 15:printf("\t\tcall后标识符属性应为过程\n" );fprintf(fa1,"\t\tcall后标识符属性应为过程\n");break;case 16:printf("\t\t条件语句中丢了then\n" );fprintf(fa1,"\t\t条件语句中丢了then\n");break;case 17:printf("\t\t丢了“end”或“;”\n" );fprintf(fa1,"\t\t丢了“end”或“;”\n");break;case 18:printf("\t\twhile型循环语句中丢了“do”\n" );fprintf(fa1,"\t\twhile型循环语句中丢了“do”\n");break;case 19:printf("\t\t语句后的符号不正确\n" );fprintf(fa1,"\t\t语句后的符号不正确\n" );break;case 20:printf("\t\t应为关系运算符\n" );fprintf(fa1,"\t\t应为关系运算符\n");break;case 21:printf("\t\t表达式标示符属性不能是过程\n" );fprintf(fa1,"\t\t表达式标示符属性不能是过程\n");break;case 22:printf("\t\t表达式漏掉了右括号\n" );fprintf(fa1,"\t\t表达式漏掉了右括号\n");break;case 23:printf("\t\t因子后的非法符号\n" );fprintf(fa1,"\t\t因子后的非法符号\n");break;case 24:printf("\t\t表达式的开始符不能是此符号\n" );fprintf(fa1,"\t\t表达式的开始符不能是此符号\n");break;case 25:printf("\t\t标识符越界\n" );fprintf(fa1,"\t\t标识符越界\n");break;case 26:printf("\t\t非法字符\n" );fprintf(fa1,"\t\t非法字符\n");break;case 31:printf("\t\t数越界\n");fprintf(fa1,"\t\t数越界\n");break;case 32:printf("\t\tread语句括号中的标识符不是变量\n" );fprintf(fa1,"\t\tread语句括号中的标识符不是变量\n");break;case 33:printf("\t\twrite()或read()中应为完整表达式\n" );fprintf(fa1,"\t\twrite()或read()中应为完整表达式\n");break;default:printf("\t\t出现未知错误\n" );fprintf(fa1,"\t\t出现未知错误\n");}err++;}//漏掉空格,读取一个字符,每次读一行,存入line缓冲区,line被getsym取空后再读一//行,被函数getsym调用int getch(){if(cc==ll){if(feof(fin)){printf("program incomplete");return-1;}ll=0;cc=0;printf("\n%d ",cx);fprintf(fa1,"\n%d ",cx);ch=' ';while(ch!=10){if(EOF==fscanf(fin,"%c",&ch)){line[ll]=0;break;}printf("%c",ch);fprintf(fa1,"%c",ch);line[ll]=ch;ll++;}fprintf(cifa,"\n");}ch=line[cc];cc++;return 0;}int getsym(){//词法分析int i,j,k,l;while(ch==' '||ch==10||ch==9)//忽略空格换行 TABgetchdo;if(ch>='a'&&ch<='z'){//以字母开头的为保留字或者标识符k=0,l=1;do{if(k<al){//al为标识符或保留字最大长度a[k]=ch;k++;}if(k==al&&l==1){error(25);l=0;}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];fprintf(cifa,"%s\t\t%ssym\n",id,id);//printf("%s\t\t%ssym\n",id,id);}else{//否则为标识符或数字sym=ident;fprintf(cifa,"%s\t\tident\n",id);//printf("%s\t\tident\n",id);}}else {if(ch>='0'&&ch<='9'){k=0;num=0;sym=number;do{num=10*num+ch-'0';//数字的数位处理k++;getchdo;}while(ch>='0'&&ch<='9');k--;if(k>nmax){//数字的长度限制fprintf(cifa,"0\t\tnumber\n");num=0;error(31);}elsefprintf(cifa,"%d\t\tnumber\n",num);//printf("%d\t\tnumber\n",num);}else{if(ch==':'){//检测赋值符号,:只能和=匹配,否则不能识别getchdo;if(ch=='='){sym=becomes;fprintf(cifa,":=\t\tbecomes\n");getchdo;}else{sym=nul;}}else{if(ch=='<'){getchdo;if(ch=='='){sym=leq;//小于等于fprintf(cifa,"<=\t\tleq\n");getchdo;}else{sym=lss;//小于fprintf(cifa,"<\t\tlss\n");}}else{if(ch=='>'){getchdo;if(ch=='='){sym=geq;//大于等于fprintf(cifa,">=\t\tgeq\n");getchdo;}else{sym=gtr;//大于fprintf(cifa,">\t\tgtr\n");}}else{sym=ssym[ch];//不满足上述条件时按单字//符处理switch(ch){case'+':fprintf(cifa,"%c\t\tplus\n",ch);break;case '-':fprintf(cifa,"%c\t\tminus\n",ch );break;case '*':fprintf(cifa,"%c\t\ttimes\n",ch);break;case '/':fprintf(cifa,"%c\t\tslash\n",ch);break;case '(':fprintf(cifa,"%c\t\tlparen\n",ch);break;case ')':fprintf(cifa,"%c\t\trparen\n",ch);break;case '=':fprintf(cifa,"%c\t\teql\n",ch);break;case ',':fprintf(cifa,"%c\t\tcomma\n",ch);break;case '#':fprintf(cifa,"%c\t\tneq\n",ch);break;case ';':fprintf(cifa,"%c\t\tsemicolon\n",ch);break;case '.':break;default :error(26);}if(sym!=period){//判断是否结束getchdo;}else{printf("\n");fprintf(cifa,".\t\tperiod\n");}}}}}}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;}//测试字符串int test(bool* s1,bool* s2,int n){if(!inset(sym,s1)){//测试sym是否属于s1,不属于则报错nerror(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;//保留初始txint cx0;//保留初始cxbool nxtlev[symnum];dx=3;//相对地址从3开始,前3个单元即0、1、2单元分别为 SL:静态链;//DL:动态链;RA:返回地址tx0=tx;//记录本层的初始位置table[tx].adr=cx;gendo(jmp,0,0);if(lev>levmax){//层数超过3error(32);}do{if(sym==constsym){//收到常量声明printf("该语句为常量定义语句\n");getsymdo;do{constdeclarationdo(&tx,lev,&dx);//常量声明处理,dx 会改//变所以使用指针while(sym==comma){//处理一次多常量定义getsymdo;constdeclarationdo(&tx,lev,&dx);}if(sym==semicolon){//常量声明处理结束getsymdo;}else{error(5);//漏掉了逗号或者分号(一般是分号)}}while(sym==ident);}if(sym==varsym){//收到变量声明printf("该语句为变量声明语句\n");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){//收到过程声明printf("该语句为过程声明语句\n");getsymdo;if(sym==ident){enter(procedur,&tx,lev,&dx);//记录过程名getsymdo;}else{error(4);//过程声明后应为标识符}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;cx0=cx;gendo(inte,0,dx);//生成分配存代码if(tableswitch){//输出符号表if(tx0+1<tx){fprintf(fas,"TABLE:\n");//printf("NULL\n");}for(i=tx0+1;i<=tx;i++){switch(table[i].kind){case constant:fprintf(fas,"%d const %s ",i,table[i].name);fprintf(fas,"val=%d\n",table[i].val);break;case variable:fprintf(fas,"%d var %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%d\n",table[i].level,table[i].adr);break;case procedur:fprintf(fas,"%d proc %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%dsize=%d\n", table[i].level,table[i].adr,table[i].size);break;}}}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;}//k:const var procedure//ptx:符号表尾的指针//pdx:dx为当前应分配变量的相对地址//lev:符号名字所在的层次//往符号表中添加void enter(enum object k,int* ptx,int lev,int* pdx){(* ptx)++;strcpy(table[(*ptx)].name,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;}}//寻找符号在符号表中的地址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);}return 0;}//变量声明处理int vardeclaration (int* ptx,int lev,int* pdx){if(sym==ident){enter(variable,ptx,lev,pdx);getsymdo;}else{error(4);}return 0;}//输出目标代码清单void listcode(int cx0){int i;if(listswitch){for(i=cx0;i<cx;i++){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){getsymdo;printf("该语句为赋值语句。

标准实验报告(PL0编译程序)

标准实验报告(PL0编译程序)

[标准实验报告]南昌航空大学实验报告年月日课程名称:编译原理实验名称:扩充的PL/0编译程序班级:姓名:同组人:指导教师评定:签名:一、实验目的进一步熟悉编译程序的整体框架,给出整个编译程序的流程结构,用C 或vc++语言编写程序;并将编制的编译程序进行调试、实现PL/0编译程序。

二、实验要求(1)根据所选的程序设计语言,修改并调试。

(2)举出例子程序,在程序中进行编译。

(3)用此编译程序对有关语句进行编译,并输出目标指令。

(4)书写出合格的实验报告。

三、实验步骤1.输入文件中变量的声明形如:var a,b,c; 以var保留字开始,不同变量以”,”分隔,最后以”;”结束。

2.read语句格式为read(a)或者read(a,b);3.write语句格式为write(a),括号里面没有字符串常量,注意与书后的形如write(‘a=’,a)是不相同的。

4.的声明形如:”procedure proname;”不含参数表。

5.一维数组形如:变量类型array 数组名[数组下标]。

6.条件语句形如:if <条件>then<语句> {;else,语句>}7.扩充的记录型数据类型形如:for 循环语句及带参数的过程。

四、参考源代码#include<stdio.h>/*#include"plo.h"*/#include"string.h"#define stacksize 500typedef enum{false,true}bool;enum object{procedur , constant ,variable};#define norw 13#define txmax 100#define nmax 14#define al 10#define levmax 3#define cxmax 200#define amax 2047#define symnum 32enum 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,};enum fct {lit, opr, lod,sto, cal, inte,jmp, jpc,};#define fctnum 8struct instruction{enum fct f;int l;int a;};FILE* fas;FILE* fa;FILE* fal;FILE* fa2;bool listswitch;bool tableswitch;char ch;enum symbol sym;char id[al+1];int num;int cc,ll;int cx;char line[81];char a [al+1];int num ;int cc,ll;int cx;char line [81];char a [al+1];struct instruction code [cxmax]; char word [norw][al];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]; bool facstatbegsys[symnum]; struct tablestruct{char name [al];enum object kind ;int val;int level;int adr;int size;};struct tablestruct table [txmax]; FILE * fin;FILE * fout;char fname [al];int err;#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 *sl,bool *s2,int n);int inset (int e,bool *s);int addset (bool* sr,bool* sl,bool *s2,int n);int subset (bool* sr,bool* sl,bool *s2,int n);int mulset (bool* sr,bool* sl,bool *s2,int n);int block (int lev,int tx,bool* fsys);void interpret();int factor (bool* fays,int * ptx,int lev);int term (bool* fays,int * ptx,int lev);int condition (bool* fays,int * ptx,int lev);int expression (bool* fays,int * ptx,int lev);int statement (bool* fays,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);int main(){bool nxtlev[symnum];printf("input pl/o file?");scanf("%s",fname);fin=fopen(fname,"r");if(fin){printf("list objeck code? (Y/N)");scanf("%s",fname);/*listwitch=(fname[0]=='y'||fname[0]=='Y');*/ printf("list symbol table? (Y/N)");scanf("%s",fname);tableswitch=(fname[0]=='y'||fname[0]=='Y'); fal=fopen("fal.tmp","w");fprintf(fal,"input pl/o file?");fprintf(fal,"%s",fname);init();err=0;cc=cx=ll=0;ch='';if(-1 !=getsym()){ fa=fopen("fa.tmp","w");fas=fopen("fas.tmp","w");addset(nxtlev,declbegsys,statbegsys,symnum); nxtlev[period]=true;if(-1==block(0,0,nxtlev)){fclose(fa);fclose(fal);fclose(fas);fclose(fin);printf("\n");return 0;}fclose(fa);fclose(fal);fclose(fas);if(sym!=period){error(9);}if(err==0){fa2=fopen("fa2.tmp","w");interpret();fclose(fa2);}else{printf("error in pl/o program"); }}fclose(fin);}else{printf("can't open file! \n");}printf("\n");return 0;}/*chushihua*/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<symnum;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;statbegsys[whilesym]=true;facstatbegsys[ident]=true; facstatbegsys[number]=true; facstatbegsys[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<n;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<n;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<n;i++){sr[i]=s1[i]&&(s2[i]);}return 0;}void error(int n){char space[81];memset(space,32,81);space[cc-1]=0;printf("*****%s!%d\n",space,n);fprintf(fal,"********%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(fal,"%d",cx);ch='';while(ch!=10){if(EOF==fscanf(fin,"%c",&ch)){line[ll]=0;break;}printf("%c",ch);fprintf(fal,"%c",ch);line[ll]=ch;++ll;}printf("\n");fprintf(fal,"\n");}ch=line[cc];cc++;return 0;}/*****************************8 */int getsym(){int i,j,k;while (ch==''||ch==10||ch==9){getchdo;}if(ch>='a'&& ch<='z'){k=0;do{if(k<al){a[k]=ch;k++;}getchdo;}while(ch>='a'&& ch<='z'||ch>='0'&& ch<='9');a[k]=0;strcpy(id,a);i=0;j=norw-1 ;do{k=(i+j)/2 ;if(strcmp(id,word[k])<=0) {j=k-1;}if(strcmp(id,word[k])>=0)i=k+1;}while(i<=j);if(i-1>j){sym=wsym[k];}else{sym=ident;}}else{if(ch>='0'&&ch<='9'){k=0;num=0;sym=number;do{num=10*num+ch-'0';k++;getchdo;}while (ch>='0'&&ch<='9');k--;if(k>nmax){error(30);}}else{if(ch==';'){getchdo;if(ch=='='){sym=becomes;getchdo;}else{sym=nul;}}else{if (ch=='<'){getchdo;if(ch=='='){sym=leq;getchdo;}else{sym=lss;}}else{if(ch=='>'){getchdo;if(ch=='='){sym=geq;getchdo;}else{sym=gtr;}}else{sym=ssym[ch];if(sym!=period){getchdo;}}}}}}return 0;}int gen(enum fct x,int y,int z){if(cx>=cxmax){printf("program too ling ");return -1;}code[cx].f=x;code[cx].l=y;code[cx].a=z;cx++;return 0;}int test(bool * s1,bool * s2,int n){if(! inset(sym,s1)){error(n);while((! inset(sym,s1))&&(! inset(sym,s2))) {getsymdo;}}return 0;}int block(int lev,int tx,bool* fsys){int i;int dx;int txo;int cxo;bool nxtlev[symnum];dx=3;txo=tx;table[tx].adr=cx;gendo(jmp,0,0);if(lev>levmax){error(32);}do{if(sym==constsym){getsymdo;do{constdeclarationdo(&tx,lev,&dx);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);}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[txo].adr].a=cx;table[txo].adr=cx;table[txo].size=dx;cxo=cx;gendo(inte,0,dx);if(tableswitch){printf("TABLE:\n");if(txo+1>tx){printf("NULL\n");}for(i=txo+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");}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(cxo);return 0;}void enter(enum object k , int * ptx , int lev , int * pdx){(*ptx)++;strcpy(table[(*ptx)].name,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;}}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 constdecalration(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);}return 0;}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);}return 0;}int vardeclaration(int* ptx,int lev,int* pdx){if (sym==ident){enter(variable,ptx,lev,pdx);getsymdo;}else{error(4);}return 0;}void listcode(int cx0){int i;if (listswitch){for (i=cx0;i<cx;i++){printf("%d %d %d %d\n",i,mnemonic[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,cxl,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){getsymdo;}else{error(13);}memcpy(nxtlev,fsys,sizeof(bool)*symnum);expressiondo(nxtlev,ptx,lev);if(i!=0){gendo(sto,lev-table[i].level,table[i].adr);}}}/*if(i==0)*/}else{if(sym==readsym){getsymdo;if(sym!=lparen){error(34);}else{do{getsymdo;if(sym==ident){i=position(id,*ptx);}else{i=0;}if(i==0){error(35);}else{gendo(opr,0,16);gendo(sto,lev-table[i].level,table[i].adr) ;}getsymdo;}while(sym==comma);}if(sym!=rparen){error(33);while(! inset(sym,fsys)){getsymdo;}}else{getsymdo;}}else{if(sym==writesym){getsymdo;if(sym==lparen){do{getsymdo; memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[rparen]=true;nxtlev[comma]=true;expressiondo(nxtlev,ptx,lev);gendo(opr,0,14);}while(sym==comma);if(sym!=rparen){error(33);}else{getsymdo;}}gendo(opr,0,15);}else{if(sym==callsym){getsymdo;if(sym!=ident){error(14);}else{i=position(id,*ptx);if(i==0){error(11);}else{if(table[i].kind==procedur){gendo(cal,lev-table[i].level,table[i].adr);}else{error(15);}}getsymdo;}}else{if(sym==ifsym){getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[thensym]=true;nxtlev[dosym]=true;conditiondo(nxtlev,ptx,lev);if(sym==thensym){getsymdo;}else{error(16);}cxl=cx;gendo(jpc,0,0);statementdo(fsys,ptx,lev);code[cxl].a=cx;}else{if(sym==beginsym){getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[semicolon]=true;nxtlev[endsym]=true;statementdo(nxtlev,ptx,lev);while(inset(sym,statbegsys)||sym==semicolon){if(sym==semicolon){getsymdo;}else{error(10);}statementdo(nxtlev,ptx,lev);}if(sym==endsym){getsymdo;}else{error(17);}}else{if(sym==whilesym){cxl=cx;getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[dosym]=true;conditiondo(nxtlev,ptx,lev);cx2=cx;gendo(jpc,0,0);if(sym==dosym){getsymdo;}else{error(18);}statementdo(fsys,ptx,lev);gendo(jmp,0,cxl);code[cx2].a=cx;}else{testdo(fsys,nxtlev,19);}}}}}}}return 0;}int expression(bool * fsys,int * ptx,int lev){enum symbol addop;bool nxtlev[symnum];if(sym==plus||sym==minus){addop=sym;getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[plus]=true;nxtlev[minus]=true;termdo(nxtlev,ptx,lev);if(addop==minus){gendo(opr,0,1);}}else{memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[plus]=true;nxtlev[minus]=true;termdo(nxtlev,ptx,lev);}while(sym==plus||sym==minus){addop=sym;getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[plus]=true;nxtlev[minus]=true;termdo(nxtlev,ptx,lev);if(addop==plus){gendo(opr,0,2);}else{gendo(opr,0,3);}}return 0;}int term(bool*fsys,int*ptx,int lev){enum symbol mulop;bool nxtlev[symnum];memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[times]=true;nxtlev[slash]=true;factordo(nxtlev,ptx,lev);while(sym==times||sym==slash){mulop=sym;getsymdo;factordo(nxtlev,ptx,lev);if(mulop==times){gendo(opr,0,4);}else{gendo(opr,0,5);}}return 0;}int factor(bool*fsys,int*ptx,int lev){int i;bool nxtlev[symnum];testdo(facbegsys,fsys,24);while(inset(sym,facbegsys)){if(sym==ident){i=position(id,*ptx);if(i==0){error(11);}else{switch(table[i].kind){case constant:gendo(lit,0,table[i].val);break;case variable:gendo(lod,lev-table[i].level,table[i].adr);break;case procedur:error(21);break;}}getsymdo;}else{if(sym==number){if(num>amax){error(31);num=0;}gendo(lit,0,num);getsymdo;}else{if(sym==lparen){getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[rparen]=true;expressiondo(nxtlev,ptx,lev);if(sym==rparen){getsymdo;}else{error(22);}}testdo(fsys,facbegsys,23);}}}return 0;}int condition(bool*fsys,int*ptx,int lev){enum symbol relop;bool nxtlev[symnum];if(sym==oddsym){getsymdo;expressiondo(fsys,ptx,lev);gendo(opr,0,6);}else{memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[eql]=true;nxtlev[neq]=true;nxtlev[lss]=true;nxtlev[leq]=true;nxtlev[gtr]=true;nxtlev[geq]=true;expressiondo(nxtlev,ptx,lev);if(sym!=eql&&sym!=neq&&sym!=lss&&sym!=leq&&sym!=gtr&&s ym!=geq){error(20);}else{relop=sym;getsymdo;expressiondo(fsys,ptx,lev);switch(relop){case eql:gendo(opr,0,8);break;case neq:gendo(opr,0,9);break;case lss:gendo(opr,0,10);break;case geq:gendo(opr,0,11);break;case gtr:gendo(opr,0,12);break;case leq:gendo(opr,0,13);break;}}}return 0;}void interpret(){int p,b,t;struct instruction i;int s[stacksize];printf("start pl0\n");t=0;b=0;p=0;s[0]=s[1]=s[2]=0;do{i=code[p];p++;switch(i.f){case lit:s[t]=i.a;t++;break;case opr:switch(i.a){case 0:t=b;p=s[t+2];b=s[t+1]; break;case 1:s[t-1]=-s[t-1]; break;case 2:t--;s[t-1]=s[t-1]+s[t]; break;case 3:t--;s[t-1]=s[t-1]-s[t]; break;case 4:t--;s[t-1]=s[t-1]*s[t]; break;case 5:t--;s[t-1]=s[t-1]/s[t]; break;case 6:t--;s[t-1]=s[t-1]%2; break;case 8:t--;s[t-1]=(s[t-1]==s[t]); break;case 9:t--;s[t-1]=(s[t-1]!=s[t]); break;case 10:t--;s[t-1]=(s[t-1]<s[t]); break;case 11:t--;s[t-1]=(s[t-1]>=s[t]); break;case 12:t--;s[t-1]=(s[t-1]>s[t]); break;case 13:t--;s[t-1]=(s[t-1]<=s[t]); break;case 14:printf("%d",s[t-1]); fprintf(fa2,"%d",s[t-1]); t--;break;case 15:printf("\n");fprintf(fa2,"\n"); break;case 16:printf("?");fprintf(fa2,"?");scanf("%d",&(s[t])); fprintf(fa2,"%d\n",s[t]);t++;break;}break;case lod:s[t]=s[base(i.l,s,b)+i.a];t++;break;case sto:t--;s[t]=s[base(i.l,s,b)+i.a]=s[t]; break;case cal:s[t]=base(i.l,s,b);s[t+1]=b;s[t+2]=p;b=t;p=i.a;break;case inte:t+=i.a;break;case jmp:p=i.a;break;case jpc:t--;if(s[t]==0)p=i.a;break;}}while(p!=0);}int base(int l,int *s,int b) {int b1;b1=b;while(l>0){b1=s[b1];l--;}return b1;}五、实验结果1.输入PL/0源程序const a=10;var b,c;procedure pbeginc:=b+aend;beginread (b);while b#0 dobegincall p;write(2*c);read(b)endend.2. 输入分别输入b值的结果当b=2;输出结果为24当b=3;输出结果为26当b=1;出结果为22当b=0;结束程序六、实验体会通过该实验,本人学会了应用C语言调试和扩充PL/0编译程序的能力,此实验完成了PL/0词法分析、语法分析、语义分析、代码生成和代码优化等功能,并在此基础上实现了PL/0语言的扩充能力,从实际的应用中深刻领悟了编译程序的原理,更加深刻的学习了理论知识。

编译原理(PL0编译程序源代码)

编译原理(PL0编译程序源代码)

/*PL/0编译程序(C语言版)*编译和运行环境:*Visual C++*WinXP/7*利用方式:*运行后输入PL/0源程序文件名*回答是不是将虚拟机代码写入文件*回答是不是将符号表写入文件*执行成功会产生四个文件(词法分析结果.txt符号表.txt虚拟代码.txt源程序和地址.txt)*/#include <>#include""#include"string"#define stacksize 500xt","w");fa1=fopen("源程序和地址.txt","w");xt","w");fas=fopen("符号表.txt","w");addset(nxtlev,declbegsys,statbegsys,symnum);nxtlev[period]=true;if(-1==block(0,0,nxtlev)){n\n");fprintf(cifa,"源程序显现错误,请检查!!!");fprintf(fa1,"源程序显现错误,请检查!!!");fprintf(fa,"源程序显现错误,请检查!!!");fprintf(fas,"源程序显现错误,请检查!!!");}fclose(fa);fclose(fa1);fclose(fas);}fclose(fin);}else{printf("Can't open file!\n");}fclose(cifa);]=period;ssym['#']=neq;ssym[';']=semicolon;strcpy(&(word[0][0]),"begin");\n\n" );fprintf(fa1,"\t\t程序结尾丢了句号“.”\n");break;case 10:printf("\t\t语句之间漏了“;”\n" );fprintf(fa1,"\t\t语句之间漏了“;”\n");break;case 11:printf("\t\t标识符拼写错误或未说明\n" );fprintf(fa1,"\t\t标识符拼写错误或未说明\n");break;case 12:printf("\t\t赋值语句中,赋值号左部标识符属性应是变量\n" );fprintf(fa1,"\t\t赋值语句中,赋值号左部标识符属性应是变量\n");break;case 13:printf("\t\t赋值语句左部标识符后应是复制号“:=”\n" );fprintf(fa1,"\t\t赋值语句左部标识符后应是复制号“:=”\n");break;case 14:printf("\t\tcall后应为标识符\n" );fprintf(fa1,"\t\tcall后应为标识符\n");break;case 15:printf("\t\tcall后标识符属性应为进程\n" );fprintf(fa1,"\t\tcall后标识符属性应为进程\n");break;case 16:printf("\t\t条件语句中丢了then\n" );fprintf(fa1,"\t\t条件语句中丢了then\n");break;case 17:printf("\t\t丢了“end”或“;”\n" );fprintf(fa1,"\t\t丢了“end”或“;”\n");break;case 18:printf("\t\twhile型循环语句中丢了“do”\n" ); fprintf(fa1,"\t\twhile型循环语句中丢了“do”\n");break;case 19:printf("\t\t语句后的符号不正确\n" );fprintf(fa1,"\t\t语句后的符号不正确\n" );break;case 20:printf("\t\t应为关系运算符\n" );fprintf(fa1,"\t\t应为关系运算符\n");break;case 21:printf("\t\t表达式内标示符属性不能是进程\n" ); fprintf(fa1,"\t\t表达式内标示符属性不能是进程\n");break;case 22:printf("\t\t表达式漏掉了右括号\n" );fprintf(fa1,"\t\t表达式漏掉了右括号\n");break;case 23:printf("\t\t因子后的非法符号\n" );fprintf(fa1,"\t\t因子后的非法符号\n");break;case 24:printf("\t\t表达式的开始符不能是此符号\n" );fprintf(fa1,"\t\t表达式的开始符不能是此符号\n");break;case 25:printf("\t\t标识符越界\n" );fprintf(fa1,"\t\t标识符越界\n");break;case 26:printf("\t\t非法字符\n" );fprintf(fa1,"\t\t非法字符\n");break;case 31:printf("\t\t数越界\n");fprintf(fa1,"\t\t数越界\n");break;case 32:printf("\t\tread语句括号中的标识符不是变量\n" );fprintf(fa1,"\t\tread语句括号中的标识符不是变量\n");break;case 33:printf("\t\twrite()或read()中应为完整表达式\n" );fprintf(fa1,"\t\twrite()或read()中应为完整表达式\n");break;default:printf("\t\t显现未知错误\n" );fprintf(fa1,"\t\t显现未知错误\n");}err++;}:break;default :error(26);}if(sym!=period){t\tperiod\n");}}}}}}return 0;}=x;code[cx].l=y;code[cx].a=z;cx++;return 0;}dr=cx;gendo(jmp,0,0);if(lev>levmax){dr].a=cx;dr=cx;ize=dx;cx0=cx;gendo(inte,0,dx);ind){case constant:fprintf(fas,"%d const %s ",i,table[i].name);fprintf(fas,"val=%d\n",table[i].val);break;case variable:fprintf(fas,"%d var %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%d\n",table[i].level,table[i].adr);break;case procedur:fprintf(fas,"%d proc %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%dsize=%d\n", table[i].level,table[i].adr,table[i].size);break;}}}memcpy(nxtlev,fsys,sizeof(bool)*symnum);ame,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;}}ame,idt);i=tx;ame,idt)!=0){i--;}return i;}],code[i].l,code[i],a);}}}ind!=variable){error(12);i=0;}else{getsymdo;if(sym==becomes){getsymdo;printf("该语句为赋值语句。

PL0编译程序

PL0编译程序

PL/0语言编译系统春秋五霸目录1 PL/0语言及编译系统2 驱动代码3 编译程序4 解释程序①词法分析②语法分析③语义分析及目标代码生成1 PL/0语言编译系统PL/语言编译系统PL/0语言编译系统是世界著名计算机科学家N.Wirth编写的。

对PL/0编译程序进行实例分析,有助于对一般编译过程和编译程序结构的理解。

PL/0语言功能简单、结构清晰、可读性强,又具备了一般高级语言的必须部分,因而PL/0语言的编译程序能充分体现一个高级语言编译程序实现的基本技术和步骤,是一个非常合适的编译程序教学模型。

PL/0源程序PL/0编译系统语法语义分析程序词法分析程序目标代码代码生成程序表格管理程序出错处理程序PL/0源程序PL/0编译系统构成类P-code程序PL/0编译程序输出数据输入数据类P-code虚拟机类P-code解释程序PL/0语言文法的EBNF表示●〈程序〉∷=〈分程序〉.●〈分程序〉∷=[〈常量说明部分〉][〈变量说明部分〉][〈过程说明部分〉]〈语句〉●〈常量说明部分〉∷=CONST〈常量定义部分〉{,〈常量定义〉};●〈常量定义〉 ::= 〈标识符〉=〈无符号整数〉;●〈无符号整数〉∷=〈数字〉{〈数字〉}●〈变量说明部分〉∷=V AR〈标识符〉{,〈标识符〉};●〈标识符〉∷=〈字母〉{〈字母〉|〈数字〉}PL/0语言文法的EBNF表示●<过程说明部分>::=<过程首部><分程序>{;<过程说明部分>}●<过程首部>::=PROCEDURE<标识符>;●<语句>::=<赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>|<读语句>|<写语句>|<复合语句>|<空>●<赋值语句>::= <标识符>:=<表达式>●<复合语句>::= BEGIN<语句>{;<语句>}END●<条件>::= <表达式><关系运算符><表达式>PL/0语言文法的EBNF表示●<表达式>::=[+|-]<项>{<加法运算符><项>}●<项>::= <因子>{<乘法运算符><因子>}●<因子>::= <标识符>|<无符号整数>|‘(’<表达式>‘)’PL/0语言文法的EBNF表示●<加法运算符>::= +|-●<乘法运算符>::= *|/●<关系运算符>::= =|#|<|<=|>|>=●<条件语句>::= IF<条件>THEN<语句>●<过程调用语句>::= CALL<标识符>●<当型循环语句>::= WHILE<条件>DO<语句>●<读语句>::= READ’(’<标识符>{,<标识符>}‘)’PL/0语言文法的EBNF表示●<写语句>::= WRITE’(’<表达式>{,<表达式>}‘)’●<字母>::= a|b|…|X|Y|Z●<数字>::= 0|1|…|8|9指令过程调用相关指令类P-code 虚 拟机指令系 统…存取指令int 0 a cal l ajmp 0 alit 0 alod l a sto l a指令一元运算和比较指令类P-code 虚 拟机指令系 统…二元运算指令opr 0 5opr 0 1opr 0 6opr 0 2opr 0 3 opr 0 4指令转移指令类P-code 虚 拟机指令系 统输入输出指令二元运算指令opr 0 13 jmp 0 ajpc 0 aopr 0 8 opr 0 10opr 0 12opr 0 14opr 0 16opr 0 15opr 0 9opr 0 112 驱动代码词法分析主要函数:main()函数功能:驱动整个编译系统的运行变量说明:fa.tmp 输出虚拟机代码fa1.tmp 输出源文件及其各行对应的首地址fa2.tmp 输出结果fas.tmp 输出名字表main函数int main(){……/*打开源程序文件*/If 打开源程序文件成功{…… /*初始化输出文件信息*/init(); /*初始化各类名字和符号信息*/err=0; /*初始化错误数*/…… /*初始化其他信息*/if(-1!=getsym()) /*成功读取第一个单词*/{……main函数if(-1==block(0,0,nxtlev)) /*调用编译程序*/{…… /*编译过程未成功结束关闭所有已打开的文件,返回*/}…… /*编译过程结束关闭所有已打开的输出文件*/if(sym!=period) /*当前符号不是程序结束符’.’*/{error(9); /*提示9号出错信息:缺少程序结束符’.’*/}if(err==0) /*未发现程序中的错误*/{……interpret(); /*调用解释程序,执行所产生的类P-code代码*/……main函数else{printf("Errors in pl/0 program");}}…… /*关闭已打开的文件*/}else{printf(“Can‘t open file! \n”);/*打开源程序文件不成功*/}printf("\n");return 0; /*返回*/}集合运算函数int inset(int e,bool* s){/*返回e在数组s中的值*/return s[e];}int addset(bool* sr,bool* s1,bool* s2,int n){/*逻辑或运算*/int i;for(i=0;i<n;i++){sr[i]=s1[i]||s2[i];}return 0;}集合运算函数int subset(bool* sr,bool* s1,bool* s2,int n){/*s1[i]为true,s2[i]为false时,sr[i]才为true*/int i;for(i=0;i<n;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<n;i++){sr[i]=s1[i]&&s2[i]; }return 0;}错误处理函数void error(int n){char space[81];memset(space,32,81);printf("-------%c\n",ch);fprintf(fa1,"-------%c\n",ch);space[cc-1]=0;//出错时当前符号已经读完,所以cc-1printf("****%s!%d\n",space,n);fprintf(fa1,"****%s!%d\n",space,n);err++;}PL/O语言的出错信息表:出错编号出错原因1:常数说明中的“=”写成“∶=”。

PL0编译程序

PL0编译程序

PL/0编译程序的运行机制:语法分析开始后,首先调用分程序处理过程(block)处理分程序。

过程入口参数置为:0层、符号表位置0、出错恢复单词集合为句号、声明符或语句开始符。

进入block过程后,首先把局部数据段分配指针设为3,准备分配3个单元供运行期存放静态链SL、动态链DL和返回地址RA。

然后用tx0记录下当前符号表位置并产生一条jmp指令,准备跳转到主程序的开始位置,由于当前还没有知到主程序究竟在何处开始,所以jmp的目标暂时填为0,稍后再改。

同时在符号表的当前位置记录下这个jmp指令在代码段中的位置。

在判断了嵌套层数没有超过规定的层数后,开始分析源程序。

首先判断是否遇到了常量声明,如果遇到则开始常量定义,把常量存入符号表。

接下去用同样的方法分析变量声明,变量定义过程中会用dx变量记录下局部数据段分配的空间个数。

然后如果遇到procedure保留字则进行过程声明和定义,声明的方法是把过程的名字和所在的层次记入符号表,过程定义的方法就是通过递归调用block过程,因为每个过程都是一个分程序。

由于这是分程序中的分程序,因此调用block时需把当前的层次号lev加一传递给block过程。

分程序声明部分完成后,即将进入语句的处理,这时的代码分配指针cx的值正好指向语句的开始位置,这个位置正是前面的jmp指令需要跳转到的位置。

于是通过前面记录下来的地址值,把这个jmp指令的跳转位置改成当前cx的位置。

并在符号表中记录下当前的代码段分配地址和局部数据段要分配的大小(dx 的值)。

生成一条int指令,分配dx个空间,作为这个分程序段的第一条指令。

下面就调用语句处理过程statement分析语句。

分析完成后,生成操作数为0的opr指令,用于从分程序返回(对于0层的主程序来说,就是程序运行完成,退出)。

逻辑表达式的处理:首先判断是否为一元逻辑表达式:判奇偶。

如果是,则通过调用表达式处理过程分析计算表达式的值,然后生成判奇指令。

PL/0编译器的实现文档

PL/0编译器的实现文档

第二章PL/0编译程序的实现【课前思考】复习第1章介绍的一个高级程序设计语言编译程序的功能和实现的步骤。

编译程序就是一个语言的翻译程序,通常是把一种高级程序设计语言(称源语言)书写的程序翻译成另一种等价功能语言(称目标语言)的程序。

换句话说,编译是指把一种用源语言表示的算法转换到另一种等价的用目标语言表示的算法。

编译程序实现的必要步骤有词法、语法、语义分析和代码生成。

此外必需有符号表管理程序和出错处理程序。

本章介绍的PL/0编译程序的实现是用PASCAL语言书写的【学习目标】本章目的:以PL/0语言编译程序为实例,学习编译程序实现的基本步骤和相关技术,对编译程序的构造和实现得到一些感性认识和建立起整体概念,为后面的原理学习打下基础。

◇了解并掌握用语法图和扩充的巴科斯-瑙尔范式(EBNF)对PL/0语言的形式描述。

◇了解并掌握PL/0语言编译程序构造和实现的基本技术和步骤。

◇了解并掌握PL/0语言编译程序的目标程序在运行时数据空间的组织管理。

【学习指南】◇要求读者阅读PL/0语言编译程序文本,了解一个编译程序构造的必要步骤和实现技术。

一个编译程序的实现比较复杂,读懂一个典型的程序从设计思想到实现技术也有一定难度,特别是入门开始需要耐心。

一但读懂,不仅了解编译程序的实现方法和技术,还可学到许多编程技巧和好的编程风格。

◇阅读PL/0语言编译程序文本时,应从整体结构开始逐步细化,弄清楚每个过程的功能和实现方法及过程之间的相互关系。

◇建议用一个PL/0源程序的例子为导引作为阅读PL/0语言编译程序文本的入门,然后再逐步全面读懂。

◇通过对PL/0语言编译程序某些指定功能的扩充,加深对编译程序构造步骤和实现技术的理解,并能在实践中应用。

【难重点】重点:◇弄清源语言(PL/0)、目标语言(类pcode)与实现语言(C)这3个语言之间的关系和作用。

◇掌握用语法图和扩充的巴科斯-瑙尔范式(EBNF)对一个高级程序设计语言的形式描述。

编译原理大作业pl语言编译程序

编译原理大作业pl语言编译程序

编译原理大作业pl语言编译程序编译原理大作业:PL语言编译程序编译原理是计算机科学中的重要课程,它研究的是如何将高级语言转化为机器语言的过程。

在这门课程的大作业中,我们需要设计一个PL语言的编译程序,将PL语言的源代码转化为可执行的机器代码。

PL语言是一种高级编程语言,它具有丰富的语法和功能,可以用来编写各种应用程序。

编写一个PL语言的编译程序需要经历以下几个步骤:首先,我们需要设计PL语言的语法规则。

语法规则定义了PL语言中各种语句和表达式的结构和组织方式。

通过定义语法规则,我们可以确定PL语言源代码的合法性,并将其转化为抽象语法树。

接下来,我们需要设计词法分析器。

词法分析器负责将源代码分解为一个个的词法单元,如关键字、标识符、运算符等。

通过词法分析器,我们可以将源代码转化为一个个的词法单元序列。

然后,我们需要设计语法分析器。

语法分析器负责根据语法规则,将词法单元序列转化为抽象语法树。

语法分析器使用一种称为“自顶向下”的分析方法,通过递归下降的方式,从源代码的起始符号开始,逐步推导出各个语法单元。

在语法分析的过程中,我们还需要设计语义分析器。

语义分析器负责对抽象语法树进行语义检查和语义处理。

它会检查变量的声明和使用是否合法,进行类型检查,生成中间代码等。

最后,我们需要设计代码生成器。

代码生成器负责将抽象语法树转化为目标机器的机器代码。

代码生成器会根据目标机器的指令集和寄存器分配策略,生成高效的机器代码。

在实现PL语言编译程序的过程中,我们还需要进行测试和调试。

我们可以编写一些PL语言的示例程序,用来测试编译程序的正确性和性能。

通过不断地测试和调试,我们可以逐步完善编译程序,使其能够正确地将PL语言源代码转化为可执行的机器代码。

编译原理大作业是一项非常有挑战性的任务,需要我们对编译原理的各个方面有深入的理解和掌握。

通过完成这个大作业,我们可以更好地理解编译原理的原理和方法,提高我们的编程能力和解决问题的能力。

第二章PL0编译程序PPT课件

第二章PL0编译程序PPT课件

PL/0的语法描述图
内的文字表示非终结符

内的文字或符号表示终结符
程序
分程序
.
PL/0的语法描述图
分程序
const
标识符
var
标识符
number
procedure 语句
标识符
分程序
PL/0的语法描述图
语句
标识符
:=
表达式
begin
语句
end
语句
read
(
标识符
)
,
PL/0语言文法的EBNF表示
目标代码类pcode是一种假想栈式计算机的汇编语言。 指令格式:
f la
f 功能码 l 层次差 (标识符引用层减去定义层) a 根据不同的指令有所区别
类pcode指令功能表
LIT 0 a LOD l a STO l a CAL l a INT 0 a JMP 0 a JPC 0 a
OPR 0 0 OPR 0 1 OPR 0 2 OPR 0 3 OPR 0 4 OPR 0 5 OPR 0 6 OPR 0 7 OPR 0 8 OPR 0 9 OPR 0 10 OPR 0 11 OPR 0 12 OPR 0 13 OPR 0 14 OPR 0 15 OPR 0 16
PROCEDURE P; (* 过程说明部分 *)
VAR D;
PROCEDURE Q; VAR X; BEGIN READ(X);
D:=X;
Q的过程体
WHILE X#0
DO CALL P; END;
BEGIN WRITE(D); CALL Q;
END; BEGIN
p的过程体
CALL P; END.
主程序体

实验一PL0编译程序

实验一PL0编译程序

实验一PL0编译程序编译原理上机实验一1.软件准备(1)、pl/0编译程序:pl0 .exe(2)、pl/0编译程序源代码程序(PASCAL程序):pl0.pas(或pl0pl0.pas)(3)、pl/0程序实例(文本文件):text.pl0, text1.pl0, test2.pl0, … text9.pl0共10个例子2.实验要求:(1)阅读pl/0源程序实例(text.pl0,test1.pl0,………text9.pl0共10个例子)理解每个PL0程序的功能;熟悉并掌握pl/0语言相关规则。

(2)用pl/0编译程序,对提供的10个例子逐一进行编译并运行。

熟悉pl/0编译程序使用操作方法。

通过理解每个实例程序的功能,编程思想,进一步理解PL/0语言的语法及其语义;提高阅读程序的能力,应用程序设计语言的编程能力;增强程序语言语法、语义意识。

(3)用pl/0语言编写以下程序,进一步熟悉PL/0语言:a、由三角形的三条边长计算三角形面积。

b、编写一个PL0过程,计算以a为直径的圆的面积。

用主程序确定圆的直径,输出计算结果。

c、编写递归程序,计算n!。

d、计算1000之内的所有素数,并输出结果。

求出1000之内所有素数之和。

(要求编写3个以上的pl/0过程实现)3.文件(软件)使用说明(1)、打开文件目录“PL0编译…”,运行PL/0编译程序(pl0.exe),按提示要求输入PL0源程序文件名(如test1.pl0),┉(2)、打开Fa2.txt文件,可看到当前经过编译并运行后的pl/0程序的目标代码及其执行结果。

(3)、打开out1.txt或out2.txt、┉或out9.txt文件,可看到各个pl/0程序实例的编译、运行、操作过程结果。

4.提交实验报告及要求(1)、简述test4.pl0 …test7.pl0各程序语法含义,执行结果。

(2)、提交实验要求编写的4个PL/0源程序及其执行结果。

(3)、简写本次实验的收获与体会。

PL0编译程序的实现-教案

PL0编译程序的实现-教案
PL/0语言 目标程序 执行结果
10
11
12
ô ¯ Æ ¶ Ã õ µ Ö ³ Ö
编 译 程 序 总 体 流 程 图
ôÃ GETSYMÈ ¥ Ê µ Ó ¡ µ ´ ôÃ BLOCK¹ Ì µ Ó ù ³
±°¥ Ê µ Ç µ ´ Ç ñ ª ´ Ì ò á ÷ ø Ê ²Î Ô ³ Ð ½ Ê ² '.'£ ¿ Y ´ Ì ò Ð Ô ³ Ð Ö Ç ñ Ð í ó ¿ Ê ²Ó ´ Î £ N ôà â Í ù Ì INTERPRET µ Ó ½ Ê ¹ ³ â Í ´ Ð ¿ ê Ì ò ½ Ê Ö Ä ±³ Ð Y
23
表格管理
CONST A=35,B=49; VAR C,D,E; PROCEDURE P; VAR G
1 2
实例分析
层次/值 VAL:35 VAL:49 LEVEL:LEV LEVEL:LEV LEVEL:LEV LEVEL:LEV LEVE:LEV+1 …… 地址 存储空间
3
4 5 6 7
名字 NAME:A NAME:B NAME:C NAME:D NAME:E NAME:P NAME:G ……
变量 b
RA 0 DL 0 SL:静态链 DL:动态链 RA:返回地址 SL 0 0 运行栈 27
允许过程嵌套、递归语言的目标程序
ห้องสมุดไป่ตู้
运行时存储空间的组织与管理
• 活动记录的内容
– 连接数据:
• RA:返回地址 • DL:动态链 • SL:静态链
– 局部变量数据区 – 临时单元
• 活动记录存储区指示器
1
PL/0语言程序实例
• • • • • • • • • • Test1.pl0 Test2.pl0 Test3.pl0 Test4.pl0 Test5.pl0 Test6.pl0 Test7.pl0 Test8.pl0 Test9.pl0 Test.pl0 : 最简单的PL/0程序 : 用while语句求累加和 :含有“过程”子程序 :定义全局量、“过程”中的局部量 :用同一标识符定义全局量和局部量 : 递归调用计算n! :“过程”嵌套,全局量和局部量为同一标识符 :多个过程嵌套或并列 : 定义全局常量和变量、局部常量和变量 :I/O语句中使用多个变量

PL0编译程序设计说明书

PL0编译程序设计说明书

PL/0编译程序设计说明书小组组长:李文(00000000)小组成员:******(00000000)******(00000000)******(00000000)******(00000000)2006年1月16日1引言 (3)1.1编写目的 (3)1.2背景 (3)1.3定义 (3)1.4参考资料 (5)2总体设计 (5)2.1需求规定 (5)2.2运行环境 (6)2.3模块流程 (6)2.4模块机理说明 (7)2.5模块设计与实现 (10)2.6人工处理过程 (12)2.7程序的亮点 (13)2.8尚未问决的问题 (13)3程序介绍和使用说明 (13)4程序测试结果分析 (16)概要设计说明书1引言1.1编写目的此文档为VK 1.0版PL/0编译器详细设计说明书,旨在说明该编译器的设计思想和实现。

此说明书可以在阅读本编译器代码时有效地帮助您理解本编译器的设计方法和实现过程,希望能提供给您所需的帮助。

1.2背景名称:VK1.0版PL/0编译器说明:此编译器为北京师范大学信息科学学院计算机科学与技术系2003级2005-2006学年度第一学期编译原理课程实验作业。

本软件由李文小组合作开发,组长李文,同组人员有吕叶、刘晟忻、肖纯、曲文星。

本软件主要用于PL/0程序的编译,软件提供生成中间代码,并执行检测。

本软件为开源软件,故除了用于编译以外还可给编译器开发者提供开发参考。

本软件开发运行在Windows 32位平台上,尚未开发其他平台版本。

1.3定义本软件开发中,用到了一些PL/0语言和PCODE的定义以及编译原理术语,下面给予说明。

●PL/0语言:BNF范式:〈程序〉∷=〈分程序〉.〈分程序〉∷=[〈常量说明部分〉][〈变量说明部分〉][〈过程说明部分〉]〈语句〉〈常量说明部分〉∷=CONST〈常量定义〉{,〈常量定义〉};〈常量定义〉∷=〈标识符〉=〈无符号整数〉〈无符号整数〉∷=〈数字〉{〈数字〉}〈变量说明部分〉∷=V AR〈标识符〉{,〈标识符〉};〈标识符〉∷=〈字母〉{〈字母〉|〈数字〉}〈过程说明部分〉∷=〈过程首部〉〈分程序〉{;〈过程说明部分〉};〈过程首部〉∷=PROCEDURE〈标识符〉;〈语句〉∷=〈赋值语句〉|〈条件语句〉|〈当型循环语句〉|〈过程调用语句〉|〈读语句〉|〈写语句〉|〈复合语句〉|〈空〉;〈赋值语句〉∷=〈标识符〉∶=〈表达式〉〈复合语句〉∷=BEGIN〈语句〉{;〈语句〉}END〈条件〉∷=〈表达式〉〈关系运算符〉〈表达式〉|ODD〈表达式〉〈表达式〉∷=[+|-]〈项〉{〈加法运算符〉〈项〉}〈项〉∷=〈因子〉{〈乘法运算符〉〈因子〉}〈因子〉∷=〈标识符〉|〈无符号整数〉|'('〈表达式〉')'〈加法运算符〉∷=+|-〈乘法运算符〉∷=*|/〈关系运算符〉∷=#|=|<|<=|>|>=〈条件语句〉∷=IF〈条件〉THEN〈语句〉〈过程调用语句〉∷=CALL〈标识符〉〈当型循环语句〉∷=WHILE〈条件〉DO〈语句〉〈读语句〉∷=READ'('〈标识符〉{,〈标识符〉}')'〈写语句〉∷=WRITE'('〈表达式〉{,〈表达式〉}')'〈字母〉∷=a|b|…|X|Y|Z〈数字〉∷=0|1|2|…|8|9PL/0语言允许过程嵌套定义,函数及变量作用于本层。

PL000编译程序

PL000编译程序

第二章 编译程序的实现
26
2、PL/0语法规则的BNF表示
<写语句>::= WRITE(<表达式>{, <表达式>}) <写语句>举例: WRITE( a+b,b*c);
第二章 编译程序的实现
27
2、PL/0语法规则的BNF表示
<过程调用语句>::=CALL <标识符>; <过程调用语句>举例:
第二章 编译程序的实现
30
2、PL/0语法规则的BNF表示
<因子>::=
<标识符>|<常量>|(<表达式>)
PROCEDURE FACTOR P294~P295
第二章 编译程序的实现
31
2、PL/0语法规则的BNF表示
<项>::=
<因子>|<项> <乘法运算符><因子>
<乘法运算符>::=*|/
第二章 编译程序的实现 38
符号表的内容
标识符名:NAME
类型:KIND ①CONSTANT(常量)
②VARIABLE(变量) ③PROCEDURE(过程) 值或层次:VAL或LEVEL 地址:ADR 大小:SIZE
第二章 编译程序的实现 39
地址:ADR
地址:ADR 简单变量或常量:该量在数据区所占单元 的绝对地址或相对地址;
(PROGRAM PROGSYM),(mysource IDENT) , (CONST CONSTSYM) , (a IDENT) , (= EQL) , (10 NUMBER) , (; SEMICOLON) , (VAR VARSYM) , (b IDENT) , (, COMMA) , (c IDENT) , (; SEMICOLON) , (PROCEDURE PROCSYM) , …… (g IDENT) , (:= BECOMES) , (a IDENT) , (+ PLUS) , (e IDENT) , (; SEMICOLON) This is a assign Statement;(赋值语句) (f IDENT) , (:= BECOMES) , (g IDENT) , (; SEMICOLON) This is a assign Statement; (赋值语句) (WRITE WRITESYM) , (( LPAREN) , (g IDENT) , ( ) RPAREN) , (; SEMICOLON) This is a write Statement;(写语句) ……

编译原理第2版第二章PL0编译程序

编译原理第2版第二章PL0编译程序
… ssym[‘;’]:=semicolon;
词法分析如何把单词传递给语法分析 type symbol=(nul,ident,number,plus,…,varsym,procsym);
3个全程量 SYM:symbol; ID:alfa; NUM:integer;
通过三个全程量 SYM 、ID和NUM 将识别出的单词信息传递给语 法分析程序。 SYM:存放单词的类别 如:有程序段落为: begin initial := 60;end 对应单词翻译后变为: begin beginsym, initial ident, ‘:= ‘ becomes, 60 number, ‘;’ semicolon, end endsym 。 ID: 存放用户所定义的标识符的值 如: initial (在 SYM中放ident,在ID中放initial) NUM:存放用户定义的数 如:60 (在SYM中放number,在NUM中放60)
OPR 0 12 OPR 0 13
次栈顶是否大于栈顶,退两个栈元素,结果值进栈 次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈
OPR 0 14 OPR 0 15 OPR 0 16
栈顶值输出至屏幕 屏幕输出换行 从命令行读入一个输入置于栈顶
const a=10; var b,c; procedure p;
出错处理程序 表格管理程序
PL/0编译程序的结构
PL/0源程序 词法分析程 序 语法语义分析程序
代码生成程序
目标程序
PL/0编译程序的总体设计
以语法、语义分析程序为核心 词法分析程序和代码生成程序都作为一个过程, 当语法分析需要读单词时就调用词法分析程序, 而当语法、语义分析正确,需要生成相应的目标 代码时,则调用代码生成程序。

第2章 PL-0编译程序的实现

第2章  PL-0编译程序的实现

3、PL/0编译程序是用PASCAL语言编写, 可在任何配有PASCAL编译系统的计算机 上运行。
PL/0 Compiler 源文本
PASCAL Compiler
PL/0 Compiler 目标文本
PL/0 Compiler 目标文本
PL/0 目标程序
PL/0 源程序
2.2 PL/0编译程序的结构
第 2章 PL/0编译程序的实现
2.1 2.2 2.3 2.4 2.5
PL/0语言描述 PL/0编译程序的结构 PL/0编译程序的语法语义分析 PL/0编译程序的错误处理 类pcode代码解释器
本章目的:以PL/0为实例,学习编译 程序实现的基本步骤和相关技术
PL/0语言简介 PL/0是一个非常小的程序设计语言, 它是由Pascal的发明人Niklaus Wirth所定 义的。它是Pascal的一个子集,有嵌套的 过程,但过程不能有参数,没有函数,没 有分支语句,没有for 循环,条件语句不支 持else,只有一个整数数据类型。
程序
分程序
.
内的文字表示非终结符 或 内的文字或符号表示终结符
2.1.1 PL/0语言的语法描述图
语法描述图 下页
分程序
Const , ;
ident
=
number
Var
, ; ;
procedure
ident
ident
;
分程序
语句
语句
ident call begin
:=
表达式
ident
.
语句 语句
0 l l l 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
a a a a a a a 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

编译原理(PL0编译程序源代码)

编译原理(PL0编译程序源代码)

/*PL/0编译程序(C语言版)*编译和运行环境:*Visual C++6.0*WinXP/7*使用方法:*运行后输入PL/0源程序文件名*回答是否将虚拟机代码写入文件*回答是否将符号表写入文件*执行成功会产生四个文件(词法分析结果.txt符号表.txt虚拟代码.txt源程序和地址.txt)*/#include <stdio.h>#include"pl0.h"#include"string"#define stacksize 500//解释执行时使用的栈int main(){bool nxtlev[symnum];printf("请输入源程序文件名:");scanf("%s",fname);fin=fopen(fname,"r");//以只读方式打开pl0源程序文件cifa=fopen("词法分析结果.txt","w");fa1=fopen("源程序和地址.txt","w");//输出源文件及各行对应的首地址fprintf(fa1,"输入pl0源程序文件名:");fprintf(fa1,"%s\n",fname);if(fin){printf("是否将虚拟机代码写入文件?(Y/N)");//是否输出虚拟机代码scanf("%s",fname);listswitch=(fname[0]=='y'||fname[0]=='Y');printf("是否将符号表写入文件?(Y/N)");//是否输出符号表scanf("%s",fname);tableswitch=(fname[0]=='y'||fname[0]=='Y');init();//初始化err=0;cc=cx=ll=0;ch=' ';if(-1!=getsym()){fa=fopen("虚拟代码.txt","w");fas=fopen("符号表.txt","w");addset(nxtlev,declbegsys,statbegsys,symnum);nxtlev[period]=true;if(-1==block(0,0,nxtlev)){//调用编译程序fclose(fa);fclose(fa1);fclose(fas);fclose(fin);return 0;}if(sym!=period){error(9);//结尾丢失了句号}if(err!=0){printf("pl0源程序出现错误,退出编译!!!请从第一个错误处开始修改.\n\n");fprintf(cifa,"源程序出现错误,请检查!!!");fprintf(fa1,"源程序出现错误,请检查!!!");fprintf(fa,"源程序出现错误,请检查!!!");fprintf(fas,"源程序出现错误,请检查!!!");}fclose(fa);fclose(fa1);fclose(fas);}fclose(fin);}else{printf("Can't open file!\n");}fclose(cifa);//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]),"int");strcpy(&(mnemonic[jmp][0]),"jmp");strcpy(&(mnemonic[jpc][0]),"jpc");for(i=0;i<symnum;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;statbegsys[whilesym]=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<n;i++)sr[i]=s1[i]||s2[i];return 0;}void error(int n){//出错处理,打印出错位置和错误编码char space[81];memset(space, 32,81);space[cc-1]=0;printf("error(%d)",n);fprintf(fa1,"error(%d)",n);switch(n){case 1:printf("\t\t常量说明中的“=”写成“:=”\n");fprintf(fa1,"\t\t常量说明中的“=”写成“:=”\n");break;case 2:printf("\t\t常量说明中的=后应该是数字\n");fprintf(fa1,"\t\t常量说明中的=后应该是数字\n");break;case 3:printf("\t\t常量说明符中的表示符应该是=\n" );fprintf(fa1,"\t\t常量说明符中的表示符应该是=\n");break;case 4:printf("\t\tconst,var,procedure后应为标识符\n" );fprintf(fa1,"\t\tconst,var,procedure后应为标识符\n");break;case 5:printf("\t\t漏掉了“,”或“;”\n" );fprintf(fa1,"\t\t漏掉了“,”或“;”\n" );break;case 6:printf("\t\t过程说明后的符号不正确\n" );fprintf(fa1,"\t\t过程说明后的符号不正确\n");break;case 7:printf("\t\t应是语句开始符\n" );fprintf(fa1,"\t\t应是语句开始符\n" );break;case 8:printf("\t\t程序体内语句部分的后跟符不正确\n" );fprintf(fa1,"\t\t程序体内语句部分的后跟符不正确\n" );break;case 9:printf("\t\t程序结尾丢了句号“.”\n\n" );fprintf(fa1,"\t\t程序结尾丢了句号“.”\n");break;case 10:printf("\t\t语句之间漏了“;”\n" );fprintf(fa1,"\t\t语句之间漏了“;”\n");break;case 11:printf("\t\t标识符拼写错误或未说明\n" );fprintf(fa1,"\t\t标识符拼写错误或未说明\n");break;case 12:printf("\t\t赋值语句中,赋值号左部标识符属性应是变量\n" );fprintf(fa1,"\t\t赋值语句中,赋值号左部标识符属性应是变量\n");break;case 13:printf("\t\t赋值语句左部标识符后应是复制号“:=”\n" );fprintf(fa1,"\t\t赋值语句左部标识符后应是复制号“:=”\n");break;case 14:printf("\t\tcall后应为标识符\n" );fprintf(fa1,"\t\tcall后应为标识符\n");break;case 15:printf("\t\tcall后标识符属性应为过程\n" );fprintf(fa1,"\t\tcall后标识符属性应为过程\n");break;case 16:printf("\t\t条件语句中丢了then\n" );fprintf(fa1,"\t\t条件语句中丢了then\n");break;case 17:printf("\t\t丢了“end”或“;”\n" );fprintf(fa1,"\t\t丢了“end”或“;”\n");break;case 18:printf("\t\twhile型循环语句中丢了“do”\n" );fprintf(fa1,"\t\twhile型循环语句中丢了“do”\n");break;case 19:printf("\t\t语句后的符号不正确\n" );fprintf(fa1,"\t\t语句后的符号不正确\n" );break;case 20:printf("\t\t应为关系运算符\n" );fprintf(fa1,"\t\t应为关系运算符\n");break;case 21:printf("\t\t表达式内标示符属性不能是过程\n" );fprintf(fa1,"\t\t表达式内标示符属性不能是过程\n");break;case 22:printf("\t\t表达式漏掉了右括号\n" );fprintf(fa1,"\t\t表达式漏掉了右括号\n");break;case 23:printf("\t\t因子后的非法符号\n" );fprintf(fa1,"\t\t因子后的非法符号\n");break;case 24:printf("\t\t表达式的开始符不能是此符号\n" );fprintf(fa1,"\t\t表达式的开始符不能是此符号\n");break;case 25:printf("\t\t标识符越界\n" );fprintf(fa1,"\t\t标识符越界\n");break;case 26:printf("\t\t非法字符\n" );fprintf(fa1,"\t\t非法字符\n");break;case 31:printf("\t\t数越界\n");fprintf(fa1,"\t\t数越界\n");break;case 32:printf("\t\tread语句括号中的标识符不是变量\n" );fprintf(fa1,"\t\tread语句括号中的标识符不是变量\n");break;case 33:printf("\t\twrite()或read()中应为完整表达式\n" );fprintf(fa1,"\t\twrite()或read()中应为完整表达式\n");break;default:printf("\t\t出现未知错误\n" );fprintf(fa1,"\t\t出现未知错误\n");}err++;}//漏掉空格,读取一个字符,每次读一行,存入line缓冲区,line被getsym取空后再读一//行,被函数getsym调用int getch(){if(cc==ll){if(feof(fin)){printf("program incomplete");return-1;}ll=0;cc=0;printf("\n%d ",cx);fprintf(fa1,"\n%d ",cx);ch=' ';while(ch!=10){if(EOF==fscanf(fin,"%c",&ch)){line[ll]=0;break;}printf("%c",ch);fprintf(fa1,"%c",ch);line[ll]=ch;ll++;}fprintf(cifa,"\n");}ch=line[cc];cc++;return 0;}int getsym(){//词法分析int i,j,k,l;while(ch==' '||ch==10||ch==9)//忽略空格换行 TABgetchdo;if(ch>='a'&&ch<='z'){//以字母开头的为保留字或者标识符k=0,l=1;do{if(k<al){//al为标识符或保留字最大长度a[k]=ch;k++;}if(k==al&&l==1){error(25);l=0;}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];fprintf(cifa,"%s\t\t%ssym\n",id,id);//printf("%s\t\t%ssym\n",id,id);}else{//否则为标识符或数字sym=ident;fprintf(cifa,"%s\t\tident\n",id);//printf("%s\t\tident\n",id);}}else {if(ch>='0'&&ch<='9'){k=0;num=0;sym=number;do{num=10*num+ch-'0';//数字的数位处理k++;getchdo;}while(ch>='0'&&ch<='9');k--;if(k>nmax){//数字的长度限制fprintf(cifa,"0\t\tnumber\n");num=0;error(31);}elsefprintf(cifa,"%d\t\tnumber\n",num);//printf("%d\t\tnumber\n",num);}else{if(ch==':'){//检测赋值符号,:只能和=匹配,否则不能识别getchdo;if(ch=='='){sym=becomes;fprintf(cifa,":=\t\tbecomes\n");getchdo;}else{sym=nul;}}else{if(ch=='<'){getchdo;if(ch=='='){sym=leq;//小于等于fprintf(cifa,"<=\t\tleq\n");getchdo;}else{sym=lss;//小于fprintf(cifa,"<\t\tlss\n");}}else{if(ch=='>'){getchdo;if(ch=='='){sym=geq;//大于等于fprintf(cifa,">=\t\tgeq\n");getchdo;}else{sym=gtr;//大于fprintf(cifa,">\t\tgtr\n");}}else{sym=ssym[ch];//不满足上述条件时按单字//符处理switch(ch){case'+':fprintf(cifa,"%c\t\tplus\n",ch);break;case '-':fprintf(cifa,"%c\t\tminus\n",ch );break;case '*':fprintf(cifa,"%c\t\ttimes\n",ch);break;case '/':fprintf(cifa,"%c\t\tslash\n",ch);break;case '(':fprintf(cifa,"%c\t\tlparen\n",ch);break;case ')':fprintf(cifa,"%c\t\trparen\n",ch);break;case '=':fprintf(cifa,"%c\t\teql\n",ch);break;case ',':fprintf(cifa,"%c\t\tcomma\n",ch);break;case '#':fprintf(cifa,"%c\t\tneq\n",ch);break;case ';':fprintf(cifa,"%c\t\tsemicolon\n",ch);break;case '.':break;default :error(26);}if(sym!=period){//判断是否结束getchdo;}else{printf("\n");fprintf(cifa,".\t\tperiod\n");}}}}}}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;}//测试字符串int test(bool* s1,bool* s2,int n){if(!inset(sym,s1)){//测试sym是否属于s1,不属于则报错nerror(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;//保留初始txint cx0;//保留初始cxbool nxtlev[symnum];dx=3;//相对地址从3开始,前3个单元即0、1、2单元分别为 SL:静态链;//DL:动态链;RA:返回地址tx0=tx;//记录本层的初始位置table[tx].adr=cx;gendo(jmp,0,0);if(lev>levmax){//层数超过3error(32);}do{if(sym==constsym){//收到常量声明printf("该语句为常量定义语句\n");getsymdo;do{constdeclarationdo(&tx,lev,&dx);//常量声明处理,dx 会改//变所以使用指针while(sym==comma){//处理一次多常量定义getsymdo;constdeclarationdo(&tx,lev,&dx);}if(sym==semicolon){//常量声明处理结束getsymdo;}else{error(5);//漏掉了逗号或者分号(一般是分号)}}while(sym==ident);}if(sym==varsym){//收到变量声明printf("该语句为变量声明语句\n");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){//收到过程声明printf("该语句为过程声明语句\n");getsymdo;if(sym==ident){enter(procedur,&tx,lev,&dx);//记录过程名getsymdo;}else{error(4);//过程声明后应为标识符}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;cx0=cx;gendo(inte,0,dx);//生成分配内存代码if(tableswitch){//输出符号表if(tx0+1<tx){fprintf(fas,"TABLE:\n");//printf("NULL\n");}for(i=tx0+1;i<=tx;i++){switch(table[i].kind){case constant:fprintf(fas,"%d const %s ",i,table[i].name);fprintf(fas,"val=%d\n",table[i].val);break;case variable:fprintf(fas,"%d var %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%d\n",table[i].level,table[i].adr);break;case procedur:fprintf(fas,"%d proc %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%dsize=%d\n", table[i].level,table[i].adr,table[i].size);break;}}}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;}//k:const var procedure//ptx:符号表尾的指针//pdx:dx为当前应分配变量的相对地址//lev:符号名字所在的层次//往符号表中添加void enter(enum object k,int* ptx,int lev,int* pdx){(* ptx)++;strcpy(table[(*ptx)].name,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;}}//寻找符号在符号表中的地址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);}return 0;}//变量声明处理int vardeclaration (int* ptx,int lev,int* pdx){if(sym==ident){enter(variable,ptx,lev,pdx);getsymdo;}else{error(4);}return 0;}//输出目标代码清单void listcode(int cx0){int i;if(listswitch){for(i=cx0;i<cx;i++){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){getsymdo;printf("该语句为赋值语句。

第二章PL0编译程序的实现

第二章PL0编译程序的实现
是整个编译过程的核心。
PL/0编译程序的总体设计
词法分析程序和代码生成程序都作为一个过 程,当语法分析需要读单词时就调用词法分 析程序,而当语法、语义分析正确,需要生 成相应的目标代码时,则调用代码生成程序
表格管理程序实现变量,常量和过程标识符 的信息的登录与查找。
出错处理程序,对词法和语法、语义分析遇 到的错误给出在源程序中出错的位置和与错 误 性质有关的编号,并进行错误恢复。
read(b);
end
end.
2.1.2 PL/0语言文法的EBNF表示
BNF(BACKUS-NAUR FORM)是根据美国 的John W.Backus与丹麦的Peter Naur来 命名的,它从语法上描述程序设计语言的元 语言(metalanguage)。
采用BNF就可说明哪些符号序列是对于某给 定语言在语法上有效的程序。
自顶向下的语法分析<程序>
<分程序>
.
VAR A; BEGIN READ(A) END.
<变量说明部分> <语句>
VAR <标识符> ; <复合语句> BEGIN <语句> END
A <读语句>
READ ( <标识符> )
A
递归子程序法
递归子程序法:对应每个非终结符语法单元,
编一个独立的处理过程(或子程序)。 语法分析从读入第一个单词开始由非终结符
非终结符(non-terminal symbol)—在描述 过程中定义的,代表某一类语法单位的集合 的,需要继续定义的符号。
终结符(terminal symbol)—最终定义的不能 用更小的语法单位替换的符号。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
11
BEGIN g:=a+e; f:=g; WRITE(g) END.
第二章 编译程序的实现
6 实验要求
实验名称:词法分析程序 实验目的: 实现功能: 实验报告内容:
第二章 编译程序的实现
12
实验目的
设计、编制、调试一个词法分析 程序,加深对词法分析原理的理解。
第二章 编译程序的实现
13
实现功能
BEGIN CALL r; WRITE(f); f:=a+e*f; WRITE(f,d) END; BEGIN d:=a+b; WRITE(d); CALL q END; PROCEDURE s; B 程 q 的 过 程 体 过 程 p 的 过 程 体
<语句部分 > ::= <语句 > |<复合语句 > <复合语句 > ::= BEGIN <语句 > {; <语句 > } END <复合语句 >举例: BEGIN a:=b+c; IF a>=0 THEN flag:=1 END
第二章 编译程序的实现 23
2、PL/0语法规则的BNF表示
<语句>::= <赋值语句>|<条件语句>|<当型 循环语句>| <过程调用语句>|<读语句>| <写语句>| <复合语句>
(PROGRAM PROGSYM),(mysource IDENT) , (CONST CONSTSYM) , (a IDENT) , (= EQL) , (10 NUMBER) , (; SEMICOLON) , (VAR VARSYM) , (b IDENT) , (, COMMA) , (c IDENT) , (; SEMICOLON) , (PROCEDURE PROCSYM) , …… (g IDENT) , (:= BECOMES) , (a IDENT) , (+ PLUS) , (e IDENT) , (; SEMICOLON) This is a assign Statement;(赋值语句) (f IDENT) , (:= BECOMES) , (g IDENT) , (; SEMICOLON) This is a assign Statement; (赋值语句) (WRITE WRITESYM) , (( LPAREN) , (g IDENT) , ( ) RPAREN) , (; SEMICOLON) This is a write Statement;(写语句) ……
<常量说明部分 > ::= CONST <常量定义 >{, <常量定义 >} ;
<常量定义 > ::= <标识符>= <无符号整数>
<常量说明部分>举例: CONST a=10,b=5;
常量定义
第二章 编译程序的实现 20
2、PL/0语法规则的BNF表示
<变量说明部分 > ::= VAR <标识符>{, <标识符>} ;
10
PROGRAM main; CONST a=10,e=5; VAR f,g;
第二章 编译程序的实现
PL/0源程序(续):
词法分析程序输出(续)
(BEGIN (g (:= (a (+ (e (; (f (:= (g (; (WRITE (( (g () (END (. BEGINSYM) IDENT) BECOMES) IDENT) PLUS) IDENT) SEMICOLON) IDENT) BECOMES) IDENT) SEMICOLON) WRITESYM) LPAREN) IDENT) RPAREN) ENDSYM) PERIOD)
CALL test1;
过程名
第二章 编译程序的实现
28
2、PL/0语法规则的BNF表示
<条件语句>::=IF <条件>THEN<语句>
<条件语句>举例: IF a>=0 THEN flag:=1
第二章 编译程序的实现
29
2、PL/0语法规则的BNF表示
<当型循环语句>::= WHILE <条件>DO <语句> <当型循环语句>例: WHILE a>=0 DO flag:=1
N
滤空格
ID:=A
N Y
标识符 SYM:=IDENT
保留字
保留字 SYM:=WSYM[K]
第二章 编译程序的实现 8
5、词法分析程序的输入和输 出
输入:PL/0源程序 输出:单词类别值、单词自身值组成 的二元组
第二章 编译程序的实现
9
PL/0源程序:
词法分析程序输出:
(PROGRAM (main (; (CONST (a (= (10 (, (e (= (5 (; (VAR (f (, (g (; PROGSYM) IDENT) SEMICOLON) CONSTSYM) IDENT) EQL) NUMBER) COMMA) IDENT) EQL) NUMBER) SEMICOLON) VARSYM) IDENT) COMMA) IDENT) SEMICOLON)
第二章 编译程序的实现
26
2、PL/0语法规则的BNF表示
<写语句>::= WRITE(<表达式>{, <表达式>}) <写语句>举例: WRITE( a+b,b*c);
第二章 编译程序的实现
27
2、PL/0语法规则的BNF表示
<过程调用语句>::=CALL <标识符>; <过程调用语句>举例:
第二章 编译程序的实现 4
3、完成的任务
(1)滤空格; (2)识别保留字;
(3)识别标识符;
(4)识别常量; (5)识别界符;
第二章 编译程序的实现 5
4、PL/0词法分析程序的设计
CH:当前符号; ID:当前标识符的单词自身值; SYM:当前单词的类别值; NUM:当前常量的单词自身值; WORD:保留字表; WSYM:保留字的单词类别值; SSYM:界符的类别值;
第二章 编译程序的实现
30
2、PL/0语法规则的BNF表示
<因子>::=
<标识符>|<常量>|(<表达式>)
PROCEDURE FACTOR P294~P295
第二章 编译程序的实现
31
2、PL/0语法规则的BNF表示
<项>::=
<因子>|<项> <乘法运算符><因子>
<乘法运算符>::=*|/
<变量说明部分 >举例: VAR a,b;
第二章 编译程序的实现
21
2、PL/0语法规则的BNF表示
<过程说明部分 > ::= <过程首部> ;<分程序>
<过程首部> ::= PROCEDURE <标识符> <过程首部>举例: PROCEDURE test1
过程名
第二章 编译程序的实现 22
2、PL/0语法规则的BNF表示
第二章 编译程序的实现
一、PL/0编译程序的词法分析 二、PL/0编译程序的语法分析 三、PL/0编译程序的伪代码生成
第二章 编译程序的实现
1
一、PL/0编译程序的词法分析
1、基本思想 2、PL/0程序设计语言的词法规则
3、完成的任务
4、PL/0词法分析程序的设计
5、词法分析程序的输入和输出
第二章 编译程序的实现 6
词法分析程序的程序框图
第二章 编译程序的实现
7
CH=‘ ’ GETCH
N
N
Y
CH=字母
Y
N
K:=0 K<10
Y
标识符长度 小于10 Y
常量 SYM:=NUMBER NUM:=数值
CH=数字
N
K:=K+1,A[K]:=CH GETCH
Y
界符 SYM:=SSYM[CH]
字母,数字
第二章 编译程序的实现
36
符号表
符号表的内容 符号表的结构 相关子程序的流程图 实验要求
第二章 编译程序的实现
37
符号表的建立
PL/0编译文本是在处理: (1)变量说明VAR (2)常量说明CONST (3)过程说明PROCEDURE 建立符号表table 按照标识符在源程序出现的先后顺序来建表。
第二章 编译程序的实现
15
二、 PL/0编译程序的语法分析
1、基本思想 2、PL/0语法规则的BNF表示
3、语法分析程序的输入和输出
4、符号表的建立
5、实验要求
第二章 编译程序的实现
16
1、基本思想
采用自顶向下的递归子程序法, 即为每一个非终结符号编写一个独 立的子程序。
第二章 编译程序的实现
<条件>::=
<表达式> <关系运算符><表达式>
|ODD <表达式> <关系运算符>::=#|=|>|>=|<|<=
PROCEDURE CONDITION P296~P297
第二章 编译程序的实现 34
3、语法分析程序的输入
PROGRAM mysource; CONST a=10; VAR b,c; PROCEDURE p; VAR d; PROCEDURE q; CONST e=5; VAR f; PROCEDURE r; VAR g; 过 程 BEGIN g:=a+e; 的 过 f:=g; 程 WRITE(g) 体 END;
相关文档
最新文档