/* * code.c : code generation for MC2 */ /* Copyright 1990, 1991, 1992 Craig Durland * Distributed under the terms of the GNU General Public License. * Distributed "as is", without warranties of any kind, but comments, * suggestions and bug reports are welcome. */ #include #include #include #include #include "mm.h" #include "mc.h" #define OPNAMES 1 #include "opcode.h" /* ******************************************************************** */ /* ****************** Initialize the Code Generator ******************* */ /* ******************************************************************** */ static int add_string(); static void gennum8(); /* Put a HALT at address 0. This will stop any programs that that have * somehow successfully compiled with unresolved jump addresses (which * are 0). * The real reason is to increment the PC. I don't want code at address * 0 because I'm using that to indicate an unresolved address. Kinda * slimey but its only 1 wasted byte. */ void init_code_generater() { gennum8(HALT); } /* ******************************************************************** */ /* ***************** code generation ********************************** */ /* ******************************************************************** */ extern address getlabel(); extern char ebuf[], *spoof(), *typename(); extern FILE *lstfile; /* in mc.c */ extern MuttCmd muttcmds[]; extern oMuttCmd omuttcmds[]; extern int xtn, msize, omsize; extern void addfref(); static void call_unknown_pgm(); address entrypt = 0; /* address of HALT */ static address pc = 0; /* Somebody puts a HALT here */ static declare_and_init_dTable(compiled_code,uint8); address pcaddr() { return pc; } unsigned int codesize() { return pc; } static void codger(n) { if (xpand_dTable(&compiled_code, n, 8192, 4096)) return; printf("Out of memory! Can't expand code.\n"); exit(1); } #define LST if (lstfile) lst void lst(opcode,text) char *text; { if (lstfile) fprintf(lstfile,"%4u: %-15s %s\n",pc,opname[opcode],text); } #define GENNUM8(n) compiled_code.table[pc++] = (n) static void gennum8(n) { codger(1); GENNUM8(n); } static void gennum16(n) { codger(2); PUT_INT16(&compiled_code.table[pc],n); pc += sizeof(int16); } static void gennum32(n) int32 n; { codger(4); PUT_INT32(&compiled_code.table[pc],n); pc += sizeof(int32); } #define GENADDR(pc,addr) \ PUT_INT16(&compiled_code.table[pc],(int16)((addr) -(pc) +1)) static void genaddr(addr,jmpaddr) address addr, jmpaddr; { codger(2); GENADDR(addr,jmpaddr); pc += sizeof(int16); } void goaddr(opcode,addr,msg) char *msg; address addr; { LST(opcode,spoof(ebuf,"%d (%s)",addr,msg)); gennum8(opcode); genaddr(pc,addr); } void gojmp(opcode,label) { int n; LST(opcode,spoof(ebuf,"L%d",label)); gennum8(opcode); if ((n = getlabel(label)) == NIL) addfref(pc,label); genaddr(pc,n); } void genop(opcode) { LST(opcode,""); gennum8(opcode); } void gostr(opcode,string) char *string; { int offset; if (lstfile) { unsigned char *ptr = (unsigned char *)string; char *qtr = ebuf; *qtr++ = '"'; while (*ptr) { if (iscntrl(*ptr)) { *qtr++ = '^'; *qtr++ = *ptr +0x40; } else *qtr++ = *ptr; ptr++; } *qtr++ = '"'; *qtr = '\0'; lst(opcode,ebuf); } switch (opcode) { case RVSTR: offset = add_string(string,TRUE); break; case PUSHNAME: offset = NIL; call_unknown_pgm(string); break; default: bitch("Unknown opcode to gostr()"); } gennum8(opcode); gennum16(offset); } void gonum8(opcode,n) { if (lstfile) { switch(opcode) { case RVBOOL: lst(opcode,n ? "TRUE" : "FALSE"); break; case TYPECHECK: case GETRVAR: case SETRVAR: lst(opcode,typename(n)); break; default: lst(opcode,spoof(ebuf,"%d",n)); } } gennum8(opcode); gennum8(n); } void gonum16(opcode,n) { extern char *lookup_ext_token_by_value(); /* in token.c */ if (lstfile) { switch(opcode) { int j; case PUSHTOKEN: for (j = 0; j < omsize; j++) if (omuttcmds[j].token == n) break; lst(opcode,spoof(ebuf,"%s (%d)",omuttcmds[j].name,n)); break; case PUSHXT: lst(opcode,spoof(ebuf,"%s (%d)",lookup_ext_token_by_value(n), n)); break; default: lst(opcode,spoof(ebuf,"%d",n)); } } gennum8(opcode); gennum16(n); } void gonumx(n) int32 n; { unsigned int opcode, type; int16 z = n; if (0 <= n && n < 128) { type = INT8; opcode = RVNUM8; } else if (n == z) { type = INT16; opcode = RVNUM16; } else { type = INT32; opcode = RVNUM32; } lst(opcode,spoof(ebuf,"%ld (%s)",n,typename(type))); gennum8(opcode); switch (type) { case INT8: gennum8((int)n); break; case INT16: gennum16((int)z); break; case INT32: gennum32(n); break; } } void go2num(opcode,n1,n2) { LST(opcode,spoof(ebuf,"%d (%s)",n2,typename(n1))); gennum8(opcode); gennum8(n1); gennum16(n2); } void genobj(opcode, scope, type, offset) { scope = (scope == GLOBAL); /* 1 or 0 for MM */ lst(opcode,spoof(ebuf,"%s %s %d", scope ? "global" : "local", typename(type), offset)); if (type == STRING) type = OSTRING; gennum8(opcode); gennum8(scope); gennum8(type); gennum16(offset); } /* ******************************************************************** */ /* ******************* link phase ************************************* */ /* ******************************************************************** */ static void label_fixup(), resolve_UnPgms(), link_pgms(), link_fas(); void link() { label_fixup(); resolve_UnPgms(); link_pgms(); link_fas(); } /* ******************************************************************** */ /* ***************** Forward referenced labels ************************ */ /* ******************************************************************** */ typedef struct { address addr; int label; } FRlabel; static int frlabels = 0; static declare_and_init_dTable(frlabel_table, FRlabel); void addfref(addr,label) address addr; { if (!xpand_dTable(&frlabel_table, 1, 100,100)) { printf("Out of memory! Can't expand forward ref label table.\n"); exit(1); } frlabel_table.table[frlabels].addr = addr; frlabel_table.table[frlabels].label = label; frlabels++; } static void label_fixup() { register int j; register address addr, pc; for (j = 0; j < frlabels; j++) { pc = frlabel_table.table[j].addr; addr = getlabel(frlabel_table.table[j].label); GENADDR(pc,addr); } } /* ******************************************************************** */ /* ***************** Strings ****************************************** */ /* ******************************************************************** */ extern char *savestr(); static declare_and_init_dTable(string_table, MuttCmd); static int strings = 0, soffset = 0, srepeats = 0; static int add_string(string,save) char *string; { register int j; register MuttCmd *ptr; for (j = strings, ptr = string_table.table; j--; ptr++) if (0 == strcmp(string,ptr->name)) { srepeats++; return ptr->token; } if (!xpand_dTable(&string_table, 1, 100,50)) { printf("Out of memory! Can't expand string table.\n"); exit(1); } soffset += (1 + strlen(string)); string_table.table[strings].token = soffset; if (save && (string = savestr(string)) == NULL) bail("Can't save string."); string_table.table[strings].name = string; strings++; return soffset; } static void dump_strings(fptr) FILE *fptr; { register int j; register MuttCmd *ptr; for (j = strings, ptr = &string_table.table[j-1]; j--; ptr--) fwrite(ptr->name,1,1+strlen(ptr->name),fptr); } static int strings_size() { return soffset; } /* ******************************************************************** */ /* ************************* Unknown Programs ************************* */ /* ******************************************************************** */ extern address getpgm(); typedef struct { char *name; address addr; int offset; } UnPgm; static declare_and_init_dTable(unpgm_table, UnPgm); static int unpgms = 0, pfrefs = 0; static int add_UnPgm(name) register char *name; { register int j; pfrefs++; /* another forward program reference */ for (j = 0; j < unpgms; j++) /* check to see if name already in table */ if (0 == strcmp(name,unpgm_table.table[j].name)) return j; if (!xpand_dTable(&unpgm_table, 1, 50,25)) bail("Out of memory! Can't expand unknown program table."); if (NULL == (unpgm_table.table[unpgms].name = savestr(name))) bail("Can't save unpgm."); return unpgms++; } /* Find the address of the unknown programs. If a program is still * unknown, add its name to the string table so it can be used for * runtime lookups. */ static void resolve_UnPgms() { register UnPgm *pgm; register int j; for (j = unpgms, pgm = unpgm_table.table; j--; pgm++) if (NIL == (pgm->addr = getpgm(pgm->name))) pgm->offset = add_string(pgm->name,FALSE); } /* ******************************************************************** */ /* *********************** Call Unknow Program ************************ */ /* ******************************************************************** */ typedef struct { int unpgm; address addr; } LinkTable; static declare_and_init_dTable(pgm_link_table, LinkTable); static int pgm_unlinked = 0, pgm_unresolved = 0; static void call_unknown_pgm(name) register char *name; { if (!xpand_dTable(&pgm_link_table, 1, 50,50)) bail("Out of memory! Can't expand unknown program link table."); pgm_link_table.table[pgm_unlinked].unpgm = add_UnPgm(name); pgm_link_table.table[pgm_unlinked].addr = pc; pgm_unlinked++; } /* Assumes: resolve_UnPgms() has been called. */ static void link_pgms() { address addr, pc; register LinkTable *ltr; register UnPgm *pgm; register int j, offset; for (j = pgm_unlinked, ltr = pgm_link_table.table; j--; ltr++) { pgm = &unpgm_table.table[ltr->unpgm]; pc = ltr->addr; if ((addr = pgm->addr) != NIL) /* resolved */ { GENNUM8(PUSHADDR); GENADDR(pc,addr); } else /* unresolved */ { pgm_unresolved++; GENNUM8(PUSHNAME); offset = pgm->offset; PUT_INT16(&compiled_code.table[pc],offset); } } } /* ******************************************************************** */ /* ************** Function addresses ********************************** */ /* ******************************************************************** */ static declare_and_init_dTable(fa_link_table, LinkTable); static int fa_unlinked = 0; /* gen a fcn address */ void genfa(addr,name) address addr; char *name; { lst(FADDR,spoof(ebuf,"%s: %d (%s)",opname[PUSHADDR],addr,name)); gennum8(FADDR); gennum8(OPADDRESS); if (addr == NIL) /* probably a forward reference */ { if (!xpand_dTable(&fa_link_table, 1, 10,5)) { printf("Out of memory! Can't expand function address table.\n"); exit(1); } fa_link_table.table[fa_unlinked].unpgm = add_UnPgm(name); fa_link_table.table[fa_unlinked].addr = pc; fa_unlinked++; } genaddr(pc,addr); } /* gen a fcn pointer */ void genfp(opcode,n,name) char *name; { switch (opcode) { case OPTOKEN: case OPXTOKEN: lst(FADDR,spoof(ebuf,"%s: %d (%s)", opname[(opcode == OPTOKEN) ? PUSHTOKEN : PUSHXT],n,name)); gennum8(FADDR); gennum8(opcode); gennum16(n); break; case OPNAME: lst(FADDR,opname[PUSHNAME]); gennum8(FADDR); gennum8(opcode); break; } } /* Assumes: resolve_UnPgms() has been called. */ static void link_fas() { address addr, pc; register LinkTable *ltr; register UnPgm *pgm; register int j; for (j = fa_unlinked, ltr = fa_link_table.table; j--; ltr++) { pgm = &unpgm_table.table[ltr->unpgm]; pc = ltr->addr; if ((addr = pgm->addr) != NIL) GENADDR(pc,addr); /* resolved */ else /* unresolved */ moan(spoof(ebuf, "(floc %s): \"%s\" not defined in this file.",pgm->name,pgm->name)); } } /* ******************************************************************* */ /* ********************* Stats *************************************** */ /* ******************************************************************* */ void dump_stats(fptr) FILE *fptr; { fprintf(fptr,"%d strings totaling %d bytes, %d repeats.\n", strings,strings_size(),srepeats); fprintf(fptr, "Unresolved function calls: %d (of %d forward references, %d unique).\n", pgm_unresolved, pfrefs, unpgms); fprintf(fptr,"Forward referenced labels: %d.\n",frlabels); } /* ******************************************************************* */ /* ********************* Dump the code ******************************* */ /* ******************************************************************* */ address pgmaddr(); char *pgmname(), *vname(); unsigned int vtype(); void dumpcode(fname) char *fname; { extern int errors; /* in mc.c */ address a; char buf[90]; FILE *fptr; uint8 bytes[50]; /* enough to hold the header and an address */ int j, z; int16 n,pgmn = pgms(); unsigned int size, code_size; link(); /* !!! should really check for errors better */ if (errors) return; if (lstfile) /* finish off the .lst file */ { /* show entry points */ fputs("\n PGM table\nADDRESS NAME\n",lstfile); fprintf(lstfile," %4d entry point\n",entrypt); for (j = 0; j < pgmn; j++) fprintf(lstfile," %4d %s\n",pgmaddr(j),pgmname(j)); /* global vars */ z = num_global_vars(); if (z == 0) fputs("\nNo global variables.\n",lstfile); else { fputs("\n Global Variables\nNAME OFFSET TYPE\n", lstfile); for (j = 0; j < z; j++) /* global vars */ fprintf(lstfile,"%-20s %5d %s\n", vname(j),voffset(j),typename(vtype(j))); } fputc('\n',lstfile); dump_stats(lstfile); } new_ext(buf,fname,".mco"); if ((fptr = fopen(buf,"wb")) == NULL) bail("Can't open output file"); /* figure out the size of the pgm name table */ for (j = n = z = 0; j < pgmn; j++) if ((pgmflags(j) & HIDDEN) == 0) { n++; z += strlen(pgmname(j)) +1; } /* entry point is offset from start of code */ PUT_ADDRESS(&bytes[H_ENTRY_POINT],entrypt); code_size = codesize(); size = code_size +strings_size() +z; PUT_UINT16(&bytes[H_BYTES_OF_CODE],size); PUT_UINT16(&bytes[H_NAME_TABLE_OFFSET],code_size); PUT_INT16 (&bytes[H_NUMBER_OF_PGMS],n); z = gvspace(); PUT_UINT16(&bytes[H_BYTES_OF_GVARS],z); PUT_UINT8(&bytes[H_MAGIC_NUMBER],MM_MAGIC_NUMBER); PUT_UINT16(&bytes[H_NUM_GLOBAL_OBJECTS],num_global_objects()); fwrite((char *)bytes,1,BYTES_IN_HEADER,fptr); /* write out header */ fwrite(compiled_code.table,1,codesize(),fptr); /* dump the code */ for (j = 0; j < pgmn; j++) /* dump the name table */ if ((pgmflags(j) & HIDDEN) == 0) fwrite(pgmname(j),1,strlen(pgmname(j))+1,fptr); dump_strings(fptr); for (j = 0; j < pgmn; j++) /* dump the pgm addresses */ if ((pgmflags(j) & HIDDEN) == 0) { a = pgmaddr(j); PUT_ADDRESS(bytes,a); fwrite((char *)bytes,sizeof(address),1,fptr); } fclose(fptr); } /* ******************************************************************** */ /* ******************************************************************** */ /* ******************************************************************** */ extern char *strcpy(), *strcat(); char *typename(type) unsigned int type; { static char str[50]; int z = type & 0xFF; *str = '\0'; if (type == ARRAY) strcat(str,"ARRAY"); if (type & POINTER) strcat(str,"POINTER to "); if ((type & 0x80) == 0) /* not a subtype */ switch (z) { case BLOB: strcat(str,"BLOB"); break; case FCNPTR: strcat(str,"POINTER to FCN"); break; case VOID: strcat(str,"VOID"); break; case STRING: strcat(str,"STRING"); break; case NUMBER: strcat(str,"NUMBER"); break; case BOOLEAN: strcat(str,"BOOLEAN"); break; case REAL: strcat(str,"REAL"); break; case LIST: strcat(str,"LIST"); break; } if (type & 0x80) /* a subtype */ switch (z) { case INT8: strcat(str,"byte"); break; case INT16: strcat(str,"int"); break; case INT32: strcat(str,"INT"); break; } if (*str == '\0') strcpy(str,"*BOGUS*"); return str; }