symtab.c 4.45 KB
/* Symbol table */

#include "ic.h"
#include "y.tab.h"

#define ktab 4

struct ste	*scopestack[100];	/* stack of saved scopes */
struct ste	**stacktop = &scopestack[0];
struct ste	**globalscope;

/*
 * Used to compute offsets of variables within local frames, records,
 * etc.
 */

int     offsetstack[100];
int     *offsettop = &offsetstack[0];

/*
 * Push a null on top of scope stack.  (Pretend there's a scope
 * outside the global scope with no symbols).  This makes some code
 * slightly simpler.
 */
void initsymtab(void)
{
    *stacktop = (struct ste *) NULL;
    *offsettop = 0;
    pushscope();  /* makes endcases easier if init with extra NULL scope */
    globalscope = stacktop;
}

/*
 * True if in global scope; false otherwise.
 */
int inglobalscope()
{
    return (stacktop == globalscope);
}

/*
 * push a copy of top of stack onto stack.
 */
void pushscope()
{
    struct ste *temp = *stacktop++;
    *stacktop = temp;

    /* Prepare the new offset. */
    offsettop++;
    *offsettop = 0;
}

/*
 * Restore old scope.  Return list of ste's from scope that was popped.
 */
struct ste *popscope()
{
    struct ste	*innerscope = *stacktop--;
    struct ste	*list = innerscope;

    /* restore previous offset */
    offsettop--;


#ifdef VERBOSE
    if (verbose) {
        printf("\nPopping scope.  STE's popped: \n");
    }
#endif

    /* Handle special case where scope is empty. */
    if (list == *stacktop) {
        return (struct ste *) NULL;
    }

    while ((list->prev != *stacktop) && (list != NULL)) {
#ifdef VERBOSE
        if (verbose) {
            printf("%s ",(list->name)->name);
        }
#endif
        list = list->prev;
    }

#ifdef VERBOSE
    if (verbose) {
        if (list) printf("%s ",(list->name)->name);
        printf("\n");
    }
#endif

    if (list == (struct ste *) NULL) {
        yyerror("No previous scope?!");
    }
    else list->prev = (struct ste *) NULL;

    /* return the popped scope. */
    return innerscope;
}

void declare(struct id *idptr, struct decl *declptr)
{
    struct ste *steptr;

    /* Make sure it hasn't already been declared in the current scope. */
    checkredecl(idptr);

    /* Allocate a new ste. */
    steptr = (struct ste *) malloc(sizeof(struct ste));

    /* bind id to declptr. */
    steptr->name = idptr;
    steptr->decl = declptr;
  
    /* push onto front of symbol table */
    steptr->prev = *stacktop;
    *stacktop = steptr;  
}

void declareglobal(struct id *idptr, struct decl *declptr)
{
    struct ste *steptr;

    /* Make sure it hasn't already been declared in the current scope. */
    checkredecl(idptr);

    /* Allocate a new ste. */
    steptr = (struct ste *) malloc(sizeof(struct ste));

    /* bind id to declptr. */
    steptr->name = idptr;
    steptr->decl = declptr;
  
    /* push onto front of symbol table */
    steptr->prev = *globalscope;
    *stacktop = steptr;  
}

/* Look up declaration on the list indicated by ste argument */
struct decl *finddecl(struct id *idptr, struct ste *steptr)
{
    struct ste *tsteptr = steptr;
    while ((tsteptr != NULL) && (idptr != tsteptr->name)) {
        tsteptr = tsteptr->prev;
    }

    if (tsteptr)
        return tsteptr->decl;
    else
        return NULL;
}

/* Look up declaration in current scope. */
struct decl *findcurrentdecl(struct id *idptr)
{
    struct decl *declptr = finddecl(idptr, *stacktop);

    if (!declptr) {
        return errorvar;
    } else {
        return declptr;
    }
}

/* Returns id of a given decl */
struct id *findname(struct decl *thedecl)
{
    struct ste *helper = *stacktop;
  
    while ((helper != NULL) && (helper->decl != thedecl)) {
        helper = helper->prev;
    }
    if (helper == NULL) return NULL;
    else return helper->name;
}

void checkredecl(struct id *idptr)
{
    struct ste *steptr = *stacktop;
    struct ste *scopeend = *(stacktop-1);

    while ((steptr != scopeend) && (idptr != steptr->name)) {
        steptr = steptr->prev;
    }
    if (steptr != scopeend) {
        yyerror("Already declared in this scope.");
    }
}

/* if id is globally declared, returns reference, else zero */
struct decl *testglobaldecl(struct id *idptr)
{
    return finddecl(idptr, *globalscope);
}

/****************************************************************************
Pretty printing stuff for symbol table
****************************************************************************/

void make_tab_str(char *tabstr, int tab)
{
    int i;
	
    for (i=0; i < tab; i++)
        tabstr[i] = ' ';

    tabstr[i] = '\0';		
}