📄 pl0.cpp
字号:
error(20);
else
{
relop= sym;
getsym();
expression(fsys,tx,lev);
switch(relop)
{
case EQL: gen(OPR,0,8);//次栈顶与栈顶是否相等,退两个栈元素,结果值进栈
break;
case NEQ: gen(OPR,0,9);//次栈顶与栈顶是否不等,退两个栈元素,结果值进栈
break;
case LSS: gen(OPR,0,10);//次栈顶是否小于栈顶,退两个栈元素,结果值进栈
break;
case GEQ: gen(OPR,0,11);//次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈
break;
case GTR: gen(OPR,0,12);//次栈顶是否大于栈顶,退两个栈元素,结果值进栈
break;
case LEQ: gen(OPR,0,13);//次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈
break;
}
}
}
}//condition结束
void PL0::statement(symset fsys,int tx,int lev)//语句分析
{
if(sourceEnd)
return;
int i,cx1,cx2;
if(sym ==IDENT)
{
i= position(id,tx);//查找表
if (i == 0)//未查到
error(11);
else if (table[i].kind!=VARIABLE)
{
error(12);//如果赋值号左边不是变量的报错
i= 0;
}
getsym();
if(sym ==BECOMES)
getsym();
else
error(13);
expression(fsys,tx,lev);
if(sym!=SEMICOLON)
error(10);
if( i!= 0)
gen(STO,lev-table[i].other.inOther.level,table[i].other.inOther.adr);//实现存数即赋值过程完成。
}
else if( sym==READSYM)//READ符号相当与C++中的CIN。
{
getsym();
if( sym!=LPAREN)//左括号
error(34);
else
do{
getsym();
if (sym==IDENT)
i=position(id,tx);
else
i=0;
if( i==0 )
error(35);
else
{
gen(OPR,0,16);//从命令行读入一个输入置于栈顶
gen(STO,lev-table[i].other.inOther.level,table[i].other.inOther.adr);//存数,即将刚刚用户输入的数存入变量。
}
getsym();
}while(sym==COMMA);
if (sym!=RPAREN)
{
error(33);
while (fsys.find(sym)!=fsys.end()) getsym();
}
else
getsym();
}
else if( sym==WRITESYM)//相当于cout
{
getsym();
if (sym==LPAREN)
{
do{
getsym();
symset tmp=fsys;
for(int t=RPAREN;t<=COMMA;t++)
tmp.insert((symbol)t);
expression(tmp,tx,lev);
gen(OPR,0,14);//栈顶值输出至屏幕
}while(sym==COMMA);
if (sym!=RPAREN)
error(33);
else
getsym();
}
gen(OPR,0,15);
}
else if( sym ==CALLSYM)//过程调用语句。
{
getsym();
if( sym!=IDENT)
error(14);
else
{
i= position(id,tx);
if (i == 0)
error(11);
else if (table[i].kind = PROCEDURE)
gen(CAL,lev-table[i].other.inOther.level,table[i].other.inOther.adr);//调用过程,adr为过程地址,level为层差
else
error(15);//CALL后接的变量不是过程名的报错
getsym();
}
}
else if( sym ==IFSYM)//IF语句的分析
{
getsym();
symset tmp=fsys;
for(int i=THENSYM;i<=DOSYM;i++)
tmp.insert((symbol)i);
condition(tmp,tx,lev);
if( sym == THENSYM)
getsym();
else
error(16);
cx1= cx;//返填技术开始
gen(JPC,0,0);
statement(fsys,tx,lev);
code[cx1].a= cx;
}
else if( sym ==BEGINSYM)//过程开始分析
{
getsym();
symset tmp=fsys;
for(int i=SEMICOLON;i<=ENDSYM;i++)
tmp.insert((symbol)i);
statement(tmp,tx,lev);
tmp=statbegsys;
tmp.insert(SEMICOLON);
while( tmp.find(sym)!=tmp.end())
{
if(sourceEnd)return;
if (sym ==SEMICOLON||sym ==ENDSYM)
getsym();
else if(sym=PERIOD)
{
error(26);
getsym();
}
else
error(10);
tmp=fsys;
for(i=SEMICOLON;i<=ENDSYM;i++)
tmp.insert((symbol)i);
if(sourceEnd)return;
if(sym==ENDSYM)
break;
statement(tmp,tx,lev);
}
if( sym ==ENDSYM)
getsym();
else if(!sourceEnd)
error(17);
}
else if(sym ==WHILESYM)//WHILE循环分析,典型的返填技术应用
{
cx1= cx;
getsym();
symset tmp=fsys;
tmp.insert(DOSYM);
condition(tmp,tx,lev);
cx2= cx;
gen(JPC,0,0);
if(sym ==DOSYM)
getsym();
else
error(18);//缺少DO
statement(fsys,tx,lev);
gen(JMP,0,cx1);//无条件跳转到cx1即WHILE条件判断处,返填的第一次应用。
code[cx2].a= cx;//返填的第二次应用。
}
}//statement结束
void PL0::block(int lev,int tx,symset fsys)//语法分析过程开始
{
if(sourceEnd)
return;
int dx;//数据区的索引
int tx0;//初始化分析表的索引,保留初始tx
int cx0;//初始化code数组的索引,保留初始cx
dx= 3;//数据区的索引要初始化为3,因为前3个数据区为固有的(静态链,动态链,返回地址),不可占用
tx0= tx;//记录本层名字的初始位置
table[tx].other.inOther.adr= cx;
gen(JMP,0,0);
if( lev>levmax)//层深的限制
error(32);
do{
if( sym ==CONSTSYM)//收到常量声明符号,开始处理常量声明
{
getsym();
do{
constdeclaration(tx,dx,lev);
while (sym ==COMMA)
{
getsym();
constdeclaration(tx,dx,lev);
}
if (sym ==SEMICOLON)
getsym();
else
error(5);
}while(sym==IDENT);
}
if( sym ==VARSYM)//收到变量声明符号,开始处理变量声明
{
getsym();
do{
vardeclaration(tx,dx,lev);
while( sym ==COMMA){
getsym();
vardeclaration(tx,dx,lev);
}
if( sym ==SEMICOLON)
getsym();
else
error(5);
}while(sym==IDENT);
}
while( sym ==PROCSYM)//收到过程声明符号,开始处理过程声明
{
getsym();
if (sym ==IDENT)
{
enter(PROCEDURE,tx,dx,lev);//记录过程名字
getsym();
}
else
error(4);//procedure后应为标识符
if( sym ==SEMICOLON)
getsym();
else
error(5);//漏掉了分号
symset tmp=fsys;
tmp.insert(SEMICOLON);
block(lev+1,tx,tmp);
if (sym ==SEMICOLON){
getsym();
symset tmp=statbegsys;
for(int i=IDENT;i<=PROCSYM;i++)
tmp.insert((symbol)i);
test(tmp,fsys,6);
}
else
error(5);
}
}while(declbegsys.find(sym)!=declbegsys.end());//直到没有声明符号
code[table[tx0].other.inOther.adr].a= cx;//开始生成当前过程代码
table[tx0].other.inOther.adr= cx;// 当前过程代码地址
table[tx0].other.inOther.size=dx;//声明部分中每增加一条声明都会给dx增加1,声明部分已经结束,dx就是当前过程数据的size
cx0= cx;
gen(INT,0,dx);//生成分配内存代码--在运行栈中为被调用的过程开辟dx个单元的数据区
symset tmp=statbegsys;
for(int i=SEMICOLON;i<=ENDSYM;i++)
tmp.insert((symbol)i);
statement(tmp,tx,lev);
gen(OPR,0,0);//过程调用结束后,返回调用点并退栈
symset s2;
test(fsys,s2,8);//检测后跟符号正确性
listcode(cx0);//输出代码
}// block结束
int PL0::base(int l,int b,int s[])//通过过程基址求上l层过程的基址
{
int b1;
b1= b;
while(l>0){//自下而上查找基址
b1= s[b1];
l= l-1;
}
return b1;
}
void PL0::errout()//错误输出方法
{
ofstream outfile("scanerr.txt");
int err1=errorString.size();
if(err1>0)
{
copy(errorString.begin(),errorString.end(),ostream_iterator<string>(outfile));
return;
}
}
void PL0::interpret()//解释执行方法
{
const stacksize = 500;//运行栈大小
int p=0,b=1,t=0;//指令指针,指令基址,栈顶指针
instruction i;// 存放当前指令
int s[stacksize+1]={0};//运行栈
cout<<" Start PL/0--Sundic\n";
do{
i= code[p];//读当前指令
p= p+1;
switch(i.f)
{
case LIT://将a的值取到栈顶
t= t+1;
s[t]= i.a;
break;
case OPR://数学、逻辑运算
switch(i.a) //判断为哪一种操作
{
case 0:
t= b-1;
p= s[t+3];
b= s[t+2];
break;
case 1:
s[t]= -s[t];
break;
case 2:
t= t-1;
s[t]= s[t]+s[t+1];
break;
case 3:
t= t-1;
s[t]= s[t]-s[t+1];
break;
case 4:
t= t-1;
s[t]= s[t]*s[t+1];
break;
case 5:
t= t-1;
s[t]= s[t] / s[t+1];
break;
case 6:
if(s[t]%2)
s[t]=1;
else
s[t]=0;
break;
case 8:
t= t-1;
if(s[t]==s[t+1])
s[t]=1;
else
s[t]=0;
break;
case 9:
t= t-1;
if(s[t]==s[t+1])
s[t]=0;
else
s[t]=1;
break;
case 10:
t= t-1;
if(s[t]<s[t+1])
s[t]=1;
else
s[t]=0;
break;
case 11:
t= t-1;
if(s[t]>=s[t+1])
s[t]= 1;
else
s[t]=0;
break;
case 12:
t= t-1;
if(s[t]>s[t+1])
s[t]= 1;
else
s[t]=0;
break;
case 13:
t= t-1;
if(s[t]<=s[t+1])
s[t]= 1;
else
s[t]=0;
break;
case 14:
cout<<" "<<s[t];
t=t-1;
break;
case 15:
cout<<endl;
break;
case 16:
t=t+1;
cout<<"?";
s[t]=0;
cin>>s[t];
break;
};
break;
case LOD://取相对当前过程的数据基地址为a的内存的值到栈顶
t= t+1;
s[t]= s[base(i.l,b,s)+i.a];
break;
case STO://栈顶的值存到相对当前过程的数据基地址为a的内存
s[base(i.l,b,s)+i.a]= s[t];
t= t-1;
break;
case CAL://调用子过程
s[t+1]= base(i.l,b,s);//将父过程基地址入栈
s[t+2]= b;//将本过程基地址入栈,此两项用于base函数
s[t+3]= p;//将当前指令指针入栈
b= t+1;//改变基地址指针值为新过程的基地址
p=i.a;//跳转
break;
case INT://分配内存
t= t+i.a;
break;
case JMP://直接跳转
p= i.a;
break;
case JPC://条件跳转
if (s[t] == 0)
p= i.a;
t= t-1;
break;
}//switch结束
}while(p!=0);
cout<<" End PL/0--Sundic\n";
}//interpret结束
void PL0::SaveCode()
{
if(fout)
for (int i=0;i<cx;i++)
fprintf(fout,"%d %s %d %d\n ",i,mnemonic[code[i].f],code[i].l,code[i].a);
fclose(fout);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -