📄 编译器.cpp
字号:
}
}
if (sym=="varsym") { //变量说明处理
getsym();
while (sym=="ident") {
vardeclaration();
while (sym=="comma") { //如果遇到了逗号则反复声明下一个变量
getsym();
vardeclaration();
}
if (sym=="semicolon") { //如果变量声明结束,应遇到分号
getsym();
}
else {
error(5); //如果变量声明语句结束后没有遇到分号则发出5号错误
}
}
}
while (sym=="procsym") { //过程说明处理
getsym();
if (sym=="ident") {
enter("procedur");
getsym();
}
else {
error(4);
}
if (sym=="semicolon") { //如果当前token为分号
getsym();
}
else {
error(5);
}
block(lev+1,tx,"ok"); //递归调用语法分析过程,当前层次加一,同时传递表头索引、合法单词符
if (sym=="semicolon") { //递归返回后当前token应为递归调用时的最后一个end后的分号
getsym();
//test(); //检查当前token是否合法,不合法则用fsys恢复语法分析同时抛6号错
}
else {
error(5);
}
//test(statbegsys + [ident], declbegsys, 7) (* 检查当前状态是否合法,不合法则用声明开始符号作出错恢复、抛7号错 *)
}
}
//声明性的源程序分析完毕,继续向下执行,分析主程序
code[table[tx0].adr].a=cx; //把前面生成的跳转语句的跳转位置改成当前位置
//在符号表中记录
table[tx0].adr=cx; //地址为当前代码分配地址
table[tx0].size=dx; //长度为当前数据代分配位置
cx0=cx; //记下当前代码分配位置
gen("int",0,dx); //生成分配空间指令,分配dx个空间
//addsym(fsys,"semicolon");
//addsym(fsys,"endsym");
statement(); //(* 处理当前遇到的语句或语句块 *)
gen("opr",0,0); //生成从子程序返回操作指令
//test(fsys, [], 8); (* 用fsys检查当前状态是否合法,不合法则抛8号错 *)
listcode(); //列出本层的类PCODE代码
}
//////////////////////////////////////////////////////////////////
int base(int *s,int b,int l){//通过静态链求出数据区基地址的函数并返回
int b1;
b1=b;
while(l>0){//如果层差大于零
b1=s[b1];// 用当前层数据区基址中的内容(正好是静态链SL数据,为上一层的基址)的作为新的当前层,即向上找了一层
l=l-1;//向上了一层,l减一
}
return b1;//把找到的要求的数据区基址返回
}
void interpret(){
int t,b,p;
int s[200];
Code i;//定义一个指令结构体
cout<<"PL/0程序开始运行!"<<endl;
t=0;//程序开始运行时栈顶寄存器置0
b=1;//数据段基址为1
p=0;//从0号代码开始执行程序
s[1]=0;
s[2]=0;
s[3]=0;//数据内存中为SL,DL,RA三个单元均为0,标识为主程序
// instruction code[25];//初始化指针
/* code[0].f="jmp";
code[0].l=0;
code[0].a=8;
code[1].f="jmp";
code[1].l=0;
code[1].a=2;
code[2].f="int";
code[2].l=0;
code[2].a=3;
code[3].f="lod";
code[3].l=1;
code[3].a=3;
code[4].f="lit";
code[4].l=0;
code[4].a=10;
code[5].f="opr";
code[5].l=0;
code[5].a=2;
code[6].f="sto";
code[6].l=1;
code[6].a=4;
code[7].f="opr";
code[7].l=0;
code[7].a=0;
code[8].f="int";
code[8].l=0;
code[8].a=5;
code[9].f="opr";
code[9].l=0;
code[9].a=16;
code[10].f="sto";
code[10].l=0;
code[10].a=3;
code[11].f="lod";
code[11].l=0;
code[11].a=3;
code[12].f="lit";
code[12].l=0;
code[12].a=0;
code[13].f="opr";
code[13].l=0;
code[13].a=9;
code[14].f="jpc";
code[14].l=0;
code[14].a=24;
code[15].f="cal";
code[15].l=0;
code[15].a=2;
code[16].f="lit";
code[16].l=0;
code[16].a=2;
code[17].f="lod";
code[17].l=0;
code[17].a=4;
code[18].f="opr";
code[18].l=0;
code[18].a=4;
code[19].f="opr";
code[19].l=0;
code[19].a=14;
code[20].f="opr";
code[20].l=0;
code[20].a=15;
code[21].f="opr";
code[21].l=0;
code[21].a=16;
code[22].f="sto";
code[22].l=0;
code[22].a=3;
code[23].f="jmp";
code[23].l=0;
code[23].a=11;
code[24].f="opr";
code[24].l=0;
code[24].a=0;*/
do{//开始依次运行程序目标代码
i=code[p];//获取一行目标代码
p=p+1;//指令指针加一,指向下一条代码
if(i.f=="lit"){//如果是lit指令
t=t+1;//栈顶指针上移,在栈中分配了一个单元
s[t]=i.a;//该单元的内容存放i指令的a操作数,即实现了把常量值放到运行栈栈顶
}
if(i.f=="opr"){//如果是opr指令
if(i.a==0){//0号操作为从子过程返回操作
t=b-1;//释放这段子过程占用的数据内存空间
p=s[t+3];//把指令指针取到RA的值,指向的是返回地址
b=s[t+2];// 把数据段基址取到DL的值,指向调用前子过程的数据段基址
}
if(i.a==1){//1号操作为栈顶数据取反操作
s[t]=-s[t];
}
if(i.a==2){//2号操作为栈顶两个数据加法操作
t=t-1;
s[t]=s[t]+s[t+1];
}
if(i.a==3){t=t-1;s[t]=s[t]-s[t+1];}//3号操作为栈顶两个数据减法操作
if(i.a==4){t=t-1;s[t]=s[t]*s[t+1];}//4号操作为栈顶两个数据乘法操作
if(i.a==5){t=t-1;//5号操作为栈顶两个数据除法操作
s[t]=s[t]/s[t+1];}
if(i.a==6){if(s[t]%2)//6号操作为判奇操作
s[t]=1;
else
s[t]=0; }
if(i.a==8){t=t-1;//8号操作为栈顶两个数据判等操作
if(s[t]==s[t+1])
s[t]=1;
else
s[t]=0;}
if(i.a==9){t=t-1;//9号操作为栈顶两个数据判不等操作
if(s[t]==s[t+1])
s[t]=0;
else
s[t]=1;}
if(i.a==10){t=t-1;// 10号操作为栈顶两个数据判小于操作
if(s[t]<s[t+1])
s[t]=1;
else
s[t]=0;}
if(i.a==11){t=t-1;//11号操作为栈顶两个数据判大于等于操作
if(s[t]>=s[t+1])
s[t]=1;
else
s[t]=0;}
if(i.a==12){t=t-1;// 12号操作为栈顶两个数据判大于操作
if(s[t]>s[t+1])
s[t]=1;
else
s[t]=0;}
if(i.a==13){t=t-1;// 13号操作为栈顶两个数据判小于等于操作
if(s[t]<=s[t+1])
s[t]=1;
else
s[t]=0;}
if(i.a==14){cout<<s[t]<<endl;//14号操作为输出栈顶值操作
t=t-1;}
if(i.a==15){cout<<endl;}//15号操作为输出换行操作
if(i.a==16){t=t+1;//16号操作是接受键盘值输入到栈顶
cout<<"?";
cin>>s[t];
cout<<endl;
}
}
if(i.f=="lod"){//如果是lod指令:将变量放到栈顶
t=t+1;//栈顶上移,开辟空间
s[t]=s[base(s,b,i.l)+i.a];//通过数据区层差l和偏移地址a找到变量的数据,存入上面开辟的新空间(即栈顶)
}
if(i.f=="sto"){//如果是sto指令
s[base(s,b,i.l)+i.a]=s[t];//把栈顶的值存入位置在数据区层差l偏移地址a的变量内存
t=t-1;//栈项下移,释放空间
}
if(i.f=="cal"){//如果是cal指令
s[t+1]=base(s,b,i.l);//在栈顶压入静态链SL
s[t+2]=b;//然后压入当前数据区基址,作为动态链DL
s[t+3]=p;//最后压入当前的断点,作为返回地址RA
//以上为过程调用前的保护现场
b=t+1;//把当前数据区基址指向SL所在位置
p=i.a;//从a所指位置开始继续执行指令,即实现了程序执行的跳转
}
if(i.f=="int"){//如果是int指令
t=t+i.a;//栈顶上移a个空间,即开辟a个新的内存单元
}
if(i.f=="jmp"){//如果是jmp指令
p=i.a;//把jmp指令操作数a的值作为下一次要执行的指令地址,实现无条件跳转
}
if(i.f=="jpc"){//如果是jpc指令
if(s[t]==0)//判断栈顶值
p=i.a;//如果是0就跳转,否则不跳转
t=t-1;//释放栈顶空间
}
}while(p!=0);//如果p等于0,意味着在主程序运行时遇到了从子程序返回指令,也就是整个程序运行的结束
}
void main() {
//这个循环把ssym数组全部填"NULL"
for (ch=0;ch<='^';ch++) {
ssym[ch]="NULL";
}
//初始化保留字
word[0]="begin";
word[1]="call";
word[2]="const";
word[3]="do";
word[4]="end";
word[5]="if";
word[6]="odd";
word[7]="procedure";
word[8]="read";
word[9]="then";
word[10]="var";
word[11]="while";
word[12]="write";
//初始化保留字符号列表
wsym[0]="beginsym";
wsym[1]="callsym";
wsym[2]="constsym";
wsym[3]="dosym";
wsym[4]="endsym";
wsym[5]="ifsym";
wsym[6]="oddsym";
wsym[7]="procsym";
wsym[8]="readsym";
wsym[9]="thensym";
wsym[10]="varsym";
wsym[11]="whilesym";
wsym[12]="writesym";
//初始化符号表,把可能出现的符号赋上相应的类型,其余符号由于开始处的循环所赋的类型均为"null"
ssym['+']="plus";
ssym['-']="minus";
ssym['*']="times";
ssym['/']="slash";
ssym['(']="lparen";
ssym[')']="rparen";
ssym['=']="eql";
ssym[',']="comma";
ssym['.']="period";
ssym['#']="neq";
ssym[';']="semicolon";
cx=0; //类PCODE代码表指针置0
tx=0; //登陆表指针置0
lev=0; //初始化层号为0
cc=0; //词法分析行缓冲区指针置0
ll=0; //词法分析行缓冲区长度置0
ch=' '; //词法分析当前字符为空格
kk=al; //置kk的值为允许的标识符的最长长度
err=0; //出错次数置0
fsys.count=0;
facbegsys.count=0;
cout<<"请输入源文件名:"<<endl;
cin>>fname;
infile.open(fname);
if (!infile) {
cout<<"没有找到文件 "<<fname<<endl;
}
getsym();
block(0,0,"ok");
cout<<"ok"<<endl;
for (int i=0;i<=cx;i++) {
cout<<code[i].f.data()<<" "<<code[i].l<<" "<<code[i].a<<endl;
}
for (int j=1;j<=tx;j++) {
cout<<table[j].kind.data()<<" "<<table[j].name.data()<<" "<<table[j].val<<endl;
//cout<<table[i].adr<<" "<<table[i].kind.data()<<" "<<table[i].level<<" "<<table[i].name.data()<<" "<<table[i].size<<" "<<table[i].val<<endl;
}
interpret();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -