/*   Symbol Environment Management Module  */


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "types.h"
#include "symbol.h"

int level = 0; /* current scope level */
   
/* Store symbols in a hash table, keyed on symbol name (saved string address).
   Each hash-table bucket points to a linked list of symbols. */
typedef struct linkedsymbol {
  struct symbol symbol;       /* the symbol itself */
  struct linkedsymbol *link;  /* ptr to next linkedsymbol for this bucket */
} *Linkedsymbol;

#define SYMBOL_TABLE_BUCKETS 1001
#define LG_ALPHA 4   /* alpha = 2^LG_ALPHA; see ASU pp. 435-438. */
static Linkedsymbol symbol_table[SYMBOL_TABLE_BUCKETS];


void enterscope(void) 
{
  level++;
}

void exitscope(void)
{
  int i;
  assert(level > 0);
  for (i = 0; i < SYMBOL_TABLE_BUCKETS; i++) {
    Linkedsymbol t, s = symbol_table[i];
    while (s && s->symbol.scope == level) {
      t = s -> link;
      free(s);
      s = t;
    }
    symbol_table[i] = s;
  };
  level--;
}

static char *strsave(char *str)
{
  char *b;
  assert (b = (char *) malloc(strlen(str) + 1));
  strcpy(b,str);
  return b;
}

unsigned hash(char *s) 
{
  unsigned h = 0;
  while (*s)
    h = (h << LG_ALPHA) + *s++;
  h %= SYMBOL_TABLE_BUCKETS;
  return h;
}


Symbol install (char *name)
{
  int i;
  unsigned h;
  Linkedsymbol s = (Linkedsymbol) malloc(sizeof(struct linkedsymbol));
  assert(s);
  s->symbol.name = strsave(name);
  s->symbol.scope = level;
  h = hash(name);
  s->link = symbol_table[h];
  symbol_table[h] = s;  
  return &s->symbol;
}


Symbol lookup(char *name)
{
  unsigned h = hash(name);
  Linkedsymbol s;
  for (s = symbol_table[h]; s; s = s-> link)
     if (strcmp(s->symbol.name,name) == 0)
       return(&s->symbol);
  return NULL;
}



