📄 pass2.cpp
字号:
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ +
+ 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 + -