编译原理--增加数据类型_第1页
编译原理--增加数据类型_第2页
编译原理--增加数据类型_第3页
编译原理--增加数据类型_第4页
编译原理--增加数据类型_第5页
免费预览已结束,剩余40页可下载查看

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、/pl0.h/ 这个文件中的代码与课本的一致/对于使用C+勺编译器,这句话可以注释掉,但对于C语言不行/typedef enum FALSE,TRUE, bool;#define norw 16 / 关键字勺个数#define txmax 100 / 名字表勺容量#define nmax 14 / 数字勺最大位数#define al 10 / 符号勺最大长度#define amax 2047 / 地址上界#define levmax 3 / 最大允许勺嵌套声明层数#define cxmax 200 / 最多勺虚拟机代码数enumsymbol/ 枚举类型:/nul=0 , ident=1 , n

2、umber=2, plus=3 , minus=4/times=5 ,依次类推, procsym=31nul,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

3、, readsym, dosym, callsym, constsym, varsym, procsym, integersym,charactersym,doubsym, charnum,integercon,doubnum;#define symnum 38enumobjectconstant,variable,procedur,integer, character, doub,;enumfct lit, sto, jmp,opr, cal, jpc,lod, inte,;#definefctnum 11struct instructionenum fct f; / 虚拟机代码指令int

4、l; / 引用层与声明层的层差 double a; / 根据 f 的不同而不同,参考课本 ;FILE* fas; / 输出名字表FILE* fa; / 输出虚拟机代码FILE* fa1; / 输出源文件及其各行对应的首地址FILE* fa2; / 输出结果bool listswitch; bool tableswitch; char ch; / 获取字符的缓冲区 enumsymbol sym;char idal+1; double num; int cc,ll; /cc 表示当前字符的位置 int cx; / 虚拟机代码指针 char line81; / 读取行缓冲区 char aal+1;

5、/ 临时符号,多出的一个字节用于表示字符串的结尾 struct instruction code cxmax;/ 存放虚拟机代码的数组char wordnorwal; / 保留字enumsymbol wsymnorw; / 保留字对应的符号值 enumsymbol ssym256; / 单符号的符号值 char mnemonic fctnum5; / 虚拟机代码指令的名称 bool declbegsyssymnum; / 表示声明开始的符号集合 bool statbegsyssymnum; / 表示语句开始的符号集合 bool facbegsyssymnum; / 表示因子开始的符号集合 /

6、名字表结构 struct tablestructchar nameal; / 名字/enum datatype type;/ 数据类型: integer,character,doub, enumobject kind; / 类型: const,var,array,procedure double val; / 数值,仅 const 使用 , 使用双精度浮点型 int level; / 所处层 int adr; / 地址int size; / 需分配的数据空间;struct tablestruct tabletxmax;/ 名字表FILE* fin;FILE* fout;char fnameal

7、;int err; / 错误计数器,每出一次错误,其加一if (-1=getsym() return -1if (-1=getch() return -1if (-1=test(a,b,c) return -1if (-1=gen(a,b,c) return -1if (-1=expression_r(a,b,c) returnif (-1=factor(a,b,c) return -1if (-1=term(a,b,c) return -1if (-1=condition(a,b,c)return -1if (-1=statement(a,b,c)return -1#define getsy

8、mdo#define getchdo#define testdo(a,b,c)#define gendo(a,b,c)#define expressiondo(a,b,c)-1#define factordo(a,b,c)#define termdo(a,b,c)#define conditiondo(a,b,c)#define statementdo(a,b,c)#define constdeclarationdo(a,b,c)if (-1=constdeclaration(a,b,c) return -1#define vardeclarationdo(a,b,c)if (-1=varde

9、claration(a,b,c) return -1#define integerdeclarationdo(a,b,c)if (-1=integerdeclaration(a,b,c) return -1 #define characterdeclarationdo(a,b,c)if (-1=characterdeclaration(a,b,c) return -1#define doubdeclarationdo(a,b,c)if (-1=doubdeclaration(a,b,c) return -1 void error( int n);int getsym();int getch()

10、;void init();intgen( enumfct x,int y, double z);inttest( bool *s1, bool *s2, int n);intinset(int e, bool *s);intaddset(bool *sr,bool *s1,bool *s2,intn);intsubset(bool *sr,bool *s1,bool *s2,intn);intmulset(bool *sr,bool *s1,bool *s2,intn);intblock(int lev,int tx, bool * fsys);void interpret();int fac

11、tor( bool * fsys, int * ptx, int lev);int term( bool *fsys, int *ptx, int lev);int condition( bool *fsys, int *ptx, int lev);int expression_r( bool *fsys, int *ptx, int lev);int statement( bool *fsys, int *ptx, int lev);void listcode( int cx0);int vardeclaration( int * ptx, int lev, int * pdx); int

12、integerdeclaration( int * ptx, int lev, int * pdx);int characterdeclaration( int doubdeclaration( intint * ptx, int ptx, int lev, lev, int * pdx); int * pdx);int constdeclaration( int * ptx, int lev, int * pdx); int position( char * idt, int tx);void enter( enumobject k,int * ptx, int lev, int * pdx

13、);int base( int l, int * s, int b);/pl0.cpp#include #include pl0.h#include string.h函数中出现,可以先/ 这个宏定义的意思表示是运行时的数据栈大小,这个会在 interpret 不用管它#define stacksize 500*,一共有个用于列举代码* 在看源程序之前,请始终记住 * sym 表示的是当前字符串的类型, * num 表示的数字, * id 中存放的是字符串, * 记住这点在看源程序的时候非常重要。 * 另外,还要记住的是 nxtlev 数组中存放的是后继符号集* */int main()bool

14、 nxtlevsymnum; / 这个数组表示的是当前语句的后继符号集 printf( Input pl/0 file? ); / 输入文件的路径 scanf( %s ,fname);fin=fopen(fname, r ); / 以只读打开文件, fin 文件指针if (fin)printf( List object code? (Y/N) );scanf( %s,fname);listswitch=(fname0= y |fname0= Y ); /listswitch printf( List symbol table? (Y/N) );scanf( %s,fname);tableswi

15、tch=(fname0=table 表y |fname0= Y ); /tableswitch 表示是否输出/ 该表类似于页的表fa1=fopen( fa1.tmp , w); / 以只读格式打开文件, 对于本程序其实是新建一个 文件/fa1 文件中存储的是源程序,运行一次,看看这个文件就明白啦 fprintf(fa1,Input pl/0 file?); / 将 Input pl/0 file?输入文件中fprintf(fa1, %sn ,fname); / 同上 init(); / 初始化 err=0;cc=cx=ll=0;ch= ;if (-1!=getsym()/ 如果程序开始是对的,

16、则往下执行/fa 存放的是模拟程序的代码/fas 存放的是 table 表中的数据/ 运行一次代码看一下文件即明白fa=fopen( fas=fopen(fa.tmp , w ); / 以只读形式打开 fas.tmp , w); / 同上/ 函数原型: int addset(bool*sr,bool*s1,bool*s2,int n); /bool nxtlev32;/* declbegsysconstsym=true; declbegsysvarsym=true; declbegsysprocsym=true;statbegsysbeginsym=true;statbegsyscallsym

17、=true;statbegsysifsym=true;statbegsyswhilesym=true;执行该函数的结果为对应的下标在 nxtlev 中上述值均为 true ; */ 在分程序开始的时候,其后继符号可以是/const,var,procedure,begin,call,if,while/ 所以在 nxtlev 中将上述这些置为 true/ 当然在整个程序可以只有一个 . ,即程序是空的也可以,所以会有 nxtlevperiod=true;addset(nxtlev,declbegsys,statbegsys,symnum);/symnum=32 ;nxtlevperiod= tru

18、e ;/block 是编译程序的主程序,是分程序的分析处理过程,其里面调用了大部分程序/ 耐心看/ 请记住在 block 程序开始的时候,只读取了源程序的一个语句单位if (-1=block(0,0,nxtlev)/ 当程序出错的时候,则关闭以下文件,并退出程序 fclose(fa);fclose(fa1);fclose(fas);fclose(fin);printf( n );return 0;fclose(fa);fclose(fa1);fclose(fas);/ 如果在源程序的结尾没有 . ,则报错if (sym!=period)error(9);/err=0 表示源程序没有错误if (

19、err=0)/ 在源程序没有错误的前提下,打开 fa2 文件,依次执行里面的语句,输 出源程序结果fa2=fopen( fa2.tmp , w);/ 模拟计算机执行源程序interpret();fclose(fa2);else/ 如果远程有错的话,会这样printf(Errors in pl/0 program);fclose(fin);elseprintf( Cant open file! n );printf( n );return 0; void init()int i;for (i=0;i=255;i+)/ssym大小为,可以表示所有的 ASCL码ssymi=nul;nul 为,将 s

20、sym初始化为ssym+ =plus;ssym- =minus;ssym* =times;ssym/ =slash;ssym( =lparen;ssym) =rparen;ssym= =eql;ssym, =comma;ssym. =period;ssym# =neq;ssym; =semicolon;/将保留字输入word数组中,为了使用二分查找,这个设置顺序是按照字母序 /* strcpy(&(word00),begin);strcpy(&(word140),character);strcpy(&(word10),call);strcpy(&(word20),const); strcpy(

21、&(word30),do);strcpy(&(word150),doub);strcpy(&(word40),end);strcpy(&(word50),if);strcpy(&(word130),integer);strcpy(&(word60),odd);strcpy(&(word70),procedure);strcpy(&(word80),read); strcpy(&(word90),then); strcpy(&(word100),var); strcpy(&(word110),while); strcpy(&(word120),write);*/strcpy(&(word00),

22、strcpy(&(word10),begin ); call );strcpy(&(word20),characterstrcpy(&(word30),strcpy(&(word40),const );do );strcpy(&(word50),doub );strcpy(&(word60),strcpy(&(word70),end );if );strcpy(&(word80),integer );strcpy(&(word90), strcpy(&(word100), strcpy(&(word110), strcpy(&(word120), strcpy(&(word130), strc

23、py(&(word140), strcpy(&(word150),odd ); procedure read ); then ); var ); while ); write );/wsym 内放有保留字所对应的枚举变量的值wsym0=beginsym;wsym1=callsym;wsym2=charactersym;wsym3=constsym;wsym4=dosym;wsym5=doubsym;wsym6=endsym;wsym7=ifsym;wsym8=integersym;wsym9=oddsym;wsym10=procsym;wsym11=readsym;wsym12=thensym

24、; wsym13=varsym; wsym14=whilesym; wsym15=writesym;/mnemonic 中存放的是模拟程序的命令符/ 大小是个,因为只有中命令符strcpy(&(mnemoniclit0),litstrcpy(&(mnemonicopr0),oprstrcpy(&(mnemoniclod0),lodstrcpy(&(mnemonicsto0),stostrcpy(&(mnemoniccal0),calstrcpy(&(mnemonicinte0),intstrcpy(&(mnemonicjmp0),jmpstrcpy(&(mnemonicjpc0),jpc/ 初

25、始化这些数组,全部为falsefor (i=0;isymnum;i+););););););););declbegsysi=falsestatbegsysi=falsefacbegsysi= false/ 下面的这三块内容的功能在后续的介绍中会有,/ 分别是声明开始符号集,语句开始符号集,因子开始符号集 declbegsysconstsym= true ;declbegsysvarsym= true ; declbegsysprocsym= true ;declbegsysintegersym= true ; declbegsyscharactersym= true ; declbegsysd

26、oubsym= true ;statbegsysbeginsym= true ; statbegsyscallsym= true ; statbegsysifsym= true ; statbegsyswhilesym= true ;facbegsysident= true ; facbegsysnumber= true ; facbegsyslparen=true ;facbegsyscharnum= true ; facbegsysdoubnum= true ;/该函数的功能是返回符号e是否在符号集s中/ 是则返回 true ,否则返回 falseint inset( int e, boo

27、l * s)return se;/对于下标i,如果si或s2是true,则sr也是true/ 这个函数其实是初始化后继符号集,即 nxtlev 数组 int addset( bool * sr, bool * s1, bool * s2, int n) int i;for (i=0;in;i+)sri=s1i|s2i;return 0;/ 下面的函数不知干什么用,我没找到这两个函数的使用地方,不知道是不是作者弄错啦 int subset( bool* sr, bool * s1, bool* s2, int n)int i;for (i=0;in;i+)sri=s1i&(! s2i);retu

28、rn 0;int mulset( bool * sr, bool* s1, bool * s2, int n)int i;for (i=0;i= a &ch=z )k=0;doif (k= a &ch= 0 &ch=9 );ak=0;/ 单词符号以结尾strcpy(id,a);/ 将该单词符号复制到 id 数组中i=0;j=norw-1; /norw=13/ 执行二分查找,搜索该单词符号是否是保留字do k=(i+j)/2;/strcmp() 比较两个字符串,相同则为,第一个小为负,第一个大为正数 if (strcmp(id,wordk)=0)i=k+1; while (ij)sym=wsym

29、k;/如果是保留字则置为保留字的数字,wsyn是保留字对应的符号值 elsesym=ident;/如果不是保留字,则置sym为else if ( int )ch=39) / 加入字符类型 getchdo;if (ch= A &ch= a &ch= 0 &ch= 0 &ch= 0 &chnmax) 11要求数字位数不能超过位,nmax=14不过我觉得这有错误 error(30);/ 输出错误码 else if (ch= : )getchdo;if (ch= = ) sym=becomes;/如果是赋值的话,则置 sym=19getchdo;elsesym=nul;/ 个人认为这地有错,我觉得应该

30、是错误退出才对elseif (ch= )getchdo;if (ch= = )sym=geq;getchdo;elsesym=gtr;elsesym=ssymch;if (sym!=period)getchdo;return 0;/int getsym()/ int i,j,k;/ / 忽略空格,换行符,制表符/ while (ch= |ch=10|ch=9)/ / 相当于执行 if(-1=getch()/ / return -1/ 即取一个符号单位/getchdo;/ / / 功能是取一个单词符号/ if(ch=a&ch=z)/ / k=0;/do/if (k=a&ch=0&ch=9);/a

31、k=0;/ 单词符号以结尾/strcpy(id,a);/将该单词符号复制到 id 数组中/i=0;/j=norw-1;/norw=13/执行二分查找,搜索该单词符号是否是保留字/ do/k=(i+j)/2;/if (strcmp(id,wordk)=0)/i=k+1;/while(ij)/ sym=wsymk;/ 如果是保留字则置为保留字的数字/else/IIsym=ide nt;/如果不是保留字,则置sym为/ / / 取一个数字单位/ else/ / if(ch=0&ch=0&ch=0&chnmax)/要求数字位数不能超过位,nmax=14,不过我觉得这有错误error(30);/输出错误

32、码/ / / 如果是赋值运算符的话,执行这个/ else/ /if(ch=:)/ getchdo;/if(ch=)/如果是赋值的话,则置 sym=19/sym=becomes;/getchdo;/else/ sym=nul;/else个人认为这地有错,我觉得应该是错误退出才对/ / if(ch=)getchdo; if(ch=)sym=geq; getchdo;elsesym=gtr;elsesym=ssymch; if(sym!=period) getchdo;/ / / / return 0;/ int gen( enumfct x, int y, double z)if (cx=cxma

33、x) /cxmax=200printf( Program too long ); return -1;codecx.f=x;codecx.l=y;codecx.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;fsys/cc=cx=ll=0;cx 表示源程序中代码的第几行 /block(0,0,nxtle

34、v) 这是主程序 /nxtlev 中已有部分值为,大小为 int block( int lev, int tx, bool * fsys) /lev 表示分程序所在层, tx 表示当前尾指针, 表示当前模块后跟符号集int i;int dx;int tx0;int cx0;/ 新建一个bool nxtlevsymnum;dx=3; / 默认为,原因在书上tx0=tx; / 记录本层名字的初始位置tabletx.adr=cx;/cx=0 ,即 table 表的第一元素的地址为gendo(jmp,0,0);if (levlevmax) /levmax=3 ,所以该编译器允许的嵌套为层error(3

35、2);do/ 如果当前字符是 constant ,则将字符放入 table 中if (sym=constsym)/ 读取 const 后的常量符号getsymdo;do/#define constdeclarationdo(a,b,c) /if(-1=constdeclaration(a,b,c) / return -1constdeclarationdo(&tx,lev,&dx); /tx=0,lev=0,dx=3;while (sym=comma)/ 如果是逗号,则表示下一个单词串为常量,将所有 的 / 在同一行的常量符号输入 table 表中 getsymdo;constdeclarat

36、iondo(&tx,lev,&dx);if (sym=semicolon) / 为分号的时候,表示常量的读取结束,读取下一 个符号串getsymdo;elseerror(5); / 每行必须以分号结束,如果不是,则报错 while (sym=ident);/ 如果当前字符是变量,则将字符放入 table 中,形式同上述代码,如对下面不动 的请参照上面的代码if (sym=varsym)getsymdo;dovardeclarationdo(&tx,lev,&dx);while (sym=comma)getsymdo; vardeclarationdo(&tx,lev,&dx);if (sym=

37、semicolon)getsymdo;elseerror(5); while (sym=ident);/ 自己修改的/ 如果当前字符是变量,则将字符放入 table 中,形式同上述代码,如对下面不 动的请参照上面的代码if (sym=integersym)getsymdo;dointegerdeclarationdo(&tx,lev,&dx);while (sym=comma)getsymdo; integerdeclarationdo(&tx,lev,&dx);if (sym=semicolon) getsymdo;elseerror(5); while (sym=ident);/ 如果当前

38、字符是变量,则将字符放入 table 中,形式同上述代码,如对下面不 动的请参照上面的代码if (sym=charactersym)getsymdo;do characterdeclarationdo(&tx,lev,&dx); while (sym=comma) getsymdo; characterdeclarationdo(&tx,lev,&dx);if (sym=semicolon) getsymdo;elseerror(5); while (sym=ident);/ 如果当前字符是变量,则将字符放入 table 中,形式同上述代码,如对下面不 动的请参照上面的代码if (sym=do

39、ubsym)getsymdo;do doubdeclarationdo(&tx,lev,&dx); while (sym=comma) getsymdo; doubdeclarationdo(&tx,lev,&dx); if (sym=semicolon) getsymdo;elseerror(5); while (sym=ident);/ 如果当前字符是子过程,则将字符放入 table 中 while (sym=procsym)getsymdo;if (sym=ident)enter(procedur,&tx,lev,&dx); getsymdo;elseerror(4);/ 子过程的语句后

40、面必须跟一个分号,否则错误if (sym=semicolon)getsymdo;elseerror(5);memcpy(nxtlev,fsys, sizeof (bool ) *symnum); / 将 fsys 所指的内存首地址, 大小为的内容放入 nxtlev 中/ 其实就是把初始化好的 nexlev 的内容复制到新申请的内存中去nxtlevsemicolon= true ;/ 分程序的程序体可以为空if (-1=block(lev+1,tx,nxtlev) / 递归调用,进入子过程,此时 lev+1 , return -1;if (sym=semicolon)getsymdo;memcp

41、y(nxtlev,statbegsys, sizeof (bool )*symnum); nxtlevident= true ;nxtlevprocsym= true ;/#define testdo(a,b,c) /if(-1=test(a,b,c) /return -1 testdo(nxtlev,fsys,6); / 测试后更符号类型类型是否合法 elseerror(5);/nxtlev 表示语句开始的符号集memcpy(nxtlev,statbegsys, nxtlevident= true ; nxtlevperiod= true ;/ testdo(nxtlev,declbegsys,7);/sizeof (bool )*symnum);测试当前符号是否是后继符号集中的元素/ 如果不是则找第一个是的位置/ 对于一个分程序的开始无非是语句开始符号集/ 如果没有了声明符号的字符,则退出循环号位置执行代码,这条语句是模拟程序的第一条指令和声明开始符号集 while (inset(sym,declbegsys); /jmp 0 CX 表示跳转到 CXcodetabletx0.adr.a=cx;tabletx0.adr=cx;tabletx0.size=dx;c

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论