home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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 <stdio.h>
- #include <ctype.h>
- #include <dtable.h>
- #include <os.h>
- #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, 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;
- bail("Out of memory! Can't expand code.");
- }
-
- #define LST if (lstfile) lst
-
- void lst(opcode,text) char *text;
- {
- if (lstfile)
- fprintf(lstfile,"%5u: %-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)
- {
- case PUSHTOKEN:
- {
- int j;
-
- 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))
- bail("Out of memory! Can't expand forward ref label table.");
-
- 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 *save_string();
-
- 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))
- bail("Out of memory! Can't expand string table.");
-
- soffset += (1 + strlen(string));
- string_table.table[strings].token = soffset;
- if (save) string = save_string(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 get_pgm();
-
- 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.");
-
- unpgm_table.table[unpgms].name = save_string(name);
-
- 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 = get_pgm(pgm->name)))
- pgm->offset = add_string(pgm->name,FALSE);
- }
-
- /* ******************************************************************** */
- /* *********************** Call Unknown 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))
- bail("Out of memory! Can't expand function address table.");
-
- 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;
- {
- extern int num_lines_read; /* in token.c */
-
- fprintf(fptr, "\n");
- 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);
- fprintf(fptr,"Number of programs: %d.\n",pgms());
- fprintf(fptr,"Number of global variables: %d (%d bytes).\n",
- num_global_vars(), gvspace());
- fprintf(fptr,"Number of global objects: %d.\n",num_global_objects());
- fprintf(fptr,"Number of constants: %d.\n",number_of_consts());
- fprintf(fptr,"Number of source lines read: %d.\n",num_lines_read);
- fprintf(fptr, "\n");
- }
-
- /* ******************************************************************* */
- /* ********************* 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 */
- {
- print_entry_points(lstfile);
- print_global_vars(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) return 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,"bool"); 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,"small-int"); break;
- case INT32: strcat(str,"int"); break;
- }
- if (*str == '\0') strcpy(str,"*BOGUS*");
- return str;
- }
-