编译原理增加数据类型Word文档格式.docx
《编译原理增加数据类型Word文档格式.docx》由会员分享,可在线阅读,更多相关《编译原理增加数据类型Word文档格式.docx(67页珍藏版)》请在冰豆网上搜索。
structinstruction
{
enumfctf;
//虚拟机代码指令
intl;
//引用层与声明层的层差
doublea;
//根据f的不同而不同,参考课本
FILE*fas;
//输出名字表
FILE*fa;
//输出虚拟机代码
FILE*fa1;
//输出源文件及其各行对应的首地址
FILE*fa2;
//输出结果
boollistswitch;
booltableswitch;
charch;
//获取字符的缓冲区
enumsymbolsym;
charid[al+1];
doublenum;
intcc,ll;
//cc表示当前字符的位置
intcx;
//虚拟机代码指针
charline[81];
//读取行缓冲区
chara[al+1];
//临时符号,多出的一个字节用于表示字符串的结尾
structinstructioncode[cxmax];
//存放虚拟机代码的数组
charword[norw][al];
//保留字
enumsymbolwsym[norw];
//保留字对应的符号值
enumsymbolssym[256];
//单符号的符号值
charmnemonic[fctnum][5];
//虚拟机代码指令的名称
booldeclbegsys[symnum];
//表示声明开始的符号集合
boolstatbegsys[symnum];
//表示语句开始的符号集合
boolfacbegsys[symnum];
//表示因子开始的符号集合
//名字表结构
structtablestruct
charname[al];
//名字
//enumdatatypetype;
//数据类型:
integer,character,doub,
enumobjectkind;
//类型:
const,var,array,procedure
doubleval;
//数值,仅const使用,使用双精度浮点型
intlevel;
//所处层
intadr;
//地址
intsize;
//需分配的数据空间
structtablestructtable[txmax];
//名字表
FILE*fin;
FILE*fout;
charfname[al];
interr;
//错误计数器,每出一次错误,其加一
#definegetsymdoif(-1==getsym())return-1
#definegetchdoif(-1==getch())return-1
#definetestdo(a,b,c)if(-1==test(a,b,c))return-1
#definegendo(a,b,c)if(-1==gen(a,b,c))return-1
#defineexpressiondo(a,b,c)if(-1==expression_r(a,b,c))return-1
#definefactordo(a,b,c)if(-1==factor(a,b,c))return-1
#definetermdo(a,b,c)if(-1==term(a,b,c))return-1
#defineconditiondo(a,b,c)if(-1==condition(a,b,c))return-1
#definestatementdo(a,b,c)if(-1==statement(a,b,c))return-1
#defineconstdeclarationdo(a,b,c)if(-1==constdeclaration(a,b,c))return-1
#definevardeclarationdo(a,b,c)if(-1==vardeclaration(a,b,c))return-1
#defineintegerdeclarationdo(a,b,c)if(-1==integerdeclaration(a,b,c))return-1
#definecharacterdeclarationdo(a,b,c)if(-1==characterdeclaration(a,b,c))return-1
#definedoubdeclarationdo(a,b,c)if(-1==doubdeclaration(a,b,c))return-1
voiderror(intn);
intgetsym();
intgetch();
voidinit();
intgen(enumfctx,inty,doublez);
inttest(bool*s1,bool*s2,intn);
intinset(inte,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(intlev,inttx,bool*fsys);
voidinterpret();
intfactor(bool*fsys,int*ptx,intlev);
intterm(bool*fsys,int*ptx,intlev);
intcondition(bool*fsys,int*ptx,intlev);
intexpression_r(bool*fsys,int*ptx,intlev);
intstatement(bool*fsys,int*ptx,intlev);
voidlistcode(intcx0);
intvardeclaration(int*ptx,intlev,int*pdx);
intintegerdeclaration(int*ptx,intlev,int*pdx);
intcharacterdeclaration(int*ptx,intlev,int*pdx);
intdoubdeclaration(int*ptx,intlev,int*pdx);
intconstdeclaration(int*ptx,intlev,int*pdx);
intposition(char*idt,inttx);
voidenter(enumobjectk,int*ptx,intlev,int*pdx);
intbase(intl,int*s,intb);
//pl0.cpp
#include<
stdio.h>
#include"
pl0.h"
string.h"
//这个宏定义的意思表示是运行时的数据栈大小,这个会在interpret函数中出现,可以先不用管它
#definestacksize500
/*********************************************************************************
**在看源程序之前,请始终记住**
**sym表示的是当前字符串的类型,**
**num表示的数字,**
**id中存放的是字符串,**
**记住这点在看源程序的时候非常重要。
**
**另外,还要记住的是nxtlev数组中存放的是后继符号集**
**********************************************************************************/
intmain()
boolnxtlev[symnum];
//这个数组表示的是当前语句的后继符号集合,一共有个
printf("
Inputpl/0file?
"
);
//输入文件的路径
scanf("
%s"
fname);
fin=fopen(fname,"
r"
//以只读打开文件,fin文件指针
if(fin)
{
Listobjectcode?
(Y/N)"
listswitch=(fname[0]=='
y'
||fname[0]=='
Y'
//listswitch用于列举代码
Listsymboltable?
tableswitch=(fname[0]=='
//tableswitch表示是否输出table表
//该表类似于页的表
fa1=fopen("
fa1.tmp"
"
w"
//以只读格式打开文件,对于本程序其实是新建一个文件
//fa1文件中存储的是源程序,运行一次,看看这个文件就明白啦
fprintf(fa1,"
//将"
输入文件中
%s\n"
//同上
init();
//初始化
err=0;
cc=cx=ll=0;
ch='
'
;
if(-1!
=getsym())
//如果程序开始是对的,则往下执行
//fa存放的是模拟程序的代码
//fas存放的是table表中的数据
//运行一次代码看一下文件即明白
fa=fopen("
fa.tmp"
//以只读形式打开
fas=fopen("
fas.tmp"
//函数原型:
//boolnxtlev[32];
/*
declbegsys[constsym]=true;
declbegsys[varsym]=true;
declbegsys[procsym]=true;
statbegsys[beginsym]=true;
statbegsys[callsym]=true;
statbegsys[ifsym]=true;
statbegsys[whilesym]=true;
执行该函数的结果为对应的下标在nxtlev中上述值均为true;
*/
//在分程序开始的时候,其后继符号可以是
//const,var,procedure,begin,call,if,while
//所以在nxtlev中将上述这些置为true
//当然在整个程序可以只有一个'
.'
,即程序是空的也可以,所以会有nxtlev[period]=true;
addset(nxtlev,declbegsys,statbegsys,symnum);
//symnum=32;
nxtlev[period]=true;
//block是编译程序的主程序,是分程序的分析处理过程,其里面调用了大部分程序
//耐心看
//请记住在block程序开始的时候,只读取了源程序的一个语句单位
if(-1==block(0,0,nxtlev))
//当程序出错的时候,则关闭以下文件,并退出程序
fclose(fa);
fclose(fa1);
fclose(fas);
fclose(fin);
\n"
return0;
}
//如果在源程序的结尾没有'
,则报错
if(sym!
=period)
error(9);
//err=0表示源程序没有错误
if(err==0)
//在源程序没有错误的前提下,打开fa2文件,依次执行里面的语句,输出源程序结果
fa2=fopen("
fa2.tmp"
//模拟计算机执行源程序
interpret();
fclose(fa2);
else
//如果远程有错的话,会这样
Errorsinpl/0program"
Can'
topenfile!
\n"
}
voidinit()
inti;
for(i=0;
i<
=255;
i++)
ssym[i]=nul;
//nul为,将ssym初始化为
//ssym大小为,可以表示所有的ASCLL码
ssym['
+'
]=plus;
-'
]=minus;
*'
]=times;
/'
]=slash;
('
]=lparen;
)'
]=rparen;
='
]=eql;
'
]=comma;
]=period;
#'
]=neq;
'
]=semicolon;
//将保留字输入word数组中,为了使用二分查找,这个设置顺序是按照字母序
/*strcpy(&
(word[0][0]),"
begin"
strcpy(&
(word[14][0]),"
character"
(word[1][0]),"
call"
(word[2][0]),"
const"
(word[3][0]),"
do"
(word[15][0]),"
doub"
(word[4][0]),"
end"
(word[5][0]),"
if"
(word[13][0]),"
integer"
(word[6][0]),"
odd"
(word[7][0]),"
procedure"
(word[8][0]),"
read"
(word[9][0]),"
then"
(word[10][0]),"
var"
(word[11][0]),"
while"
(word[12][0]),"
write"
*/
//wsym内放有保留字所对应的枚举变量的值
wsym[0]=beginsym;
wsym[1]=callsym;
wsym[2]=charactersym;
wsym[3]=constsym;
wsym[4]=dosym;
wsym[5]=doubsym;
wsym[6]=endsym;
wsym[7]=ifsym;
wsym[8]=integersym;
wsym[9]=oddsym;
wsym[10]=procsym;
wsym[11]=readsym;
wsym[12]=thensym;
wsym[13]=varsym;
wsym[14]=whilesym;
wsym[15]=writesym;
//mnemonic中存放的是模拟程序的命令符
//大小是个,因为只有中命令符
(mnemonic[lit][0]),"
lit"
(mnemonic[opr][0]),"
opr"
(mnemonic[lod][0]),"
lod"
(mnemonic[sto][0]),"
sto"
(mnemonic[cal][0]),"
cal"
(mnemonic[inte][0]),"
int"
(mnemonic[jmp][0]),"
jmp"
(mnemonic[jpc][0]),"
jpc"
//初始化这些数组,全部为false
for(i=0;
symnum;
declbegsys[i]=false;
statbegsys[i]=false;
facbegsys[i]=false;
//下面的这三块内容的功能在后续的介绍中会有,
//分别是声明开始符号集,语句开始符号集,因子开始符号集
declbegsys[integersym]=true;
declbegsys[charactersym]=true;
declbegsys[doubsym]=true;
facbegsys[ident]=true;
facbegsys[number]=true;
facbegsys[lparen]=true;
facbegsys[charnum]=true;
facbegsys[doubnum]=true;
//该函数的功能是返回符号e是否在符号集s中
//是则返回true,否则返回false
intinset(inte,bool*s)
returns[e];
//对于下标i,如果s1或s2是true,则sr也是true
//这个函数其实是初始化后继符号集,即nxtlev数组
intaddset(bool*sr,bool*s1,bool*s2,intn)
n;
sr[i]=s1[i]||s2[i];
//下面的函数不知干什么用,我没找到这两个函数的使用地方,不知道是不是作者弄错啦
intsubset(bool*sr,bool*s1,bool*s2,intn)
sr[i]=s1[i]&
&
(!
s2[i]);
intmulset(bool*sr,bool*s1,bool*s2,intn)
s2[i];
//当出问题的时候,仅仅输出错误,并不退出程序
//对于出错码,可以参考课本页
voiderror(intn)
charspace[81];
memset(space,32,81);
//将space全部置为空格
space[cc-1]=0;
//出错时当前符号已经读完,所以是CC-1
****%s!
%d\n"
space,n);
err++;
intgetch()
if(cc==ll)
if(feof(fin))//fin未知
programincomplete"