/* * supp.c : support routines for the Mutt compiler * label routines * pgms * vars */ /* 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 "mm.h" #include "mc.h" extern address pcaddr(); extern char ebuf[], *savestr(), *strcpy(), *spoof(); extern FILE *lstfile; /* in mc.c */ MMDatum *getconst(); /* ******************************************************************** */ /* ****************** error routines ********************************** */ /* ******************************************************************** */ extern char *muttfile; /* in mc.c */ extern int srcline, errors, warnings; /* in mc.c */ void errmsg(errtype,msg) char *errtype, *msg; { char buf[300]; spoof(buf,"%s %d %s: %s\n",muttfile,srcline,errtype,msg); if (lstfile) fputs(buf,lstfile); fputs(buf,stdout); } int no_warn = FALSE, no_gripe = FALSE; void gripe(msg) char *msg; { if (!no_gripe) errmsg("Note",msg); } void groan(msg) char *msg; { warnings++; if (!no_warn) errmsg("Warning",msg); } void moan(msg) char *msg; { errors++; errmsg("Error",msg); } void bitch(msg) char *msg; { moan(msg); exit(1); } /* Internal error : print message and bail out */ bail(msg) char *msg; { fprintf(stderr,"Internal error! %s\n",msg); exit(1); } /* ******************************************************************** */ /* ******************************* misc ******************************* */ /* ******************************************************************** */ is_object_type(type) { return (type == LIST || type == STRING); } /* ******************************************************************** */ /* ****************** label routines ********************************** */ /* ******************************************************************** */ static declare_and_init_dTable(label_table, address); genlabel() { static int labels = 0; if (!xpand_dTable(&label_table, 1, 100,100)) bail("Out of memory! Can't expand label table."); label_table.table[labels] = NIL; return labels++; } address getlabel(label) { return label_table.table[label]; } void stufflabel(label) { if (lstfile) fprintf(lstfile,"%4u: L%d:\n",pcaddr(),label); label_table.table[label] = pcaddr(); } typedef struct { int name; int label; } NamedLabel; static declare_and_init_dTable(named_label_table,NamedLabel); static declare_and_init_dTable(lname_heap,char); static int named_labels = 0, lptr = 0; gen_named_label(name) char *name; { int n; if (get_named_label(name) != -1) { moan(spoof(ebuf,"Label \"%s\" already in use.",name)); return 0; } if (!xpand_dTable(&named_label_table, 1, 10,10)) bail("Out of memory! Can't expand named label table."); n = strlen(name) +1; if (!xpand_dTable(&lname_heap, n, 256,256)) bail("Out of memory! Can't expand named label heap."); named_label_table.table[named_labels].name = lptr; strcpy(&lname_heap.table[lptr], name); lptr += n; return (named_label_table.table[named_labels++].label = genlabel()); } get_named_label(name) char *name; /* return label */ { char *heap_start = lname_heap.table; int j; NamedLabel *label = named_label_table.table; for (j = named_labels; j--; label++) if (0 == strcmp(name, heap_start + label->name)) return label->label; return -1; } void reset_named_labels() { char *heap_start = lname_heap.table; int j; NamedLabel *label = named_label_table.table; for (j = named_labels; j--; label++) if (getlabel(label->label) == NIL) moan(spoof(ebuf,"Label \"%s\" unresolved.", heap_start + label->name)); reset_dTable(&lname_heap); reset_dTable(&named_label_table); named_labels = lptr = 0; } /* ******************************************************************** */ /* ****************** PGMs ******************************************** */ /* ******************************************************************** */ typedef struct { char *name; address addr; uint8 flags; } PgmTable; static int pgmn = 0; static declare_and_init_dTable(pgm_table, PgmTable); /* ??? use bsearch */ address getpgm(name) char *name; { register int j, lower = 0, upper = pgmn-1, x; PgmTable *pgmtable = pgm_table.table; while (lower <= upper) { j = (lower+upper)/2; if ((x = strcmp(name,pgmtable[j].name)) > 0) lower = j +1; else if (x < 0) upper = j -1; else /* found it */ { if (pgmtable[j].flags & LEAR) moan(spoof(ebuf,"%s is special and can't be used.",pgmtable[j].name)); return pgmtable[j].addr; } } return NIL; } addpgm(name) char *name; { int i,j,x, flags = 0; PgmTable *pgmtable; if (getvar(name) != -1) moan(spoof(ebuf,"\"%s\" is a var name.",name)); if (!xpand_dTable(&pgm_table, 1, 50,20)) bail("Out of memory! Can't expand pgm table."); pgmtable = pgm_table.table; if (0 == strcmp(name,"MAIN")) flags = (MAIN | HIDDEN | LEAR); for (i = 0; i < pgmn; i++) { if ((x = strcmp(pgmtable[i].name,name)) == 0) { if ((flags & LEAR) == 0) bitch(spoof(ebuf,"pgm \"%s\" already used.",name)); } else if (x > 0) break; } for (j = pgmn; j > i; j--) pgmtable[j] = pgmtable[j-1]; if (!(pgmtable[i].name = savestr(name))) bail("Can't save pgm name"); pgmtable[i].addr = pcaddr(); pgmtable[i].flags = flags; pgmn++; return i; } pgms() { return pgmn; } void modpgm(n,f) { pgm_table.table[n].flags |= f; } address pgmaddr(n) { return pgm_table.table[n].addr; } char *pgmname(n) { return pgm_table.table[n].name; } pgmflags(n) { return (int)pgm_table.table[n].flags; } /* Return the id of the next pgm with id >= n, -1 if none */ get_main(n) { for (; n < pgmn; n++) if (pgm_table.table[n].flags & MAIN) return n; return -1; } /* ******************************************************************** */ /* ****************** VARs ******************************************** */ /* ******************************************************************** */ typedef struct { int name; /* offset into var_name_table */ unsigned int type; int offset; /* from var base (first var of same scope) */ uint8 scope; /* LOCAL or GLOBAL */ int blobs; /* number of VBlobs that make up blob */ int list; /* index into blob array */ } Var; static int vars = 0, blobs = 0, local_objects = 0, global_objects = 0, global_vars = 0, /* number of global vars and where local vars start */ vnbase = 0, /* ditto but for var names */ size_of_global_vars = 0, size_of_local_vars = 0, global_blobs = 0; /* number of global blobs and where local blobs start */ VBlob *proto_name(); static declare_and_init_dTable(var_table, Var); static declare_and_init_dTable(blob_table, VBlob); /* ************ Var Names ************************ */ static declare_and_init_dTable(var_name_table, char); static int vptr = 0; /* WARNING!!! * The proto stuff uses a pointer into the var_name_table.table. This * is a no-no since the table can be realloc()ed and thus move. I * need to fix this. But since this bug has been here forever and * I've never hit it, I'm going to punt for now. */ static int add_var_name(name) char *name; { int len = strlen(name) +1, start = vptr; if (!xpand_dTable(&var_name_table, len, 1024,512)) bail("Out of memory! Can't expand var name table."); strcpy(&var_name_table.table[vptr],name); vptr += len; return start; } #define GET_VAR_NAME(n) &var_name_table.table[n] void reset_vars() /* reset var tables for new function */ { vars = global_vars; size_of_local_vars = 0; vptr = vnbase; sizeof_dTable(&var_name_table) = vnbase; blobs = global_blobs; local_objects = 0; } addvar(name,type,var_size,scope) char *name; unsigned int type; { int n, is_object; Var *the_var; if (scope == GLOBAL && (getconst(name) || getpgm(name) )) moan(spoof(ebuf, "\"%s\" is a pgm or const - can't be reused as a var.",name)); if ((scope == LOCAL && proto_name(name)) || ((n = getvar(name)) != -1 && scope == vscope(n))) bitch(spoof(ebuf,"var \"%s\" already in use.",name)); is_object = is_object_type(type); if (!xpand_dTable(&var_table, 1, 30,10)) bail("Out of memory! Can't expand var table."); the_var = &var_table.table[vars]; the_var->name = add_var_name(name); if (scope == LOCAL) { if (is_object) the_var->offset = local_objects++; else { the_var->offset = size_of_local_vars; size_of_local_vars += var_size; } } else { global_vars++; vnbase = vptr; if (is_object) the_var->offset = global_objects++; else { the_var->offset = size_of_global_vars; size_of_global_vars += var_size; } } the_var->type = type; the_var->scope = scope; return vars++; /* pass back the var id */ } static void blubber() { if (!xpand_dTable(&blob_table, 1, 20,10)) bail("Out of memory! Can't expand blob table."); } add_array(name,type,size,scope,dims,dim) char *name; unsigned int type; int dim[]; { int j,n; blubber(); n = addvar(name,ARRAY,size,scope); var_table.table[n].list = blobs; blob_table.table[blobs].type = type; blob_table.table[blobs].dims = dims; for (j = 0; j < dims; j++) blob_table.table[blobs].dim[j] = dim[j]; if (scope == GLOBAL) global_blobs++; blobs++; return n; } #if 0 /* not used (yet) */ add_vblob(name,offset,type,dims,dim) char *name; unsigned int type; int dim[]; { int j, n; blubber(); n = blobs++; if (NULL == (blob_table.table[n].name = savestr(name))) bail("Can't malloc vblob name."); blob_table.table[n].offset = offset; blob_table.table[n].type = type; blob_table.table[n].dims = dims; for (j = 0; j < dims; j++) blob_table.table[n].dim[j] = dim[j]; return n; } #endif vscope(n) { return (int)var_table.table[n].scope; } char *vname(n) { return GET_VAR_NAME(var_table.table[n].name); } voffset(n) { return var_table.table[n].offset; } getvar(name) char *name; { int i; for (i = global_vars; i < vars; i++) /* first check local vars */ if (0 == strcmp(vname(i),name)) return i; for (i = 0; i < global_vars; i++) /* then check globals */ if (0 == strcmp(vname(i),name)) return i; return -1; } VBlob *get_blob(n) { return &blob_table.table[var_table.table[n].list]; } typesize(type) unsigned int type; { if ((type & POINTER) || type == BLOB) return sizeof(int32); switch(type) { case INT8: case BOOLEAN: case STRING: return sizeof(uint8); case INT16: return sizeof(int16); case INT32: return sizeof(int32); case FCNPTR: moan("typesize(FCNPTR)"); return 4; } /* NOTREACHED */ } unsigned int mmtype(type) unsigned int type; { /*if (type & MCTYPE) bitch(spoof(ebuf,"mmtype(%d): not a MMable type.",type));*/ if (type & POINTER) return BLOB; switch (type) { case INT8: case INT16: case INT32: return NUMBER; } return type; } unsigned int vtype(n) { return (unsigned int)var_table.table[n].type; } unsigned int vctype(n) unsigned int n; { return mmtype(vtype(n)); } /* space needed to hold local vars */ lvspace() { return size_of_local_vars; } /* Number of local vars for current defun */ lvars() { return (vars -global_vars); } first_local_var() { return global_vars; } num_global_vars() { return global_vars; } /* number of global vars */ /* space needed to hold global vars */ gvspace() { return size_of_global_vars; } num_global_objects() { return global_objects; } /* Return the id of the next globabl variable with id >= n, -1 if * none. */ get_global_object(n) { for (; n < global_vars; n++) if (is_object_type(vtype(n))) return n; return -1; } /* ******************************************************************** */ /* ****************** Prototypes ************************************** */ /* ******************************************************************** */ typedef struct { char *name; int blobs; /* number of VBlobs that make up proto */ int list; /* index into blob array */ } Proto; static Proto proto; VBlob *proto_name(name) char *name; { int n = proto.blobs; VBlob *blob = &blob_table.table[proto.list]; for (; n--; blob++) if (0 == strcmp(blob->name,name)) return blob; return NULL; } addproto(name) char *name; { proto.name = NULL; proto.blobs = proto.list = 0; return 0; } void killproto() { proto.blobs = 0; } void moreproto(name,ntharg,type,dims,dim) char *name; unsigned int type; int dim[]; { int j, n; if (proto_name(name)) moan(spoof(ebuf,"arg \"%s\" already in use.",name)); blubber(); n = blobs++; j = add_var_name(name); /* HP-UX s800 7.0 CC bug */ blob_table.table[n].name = GET_VAR_NAME(j); blob_table.table[n].offset = ntharg; blob_table.table[n].type = type; blob_table.table[n].dims = dims; for (j = 0; j < dims; j++) blob_table.table[n].dim[j] = dim[j]; if (proto.blobs == 0) proto.list = n; proto.blobs++; } #if 0 /* not used (yet) */ VBlob *proto_arg(nth_arg) { int n = proto.blobs; VBlob *blob = &blob_table.table[proto.list]; for (; n--; blob++) if (blob->offset == nth_arg) return blob; return NULL; } #endif /* ******************************************************************** */ /* ************************ CONSTS ************************************ */ /* ******************************************************************** */ /* Here is where I save (const foo ) */ typedef struct { char *name; MMDatum rv; } Const; static int nconsts = 0; static declare_and_init_dTable(consts, Const); MMDatum *getconst(name) char *name; { Const *ptr; int j; for (j = nconsts, ptr = consts.table; j--; ptr++) if (strcmp(name,ptr->name) == 0) return &ptr->rv; return NULL; } void add_const(name,rv) char *name; MMDatum *rv; { if (getconst(name) || proto_name(name) || getvar(name) != -1) { moan(spoof(ebuf,"\"%s\" already defined.",name)); return; } if (!xpand_dTable(&consts, 1, 10,10)) bail("Out of memory! Can't expand constant table."); consts.table[nconsts].name = savestr(name); consts.table[nconsts].rv = *rv; nconsts++; }