📄 compiler.cpp
字号:
{
getsym(); //获取下一个token,这里正好应该是标识符
constdeclaration(); //声明以当前token为标识符的常量
}
if(strcmp(sym,"semicolon")==0) //如果常量声明结束,应最到分号
getsym(); //获取下一个token
else
error(5); //否则抛出5号错误
}while(strcmp(sym,"ident")==0);
}
if(strcmp(sym,"varsym")==0)
{
getsym(); //获取下一个token,此处正常应为用作变量名的一个标识符
do
{
vardeclaration(); //以当前token为标识符声明一个变量
while(strcmp(sym,"comma")==0)//如果最到的逗号,则反复声明下一个变量
{
getsym(); //获取下一个token
vardeclaration(); //声明以当前token为标识符的变量
}
if(strcmp(sym,"semicolon")==0)//如果变量声明结束,应遇到分号
getsym(); //获取下一个token,为下一轮循环做好准备
else
error(5); //否则抛出5号错误
}while(strcmp(sym,"ident")==0);
}
while(strcmp(sym,"procsym")==0) //循环声明各子过程
{
getsym(); //获取下一个token,此处正常应为作业过程名的标识符
if(strcmp(sym,"ident")==0) //如果token确为标识符
{
enter(procedur); //把这个过程登录到名字表中
getsym(); //获取下一个token,正常情况应为分号
}
else
error(4); //如果procsym后不是标识符,抛出4号错误
if(strcmp(sym,"semicolon")==0) //如果当前token是分号,获取下一个token
getsym();
else
error(5); //否则抛出5号错误
block(plev+1,add(temp3,fsys)); //递归调用语法分析过程,当前层次加一,同时传递表头索引,合法单词
lev=lev-1;
if(strcmp(sym,"semicolon")==0)
{
getsym();
test(add(statbegsys,temp2),fsys,6);//检查当前token是否合法,不合法则用fsys恢复语法分析,同时抛出6号错误
}
else
error(5); //如果过程声明后的符号不是分号,抛出5号错误
}
test(add(statbegsys,temp4),declbegsys,7);//检查当前状态是否合汇款单,不合法则且声明开始符号作出错恢复,抛7号错误
}while(in(sym,declbegsys)==1); //直到声明性的源程序分析完毕,继续向下执行,分析主程序
code[table1[tx0].adr].a=cx; //把前面生成的跳转语句的跳转位置改成当前位置
table1[tx0].adr=cx; //地址为当前代码分配地址
table1[tx0].size=dx; //长度为当前数据代分配位置
gen(ini,0,dx); //生成分配空间指令,分配dx个空间
cx0=cx; //记下当代码分配位置
statement(add(temp1,fsys),plev);//处理当前遇到的语句或语句块
gen(opr,0,0); //生成从子程序返回操作指令
test(fsys,temp5,8); //用fsys检查当前状态是否合法,不合法则抛出8号错
listcode(&cx0); //列出本层的类PCODE代码
cx0=cx;
}
//通过静态链求出数据区基地址的函数base
//返回值:要求的数据区基址
int base(int l,int *b,int s[STACKSIZE])
{
int b1;
b1=*b; //首先从当前层开始
while(l>0) //如果l大于0,循环通过静态链往前找需要的数据区基址
{
b1=s[b1]; //用当前层数据区基址中的内容(正好是静态链SL数据,为上一层的基址)作为新的当前层,即向上找了一层
l=l-1; //向上了一层,l减1
}
return b1; //把找到的要求的数据区基址返回
}
void interpret()
{
int p=0; //程序指令指针,指向下一条要运行的代码
int b=1; //基址指针,指向每个过程被调用时数据区中分配给它的局部变量数据段基址
int t=0; //栈顶寄存器,类PCODE,是在一种假想的栈式计算上运行的,这个变量记录这个计算机的当前栈顶位置
struct instruction i; //i变量中存放当前在运行的指令
int s[STACKSIZE]; //s为栈式计算机的数据内存区
cout<<"开始执行PL0文件…………"<<endl<<endl;
s[0]=0;
s[1]=0;
s[2]=0; //数据内存中为SL,DL,RA三个均为0,标识为主程序
s[3]=0;
do
{
i=code[p]; //获取一行目标代码
p++; //指令指针加一,指向下一条代码
switch(i.f)
{
case lit: //如果是lit指令
t=t+1; //栈顶指针上移,在栈中分配 一个单元
s[t]=i.a; //该单元的内容存入i指令的a操作数,即实现了把常量值放到运行栈栈顶
break;
case opr: //如果是opr指令
switch(i.a) //根据a操作数不同,执行不同的操作
{
case 0: //0操作为从子过程返回操作
t=b-1; //释放这段子过程占用的数据内存空间
p=s[t+3]; //把指令指针取到RA的值,指向的是返回地址
b=s[t+2]; //把数据段基址取到DL的值,指向调用前子过程的数据段基址
break;
case 1: //1号操作为栈顶数据取反操作
s[t]=-s[t]; //对栈顶数据进行取反
break;
case 2: //2号操作为栈顶两个数据加法操作
t--; //栈顶指针下移
s[t]=s[t]+s[t+1];//把两单元数据相加存入栈顶
break;
case 3: //3号操作为栈顶两个数据减法操作
t--; //栈顶指针下移
s[t]=s[t]-s[t+1];//把两单元数据相减存入栈顶
break;
case 4: //4号操作为栈顶两个数据乘法操作
t--;
s[t]=s[t]*s[t+1];
break;
case 5: //5号操作为栈顶两个数据除法操作
t--;
if(s[t+1]==0)
{
cout<<"运行时错误,除数不能为0!!"<<endl;
exit(0);
}
else
s[t]=s[t]/s[t+1];
break;
case 6: //6号操作为奇偶判断操作
s[t]=s[t]%2;
break;
case 8: //8号操作为栈顶两个数据判等操作
t--;
s[t]=(s[t]==s[t+1]);//相等置1,不等置0
break;
case 9: //9号操作为判不等操作
t--;
s[t]=(s[t]!=s[t+1]);
break;
case 10: //10号操作为栈顶两个数据判小于操作
t--;
s[t]=(s[t]<s[t+1]);
break;
case 11: //11号操作为栈顶两个数据判大于等于操作
t--;
s[t]=(s[t]>=s[t+1]);
break;
case 12: //12号操作为栈顶两个数据判大于操作
t--;
s[t]=(s[t]>s[t+1]);
break;
case 13: //13号操作为栈顶两个数据判小于等于操作
t--;
s[t]=(s[t]<=s[t+1]);
break;
case 14: //14号操作为输出栈顶值操作
cout<<"运行结果: "<<s[t]<<endl;//输出栈顶值
fprintf(fa2,"运行结果: %d\n",s[t]);//同时打印到文件
t--; //栈顶下移
break;
case 15: //15号操作为输出换行操作
cout<<endl;
fprintf(fa2,"\n");
case 16: //16号操作是接受键盘值输入到栈顶
t++; //栈顶上移,分配空间
cout<<"输入数字:"<<endl;
fprintf(fa2,"执行程序所用的整数为: ");
char inputChar;
cin>>inputChar;
while(!isdigit(inputChar))
{
cout<<"请输入数字"<<endl;
cin>>inputChar;
}
s[t]=inputChar-48;
cout<<endl;
fprintf(fa2,"%d\n\n",s[t]);
break;
}
break;
case lod: //如果是lod指令,将变量放到栈顶
t++; //栈顶上移,开辟空间
s[t]=s[base(i.l,&b,s)+i.a];//通过数据层差1和偏移地址a找到变量的数据,存入上面开辟的新空间(即栈顶)
break;
case sto: //如果是sto指令
s[base(i.l,&b,s)+i.a]=s[t];//把栈顶的值存入位置在数据区层差1偏移地址a的变量内存
t--;
break;
case cal: //如果是cal指令
s[t+1]=base(i.l,&b,s); //在栈顶压入静态链SL
s[t+2]=b; //然后压入当前数据区基址,作为动态链DL
s[t+3]=p; //最后压入当前的断点,作为返回地址RA
//以上工作即为过程调用前的现场保护
b=t+1; //把当前数据区基址指向SL所在位置
p=i.a; //从a指位置开始继续执行指令,即实现了程序执行的跳转
break;
case ini: //如果是ini指令
t=t+i.a; //栈顶上移a个空间,即开辟a个新的内存单元
break;
case jmp: //如果是jmp指令
p=i.a; //把jmp指令操作数a的值作为下一次要执行的指令地址,实现无条件跳转
break;
case jpc: //如果是jpc指令
if(s[t]==0) //判栈顶值
p=i.a; //如果是0就跳转
t--; //释放栈顶空间
break;
}
}while(p!=0); //如果p等于0,意味着在主程序运行时遇到了从子程序返回指令,也就是整个程序运行的结束
cout<<endl;
cout<<"PL0执行结束!!"<<endl<<endl;
fclose(fa2);
}
void main()
{
int i=0,j=0;
char *declbeg[]={"constsym","varsym","procsym",NULL};
char *statbeg[]={"beginsym","callsym","ifsym","whilesym",NULL};
char *facbeg[]={"ident","number","lparen",NULL};
char *tempset[]={"period","constsym","varsym","procsym",NULL};
declbegsys=(struct node*)malloc(sizeof(struct node));
statbegsys=(struct node*)malloc(sizeof(struct node));
facbegsys=(struct node*)malloc(sizeof(struct node));
tempsetsys=(struct node*)malloc(sizeof(struct node));
while(declbeg[j]!=NULL)
declbegsys->pa[i++]=declbeg[j++];
declbegsys->pa[i]=NULL;
i=0;
j=0;
while(statbeg[j]!=NULL)
statbegsys->pa[i++]=statbeg[j++];
statbegsys->pa[i]=NULL;
i=0;
j=0;
while(facbeg[j]!=NULL)
facbegsys->pa[i++]=facbeg[j++];
facbegsys->pa[i]=NULL;
i=0;
j=0;
while(tempset[j]!=NULL)
tempsetsys->pa[i++]=tempset[j++];
tempsetsys->pa[i]=NULL;
if((fa1=fopen("Analyse.txt","w"))==NULL)
{
cout<<"打开存放分析文件过程信息文件时出错!"<<endl;
exit(0);
}
cout<<"要编译的源文件: ";
cin>>fname;
while((fin=fopen(fname,"r"))==NULL)
{
cout<<"无法打开文件!"<<endl;
cout<<"再一次打开文件(Y/N)"<<endl;
char trychar;
cin>>trychar;
if(trychar=='Y'||trychar=='y')
{
system("cls"); //清屏
cout<<"要编译的源文件: "<<endl;
cin>>fname;
}
else
exit(0);
}
fprintf(fa1,"对pascal源程序的分析为:\n(源程序来自:%s)\n\n",fname);
cout<<"是否列出伪代码?(Y/N)"<<endl;
char mychar;
cin>>mychar;
if(mychar=='Y'||mychar=='y')
{
listswitch=true;
cout<<endl;
cout<<"伪代码如下:"<<endl<<endl;
}
else
{
listswitch=false;
cout<<endl;
cout<<"源程序如下:"<<endl<<endl;
}
//初始化
err=0;
cc=1;
cx=0;
ll=0;
ch=' ';
kk=AL;
getsym();
if((fa=fopen("ObjectCode.txt","w"))==NULL)
{
cout<<"无法打开伪代码存放文件!"<<endl;
exit(0);
}
else
fprintf(fa,"伪代码如下:\n\n");
if((fa2=fopen("Result.txt","w"))==NULL)
{
cout<<"打开程序执行结果文件失败!"<<endl;
exit(0);
}
block(0,add(statbegsys,tempsetsys));
fclose(fa);
if(strcmp(sym,"period")!=0)
error(9);
if(err==0)
{
cout<<"编译通过,无语法错误!"<<endl;
interpret();
}
else
{
cout<<endl<<" "<<err<<"个错误在该pascal源程序中!"<<endl;
cout<<"请修改后重新编译"<<endl;
}
fclose(fa1);
fclose(fin);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -