home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / me34src.zip / me3 / mc / code.c next >
C/C++ Source or Header  |  1995-01-14  |  16KB  |  581 lines

  1. /*
  2.  * code.c : code generation for MC2
  3.  */
  4.  
  5. /* Copyright 1990, 1991, 1992 Craig Durland
  6.  *   Distributed under the terms of the GNU General Public License.
  7.  *   Distributed "as is", without warranties of any kind, but comments,
  8.  *     suggestions and bug reports are welcome.
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <ctype.h>
  13. #include <dtable.h>
  14. #include <os.h>
  15. #include "mm.h"
  16. #include "mc.h"
  17.  
  18. #define OPNAMES 1
  19. #include "opcode.h"
  20.  
  21. /* ******************************************************************** */
  22. /* ****************** Initialize the Code Generator ******************* */
  23. /* ******************************************************************** */
  24.  
  25. static int add_string();
  26. static void gennum8();
  27.  
  28.     /* Put a HALT at address 0.  This will stop any programs that that have
  29.      *   somehow successfully compiled with unresolved jump addresses (which
  30.      *   are 0).
  31.      * The real reason is to increment the PC.  I don't want code at address
  32.      *   0 because I'm using that to indicate an unresolved address.  Kinda
  33.      *   slimey but its only 1 wasted byte.
  34.      */
  35. void init_code_generater()
  36. {
  37.   gennum8(HALT);
  38. }
  39.  
  40. /* ******************************************************************** */
  41. /* ***************** code generation ********************************** */
  42. /* ******************************************************************** */
  43.  
  44. extern address getlabel();
  45. extern char ebuf[], *spoof(), *typename();
  46. extern FILE *lstfile;            /* in mc.c */
  47. extern MuttCmd muttcmds[];
  48. extern oMuttCmd omuttcmds[];
  49. extern int xtn, omsize;
  50. extern void addfref();
  51.  
  52. static void call_unknown_pgm();
  53.  
  54. address entrypt = 0;        /* address of HALT */
  55. static address pc = 0;        /* Somebody puts a HALT here */
  56.  
  57. static declare_and_init_dTable(compiled_code,uint8);
  58.  
  59. address pcaddr() { return pc; }
  60.  
  61. unsigned int codesize() { return pc; }
  62.  
  63. static void codger(n)
  64. {
  65.   if (xpand_dTable(&compiled_code, n, 8192, 4096)) return;
  66.   bail("Out of memory! Can't expand code.");
  67. }
  68.  
  69. #define LST if (lstfile) lst
  70.  
  71. void lst(opcode,text) char *text;
  72. {
  73.   if (lstfile)
  74.     fprintf(lstfile,"%5u:     %-15s %s\n",pc,opname[opcode],text);
  75. }
  76.  
  77. #define GENNUM8(n) compiled_code.table[pc++] = (n)
  78.  
  79. static void gennum8(n) { codger(1); GENNUM8(n); }
  80.  
  81. static void gennum16(n)
  82.   { codger(2); PUT_INT16(&compiled_code.table[pc],n);  pc += sizeof(int16); }
  83.  
  84. static void gennum32(n) int32 n;
  85.   { codger(4); PUT_INT32(&compiled_code.table[pc],n);  pc += sizeof(int32); }
  86.  
  87. #define GENADDR(pc,addr) \
  88.     PUT_INT16(&compiled_code.table[pc],(int16)((addr) -(pc) +1))
  89.  
  90. static void genaddr(addr,jmpaddr) address addr, jmpaddr;
  91.   { codger(2); GENADDR(addr,jmpaddr); pc += sizeof(int16); }
  92.  
  93. void goaddr(opcode,addr,msg) char *msg; address addr;
  94. {
  95.   LST(opcode,spoof(ebuf,"%d (%s)",addr,msg));
  96.   gennum8(opcode); genaddr(pc,addr);
  97. }
  98.  
  99. void gojmp(opcode,label)
  100. {
  101.   int n;
  102.  
  103.   LST(opcode,spoof(ebuf,"L%d",label));
  104.   gennum8(opcode);
  105.   if ((n = getlabel(label)) == NIL) addfref(pc,label);
  106.   genaddr(pc,n);
  107. }
  108.  
  109. void genop(opcode) { LST(opcode,""); gennum8(opcode); }
  110.  
  111. void gostr(opcode,string) char *string;
  112. {
  113.   int offset;
  114.  
  115.   if (lstfile)
  116.   {
  117.     unsigned char *ptr = (unsigned char *)string;
  118.     char *qtr = ebuf;
  119.     *qtr++ = '"';
  120.     while (*ptr)
  121.     {
  122.       if (iscntrl(*ptr)) { *qtr++ = '^'; *qtr++ = *ptr +0x40; }
  123.       else *qtr++ = *ptr;
  124.       ptr++;
  125.     }
  126.     *qtr++ = '"'; *qtr = '\0';
  127.     lst(opcode,ebuf);
  128.   }
  129.   switch (opcode)
  130.   {
  131.     case RVSTR:    offset = add_string(string,TRUE);       break;
  132.     case PUSHNAME: offset = NIL; call_unknown_pgm(string); break;
  133.     default: bitch("Unknown opcode to gostr()");
  134.   }
  135.   gennum8(opcode); gennum16(offset);
  136. }
  137.  
  138. void gonum8(opcode,n)
  139. {
  140.   if (lstfile)
  141.   {
  142.     switch(opcode)
  143.     {
  144.       case RVBOOL: lst(opcode,n ? "TRUE" : "FALSE"); break;
  145.       case TYPECHECK: case GETRVAR: case SETRVAR:
  146.         lst(opcode,typename(n)); break;    
  147.       default: lst(opcode,spoof(ebuf,"%d",n));
  148.     }
  149.   }
  150.   gennum8(opcode); gennum8(n);
  151. }
  152.  
  153. void gonum16(opcode,n)
  154. {
  155.   extern char *lookup_ext_token_by_value();    /* in token.c */
  156.  
  157.   if (lstfile)
  158.   {
  159.     switch(opcode)
  160.     {
  161.       case PUSHTOKEN:
  162.       {
  163.     int j;
  164.  
  165.     for (j = 0; j < omsize; j++) if (omuttcmds[j].token == n) break;
  166.     lst(opcode,spoof(ebuf,"%s (%d)",omuttcmds[j].name,n));
  167.     break;
  168.       }
  169.       case PUSHXT:
  170.     lst(opcode,spoof(ebuf,"%s (%d)",lookup_ext_token_by_value(n), n));
  171.     break;
  172.       default: lst(opcode,spoof(ebuf,"%d",n));
  173.     }
  174.   }
  175.   gennum8(opcode); gennum16(n);
  176. }
  177.  
  178. void gonumx(n) int32 n;
  179. {
  180.   unsigned int opcode, type;
  181.   int16 z = n;
  182.  
  183.   if (0 <= n && n < 128) { type = INT8; opcode = RVNUM8; }
  184.   else
  185.     if (n == z) { type = INT16; opcode = RVNUM16; }
  186.     else { type = INT32; opcode = RVNUM32; }
  187.  
  188.   lst(opcode,spoof(ebuf,"%ld (%s)",n,typename(type)));
  189.  
  190.   gennum8(opcode);
  191.   switch (type)
  192.   {
  193.     case INT8:  gennum8((int)n); break;
  194.     case INT16: gennum16((int)z); break;
  195.     case INT32: gennum32(n); break;
  196.   }
  197. }
  198.  
  199. void go2num(opcode,n1,n2)
  200. {
  201.   LST(opcode,spoof(ebuf,"%d (%s)",n2,typename(n1)));
  202.   gennum8(opcode); gennum8(n1); gennum16(n2);
  203. }
  204.  
  205. void genobj(opcode, scope, type, offset)
  206. {
  207.   scope = (scope == GLOBAL);        /* 1 or 0 for MM */
  208.  
  209.   lst(opcode,spoof(ebuf,"%s %s %d", scope ? "global" : "local",
  210.     typename(type), offset));
  211.  
  212.   if (type == STRING) type = OSTRING;
  213.  
  214.   gennum8(opcode);
  215.   gennum8(scope);
  216.   gennum8(type);
  217.   gennum16(offset);
  218. }
  219.  
  220. /* ******************************************************************** */
  221. /* ******************* link phase ************************************* */
  222. /* ******************************************************************** */
  223.  
  224. static void label_fixup(), resolve_UnPgms(), link_pgms(), link_fas();
  225.  
  226. void link()
  227. {
  228.   label_fixup();
  229.   resolve_UnPgms(); link_pgms(); link_fas();
  230. }
  231.  
  232. /* ******************************************************************** */
  233. /* ***************** Forward referenced labels ************************ */
  234. /* ******************************************************************** */
  235.  
  236. typedef struct { address addr; int label; } FRlabel;
  237.  
  238. static int frlabels = 0;
  239. static declare_and_init_dTable(frlabel_table, FRlabel);
  240.  
  241. void addfref(addr,label) address addr;
  242. {
  243.   if (!xpand_dTable(&frlabel_table, 1, 100,100))
  244.     bail("Out of memory! Can't expand forward ref label table.");
  245.  
  246.   frlabel_table.table[frlabels].addr  = addr;
  247.   frlabel_table.table[frlabels].label = label;
  248.  
  249.   frlabels++;
  250. }
  251.  
  252. static void label_fixup()
  253. {
  254.   register int j;
  255.   register address addr, pc;
  256.  
  257.   for (j = 0; j < frlabels; j++)
  258.   {
  259.     pc   = frlabel_table.table[j].addr;
  260.     addr = getlabel(frlabel_table.table[j].label);
  261.     GENADDR(pc,addr);
  262.   }
  263. }
  264.  
  265. /* ******************************************************************** */
  266. /* ***************** Strings ****************************************** */
  267. /* ******************************************************************** */
  268.  
  269. extern char *save_string();
  270.  
  271. static declare_and_init_dTable(string_table, MuttCmd);
  272. static int strings = 0, soffset = 0, srepeats = 0;
  273.  
  274. static int add_string(string,save) char *string;
  275. {
  276.   register int j;
  277.   register MuttCmd *ptr;
  278.  
  279.   for (j = strings, ptr = string_table.table; j--; ptr++)
  280.     if (0 == strcmp(string,ptr->name)) { srepeats++; return ptr->token; }
  281.  
  282.   if (!xpand_dTable(&string_table, 1, 100,50))
  283.     bail("Out of memory! Can't expand string table.");
  284.  
  285.   soffset += (1 + strlen(string));
  286.   string_table.table[strings].token = soffset;
  287.   if (save) string = save_string(string);
  288.   string_table.table[strings].name = string;
  289.   strings++;
  290.  
  291.   return soffset;
  292. }
  293.  
  294. static void dump_strings(fptr) FILE *fptr;
  295. {
  296.   register int j;
  297.   register MuttCmd *ptr;
  298.  
  299.   for (j = strings, ptr = &string_table.table[j-1]; j--; ptr--)
  300.     fwrite(ptr->name, 1, 1 + strlen(ptr->name), fptr);
  301. }
  302.  
  303. static int strings_size() { return soffset; }
  304.  
  305. /* ******************************************************************** */
  306. /* ************************* Unknown Programs ************************* */
  307. /* ******************************************************************** */
  308.  
  309. extern address get_pgm();
  310.  
  311. typedef struct { char *name; address addr; int offset; } UnPgm;
  312.  
  313. static declare_and_init_dTable(unpgm_table, UnPgm);
  314. static int unpgms = 0, pfrefs = 0;
  315.  
  316. static int add_UnPgm(name) register char *name;
  317. {
  318.   register int j;
  319.  
  320.   pfrefs++;        /* another forward program reference */
  321.  
  322.   for (j = 0; j < unpgms; j++)    /* check to see if name already in table */
  323.     if (0 == strcmp(name,unpgm_table.table[j].name)) return j;
  324.  
  325.   if (!xpand_dTable(&unpgm_table, 1, 50,25))
  326.     bail("Out of memory! Can't expand unknown program table.");
  327.  
  328.   unpgm_table.table[unpgms].name = save_string(name);
  329.  
  330.   return unpgms++;
  331. }
  332.  
  333.    /* Find the address of the unknown programs.  If a program is still
  334.     *   unknown, add its name to the string table so it can be used for
  335.     *   runtime lookups.
  336.     */
  337. static void resolve_UnPgms()
  338. {
  339.   register UnPgm *pgm;
  340.   register int j;
  341.  
  342.   for (j = unpgms, pgm = unpgm_table.table; j--; pgm++)
  343.     if (NIL == (pgm->addr = get_pgm(pgm->name)))
  344.       pgm->offset = add_string(pgm->name,FALSE);
  345. }
  346.  
  347. /* ******************************************************************** */
  348. /* *********************** Call Unknown Program *********************** */
  349. /* ******************************************************************** */
  350.  
  351. typedef struct { int unpgm;  address addr; } LinkTable;
  352.  
  353. static declare_and_init_dTable(pgm_link_table, LinkTable);
  354. static int pgm_unlinked = 0, pgm_unresolved = 0;
  355.  
  356. static void call_unknown_pgm(name) register char *name;
  357. {
  358.   if (!xpand_dTable(&pgm_link_table, 1, 50,50))
  359.     bail("Out of memory! Can't expand unknown program link table.");
  360.  
  361.   pgm_link_table.table[pgm_unlinked].unpgm = add_UnPgm(name);
  362.   pgm_link_table.table[pgm_unlinked].addr = pc;
  363.  
  364.   pgm_unlinked++;
  365. }
  366.  
  367.    /* Assumes:  resolve_UnPgms() has been called.
  368.     */
  369. static void link_pgms()
  370. {
  371.   address addr, pc;
  372.   register LinkTable *ltr;
  373.   register UnPgm *pgm;
  374.   register int j, offset;
  375.  
  376.   for (j = pgm_unlinked, ltr = pgm_link_table.table; j--; ltr++)
  377.   {
  378.     pgm = &unpgm_table.table[ltr->unpgm];
  379.     pc = ltr->addr;
  380.     if ((addr = pgm->addr) != NIL)        /* resolved */
  381.       { GENNUM8(PUSHADDR); GENADDR(pc,addr); }
  382.     else                    /* unresolved */
  383.     {
  384.       pgm_unresolved++;
  385.       GENNUM8(PUSHNAME);
  386.       offset = pgm->offset;
  387.       PUT_INT16(&compiled_code.table[pc],offset);
  388.     }
  389.   }
  390. }
  391.  
  392. /* ******************************************************************** */
  393. /* ************** Function addresses ********************************** */
  394. /* ******************************************************************** */
  395.  
  396. static declare_and_init_dTable(fa_link_table, LinkTable);
  397. static int fa_unlinked = 0;
  398.  
  399.     /* gen a fcn address */
  400. void genfa(addr,name) address addr; char *name;
  401. {
  402.   lst(FADDR,spoof(ebuf,"%s: %d (%s)",opname[PUSHADDR],addr,name));
  403.   gennum8(FADDR); gennum8(OPADDRESS);
  404.   if (addr == NIL)        /* probably a forward reference */
  405.   {
  406.     if (!xpand_dTable(&fa_link_table, 1, 10,5))
  407.       bail("Out of memory! Can't expand function address table.");
  408.  
  409.     fa_link_table.table[fa_unlinked].unpgm = add_UnPgm(name);
  410.     fa_link_table.table[fa_unlinked].addr = pc;
  411.  
  412.     fa_unlinked++;
  413.   }
  414.   genaddr(pc,addr);
  415. }
  416.  
  417.     /* gen a fcn pointer */
  418. void genfp(opcode,n,name) char *name;
  419. {
  420.   switch (opcode)
  421.   {
  422.     case OPTOKEN: case OPXTOKEN:
  423.       lst(FADDR,spoof(ebuf,"%s: %d (%s)",
  424.         opname[(opcode == OPTOKEN) ? PUSHTOKEN : PUSHXT],n,name));
  425.       gennum8(FADDR); gennum8(opcode); gennum16(n);
  426.       break;
  427.     case OPNAME:
  428.       lst(FADDR,opname[PUSHNAME]);
  429.       gennum8(FADDR); gennum8(opcode);
  430.       break;
  431.   }
  432. }
  433.  
  434.    /* Assumes:  resolve_UnPgms() has been called.
  435.     */
  436. static void link_fas()
  437. {
  438.   address addr, pc;
  439.   register LinkTable *ltr;
  440.   register UnPgm *pgm;
  441.   register int j;
  442.  
  443.   for (j = fa_unlinked, ltr = fa_link_table.table; j--; ltr++)
  444.   {
  445.     pgm = &unpgm_table.table[ltr->unpgm];
  446.     pc = ltr->addr;
  447.     if ((addr = pgm->addr) != NIL) GENADDR(pc,addr);    /* resolved */
  448.     else                        /* unresolved */
  449.       moan(spoof(ebuf,
  450.     "(floc %s):  \"%s\" not defined in this file.",pgm->name,pgm->name));
  451.   }
  452. }
  453.  
  454. /* ******************************************************************* */
  455. /* ********************* Stats *************************************** */
  456. /* ******************************************************************* */
  457.  
  458. void dump_stats(fptr) FILE *fptr;
  459. {
  460.   extern int num_lines_read;    /* in token.c */
  461.  
  462.   fprintf(fptr, "\n");
  463.   fprintf(fptr,"%d strings totaling %d bytes, %d repeats.\n",
  464.     strings,strings_size(),srepeats);
  465.   fprintf(fptr,
  466.     "Unresolved function calls: %d (of %d forward references, %d unique).\n",
  467.     pgm_unresolved, pfrefs, unpgms);
  468.   fprintf(fptr,"Forward referenced labels: %d.\n",frlabels);
  469.   fprintf(fptr,"Number of programs: %d.\n",pgms());
  470.   fprintf(fptr,"Number of global variables: %d (%d bytes).\n",
  471.     num_global_vars(), gvspace());
  472.   fprintf(fptr,"Number of global objects: %d.\n",num_global_objects());
  473.   fprintf(fptr,"Number of constants: %d.\n",number_of_consts());
  474.   fprintf(fptr,"Number of source lines read: %d.\n",num_lines_read);
  475.   fprintf(fptr, "\n");
  476. }
  477.  
  478. /* ******************************************************************* */
  479. /* ********************* Dump the code ******************************* */
  480. /* ******************************************************************* */
  481.  
  482. address pgmaddr();
  483. char *pgmname(), *vname();
  484. unsigned int vtype();
  485.  
  486. void dumpcode(fname) char *fname;
  487. {
  488.   extern int errors;        /* in mc.c */
  489.  
  490.   address a;
  491.   char buf[90];
  492.   FILE *fptr;
  493.   uint8 bytes[50];    /* enough to hold the header and an address */
  494.   int j, z;
  495.   int16 n,pgmn = pgms();
  496.   unsigned int size, code_size;
  497.  
  498. /*  link();    /* !!! should really check for errors better */
  499.   if (errors) return;
  500.  
  501.   if (lstfile)        /* finish off the .lst file */
  502.   {
  503.     print_entry_points(lstfile);
  504.     print_global_vars(lstfile);
  505.     dump_stats(lstfile);
  506.   }
  507.  
  508.   new_ext(buf,fname,".mco");
  509.   if ((fptr = fopen(buf,"wb")) == NULL) bail("Can't open output file");
  510.  
  511.     /*  figure out the size of the pgm name table */
  512.   for (j = n = z = 0; j < pgmn; j++)
  513.     if ((pgmflags(j) & HIDDEN) == 0) { n++; z += strlen(pgmname(j)) +1; }
  514.  
  515.     /* entry point is offset from start of code */
  516.   PUT_ADDRESS(&bytes[H_ENTRY_POINT],entrypt);
  517.   code_size = codesize();
  518.   size = code_size +strings_size() +z;
  519.   PUT_UINT16(&bytes[H_BYTES_OF_CODE],size);
  520.   PUT_UINT16(&bytes[H_NAME_TABLE_OFFSET],code_size);
  521.   PUT_INT16 (&bytes[H_NUMBER_OF_PGMS],n);
  522.   z = gvspace(); PUT_UINT16(&bytes[H_BYTES_OF_GVARS],z);
  523.   PUT_UINT8(&bytes[H_MAGIC_NUMBER],MM_MAGIC_NUMBER);
  524.   PUT_UINT16(&bytes[H_NUM_GLOBAL_OBJECTS],num_global_objects());
  525.  
  526.   fwrite((char *)bytes,1,BYTES_IN_HEADER,fptr);        /* write out header */
  527.   fwrite(compiled_code.table,1,codesize(),fptr);    /* dump the code */
  528.  
  529.   for (j = 0; j < pgmn; j++)            /* dump the name table */
  530.     if ((pgmflags(j) & HIDDEN) == 0)
  531.       fwrite(pgmname(j),1,strlen(pgmname(j))+1,fptr);
  532.   dump_strings(fptr);
  533.  
  534.   for (j = 0; j < pgmn; j++)            /* dump the pgm addresses */
  535.     if ((pgmflags(j) & HIDDEN) == 0)
  536.     {
  537.       a = pgmaddr(j); PUT_ADDRESS(bytes,a);
  538.       fwrite((char *)bytes,sizeof(address),1,fptr);
  539.     }
  540.  
  541.   fclose(fptr);
  542. }
  543.  
  544. /* ******************************************************************** */
  545. /* ******************************************************************** */
  546. /* ******************************************************************** */
  547. extern char *strcpy(), *strcat();
  548.  
  549. char *typename(type) unsigned int type;
  550. {
  551.   static char str[50];
  552.   int z = type & 0xFF;
  553.  
  554.   *str = '\0';
  555.  
  556.   if (type == ARRAY) return strcat(str,"array");
  557.  
  558.   if (type & POINTER) strcat(str,"pointer to ");
  559.   if ((type & 0x80) == 0)        /* not a subtype */
  560.     switch (z)
  561.     {
  562.       case BLOB:    strcat(str,"blob");            break;
  563.       case FCNPTR:  strcat(str,"pointer to fcn");    break;
  564.       case VOID:    strcat(str,"void");            break;
  565.       case STRING:  strcat(str,"string");        break;
  566.       case NUMBER:  strcat(str,"number");        break;
  567.       case BOOLEAN: strcat(str,"bool");            break;
  568.       case REAL:    strcat(str,"real");            break;
  569.       case LIST:    strcat(str,"list");            break;
  570.     }
  571.   if (type & 0x80)        /* a subtype */
  572.     switch (z)
  573.     {
  574.       case INT8:  strcat(str,"byte");        break;
  575.       case INT16: strcat(str,"small-int");    break;
  576.       case INT32: strcat(str,"int");        break;
  577.     }
  578. if (*str == '\0') strcpy(str,"*BOGUS*");
  579.   return str;
  580. }
  581.