/* * lsym.c -- functions for symbol table manipulation. */ #include "..\h\config.h" #include "link.h" #include "general.h" #include "tproto.h" #include "globals.h" /* * Prototypes. */ hidden struct fentry *alcfhead Params((struct fentry *blink,char *name, int fid, struct rentry *rlist)); hidden struct rentry *alcfrec Params((struct rentry *link,int rnum, int fnum)); hidden struct gentry *alcglobal Params((struct gentry *blink,char *name, int flag,int nargs,int procid)); hidden struct ientry *alcident Params((char *nam,int len)); int dynoff; /* stack offset counter for locals */ int argoff; /* stack offset counter for arguments */ int static1; /* first static in procedure */ int lstatics = 0; /* static variable counter */ int nlocal; /* number of locals in local table */ int nconst; /* number of constants in constant table */ int nfields = 0; /* number of fields in field table */ /* * instid - copy the string s to the start of the string free space * and call putident with the length of the string. */ char *instid(s) char *s; { register int l; register char *p1, *p2; p1 = lsfree; p2 = s; l = 0; do { if (p1 > lsend) quit("out of string space"); l++; } while (*p1++ = *p2++); return putident(l); } /* * putident - install the identifier named by the string starting at lsfree * and extending for len bytes. The installation entails making an * entry in the identifier hash table and then making an identifier * table entry for it with alcident. A side effect of installation * is the incrementing of lsfree by the length of the string, thus * "saving" it. * * Nothing is changed if the identifier has already been installed. */ char *putident(len) int len; { register int hash; register char *s; register struct ientry *ip; int l; /* * Compute hash value by adding bytes and masking result with imask. * (Recall that imask is ihsize-1.) */ s = lsfree; hash = 0; l = len; while (l--) hash += *s++; l = len; s = lsfree; hash &= imask; /* * If the identifier hasn't been installed, install it. */ if ((ip = lihash[hash]) != NULL) { /* collision */ for (;;) { /* work down i_blink chain until id is found or the end of the chain is reached */ if (l == ip->i_length && lexeql(l, s, ip->i_name)) return (ip->i_name); /* id is already installed, return it */ if (ip->i_blink == NULL) { /* end of chain */ ip->i_blink = alcident(s, l); lsfree += l; return s; } ip = ip->i_blink; } } /* * Hashed to an empty slot. */ lihash[hash] = alcident(s, l); lsfree += l; return s; } /* * lexeql - compare two strings of given length. Returns non-zero if * equal, zero if not equal. */ int lexeql(l, s1, s2) register int l; register char *s1, *s2; { while (l--) if (*s1++ != *s2++) return 0; return 1; } /* * alcident - get the next free identifier table entry, and fill it in with * the specified values. */ static struct ientry *alcident(nam, len) char *nam; int len; { register struct ientry *ip; if (lifree >= &litable[isize]) quit("out of identifier table space"); ip = lifree++; ip->i_blink = NULL; ip->i_name = nam; ip->i_length = len; return ip; } /* * locinit - clear local symbol table. */ novalue locinit() { dynoff = 0; argoff = 0; nlocal = -1; nconst = -1; static1 = lstatics; } /* * putlocal - make a local symbol table entry. */ novalue putlocal(n, id, flags, imperror, procname) int n; char *id; register int flags; int imperror; char *procname; { register struct lentry *lp; union { struct gentry *gp; int bn; } p; if (n >= lsize) quit("out of local symbol table space"); if (n > nlocal) nlocal = n; lp = &lltable[n]; lp->l_name = id; lp->l_flag = flags; if (flags == 0) { /* undeclared */ if ((p.gp = glocate(id)) != NULL) { /* check global */ lp->l_flag = F_Global; lp->l_val.global = p.gp; } else if ((p.bn = blocate(id)) != 0) { /* check for function */ lp->l_flag = F_Builtin; lp->l_val.global = putglobal(id, F_Builtin | F_Proc, -1, p.bn); } else { /* implicit local */ if (imperror) lwarn(id, "undeclared identifier, procedure ", procname); lp->l_flag = F_Dynamic; lp->l_val.offset = ++dynoff; } } else if (flags & F_Global) { /* global variable */ if ((p.gp = glocate(id)) == NULL) quit("putlocal: global not in global table"); lp->l_val.global = p.gp; } else if (flags & F_Argument) /* procedure argument */ lp->l_val.offset = ++argoff; else if (flags & F_Dynamic) /* local dynamic */ lp->l_val.offset = ++dynoff; else if (flags & F_Static) /* local static */ lp->l_val.staticid = ++lstatics; else quit("putlocal: unknown flags"); } /* * putglobal - make a global symbol table entry. */ struct gentry *putglobal(id, flags, nargs, procid) char *id; int flags; int nargs; int procid; { register struct gentry *p; if ((p = glocate(id)) == NULL) { /* add to head of hash chain */ p = lghash[ghasher(id)]; lghash[ghasher(id)] = alcglobal(p, id, flags, nargs, procid); return lghash[ghasher(id)]; } p->g_flag |= flags; p->g_nargs = nargs; p->g_procid = procid; return p; } /* * putconst - make a constant symbol table entry. */ novalue putconst(n, flags, len, pc, valp) int n; int flags, len; word pc; union xval *valp; { register struct centry *p; if (n >= csize) quit("out of constant table space"); if (nconst < n) nconst = n; p = &lctable[n]; p->c_flag = flags; p->c_pc = pc; if (flags & F_IntLit) { p->c_val.ival = valp->ival; } else if (flags & F_StrLit) { p->c_val.sval = valp->sval; p->c_length = len; } else if (flags & F_CsetLit) { p->c_val.sval = valp->sval; p->c_length = len; } else if (flags & F_RealLit) #ifdef Double /* access real values one word at a time */ { int *rp, *rq; rp = (int *) &(p->c_val.rval); rq = (int *) &(valp->rval); *rp++ = *rq++; *rp = *rq; } #else /* Double */ p->c_val.rval = valp->rval; #endif /* Double */ else fprintf(stderr, "putconst: bad flags: %06o %011lo\n", flags, valp->ival); } /* * putfield - make a record/field table entry. */ novalue putfield(fname, rnum, fnum) char *fname; int rnum, fnum; { register struct fentry *fp; register struct rentry *rp, *rp2; word hash; fp = flocate(fname); if (fp == NULL) { /* create a field entry */ nfields++; hash = fhasher(fname); fp = lfhash[hash]; lfhash[hash] = alcfhead(fp, fname, nfields, alcfrec((struct rentry *)NULL, rnum, fnum)); return; } rp = fp->f_rlist; /* found field entry, look for */ if (rp->r_recid > rnum) { /* spot in record list */ fp->f_rlist = alcfrec(rp, rnum, fnum); return; } while (rp->r_recid < rnum) { /* keep record list ascending */ if (rp->r_link == NULL) { rp->r_link = alcfrec((struct rentry *)NULL, rnum, fnum); return; } rp2 = rp; rp = rp->r_link; } rp2->r_link = alcfrec(rp, rnum, fnum); } /* * glocate - lookup identifier in global symbol table, return NULL * if not present. */ struct gentry *glocate(id) char *id; { register struct gentry *p; p = lghash[ghasher(id)]; while (p != NULL && p->g_name != id) p = p->g_blink; return p; } /* * flocate - lookup identifier in field table. */ struct fentry *flocate(id) char *id; { register struct fentry *p; p = lfhash[fhasher(id)]; while (p != NULL && p->f_name != id) p = p->f_blink; return p; } /* * alcglobal - create a new global symbol table entry. */ static struct gentry *alcglobal(blink, name, flag, nargs, procid) struct gentry *blink; char *name; int flag; int nargs; int procid; { register struct gentry *gp; if (lgfree >= &lgtable[gsize]) quit("out of global symbol table space"); gp = lgfree++; gp->g_blink = blink; gp->g_name = name; gp->g_flag = flag; gp->g_nargs = nargs; gp->g_procid = procid; return gp; } /* * alcfhead - allocate a field table header. */ static struct fentry *alcfhead(blink, name, fid, rlist) struct fentry *blink; char *name; int fid; struct rentry *rlist; { register struct fentry *fp; if (lffree >= &lftable[fsize]) quit("out of field table space"); fp = lffree++; fp->f_blink = blink; fp->f_name = name; fp->f_fid = fid; fp->f_rlist = rlist; return fp; } /* * alcfrec - allocate a field table record list element. */ static struct rentry *alcfrec(link, rnum, fnum) struct rentry *link; int rnum, fnum; { register struct rentry *rp; if (lrfree >= &lrtable[rsize]) quit("out of field table space for record lists"); rp = lrfree++; rp->r_link = link; rp->r_recid = rnum; rp->r_fnum = fnum; return rp; } /* * blocate - search for a function. The search is linear to make * it easier to add/delete functions. If found, returns index+1 for entry. */ int blocate(s) register char *s; { register int i; extern char *ftable[]; extern int ftbsize; for (i = 0; i < ftbsize; i++) if (strcmp(ftable[i], s) == 0) return i + 1; return 0; }