当前位置:文档之家› 编译原理课程设计报告

编译原理课程设计报告

武汉纺织大学编译原理课程设计实验报告学院:数学与计算机专业:计算机姓名:班级:学号:constdccl rtrfilri onVEM'decl OTIli-expression to ftnconditionintet'prct函数:)过程或曲数名功能简蔑说咽pio主程序error出错处理*打印出错位苫和错误编码gdsym词济分祈,煤取一t单詞秦理空格,读収「牛字苻生止目标优码.井送入目林序区test義试当前单诵符是否合法block务析程启噩理讨稈enterpnwfiion(画慰)查找标识符在名字丢中肿位置constdeclaratiDn常虽定克牲理TardeclaratiDn变虽主兗魁理listccxle列出目掃诧码詩单statemeiitespressiiMi盂这式处理tennfactorcrnidiiicn条件辿埋iiiteipret刖日标吒码购解释执厅程序通过静蠱穆求;L数据仅的宰地圳编译原理课设报告一、实验目的加强对编译程序的整体认识和了解,巩固《编译原理》课程所学知识。

通过本次课程设计掌握编译程序调试技巧和设计编译程序一般的原则,加深对词法分析、语法分析、语义分析等编译阶段及实用编译系统的认识。

使学生能将编译理论与实际应用结合起来,提高学生软件开发的能力。

二、实验内容1)仔细阅读PL/O编译程序文本(编译原理(第二版)张素琴吕映芝蒋维杜戴桂兰主编清华大学出版社),并上机调试通过。

2)对PL/0语言进行下列扩充(1)扩充一维整型数组。

扩充var数组:VAR <数组标识名>(<下界>:<上界>)〈下界〉和〈上界〉可用常量标识名。

(2)扩充条件语句的功能使其为:IF<条件>THEN齬句>[ELSE语句>](3)增加repeat重复语句:REPEAT<语句>{;<语句>}UNTIL<条件>可根据自己具体情况从中选择2个以上题目进行扩充。

三、实验原理PL/0语言可以看成PASCALS言的子集,它的编译程序是一个编译解释执行系统。

PL/0的目标程序为假想栈式计算机的汇编语言,与具体计算机无关。

PL/0的编译程序和目标程序的解释执行程序都是用PASCAL语言书写的,因此PL/0语言可在配备PASCAL语言的任何机器上实现。

其编译过程采用一趟扫描方式,以语法分析程序为核心,词法分析和代码生成程序都作为一个独立的过程,当语法分析需要读单词时就调用词法分析程序,而当语法分析正确需要生成相应的目标代码时,则调用代码生成程序。

用表格管理程序建立变量、常量和过程表示符的说明与引用之间的信息联系。

当源程序编译正确时,PL/0编译程序自动调用解释执行程序,对目标代码进行解释执行,并按用户程序的要求输入数据和输出运行结果。

编译原理errortest隔麺功能说阴孟:四、实验分析PL/O语言编译程序采用以语法分析为核心、一遍扫描的编译方法。

词法分析和代码生成作为独立的子程序供语法分析程序调用。

语法分析的同时,提供了出错报告和出错恢复的功能。

在源程序没有错误编译通过的情况下,调用类PCODE解释程序解释执行生成的类PCODE代码。

词法分析子程序分析:词法分析子程序名为GETSYM功能是从源程序中读出一个单词符号(TOTAKEN,把它的信息放入全局变量SYM ID和NUM中,字符变量放入CH中,语法分析器需要单词时,直接从这三个变量中获得。

Getch过程通过反复调用Getch子过程从源程序过获取字符,并把它们拼成单词。

GETCH过程中使用了行缓冲区技术以提高程序运行效率。

词法分析器的分析过程:调用GETSYM时,它通过GETCH过程从源程序中获得一个字符。

如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把SYM变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把SYM置为IDENT,把这个单词存入ID变量。

查保留字表时使用了二分法查找以提高效率。

如果Getch获得的字符是数字,则继续用Getch获取数字,并把它们拼成一个整数或实数,然后把SYM置为INTEGER或REAL并把拼成的数值放入NUM变量。

如果识别出其它合法的符号(比如:赋值号、大于号、小于等于号等),则把SYM则成相应的类型。

如果遇到不合法的字符,把SYM 置成NUL。

语法分析子程序分析:语法分析子程序采用了自顶向下的递归子程序法,语法分析同时也根据程序的语义生成相应三元代码,并提供了出错处理的机制。

语法分析主要由分程序分析过程(BLOCK、参数变量分析过程(ParaDeclaration、、参数变量处理过程(ParaGetSub)、数组处理过程(ParaGetSub)、常量定义分析过程(ConstDeclaration、、变量定义分析过程(Vardeclaration、、语句分析过程(Stateme nt )、表达式处理过程(Expressio n)、项处理过程(Term)、因子处理过程(Factor、和条件处理过程(Condition、构成。

这些过程在结构上构成一个嵌套的层次结构。

除此之外,还有出错报告过程(Error)、代码生成过程(Gen)、测试单词合法性及出错恢复过程(Test)、登录名字表过程(Enter、、查询名字表函数(Position)以及列出类PCODE 代码过程(Listcode、作过语法分析的辅助过程。

由PL/0的语法图可知:一个完整的PL/0程序是由分程序和句号构成的。

因此,本编译程序在运行的时候,通过主程序中调用分程序处理过程block来分析分程序部分(分程序分析过程中还可能会递归调用block过程),然后,判断最后读入的符号是否为句号。

如果是句号且分程序分析中未出错,则是一个合法的PL/0程序,可以运行生成的代码,否则就说明源PL/0程序是不合法的,输出出错提示即可。

if-then-else语句的处理:按if语句的语法,首先调用逻辑表达式处理过程处理if语句的条件,把相应的真假值放到数据栈顶。

接下去记录下代码段分配位置(即下面生成的jpc指令的位置),然后生成条件转移jpc指令(遇0或遇假转移),转移地址未知暂时填0。

然后调用语句处理过程处理then 语句后面的语句或语句块。

then后的语句处理完后,如果遇到else,就调用语句处理过程处理else语句后面的语句或语句块,这时当前代码段分配指针的位置就应该是上面的jpc指令的转移位置。

通过前面记录下的jpc指令的位置,把它的跳转位置改成当前的代码段指针位置,否则没遇到else,那么此时的当前代码段分配指针的位置也是上面jpc指令的转移位置,也是通过前面记录下的jpc位置指令的位置,把它的跳转到当前的代码段指针位k-i/ii■< !-|XVh luDotlWh kidraidJlRepeat 语句的处理:首先用CX1变量记下当前代码段分配位置,作为循环的开始位置。

然后通过递归调用语句 分析过程分析,直到遇到until 保留字,如果未对应 until 则出错。

调用条件表达式处理过程生成相应代码把结果放在数据栈顶,再生成条件转移指令,转移位置为上面记录的CX1。

tSkl宝 £ 丿 .2」实验代码;PLO.h 代码: #in elude <stdio.h> #in elude <set> #in elude <stri ng> #in elude <iostream> #in elude <iostream> #in elude <veetor> #ifndef WIRTH ZYC #define WIRTH ZYC using n amespaee std;〃 no. of reserved words 保留字的个数// le ngth of ide ntifier table 标示符表的长度(容量)// le ngth of ide ntifiers 标示符的最大长度// max. no. of digits in nu mbers 数字的最大长度 // maximum address 寻址空间 // maximum depth of block nest ing最大允许的块嵌套层数// size of code array 类PCODE 目标代码数组长度 (可容纳代 const int lineLength = 82; // 行缓冲区长度T 二)<Z>m五、 相关代码及运行结果 con st i nt norw = 16; con st i nt txmax = 100; const int al = 10; con st i nt nmax = 14; con st i nt amax = 2047;con st i nt levmax = 3; con st i nt exmax =typedef enum{NUL,IDENT,NUMBER,PLUS,MINUS,TIMES,SLASH,ODDSYM,EQL,NEQ,LSS,LEQ,GTR,GEQ,LPAREN,RPAREN,COMMA,SEMICOLON,PERIOD,BECOMES,BEGINSYM,ENDSYM,IFSYM,THENSYM,WHIL ESYM,WRITESYM,READSYM,DOSYM,CALLSYM,CONSTSYM,VARSYM,PROCSYM,ELSESYM,REPEATSY M,UNTILSYM} symbol; // symobl 类型标识了不同类型的词汇typedef char alfa[al+1]; // alfa 类型用于标识符typedef enum {CONSTANT,VARIABLE,PROCEDURE,ARRAY} obj0; // 三种标识符的类型typedef enum {LIT,OPR,LOD,STO,CAL,INT,JM,JPC} fct; // functionstypedef set<symbol> symset;struct instruction{fct f; // function codeint l; // level,cann't big than levmaxint a; // displacement address,cann't big than amax}; //类PCODE指令类型,包含三个字段:指令f、层差I和另一个操作数a/******************************************** Iit 0,a: Ioad constant a* opr 0,a: execute operation a* Iod I,a: Ioad variabIe I,a* sto I,a: store variabIe I,a* caI I,a: caII procedure a at IeveI I* int 0,a: increment t-register by a* jmp 0,a: jump to a* jpc 0,a: jump conditionaI to a *******************************************/typedef struct{aIfa name;obj0 kind;union {struct{int IeveI,adr,size;}inOther; int vaI;}other;} TabIe;cIass PL0{protected:bool listswitch,sourceEnd; char ch; symbol sym; II last character read II last symbol read II last identifier read II last number readalfa int id; num;int cc; II character count int ll;II line lengthint kk,err;int cx;II code allocation index int codeNo;II code line no.// error string// code line// error array// 词法分析器中用于临时存放正在分析的词// destination code array // 保留字表// 保留字表中每一个保留字对应的 symbol // 一些符号对应的 symbol 类型表II 类PCODE 指令助记符表symset declbegsys,statbegsys,facbegsys; // 声明开始、表达式开始和项开始符号集个字符static string errStr[]; char line[lineLength];vector<string> errorString; alfa a;instruction code[cxmax+1]; alfa word[norw+1];symbol wsym[norw+1]; 类型 symbol ssym[100]; char mnemonic[8][6];合Table table[txmax+1]; FILE* fin,*fout; public:PL0(char* source,char*destination); ~PL0(){fclose(fin),fclose(fout);}void error(int n);位置和出错代码void getsym();个单词void getch();II 符号表II 构造函数 II 析构函数II 出错处理, 打印出错II 词法分析,读取一 II 漏掉空格, 读取一void gen(fct x,int y,int z); II 生成目标代码,并送入目标void test(symset s1,symset s2,int n);合法void block(int lev,int tx,symset fsys); //分程序分析处理过程void enter(obj0 k,int &tx,int &dx,int lev); //登入名字表int position(alfa id,int tx);// 查找标示符在名字表中的位置void constdeclaration(int&tx,int&dx,int lev); // 常量定义处理void vardeclaration(int&tx,int&dx,int lev);//变量说明处理void listcode(int cx0);// 列出目标代码清单void statement(symset fsys,int tx,int lev); //语句部分处理void expression(symset fsys,int tx,int lev); // 表达式处理void term(symset fsys,int tx,int lev); // 项处理void factor(symset fsys,int tx,int lev);//因子处理void condition(symset fsys,int tx,int lev);// 条件处理void arraydeclaration(int& tx,int& dx,int lev);// 数组说明处理void interpret();// 对目标代码的解释执行程序int base(int l,int b,int s[]);// 通过静态链求出数据区的基地址void SaveCode();// 保存代码};#endifPL0.cpp 代码: #include "pl0.h" // 错误字符串数组string PL0::errStr[]={" ","error 0001: 常数说明中“ =”写成“: =” ", "error 0002: 常数说明中的“ =”后应为数字 ","error 0003: 常数说明中的标识符后应是“ =” ", "error 0004: const,var,procedure 后应为标识符 ", "error 0005: 漏掉了‘ ,'或‘ ;' ","error 0006: 过程说明后的符号不正确(应是语句开始符或过程开始符) "error 0007: 应是语句开始符 ","error 0008: 过程体内语句部分的后跟符不正确 ", "error 0009: 程序皆为丢了句号‘ .' ", "error 0010: 语句之间漏了‘ ;' ", "error 0011: 标识符没说明 ","error 0012: 赋值语句中,赋值号左部标识符属性应是变量 ", "error 0013: 赋值语句左部标识符应是赋值号 :=",程序区// 测试当前单词符号是否"error 0014: call 后应为标识符","error 0015: call 后标识符属性应为过程","error 0016: 条件语句中丢了then","error 0017: 丢了end 或;","error 0018: while 型循环语句中丢了do","error 0019: 语句后的标识符不正确","error 0020: 应为关系运算符","error 0021: 表达式内标识符属性不能是过程","error 0022: 表达式中漏掉了右括号‘ )' ","error 0023: 因子后的非法符号","error 0024: 表达式开始符不能是此符号","error 0025: 文件在不该结束的地方结束了","error 0026: 结束符出现在不该结束的地方","error 0027: ","error 0028: ","error 0029: ","error 0030: " "error 0031: 数越界","error 0032: read 语句括号中标识符不是变量","error 0033: else 附近错误" ,"error 0034: repeat 附近错误"};// PL0 构造函数PL0::PL0(char* source,char*destination) {listswitch=true,sourceEnd=false;strcpy(word[1],"begin"); strcpy(word[2],"call");// 初始化存储保留字strcpy(word[3],"const"); strcpy(word[4],"do"); strcpy(word[5],"else"); strcpy(word[6],"end");strcpy(word[7],"if"); strcpy(word[8],"odd"); strcpy(word[9],"procedure");strcpy(word[10],"read"); strcpy(word[11],"repeat"); strcpy(word[12],"then");strcpy(word[13],"until"); strcpy(word[14],"var"); strcpy(word[15],"while");strcpy(word[16],"write");wsym[1]= BEGINSYM; wsym[2]= CALLSYM;// 初始化保留字表中每一个保留字对应的symbol 类型wsym[3]= CONSTSYM; wsym[4]= DOSYM;wsym[5]= ELSESYM; wsym[6]= ENDSYM;wsym[7]= IFSYM; wsym[8]= ODDSYM;wsym[9]= PROCSYM; wsym[10]= READSYM;wsym[11]= REPEATSYM; wsym[12]=THENSYM;wsym[13]= UNTILSYM; wsym[14]= VARSYM; wsym[15]= WHILESYM; wsym[16]=WRITESYM;memset(code,0,sizeof(code)); memset(ssym,0,100*sizeof(symbol));memset(table,0,sizeof(table));memset(line,0,sizeof(line));ssym['+']= PLUS; // 初始化一些符号对应的symbol 类型表ssym['-']= MINUS;ssym['*']= TIMES;ssym['/']= SLASH;ssym['(']= LPAREN;ssym[')']= RPAREN;ssym['=']= EQL;ssym[',']= COMMA;ssym['.']= PERIOD;ssym['#']= NEQ;ssym['<']= LSS;ssym['>']= GTR;ssym[';']= SEMICOLON;strcpy(mnemonic[LIT]," lit"); // 初始化类PCODE指令助记符表strcpy(mnemonic[OPR]," opr "); strcpy(mnemonic[LOD]," lod "); strcpy(mnemonic[STO]," sto"); strcpy(mnemonic[CAL]," cal "); strcpy(mnemonic[INT]," int ");strcpy(mnemonic[JMP]," jmp "); strcpy(mnemonic[JPC]," jpc ");declbegsys.insert(CONSTSYM),declbegsys.insert(VARSYM),declbegsys.insert(PROCSYM); // 初始化声明开始符号集合statbegsys.insert(BEGINSYM),statbegsys.insert(CALLSYM),statbegsys.insert(IFSYM),statb egsys.insert(WHILESYM); // 初始化表达式开始符号集合facbegsys.insert(IDENT),facbegsys.insert(NUMBER),facbegsys.insert(LPAREN); // 初始化项开始符号集合err= 0;cc= 0;cx= 0;置生成新的代码ll= 0;ch= ' ';kk= al;codeNo=0;fin=fopen(source,"r");fout=fopen(destination,"w");}// 行缓冲区指针// 代码分配指针,代码生成模块总在// 行缓冲区长度// last character read// 引入此变量是出于程序性能考虑// code line no.// 出错处理,打印出错位置和出错代码void PL0::error(int n){char s[10];sprintf(s," 第%d 行:",codeNo); errorString.push_back(s+errStr[n]); err=err+1;//error count}//error end// 词法分析,读取一个单词void PL0::getsym(){if(sourceEnd)return;int i,j,k;while (ch ==' '||ch==9)getch(); // cls space and tab if(isalpha(ch)) // id or reserved word {k=0;memset(a,0,al+1);// 检测一个单词长度do{if (k < al){a[k]= ch; k= k+1;cx 所指位}getch();if(sourceEnd)return; }while(isalpha(ch)||isdigit(ch)); if(k >= kk) kk = k;else{do{a[kk]= ' ';kk= kk-1;}while(kk > k);}strcpy(id,a);i= 1;j= norw;// 判断是否是关键字(二分搜索) 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];elsesym= IDENT;}else if(isdigit(ch)) // number{k= 0;num= 0;sym= NUMBER;do{num= 10 * num + ch - '0';k= k+1;getch();}while(isdigit(ch));if(k > nmax)error(30);}else if (ch == ':'){getch();if( ch == '='){sym= BECOMES;getch();}elsesym= NUL;}else if(ch == '<') // extra stuff added to support <={getch();if (ch== '='){sym= LEQ;getch();}elsesym= LSS;}else if (ch == '>'){getch();if( ch == '='){sym= GEQ;getch();}elsesym= GTR;}else // end of extra stuff{sym= ssym[ch]; // 其它符号的赋值getch();}}// 漏掉空格,读取一个字符void PL0::getch(){if(cc == ll){if(feof(fin)){}if(sym!=PERIOD)error(25); sourceEnd=true; return; }cc= 0; fgets(line,lineLength,fin); codeNo++; ll=strlen(line);if(line[ll-1]==10) ll--;}ch= line[cc];cc= cc+1;}// 生成目标代码,并送入目标程序区void PL0::gen(fct x,int y,int z){if (cx > cxmax){cout<<"Program too long\n";return;}code[cx].f= x;code[cx].l= y;code[cx].a= z;cx= cx+1;}//gen end// 测试当前单词符号是否合法void PL0::test(symset s1,symset s2,int n){if(sourceEnd) return;if (s1.find(sym)==s1.end()){error(n);symset::iterator it;for(it=s2.begin();it!=s2.end();it++) s1.insert(*it);//s1=s1+s2 while(s1.find(sym)==s1.end()) getsym();}//test end// 分程序分析处理过程void PL0::block(int lev,int tx,symset fsys){ if(sourceEnd) return;int dx; // data allocation index int tx0; // initial table index int cx0; // initial code index dx= 3; // 变量的个数tx0= tx; // 表指针table[tx].other.inOther.adr= cx; gen(JMP,0,0);if( lev>levmax) error(32);do{if( sym == CONSTSYM) // 处理常量声明{getsym(); do{constdeclaration(tx,dx,lev); while (sym == COMMA) {getsym(); constdeclaration(tx,dx,lev);}if (sym ==SEMICOLON)getsym();else error(5);}while(sym==IDENT);}if( sym == VARSYM) // 处理变量声明{getsym(); do{vardeclaration(tx,dx,lev); while( sym == COMMA){ getsym();vardeclaration(tx,dx,lev);}if( sym ==SEMICOLON)getsym();elseerror(5);}while(sym==IDENT);}while( sym ==PROCSYM) // 处理过程的声明{getsym();if (sym ==IDENT){ enter(PROCEDURE,tx,dx,lev); getsym();}elseerror(4);if( sym ==SEMICOLON)getsym();elseerror(5);symset tmp = fsys;tmp.insert(SEMICOLON);block(lev+1,tx,tmp);if (sym == SEMICOLON){ getsym(); symset tmp = statbegsys; for(int i=IDENT;i<=PROCSYM;i++) tmp.insert((symbol)i);test(tmp,fsys,6);}elseerror(5);}symset tmp=statbegsys;tmp.insert(IDENT); test(tmp,declbegsys,7);}while(declbegsys.find(sym)!=declbegsys.end());code[table[tx0].other.inOther.adr].a= cx; table[tx0].other.inOther.adr= cx; // start adr of code table[tx0].other.inOther.size=dx;cx0= cx;gen(INT,0,dx);symset tmp=statbegsys;for(int i=SEMICOLON;i <= ENDSYM;i++)tmp.insert((symbol)i);statement(tmp,tx,lev);gen(OPR,0,0); // returnsymset s2;test(fsys,s2,8);listcode(cx0);}// block end// 登入名字表void PL0::enter(obj0 k,int &tx,int &dx,int lev){tx= tx+1;strcpy(table[tx].name,id);table[tx].kind=k;switch(k){case CONSTANT:if(num>amax){error(31);num=0;}table[tx].other.val=num;break;case VARIABLE: table[tx].other.inOther.level=lev; table[tx].other.inOther.adr=dx; dx++;break;case PROCEDURE: table[tx].other.inOther.level=lev; break;case ARRAY:table[tx].other.inOther.size = lev;break;}}//enter end// 查找标示符在名字表中的位置int PL0::position(alfa id,int tx)//find identifier id in table { int i; strcpy(table[0].name, id);i= tx;while (strcmp(table[i].name,id)!=0)i--;return i;}//position end// 常量定义处理void PL0::constdeclaration(int&tx,int&dx,int lev){if(sym == IDENT){getsym();if(sym>=EQL&&sym<=BECOMES){if( sym ==BECOMES)error(1);getsym();if( sym == NUMBER){enter(CONSTANT,tx,dx,lev); getsym();}elseerror(2);}elseerror(3);}elseerror(4);}// constdeclaration end// 变量说明处理void PL0::vardeclaration(int&tx,int&dx,int lev){if( sym == IDENT){enter(VARIABLE,tx,dx,lev);getsym();}elseerror(4);}//vardeclaration end// 数组说明处理void PL0::arraydeclaration(int&tx,int&dx,int lev){int upscript=0,downscript=0; getsym();if(sym == NUMBER || sym == CONSTSYM){if(num == 0){ upscript = num; getsym();}else error(32);} if(sym == COMMA) getsym();elseerror(32);if(sym == NUMBER || sym == CONSTSYM){downscript = num; getsym();} if(sym != RPAREN)error(32);else{ enter(ARRAY,tx,dx,downscript+1); getsym();}}// 列出目标代码清单void PL0::listcode(int cx0)//list code generated for this block {int i; if(listswitch)for (i= cx0;i<cx;i++) cout<<" "<<i<<" "<<mnemonic[code[i].f] <<" "<<code[i].l<<""<<code[i].a<<endl;}// listcode end// 语句部分处理void PL0::statement(symset fsys,int tx,int lev){ if(sourceEnd) return;int i,cx1,cx2;if(sym ==IDENT){i= position(id,tx);if (i == 0)error(11);else if (table[i].kind!=VARIABLE){error(12);i= 0;}getsym();if(sym ==BECOMES)getsym();elseerror(13);expression(fsys,tx,lev);if(sym != SEMICOLON)error(10);if( i!= 0)gen(STO,lev-table[i].other.inOther.level,table[i].other.inOther.adr); }else if( sym == READSYM){getsym();if( sym!=LPAREN)error(34);elsedo{getsym();if (sym==IDENT)i=position(id,tx);elsei=0;if( i==0 )error(35);else{gen(OPR,0,16); gen(STO,lev-table[i].other.inOther.level,table[i].other.inOther.adr);}getsym();}while(sym == COMMA);if (sym != RPAREN){error(33);while (fsys.find(sym)!=fsys.end()) getsym();}elsegetsym();}else if( sym == WRITESYM ){getsym();if (sym==LPAREN){do{getsym();symset tmp=fsys;for(int t=RPAREN;t<=COMMA;t++)tmp.insert((symbol)t);expression(tmp,tx,lev);gen(OPR,0,14);}while(sym==COMMA);if (sym!=RPAREN)error(33);elsegetsym();}gen(OPR,0,15);}else if( sym ==CALLSYM){getsym();if( sym!=IDENT)error(14);else{i= position(id,tx);if (i == 0)error(11);else if (table[i].kind = PROCEDURE)gen(CAL,lev-table[i].other.inOther.level,table[i].other.inOther.adr);else error(15);getsym();}}else if( sym ==IFSYM){getsym();symset tmp=fsys;for(int i = THENSYM;i<= DOSYM;i++)tmp.insert((symbol)i); condition(tmp,tx,lev); if( sym == THENSYM)getsym();elseerror(16); cx1= cx; gen(JPC,0,0); tmp.insert(ELSESYM); statement(tmp,tx,lev);getsym(); code[cx1].a= cx;if(sym == ELSESYM){getsym();cx2=cx; gen(JMP,0,0); code[cx1].a=cx; statement(fsys,tx,lev); code[cx2].a=cx;}}else if( sym ==BEGINSYM){getsym();symset tmp=fsys;for(int i=SEMICOLON;i<=ENDSYM;i++)tmp.insert((symbol)i); statement(tmp,tx,lev); tmp=statbegsys;tmp.insert(SEMICOLON); while( tmp.find(sym)!=tmp.end()) {if(sourceEnd)return;if (sym ==SEMICOLON||sym ==ENDSYM) getsym();else if(sym=PERIOD){error(26);getsym();}elseerror(10);tmp=fsys;for(i=SEMICOLON;i<=ENDSYM;i++)tmp.insert((symbol)i); if(sourceEnd)return; if(sym==ENDSYM)break;statement(tmp,tx,lev);}if( sym ==ENDSYM) getsym();else if(!sourceEnd) error(17);}else if(sym ==WHILESYM) {cx1= cx;getsym();symset tmp=fsys;tmp.insert(DOSYM);condition(tmp,tx,lev); cx2= cx;句的开始位置gen(JPC,0,0);if(sym ==DOSYM) getsym();elseerror(18); statement(fsys,tx,lev); gen(JMP,0,cx1); code[cx2].a= cx;} else if(sym == REPEATSYM) {symset temp1, temp2; temp1=fsys,temp1.insert(SEMICOLON),temp1.insert(UNTILSYM); cx1= cx;getsym(); statement(temp1,tx,lev); temp2 = statbegsys;temp2.insert(SEMICOLON); while(temp2.find(sym) != temp2.end()){if(sym == SEMICOLON) getsym();else error(34);statement(temp1,tx,lev);}if(sym == UNTILSYM){ getsym(); condition(fsys,tx,lev); gen(JPC,0,cx1);}else error(34);} symset setT; test(fsys,setT,19);}//statement end// 记下当前代码分配位置, 这是 while 循环的开始// 记下当前代码分配位置, 这是 while 的 do 中的语// 表达式处理void PL0::expression(symset fsys,int tx,int lev){symbol addop;symset tmp=fsys;for(int t=PLUS;t<=MINUS;t++) tmp.insert((symbol)t);if( sym>=PLUS&&sym<=MINUS){ addop= sym; getsym();term(tmp,tx,lev);if( addop ==MINUS)gen(OPR,0,1);}elseterm(tmp,tx,lev);while (sym >=PLUS&&sym<=MINUS){addop= sym;getsym(); term(tmp,tx,lev); if (addop ==PLUS) gen(OPR,0,2);elsegen(OPR,0,3);}}// expression end// 项处理void PL0::term(symset fsys,int tx,int lev){if(sourceEnd)return;symbol mulop;symset tmp=fsys;for(int t=TIMES;t<=SLASH;t++)tmp.insert((symbol)t);factor(tmp,tx,lev);while( sym>=TIMES && sym<=SLASH){mulop= sym;getsym();factor(tmp,tx,lev);if (mulop ==TIMES)gen(OPR,0,4);elsegen(OPR,0,5);}}// term end// 因子处理void PL0:: factor(symset fsys,int tx,int lev){int i;test(facbegsys,fsys,24);while(facbegsys.find(sym)!=facbegsys.end()) {if( sym ==IDENT) {i= position(id,tx);if( i == 0)error(11);elseswitch(table[i].kind){case CONSTANT: gen(LIT,0,table[i].other.val); break;case VARIABLE: gen(LOD,lev-table[i].other.inOther.level,table[i].other.inOther.adr); break;case PROCEDURE: error(21); break;}getsym();}else if (sym ==NUMBER){if (num>amax){error(31);num= 0;}gen(LIT,0,num);getsym();}else if( sym ==LPAREN){getsym();symset tmp=fsys;tmp.insert(RPAREN);expression(tmp,tx,lev);if (sym == RPAREN)getsym();elseerror(22);} test(fsys,facbegsys,23);}}//factor end// 条件处理void PL0::condition(symset fsys,int tx,int lev){symbol relop;symset tmp=fsys;tmp.insert(EQL),tmp.insert(NEQ),tmp.insert(LSS),tmp.insert(LEQ),tmp.insert(GTR),tmp.i nsert(GEQ);if( sym == ODDSYM){expression(fsys,tx,lev);gen(OPR,0,6);}else{expression(tmp,tx,lev);if(tmp.find(sym)==tmp.end())error(20);else{relop= sym;getsym();expression(fsys,tx,lev);switch(relop){case EQL: gen(OPR,0,8);break;case NEQ: gen(OPR,0,9);break;case LSS: gen(OPR,0,10);break;case GEQ: gen(OPR,0,11);break;case GTR: gen(OPR,0,12);break;case LEQ: gen(OPR,0,13);break;}}}}//condition end// 对目标代码的解释执行程序void PL0::interpret(){int err1=errorString.size(); if(err1>0){cout<<"存在%d 个错误:"<<err1<<endl;for(int i=0;i<err1;i++) cout<<errorString[i]<<endl;//return;}const int stacksize = 500;int p=0,b=1,t=0;//program-,base-,topstack-registersinstruction i;// instruction registerint s[stacksize+1]={0};// datastorecout<<" Start PL/0\n";do{i= code[p];p= p+1;{case LIT:t= t+1;s[t]= i.a; break;case OPR: switch(i.a) //operator {case 0:// return t= b-1; p= s[t+3]; b= s[t+2]; break;case 1:s[t]= -s[t]; break;case 2:t= t-1;s[t]= s[t]+s[t+1]; break;case 3:t= t-1;s[t]= s[t]-s[t+1]; break;case 4:t= t-1;s[t]= s[t]*s[t+1];break;case 5:t= t-1;s[t]= s[t] / s[t+1];break;case 6:if(s[t]%2) s[t]=1;elses[t]=0;break;case 8:t= t-1;if(s[t]==s[t+1]) s[t]=1;elses[t]=0;break;case 9:t= t-1;if(s[t]==s[t+1]) s[t]=0;elses[t]=1;break;case 10:t= t-1;if(s[t]<s[t+1]) s[t]=1;elses[t]=0;break;case 11:t= t-1;if(s[t]>=s[t+1]) s[t]= 1;else s[t]=0;break;case 12:t= t-1;if(s[t]>s[t+1]) s[t]= 1;else s[t]=0;break;case 13:t= t-1;if(s[t]<=s[t+1])s[t]= 1;elses[t]=0;break;case 14:cout<<" "<<s[t];t=t-1;break;case 15:cout<<endl;break;case 16:t=t+1;cout<<"?";s[t]=0;cin>>s[t];break;};break;case LOD:t= t+1;s[t]= s[base(i.l,b,s)+i.a]; break; case STO:s[base(i.l,b,s)+i.a]= s[t];t= t-1;break;case CAL:// generate new block marks[t+1]= base(i.l,b,s);s[t+2]= b;s[t+3]= p;b= t+1;p=i.a;break;case INT:t= t+i.a;break; case JMP:p= i.a;break; caseJPC:if (s[t] == 0)p= i.a; t= t-1; break;}//switch end }while(p!=0); cout<<" End PL/0\n";} // interpret end// 通过静态链求出数据区的基地址int PL0::base(int l,int b,int s[]) {int b1;b1= b;//find base l levels down while(l>0){b1= s[b1];l= l-1;}return b1;}// 保存代码void PL0::SaveCode(){ if(fout)for (int i=0;i<cx;i++)fprintf(fout,"%d %s %d %d\n ",i,mnemonic[code[i].f],code[i].l,code[i].a);}TestPLO.cpp 代码:#include "pl0.h"void main(){PL0 cp("testPas2.txt","nasm.txt");symset fsys;fsys.insert(PERIOD); fsys.insert(CONSTSYM),fsys.insert(VARSYM),fsys.insert(PROCSYM); fsys.insert(BEGINSYM),fsys.insert(CALLSYM),fsys.insert(IFSYM),fsys.insert(WHILESYM);cp.getsym();cp.block(0,0,fsys); cp.SaveCode(); cp.interpret();// 词法分析,分析一个词// 分程序分析处理功能// 保存代码// 对目标代码的解释执行程序}实验运行结果:运行的的文件见下图右侧:实验中我是固定了文件名的,可以是改写成动态输入,由于在测试中我把所有的测试语句都放在同一个文件中了,没有太多的必要。

相关主题