/* %%%%%%%%%%%%%%%%%%%% (c) William Landi 1991 %%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* Permission to use this code is granted as long as the copyright */
/* notice remains in place. */
/* ============================== op_tab =================================== */
/* Defines and allows for loop up in the OPERATOR TABLE                      */
#include <stdio.h>
#include <string.h>
#include "pseudo.h"

/* ---------------- Possible formats for instructions.                       */
enum formats {ONE,TWO,THREE_FOUR,PSEUDO,NOT_FOUND};
/* ---------------- Possible operand types --------------------------------- */
enum operands 
   {NONE,REG,REG_REG,MEM,REG_NUM,NUM,PSEUDO_LOC,PSEUDO_NOLOC,PSEUDO_ADDR};

/* ---------------- Structure of the operator table                          */
struct OP_ENTRY {
  char *MNEMONIC;                /* Name of the operator                     */
  enum formats FORMAT;           /* FORMAT of this operator                  */
  char *OPCODE;                  /* OPCODE for this operator                 */
  enum operands OPERAND;         /* Number and type of operands              */
  int FUNCTION;                  /* Function to execute is PASS1. Pseudo     */
                                 /* operators only.                          */
};


#define NUM_OPCODES               59  /* number of opcodes in the table */
                                      /* NOT counting the NOT_FOUND entry */

/* table (sorted array) of keywords used in EMITID */
struct OP_ENTRY OP_TABLE[] = 
   {{"ADD",THREE_FOUR,"18",MEM,NULL},    
    {"ADDR",TWO,"90",REG_REG,NULL},
    {"AND",THREE_FOUR,"40",MEM,NULL},    
    {"BYTE",PSEUDO,"  ",PSEUDO_LOC,PSEUDO_BYTE0},
    {"CLEAR",TWO,"B4",REG,NULL},         
    {"COMP",THREE_FOUR,"28",MEM,NULL},
    {"COMPR",TWO,"A0",REG_REG,NULL},     
    {"CSECT",PSEUDO,"  ",PSEUDO_ADDR,PSEUDO_CSECT0},
    {"DIV",THREE_FOUR,"24",MEM,NULL},    {"DIVR",TWO,"9C",REG_REG,NULL},
    {"END",PSEUDO,"  ",PSEUDO_LOC,PSEUDO_END0},
    {"EQU",PSEUDO,"  ",PSEUDO_ADDR,PSEUDO_EQU0},
    {"EXTDEF",PSEUDO,"  ",PSEUDO_NOLOC,PSEUDO_EXTDEF0},
    {"EXTREF",PSEUDO,"  ",PSEUDO_NOLOC,PSEUDO_EXTREF0},
    {"HIO",ONE,"F4",NONE,NULL},          {"J",THREE_FOUR,"3C",MEM,NULL},
    {"JEQ",THREE_FOUR,"30",MEM,NULL},    {"JGT",THREE_FOUR,"34",MEM,NULL},
    {"JLT",THREE_FOUR,"38",MEM,NULL},    {"JSUB",THREE_FOUR,"48",MEM,NULL},
    {"LDA",THREE_FOUR,"00",MEM,NULL},    {"LDB",THREE_FOUR,"68",MEM,NULL},
    {"LDCH",THREE_FOUR,"50",MEM,NULL},   {"LDL",THREE_FOUR,"08",MEM,NULL},
    {"LDS",THREE_FOUR,"6C",MEM,NULL},    {"LDT",THREE_FOUR,"74",MEM,NULL},
    {"LDX",THREE_FOUR,"04",MEM,NULL},    {"LPS",THREE_FOUR,"D0",MEM,NULL},
    {"MUL",THREE_FOUR,"20",MEM,NULL},    {"MULR",TWO,"98",REG_REG,NULL},
    {"OR",THREE_FOUR,"44",MEM,NULL},     {"RD",THREE_FOUR,"D8",MEM,NULL},
    {"RESB",PSEUDO,"  ",PSEUDO_LOC,PSEUDO_RESB0},
    {"RESW",PSEUDO,"  ",PSEUDO_LOC,PSEUDO_RESW0},
    {"RMO",TWO,"AC",REG_REG,NULL},       {"RSUB",THREE_FOUR,"4C",NONE,NULL},
    {"SHIFTL",TWO,"A4",REG_NUM,NULL},    {"SHIFTR",TWO,"A8",REG_NUM,NULL},
    {"SIO",ONE,"F0",NONE,NULL},          {"SSK",THREE_FOUR,"EC",MEM,NULL},
    {"STA",THREE_FOUR,"0C",MEM,NULL},    
    {"START",PSEUDO,"  ",PSEUDO_ADDR,PSEUDO_START0},
    {"STB",THREE_FOUR,"78",MEM,NULL},    {"STCH",THREE_FOUR,"54",MEM,NULL},
    {"STI",THREE_FOUR,"D4",MEM,NULL},    {"STL",THREE_FOUR,"14",MEM,NULL},
    {"STS",THREE_FOUR,"7C",MEM,NULL},    {"STSW",THREE_FOUR,"E8",MEM,NULL},
    {"STT",THREE_FOUR,"84",MEM,NULL},    {"STX",THREE_FOUR,"10",MEM,NULL},
    {"SUB",THREE_FOUR,"1C",MEM,NULL},    {"SUBR",TWO,"94",REG_REG,NULL},
    {"SVC",TWO,"B0",NUM,NULL},           {"TD",THREE_FOUR,"E0",MEM,NULL},
    {"TIO",ONE,"F8",NONE,NULL},          {"TIX",THREE_FOUR,"2C",MEM,NULL},
    {"TIXR",TWO,"B8",REG,NULL},          {"WD",THREE_FOUR,"DC",MEM,NULL},
    {"WORD",PSEUDO,"  ",PSEUDO_LOC,PSEUDO_WORD0},
/* the next entry must always be last                                        */
    {"*END OF TABLE*",NOT_FOUND,"00",NONE,NULL}};


/* ---------------------------- LOOK_UP_OP --------------------------------- */
/* Find operator in the table. Return the entry if it is found, else return  */
/* the not found entry. Uses BINARY SEARCH.                                  */
struct OP_ENTRY *LOOK_UP_OP(char OP[])
{
  int LOW = 0,           /* LOWest element in OP_TABLE that may be the OP    */
    HIGH = NUM_OPCODES-1,/* HIGHest element that may be the OP               */
    MIDDLE;              /* (LOW+HIGH)/2... next element considering         */

  int CMP;               /* stores the result of a string comparison;        */
			 /*  0 str1 = str2, 1 str1 > str2, -1 str1 < str2    */

  MIDDLE = 0;
  while (LOW <= HIGH) 
    { 
      MIDDLE = (HIGH + LOW)/2;
      if (!(CMP = strcmp(OP_TABLE[MIDDLE].MNEMONIC,OP)))
	return &OP_TABLE[MIDDLE];
      if (CMP > 0)
	HIGH = MIDDLE - 1;
      else LOW = MIDDLE + 1;
    }
  return &OP_TABLE[NUM_OPCODES];
}
