编译原理--增加数据类型_第1页
编译原理--增加数据类型_第2页
编译原理--增加数据类型_第3页
编译原理--增加数据类型_第4页
编译原理--增加数据类型_第5页
已阅读5页,还剩42页未读 继续免费阅读

下载本文档

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

文档简介

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

2、, ident=1 , number=2, plus=3 , minus=4 /times=5 ,依次类推, procsym=31 nul,ident, number, / 下面勺表示勺是系统勺算数运算符以及逻辑运算符,知道意思就可以 plus, minus, times,/ 相乘勺意思 slash, oddsym, eql, neq, lss, leq, gtr, geq, lparen, / 左括号 rparen, comma, semicolon, period, becomes,/ 赋值勺意思 / 下面勺表示是系统勺保留字 beginsym, endsym, ifsym, thensy

3、m, whilesym, writesym, readsym, dosym, callsym, constsym, varsym, procsym, integersym,charactersym,doubsym, charnum,integercon,doubnum ; #define symnum 38 enumobject constant, variable, procedur, integer, character, doub, ; enumfct lit, sto, jmp, opr, cal, jpc, lod, inte, ; #define fctnum 11 struct

4、instruction enum fct f; / 虚拟机代码指令 int 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;

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

6、开始的符号集合 bool facbegsyssymnum; / 表示因子开始的符号集合 / 名字表结构 struct tablestruct char nameal; / 名字 /enum datatype type;/ 数据类型: integer,character,doub, enumobject kind; / 类型: const,var,array,procedure double val; / 数值,仅 const 使用 , 使用双精度浮点型 int level; / 所处层 int adr; / 地址 int size; / 需分配的数据空间 ; struct tablestruc

7、t tabletxmax;/ 名字表 FILE* fin; FILE* fout; char fnameal; int err; / 错误计数器,每出一次错误,其加一 if (-1=getsym() return -1 if (-1=getch() return -1 if (-1=test(a,b,c) return -1 if (-1=gen(a,b,c) return -1 if (-1=expression_r(a,b,c) return if (-1=factor(a,b,c) return -1 if (-1=term(a,b,c) return -1 if (-1=conditi

8、on(a,b,c)return -1 if (-1=statement(a,b,c)return -1 #define getsymdo #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=

9、constdeclaration(a,b,c) return -1 #define vardeclarationdo(a,b,c) if (-1=vardeclaration(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)

10、if (-1=doubdeclaration(a,b,c) return -1 void error( int n); int getsym(); int getch(); void init(); int gen( enumfct x, int y, double z); int test( bool *s1, bool *s2, int n); int inset( int e, bool *s); int addset( bool *sr, bool *s1, bool *s2, int n); int subset( bool *sr, bool *s1, bool *s2, int

11、n); int mulset( bool *sr, bool *s1, bool *s2, int n); int block( int lev, int tx, bool * fsys); void interpret(); int factor( bool * fsys, int * ptx, int lev); int term( bool *fsys, int *ptx, int lev); int condition( bool *fsys, int *ptx, int lev); int expression_r( bool *fsys, int *ptx, int lev); i

12、nt statement( bool *fsys, int *ptx, int lev); void listcode( int cx0); int vardeclaration( int * ptx, int lev, int * pdx); int integerdeclaration( int * ptx, int lev, int * pdx); int characterdeclaration( int doubdeclaration( int int * ptx, int ptx, int lev, lev, int * pdx); int * pdx); int constdec

13、laration( int * ptx, int lev, int * pdx); int position( char * idt, int tx); void enter( enumobject k, int * ptx, int lev, int * pdx); int base( int l, int * s, int b); /pl0.cpp #include #include pl0.h #include string.h 函数中出现,可以先 / 这个宏定义的意思表示是运行时的数据栈大小,这个会在 interpret 不用管它 #define stacksize 500 * ,一共

14、有个 用于列举代码 * 在看源程序之前,请始终记住 * * sym 表示的是当前字符串的类型, * * num 表示的数字, * * id 中存放的是字符串, * * 记住这点在看源程序的时候非常重要。 * * 另外,还要记住的是 nxtlev 数组中存放的是后继符号集 * */ int main() bool nxtlevsymnum; / 这个数组表示的是当前语句的后继符号集 printf( Input pl/0 file? ); / 输入文件的路径 scanf( %s ,fname); fin=fopen(fname, r ); / 以只读打开文件, fin 文件指针 if (fin)

15、printf( List object code? (Y/N) ); scanf( %s,fname); listswitch=(fname0= y |fname0= Y ); /listswitch printf( List symbol table? (Y/N) ); scanf( %s,fname); tableswitch=(fname0= table 表 y |fname0= Y ); /tableswitch 表示是否输出 / 该表类似于页的表 fa1=fopen( fa1.tmp , w); / 以只读格式打开文件, 对于本程序其实是新建一个 文件 /fa1 文件中存储的是源程序

16、,运行一次,看看这个文件就明白啦 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() / 如果程序开始是对的,则往下执行 /fa 存放的是模拟程序的代码 /fas 存放的是 table 表中的数据 / 运行一次代码看一下文件即明白 fa=fopen( fas=fopen( fa.tmp , w ); / 以只读形式打开 fas.tmp , w); / 同上 /

17、函数原型: int addset(bool*sr,bool*s1,bool*s2,int n); /bool nxtlev32; /* declbegsysconstsym=true; declbegsysvarsym=true; declbegsysprocsym=true; statbegsysbeginsym=true; statbegsyscallsym=true; statbegsysifsym=true; statbegsyswhilesym=true; 执行该函数的结果为对应的下标在 nxtlev 中上述值均为 true ; */ / 在分程序开始的时候,其后继符号可以是 /co

18、nst,var,procedure,begin,call,if,while / 所以在 nxtlev 中将上述这些置为 true / 当然在整个程序可以只有一个 . ,即程序是空的也可以,所以会有 nxtlevperiod=true; addset(nxtlev,declbegsys,statbegsys,symnum);/symnum=32 ; nxtlevperiod= true ; /block 是编译程序的主程序,是分程序的分析处理过程,其里面调用了大部 分程序 / 耐心看 / 请记住在 block 程序开始的时候,只读取了源程序的一个语句单位 if (-1=block(0,0,nxt

19、lev) / 当程序出错的时候,则关闭以下文件,并退出程序 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 (err=0) / 在源程序没有错误的前提下,打开 fa2 文件,依次执行里面的语句,输 出源程序结果 fa2=fopen( fa2.tmp , w); / 模拟计算机执行源程序

20、interpret(); fclose(fa2); else / 如果远程有错的话,会这样 printf(Errors in pl/0 program); fclose(fin); else printf( Cant open file! n ); printf( n ); return 0; void init() int i; for (i=0;i=255;i+) /ssym大小为,可以表示所有的 ASCL码 ssymi=nul;nul 为,将 ssym初始化为 ssym + =plus; ssym - =minus; ssym * =times; ssym / =slash; ssym

21、( =lparen; ssym ) =rparen; ssym = =eql; ssym , =comma; ssym . =period; ssym # =neq; ssym ; =semicolon; /将保留字输入word数组中,为了使用二分查找,这个设置顺序是按照字母序 /* strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy(*/ strcpy( call ); strcpy( do

22、); strcpy( strcpy( if ); strcpy( strcpy( 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;

23、 wsym12=thensym; wsym13=varsym; wsym14=whilesym; wsym15=writesym; /mnemonic 中存放的是模拟程序的命令符 / 大小是个,因为只有中命令符 strcpy(isymnum;i+) ); ); ); ); ); ); ); ); declbegsysi=false statbegsysi=false facbegsysi= false / 下面的这三块内容的功能在后续的介绍中会有, / 分别是声明开始符号集,语句开始符号集,因子开始符号集 declbegsysconstsym= true ; declbegsysvarsym=

24、 true ; declbegsysprocsym= true ; declbegsysintegersym= true ; declbegsyscharactersym= true ; declbegsysdoubsym= true ; statbegsysbeginsym= true ; statbegsyscallsym= true ; statbegsysifsym= true ; statbegsyswhilesym= true ; facbegsysident= true ; facbegsysnumber= true ; facbegsyslparen=true ; facbeg

25、syscharnum= true ; facbegsysdoubnum= true ; /该函数的功能是返回符号e是否在符号集s中 / 是则返回 true ,否则返回 false int inset( int e, bool * 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; / 下面的函数不知干什么用

26、,我没找到这两个函数的使用地方,不知道是不是作者弄错啦 int subset( bool* sr, bool * s1, bool* s2, int n) int i; for (i=0;in;i+) sri=s1i return 0; int mulset( bool * sr, bool* s1, bool * s2, int n) int i; for (i=0;i= a do if (k= a ak=0;/ 单词符号以结尾 strcpy(id,a);/ 将该单词符号复制到 id 数组中 i=0; j=norw-1; /norw=13 / 执行二分查找,搜索该单词符号是否是保留字 do

27、k=(i+j)/2; /strcmp() 比较两个字符串,相同则为,第一个小为负,第一个大为正数 if (strcmp(id,wordk)=0) i=k+1; while (ij) sym=wsymk;/如果是保留字则置为保留字的数字,wsyn是保留字对应的符 号值 else sym=ident;/如果不是保留字,则置sym为 else if ( int )ch=39) / 加入字符类型 getchdo; if (ch= A / 输出错误码 else if (ch= : ) getchdo; if (ch= = ) sym=becomes;/如果是赋值的话,则置 sym=19 getchdo;

28、 else sym=nul;/ 个人认为这地有错,我觉得应该是错误退出才对 else if (ch= ) getchdo; if (ch= = ) sym=geq; getchdo; else sym=gtr; else sym=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; / / / 功能是取

29、一个单词符号 / if(ch=a /do / /if (k=a /ak=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/输出

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

31、umfct x, int y, double z) if (cx=cxmax) /cxmax=200 printf( 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) return 0; fsys /cc=cx=ll=0;cx 表示源程序

32、中代码的第几行 /block(0,0,nxtlev) 这是主程序 /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 (levlevm

33、ax) /levmax=3 ,所以该编译器允许的嵌套为层 error(32); do / 如果当前字符是 constant ,则将字符放入 table 中 if (sym=constsym) / 读取 const 后的常量符号 getsymdo; do /#define constdeclarationdo(a,b,c) /if(-1=constdeclaration(a,b,c) / return -1 constdeclarationdo( /tx=0,lev=0,dx=3; while (sym=comma)/ 如果是逗号,则表示下一个单词串为常量,将所有 的 / 在同一行的常量符号输入

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

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

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

37、bdeclarationdo( while (sym=comma) getsymdo; doubdeclarationdo( if (sym=semicolon) getsymdo; else error(5); while (sym=ident); / 如果当前字符是子过程,则将字符放入 table 中 while (sym=procsym) getsymdo; if (sym=ident) enter(procedur, getsymdo; else error(4); / 子过程的语句后面必须跟一个分号,否则错误 if (sym=semicolon) getsymdo; else err

38、or(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; memcpy(nxtlev,statbegsys, sizeof (bool )*symn

39、um); nxtlevident= true ; nxtlevprocsym= true ; /#define testdo(a,b,c) /if(-1=test(a,b,c) /return -1 testdo(nxtlev,fsys,6); / 测试后更符号类型类型是否合法 else error(5); /nxtlev 表示语句开始的符号集 memcpy(nxtlev,statbegsys, nxtlevident= true ; nxtlevperiod= true ; / testdo(nxtlev,declbegsys,7);/ sizeof (bool )*symnum); 测试当

40、前符号是否是后继符号集中的元素 / 如果不是则找第一个是的位置 / 对于一个分程序的开始无非是语句开始符号集 / 如果没有了声明符号的字符,则退出循环 号位置执行代码,这条语句是模拟程序的第一条指令 和声明开始符号集 while (inset(sym,declbegsys); /jmp 0 CX 表示跳转到 CX codetabletx0.adr.a=cx; tabletx0.adr=cx; tabletx0.size=dx; cx0=cx; / 模拟程序的第二条语句表示申请多大的存储空间,用于存储变量 gendo(inte,0,dx); if (tableswitch) / 是否列出 tab

41、le 表中的内容 printf( TABLE:n ); if (tx0+1tx) / 当 table 表为空时,只输出 NULL printf(NULLn ); for (i=tx0+1;iamax)/amax=2047, 即 const 数最大为 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 ; / 自

42、己修改的 case integer: table(*ptx).level=lev; table(*ptx).adr=(*pdx); (*pdx)+; break ; case doub: table(*ptx).level=lev; table(*ptx).adr=(*pdx); (*pdx)+; break ; case character: table(*ptx).level=lev; table(*ptx).adr=(*pdx); (*pdx)+; break ; / 在 table 表中查找 idt 的位置,并返回其所在位置 int position( char * idt, int

43、tx) int i; strcpy(,idt); i=tx; while (strcmp(,idt)!=0) i-; return i; int characterdeclaration( int * ptx, int lev, int * pdx) / 如果当前的符号是一个字符类型,则继续执行 if (sym=ident) enter(character,ptx,lev,pdx); getsymdo; else error(4); return 0; int integerdeclaration( int * ptx, int lev, int *

44、 pdx) / 如果当前的符号是一个字符类型,则继续执行 if (sym=ident) enter(integer,ptx,lev,pdx); getsymdo; else error(4); return 0; int doubdeclaration( int * ptx, int lev, int * pdx) / 如果当前的符号是一个字符类型,则继续执行 if (sym=ident) enter(doub,ptx,lev,pdx); getsymdo; else error(4); return 0; int constdeclaration( int * ptx, int lev, i

45、nt * 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

46、(variable,ptx,lev,pdx); getsymdo; else error(4); return 0; / 列举模拟程序,即目标程序 void listcode( int cx0) int i; if (listswitch) for (i=cx0;iamax|numamax)/ 如果数字大于最大能表示的数字,则报错。 / /error(31); /num=0; / /gendo(lit,0,num); /getsymdo; / /else / / /如果当前是一个左括号,则表示进入一个表达式的处理过程 /if(sym=lparen) / /getsymdo; /memcpy(n

47、xtlev,fsys,sizeof(bool)*symnum); /nxtlevrparen=true; / 在左括号里面是一个表达式 /expressiondo(nxtlev,ptx,lev); /if(sym=rparen) / /getsymdo; / /else / /error(22); / / /testdo(fsys,facbegsys,23);/ 么是其他的开始符号 / / / / return 0; / 当前符号要么是因子的开始符号,要 int factor ( bool * fsys, int *ptx, int lev) int i; bool nxtlevsymnum;

48、 testdo(facbegsys,fsys,24); / 判断当前是否是因子的语法开始符号,如果不是,则 找到一个合适的 / 开始符号继续执行 while (inset(sym,facbegsys) / 如果当前不是因子的开始符号,则退出该函数 / 如果当前字符是一个变量的话 if (sym=ident) i=position(id,*ptx); if (i=0) error(11); else switch (tablei.kind) case constant: gendo(lit,0,tablei.val); / 将当前常量放在栈顶 break ; case variable: gen

49、do(lod,lev-tablei.level,tablei.adr); break ; case procedur: / 因子中不能含有过程的定义 error(21); break ; / 自己添加的 case character: gendo(lod,lev-tablei.level,tablei.adr); break ; case integer: gendo(lod,lev-tablei.level,tablei.adr); break ; case doub: gendo(lod,lev-tablei.level,tablei.adr); break ; getsymdo; else if (sym=charnum) if (num256|numamax)/ 如果数字大于最大能表示的数字,则报错。 amax=2047 error(31); num=0; gendo(lit,0,num); getsymdo; else / 如果当前是一个左括号,则表示进入一个表达式的处理过程 if (sym=lparen) getsymdo; memcpy(nxtlev,fsys, sizeof (bool )*symnum); nxtlevrparen= true ; / 在左括号里面是一个表达式 expressiondo(nxtlev,ptx,lev);

温馨提示

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

评论

0/150

提交评论