  { TUSYMS:  Symbol table handling for skeleton files. }
  { Copyright (C) 1986 by QCAD Systems Inc., All Rights Reserved. }

  {*******************}
  function HASHIT(FSYM: symbol): int;
    var K, S: integer;
  begin
    s:=0;
    for k:=1 to length(fsym) do
      s:=s + ord(fsym[k]);   {just the sum of the characters}
    hashit := s mod hashsize;
  end;

  {********************}
  function NEW_SYM(SYT: symtype): symtabp;
    var TSYM: symtabp;
  begin
    new(tsym);
    new_sym:=tsym;
    with tsym^ do begin
      next:=nil;
      symt:=syt;
      case syt of
        reserved: tokval:=1;
        var_type: vaddr:=0;
        func_type: begin
          faddr:=0;
          pbytes:=0;
          is_actual:=false;
          is_system:=false;
          end;
        ELSE ;
        end
      end
    end;
        
  {*****************}
  function FINDSYM(var SYMTAB: symtable; FSYM: symbol): symtabp;
    { Finds a symbol, returning NIL if not there.  Use this for
      variable references, calling error if it returns NIL. }
    var SP: symtabp;
  begin
    findsym := nil;
    sp := symtab[hashit(fsym)];
    while sp <> nil do begin
      with sp^ do begin
        if sym <> fsym then
          sp := next
        else begin
          findsym := sp;
          sp := nil
        end
      end
    end
  end;

  {************************}
  procedure REMOVESYM(var SYMTAB: symtable; SYMP: symtabp);
    var SP: symtabp;
        HX: integer;
  begin  {remove and dispose the symtab entry SYMP}
    hx:=hashit(symp^.sym);
    sp := symtab[hx];
    if sp<>nil then begin  {may not be in table}
      if sp=symp then
      symtab[hx]:=sp^.next
      else begin
        while (sp<>nil) and (sp^.next<>symp) do sp:=sp^.next;
        if (sp<>nil) and (sp^.next=symp) then
          sp^.next:=symp^.next;  {point around it}
        end;
      dispose(symp);
      end
    end;

  {**********************}
  function MAKESYM(var SYMTAB: symtable;
                   FSYM: symbol;  SYT: symtype;  LEV: int):  symtabp;
    { this returns a symbol entry if there; makes a new one if not.
      Useful for FORTRAN-style variable declaration -- declare name
      on first appearance, whether in a declaration or not. }
    var SP: symtabp;
        HX: int;
  begin
    sp := findsym(symtab, fsym);
    if sp = nil then begin
      sp:=new_sym(syt);  { need a new one if here }
      with sp^ do begin
        { put at the head of the hash list}
        sym := fsym;
        hx := hashit(fsym);
        next := symtab[hx];
        symtab[hx] := sp;
        level := lev;
      end
    end;
    makesym := sp
  end;

  {**********************}
  function FORCESYM(var SYMTAB: symtable;
                    FSYM: symbol;  SYT: symtype;  LEV: int):  symtabp;
    { This forces a new symbol entry.  Use this for declarations
      to cover a previous declaration with the same name. }
    var SP: symtabp;
        HX: int;
  begin
    hx := hashit(fsym);
    sp:=new_sym(syt);
    with sp^ do begin
      { put at the head of the hash list. }
      sym := fsym;
      next := symtab[hx];
      symtab[hx] := sp;
      level := lev;
    end;
    forcesym := sp;
  end;

  {********************}
  procedure CLEARSYM(var SYMTAB: symtable; CLEVEL: int);
    { Sets the symbol table pointers to remove references to
      everything at level >= CLEVEL, assuming that level numbers
      are monotonic.  Prepares for a RELEASE of memory. }
    var HX: int;
        SP, KEEP: symtabp;
  begin
    { Don't clear the reserved words -- check, just in case }
    if clevel<0 then clevel := 0;
    for hx := 0 to hlimit do begin
      sp := symtab[hx];  
      keep := nil;
      while sp <> nil do begin
        if sp^.level >= clevel then sp := sp^.next
        else begin
          keep := sp;
          sp := nil;
          end
        end;
      symtab[hx] := keep;
      end
    end;


