/*
 *  MODULE  : symtab.c
 *  This module handles the data structure symtab.
 *  symtab stores all keywords and identifiers.
{*  last modification:	24.01.92  17:10   }

 *  uli 11.02.91 : symsymc added
 *  uli 11.02.91 : symentry checks symNIL, all call simplified
 *  uli 12.02.91 : syminit: sNosym added
 *  uli 20.02.91 : hash: h is long int now to prevent overflow.
 *  uli 06.03.91 : new style headers.
 *  uli 06.08.91 : sPTRCHAR sSIZEOF added.
 *  uli 09.08.91 : sINT_OF_C sFILE_OF_C sPOINTER_OF_C added.
 *  uli 12.12.91 : function symtab deleted.
 *  uli 23.01.92 : sIDOT etc. added.
 *  uli 24.01.92 : symtext returns "  " in case of error.
 *  tim 23.10.92 : sALLOCATE, sFREE, sALLOCATED added.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include           "impor.t"
#include "error.h"
#include "scan.h"
#include           "expor.t"
#include "symtab.h"
#include           "implemen.t"

#define HASHLENGTH 256
#define DUMMYLEN   1

struct tab                                          /* symtab data type */
       begin
	struct tab    *next;
	byte           symc; /* internal symbol code */
	char  sym[DUMMYLEN]; /* textual representation */
       end *symtable[HASHLENGTH] VAL((struct tab *)nil);

#ifdef LINT_ARGS
local shortint hash(register char * str) ;
local struct tab *symentry (register symptr sym);
#endif

#ifdef LINT_ARGS
local shortint hash (  register char *str)
#else
local shortint hash(str)
  /* Hashindex of the String str */
  register char *str;
#endif
BEGIN(hash)
  register shortint l ;
  register long int h=0;

  for (l=0; str[l]!='\0'; l++)
    h+= str[l];
  l--;
  h+= l*str[0];
  h=h mod HASHLENGTH;
  RETURN(h);
END /*hash*/


#ifdef LINT_ARGS
local struct tab *symentry  (  register symptr sym)
#else
local struct tab *symentry (sym)
 /* returns the pointer to the symbols record */
register symptr sym;
#endif
BEGIN(symentry)
 register shortint i,l;
 register struct tab *p;

 if  (sym < 0)   return (struct tab *) 0 ;
 p=symtable[sym div(16384 div HASHLENGTH)];
 l=sym mod (16384 div HASHLENGTH);
 for (i=0; (i<l and p!=(struct tab *)nil); i++ ) p=p->next;
 RETURN(p);
END /* symentry */


						/*-----------------*/
#ifdef LINT_ARGS
global symptr symcins ( register char * str,register symctype * symc)
#else
global symptr symcins(str, symc)                /*  s y m c i n s  */
  register char      * str;
  register symctype  * symc; /* symbol code in/out parameter */
#endif
BEGIN(symcins)
  register symptr       h1,h2;
  register struct tab *p1,*p2;

 if  (str)  then
  begin
   h1=hash(str); h2=h1*(16384 div HASHLENGTH);
   p1=symtable[h1]; p2=(struct tab *)nil;
   while ((p1 != (struct tab *)nil) and (strcmp(p1->sym,str)!=0))
    p2=p1, p1=p1->next, h2++;

   if (p1==(struct tab *)nil)
   begin                                        /* new symbol */
    p1= (struct tab*) malloc (sizeof(struct tab)+strlen(str)+1-DUMMYLEN);
    if (p1==0)  memerror (pos) ;
    strcpy (p1->sym, str) ;
    p1->next=(struct tab *)nil;

    if (h2-h1*(16384 div HASHLENGTH)>(16384 div HASHLENGTH))
       printf("Error : Symboltable Overflow !\n");

    if (p2==(struct tab *)nil)
      symtable[h1]=p1;
    else
      p2->next=p1;
    p1->symc= (byte) *symc;

   end    /* new symbol inserted */
   else
   *symc= (symctype) p1->symc ;      /* symbol found, symbol code updated */
  end /* str != NULL */
 else  h2= -1 ;
RETURN(h2);
END /*symcins*/

					       /*--------------------*/
					       /*  s y m c h a n g e */
#ifdef LINT_ARGS
global void symchange (  register symptr sym,register symctype symc)
#else
global void symchange(sym, symc)
 /* changes the symc of the symbol table entry sym to symc, */
 /* used for priority definition. */
 register symptr sym;
 register symctype  symc; /* symbol code */
#endif
BEGIN(symchange)
 struct tab *p;

 p = symentry (sym) ;
 if  (p)  then
    p->symc = (byte) symc ;
END /*symchange*/


							/*-----------------*/
#ifdef LINT_ARGS
global symctype symsymc  (  register symptr sym)
#else
global symctype symsymc (sym)                           /*  s y m s y m c  */
 /* returns the symbol code of the symbol sym. */
 register symptr sym;
#endif
BEGIN(symsymc)
 struct tab *p;

  p = symentry (sym) ;
  if  (p)  then
    return ((symctype) p->symc) ;
  else
    return (cNosym) ;     /* not found */
END /*symsymc*/


							/*-----------------*/
							/*  s y m t e x t  */
#ifdef LINT_ARGS
global char *symtext (  symptr n)
#else
global char *symtext(n)
 /* textual representation  */
 symptr n;
#endif
BEGIN(symtext)
 struct tab        *p;

 p= symentry (n) ;
 return ( p ? (p->sym) : "  " /* "???" */ );
END /*symtext*/

						/*-------------------*/
						/*  s y m p r i n t  */
#ifdef LINT_ARGS
global void  symprint (  symptr n)
#else
global void  symprint(n)
 /* writes the textual representation to stdout, used for debugging */
 symptr n;
#endif
BEGIN(symprint)
  printf ("%s\n", symtab(n)) ;
END /* symprint */


						/*-----------------*/
#ifdef LINT_ARGS
global void syminit ( void)
#else
global void syminit()                           /*  s y m i n i t  */
#endif
BEGIN(syminit)
  symctype  s ;
  register symptr    p ;  /* dummies */
#define keyword(st,c) s=c; p=symcins(st,&s); \
   if (s!=c) printf ("Error: Keyword %s already inserted.\n",st)
#define stdname(st,c) ( s=c, p=symcins(st,&s), \
   (s!=c) ? printf ("Error: Name %s already inserted.\n",st) : p)

 pos.line=0;                                    /* Pascal-SC keywords */
 pos.col =1;
 keyword("PROGRAM"    , cPROGRAM       ) ;
 keyword("MODULE"     , cMODULE        ) ;
 keyword("PRIORITY"   , cPRIORITY      ) ;
 keyword("GLOBAL"     , cGLOBAL        ) ;
 keyword("Global"     , cGLOBAL        ) ;
 keyword("global"     , cGLOBAL        ) ;
 keyword("USE"        , cUSE           ) ;
 keyword("REALCONSTANTCONVERSION", cREALCONSTANTCONVERSION) ;
 keyword("LABEL"      , cLABEL         ) ;
 keyword("CONST"      , cCONST         ) ;
 keyword("TYPE"       , cTYPE          ) ;
 keyword("PACKED"     , cPACKED        ) ;
 keyword("FILE"       , cFILE          ) ;
 keyword("SET"        , cSET           ) ;
 keyword("RECORD"     , cRECORD        ) ;
 keyword("CASE"       , cCASE          ) ;
 keyword("DYNAMIC"    , cDYNAMIC       ) ;
 keyword("ARRAY"      , cARRAY         ) ;
 keyword("OF"         , cOF            ) ;
 keyword("VAR"        , cVAR           ) ;
 keyword("PROCEDURE"  , cPROCEDURE     ) ;
 keyword("FUNCTION"   , cFUNCTION      ) ;
 keyword("OPERATOR"   , cOPERATOR      ) ;
 keyword("FORWARD"    , cFORWARD       ) ;
 keyword("EXTERNAL"   , cEXTERNAL      ) ;

 keyword("BEGIN"      , cBEGIN         ) ;
 keyword("END"        , cEND           ) ;
 keyword("FOR"        , cFOR           ) ;
 keyword("TO"         , cTO            ) ;
 keyword("DOWNTO"     , cDOWNTO        ) ;
 keyword("DO"         , cDO            ) ;
 keyword("SUM"        , cSUM           ) ;
 keyword("GOTO"       , cGOTO          ) ;
 keyword("IF"         , cIF            ) ;
 keyword("THEN"       , cTHEN          ) ;
 keyword("ELSE"       , cELSE          ) ;
 keyword("REPEAT"     , cREPEAT        ) ;
 keyword("UNTIL"      , cUNTIL         ) ;
 keyword("WHILE"      , cWHILE         ) ;
 keyword("WITH"       , cWITH          ) ;
 keyword("NIL"        , cNIL           ) ;

 keyword("IN"         , cIN            ) ;
 keyword("OR"         , cOR            ) ;
 keyword("AND"        , cAND           ) ;
/* keyword("AND",         cOR);        */
 keyword("DIV"        , cDIV           ) ;
 keyword("MOD"        , cMOD           ) ;
 keyword("NOT"        , cNOT           ) ;
						    /* Standard identifiers */
 sNosym       = stdname("bad?id"     , cIdent         ) ;
 sFALSE       = stdname("FALSE"      , cFALSE         ) ;
/* sFALSE       = stdname("FALSE"      , cTRUE          ) ; */
 sTRUE        = stdname("TRUE"       , cTRUE          ) ;
 sMAXINT      = stdname("MAXINT"     , cMAXINT        ) ;
 sBOOLEAN     = stdname("BOOLEAN"    , cBOOLEAN       ) ;
 sCHAR        = stdname("CHAR"       , cCHAR          ) ;
 sINTEGER     = stdname("INTEGER"    , cINTEGER       ) ;
 sREAL        = stdname("REAL"       , cREAL          ) ;
 sTEXT        = stdname("TEXT"       , cTEXT          ) ;
 sDOTPRECISION= stdname("DOTPRECISION", cDOTPRECISION ) ;
 sIDOTPRECISION= stdname("IDOTPRECISION", cIDOTPRECISION ) ;
 sCDOTPRECISION= stdname("CDOTPRECISION", cCDOTPRECISION ) ;
 sCIDOTPRECISION= stdname("CIDOTPRECISION", cCIDOTPRECISION ) ;
 sSTRING      = stdname("STRING"     , cSTRING        ) ;
 sINPUT       = stdname("INPUT"      , cINPUT         ) ;
 sOUTPUT      = stdname("OUTPUT"     , cOUTPUT        ) ;
 sLBOUND      = stdname("LBOUND"     , cLBOUND        ) ;
 sLB          = stdname("LB"         , cLB            ) ;
 sUBOUND      = stdname("UBOUND"     , cUBOUND        ) ;
 sUB          = stdname("UB"         , cUB            ) ;
 sSUCC        = stdname("SUCC"       , cSUCC          ) ;
 sPRED        = stdname("PRED"       , cPRED          ) ;
 sCHR         = stdname("CHR"        , cCHR           ) ;
 sORD         = stdname("ORD"        , cORD           ) ;
 sROUND       = stdname("ROUND"      , cROUND         ) ;
 sTRUNC       = stdname("TRUNC"      , cTRUNC         ) ;
 sODD         = stdname("ODD"        , cODD           ) ;
 sLENGTH      = stdname("LENGTH"     , cLENGTH        ) ;
 sMAXLENGTH   = stdname("MAXLENGTH"  , cMAXLENGTH     ) ;
 sPOS         = stdname("POS"        , cPOS           ) ;
 sSUBSTRING   = stdname("SUBSTRING"  , cSUBSTRING     ) ;
 sSCALP       = stdname("SCALP"      , cSCALP         ) ;
 sEOF         = stdname("EOF"        , cEOF           ) ;
 sEOLN        = stdname("EOLN"       , cEOLN          ) ;
 sRESET       = stdname("RESET"      , cRESET         ) ;
 sREWRITE     = stdname("REWRITE"    , cREWRITE       ) ;
 sGET         = stdname("GET"        , cGET           ) ;
 sPUT         = stdname("PUT"        , cPUT           ) ;
 sREAD        = stdname("READ"       , cREAD          ) ;
 sREADLN      = stdname("READLN"     , cREADLN        ) ;
 sWRITE       = stdname("WRITE"      , cWRITE         ) ;
 sWRITELN     = stdname("WRITELN"    , cWRITELN       ) ;
 sPAGE        = stdname("PAGE"       , cPAGE          ) ;
 sIMAGE       = stdname("IMAGE"      , cIMAGE         ) ;
 sPACK        = stdname("PACK"       , cPACK          ) ;
 sUNPACK      = stdname("UNPACK"     , cUNPACK        ) ;
 sNEW         = stdname("NEW"        , cNEW           ) ;
 sDISPOSE     = stdname("DISPOSE"    , cDISPOSE       ) ;
 sALLOCATE    = stdname("ALLOCATE"   , cALLOCATE      ) ;
 sFREE        = stdname("FREE"       , cFREE          ) ;
 sALLOCATED   = stdname("ALLOCATED"  , cALLOCATED     ) ;

 sABS         = stdname("ABS"        , cABS           ) ;
 sARCTAN      = stdname("ARCTAN"     , cARCTAN        ) ;
 sCINTERVAL   = stdname("CINTERVAL"  , cCINTERVAL     ) ;
 sCOMPLEX     = stdname("COMPLEX"    , cCOMPLEX       ) ;
 sCOS         = stdname("COS"        , cCOS           ) ;
 sEXP         = stdname("EXP"        , cEXP           ) ;
 sIM          = stdname("IM"         , cIM            ) ;
 sINF         = stdname("INF"        , cINF           ) ;
 sINTERVAL    = stdname("INTERVAL"   , cINTERVAL      ) ;
 sIVAL        = stdname("IVAL"       , cIVAL          ) ;
 sLN          = stdname("LN"         , cLN            ) ;
 sRE          = stdname("RE"         , cRE            ) ;
 sRVAL        = stdname("RVAL"       , cRVAL          ) ;
 sSIN         = stdname("SIN"        , cSIN           ) ;
 sSQR         = stdname("SQR"        , cSQR           ) ;
 sSQRT        = stdname("SQRT"       , cSQRT          ) ;
 sSUP         = stdname("SUP"        , cSUP           ) ;
 sRVECTOR     = stdname("RVECTOR"    , cRVECTOR       ) ;
 sCVECTOR     = stdname("CVECTOR"    , cCVECTOR       ) ;
 sIVECTOR     = stdname("IVECTOR"    , cIVECTOR       ) ;
 sCIVECTOR    = stdname("CIVECTOR"   , cCIVECTOR      ) ;
 sRMATRIX     = stdname("RMATRIX"    , cRMATRIX       ) ;
 sCMATRIX     = stdname("CMATRIX"    , cCMATRIX       ) ;
 sIMATRIX     = stdname("IMATRIX"    , cIMATRIX       ) ;
 sCIMATRIX    = stdname("CIMATRIX"   , cCIMATRIX      ) ;
 sINTVAL      = stdname("INTVAL"     , cINTVAL        ) ;
 sCOMPL       = stdname("COMPL"      , cCOMPL         ) ;
 sNULL        = stdname("NULL"       , cNULL          ) ;
 sID          = stdname("ID"         , cID            ) ;
 sCONJ        = stdname("CONJ"       , cCONJ          ) ;
 sTRANSP      = stdname("TRANSP"     , cTRANSP        ) ;
 sHERM        = stdname("HERM"       , cHERM          ) ;
 sBUFSIZ      = stdname("BUFSIZ"     , cBUFSIZ        ) ;
 sPTRCHAR     = stdname("STRING_OF_C", cPTRCHAR       ) ;
 sSIZEOF      = stdname("SIZEOF"     , cSIZEOF        ) ;
 sINT_OF_C    = stdname("INT_OF_C"   , cINT_OF_C      ) ;
 sFILE_OF_C   = stdname("FILE_OF_C"  , cFILE_OF_C     ) ;
 sPOINTER_OF_C= stdname("POINTER_OF_C", cPOINTER_OF_C ) ;

END /*syminit*/



						/*---------------*/
#ifdef LINT_ARGS
global symptr symins ( char *sym)
#else
global symptr symins(sym)                       /*  s y m i n s  */
char *sym;                                      /* Ottmann version */
#endif
BEGIN(symins)
symptr       h1,h2;
struct tab *p1,*p2;

 h1=hash(sym); h2=h1*(16384 div HASHLENGTH);
 p1=symtable[h1]; p2=(struct tab *)nil;
 while ((p1!=(struct tab *)nil) and (strcmp(p1->sym,sym)!=0))
  p2=p1, p1=p1->next, h2++;

 if (p1==(struct tab *)nil)
 begin                                        /* new symbol */
  p1= (struct tab*) malloc (sizeof(struct tab)+strlen(sym)+1-DUMMYLEN);
  if (p1==0)   memerror (pos) ;
  strcpy (p1->sym, sym) ;
  p1->next=(struct tab *)nil;
  p1->symc= (byte) cIdent ;     /* default symbol code, used for idtab */

  if (h2-h1*(16384 div HASHLENGTH)>(16384 div HASHLENGTH))
   printf("Error : Symboltable Overflow !\n");

  if (p2==(struct tab *)nil)
   symtable[h1]=p1;
  else
   p2->next=p1;
 end;    /* new symbol inserted */
RETURN(h2);
END /*symins*/


