/*--------------------------------------------------------------*/ /* 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 } /*--------------------------------------------------------------*/