home *** CD-ROM | disk | FTP | other *** search
- /*
- * 68K/386 32-bit C compiler.
- *
- * copyright (c) 1996, David Lindauer
- *
- * This compiler is intended for educational use. It may not be used
- * for profit without the express written consent of the author.
- *
- * It may be freely redistributed, as long as this notice remains intact
- * and sources are distributed along with any executables derived from them.
- *
- * The author is not responsible for damages, either direct or consequential,
- * that may arise from use of this software.
- *
- * v1.5 August 1996
- * David Lindauer, gclind01@starbase.spd.louisville.edu
- *
- * Credits to Mathew Brandt for original K&R C compiler
- *
- */
- #include <stdio.h>
- #include "expr.h"
- #include "c.h"
- #include "gen.h"
- #include "cglbdec.h"
-
- typedef struct muldiv {
- struct muldiv * link;
- long value;
- double floatvalue;
- int size;
- int label;
- } MULDIV;
- /* variable initialization */
- extern HASHREC **globalhash;
- extern int phiused;
-
- enum e_gt { nogen, bytegen, wordgen, longgen, floatgen, doublegen, longdoublegen, storagegen,srrefgen };
- enum e_sg { noseg, codeseg, dataseg,bssxseg,startupxseg,rundownxseg,cppxseg };
-
- extern int prm_asmfile;
- extern int prm_lines;
- extern FILE *tempfil;
-
- MULDIV *muldivlink = 0;
- int gentype = nogen; /* Current DC type */
- int curseg = noseg; /* Current seg */
- int outcol = 0; /* Curront col (roughly) */
- int newlabel;
- int needpointer;
- static int phiput;
- /* Init module */
- void outcodeini(void)
- {
- gentype = nogen;
- curseg = noseg;
- outcol = 0;
- newlabel = FALSE;
- phiput = FALSE;
- }
- /* List of opcodes
- * This list MUST be in the same order as the op_ enums
- */
- char * oplst[] = { "LINE#", "LABEL","SEQ@","DB",
- "ADD", "AND", "CALL", "CLD", "CMP", "CMPSB", "CMPSW", "CMPSD",
- "CWD", "CBW", "CBD", "DEC",
- "DIV", "IDIV", "IMUL", "INC", "JB", "JBE","JE", "JL",
- "JLE", "JNC", "JA", "JNE", "JGE", "JG", "JMP", "LEA", "LODSB",
- "LODSW", "LODSD",
- "MOV", "MOVSB", "MOVSW", "MOVSD", "MOVSX", "MOVZX", "MUL",
- "NEG", "NOT", "OR", "POP", "PUSH", "REP", "REPNZ", "REPZ",
- "RET", "SAHF", "SAL", "SAR", "SCASB", "SCASW", "SCASD",
- "SHR", "SHL", "STD", "STOSB", "STOSW", "STOSD", "SUB",
- "TEST", "XCHG", "XOR", "DD", "PUSHFD", "IRETD", "PUSHAD", "POPAD",
- "FADD", "FIADD", "FCHS", "FCOM", "FCOMP", "FCOMPP",
- "FDIV", "FIDIV", "FICOM", "FICOMP", "FILD", "FIST", "FISTP",
- "FLD", "FLDZ", "FMUL", "FIMUL", "FPREM", "FSCALE", "FST", "FSTP",
- "FSTCW", "FSTSW", "FSUB", "FISUB", "FTST", "FXCH", "FWAIT"
- };
- /*
- * Register a fixup
- */
- /* Put an opcode
- */
- void putop(int op)
- {
- if (op > op_fwait)
- diag("illegal opcode.");
- else
- fprintf(tempfil,"\t%s",oplst[op]);
- }
-
- void putconst(ENODE *offset)
- /*
- * put a constant to the tempfil file.
- */
- { switch( offset->nodetype )
- {
- case en_autoreg:
- case en_autocon:
- case en_icon:
- case en_acon:
- fprintf(tempfil,"0%lXH",offset->v.i);
- break;
- case en_rcon:
- fprintf(tempfil,"%f",offset->v.f);
- break;
- case en_nalabcon:
- fprintf(tempfil,"L_%d",offset->v.i);
- break;
- case en_labcon:
- fprintf(tempfil,"CS:L_%d",offset->v.i);
- break;
- case en_napccon:
- case en_nacon:
- fprintf(tempfil,"%s",offset->v.p[0]);
- break;
- case en_add:
- putconst(offset->v.p[0]);
- fprintf(tempfil,"+");
- putconst(offset->v.p[1]);
- break;
- case en_sub:
- putconst(offset->v.p[0]);
- fprintf(tempfil,"-");
- putconst(offset->v.p[1]);
- break;
- case en_uminus:
- fprintf(tempfil,"-");
- putconst(offset->v.p[0]);
- break;
- default:
- diag("illegal constant node.");
- break;
- }
- }
- void putlen(int l)
- /*
- * append the length field to an instruction.
- */
- {
- if (l!= 10 && l != 8 && l != 6 && l != 4 && l != 1 && l != 2 && l != 0)
- diag("illegal length field.");
- }
- void putsizedreg(char *string, int reg, int size)
- {
- static char *byteregs[] = { "AL","CL","DL","BL","*A","*C","*D","*B" };
- static char *wordregs[] = { "AX", "CX", "DX","BX","SP","BP","SI","DI" };
- static char *longregs[] = { "EAX", "ECX", "EDX","EBX","ESP","EBP","ESI","EDI" };
- if (size == 4)
- fprintf(tempfil,string,longregs[reg]);
- else if (size == 1)
- fprintf(tempfil,string,byteregs[reg]);
- else
- fprintf(tempfil,string,wordregs[reg]);
- }
- void pointersize(int size)
- {
- // if (needpointer)
- switch (size) {
- case 10:
- fprintf(tempfil,"TWORD PTR ");
- break;
- case 8:
- fprintf(tempfil,"QWORD PTR ");
- break;
- case 6:
- case 4:
- fprintf(tempfil,"DWORD PTR ");
- break;
- case 2:
- fprintf(tempfil,"WORD PTR ");
- break;
- case 1:
- fprintf(tempfil,"BYTE PTR ");
- break;
- default:
- diag("Bad pointer");
- }
- }
- void putamode(AMODE *ap,int size)
- /*
- * tempfil a general addressing mode.
- */
- { switch( ap->mode )
- {
- case am_cs:
- fprintf(tempfil,"CS");
- break;
- case am_immed:
- if (size && (ap->offset->nodetype == en_labcon
- || ap->offset->nodetype == en_nacon
- || ap->offset->nodetype == en_napccon
- || ap->offset->nodetype == en_nalabcon))
- fprintf(tempfil,"OFFSET ");
- putconst(ap->offset);
- break;
- case am_direct:
- pointersize(size);
- fputc('[',tempfil);
- putconst(ap->offset);
- fputc(']',tempfil);
- break;
- case am_dreg:
- putsizedreg("%s",ap->preg,size);
- break;
- case am_freg:
- fprintf(tempfil,"ST(%d)",ap->preg);
- break;
- case am_indisp:
- pointersize(size);
- putsizedreg("[%s",ap->preg,4);
- if (ap->offset) {
- fputc('+',tempfil);
- putconst(ap->offset);
- }
- fputc(']',tempfil);
- break;
- case am_indispscale:
- pointersize(size);
- putsizedreg("[%s+",ap->preg,4);
- putsizedreg("%s",ap->sreg,4);
- if (ap->scale != 1)
- fprintf(tempfil,"*0%XH",ap->scale);
- if (ap->offset) {
- fputc('+',tempfil);
- putconst(ap->offset);
- }
- fputc(']',tempfil);
- break;
- default:
- diag("illegal address mode.");
- break;
- }
- }
-
- void put_code(int op,int len,int len2,AMODE *aps,AMODE *apd)
- /*
- * tempfil a generic instruction.
- */
- {
- if (!prm_asmfile)
- return;
- if (op == op_line) {
- if (!prm_lines)
- return;
- fprintf(tempfil,";\n; Line %d:\t%s\n;\n",len,(char *)aps);
- return;
- }
- needpointer = (len != len2) || ((!aps || aps->mode !=am_dreg) && (!apd || apd->mode !=am_dreg));
- putop(op);
- putlen(len);
- if( aps != 0 )
- {
- fprintf(tempfil,"\t");
- putamode(aps,len);
- if( apd != 0 )
- {
- fprintf(tempfil,",");
- putamode(apd,len2);
- }
- }
- fprintf(tempfil,"\n");
- }
-
- void gen_strlab(char *s)
- /*
- * generate a named label.
- */
- {
- if (prm_asmfile)
- if (curseg == dataseg || curseg == bssxseg) {
- newlabel = TRUE;
- fprintf(tempfil,"\n%s",s);
- outcol = strlen(s)+1;
- }
- else
- fprintf(tempfil,"%s:\n",s);
- }
-
- void put_label(int lab)
- /*
- * tempfil a compiler generated label.
- */
- {
- if (prm_asmfile)
- fprintf(tempfil,"L_%d:\n",lab);
- }
-
- void genfloat(float val)
- /*
- * Output a float value
- */
- { if (prm_asmfile)
- if( gentype == floatgen && outcol < 60) {
- fprintf(tempfil,",%f",val);
- outcol += 8;
- }
- else {
- if (!newlabel)
- nl();
- else newlabel = FALSE;
- fprintf(tempfil,"\tDD\t%f",val);
- gentype = floatgen;
- outcol = 19;
- }
- }
-
- void gendouble(double val)
- /*
- * Output a double value
- */
- { if (prm_asmfile)
- if( gentype == doublegen && outcol < 60) {
- fprintf(tempfil,",%f",val);
- outcol += 8;
- }
- else {
- if (!newlabel)
- nl();
- else newlabel = FALSE;
- fprintf(tempfil,"\tDQ\t%f",val);
- gentype = doublegen;
- outcol = 19;
- }
- }
- void genlongdouble(double val)
- /*
- * Output a double value
- */
- { if (prm_asmfile)
- if( gentype == longdoublegen && outcol < 60) {
- fprintf(tempfil,",%f",val);
- outcol += 8;
- }
- else {
- if (!newlabel)
- nl();
- else newlabel = FALSE;
- fprintf(tempfil,"\tDT\t%f",val);
- gentype = longdoublegen;
- outcol = 19;
- }
- }
-
- void genbyte(long val)
- /*
- * Output a byte value
- */
- { if (prm_asmfile)
- if( gentype == bytegen && outcol < 60) {
- fprintf(tempfil,",0%XH",val & 0x00ff);
- outcol += 4;
- }
- else {
- if (!newlabel)
- nl();
- else newlabel = FALSE;
- fprintf(tempfil,"\tDB\t0%XH",val & 0x00ff);
- gentype = bytegen;
- outcol = 19;
- }
- }
-
- void genword(long val)
- /*
- * Output a word value
- */
- { if (prm_asmfile)
- if( gentype == wordgen && outcol < 58) {
- fprintf(tempfil,",0%XH",val & 0x0ffff);
- outcol += 6;
- }
- else {
- if (!newlabel)
- nl();
- else newlabel = FALSE;
- fprintf(tempfil,"\tDW\t0%XH",val & 0x0ffff);
- gentype = wordgen;
- outcol = 21;
- }
- }
-
- void genlong(long val)
- /*
- * Output a long value
- */
- { if (prm_asmfile)
- if( gentype == longgen && outcol < 56) {
- fprintf(tempfil,",0%lXH",val);
- outcol += 10;
- }
- else {
- if (!newlabel)
- nl();
- else newlabel = FALSE;
- fprintf(tempfil,"\tDD\t0%lXH",val);
- gentype = longgen;
- outcol = 25;
- }
- }
-
- void gensrref(char *name, int val)
- {
- if (prm_asmfile)
- if( gentype == srrefgen && outcol < 56) {
- fprintf(tempfil,",%s,%d",name,val);
- outcol += strlen(name)+1;
- }
- else {
- nl();
- fprintf(tempfil,"\tDD\t%s,%d",name,val);
- gentype = srrefgen;
- outcol = 25;
- }
- }
- void genref(SYM *sp,int offset)
- /*
- * Output a reference to the data area (also gens fixups )
- */
- { char sign;
- char buf[40];
- if( offset < 0) {
- sign = '-';
- offset = -offset;
- }
- else
- sign = '+';
- if (sp->storage_class == sc_static)
- sprintf(buf,"L_%d%c%d",sp->value.i,sign,offset);
- else
- sprintf(buf,"%s%c%d",sp->name,sign,offset);
- if (prm_asmfile) {
- if( gentype == longgen && outcol < 55 - strlen(sp->name)) {
- fprintf(tempfil,",%s",buf);
- outcol += (11 + strlen(sp->name));
- }
- else {
- if (!newlabel)
- nl();
- else newlabel = FALSE;
- fprintf(tempfil,"\tDD\t%s",buf);
- outcol = 26 + strlen(sp->name);
- gentype = longgen;
- }
- }
- }
- void genpcref(SYM *sp,int offset)
- /*
- * Output a reference to the code area (also gens fixups )
- */
- {
- genref(sp,offset);
- }
- void genstorage(int nbytes)
- /*
- * Output bytes of storage
- */
- { if (prm_asmfile) {
- if (!newlabel)
- nl();
- else newlabel = FALSE;
- fprintf(tempfil,"\tDB\t0%XH DUP (?)",nbytes);
- outcol = 28;
- gentype = storagegen;
- }
- }
-
- void gen_labref(int n)
- /*
- * Generate a reference to a label
- */
- { if (prm_asmfile)
- if( gentype == longgen && outcol < 58) {
- fprintf(tempfil,",L_%d",n);
- outcol += 6;
- }
- else {
- if (!newlabel)
- nl();
- else newlabel = FALSE;
- fprintf(tempfil,"\tDD\tL_%d",n);
- outcol = 22;
- gentype = longgen;
- }
- }
-
- int stringlit(char *s)
- /*
- * make s a string literal and return it's label number.
- */
- { struct slit *lp;
- ++global_flag; /* always allocate from global space. */
- lp = xalloc(sizeof(struct slit));
- lp->label = nextlabel++;
- lp->str = litlate(s);
- lp->next = strtab;
- strtab = lp;
- --global_flag;
- return lp->label;
- }
-
- void dumplits(void)
- /*
- * dump the string literal pool.
- */
- { char *cp;
- while( strtab != 0) {
- cseg();
- nl();
- put_label(strtab->label);
- cp = strtab->str;
- while(*cp)
- genbyte(*cp++);
- genbyte(0);
- strtab = strtab->next;
- }
- nl();
- }
-
- void nl(void)
- /*
- * New line
- */
- { if (prm_asmfile) {
- if(outcol > 0) {
- fputc('\n',tempfil);
- outcol = 0;
- gentype = nogen;
- }
- if (phiused && !phiput)
- fputc(0x1f,outputFile);
- }
- }
- /*
- * Exit if from a special segment
- */
- void exitseg(void)
- {
- if (curseg == startupxseg) {
- curseg = noseg;
- fprintf(tempfil,"cstartup\tENDS\n");
- }
- else if (curseg == rundownxseg) {
- curseg = noseg;
- fprintf(tempfil,"crundown\tENDS\n");
- }
- else if (curseg == cppxseg) {
- curseg = noseg;
- fprintf(tempfil,"cppinit\tENDS\n");
- }
- }
- /*
- * Switch to cseg
- */
- void cseg(void)
- { if (prm_asmfile)
- if( curseg != codeseg) {
- nl();
- exitseg();
- fprintf(tempfil,"\t.CODE\n");
- curseg = codeseg;
- }
- }
- /*
- * Switch to deseg
- */
- void dseg(void)
- { if (prm_asmfile)
- if( curseg != dataseg) {
- nl();
- exitseg();
- fprintf(tempfil,"\t.DATA\n");
- curseg = dataseg;
- }
- }
- /*
- * Switch to bssseg
- */
- void bssseg(void)
- { if (prm_asmfile)
- if( curseg != bssxseg) {
- nl();
- exitseg();
- fprintf(tempfil,"\t.DATA?\n");
- curseg = bssxseg;
- }
- }
- /*
- * Switch to startupseg
- */
- void startupseg(void)
- { if (prm_asmfile)
- if( curseg != startupxseg) {
- nl();
- exitseg();
- fprintf(tempfil,"cstartup\tSEGMENT USE32 PUBLIC DWORD \042INITDATA\042\n");
- curseg = startupxseg;
- }
- }
- /*
- * Switch to rundownseg
- */
- void rundownseg(void)
- { if (prm_asmfile)
- if( curseg != rundownxseg) {
- nl();
- exitseg();
- fprintf(tempfil,"crundown\tSEGMENT USE32 PUBLIC DWORD \042EXITDATA\042\n");
- curseg = rundownxseg;
- }
- }
- void cppseg(void)
- { if (prm_asmfile)
- if( curseg != cppxseg) {
- nl();
- exitseg();
- fprintf(tempfil,"cppinit\tSEGMENT USE32 PUBLIC DWORD \042CPPDATA\042\n");
- curseg = cppxseg;
- }
- }
- void gen_virtual(char *name)
- {
- if (prm_asmfile) {
- nl();
- fprintf(tempfil,"@%s\tSEGMENT VIRTUAL",name);
- }
- }
- void gen_endvirtual(char *name)
- {
- if (prm_asmfile) {
- nl();
- fprintf(tempfil,"@%s\tENDS",name);
- }
- }
- /*
- * Align
- */
- void align(int size)
- {
- if (prm_asmfile) {
- nl();
- fprintf(tempfil,"\tALIGN\t%d\n",4);
- }
- }
- /* muldiv val init
- */
- void init_muldivval(void)
- {
- muldivlink = 0;
- }
- /*
- * queue muldiv val
- */
- void queue_muldivval(int label, long number)
- {
- MULDIV *p = xalloc(sizeof(MULDIV));
- p->link = muldivlink;
- p->value = number;
- p->label = label;
- p->size = 0;
- muldivlink = p;
- }
- void queue_floatval(int label, double number, int size)
- {
- MULDIV *p = xalloc(sizeof(MULDIV));
- p->link = muldivlink;
- p->floatvalue = number;
- p->label = label;
- p->size = size;
- muldivlink = p;
- }
- void dump_muldivval(void)
- {
- int tag = FALSE;
- if (prm_asmfile) {
- fprintf(tempfil,"\n");
- if (muldivlink) {
- tag = TRUE;
- align(4);
- }
- while (muldivlink) {
- put_label(muldivlink->label);
- if (muldivlink->size == 0)
- fprintf(tempfil,"\tDD\t0%xH\n",muldivlink->value);
- else if (muldivlink->size == 6)
- fprintf(tempfil,"\tDD\t%f\n",muldivlink->floatvalue);
- else
- fprintf(tempfil,"\tDQ\t%f\n",muldivlink->floatvalue);
- muldivlink = muldivlink->link;
- }
- if (tag)
- fprintf(tempfil,"\n");
- }
- }
-
- void putexterns(void)
- /*
- * Output the fixup tables and the global/external list
- */
- { SYM *sp;
- int i;
- if (prm_asmfile){
- nl();
- exitseg();
- fprintf(outputFile,"\t.386\n\t.MODEL SMALL\n\n");
- for (i=0; i < HASHTABLESIZE; i++) {
- if ((sp=(SYM *) globalhash[i]) != 0) {
- while (sp) {
- if( sp->storage_class == sc_external && sp->extflag)
- fprintf(outputFile,"\tEXTRN\t%s\n",sp->name);
- else if( sp->storage_class == sc_externalfunc && sp->extflag)
- fprintf(outputFile,"\tEXTRN\t%s:PROC\n",sp->name);
- else if( sp->storage_class == sc_global )
- fprintf(outputFile,"\tPUBLIC\t%s\n",sp->name);
- sp = sp->next;
- }
- }
- }
- rewind(tempfil);
- while (!feof(tempfil)) {
- char buf[256];
- buf[0] = 0;
- fgets(buf,256,tempfil);
- fputs(buf,outputFile);
- }
- fprintf(outputFile,"\tEND\n");
- }
- }