/*
 * Symbol.c -  The symbol table manager
 *        Last revised 2/12/97
 */

#include  <ctype.h>
#include  "symbol.h"
/*#include     "stack.h"*/

/*
 * The names of the token classes in a format that can
 * be printed in a symbol table dump
 */
char *tokclstring[] = {    "begin     ", "call      ",
          "declare   ", "do        ", "else      ", "end       ",
          "endif     ", "enduntil  ", "endwhile  ", "if        ",
          "integer   ", "parameters", "procedure ", "program   ",
          "read      ", "real      ", "set       ", "then      ",
          "until     ", "while     ", "write     ", "star      ",
          "plus      ", "minus     ", "slash     ", "equals    ",
          "semicolon ", "comma     ", "period    ", "greater   ",
          "less      ", "notequal  ", "openparen ", "closeparen",
           "float     ","identifier", "constant  ", "error     ",
          "eof       "
};

char *symtypestring[] =  {"unknown  ", "keyword  ", "program  ",
		    "parameter", "variable ", "temp. var",
		    "constant ", "enum     ", "struct   ",
		    "union    ", "procedure", "function ",
		    "label    ", "literal  ", "operator "
};

char *datatypestring[] = {"unknown","none   ", "program",
                    "proced.", "integer", "real   "
};



/*
 * The key words and operators - used in initializing the symbol
table
 */
char *keystring[/*NUMTOKENS*/] = {"begin", "call", "declare",
          "do", "else", "end", "endif", "enduntil", "endwhile",
          "if", "integer", "parameters", "procedure", "program",
          "read", "real", "set", "then", "until", "while",
          "write", "*", "+", "-", "/", "=", ";",
          ",", ".", ">", "<", "!", "(", ")", "_float"
};

char stringtable[STRINGTABLESIZE];


struct nametabtype  nametable[TABLESIZE];
struct symtabtype   symtab[SYMTABLESIZE];

int  hashtab[HASHTABLESIZE];
int  strtablen, namtablen, symtablen, auxtablen;
procstackitem  thisproc;

enum boolean   ispresent(char string[], int length, int *code,
                                   int *nameindex);
void      LexemeInCaps(int tabindex);
int       hashcode(char string[], int length);
void	makelabel(int tabindex, char *label);

/*
 * InitializeSymTab() -  Initializes the symbol table.
 */
void initializesymtab(void)
{
     int  i, nameindex;

     initprocstack();
     thisproc = initprocentry(-1);

     /* initialize the hash table, the name table's next 
          field and the attribute table's fields as -1.  */
     for  (i = 0; i < HASHTABLESIZE;  i++)
          hashtab[i] = -1;

     for  (i = 0;  i < TABLESIZE;  i++)
          nametable[i].nextname = -1;

     for  (i = 0;  i < SYMTABLESIZE;  i++)   {
          symtab[i].symtype = -1;
          symtab[i].tok_class = -1;
          symtab[i].thisname = -1;
          symtab[i].value.tag = tint;
          symtab[i].value.val.ival = 0;
                symtab[i].owningprocedure = -1;
          symtab[i].outerscope = -1;
                symtab[i].scopenext = -1;
          symtab[i].label[0] = '\0';
     }

     /* Install the keywords in the name table and
               set their attributes to keyword */
     for  (i = 0;  i < NUMKEYWORDS;  i++)    {
          installname(keystring[i], &nameindex);
          setattrib(stkeyword, i, nameindex);
     }

     /* Install the operators in the name table and
               set their attributes to operator */
     for  (i = NUMKEYWORDS; i < NUMTOKENS;  i++)  {
          installname(keystring[i],&nameindex);
          setattrib(stoperator, i, nameindex);
     }

     installname(keystring[i], &nameindex);
     setattrib(stfunction, i, nameindex);
     installdatatype(nameindex, stfunction, dtreal);

     printf("all initiallized\n");
}

/*
 * DumpSymbolTable() -   Prints out the basic symbol table
 *             information, including the name and token class
 */
void dumpsymboltable(void)
{
     int  i, j;
     char printstring[MAXLINE];

     printf("SYMBOL TABLE DUMP\n-----------------\n\n");
     printf("                   Token       Symbol     Data");
     printf("              Owning\n");
     printf("Index   Name       Class       Type       Type");
     printf("    Value   Procedure    Label\n");
     printf("-----   ----       -----       ------     ----");
     printf("    -----   ---------\n");

     for  (i = 0;  i < symtablen;  i++) {
	  if (i%10 == 9) getchar();
          printf("%5d\t",i);
          printlexeme(i);

	  /*
           *   After printing the lexeme, move to column 20.  If
	   *   the name is too long to permit, go to the next
           *   line
           */
          if (nametable[symtab[i].thisname].strlength < 11)
               for (j = 0;
                         j < 11
                    - nametable[symtab[i].thisname].strlength;
                         j++)
                    putchar(' ');
          else
               printf("\n          ");                           

          /* Print the token class, symbol type and data type */
          printf("%s  ",tokclstring[symtab[i].tok_class]);

          printf("%s  ", symtypestring[symtab[i].symtype]);

          printf("%s",  datatypestring[symtab[i].dataclass]);

          if (symtab[i].value.tag == tint)
               printf(" %5d", symtab[i].value.val.ival);
          else
               printf(" %8.3f", symtab[i].value.val.rval);

          if (symtab[i].owningprocedure == -1)
               printf("   global");
          else {
               printf("   ");
	       LexemeInCaps(symtab[i].owningprocedure);
	  }
	  printf("   %s", symtab[i].label);
	  putchar('\n');
     }

}

void dumpsymboltable2(void)
{
     int  i;

     for (i = 0;  i < namtablen;  i++)  {
          if (i%10 == 9) getchar();
          printf("%d\t%d\t%d\t%d\t%d\n", i,
               nametable[i].strstart,
               nametable[i].strlength, nametable[i].symtabptr,
               nametable[i].nextname);
        }

     for (i = 0;  i < symtablen;  i++)  {
          if (i%10 == 9) getchar();
          printf("%d  %d  %d  %d  %d  %d  %d  %d  %d\t", i,
               symtab[i].symtype,
               symtab[i].tok_class, symtab[i].dataclass,
               symtab[i].owningprocedure, symtab[i].thisname,
               symtab[i].outerscope, symtab[i].scopenext,
	       symtab[i].value.tag);
          if (symtab[i].value.tag == treal)
               printf("%f\t", symtab[i].value.val.rval);
          else
                    printf("%d\t", symtab[i].value.val.ival);
          printf("%s\n", symtab[i].label);
     }
           
     for (i = 0;  i< strtablen; i++)    {
	  if (i%60 == 59) getchar();
          putchar(stringtable[i]);
        }
}



/*
 * InstallName() -  Check if the name is already in the table.
 *             If not add it to the name table and create an
 *             attribute table entry.  
 */
enum boolean installname(char string[], int *tabindex)
{
     int  i, code, lastcode, length, nameindex;

     /*
      * Use the function ispresent to see if the token string
      * is in the table.  If so, return a pointer to its
      * attribute table entry.
      */
     length = strlen(string);
     if (ispresent(string, length, &code, &nameindex)) {
          if (nametable[nameindex].symtabptr == -1)    {
               *tabindex = installattrib(nameindex);
               return(NO);
          }
          else {
               *tabindex = nametable[nameindex].symtabptr;
               return(YES);
          }
     }

     /*
      * If not create entries in the name table, copy the name
      * into the string table and create a hash table entry
      * (linking it to its previous entry if necessary) and
      * create an entry in the attribute table with the
      * bare essentials.
         */
     nametable[nameindex = namtablen++].strstart = strtablen;
     nametable[nameindex].strlength = length;

     for  (i = 0;  i < length;  i++)
          stringtable[strtablen++] = string[i];

     nametable[nameindex].nextname = hashtab[code];
     hashtab[code] = nameindex;
     *tabindex = installattrib(nameindex);
     return(NO);
}


int  installattrib(int nameindex)
{
     int  i, tabindex;

     tabindex = nametable[nameindex].symtabptr = symtablen++;
     symtab[tabindex].thisname = nameindex;
     symtab[tabindex].symtype = stunknown;
     symtab[tabindex].dataclass = dtunknown;


     return(tabindex);
}

/*
 * IsPresent() -    After finding the hash value, it traces
 *             through the hash list, link by link looking to see
 *             if the current token string is there.
 */
enum boolean   ispresent(char string[], int length, int *code,
                                   int *nameindex)
{
     int  found = NO, oldnameindex, j, k;

        /* Initialize the old name's index to -1; 
                                   it may not be there */
     oldnameindex = -1;

     /* Find the hash value */
     *code = hashcode(string, length);

     /*
      * Starting with the entry in the hash table, trace through
      * the name table's link list for that hash value.  The
      * inner loop
      * look to see if this name matches the one that we're
      * looking for.
      * Since this is part of a long string, strcmp cannot be
      * used.
      */
     for  (*nameindex = hashtab[*code];
                    !found && *nameindex != -1;
               oldnameindex = *nameindex,
               *nameindex = nametable[*nameindex].nextname) {
          for  (j = 0, k = nametable[*nameindex].strstart;
               j < length &&
                    string[j] == stringtable[k];  j++, k++)
               ;
          if  (j == length)   
               found = YES;

     }

        /* If it's there, we actually went right past it. */
     if (found)     
          *nameindex = oldnameindex;

     return(found);
}


/*
 * HashCode() -     A hashing function which uses the characters
 *        from the end of the token string.  The algorithm comes
 *        from Matthew Smosna of NYU.    
 */
int  hashcode(char string[], int length)
{
     int       i, numshifts, startchar;
     unsigned  code;

     numshifts = (int) min(length, (8*sizeof(int)-8));
     startchar = ((length-numshifts) % 2);
     code = 0;

     for (i = startchar;  i <= startchar + numshifts - 1;  i++)
          code = (code << 1) + string[i];

     return(code % HASHTABLESIZE);
}

/*
 * SetAttrib() -    Set attribute table information, given
 *             a pointer to the correct entry in the table.
 */
void setattrib(int symbol, int token, int tabindex)
{
     symtab[tabindex].symtype = symbol;
     symtab[tabindex].tok_class = token;

     if (symtab[tabindex].symtype == stkeyword
               || symtab[tabindex].symtype == stoperator)
          symtab[tabindex].dataclass = dtnone;
     else
          symtab[tabindex].dataclass = dtunknown;

     if (tokenclass(tabindex) == tokidentifier
                              && thisproc.proc != -1)
          if (thisproc.sstart == -1)    {
               thisproc.sstart = tabindex;
                     thisproc.snext = tabindex;
          }
          else {
               symtab[thisproc.snext].scopenext = tabindex;
                    thisproc.snext = tabindex;
          }

}


int  openscope(int tabindex)
{
     int  newtabindex, nameindex;

     nameindex = symtab[tabindex].thisname;
     newtabindex = installattrib(nameindex);
     setattrib(stunknown, tokidentifier, newtabindex);
        symtab[newtabindex].outerscope = tabindex;
     return(newtabindex);
}

void closescope(void)
{
     int  nmptr, symptr;

     for (symptr = thisproc.sstart;  symptr != -1;
               symptr = symtab[symptr].scopenext) {
          nmptr = symtab[symptr].thisname;
          nametable[nmptr].symtabptr = symtab[symptr].outerscope;
        }

}

int	labelscope(int	procindex)
{
	int	oldsymptr, symptr, numbytes = 0, totalbytes;
        char	label[LABELSIZE];

	for  (symptr = getivalue(procindex); symptr != 0;
			symptr = getivalue(symptr))
		numbytes += (data_class(symptr) == dtinteger)? 2 : 4;

        totalbytes = numbytes;
	for  (oldsymptr = symptr, symptr = getivalue(procindex);
			symptr != 0;
			oldsymptr = symptr, symptr = getivalue(symptr))	
		paramlabel(symptr, label, &numbytes);


	numbytes -=2;
	for (symptr = (getivalue(procindex) == 0)?
			procindex+1: symtab[oldsymptr].scopenext;
			symptr != -1 && symclass(symptr) != stprocedure;
			symptr = symtab[symptr].scopenext)	
		paramlabel(symptr, label, &numbytes);
	return(-numbytes-2);
}

void installdatatype(int tabindex, enum symboltype stype,
                              enum datatype dclass)
{
     symtab[tabindex].symtype = stype;
     symtab[tabindex].dataclass = dclass;
}

/*
 * TokenClass() -   Return the token class, given the pointer to
 *             the attribute table entry.            
 */
enum tokentype tokenclass(int tabindex)
{
     return(symtab[tabindex].tok_class);
}

enum datatype  data_class(int tabindex)
{
     return(symtab[tabindex].dataclass);
}

enum boolean   isvalidtype(int tabindex)
{
     return(symtab[tabindex].dataclass == dtinteger
           ||symtab[tabindex].dataclass == dtreal);
}

enum symboltype     symclass(int tabindex)
{
     return(symtab[tabindex].symtype);
}

void setivalue(int tabindex, int val)
{
     symtab[tabindex].value.tag = tint;
     symtab[tabindex].value.val.ival = val;  
}

int  getivalue(int tabindex)
{
     return(symtab[tabindex].value.val.ival);
}

void setrvalue(int tabindex, float val)
{
     symtab[tabindex].value.tag = treal;
     symtab[tabindex].value.val.rval = val;  
}

float	getrvalue(int tabindex)
{
     return(symtab[tabindex].value.val.rval);
}


void setproc(int thisproc, int tabindex)
{
     symtab[tabindex].owningprocedure = thisproc;
}

int  getproc(int tabindex)
{
     return(symtab[tabindex].owningprocedure);
}

/*
 * PrintToken() - Print the token class's name given the token
 *                  class.
 */
void printtoken(int i)
{
     printf("%s", tokclstring[i]);
}

/*
 * PrintLexeme() - Print the lexeme for a given token
 */
void printlexeme(int tabindex)
{
	int  i, j;

	i = symtab[tabindex].thisname;

	for  (j = nametable[i].strstart;
               j < nametable[i].strstart+nametable[i].strlength;
		    j++)
	putchar(stringtable[j]);
}

/*
 * PrintLexeme() - Print the lexeme for a given token
 */
void fprintlexeme(FILE *ptr, int tabindex)
{
 	int  i, j;

        i = symtab[tabindex].thisname;


 	for  (j = nametable[i].strstart;
 		j < nametable[i].strstart+nametable[i].strlength;
                    j++)

	putc(stringtable[j], ptr);
}

/*
 * LexemeInCaps() - Print the lexeme for a given token
 */
void LexemeInCaps(int tabindex)
{
	int  i, j;

	i = symtab[tabindex].thisname;

	for  (j = nametable[i].strstart;
               j < nametable[i].strstart+nametable[i].strlength;
                    j++)
		putchar(toupper(stringtable[j]));
}

/*
 * getlabel() -		Gets a label which is used by the final code
 *			generator.  If the label is not installed in the
 *			symbol table, it creates one and returns it.
 */
void	getlabel(int tabindex, char *varlabel)
{
	if (symtab[tabindex].label[0] != '\0')
		strcpy(varlabel, symtab[tabindex].label);
	else
        	makelabel(tabindex, varlabel);
}

/*
 * makelabel() -	Makes a label which is used by the final code
 *			generator and installs it in the symbol table.
 */
void	makelabel(int tabindex, char *label)
{
	int		i, j, k, m, n, ivalue;
        float		fvalue;
	char		indexstr[5];
	enum symboltype thissymbol;

	printf("in makelabel, ");
	printlexeme(tabindex);
	printf(" is it\n");
        label[0] = '\0';
	switch (symclass(tabindex))	{
	  case stliteral:
          	if (data_class(tabindex) == dtinteger)	{
	  		i = symtab[tabindex].thisname;

			for  (k = 0, j = nametable[i].strstart;
				j < nametable[i].strstart+
						nametable[i].strlength;
				j++, k++)
				label[k] = stringtable[j];
				label[k] = '\0';
			break;
		}


	  case sttempvar:	label[0] = '_';
				label[1] = 't';
				label[2] = '\0';
				itoa(tabindex, indexstr, 10);
				strcat(label, indexstr);
				break;

	  case stlabel:		strcpy(label, "_loop");
				itoa(tabindex, indexstr, 10);
				strcat(label, indexstr);
				break;
          case stprogram:
	  case stvariable:	
	  case stparameter:
	  case stprocedure:
	  	i = symtab[tabindex].thisname;

		for  (k = 0, j = nametable[i].strstart;
			j < nametable[i].strstart+nametable[i].strlength
	       				&& j < nametable[i].strstart+5;
		    		j++, k++)
			label[k] = stringtable[j];
		label[k] = '\0';
                if (strlen(label) >= 5)	{
			itoa(tabindex, indexstr, 10);
			strcat(label, indexstr);
                }
	  }
	  strcpy(symtab[tabindex].label, label);
          printf("Tabindex is %d\n", tabindex);
}


void	paramlabel(int tabindex, char *label, int *bytecount)
{
	int		i, j, k, m, n, ivalue;
        float		fvalue;
	char		indexstr[5];
	enum symboltype thissymbol;

	if (*bytecount < 0)	{
        	if (data_class(tabindex) == dtinteger)
			strcpy(label, "[bp");
		else
			strcpy(label, "[bp");
	}
	else
        	strcpy(label, "[bp");
	if (*bytecount > 0)
		strcat(label, "+");
	itoa(*bytecount, indexstr, 10);
	strcat(label, indexstr);
	*bytecount -= data_class(tabindex) == dtinteger? 2: 4;
	strcat(label, "]");
	strcpy(symtab[tabindex].label, label);
}

int	tablesize(void)
{
	return(symtablen);
}

procstack      ps;

/*
 *  ProcPop() -     Remove the top element from the Procedure
 *        Stack and return it.
 *        Precondition: the stack is not empty.
 */
procstackitem  procpop(void)
{
     if (procempty())    {
          printf("Procedure stack underflow\n");
                exit(10);
     }
          
     return(ps.item[--ps.top]);
}

/*
 * ProcPush() -     Place the item given as an argument onto the
 *        top of the Procedure Stack.
 *        Precondition: the stack is not full
 */
void procpush(procstackitem x)
{
     if (ps.top == MAXSTACK)  {
          printf("Procedure stack overflow\n");
                exit(10);
        }
     ps.item[ps.top++] = x;
}

/*
 * Empty() -   Returns True if the stack is empty,
 *        False if it is not empty.
 */
enum logical    procempty()
{
     return(ps.top == 0);
}

/*
 * Initstack() -    Initialize the stack by setting top to zero.
 */
void initprocstack(void)
{
     ps.top = 0;
}

procstackitem  initprocentry(int tabindex)
{
     procstackitem thisproc;

     thisproc.proc = tabindex;
     thisproc.sstart = -1;
     thisproc.snext = -1;
     return(thisproc);
}

[Back to the Notes Index]