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