/***  hash.c  ***/

#include "Lalgol.h"
#include "hash.h"
#include "io.h"		/* fatal error */

#define HASH_max	1237
static struct { int value; char *key;} HASH[HASH_max];
int STNG_pointer, SYMBOL_number;
char STNG[STNG_max];
/*----------------------------------------------------------------------*/
/* prototypes */
static bool nohit(int,char*);
static void force_in(char*,int);
/*----------------------------------------------------------------------*/

/* hashing procedures */
/*----------------------------------------------------------------------*
 *  STNG[]	   stores the charcter form of everything
 *  STNG_max	   the length of STNG[]
 *  STNG_pointer   the first free element in STNG[]
 *  HASH_max	   the length of HASH[]
 *  HASH[]	   the hashing table, it has the structure
			(int value; char *key)
 *  SYMBOL_number  the next internal code for an identifier or indicator
 *----------------------------------------------------------------------*/

static bool nohit(h,p) int h; char *p;
{char *q;
	if(!(q=HASH[h].key))return(FALSE);
	for(;*p==*q;p++,q++) if(*p == 0) return(FALSE);
	return(TRUE);
}

int insert(p,code) int p,code;
{int c,hashcode; char *q,*r; int cnt=0;
	q=r= &STNG[p]; hashcode=((*q)*353)%HASH_max;
	while(c= *(++q)) hashcode=((hashcode<<4)+19*c)%HASH_max;
	if(hashcode<0) hashcode+=HASH_max;
	while(nohit(hashcode,r) && (++cnt < HASH_max))
	    hashcode=(hashcode+1)%HASH_max;
	if(cnt==HASH_max)fatal_error("hash table is full");
	if(HASH[hashcode].key){STNG_pointer=p;}else{
	    HASH[hashcode].key=r;
	    HASH[hashcode].value = code | (SYMBOL_number++);
	}
	return(HASH[hashcode].value);
}

static void force_in(s,code) char *s; int code;
{ int p;
	p=STNG_pointer;
	while(STNG[STNG_pointer++]= *s++);
	SYMBOL_number=0; insert(p,code);
}

/*----------------------------------------------------------------------*/
/* initialize the HASH table */

void init_HASH()
{
    /* open --  close symbols and related stuff */
	force_in("'begin",OPEN_1);
	force_in("'end",CLOSE_1);
	force_in("'if",OPEN_2);
	force_in("'fi",CLOSE_2);
	force_in("'then",VERT_21);
	force_in("'else",VERT_22);
	force_in("'elif",AGAIN_2);
	force_in("'case",OPEN_3);
	force_in("'esac",CLOSE_3);
	force_in("'in",VERT_31);
	force_in("'out",VERT_32);
	force_in("'ouse",AGAIN_3);
	force_in("'do",DO_1);
	force_in("'od",OD_1);

    /* comment symbols */
	force_in("'co",CO);
	force_in("'comment",COMMENT);

    /* other bold symbols */
	force_in("'exit",EXIT);
	force_in("'at",AT);
	force_in("'goto",GOTO);
	force_in("'for",FOR);
	force_in("'from",FROM);
	force_in("'by",BY);
	force_in("'to",TO);
	force_in("'while",WHILE);
	force_in(":=:",IS);
	force_in("'is",IS);
	force_in(":/=:",ISNT);
	force_in("'isnt",ISNT);
	force_in("'true",DTRUE);
	force_in("'false",DFALSE);
	force_in("'empty",EMPTY);
	force_in("'of",OF);
	force_in("'nil",NIL);
	force_in("'skip",SKIP);

	force_in("'void",VOID);
	force_in("'ref",REF);
	force_in("'flex",FLEX);
	force_in("'proc",PROC);
	force_in("'mode",MODE);
	force_in("'struct",STRUCT);
	force_in("'union",UNION);
	force_in("'op",OP);
	force_in("'prio",PRIO);
	force_in("'int",INT);
	force_in("'real",REAL);
	force_in("'bool",BOOL);
	force_in("'char",CHAR);
	force_in("'string",STRING);
	force_in("'compl",COMPL);
	force_in("'bits",BITS);
	force_in("'loc",LOC);
	force_in("'heap",HEAP);

    /* binary operators */
	force_in("+:=",PLUSAB);
	force_in("'plusto",PLUSTO);
	force_in("+=:",PLUSTO);
	force_in("-:=",MINAB);
	force_in("*:=",TIMEAB);
	force_in("%:=",OVERAB);
	force_in("*%:=",MODAB);
	force_in("/:=",DIVAB);
	force_in("'or",OR);
	force_in("'and",AND);
	force_in("&",AND);
	force_in("'eq",EQ_ST);
	force_in("=",EQ_ST);
	force_in("/=",NE);
	force_in("<",LESS);
	force_in("<=",LE);
	force_in("'le",LE);
	force_in("'ge",GE);
	force_in(">=",GE);
	force_in(">",GREATER);
	force_in("+",PLUS);
	force_in("-",MINUS);
	force_in("*",TIMES);
	force_in("/",DIV);
	force_in("%",OVER);
	force_in("%*",MOD);
	force_in("'mod",MOD);
	force_in("'elem",ELEM);
	force_in("^",UP);
	force_in("**",UP);
	force_in("'up",UP);
	force_in("'down",DOWN);
	force_in("'upb",UPB);
	force_in("'lwb",LWB);
	force_in("'i",PLIT);

    /* bold unary operators */
	force_in("'not",NOT);
	force_in("'abs",ABS);
	force_in("'odd",ODD);
	force_in("'sign",SIGN);
	force_in("'entier",ENTIER);
	force_in("'round",ROUND);
	force_in("'re",RE);
	force_in("'im",IM);
	force_in("'conj",CONJ);
	force_in("'arg",ARG);
	force_in("'repr",REPR);
	force_in("'bin",BIN);

    /* standard procedures */
	force_in("sqrt",SQRT);
	force_in("exp",EXP);
	force_in("log",LOG);
	force_in("cos",COS);
	force_in("arccos",ARCCOS);
	force_in("sin",SIN);
	force_in("arcsin",ARCSIN);
	force_in("tan",TAN);
	force_in("arctan",ARCTAN);
	force_in("print",PRINT);
	force_in("read",READ);
	force_in("write",WRITE);
	force_in("newline",NEWLINE);
	force_in("space",SPACE);
	force_in("newpage",NEWPAGE);
	force_in("random",RANDOM);
	force_in("bitspack",BITSPACK);

    /* other identifiers */
	force_in("pi",PI_TAG);
	force_in("re",RE_TAG);
	force_in("im",IM_TAG);
	force_in("standin",STANDIN);
	force_in("standout",STANDOUT);
	force_in("bitswidth",BITSWIDTH);
	force_in("blank",BLANK_TAG);
	force_in("stop",STOP_TAG);

    /* others */
	force_in(":",COLON);
	force_in(":=",BECOMES);
    /* the first usable internal code */
	SYMBOL_number=first_SYMBOL_number;
}
