/* starsym.c -- STAR-Dependent Symbol Table Operations

This file is part of STAR, the Saturn Macro Assembler.

   STAR is not distributed by the Free Software Foundation. Do not ask
them for a copy or how to obtain new releases. Instead, send e-mail to
the address below. STAR is merely covered by the GNU General Public
License.

Please send your comments, ideas, and bug reports to
Jan Brittenson <bson@ai.mit.edu>

*/


/* Copyright (C) 1991 Jan Brittenson.

   STAR is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 1, or (at your option) any
later version.

   STAR is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.

   You should have received a copy of the GNU General Public License
along with STAR; see the file COPYING. If not, to obtain a copy, write
to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
USA, or send e-mail to bson@ai.mit.edu. */

#include <stdio.h>
#include "sects.h"
#include "star.h"
#include "symbols.h"


SYM_NODE
  *sym_list,			/* `LIST' symbol */
  *sym_stdsect,			/* `STDSECT' symbol */
  *sym_cursect;			/* `SECT' symbol */


SYM_ROOT
  *symtbl;			/* Global symbol table */

int
  nhidden;			/* # of hidden symbols (at end of run) */


extern char *malloc();
extern void free();


/* Initialize symbol table */
initsym()
{ 
  struct val v;
  extern double version_real;
  extern SECT *stdsect;
  
  
  /* Create symbol table root */
  symtbl = sm_open(malloc, free);

  v.type = VT_INT;
  v.vint = 48;

  sm_enter_sym(symtbl, "SATURN", v, F_REF+F_HID);

  sm_enter_sym(symtbl, "MP", intval(3), F_HID+F_REF);
  sm_enter_sym(symtbl, "SR", intval(2), F_HID+F_REF);
  sm_enter_sym(symtbl, "SB", intval(1), F_HID+F_REF);
  sm_enter_sym(symtbl, "XM", intval(0), F_HID+F_REF);
  sm_enter_sym(symtbl, "VERSION", realval(version_real), F_HID+F_REF);

  sm_enter_sym(symtbl, "PI", realval(3.14159265358979323846), F_HID+F_REF);
  sm_enter_sym(symtbl, "LN2", realval(0.69314718055994530942), F_HID+F_REF);
  sm_enter_sym(symtbl, "SQRT2", realval(1.41421356237309504880), F_HID+F_REF);
  sm_enter_sym(symtbl, "E", realval(2.7182818284590452354), F_HID+F_REF);
  sm_enter_sym(symtbl, "LOG2E", realval(1.4426950408889634074), F_HID+F_REF);
  sm_enter_sym(symtbl, "LOG10E", realval(0.43429448190325182765), F_HID+F_REF);
  sm_enter_sym(symtbl, "LN10", realval(2.30258509299404568402), F_HID+F_REF);

  sym_list = sm_enter_sym(symtbl, "LIST", intval(1), F_HID+F_REF);
  sym_stdsect = sm_enter_sym(symtbl, "STDSECT", val_zero, F_HID+F_REF);
  sym_cursect = sm_enter_sym(symtbl, "SECT", val_zero, F_HID+F_REF);

  sym_cursect->value.type = sym_stdsect->value.type = VT_SECT;

  sym_cursect->value.vsect = sym_stdsect->value.vsect= stdsect;
  stdsect->sc_symbol = sym_stdsect;

  sm_enter_sym(symtbl, "BITS", intval(sizeof(INT)*8), F_HID+F_REF);
}


/* Add symbol, as undefined, if not in symbol table */
SYM_NODE *symref(symid)
  char *symid;
{
  SYM_NODE *sym;

  /* Simply return it if it already exists */
  if(sym = sm_find_sym(symtbl, symid))
    return(sym);

  /* Otherwise create it, but mark as unbound */
  return(sm_enter_sym(symtbl, symid, val_zero, F_UDF));
}


/* Compare two reference entries for qsort */
static refcmp(r1, r2)
  SYM_NODE **r1, **r2;
{
  extern scmp();

  return(scmp((*r1)->name, (*r2)->name));
}


/* Add symbol tree to reference array */
static void add_sym_to_table(symp, slot, nsymp)
  SYM_NODE *symp, ***slot;
  int *nsymp;
{
  for(; symp; symp = symp->sgt)
    {
      /* Add less-than branch */
      if(symp->slt)
	add_sym_to_table(symp->slt, slot, nsymp);
      
      /* Update statistics */
      if(symp->flags & (F_UDF|F_HID) == F_HID)
	nhidden++;

      /* Add this node */
      if(!(symp->flags & (F_UDF | F_HID)) &&
	 !(symp->name[0] == 'L' && symp->name[1] == '_'))
	{
	  *(*slot)++ = symp;
	  (*nsymp)++;
	}
    }
}


/* Return symbol table reference, suitable for printing */
SYM_NODE **create_sym_ref(nsymp)
  int *nsymp;
{
  SYM_NODE **refarr, **curslot, **curhash;
  extern char *malloc();


  /* Allocate reference array */
  if(!(refarr = (SYM_NODE **) malloc(symtbl->nsymbols * sizeof(SYM_ROOT **))))
    fatal("Can't allocate %d bytes for symbol table reference",
	  symtbl->nsymbols * sizeof(SYM_ROOT));


  /* Add references tree by tree */
  for(*nsymp = 0,
      curslot = refarr,
      curhash = symtbl->sm_slot,
      nhidden = 0;

      curhash < symtbl->sm_slot + SYM_NHASH;

      add_sym_to_table(*curhash++, &curslot, nsymp));


  /* Sort the reference array */
  qsort((char *) refarr, *nsymp, sizeof(SYM_NODE *), refcmp);

  /* Return it */
  return(refarr);
}
