⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 编译器.cpp

📁 编译原理课程设计,用C写的PL/0编译器,有详细的文档和代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
			}
		}
		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 + -