/*--------------------------------------------------------------*/
/*
TinC - Tiny, in C
tinct13.c
Jan 2005, Peter F. Gray
Extrapolated from Tiny 1.1 coded by Jack W. Crenshaw, in Pascal,
as part of Jack's "Let's Build A Compiler" tutorial.
*/
/*--------------------------------------------------------------*/
#include "tinc13.h"
#include <stdio.h>
extern FILE *ip[MAXINCL]; // input (source) file
extern int slevel; // source level (for #includes)
extern long linenumber[MAXINCL]; // current source line number
extern char sname[MAXINCL][STRTMPSIZE]; // current source name
extern FILE *op; // output file
extern FILE *op1; // output file 1
extern FILE *op2; // output file 2
extern FILE *tr; // trace file
extern int tracing; // tracing flag
extern int opfile1; // output file flag 1
extern int opfile2; // output file flag 2
extern int genreguse; // generate reg use pcodes
extern int genreguse2; // as above, but for the final code
extern int warn; // warning flag
extern int wcount; // warning count
extern int interactive; // interactive flag
extern int trindent; // trace indent level
extern long totallines; // total number of source lines
extern int endofallsource; // no more source to process
extern int ifdeflevel; // #ifdef level
extern int section; // section type
extern int optlevel; // optimization level
/*--------------------------------------------------------------*/
/* Symbol Tables etc */
extern Symbol GS_Name[MAXGLOBALS]; // global symbol table (name)
extern int GS_Type[MAXGLOBALS]; // data type
extern int GS_Size[MAXGLOBALS]; // size (in 'data type' units)
extern int GS_ParamCount[MAXGLOBALS];
extern int GS_ParamType[MAXGLOBALS][MAXPARAMS];
extern Symbol LS_Name[MAXLOCALS]; // local symbol table (name)
extern int LS_Type[MAXLOCALS]; // data type
extern int LS_Size[MAXLOCALS]; // size (in 'data type' units)
extern long NumGlobals; // number of globals used
extern long NumLocals; // number of locals used
extern int TotLocSize; // space required for locals
extern Symbol DS_Name[MAXDEFS]; // definition table (name)
extern Symbol DS_Value[MAXDEFS]; // definition table (value)
extern long NumDefs; // number of Defs used
extern Symbol PS_Name[MAXPARAMS]; // parameter list (name)
extern int PS_Type[MAXPARAMS]; // data type
extern long NumParams;
extern Symbol CS_Name[MAXCONSTS]; // constant symbol table (name)
extern int CS_Type[MAXCONSTS]; // data type
extern char CS_Value[MAXCONSTS][MAXCONSTSIZE];
extern int CCount; // # of autogen constants
extern int NumConsts; // total # of constants
extern long LCount; // label Count
/*--------------------------------------------------------------*/
/* Staging Buffer */
extern struct sbuff_struct {
int pcode;
char s1[MAXLINESIZE]; // allow for #inline
char s2[MAXSYMSIZE];
char s3[MAXSYMSIZE];
int t1;
int t2;
} sbuff[MAXSTAGE];
extern long int sbufftop; // top of the staging buffer
extern long int sbuffopt; // pcode reduction by optimizer
/*--------------------------------------------------------------*/
/* Register Control */
extern struct vreg_struct {
char inuse; // reg in use flag
int allowed; // data types this reg can be used for
int datatype; // data type being held in reg
char type; // type of reg (NORMAL or STACK)
} vreg[MAXREGS];
extern char * DataTypeDesc (int);
extern void EmitLn();
extern void EmitLn_notab();
extern void Abort();
extern void EmitChar(char);
extern void Stage();
extern void Trace();
/*--------------------------------------------------------------*/
/* Generate code for a Staging Buffer item */
void Gen_Item (int pcode, char *s1, char *s2, char *s3,
int t1, int t2)
{
char strtmp1[STRTMPSIZE], dt1[TYPEDESCSIZE], dt2[TYPEDESCSIZE];
int tmp, tmp2 = 0;
strcpy(dt1,DataTypeDesc(t1));
strcpy(dt2,DataTypeDesc(t2));
if (pcode < 0) return;
switch (pcode) {
case PC_LABEL:
EmitLn("");
sprintf(strtmp1,"%s:",s1);
EmitLn_notab(strtmp1);
break;
case PC_BRANCH:
sprintf(strtmp1,"Branch to %s",s1);
EmitLn(strtmp1);
EmitLn("");
break;
case PC_BRANCH_FALSE:
sprintf(strtmp1,"Branch to %s if Reg%s (%s) false",s1,s2,dt1);
EmitLn(strtmp1);
EmitLn("");
break;
case PC_HEADER:
EmitLn("Header");
break;
case PC_PROLOG:
sprintf(strtmp1,"Prolog (%s)",s1);
EmitLn(strtmp1);
break;
case PC_EPILOG:
sprintf(strtmp1,"Epilog (%s)",s1);
EmitLn(strtmp1);
EmitLn("");
break;
case PC_ALLOCATE:
sprintf(strtmp1,"Allocate %s %s",s1,s2);
EmitLn(strtmp1);
break;
case PC_GROWSTACK:
sprintf(strtmp1,"Grow Stack for '%s' (%s of type %s)",s1,s2,s3);
EmitLn(strtmp1);
break;
case PC_SHRINKSTACK:
sprintf(strtmp1,"Shrink Stack %s (%s)",s1,s2);
EmitLn(strtmp1);
break;
case PC_MOVE_REG:
sprintf(strtmp1,"Move Reg%s (%s) to Reg%s (%s) ",s1,dt1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_ADD_REG:
sprintf(strtmp1,"Add Reg%s (%s) to Reg%s (%s)",s1,dt1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_SUB_REG:
sprintf(strtmp1,"Sub Reg%s (%s) from Reg%s (%s) (result in Reg%s)",s1,dt1,s2,dt2,s2);
EmitLn(strtmp1);
break;
case PC_MOVE_VAR_REG:
sprintf(strtmp1,"Move var '%s' (%s) to Reg%s (%s)",s1,dt1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_MOVE_LVAR_REG:
sprintf(strtmp1,"Move local var '%s' (%s) (offset %s) to Reg%s (%s)",s1,dt1,s2,s3,dt2);
EmitLn(strtmp1);
break;
case PC_MOVE_REG_VAR:
sprintf(strtmp1,"Move Reg%s (%s) to var '%s' (%s)",s1,dt1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_MOVE_REG_LVAR:
sprintf(strtmp1,"Move Reg%s (%s) to local var '%s' (%s) (offset %s)",s1,dt1,s2,dt2,s3);
EmitLn(strtmp1);
break;
case PC_MUL_REG:
sprintf(strtmp1,"Multiply Reg%s (%s) by Reg%s (%s)",s1,dt1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_DIV_REG:
sprintf(strtmp1,"Divide Reg%s (%s) by Reg%s (%s)",s1,dt1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_CLEAR_REG:
sprintf(strtmp1,"Clear Reg%s (%s)",s1,dt1);
EmitLn(strtmp1);
break;
case PC_COMPARE_REG:
sprintf(strtmp1,"Compare Reg%s (%s) to Reg%s (%s)",s1,dt1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_AND_REG:
sprintf(strtmp1,"AND Reg%s (%s) with Reg%s (%s)",s1,dt1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_OR_REG:
sprintf(strtmp1,"OR Reg%s (%s) with Reg%s (%s)",s1,dt1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_XOR_REG:
sprintf(strtmp1,"XOR Reg%s (%s) with Reg%s (%s)",s1,dt1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_NOT_REG:
sprintf(strtmp1,"NOT Reg%s (%s)",s1,dt1);
EmitLn(strtmp1);
break;
case PC_MOVE_A_REG:
sprintf(strtmp1,"Move address of var '%s' to Reg%s (%s)",s1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_MOVE_AL_REG:
sprintf(strtmp1,"Move address of local var '%s' (%s) (offset %s) to Reg%s (%s)",
s1,dt1,s3,s2,dt2);
EmitLn(strtmp1);
break;
case PC_ADJUST_REG:
sprintf(strtmp1,"Adjust Reg%s (%s) by data size of '%s' (%s)",s1,dt1,s2,s3);
EmitLn(strtmp1);
break;
case PC_MOVE_I_REG:
sprintf(strtmp1,"Move [Reg%s] to Reg%s (%s)",s1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_MOVE_REG_I:
sprintf(strtmp1,"Move Reg%s (%s) to [Reg%s] (%s)",s1,dt1,s2,s3);
EmitLn(strtmp1);
break;
case PC_MOVE_CONST_REG:
sprintf(strtmp1,"Move constant '%s' to Reg%s (%s)",s1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_SET_REG_EQ:
sprintf(strtmp1,"Set Reg%s if EQ",s1);
EmitLn(strtmp1);
break;
case PC_SET_REG_NE:
sprintf(strtmp1,"Set Reg%s if NE",s1);
EmitLn(strtmp1);
break;
case PC_SET_REG_LT:
sprintf(strtmp1,"Set Reg%s if LT",s1);
EmitLn(strtmp1);
break;
case PC_SET_REG_GT:
sprintf(strtmp1,"Set Reg%s if GT",s1);
EmitLn(strtmp1);
break;
case PC_SET_REG_GE:
sprintf(strtmp1,"Set Reg%s if GE",s1);
EmitLn(strtmp1);
break;
case PC_SET_REG_LE:
sprintf(strtmp1,"Set Reg%s if LE",s1);
EmitLn(strtmp1);
break;
case PC_INLINE:
sprintf(strtmp1,"#inline ");
strcat(strtmp1,s1);
EmitLn_notab(strtmp1);
break;
case PC_GETREG:
if (genreguse) {
sprintf(strtmp1,"+Reg%s",s1);
EmitLn_notab(strtmp1);
}
break;
case PC_FREEREG:
if (genreguse) {
sprintf(strtmp1,"-Reg%s",s1);
EmitLn_notab(strtmp1);
}
break;
case PC_SHIFTRIGHT:
sprintf(strtmp1,"Shift Reg%s (%s) right by Reg%s (%s) bits",s1,dt1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_SHIFTLEFT:
sprintf(strtmp1,"Shift Reg%s (%s) left by Reg%s (%s) bits",s1,dt1,s2,dt2);
EmitLn(strtmp1);
break;
case PC_SETFP:
EmitLn("Set the Frame Pointer");
break;
case PC_PUSHFP:
EmitLn("Push the Frame Pointer");
break;
case PC_POPFP:
EmitLn("Pop the Frame Pointer");
break;
case PC_DOCALL:
sprintf(strtmp1,"Call %s",s1);
EmitLn(strtmp1);
break;
case PC_CALLRET:
EmitLn("Return from routine");
break;
case PC_INTRET:
EmitLn("Return from interrupt");
break;
case PC_MOVE_PVAR_REG:
sprintf(strtmp1,"Move param '%s' (%s) (roffset %s) to Reg%s (%s)",s1,dt1,s2,s3,dt2);
EmitLn(strtmp1);
break;
case PC_MOVE_REG_PVAR:
sprintf(strtmp1,"Move Reg%s (%s) to param '%s' (%s) (roffset %s)",s1,dt1,s2,dt2,s3);
EmitLn(strtmp1);
break;
case PC_MOVE_AP_REG:
sprintf(strtmp1,"Move address of param '%s' (%s) (roffset %s) to Reg%s (%s)",
s1,dt1,s3,s2,dt2);
EmitLn(strtmp1);
break;
case PC_PUSH_REG:
sprintf(strtmp1,"Push Reg%s (%s) (%s)",s1,dt1,dt2);
EmitLn(strtmp1);
break;
case PC_PROGSEC:
EmitLn("");
EmitLn("Program Section");
break;
case PC_DATASEC:
EmitLn("");
EmitLn("Data Section");
break;
case PC_CONST:
sprintf(strtmp1,"Const %s (%s)",s1,dt1);
EmitLn_notab(strtmp1);
tmp = IsConst(s1);
while (CS_Value[tmp-1][tmp2]) {
EmitChar(CS_Value[tmp-1][tmp2]);
tmp2++;
}
EmitLn("");
break;
// level 1 optimization pcodes
case PC_BRANCH_EQ:
sprintf(strtmp1,"Branch to %s if EQ",s1);
EmitLn(strtmp1);
EmitLn("");
break;
case PC_BRANCH_NE:
sprintf(strtmp1,"Branch to %s if NE",s1);
EmitLn(strtmp1);
EmitLn("");
break;
case PC_BRANCH_LT:
sprintf(strtmp1,"Branch to %s if LT",s1);
EmitLn(strtmp1);
EmitLn("");
break;
case PC_BRANCH_GT:
sprintf(strtmp1,"Branch to %s if GT",s1);
EmitLn(strtmp1);
EmitLn("");
break;
case PC_BRANCH_GE:
sprintf(strtmp1,"Branch to %s if GE",s1);
EmitLn(strtmp1);
EmitLn("");
break;
case PC_BRANCH_LE:
sprintf(strtmp1,"Branch to %s if LE",s1);
EmitLn(strtmp1);
EmitLn("");
break;
// unknown pcode
default:
sprintf(strtmp1,"Unknown pcode (%d)",pcode);
Abort(strtmp1);
break;
}
}
/*--------------------------------------------------------------*/
/* Register Control Initialization */
void InitRegs()
{
int tmp;
for (tmp=0; tmp<MAXREGS; tmp++) {
vreg[tmp].inuse = FALSE;
vreg[tmp].datatype = ' ';
vreg[tmp].type = REG_NORMAL;
}
for (tmp=REG_STACKSTART; tmp<MAXREGS; tmp++) {
vreg[tmp].type = REG_STACK;
vreg[tmp].allowed = DT_ALL; // all types
}
vreg[0].allowed = DT_XCHAR; // all char types
vreg[1].allowed = DT_XCHAR; // all char types
vreg[2].allowed = DT_XINT | DT_XPTR; // all ints and ptrs
vreg[3].allowed = DT_XINT | DT_XPTR; // all ints and ptrs
}
/*--------------------------------------------------------------*/
/* Write Header Info */
void Header()
{
Stage (PC_HEADER,"","","",0,0);
}
/*--------------------------------------------------------------*/
/* Write Trailer Info */
void Trailer()
{
int tmp;
trace (' ',"Trailer","","","");
for (tmp=0; tmp<NumConsts; tmp++)
Stage (PC_CONST,CS_Name[tmp],"","",CS_Type[tmp],0);
}
/*--------------------------------------------------------------*/
/* Get the next 'real' pcode */
long int NextPcode (long int i)
{
long int j;
for (j=i+1; j<sbufftop; j++)
if (sbuff[j].pcode >= PC_FIRST_REAL) return j;
return sbufftop; // i.e. no more
}
/*--------------------------------------------------------------*/
/* Staging buffer optimizer (code according to target) */
void Optimize ()
{
long int i,j;
if (optlevel >= 1) { // optimization level 1 (all targets)
for (i=0; i<sbufftop; i++) {
if ((j=NextPcode(i))==sbufftop) { i=sbufftop; break; }
// set reg <condition>; branch false; -> branch <reverse condition>
if (sbuff[i].pcode >= PC_SET_REG_EQ &&
sbuff[i].pcode <= PC_SET_REG_LE &&
sbuff[j].pcode == PC_BRANCH_FALSE) {
sbuff[j].pcode = -sbuff[j].pcode;
strcpy(sbuff[i].s1,sbuff[j].s1);
switch (sbuff[i].pcode) {
case PC_SET_REG_EQ:
sbuff[i].pcode = PC_BRANCH_NE; break;
case PC_SET_REG_NE:
sbuff[i].pcode = PC_BRANCH_EQ; break;
case PC_SET_REG_LT:
sbuff[i].pcode = PC_BRANCH_GE; break;
case PC_SET_REG_GT:
sbuff[i].pcode = PC_BRANCH_LE; break;
case PC_SET_REG_GE:
sbuff[i].pcode = PC_BRANCH_LT; break;
case PC_SET_REG_LE:
sbuff[i].pcode = PC_BRANCH_GT; break;
}
sbuffopt++;
if ((i=NextPcode(i-1))==sbufftop) break;
if ((j=NextPcode(i))==sbufftop) { i=sbufftop; break; }
} // end of rule
// non-zero 'while' loop - simply remove the pcodes
if (sbuff[i].pcode == PC_MOVE_CONST_REG &&
sbuff[j].pcode == PC_BRANCH_FALSE &&
!strcmp(sbuff[i].s2,sbuff[i].s2) &&
strcmp(sbuff[i].s1,"0") ) {
sbuffopt += 2;
sbuff[i].pcode = -sbuff[i].pcode;
sbuff[j].pcode = -sbuff[j].pcode;
if ((i=NextPcode(i-1))==sbufftop) break;
if ((j=NextPcode(i))==sbufftop) { i=sbufftop; break; }
} // end of rule
} // end of 'for'
} // end of optimization level 1
}
/*--------------------------------------------------------------*/