📄 pl0.cpp
字号:
break;
case 5:
t--;
s[t-1]=s[t-1]/s[t];
break;
case 6:
s[t-1]=s[t-1]%2;
break;
case 7:
break;
case 8:
t--;
s[t-1]=s[t-1]==s[t];
break;
case 9:
t--;
s[t-1]=s[t-1]!=s[t];
break;
case 10:
t--;
s[t-1]=s[t-1]<s[t];
break;
case 11:
t--;
s[t-1]=s[t-1]>=s[t];
break;
case 12:
t--;
s[t-1]=s[t-1]>s[t];
break;
case 13:
t--;
s[t-1]=s[t-1]<=s[t];
break;
case 14:
printf("%d",s[t-1]);
fprintf(fa2,"%d",s[t-1]);
t--;
break;
case 15:
printf("\n");
fprintf(fa2,"\n");
break;
case 16:
printf("?");
fprintf(fa2,"?");
scanf("%d",&s[t]);
fprintf(fa2,"%d\n",s[t]);
t++;
break;
}
break;
case lod://取相对当前过程的数据基地址为a的内存的值到栈顶
s[t]=s[base(i.l,s,b)+i.a];
t++;
break;
case sto://栈顶的值存到相对当前过程的数据基地址为a 的内存
t--;
s[base(i.l,s,b)+i.a]=s[t];
break;
case cal://调用子过程
s[t]=base(i.l,s,b);//将父过程的基地址入栈
s[t+1]=b;//将本过程基地址入栈
s[t+2]=p;//将当前指令指针入栈
b=t;//改变基地址指针的值为新过程的基地址
p=i.a;//跳转
break;
case inte://分配内存
t+=i.a;
break;
case jmp://直接跳转
p=i.a;
break;
case jpc://条件跳转
t--;
if(s[t]==0) p=i.a;
break;
}
}while(p!=0);
}
/*
* 因子处理
*/
int factor(bool*fsys,int *ptx,int lev)
{
int i;
bool nxtlev[symnum];
testdo(facbegsys,fsys,24);//检测因子的开始符号
while(inset(sym,facbegsys))//循环直到不是因子的开始符号
{
if(sym==ident)//因子为常量或变量
{
i=position(id,*ptx);//查找名字
if(i==0)
{
error(11);//标识符没有声明
}
else
{
switch(table[i].kind)
{
case constant://名字是常量
gendo(lit,0,table[i].val);//直接把常量的值入栈
break;
case variable://名字是变量
gendo(lod,lev-table[i].level,table[i].adr);//找到变量的地址入栈
break;
case procedure://名字是过程
error(21);//不能为过程
break;
}
}
getsymdo;
}
else
{
if(sym==number)//因子为数
{
if(num>amax)
{
error(31);
num=0;
}
gendo(lit,0,num);
getsymdo;
}
else
{
if(sym==lparen)//因子是表达式
{
getsymdo;
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[rparen]=true;
expressiondo(nxtlev,ptx,lev);
if(sym==rparen)
{
getsymdo;
}
else
{
error(22);//缺少右括号
}
}
testdo(fsys,facbegsys,23);//因子后有非法符号
}
}
}
return 0;
}
/*
* 项处理
*/
int term(bool*fsys,int *ptx,int lev)
{
enum symbol mulop;//用于保存乘法或除法符号
bool nxtlev[symnum];
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[times]=true;
nxtlev[slash]=true;
factordo(nxtlev,ptx,lev);//处理因子
while(sym==times||sym==slash)
{
mulop=(symbol)sym;
getsymdo;
factordo(nxtlev,ptx,lev);
if(mulop==times)
{
gendo(opr,0,4);//生成乘法指令
}
else
{
gendo(opr,0,5);//生成除法指令
}
}
return 0;
}
/*
* 条件处理
*/
int condition(bool*fsys,int *ptx,int lev)
{
enum symbol relop;
bool nxtlev[symnum];
if(sym==oddsym)//按照odd运算处理
{
getsymdo;
expressiondo(fsys,ptx,lev);
gendo(opr,0,6);//生成odd指令
}
else
{ //逻辑表达式处理
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[eql]=true;
nxtlev[neq]=true;
nxtlev[lss]=true;
nxtlev[leq]=true;
nxtlev[gtr]=true;
nxtlev[geq]=true;
expressiondo(nxtlev,ptx,lev);
if(sym!=eql&&sym!=neq&&sym!=lss&&sym!=leq&&sym!=gtr&&sym!=geq)
{
error(20);
}
else
{
relop = sym;
getsymdo;
expressiondo(fsys,ptx,lev);
switch(relop)
{
case eql:
gendo(opr,0,8);
break;
case neq:
gendo(opr,0,9);
break;
case lss:
gendo(opr,0,10);
break;
case leq:
gendo(opr,0,13);
break;
case gtr:
gendo(opr,0,12);
break;
case geq:
gendo(opr,0,11);
break;
}
}
}
return 0;
}
/*
* 表达式处理
*/
int expression(bool*fsys,int *ptx,int lev)
{
enum symbol addop;//用于保存正负号
bool nxtlev[symnum];
if(sym==plus||sym==minus)//开头是正负号,此时当前表达式被看作一个正的或负的项
{
addop=sym;//保存开头的正负号
getsymdo;
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[plus]=true;
nxtlev[minus]=true;
termdo(nxtlev,ptx,lev);//处理项
if(addop==minus)//如果开头为负号生成取负指令
{
gendo(opr,0,1);
}
}
else//此时表达式被看作项的加减
{
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[plus]=true;
nxtlev[minus]=true;
termdo(nxtlev,ptx,lev);//处理项
}
while(sym==plus||sym==minus)
{
addop=sym;
getsymdo;
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[plus]=true;
nxtlev[minus]=true;
termdo(nxtlev,ptx,lev);//处理项
if(addop==plus)
{
gendo(opr,0,2);//生成加法指令
}
else
{
gendo(opr,0,3);//生成减法指令
}
}
return 0;
}
/*
* 语句处理
*/
int statement(bool*fsys,int *ptx,int lev)
{
int i,cx1,cx2;
bool nxtlev[symnum];
if(sym==ident)//按照赋值语句处理
{
i=position(id,*ptx);
if(i==0)//变量没有找到
{
error(11);
}
else
{
if(table[i].kind!=variable)
{
error(12);//赋值语句格式错误
i=0;
}
else
{
getsymdo;
if(sym==becomes)
{
getsymdo;
}
else
{
error(13);//没有检测到赋值符号
}
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
expressiondo(nxtlev,ptx,lev);//处理赋值符号右边的表达式
/* expression将执行一系列指令,但最终结果将会保存在栈顶
* 执行sto命令完成赋值
*/
if(i!=0)
{
gendo(sto,lev-table[i].level,table[i].adr);
}
}
}
}
else
{
if(sym==readsym)//按照read语句处理
{
getsymdo;
if(sym!=lparen)
{
error(34);//格式错误,应是左括号
}
else
{
do
{
getsymdo;
if(sym==ident)
{
i=position(id,*ptx);//查找要读的变量
}
else
{
i=0;
}
if(i==0)
{
error(35);//read()中应是声明过的变量名
}
else
{
gendo(opr,0,16);//生成输入指令,读取值到栈顶
gendo(sto,lev-table[i].level,table[i].adr);//存储到变量
}
getsymdo;
}while(sym==comma);//一条read语句可以读取多个变量
}
if(sym!=rparen)
{
error(33);//格式错误,应是右括号
while(!inset(sym,fsys))//出错补救,直到收到上层函数的后继符号
{
getsymdo;
}
}
else
{
getsymdo;
}
}
else
{
if(sym==writesym)//按照write语句处理
{
getsymdo;
if(sym==lparen)
{
do
{
getsymdo;
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[rparen]=true;//write的后继符号是右括号或逗号
nxtlev[comma]=true;
expressiondo(nxtlev,ptx,lev);//调用表达式处理
gendo(opr,0,14);//生成输出指令,输出栈顶的值
}while(sym==comma);
if(sym!=rparen)
{
error(33);//write中应为完整表达式
}
else
{
getsymdo;
}
}
gendo(opr,0,15);//输出换行
}
else
{
if(sym==callsym)//按照call语句处理
{
getsymdo;
if(sym!=ident)
{
error(14);//call应是标识符
}
else
{
i=position(id,*ptx);
if(i==0)
{
error(11);//过程没有找到
}
else
{
if(table[i].kind==procedure)
{
gendo(cal,lev-table[i].level,table[i].adr);//生成call指令
}
else
{
error(15);//call后标识符应是过程
}
}
getsymdo;
}
}
else
{
if(sym==ifsym)//按照if 语句处理
{
getsymdo;
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[thensym]=true;//后继符号是then或do
nxtlev[dosym]=true;
condition(nxtlev,ptx,lev);//调用条件处理函数
if(sym==thensym)
{
getsymdo;
}
else
{
error(16);//缺少then
}
cx1 = cx;//保存当前指令地址
gendo(jpc,0,0);//生成条件跳转指令,跳转地址暂时写0
statementdo(fsys,ptx,lev);//处理then后的语句
code[cx1].a=cx;/* 经过statement处理后cx为then后语句执行
* 完的位置,它正是前面未指定的跳转地址
*/
}
else
{
if(sym==beginsym)//按照复合语句处理
{
getsymdo;
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[semicolon]=true;//后继符号是分号或end
nxtlev[endsym]=true;
/* 循环调用语句处理函数,直到下一个符号不是
* 语句开始符号或收到end
*/
statementdo(nxtlev,ptx,lev);
while(inset(sym,statbegsys)||sym==semicolon)
{
if(sym==semicolon)
{
getsymdo;
}
else
{
error(10);//少分号
}
statementdo(nxtlev,ptx,lev);
}
if(sym==endsym)
{
getsymdo;
}
else
{
error(17);//少end 或分号
}
}
else
{
if(sym==whilesym)//按照while语句处理
{
cx1 = cx;//保存判断条件操作的位置
getsymdo;
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[dosym]=true;//后继符号是do
conditiondo(nxtlev,ptx,lev);
cx2 = cx;//保存循环体内的结束的下一个位置
gendo(jpc,0,0);//生成条件跳转,但跳出的地址不知道
if(sym==dosym)
{
getsymdo;
}
else
{
error(18);//少do
}
statementdo(fsys,ptx,lev);//循环体
gendo(jmp,0,cx1);//回头重新判断条件
code[cx2].a=cx;//反填跳出循环的地址,与if类似
}
else
{
memset(nxtlev,0,sizeof(bool)*symnum);//语句结束无补救集合
testdo(fsys,nxtlev,19);//检查语句结束的正确性
}
}
}
}
}
}
}
return 0;
}
/*
* 输出目标代码清单
*/
void listcode(int cx0)
{
int i;
if(listswitch)
{
for(i=cx0;i<cx;i++)
{
printf("%d %s %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);
fprintf(fa,"%d %s %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);
}
}
}
/*
* 变量声明处理
*/
int vardeclaration(int *ptx,int lev,int*pdx)
{
if(sym==ident)
{
enter(variable,ptx,lev,pdx);//填写名字表
getsymdo;
}
else
{
error(4);//var后应是标识符
}
return 0;
}
/*
* 常量声明处理
*/
int constdeclaration(int*ptx,int lev,int *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);//const后应是标识符
}
return 0;
}
/*
* 查找名字的位置
* idt:要查找的名字
* tx:当前名字表尾指针
*/
int position(char*idt,int tx)
{
int i;
strcpy(table[0].name,idt);
i=tx;
while(strcmp(table[i].name,idt)!=0)
{
i--;
}
return i;
}
/*
* 在名字表中加入一项
* k:名字的种类
* ptx:名字表尾指针的指针
* lev:名字所在的层次
* pdx:当前应分配的变量的相对地址
*/
void enter(enum object k,int *ptx,int lev,int *pdx)
{
(*ptx)++;
strcpy(table[*ptx].name,id);//全局变量id已经存有当前名字的名字
table[*ptx].kind=k;
switch(k)
{
case constant://常量名字
if(num>amax)
{
error(31);//数越界
num=0;
}
table[(*ptx)].val =num;
break;
case variable://变量名字
table[(*ptx)].level=lev;
table[(*ptx)].adr=(*pdx);
(*pdx)++;
break;
case procedure://过程名字
table[(*ptx)].level=lev;
break;
}
}
/*
*通过过程基址求上1层过程的基址
*/
int base(int l,int*s,int b)
{
int bl;
bl = b;
while(l>0)
{
bl=s[bl];
l--;
}
return bl;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -