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

📄 pl0.cpp

📁 使用C语言实现的PL0编译器。 扩充了++ -- 以及添加注释功能
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// PL0.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <stdio.h>  
#include "string.h"  
/*   PL/0编译系统C版本头文件pl0.h   */ 
/*typedef enum{
	false,
	true;
} bool; */ 
#define norw 13					/* 关键字个数 */  
#define txmax 100				/* 名字表容量 */   
#define nmax 14				/* number的最大位数 */  
#define al 10						/* 符号的最大长度 */ 
#define amax 2047			/* 地址上界 */  
#define levmax 3				/* 最大允许过程嵌套声明层数 */  
#define cxmax 200				/* 最多的虚拟机代码数 */  
/*  符号  */
enum symbol {
		nul,			ident,		number,			plus,		minus,
		times,			slash,		oddsym,			eql,		neq,
		lss,			leq,		gtr,			geq,		lparen,
		rparen,			comma,		semicolon,		period,		becomes,
		beginsym,		endsym,	    ifsym,			thensym,	whilesym,
		writesym,		readsym,	dosym,			callsym,	constsym,
		varsym,			procsym,
};  
#define symnum 32  
/* 名字表中的类型 */  
enum object {
		constant,
		variable,
		procedur,
};  
/* 虚拟机代码 */  
enum fct {
		lit,			opr,			lod,
		sto,			cal,			inte,
		jmp,			jpc,
};  
#define fctnum 8  
/* 虚拟机代码结构 */  
struct instruction  
{  
		enum fct f;	/* 虚拟机代码指令 */  
		int l;				/* 引用层与声明层的层次差 */  
		int a;				/* 根据f的不同而不同 */  
};  
FILE* fas;										/* 输出名字表 */  
FILE* fa;										/* 输出虚拟机代码 */  
FILE* fa1;										/* 输出源文件及其各行对应的首地址 */  
FILE* fa2;										/* 输出结果 */  
bool listswitch;								/* 显示虚拟机代码与否 */  
bool tableswitch;							/* 显示名字表与否 */  
char ch;										/* 获取字符的缓冲区,getch 使用 */  
enum symbol sym;							/* 当前的符号 */  
char id[al+1];									/* 当前ident */  
int num;										/* 当前number */  
int cc,ll;											/* getch使用的计数器,cc表示当前字符(ch)的位置 */  
int cx;											/* 虚拟机代码指针 */  
char line[81];									/* 读取行缓冲区 */  
char a[al+1];									/* 临时符号 */  
struct instruction code[cxmax];		/* 存放虚拟机代码的数组 */  
char word[norw][al];						/* 保留字 */  
enum symbol wsym[norw];				/* 保留字对应的符号值 */  
enum symbol ssym[256];				/* 单字符的符号值 */  
char mnemonic[fctnum][5];				/* 虚拟机代码指令名称 */  
bool declbegsys[symnum];				/* 表示声明开始的符号集合 */  
bool statbegsys[symnum];				/* 表示语句开始的符号集合 */  
bool facbegsys[symnum];				/* 表示因子开始的符号集合 */  
/* 名字表结构 */  
struct tablestruct  
{  
		char name[al];				/* 名字 */  
		enum object kind;			/* 类型:const,var or procedure */  
		int val;							/* 数值,仅const使用 */  
		int level;						/* 所处层,仅const不使用 */  
		int adr;							/* 地址,仅const不使用 */  
		int size;							/* 需要分配的数据区空间,仅procedure使用 */  
};  
struct tablestruct table[txmax]; /* 名字表 */  
FILE* fin;  
FILE* fout;  
char fname[al];  
int err;		/* 错误计数器 */  
/* 当函数中会发生fatal error时,返回-1告知调用它的函数,最终退出程序 */  
#define getsymdo							if(-1==getsym())return -1  
#define getchdo								if(-1==getch())return -1  
#define testdo(a,b,c)						if(-1==test(a,b,c))return -1  
#define gendo(a,b,c)						if(-1==gen(a,b,c))return -1  
#define expressiondo(a,b,c)				if(-1==expression(a,b,c))return -1  
#define factordo(a,b,c)					if(-1==factor(a,b,c))return -1  
#define termdo(a,b,c)						if(-1==term(a,b,c))return -1  
#define conditiondo(a,b,c)				if(-1==condition(a,b,c))return -1  
#define statementdo(a,b,c)				if(-1==statement(a,b,c))return -1  
#define constdeclarationdo(a,b,c)	if(-1==constdeclaration(a,b,c))return -1  
#define vardeclarationdo(a,b,c)		if(-1==vardeclaration(a,b,c))return -1  
void error(int n);   
int getsym();  
int getch();  
void init();  
int gen(enum fct x,int y,int z);  
int test(bool* s1,bool* s2,int n);  
int inset(int e,bool* s);  
int addset(bool* sr,bool* s1,bool* s2,int n);  
int subset(bool* sr,bool* s1,bool* s2,int n);  
int mulset(bool* sr,bool* s1,bool* s2,int n);  
int block(int lev,int tx,bool* fsys);  
void interpret();  
int factor(bool* fsys,int* ptx,int lev);  
int term(bool* fsys,int* ptx,int lev);  
int condition(bool* fsys,int* ptx,int lev);  
int expression(bool* fsys,int* ptx,int lev);  
int statement(bool* fsys,int* ptx,int lev);  
void listcode(int cx0);  
int vardeclaration(int* ptx,int lev,int* pdx);  
int constdeclaration(int* ptx,int lev,int* pdx);  
int postion(char* idt,int tx);  
void enter(enum object k,int* ptx,int lev,int* pdx);  
int base(int l,int* s,int b);  

/*编译和运行环境:   
*1 Visual C++ 6.0, Visual C++.NET and Visual C++.NET 2003
*   WInNT, Win2000, WinXP and Win2003
*2 gcc version 3.3.2 20031022(Red Hat Linux 3.3.2-1)
*   Redhat Fedora core 1
*   Intel 32 platform
*使用方法:  
*运行后输入PL/0源程序文件名  
*回答是否输出虚拟机代码  
*回答是否输出名字表  
*fa.tmp输出虚拟机代码  
*fa1.tmp输出源文件及其各行对应的首地址  
*fa2.tmp输出结果  
*fas.tmp输出名字表  
*/ 
#define stacksize 500    /* 解释执行时使用的栈 */  
#define SOURCE_FILE_NAME "F:\\My Documents\\学习\\编译原理\\pl0\\PL0\\Source.pl0"
int main()  
{  
    bool nxtlev[symnum];  
    printf("Input pl/0 file?   ");  
    //scanf("%s",fname);             /* 输入文件名 */  
	strcpy(fname,SOURCE_FILE_NAME);       //直接打开pl0文件,避免重复输入文件名
    fin=fopen(fname,"r");  
    if(fin)  
    {	printf("List object code?(Y/N)");       /* 是否输出虚拟机代码 */  
		/*scanf("%s",fname);  */
        listswitch=(fname[0]=='y'||fname[0]=='Y');  
        printf("List symbol table?(Y/N)");       /* 是否输出名字表 */  
        scanf("%s",fname);  
        tableswitch=(fname[0]=='y'||fname[0]=='Y');  
        fa1=fopen("fa1.tmp","w");
		fprintf(fa1,"Input pl\0 file?   ");
		fprintf(fa1,"%s\n",fname);
		init();
		err=0;  
        cc=cx=ll=0;  
        ch=' ';   
        if(-1!=getsym())  
        {  
            fa=fopen("fa.tmp","w");  
			fas=fopen("fas.tmp","w");  
			addset(nxtlev,declbegsys,statbegsys,symnum);  
			nxtlev[period]=true;  
			if(-1==block(0,0,nxtlev))                                   /* 调用编译程序 */  
            {  
				fclose(fa);  
				fclose(fa1);  
				fclose(fas);
				fclose(fin);  
				printf("\n");  
				return 0;  
            }  
			fclose(fa);  
			fclose(fa1);
			fclose(fas);
			if(sym!=period)
			{
				error(9); 
			}
			if(err==0)
			{   fa2=fopen("fa2.tmp","w");
				interpret();   /* 调用解释执行程序 */ 
				fclose(fa2);
			}
			else  
			{  
                printf("Errors in pl/0 program");  
            }  
         }  
         fclose(fin);  
    }  
    else  
    {  
         printf("Can't open file!\n");  
    }  
    printf("\n");  
    return 0;  
} 

/* 初始化 */  
void init()  
{  
	int i;  
	/* 设置单字符符号 */  
	for(i=0;i<=255;i++)
	{ 
		ssym[i]=nul;
	}
	ssym['+']=plus;  
	ssym['-']=minus;  
	ssym['*']=times;  
	ssym['/']=slash;  
	ssym['(']=lparen;  
	ssym[')']=rparen;  
	ssym['=']=eql;  
	ssym[',']=comma;  
	ssym['.']=period;  
	ssym['#']=neq;  
	ssym[';']=semicolon;  

	/* 设置保留字名字 */  
	strcpy(&(word[0][0]),"begin");  
	strcpy(&(word[1][0]),"call");  
	strcpy(&(word[2][0]),"const");  
	strcpy(&(word[3][0]),"do");  
	strcpy(&(word[4][0]),"end");  
	strcpy(&(word[5][0]),"if");  
	strcpy(&(word[6][0]),"odd");  
	strcpy(&(word[7][0]),"procedure");  
	strcpy(&(word[8][0]),"read");  
	strcpy(&(word[9][0]),"then");  
	strcpy(&(word[10][0]),"var");  
	strcpy(&(word[11][0]),"while");  
	strcpy(&(word[12][0]),"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;  

	/* 设置指令名称 */  
	strcpy(&(mnemonic[lit][0]),"lit");  
	strcpy(&(mnemonic[opr][0]),"opr");  
	strcpy(&(mnemonic[lod][0]),"lod");  
	strcpy(&(mnemonic[sto][0]),"sto");  
	strcpy(&(mnemonic[cal][0]),"cal");  
	strcpy(&(mnemonic[inte][0]),"int");  
	strcpy(&(mnemonic[jmp][0]),"jmp");  
	strcpy(&(mnemonic[jpc][0]),"jpc");  

	/* 设置符号集 */  
	for(i=0;i<symnum;i++)  
	{  
		declbegsys[i]=false;  
		statbegsys[i]=false;  
		facbegsys[i]=false;  
	}  

	/* 设置声明开始符号集 */  
	declbegsys[constsym]=true;  
	declbegsys[varsym]=true;  
	declbegsys[procsym]=true;  

	/* 设置语句开始符号集 */  
	statbegsys[beginsym]=true;  
	statbegsys[callsym]=true;  
	statbegsys[ifsym]=true;  
	statbegsys[whilesym]=true;  

	/* 设置因子开始符号集 */  
	facbegsys[ident]=true;  
	facbegsys[number]=true;  
	facbegsys[lparen]=true;  
}  

/* 用数组实现集合的集合运算 */  
int inset(int e,bool* s)  
{  
	return s[e];  
}  

int addset(bool* sr,bool* s1,bool* s2,int n)  
{  
	int i;  
	for(i=0;i<n;i++)  
	{  
		sr[i]=s1[i]||s2[i];  
	}  
	return 0;  
}  

int subset(bool* sr,bool* s1,bool* s2,int n)  
{  
	int i;  
	for(i=0;i<n;i++)  
	{  
	sr[i]=s1[i]&&(!s2[i]);  
	}  
	return 0;  
}  

int mulset(bool* sr,bool* s1,bool* s2,int n)  
{  
	int i;  
	for(i=0;i<n;i++)  
	{  
		sr[i]=s1[i]&&s2[i];  
	}  
	return 0;  
}  

/* 在适当的位置显示错误 */  
void error(int n)  
{  
    char space[81];  
    memset(space,32,81);  
    space[cc-1]=0;   //出错时当前符号已经读完,所以cc-1                                                    
    printf("****%s!%d\n",space,n);  
    fprintf(fa1,"****%s!%d\n",space,n);  
    err++;  
}  
/* 漏掉空格,供getsym取一个字符。
每次读一行,存入line缓冲区,line被getsym取空时 再读一行*/  
int getch()  
{  
	if(cc==ll)  
	{  
		if(feof(fin))  
		{
			printf("program incomplete");  
			return -1;  
		}  
		ll=0;  
		cc=0;  
		printf("%d ",cx);  
		fprintf(fa1,"%d ",cx);  
		ch=' ';  
		while(ch!=10)  
		{  
			if(EOF==fscanf(fin,"%c",&ch))
			{  
				line[ll]=0;  
				break;  
			}  
			printf("%c",ch);
			fprintf(fa1,"%c",ch);
			line[ll]=ch;
			ll++;
		}
		printf("\n");  
		fprintf(fa1,"\n");  
	}  
	ch=line[cc];  
	cc++;  
	return 0;  
}  

/* 词法分析,获取一个符号 */  
int getsym()  
{  
    int i,j,k;  
    while(ch==' '||ch==10||ch==9)  /*忽略空格、换行和TAB*/                              
    {  
	 getchdo;  
    }
    if(ch>='a'&&ch<='z')  
    {                        /*名字或保留字以a..z开头*/                                        
	 k=0;  
	 do  
	 {  
	      if(k<al)  
	      {  
		   a[k]=ch;  
		   k++;  
	      }  
	      getchdo;  
         }  
	 while(ch>='a'&&ch<='z'||ch>='0'&&ch<='9');  
	      a[k]=0;  
	 strcpy(id,a);  
	 i=0;  
	 j=norw-1;  
	 do             /* 搜索当前符号是否为保留字 */  
	 {  
              k=(i+j)/2;  
	      if(strcmp(id,word[k])<=0)
		  {  
			  j=k-1; 
		  }
	      if(strcmp(id,word[k])>=0)
		  {
			  i=k+1;
		  }
	 } while(i<=j);  
	      if(i-1>j)
		  {
		     sym=wsym[k];
		  }
	      else 
		  {
			  sym=ident;
		  }/* 搜索失败则,是名字或数字 */  
    }  
    else  
    {  
	 if(ch>='0'&&ch<='9')  
         { /* 检测是否为数字:以0..9开头 */  
	      k=0;  
	      num=0;  
	      sym=number;  
	      do  
	      {  
	           num=10*num+ch-'0';  
				k++;  
	     	    getchdo;  
	      } while(ch>='0'&&ch<='9');                               /* 获取数字的值 */  
	           k--;  
				if(k>nmax)
				{
					error(30);
				}
	 }  
	 else  
	 {  
          if(ch==':') /* 检测赋值符号 */  
	      {  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -