📄 cgen.c
字号:
/****************************************************/
/* File: cgen.c */
/* The code generator implementation */
/* for the TINY compiler */
/* (generates code for the TM machine) */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/
#include "Globals.h"
#include "SymTab.h"
#include "Code.h"
#include "CGen.h"
int iloc = 0 ;
int dloc = 0 ;
int traceflag = TRUE;
int icountflag = TRUE;
int dMem [DADDR_SIZE];
int reg [NO_REGS];
char in_Line[LINESIZE] ;
int lineLen ;
int inCol ;
int num ;
/* tmpOffset is the memory offset for temps
It is decremented each time a temp is
stored, and incremeted when loaded again
*/
static int tmpOffset = 0;
const char * opCodeTab[] = {
"HALT","IN","OUT","ADD","SUB","MUL","DIV","????",
/* RR opcodes */
"LD","ST","????", /* RM opcodes */
"LDA","LDC","JLT","JLE","JGT","JGE","JEQ","JNE","????"
/* RA opcodes */
};
/********************************************/
void writeInstruction ( int loc )
{
printf( "%5d: ", loc) ;
if ( (loc >= 0) && (loc < IADDR_SIZE) )
{
printf("%6s%3d,", opCodeTab[iMem[loc].iop], iMem[loc].iarg1);
switch ( opClass(iMem[loc].iop) )
{
case opclRR:
printf("%1d,%1d", iMem[loc].iarg2, iMem[loc].iarg3);
break;
case opclRM:
case opclRA:
printf("%3d(%1d)", iMem[loc].iarg2, iMem[loc].iarg3);
break;
}
printf ("\n") ;
}
} /* writeInstruction */
/* prototype for internal recursive code generator */
static void cGen (TreeNode * tree);
/* Procedure genStmt generates code at a statement node */
static void genStmt( TreeNode * tree)
{
TreeNode * p1, * p2, * p3;
int savedLoc1,savedLoc2,currentLoc;
int loc;
switch (tree->kind.stmt) {
case IfK :
if (TraceCode)
emitComment("-> if") ;
p1 = tree->child[0] ;
p2 = tree->child[1] ;
p3 = tree->child[2] ;
/* generate code for test expression */
cGen(p1);
savedLoc1 = emitSkip(1) ;
emitComment("if: jump to else belongs here");
/* recurse on then part */
cGen(p2);
savedLoc2 = emitSkip(1) ;
emitComment("if: jump to end belongs here");
currentLoc = emitSkip(0) ;
emitBackup(savedLoc1) ;
emitRM_Abs(opJEQ,ac,currentLoc,"if: jmp to else");
emitRestore() ;
/* recurse on else part */
cGen(p3);
currentLoc = emitSkip(0) ;
emitBackup(savedLoc2) ;
emitRM_Abs(opLDA,pc,currentLoc,"jmp to end") ;
emitRestore() ;
if (TraceCode)
emitComment("<- if") ;
break; /* if_k */
case RepeatK:
if (TraceCode)
emitComment("-> repeat") ;
p1 = tree->child[0] ;
p2 = tree->child[1] ;
savedLoc1 = emitSkip(0);
emitComment("repeat: jump after body comes back here");
/* generate code for body */
cGen(p1);
/* generate code for test */
cGen(p2);
emitRM_Abs(opJEQ,ac,savedLoc1,"repeat: jmp back to body");
if (TraceCode)
emitComment("<- repeat") ;
break; /* repeat */
case AssignK:
if (TraceCode)
emitComment("-> assign") ;
/* generate code for rhs */
cGen(tree->child[0]);
/* now store value */
loc = st_lookup(tree->attr.name);
emitRM(opST,ac,loc,gp,"assign: store value");
if (TraceCode)
emitComment("<- assign") ;
break; /* assign_k */
case ReadK:
emitRO(opIN,ac,0,0,"read integer value");
loc = st_lookup(tree->attr.name);
emitRM(opST,ac,loc,gp,"read: store value");
break;
case WriteK:
/* generate code for expression to write */
cGen(tree->child[0]);
/* now output it */
emitRO(opOUT,ac,0,0,"write ac");
break;
default:
break;
}
} /* genStmt */
/* Procedure genExp generates code at an expression node */
static void genExp( TreeNode * tree)
{
int loc;
TreeNode * p1, * p2;
switch (tree->kind.exp) {
case ConstK :
if (TraceCode)
emitComment("-> Const") ;
/* gen code to load integer constant using LDC */
emitRM(opLDC,ac,tree->attr.val,0,"load const");
if (TraceCode)
emitComment("<- Const") ;
break; /* ConstK */
case IdK :
if (TraceCode)
emitComment("-> Id") ;
loc = st_lookup(tree->attr.name);
emitRM(opLD,ac,loc,gp,"load id value");
if (TraceCode)
emitComment("<- Id") ;
break; /* IdK */
case OpK :
if (TraceCode)
emitComment("-> Op") ;
p1 = tree->child[0];
p2 = tree->child[1];
/* gen code for ac = left arg */
cGen(p1);
/* gen code to push left operand */
emitRM(opST,ac,tmpOffset--,mp,"op: push left");
/* gen code for ac = right operand */
cGen(p2);
/* now load left operand */
emitRM(opLD,ac1,++tmpOffset,mp,"op: load left");
switch (tree->attr.op) {
case PLUS :
emitRO(opADD,ac,ac1,ac,"op +");
break;
case MINUS :
emitRO(opSUB,ac,ac1,ac,"op -");
break;
case TIMES :
emitRO(opMUL,ac,ac1,ac,"op *");
break;
case OVER :
emitRO(opDIV,ac,ac1,ac,"op /");
break;
case LT :
emitRO(opSUB,ac,ac1,ac,"op <") ;
emitRM(opJLT,ac,2,pc,"br if true") ;
emitRM(opLDC,ac,0,ac,"false case") ;
emitRM(opLDA,pc,1,pc,"unconditional jmp") ;
emitRM(opLDC,ac,1,ac,"true case") ;
break;
case EQ :
emitRO(opSUB,ac,ac1,ac,"op ==") ;
emitRM(opJEQ,ac,2,pc,"br if true");
emitRM(opLDC,ac,0,ac,"false case") ;
emitRM(opLDA,pc,1,pc,"unconditional jmp") ;
emitRM(opLDC,ac,1,ac,"true case") ;
break;
default:
emitComment("BUG: Unknown operator");
break;
} /* case op */
if (TraceCode)
emitComment("<- Op") ;
break; /* OpK */
default:
break;
}
} /* genExp */
/* Procedure cGen recursively generates code by
* tree traversal
*/
static void cGen( TreeNode * tree)
{
if (tree != NULL)
{
switch (tree->nodekind) {
case StmtK:
genStmt(tree);
break;
case ExpK:
genExp(tree);
break;
default:
break;
}
cGen(tree->sibling);
}
}
/**********************************************/
/* the primary function of the code generator */
/**********************************************/
/* Procedure codeGen generates code to a code
* file by traversal of the syntax tree. The
* second parameter (codefile) is the file name
* of the code file, and is used to print the
* file name as a comment in the code file
*/
void codeGen(TreeNode * syntaxTree, char * codefile)
{
emitLoc = 0;
char *s = (char*)malloc(strlen(codefile)+7);
strcpy(s,"File: ");
strcat(s,codefile);
emitComment("TINY Compilation to TM Code");
emitComment(s);
/* generate standard prelude */
emitComment("Standard prelude:");
emitRM(opLD,mp,0,ac,"load maxaddress from location 0");
emitRM(opST,ac,0,ac,"clear location 0");
emitComment("End of standard prelude.");
/* generate code for TINY program */
cGen(syntaxTree);
/* finish */
emitComment("End of execution.");
emitRO(opHALT,0,0,0,"");
};
/********************************************/
static STEPRESULT stepTM ()
{
INSTRUCTION currentinstruction;
int pcindex;
int r,s,t,m;
int ok ;
pcindex = reg[PC_REG] ;
if ( (pcindex < 0) || (pcindex > IADDR_SIZE) )
return srIMEM_ERR ;
reg[PC_REG] = pcindex + 1 ;
currentinstruction = iMem[ pcindex ] ;
switch (opClass(currentinstruction.iop) )
{
case opclRR :
/***********************************/
r = currentinstruction.iarg1 ;
s = currentinstruction.iarg2 ;
t = currentinstruction.iarg3 ;
break;
case opclRM :
/***********************************/
r = currentinstruction.iarg1 ;
s = currentinstruction.iarg3 ;
m = currentinstruction.iarg2 + reg[s] ;
if ( (m < 0) || (m > DADDR_SIZE))
return srDMEM_ERR ;
break;
case opclRA :
/***********************************/
r = currentinstruction.iarg1 ;
s = currentinstruction.iarg3 ;
m = currentinstruction.iarg2 + reg[s] ;
break;
} /* case */
switch ( currentinstruction.iop)
{
/* RR instructions */
case opHALT :
/***********************************/
printf("HALT: %1d,%1d,%1d\n",r,s,t);
return srHALT ;
/* break; */
case opIN :
/***********************************/
ok = 0;
do
{
printf("Enter value for IN instruction: ") ;
fflush (stdin);
fflush (stdout);
gets(in_Line);
lineLen = strlen(in_Line) ;
inCol = 0;
//ok = getNum();
//if ( ! ok )
// printf ("Illegal value\n");
num = atoi(in_Line);
printf("Num is: %d\n", num);
if(num > 0)
ok = 1;
//else reg[r] = num;
reg[r] = num;
}
while (! ok);
break;
case opOUT :
printf ("OUT instruction prints: %d\n", reg[r] ) ;
break;
case opADD :
reg[r] = reg[s] + reg[t] ;
break;
case opSUB :
reg[r] = reg[s] - reg[t] ;
break;
case opMUL :
reg[r] = reg[s] * reg[t] ;
break;
case opDIV :
/***********************************/
if ( reg[t] != 0 )
reg[r] = reg[s] / reg[t];
else
return srZERODIVIDE ;
break;
/*************** RM instructions ********************/
case opLD :
reg[r] = dMem[m] ;
break;
case opST :
dMem[m] = reg[r] ;
break;
/*************** RA instructions ********************/
case opLDA :
reg[r] = m ;
break;
case opLDC :
reg[r] = currentinstruction.iarg2 ;
break;
case opJLT :
if ( reg[r] < 0 )
reg[PC_REG] = m ;
break;
case opJLE :
if ( reg[r] <= 0 )
reg[PC_REG] = m ;
break;
case opJGT :
if ( reg[r] > 0 )
reg[PC_REG] = m ;
break;
case opJGE :
if ( reg[r] >= 0 )
reg[PC_REG] = m ;
break;
case opJEQ :
if ( reg[r] == 0 )
reg[PC_REG] = m ;
break;
case opJNE :
if ( reg[r] != 0 )
reg[PC_REG] = m ;
break;
/* end of legal instructions */
} /* case */
return srOKAY ;
} /* stepTM */
int doRun(){
//初始化
int stepResult, regNo, loc;
int stepcnt=0;
iloc = 0;
dloc = 0;
for (regNo = 0; regNo < NO_REGS ; regNo++)
reg[regNo] = 0 ;
dMem[0] = DADDR_SIZE - 1 ;
for (loc = 1 ; loc < DADDR_SIZE ; loc++)
dMem[loc] = 0 ;
printf("\nInstucation Begin: \n");
for(loc = 0; loc < emitLoc; loc++)
writeInstruction( loc ) ;
printf("Instucation End: \n\n");
stepResult = srOKAY;
while (stepResult == srOKAY)
{
iloc = reg[PC_REG] ;
if ( traceflag )
writeInstruction( iloc ) ;
stepcnt++;
stepResult = stepTM ();
}
if(!stepResult)
printf("Run Error !\n");
if ( icountflag )
printf("Number of instructions executed = %d\n",stepcnt);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -