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

📄 pass2.cpp

📁 虚拟机设计与实现——C/C++
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+                                                                   +
+ pass2.c -	build listing file and                                  +
+           generate bytecode into temporary file					+
+                                                                   +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
+ macros                                                            +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/*#define PASS2_DEBUG		1*/

#ifdef	PASS2_DEBUG
#define	PASS2_DEBUG0(arg);						printf(arg);
#define PASS2_DEBUG1(arg1,arg2);				printf(arg1,arg2);
#define PASS2_DEBUG2(arg1,arg2,arg3);			printf(arg1,arg2,arg3);
#else
#define	PASS2_DEBUG0(arg);
#define PASS2_DEBUG1(arg1,arg2);
#define PASS2_DEBUG2(arg1,arg2,arg3);
#endif

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ declaration                                                       +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

class Pass2
{
	U4 bytePosPass2;		/*current index of bytecode being generated*/

	FILE *lfptr;			/*pointer to list file*/
	FILE *tfptr;			/*pointer to temporary bytecode file*/

	char *lfile;			/*pointer to list file name*/
	char *tfile;			/*pointer to temporary bytecode file name*/

	char lfBuffer[BUFFER_SIZE];   /*output buffer for list file*/
	char tfBuffer[BUFFER_SIZE];	  /*output buffer for temp file*/

	int iLFChar;	/*index into lfBuffer*/
	int iTFChar;	/*index into tfBuffer*/

	CommandLine *cmdLine;
	StringTable *strTbl;
	SymbolTable *symTbl;
	HashTable *hashTbl;
	LineTokenizer *toker;

	char listing[LINE_SIZE];	/*line of text file to place in listing file*/	
	char lineNumber[32];		/*line number to place in listing file*/
	U1 encoded[11];				/*holds bytes to write to temp file*/

	void putByteTempBuff(U1 byte);
	void flushTempBuff();

	void putStrLstBuff(char *str);
	void putByteLstBuff(U1 byte);
	void flushLstBuff();

	void  processDirective(struct Token *tptr, struct Line *line);
	void  processGDirective(struct Token *tptr, struct Line *line);
	void  processPDirective(struct Token *tptr, struct Line *line);

	void  processInstruction(struct Token *tptr);

	/*print symbol table, called by generateSymbolSummary()*/
	void printGlobVarToLst(struct GlobalVariable *ptr); 
	void printProcToLst(struct Procedure *ptr);
	void printTreeToLst(struct HashTbl* link, int level);

	/*
	Instruction handling
		I = instruction opcode
		B = byte constant
		R, F, D = registers ( int, float, double )
		C = constant, varies in size
		A = identifier -> resolved to 'A'ddress
	*/

	void I(U1 opcode, struct Token *tptr);
	
	void IB(U1 opcode, struct Token *tptr);
	void IRC(U1 opcode, U1 bytes, struct Token *tptr);
	void IRA(struct Token *tptr);
	void I2RA(struct Token *tptr);

	void IR(U1 opcode, struct Token *tptr);
	void I2R(U1 opcode,struct Token *tptr);
	void I3R(U1 opcode, struct Token *tptr);
	void I4R(U1 opcode, struct Token *tptr);

	void IRF(U1 opcode, struct Token *tptr);
	void IRD(U1 opcode, struct Token *tptr);

	void IFC(U1 opcode, struct Token *tptr);
	void IF(U1 opcode, struct Token *tptr);
	void I2F(U1 opcode, struct Token *tptr);
	void I3F(U1 opcode, struct Token *tptr);
	void IFR(U1 opcode, struct Token *tptr);
	void IFD(U1 opcode, struct Token *tptr);

	void IDC(U1 opcode, struct Token *tptr);
	void ID(U1 opcode, struct Token *tptr);
	void I2D(U1 opcode, struct Token *tptr);
	void I3D(U1 opcode, struct Token *tptr);
	void IDR(U1 opcode, struct Token *tptr);
	void IDF(U1 opcode, struct Token *tptr);

	void commitToFiles(U1 len);

	public:
	Pass2(CommandLine *cptr, StringTable *st, SymbolTable *syt, HashTable *ht);
	~Pass2();

	void parseLine(struct Line *line);
	void generateSymbolSummary();
};

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ definitions                                                       +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

Pass2::Pass2(CommandLine *cptr, StringTable *st, SymbolTable *syt, HashTable *ht)
{ 
	cmdLine = cptr;
	strTbl = st;
	symTbl = syt;
	hashTbl = ht;

	lfile = (*cptr).listFile;
	tfile = (*cptr).tempFile;

	if((*cmdLine).listing==TRUE)
	{
		if(lfile==NULL)
		{
			ERROR0("Pass2::Pass2(): listing file name has not been specified\n");
			FATAL_ERROR();
		}
		lfptr = fopen(lfile,"wb");
		if(lfptr==NULL)
		{
			ERROR0("Pass2::Pass2(): could not open listing file\n");
			FATAL_ERROR();
		}
	}

	if(tfile==NULL)
	{
		ERROR0("Pass2::Pass2(): temporary file's name is NULL\n");
		FATAL_ERROR();
	}
	tfptr = fopen(tfile,"wb");
	if(tfptr==NULL)
	{
		ERROR0("Pass2::Pass2(): could not open temporary file\n");
		FATAL_ERROR();
	}
	bytePosPass2 = 0;
	iLFChar = 0;
	iTFChar = 0;
	return;

}/*end constructor*/

/*-----------------------------------------------------------------*/

Pass2::~Pass2()
{
	if((*cmdLine).listing==TRUE)
	{
		flushLstBuff();
		if(fclose(lfptr)){ ERROR1("Pass2::~Pass2(): problem closing listing file\n",lfile); }
	}

	flushTempBuff();
	if(fclose(tfptr)){ ERROR1("Pass2::~Pass2(): problem closing temp file\n",tfile); }
	return;

}/*end destructor*/

/*-----------------------------------------------------------------*/

void Pass2::putByteTempBuff(U1 byte)
{
	int nbytes;
	nbytes = 0;

	tfBuffer[iTFChar] = byte;
	iTFChar++;

	if(iTFChar==BUFFER_SIZE)
	{
		nbytes = fwrite(tfBuffer,sizeof(U1),BUFFER_SIZE,tfptr);
		if(nbytes!=BUFFER_SIZE)
		{
			ERROR1("Pass2::putByteTempBuff(): error during fwrite to %s\n",tfile);
			FATAL_ERROR();
		}
		iTFChar = 0;
	}
	return;

}/*end putByteTempBuff*/

/*-----------------------------------------------------------------*/

void Pass2::flushTempBuff()
{
	int nbytes;
	nbytes = 0;

	if(iTFChar>0)
	{
		PASS2_DEBUG1("Pass2::flushTempBuff(): trying to flush %lu bytes\n",iTFChar);
		nbytes = fwrite(tfBuffer,sizeof(U1),iTFChar,tfptr);
		if(nbytes!=iTFChar)
		{
			ERROR1("Pass2::flushTempBuff(): only flushed %lu bytes\n",nbytes);
			ERROR1("Pass2::flushTempBuff(): error during flush to %s\n",tfile);
			FATAL_ERROR();
		}
		iTFChar = 0;	
	}
	return;

}/*end flushTempBuff*/

/*-----------------------------------------------------------------*/

void Pass2::putStrLstBuff(char *str)
{
	U4 i;
	U4 j;
	U4 size;
	size = strlen(str);
	j=0;
	while((str[j]==' ')||(str[j]=='\t')){ j++; }
	for(i=j;i<size;i++){ putByteLstBuff(str[i]); }
	return;

}/*end putStrLstBuff*/

/*-----------------------------------------------------------------*/

void Pass2::putByteLstBuff(U1 byte)
{
	int nbytes;

	nbytes = 0;

	lfBuffer[iLFChar] = byte;
	iLFChar++;

	if(iLFChar==BUFFER_SIZE)
	{
		nbytes = fwrite(lfBuffer,sizeof(U1),BUFFER_SIZE,lfptr);
		if(nbytes!=BUFFER_SIZE)
		{
			ERROR1("Pass2::putByteLstBuff(): only flushed %lu bytes\n",nbytes);
			ERROR1("Pass2::putByteLstBuff(): error during fwrite to %s\n",lfile);
			FATAL_ERROR();
		}
		iLFChar = 0;
	}
	return;

}/*end putByteLstBuff*/

/*-----------------------------------------------------------------*/

void Pass2::flushLstBuff()
{
	int nbytes;

	nbytes = 0;

	if(iLFChar>0)
	{
		PASS2_DEBUG1("Pass2::flushLstBuff(): trying to flush %lu bytes\n",iLFChar);
		nbytes = fwrite(lfBuffer,sizeof(U1),iLFChar,lfptr);
		if(nbytes!=iLFChar)
		{
			ERROR1("Pass2::flushLstBuff(): only flushed %lu bytes\n",nbytes);
			ERROR1("Pass2::flushLstBuff(): error during fwrite to %s\n",lfile);
			FATAL_ERROR();
		}
		iLFChar = 0;	
	}
	return;

}/*end flushLstBuff*/

/*-----------------------------------------------------------------*/

void Pass2::parseLine(struct Line *line)
{
	struct Token token;
	PASS2_DEBUG2("Pass2::parseLinePass2(): line->(%d)\t text->(%s)\n",(*line).line,(*line).src);

	/*
	line can be
		i) a directive ( starts with a period, i.e.  .IP )
		ii) an instruction ( opcode operand(s) )
		iii) a comment ( starts with # )
	*/
	
	LineTokenizer t(line);
	toker = &t;

	token = (*toker).getNextLineToken();

	if(token.type==TOK_NO_MORE){ return; }

	switch(token.text[0])
	{
		case '.':
		{ 
			if((*cmdLine).listing==TRUE){ processDirective(&token,line); } 
		}break;
		case '#':
		{ 
			/*ignore line*/ 
		}break;
		default:{ processInstruction(&token); }
	}
	return;

}/*end parseLine*/

/*-----------------------------------------------------------------*/

/*
	Directives:
	.IP identifier							import procedure
	.IG identifier							import global variable
	.GB identifier  [ integer ] [ EXPORT ]	define global variable
	( same for .GW, .GD, .GQ )
	.PB	identifier [ EXPORT ]				procedure begin
		.PR identifier +n					procedure return value
		.PA identifier +n					procedure argument
		.PV identifier -n					procedure local variable
		.PL identifier						procedure label
	.PE
*/

void  Pass2::processDirective(struct Token *tptr, struct Line *line)
{
	if((*tptr).type==TOK_IDENTIFIER)
	{
		switch((*tptr).text[1])
		{
			case 'G':{ processGDirective(tptr,line); }break;
			case 'P':{ processPDirective(tptr,line); }break;
			default:
			{
				ERROR1("Pass2::processDirective(): %s not a directive\n",(*tptr).text);
			}
		}
	}
	else
	{
		ERROR1("Pass2::processDirective(): %s not a directive\n",(*tptr).text);
	}
	return;

}/*end processDirective*/

/*-----------------------------------------------------------------*/

/*
.GB identifier  [ integer ] [ EXPORT ]	define global variable
	( same for .GW, .GD, .GQ )
*/

void  Pass2::processGDirective(struct Token *tptr, struct Line *line)
{
	sprintf(lineNumber,"%lu",(*tptr).line);
	putStrLstBuff(lineNumber);
	putByteLstBuff(')');

	putStrLstBuff((*line).src);
	putByteLstBuff('\n');

	return;

}/*end processGDirective*/

/*-----------------------------------------------------------------*/

/*
	.PB	identifier [ EXPORT ]				procedure begin
		.PR identifier +n					procedure return value
		.PA identifier +n					procedure argument
		.PV identifier -n					procedure local variable
		.PL identifier						procedure label
	.PE
*/

void  Pass2::processPDirective(struct Token *tptr, struct Line *line)
{
	if(strcmp((*tptr).text,".PB")==0)/*.PB	identifier [ EXPORT ]*/
	{
		putStrLstBuff("#++++++++++++++++++++++++++++++++++++++++\n");

		sprintf(lineNumber,"%lu",(*tptr).line);
		putStrLstBuff(lineNumber);
		putByteLstBuff(')');

		putStrLstBuff((*line).src);
		putByteLstBuff('\n');

	}/*end .PB*/
	else 
	{
		sprintf(lineNumber,"%lu",(*tptr).line);
		putStrLstBuff(lineNumber);
		putByteLstBuff(')');
		putByteLstBuff('\t');

		putStrLstBuff((*line).src);
		putByteLstBuff('\n');	
	}
	return;

}/*end processPDirective*/

/*-----------------------------------------------------------------*/

/*
Do not generate bytecode in first pass, but we need to know
	-offset of label directives
	-size of functions
Thus, we need to do minimal instruction processing to keep
track of bytesize via ->bytePos<- variable

use switch to help cut down on calls to strcmp()

can probably recycle basic skeleton and extend on this code for Pass2

Note: have 68 instructions total

Basic goal in each case is to populate 1/2 arrays and write them to file
	char listing[LINE_SIZE]; -> to listing file	
	U1 encoded[11];		-> to bytecode temp file
*/

void  Pass2::processInstruction(struct Token *tptr)
{
	if((*tptr).type==TOK_IDENTIFIER)
	{
		switch((*tptr).text[0])
		{
			case 'A':
			{
				if(strcmp((*tptr).text,"ADD")==0){ I3R(ADD,tptr); }
				else if(strcmp((*tptr).text,"AND")==0){ I3R(AND,tptr); }
				else
				{
					ERROR2("processInstructionPass1(): line %d, invalid opcode (%s)\n",(*tptr).line,(*tptr).text);
					return;
				}

			}break;
			case 'B':
			{
				if(strcmp((*tptr).text,"BS")==0){ I2R(BS,tptr); }
				else if(strcmp((*tptr).text,"BT")==0){ I3R(BT,tptr); }
				else
				{
					ERROR2("processInstructionPass1(): line %d, invalid opcode (%s)\n",(*tptr).line,(*tptr).text);
					return;
				}

			}break;
			case 'C':
			{
				if(strcmp((*tptr).text,"CAST_IF")==0){ IRF(CAST_IF,tptr);}
				else if(strcmp((*tptr).text,"CAST_ID")==0){ IRD(CAST_ID,tptr);}
				else if(strcmp((*tptr).text,"CAST_FI")==0){ IFR(CAST_FI,tptr);}
				else if(strcmp((*tptr).text,"CAST_FD")==0){ IFD(CAST_FD,tptr);}
				else if(strcmp((*tptr).text,"CAST_DI")==0){ IDR(CAST_DI,tptr);}
				else if(strcmp((*tptr).text,"CAST_DF")==0){ IDF(CAST_DF,tptr);}
				else
				{
					ERROR2("processInstructionPass1(): line %d, invalid opcode (%s)\n",(*tptr).line,(*tptr).text);
					return;
				}

			}break;
			case 'D':
			{
				if(strcmp((*tptr).text,"DIV")==0){ I4R(DIV,tptr);}
				else if(strcmp((*tptr).text,"DI")==0){ I(DI,tptr);}
				else if(strcmp((*tptr).text,"DADD")==0){ I3D(DADD,tptr);}
				else if(strcmp((*tptr).text,"DSUB")==0){ I3D(DSUB,tptr);}
				else if(strcmp((*tptr).text,"DMULT")==0){ I3D(DMULT,tptr);}
				else if(strcmp((*tptr).text,"DDIV")==0){ I3D(DDIV,tptr);}
				else if(strcmp((*tptr).text,"DSLT")==0){ I3D(DSLT,tptr);}
				else
				{
					ERROR2("processInstructionPass1(): line %d, invalid opcode (%s)\n",(*tptr).line,(*tptr).text);
					return;
				}

			}break;
			case 'E':
			{
				if(strcmp((*tptr).text,"EI")==0){ I(EI,tptr);}
				else
				{
					ERROR2("processInstructionPass1(): line %d, invalid opcode (%s)\n",(*tptr).line,(*tptr).text);
					return;
				}

			}break;
			case 'F':
			{
				if(strcmp((*tptr).text,"FADD")==0){ I3F(FADD,tptr);}
				else if(strcmp((*tptr).text,"FSUB")==0){ I3F(FSUB,tptr);}
				else if(strcmp((*tptr).text,"FMULT")==0){ I3F(FMULT,tptr);}
				else if(strcmp((*tptr).text,"FDIV")==0){ I3F(FDIV,tptr);}
				else if(strcmp((*tptr).text,"FSLT")==0){ I3F(FSLT,tptr);}
				else
				{
					ERROR2("processInstructionPass1(): line %d, invalid opcode (%s)\n",(*tptr).line,(*tptr).text);
					return;
				}

			}break;
			case 'H':
			{
				if(strcmp((*tptr).text,"HALT")==0){ I(HALT,tptr);}
				else
				{
					ERROR2("processInstructionPass1(): line %d, invalid opcode (%s)\n",(*tptr).line,(*tptr).text);
					return;
				}

			}break;
			case 'I':
			{
				if(strcmp((*tptr).text,"INT")==0){ IB(INT,tptr);}
				else
				{
					ERROR2("processInstructionPass1(): line %d, invalid opcode (%s)\n",(*tptr).line,(*tptr).text);
					return;

⌨️ 快捷键说明

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