/*
 *      install --- add a symbol to the table
 */
int install (char *str, int val) {
  struct link *lp;
  struct nlist *np, *p, *backp;
  int i;

  if (!alpha (*str)) {
    error ("Illegal Symbol Name");
    return (NO);
  }
  if ((np = lookup (str)) != NULL) {
    if (Pass == 2) {
      if (np->def == val)
        return (YES);
      else {
        error ("Phasing Error");
        return (NO);
      }
    }
    error ("Symbol Redefined");
    return (NO);
  }
  /* enter new symbol */
  if (DEBUG) {
    fprintf (stderr, "Installing %s as %d\n", str, val);
  }
  np = (struct nlist *) malloc (sizeof (struct nlist));
  if (np == (struct nlist *) ERR) {
    error ("Symbol table full");
    return (NO);
  }
  np->name = malloc (strlen (str) + 1);
  if (np->name == (char *) ERR) {
    error ("Symbol table full");
    return (NO);
  }
  strcpy (np->name, str);
  np->def = val;
  np->Lnext = NULL;
  np->Rnext = NULL;
  lp = (struct link *) malloc (sizeof (struct link));
  np->L_list = lp;
  lp->L_num = Line_num;
  lp->next = NULL;
  p = root;
  backp = NULL;
  while (p != NULL) {
    backp = p;
    i = strcmp (str, p->name);
    if (i < 0)
      p = p->Lnext;
    else
      p = p->Rnext;
  }
  if (backp == NULL)
    root = np;
  else if (strcmp (str, backp->name) < 0)
    backp->Lnext = np;
  else
    backp->Rnext = np;
  return (YES);
}

/*
 *      lookup --- find string in symbol table
 */
struct nlist *lookup (char *name) {
  struct nlist *np;
  int i;

  np = root;
  while (np != NULL) {
    i = strcmp (name, np->name);
    if (i == 0) {
      Last_sym = np->def;
      return (np);
    } else if (i < 0)
      np = np->Lnext;
    else
      np = np->Rnext;
  }
  Last_sym = 0;
  if (Pass == 2)
    error ("symbol Undefined on pass 2 - %s", name);
  return (NULL);
}

#define NMNE (sizeof(table)/ sizeof(struct oper))
#define NPSE (sizeof(pseudo)/ sizeof(struct oper))
/*
 *      mne_look --- mnemonic lookup
 *
 *      Return pointer to an oper structure if found.
 *      Searches both the machine mnemonic table and the pseudo table.
 */
struct oper *mne_look (char *str) {
  struct oper *low, *high, *mid;
  int cond;

  /* Search machine mnemonics first */
  low = &table[0];
  high = &table[NMNE - 1];
  while (low <= high) {
    mid = low + (high - low) / 2;
    if ((cond = strcmp (str, mid->mnemonic)) < 0)
      high = mid - 1;
    else if (cond > 0)
      low = mid + 1;
    else
      return (mid);
  }

  /* Check for pseudo ops */
  low = &pseudo[0];
  high = &pseudo[NPSE - 1];
  while (low <= high) {
    mid = low + (high - low) / 2;
    if ((cond = strcmp (str, mid->mnemonic)) < 0)
      high = mid - 1;
    else if (cond > 0)
      low = mid + 1;
    else
      return (mid);
  }

  return (NULL);
}
