PL0编译程序实现的简要回顾
第二章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编译程序)
[标准实验报告]南昌航空大学实验报告年月日课程名称:编译原理实验名称:扩充的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编译程序的实现 (上)
2.1
PL/0 语言描述
2.1.1 PL/0语言的语法描述图 下面借用语法图来描述语法规则。其中: 英文表示终结符,中文表示非终结符。 终结符:构成语言文法的单词,是语法成分 的最小单位。 非终结符:是个语法成分,还没有进行分析。 程 序
分 程 序
语 句
条ቤተ መጻሕፍቲ ባይዱ:
表 达 式
项
因子:
2.12 PL/0 语言文法的EBNF表示
单词的种类有五种:
1. 基本字:也称保留字,如END、IF等
2. 运算符:如+、—、*、/、> =、# 等等
3. 标识符:用户定义的变量名、常数名、 过程名 4. 常数:如100等整数
5. 界符:如‘,’、‘.’、‘(’‘;’ 等
词法分析程序完成下列任务: 1.滤空格:语法分析时没用 2.识别保留字:对应的类别放在SYM中,若查不到, 认为是用户定义的标识符 3.识别标识符:对用户定义的标识符放在SMY中, 标识符本身的值放在ID中 4.拼数:所取单词是数字时,将数的类别放在SYM 中,数值本身的值存放在NUM中 5.拼复合词:对两个字符组成的算符进行识别(<=) 6.输出源程序:边读入字符边输出
源程序
表 格 管 理 程 序
词法分析程序 语法分析程序
代码生成程序
出 错 处 理 程 序
目标程序
PL/0编译程序的过程或 函数的功能表见表2.1
过程或函数的嵌套定 义层次结构如图2.3 所示
语法分析程序
图2.4 PL/0编译程序总体流程图
2.3 PL/0编译程序的词法分析
词法分析程序是为语法分析提供单词用 的,是语法分析的基础。它把输入的字 符串形式的源程序分割成一个个单词符 号。编译器为此设置了3个全程量的公用 单元为: SYM:存放每个单词的类别 ID:存放用户所定义的标识符的值 NUM:存放用户定义的数
pl0编译原理
pl0编译原理编译原理是计算机科学中的一门重要课程,它研究的是如何将高级语言转化为机器语言的过程。
在编译原理中,pl0是一种简单的编程语言,它的设计目标是为了教学和研究目的而产生的。
本文将介绍pl0编译原理的基本概念和主要过程。
一、pl0编译原理的基本概念1.1 什么是pl0编程语言pl0是一种结构化的过程性编程语言,它的语法规则简单明了,易于学习和理解。
pl0支持基本的数据类型和控制结构,包括整型、实型、布尔型等。
1.2 pl0编译器的作用pl0编译器的主要作用是将pl0源代码转化为目标代码,使计算机能够理解和执行这些代码。
编译器的工作包括词法分析、语法分析、语义分析、中间代码生成和目标代码生成等。
1.3 pl0编译过程的主要阶段pl0编译过程主要包括词法分析、语法分析、语义分析和代码生成等阶段。
在词法分析阶段,编译器将源代码分解成一个个的词法单元;在语法分析阶段,编译器将词法单元按照语法规则组织成一个抽象语法树;在语义分析阶段,编译器对抽象语法树进行语义检查和类型推导;最后,在代码生成阶段,编译器将抽象语法树转化为目标代码。
二、pl0编译原理的主要过程2.1 词法分析词法分析是编译过程的第一步,它将源代码分解成一个个的词法单元。
在pl0编译器中,常见的词法单元包括关键字、标识符、常量、运算符和界符等。
编译器通过正则表达式和有限自动机等技术来实现词法分析。
2.2 语法分析语法分析是编译过程的第二步,它将词法单元按照语法规则组织成一个抽象语法树。
在pl0编译器中,常见的语法规则包括表达式、语句、函数和过程等。
编译器通过上下文无关文法和递归下降等技术来实现语法分析。
2.3 语义分析语义分析是编译过程的第三步,它对抽象语法树进行语义检查和类型推导。
在pl0编译器中,常见的语义检查包括变量声明检查、类型匹配检查和作用域检查等。
编译器通过符号表和类型推导等技术来实现语义分析。
2.4 代码生成代码生成是编译过程的最后一步,它将抽象语法树转化为目标代码。
PL0编译概述讲解
类P-code虚拟机
指令 “OPR 0 0”
T’
《编译原理》
过程调用结束后,返回调用点并退栈 重置基址寄存器和栈顶寄存器
. . . RA’ DL’ . . . T . . . RA B DL SL . . . B = DL’ 返返返 返返返 返返 P 返 RA’ T = B’
B’
SL’ . . . RA DL ቤተ መጻሕፍቲ ባይዱL . . .
PL/0 语言的 EBNF 表示
例:PL/0 语言的EBNF表示
<程序> ::= <分程序>.
<分程序> ::= [<常量说明部分>] [<变量说明部分>] [<过程说明部分>] <语句>
《编译原理》
<常量说明部分> ::= CONST <常量定义> { ,<常量定义> } ; <常量定义> ::= <标识符> = <无符号整数> <无符号整数> ::= <数字> {<数字>} <变量说明部分> ::= VAR <标识符 > { , <标识符 > } ; <标识符> ::= <字母> {<字母>|<数字>} <过程说明部分> ::= <过程首部><分程序>{; <过程说明部分> }; <过程首部> ::= PROCEDURE <标识符> ;
PL/0 程序示例
计算最大公约数
var m, n, r, q; { 计算m和n的最大公约数 } procedure gcd; begin while r#0 do begin q := m / n; r := m - q * n; m := n; n := r; end end;
第2章 PL0编译程序的实现
1
2. 1 PL/0语言描述
终结符和非终结符 ➢ 终结符是最小的语法单位,例如构成文法的单词。 ➢ 非终结符是一个语法单位,它可以由其他一些语法单位组 成,即可以由其他一些终结符和非终结符串、或终结符串 组成。
PL/0语言的语法描述图 ➢ 用圆圈表示终结符 ➢ 用长方形表示非终结符
10
回家作业
1 编写一个PL0语言的程序,要求:
a) 声明2个常数,c1为2,c2为10 b) 声明3个变量,num1、count和sum c) 第一条语句是赋值语句,将c1赋给num1 d) 第二条语句是条件语句,如果num1>0,则执行第三条语句,
否则将num1减1 e) 第三条语句是赋值语句,将0赋给sum e) 第四条语句是循环语句,循环变量count从1到c2,每次将
常量说明部分
变量说明部分 过程说明部分
语句
<分程序>::=[<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句>
9
由语法描述图转化到BNF范式
常量定义
<常量说明部分>::=CONST<常量定义>{,<常量定义>}; <常量定义>::=<标识符>=<无符号整数> <无符号整数>::=<数字>{<数字>}
a+2(x+10)是不是表达式?
6
BNF范式
BNF(Backus Normal Form)范式表示
< > 用左右尖括号括起来的中文字表示待描述的语法 成分<语法单位>,为非终结符
PL0 编译程序讲解
write(2*c);
变量c
(16) lit 0 2 (17) lod 0 4 (18) opr 0 4 (19) opr 0 14
read(b);
变量b
end
end.
RA 0
(20) opr 0 15 换行
DL 0
(21) opr 0 16 (22) sto 0 3 (23) jmp 0 11 (24) opr 0 0
调用getsym取单词
调用block过程
当前单词 是否为源程序结束符
'.'? Y
源程序中 是否有错误?
N 调用解释过程interpret
解释执行目标程序
PL/0编译程序 语法、语义分
析的核心
N 出错
Y 打印错误
结束
3.2 PL/0编译程序词法分析的实现
词法分析函数getsym()所识别的单词: 保留字或关键字:如:BEGIN、 END、 IF、 THEN等 运算符: 如:+、-、*、/、:=、#、>=、<=等 标识符: 用户定义的变量名、常数名、过程名 常数: 如:10、25、100等整数 界符: 如:‘,’、‘.’ 、‘;’ 、‘(’ 、‘)’等
PL/0程序示例
CONST A=10; (* 常量说明部分 *) VAR B,C; (* 变量说明部分 *) PROCEDURE P; (* 过程说明部分 *)
VAR D;(* P的局部变量说明部分 *) PROCEDURE Q; (* P的局部过程说明部分 *) VAR X;
BEGIN READ(X); D:=X; IF X#0 DO CALL P;
PL/0编译程序
PL/0源程序
PL/0
PL0编译程序的实现(精)
( 0) ( 1) ( 2) ( 3) ( 4) ( 5) ( 6) ( 7) ( 8) ( 9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) (20) (21) (22) (23) (24)
jmp jmp int lod lit opr sto opr int opr sto lod lit opr jpc cal lit lod opr opr opr opr sto jmp opr
PL/0编译程序功能的框架 PL/0源程序 PL/0编译程序
类 pcode代码
类 pcode解释程序 输入 输出
第2 章
PL/0编译程序的实现
步骤1. 源语言PL/0与目标代码类pcode 之间的映射 步骤2. PL/0编译程序的总体设计 步骤3. PL/0编译程序词法分析的设计与实现 步骤4. PL/0编译程序语法语义分析的设计与实现 步骤5. PL/0编译程序代码生成的实现 *步骤6. PL/0编译程序错误处理的实现 步骤7. 类pcode代码解释器的设计与实现
步骤1 PL/0程序到类pcode代码的映射
目标代码类pcode是一种假想栈式计算机的汇编 语言。 指令格式 f l a
f
l a
功能码
层次差 (标识符的引用层减去它的定义层) 根据不同的指令有所区别
假想栈式计算机的运行栈 T是栈顶指针 B是基地址:分配给一个过程数据空间的开始位置 T
B
2 1 0
步骤3
PL/0编译程序词法分析的 设计与实现
词法分析如何把单词传递给语法分析 单词定义(见教材288页) type symbol=(nul,ident,number,plus,…, varsym,procsym); ( 定义纯量/枚举类型,类似C的enum) sym:symbol; id:alfa; (type alfa=packed array[1..al] of char) al=10; num:integer;
第二章 PL0编译程序的实现
编译原理
◇ 建议用一个PL/0源程序的例子为导引作为 阅读PL/0语言编译程序文本的入门,然后再逐步 全面读懂。 ◇ 通过对PL/0语言编译程序某些指定功能的 扩充,加深对编译程序构造步骤和实现技术的理 解,并能在实践中应用。 【教学方式】 以学生自学为主。
编译原理
【难 重 点】 重点: ◇ 弄清源语言(PL/0)目标语言(类 pcode)实现 语言(pascal) 这3个语言之间的关系和作用。 ◇ 掌握用语法图和扩充的巴科斯-瑙尔范式 (EBNF)对一个高级程序设计语言的形式描述。 ◇ 了解PL/0语言编译程序的语法分析技术采用 的是自顶向下递归子程序法。 ◇ 掌握PL/0语言编译程序的整体结构和实现步 骤,并弄清词法分析、语法分析、语义分析、代码 生成及符号表管理每个过程的功能和相互联系。
编译原理
第2章 PL/0编译程序的实现
【学习目标】 本章目的:以PL/0语言编译程序为实例,学习编 译程序实现的基本步骤和相关技术,对编译程序的构 造和实现得到一些感性认识和建立起整体概念,为后 面的原理学习打下基础。 ◇ 了解用语法图和扩充的巴科斯-瑙尔范式 (EBNF)对 PL/0语言的形式描述。 ◇ 了解PL/0语言编译程序构造和实现的基本技 术和步骤。 ◇ 了解PL/0语言编译程序的目标程序在运行时 数据空间的组织管理。
返回目录
Байду номын сангаас
编译原理
【学习指南】 ◇ 要求读者阅读PL/0语言编译程序文本,了 解一个编译程序构造的必要步骤和实现技术。一个 编译程序的实现比较复杂,读懂一个典型的程序从 设计思想到实现技术也有一定难度,特别是入门开 始需要耐心。一但读懂,不仅了解编译程序的实现 方法和技术,还可学到许多编程技巧和好的编程风 格。 ◇ 阅读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语言编译程序分析和详细注释(Pascal版
PL/0语言编译程序分析PL/0语言是Pascal语言的一个子集,我们这里分析的PL/0的编译程序包括了对PL/0语言源程序进行分析处理、编译生成类PCODE代码,并在虚拟机上解释运行生成的类PCODE代码的功能。
PL/0语言编译程序采用以语法分析为核心、一遍扫描的编译方法。
词法分析和代码生成作为独立的子程序供语法分析程序调用。
语法分析的同时,提供了出错报告和出错恢复的功能。
在源程序没有错误编译通过的情况下,调用类PCODE解释程序解释执行生成的类PCODE代码。
词法分析子程序分析:词法分析子程序名为getsym,功能是从源程序中读出一个单词符号(token),把它的信息放入全局变量sym、id和num中,语法分析器需要单词时,直接从这三个变量中获得。
(注意:语法分析器每次用完这三个变量的值就立即调用getsym子程序获取新的单词供下一次使用。
而不是在需要新单词时才调用getsym过程)。
getsym过程通过反复调用getch子过程从源程序过获取字符,并把它们拼成单词。
getch过程中使用了行缓冲区技术以提高程序运行效率。
词法分析器的分析过程:调用getsym时,它通过getch过程从源程序中获得一个字符。
如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到则为保留字,把sym变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把sym 置为ident,把这个单词存入id变量。
查保留字表时使用了二分法查找以提高效率。
如果getch获得的字符是数字,则继续用getch获取数字,并把它们拼成一个整数,然后把sym置为number,并把拼成的数值放入num变量。
如果识别出其它合法的符号(比如:赋值号、大于号、小于等于号等),则把sym则成相应的类型。
如果遇到不合法的字符,把sym置成nul。
语法分析子程序分析:语法分析子程序采用了自顶向下的递归子程序法,语法分析同时也根据程序的语意生成相应的代码,并提供了出错处理的机制。
PL0语言编译器分析实验报告
PL0语言编译器分析实验报告1. 引言1.1 PL0语言简介PL0语言是一种早期的程序设计语言,由瑞士计算机科学家尼克劳斯·沃斯(Niklaus Wirth)于1970年左右设计。
它是为了教学目的而设计的,具有简单、清晰、易于理解的特点。
PL0语言是一种过程式编程语言,不支持面向对象编程。
它的语法与Pascal语言相似,是许多编程语言教材中的入门语言。
1.2 编译器概述编译器是一种将高级编程语言源代码转换为低级机器语言或中间代码的程序。
它主要包括词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等阶段。
编译器的主要目的是提高程序的可移植性、执行效率和开发效率。
1.3 实验目的与意义本次实验通过对PL0语言编译器的分析,旨在让学生深入了解编译器的工作原理和实现方法,提高编程实践能力。
实验的意义在于:1.加深对编译原理的理解,掌握编译器各阶段的基本任务和关键技术;2.培养学生独立分析问题、解决问题的能力;3.提高学生的编程技巧,为后续学习更高级的编程语言打下基础;4.通过实验,使学生了解编译器在软件开发中的重要作用,为今后从事软件开发工作奠定基础。
2 PL0语言编译器原理2.1 编译器的工作流程编译器的工作流程主要包括词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等阶段。
1.词法分析:将源程序中的字符序列转换为记号(Token)序列。
2.语法分析:根据语法规则,将记号序列转换为抽象语法树(AST)。
3.语义分析:检查源程序是否有语义错误,如类型检查、作用域检查等。
4.中间代码生成:将AST转换为中间代码,方便后续优化和目标代码生成。
5.代码优化:对中间代码进行优化,提高目标代码的执行效率。
6.目标代码生成:将优化后的中间代码转换为特定平台的目标代码。
2.2 PL0语言的词法、语法和语义1.词法:PL0语言的词法规则包括标识符、常数、运算符和界限符等。
2.语法:PL0语言的语法规则定义了各种语句和表达式的结构,如条件语句、循环语句、赋值语句等。
PL0编译程序的实现
译程序实现的基本步骤和相关技术,对编译程序的 构造和实现得到一些感性认识和建立起整体概念, 为后面的原理学习打下基础。
◇ 了解并掌握用语法图和扩充的巴科斯-瑙尔 范式(EBNF)对计算机语言的形式描述。
【难 重 点】 重点: ◇ 弄清源语言(PL/0)目标语言(类 pcode)实现
2. V集n合是N一on个-te非rm空in有als穷,集且合V,t称Vn作= 非。终结符号 3. S Vn ,称作开始符号Start Symbol 。 4. P是一个非空有穷集合,称为产生式集合
Production Rules ,每条产生式形为A,其22 中AV ,(V V )*。
例2.1 简单的算术表达式
17
Bakus-Naur范式(BNF)
18
Examples of BNF
19
Syntax Graph
20
2.2 语法定义
❖ 语法描述程序设计语言的层次结构,如C语言 的条件语句为
if_stmt if (expr) stmt else stmt if_stmt if (expr) stmt
string
string + string
string - string 2
9
5
string
string - string
9 string + string
5
2
对某个文法,如一个句子有两棵以上的分析树,称为
二义(歧义)文法。
29
2.2.3 Associativity of Operators
❖ 可以用括号来表明计算顺序,如 9-5+2 = (9-5)+2
PL0语言实验报告
PL0语⾔实验报告PL/0语⾔是Pascal语⾔的⼀个⼦集,我们这⾥分析的PL/0的编译程序包括了对PL/0语⾔源程序进⾏分析处理、编译⽣成类PCODE代码,并在虚拟机上解释运⾏⽣成的类PCODE代码的功能。
PL/0语⾔编译程序采⽤以语法分析为核⼼、⼀遍扫描的编译⽅法。
词法分析和代码⽣成作为独⽴的⼦程序供语法分析程序调⽤。
语法分析的同时,提供了出错报告和出错恢复的功能。
在源程序没有错误编译通过的情况下,调⽤类PCODE解释程序解释执⾏⽣成的类PCODE代码。
词法分析⼦程序分析:词法分析⼦程序名为getsym,功能是从源程序中读出⼀个单词符号(token),把它的信息放⼊全局变量sym、id和num中,语法分析器需要单词时,直接从这三个变量中获得。
(注意!语法分析器每次⽤完这三个变量的值就⽴即调⽤getsym⼦程序获取新的单词供下⼀次使⽤。
⽽不是在需要新单词时才调⽤getsym过程。
)getsym过程通过反复调⽤getch⼦过程从源程序过获取字符,并把它们拼成单词。
getch过程中使⽤了⾏缓冲区技术以提⾼程序运⾏效率。
词法分析器的分析过程:调⽤getsym时,它通过getch过程从源程序中获得⼀个字符。
如果这个字符是字母,则继续获取字符或数字,最终可以拼成⼀个单词,查保留字表,如果查到为保留字,则把sym变量赋成相应的保留字类型值;如果没有查到,则这个单词应是⼀个⽤户⾃定义的标识符(可能是变量名、常量名或是过程的名字),把sym 置为ident,把这个单词存⼊id 变量。
查保留字表时使⽤了⼆分法查找以提⾼效率。
如果getch获得的字符是数字,则继续⽤getch获取数字,并把它们拼成⼀个整数,然后把sym置为number,并把拼成的数值放⼊num变量。
如果识别出其它合法的符号(⽐如:赋值号、⼤于号、⼩于等于号等),则把sym则成相应的类型。
如果遇到不合法的字符,把sym置成nul。
语法分析⼦程序分析:语法分析⼦程序采⽤了⾃顶向下的递归⼦程序法,语法分析同时也根据程序的语意⽣成相应的代码,并提供了出错处理的机制。
编译原理PL0编译程序的实现2(希赛教育基础学院)
2.2 PL/0编译程序的结构由2.1节可知,PL/0语言可看成是PASCAL语言的子集,它的编译程序是一个编译解释执行系统。
PL/0的目标程序为假想栈式计算机的汇编语言,与具体计算机无关。
PL/0的编译程序和目标程序的解释执行程序都是用PASCAL语言书写的,因此PL/0语言可在配备PASCAL语言的任何机器上实现。
其编译过程采用一趟扫描方式,以语法分析程序为核心,词法分析程序和代码生成程序都作为一个独立的过程,当语法分析需要读单词时就调用词法分析程序,而当语法分析正确需生成相应的目标代码时,则调用代码生成程序。
此外,用表格管理程序建立变量、常量和过程标识符的说明与引用之间的信息联系。
用出错处理程序对词法和语法分析遇到的错误给出在源程序中出错的位置和错误性质。
当源程序编译正确时,PL/0编译程序自动调用解释执行程序,对目标代码进行解释执行,并按用户程序要求输入数据和输出运行结果。
其编译和解释执行的结构图如图2.2(a)和2.2(b)所示。
PL/0的编译程序和目标程序的解释执行程序都是用PASCAL语言书写的,因此PL/0语言可在配置有PASCAL语言的任何机器上实现。
读者也可用其它语言改写PL/0编译程序,也可以用另一种语言编写目标代码类pcode的解释执行程序。
PL/0编译程序的编译过程是按源程序顺序进行分析的,常量变量说明部分不产生目标代码。
图 2.2(a) PL/0编译程序的结构图图 2.2(b) PL/0的解释执行结构PL/0编译程序是用PASCAL语言书写的,整个编译程序(包括主程序)是由18个嵌套及并列的过程或函数组成,下面分别简要给出这些函数的功能及它们的层次结构。
如表2.1和图2.3所示。
表 2.1 PL/0编译程序的过程或函数的功能表这些过程或函数的嵌套定义层次结构如图2.3所示。
图 2.3 PL/0编译程序过程与函数定义层次结构图由于PL/0编译程序采用一趟扫描方法,所以语法分析过程BLOCK是整个编译过程的核心。
PL0语言编译器的设计与实现
PL0语⾔编译器的设计与实现⼀、设计任务1.1程序实现要求PL/0语⾔可以看成PASCAL语⾔的⼦集,它的编译程序是⼀个编译解释执⾏系统。
PL/0的⽬标程序为假想栈式计算机的汇编语⾔,与具体计算机⽆关。
PL/0的编译程序和⽬标程序的解释执⾏程序都是⽤JAVA语⾔书写的,因此PL/0语⾔可在配备JDK的任何机器上实现。
其编译过程采⽤⼀趟扫描⽅式,以语法分析程序为核⼼,词法分析和代码⽣成程序都作为⼀个独⽴的过程,当语法分析需要读单词时就调⽤词法分析程序,⽽当语法分析正确需要⽣成相应的⽬标代码时,则调⽤代码⽣成程序。
⽤表格管理程序建⽴变量、常量和过程标⽰符的说明与引⽤之间的信息联系。
⽤出错处理程序对词法和语法分析遇到的错误给出在源程序中出错的位置和错误性质。
当源程序编译正确时,PL/0编译程序⾃动调⽤解释执⾏程序,对⽬标代码进⾏解释执⾏,并按⽤户程序的要求输⼊数据和输出运⾏结果。
1.2 PL/0语⾔的BNF描述(扩充的巴克斯范式表⽰法)<prog> → program <id>;<block><block> → [<condecl>][<vardecl>][<proc>]<body><condecl> → const <const>{,<const>};<const> → <id>:=<integer><vardecl> → var <id>{,<id>};<proc> → procedure <id>([<id>{,<id>}]);<block>{;<proc>}<body> → begin <statement>{;<statement>}end<statement> → <id> := <exp>|if <lexp> then <statement>[else <statement>]|while <lexp> do <statement>|call <id>([<exp>{,<exp>}])|<body>|read (<id>{,<id>})|write (<exp>{,<exp>})<lexp> → <exp> <lop> <exp>|odd <exp><exp> → [+|-]<term>{<aop><term>}<term> → <factor>{<mop><factor>}<factor>→<id>|<integer>|(<exp>)<lop> → =|<>|<|<=|>|>=<aop> → +|-<mop> → *|/<id> → l{l|d} (注:l表⽰字母)<integer> → d{d}注释:<prog>:程序;<block>:块、程序体;<condecl>:常量说明;<const>:常量;<vardecl>:变量说明;<proc>:分程序; <body>:复合语句;<statement>:语句;<exp>:表达式;<lexp>:条件;<term>:项; <factor>:因⼦;<aop>:加法运算符;<mop>:乘法运算符; <lop>:关系运算符。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Lex文件格式
%{
#include <math.h>
%}
DIGIT [0-9]
ID
[a-z][a-z0-9]*
%%
{DIGIT}+ {
printf(“An integer: %s (%d)\n”,
yytext,atoi(yytext));}
{ID}
printf( "An identifier: %s\n", yytext );
<分程序> <变量说明部分> VAR <标识符>
A
<程序> .
<语句>
; <复合语句>
BEGIN
<语句>
END
<读语句>
READ ( <标识符> )
A
VAR A; 自底向上的语法分<程析序>
BEGIN READ(A)
END.
<分程序>
<语句>
<复合语句>
<变量说明部分> <标识符>
<语句> <读语句> <标识符>
printf( “An identifier: %s\n”, yytext ); strcpy(yylval.id,yytext); return ID } printf( "An operator: %s\n", yytext ); return OPR }
Yacc文件格式
%{ C DECLARATIONS %}
%right '^' /* exponentiation
*/
❖ 五、二义性及移进/规约冲突
❖ 六、出错处理
PL/0源程序
PL/0编译程序
pcode代码
注:此处的pcode代码专指PL/0的目标码,注意与传统pcode的区别
pcode解释程序
❖ 步骤1、 认识源语言PL/0与目标代码pcode及它 们之间的映射
❖ 步骤2、 PL/0编译程序的总体设计 ❖ 步骤3、 PL/0编译程序词法分析的设计与实现 ❖ 步骤4、 PL/0编译程序语法语义分析的设计与
NUM
{ $$ = $1;
}
| exp '+' exp
{ $$ = $1 + $3; }
| exp '-' exp
{ $$ = $1 - $3; }
| exp '*' exp
{ $$ = $1 * $3; }
| exp '/' exp
{ $$ = $1 / $3; }
| '-' exp %prec NEG { $$ = -$2;
❖ 目标代码pcode是一种假想栈式计算机的汇编语言。
const
a=10;
var
b,c;
0 jmp 0 8 1 jmp 0 2
procedure
p;
begin
2 int 0 3
c:=b+a;
3 lod 1 3
end;
4 lit 5 opr 6 sto 7 opr 8 int 9 opr
0 10
begin
0 2 次栈顶与栈顶相加
read(b);
14
call
p;
00 05 0 16
在运行栈中申请5个栈空间 从命令行读入输入置于栈顶
write(c); end.
10 sto 0 3 将栈顶值存入变量
11 cal 0 2 调用过程
12 lod 0 4 将变量取至栈顶
13 opr 0 14 栈顶值输出至屏幕
14 opr 0 15 换行
"+"|"-"|"*"|"/" printf( "An operator: %s\n", yytext );
%%
main(int argc, char ** argv )
{ ++argv, --argc; /* skip over program name */
if ( argc > 0 ) yyin = fopen( argv[0], "r" );
}
| exp '^' exp
{ $$ = pow ($1, $3); }
| '(' exp ')'
{ $$ = $2;
}
Yacc文件格式中的关键问题
❖ 四、算符的优先级与结合率
%left '-' '+’
%left '*' '/’
%left NEG
/* negation--unary minus */来自VARA;
BEGIN
READ (
A)
移进 规约 接受 错误
END .
YACC&LEX介绍及实 例分析
清华大学计算机系软件研究所 赖辉旻
简要介绍
❖ Yacc ( Yet Another Compiler-Compiler )
基于LALR(1)的语法分析程序的生成器
❖ Lex (A Lexical Analyzer Generator)
❖词法分析程序的生成器,其输入是描述三型语言 的正规式,输出是一个相应正规表达式的词法分 析程序。
输入
词法规则(.l文件)
语法规则(.y文件)
Lex yylex()
Yacc yyparse()
输出
{definitions} %% {rules} %% {user subroutines}
实例:一个Java编译 器的Lex程序
else
yyin = stdin;
yylex();
}
Lex文件格式中应注意的问题
正规表达式:
IDENTIFIER DIGIT HEXDIGIT HEXNUMBER
[A-Za-z][A-Za-z0-9]* [0-9] [A-Fa-f0-9] 0[Xx]{HEXDIGIT}+
语义动作:
{ID}
{
"+"|"-"|"*"|"/" {
一个简单实例
BISON DECLARATIONS
实例:一个Java编译器的 Yacc程序
%% GRAMMAR RULES %%
ADDITIONAL C CODE
Yacc文件格式中应注意的问题
❖ 一、TOKEN的定义 %token NUM
%token <id> IDENT
❖ 二、语法规则与语义动作
exp:
实现 ❖ 步骤5、 PL/0编译程序代码生成的实现 ❖ 步骤6、 PL/0编译程序语法错误处理的实现 ❖ 步骤7、 pcode代码解释器的设计与实现
❖ PL/0语言:PASCAL语言的子集,功能简单,结构清 晰,可读性强,具备了一般高级语言的必备部分
❖ PL/0程序示例 ❖ PL/0的非形式描述 ❖ PL/0的语法描述图 ❖ PL/0语言文法的EBNF表示
15 opr 0 0
RA 12 DL 0 SL 0 变量2 变量1 RA 0 DL 0
SL:静态链
SL 0 0
DL:动态链
运行栈
RA:返回地址
出错处理程序 表格管理程序
PL/0源程序 词法分析程序 语法语义分析程序 代码生成程序
目标程序
自顶向下的语法分析
VAR A; BEGIN
READ(A) END.