symtab.c++ 3.88 KB
/* Symbol table */

#include "libbank.h"

#define ktab 4

int objectID = 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.
 */
ICSymTab::ICSymTab(void)
{
    stacktop   = &scopestack[0];        /* used to be **stacktop = ### ??? */
    offsettop  = &offsetstack[0];

    *stacktop  = NULL;
    *offsettop = 0;
    
    PushScope();  /* makes endcases easier if init with extra NULL scope */

    globalscope = stacktop;

}

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

/*
 * push a copy of top of stack onto stack.
 */
void ICSymTab::PushScope()
{
    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.
 */
ste *ICSymTab::PopScope()
{
    ste	*innerscope = *stacktop--;
    ste	*list = innerscope;

    /* restore previous offset */
    offsettop--;

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

    while ((list->prev != *stacktop) && (list != NULL)) {
        list = list->prev;
    }

    if (!list)
        return NULL;
        
    list->prev = NULL;

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

void ICSymTab::Declare(id *idptr, ICDecl *declptr)
{
    ste *steptr;

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

    /* Allocate a new ste. */
    steptr = new ste;

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

void ICSymTab::DeclareGlobal(id *idptr, ICDecl *declptr)
{
    ste *steptr;

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

    /* Allocate a new ste. */
    steptr = new ste;

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

/* Look up declaration on the list indicated by ste argument */
ICDecl *ICSymTab::FindDecl(id *idptr, ste *steptr)
{
    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. */
ICDecl *ICSymTab::FindCurrentDecl(struct id *idptr)
{
    ICDecl *declptr = FindDecl(idptr, *stacktop);

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

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

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

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

/* if id is globally declared, returns reference, else zero */
ICDecl *ICSymTab::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';		
}