
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>

#include "ast.h"
#include "icode.h"
extern FILE *icode_file;
extern int PARM_DEBUG;

const char *icode_name[256] = {
"<0>", "<1>", "<2>", "<3>", "<4>", "<5>", "<6>", "<7>",
"<8>", "<9>", "<10>", "<11>", "<12>", "<13>", "<14>", "<15>",
"<16>", "<17>", "<18>", "<19>", "<20>", "<21>", "<22>", "<23>",
"<24>", "<25>", "<26>", "<27>", "<28>", "<29>", "<30>", "<31>",
/* SP    !     "                   #      $     %       &     '  */
"<32>", "OR", "JUMPIFD", "BNE", "DEF", "XOR", "AND", "PUSHS",
/* (    )      *      +      ,      -      .         /                 */
"ble", "bge", "MUL", "ADD", "+  ", "SUB", "CONCAT", "QUOT",
/*  0     1        2        3        4        5        6        7      */
"<'0'>", "<'1'>", "<'2'>", "<'3'>", "<'4'>", "<'5'>", "<'6'>", "<'7'>",
/*  8     9        :         ;      <      =      >      ?             */
"<'8'>", "<'9'>", "LOCATE", "END", "blt", "beq", "bgt", "JUMPIF",
/*  @    A       B         C                      D        E       F      G */
"PUSH", "INIT", "REPEAT", "JUMPIFA", "PUSHR", "CALL", "GOTO", "ALIAS",
/*  H     I                 J       K        L        M      N       O */
"BEGIN", "select-input-2", "JUMP", "FALSE", "LABEL", "MAP", "PUSHI", "LINE",
/*  P     Q         R         S         T       U         V         W  */
"PLANT", "DIVIDE", "RETURN", "ASSVAL", "TRUE", "NEGATE", "RESULT", "SJUMP",
/*  X    Y          Z         [      \      ]      ^       _           */
"IEXP", "DEFAULT", "ASSREF", "LSH", "NOT", "RSH", "PROC", "SLABEL",
/*  `     a         b         c        d      e        f      g        */
"DEFSWLABEL", "ACCESS", "BOUNDS", "MCODE", "DIM", "EVENT", "FOR", "<'g'>",
/*   h     i        j      k     l       m          n         o        */
"ALTBEG", "INDEX", "JAM", "BF", "LANG", "MONITOR", "SELECT", "ON",
/*   p     q         r          s       t     u      v       w         */
"ASSPAR", "ALTEND", "RESOLVE", "STOP", "BT", "ADDA", "MOD", "SUBA",
/*  x    y       z          {        |      }         ~          DEL   */
"REXP", "DIAG", "CONTROL", "START", "ALT", "FINISH", "pending", "<127>",

"<128-255>", "<128-255>", "<128-255>", "<128-255>",
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
/*   SP  !   "   #   $   %   &   '   (   )   *   +   ,   -   .   / */
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
/*   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ? */
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
/*   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O */
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
/*   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _ */
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
/*   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o */
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
/*   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~ DEL */
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
"<128-255>", "<128-255>", "<128-255>", "<128-255>",
};

// having separate arrays here for compiler labels and user labels may
// not be needed.  I'll re-examine this *after* I have user labels working...

int label_id[MAX_LABEL_IDS];        /* init to 0 means not used */
int user_label_id[MAX_LABEL_IDS];   /* init to 0 means not used */
static int next_label_id = 0;           // start at L_0001
static int next_user_label_id = 0x0FFF; // start at U_1000

int get_next_user_label(void) {
  next_user_label_id += 1;
  if (next_user_label_id >= MAX_LABEL_IDS) {
    fprintf(stderr, "* Ran out of label IDs!!!\n");
    exit(1);
  }
  //fprintf(stderr, "next user label: %08x\n", next_user_label_id);
  return next_user_label_id;
}



int get_next_label_id(void) {
  next_label_id += 1;
  if (next_label_id >= MAX_LABEL_IDS) {
    fprintf(stderr, "* Ran out of label IDs!!!\n");
    exit(1);
  }
  //fprintf(stderr, "next lab: %08x\n", next_label_id);
  return next_label_id;
}

int get_icode(FILE *f) {
  int c = fgetc(f);
  if (c != EOF) {
    c &= 0xFF;
#ifdef NEVER
    if (PARM_DEBUG) {
      if ('!' <= c && c <= '~') {
        fprintf(stderr, "'%c':\n", c);
      } else if ((('!'|128) <= (c|128)) && ((c|128) <= ('~'|128))) {
        fprintf(stderr, "128+'%c':\n", c&127);
      } else {
        fprintf(stderr, "%d:\n", c);
      }
    }
#endif
  }
  return(c);
}

int getbyte(void) {
  int c;
  c = get_icode(icode_file); assert(c != EOF);
  return c&255;
}

int getshort(void) {
  int i, c;
  int word = 0;
  for (i = 0; i < 2; i++) {
    word = word << 8 | (c = get_icode(icode_file));
    assert(c != EOF);
  }
  return word;
}

int gettag(void) { // alias of getshort just to emphasise type of the object is a tag. May later include range checking.
  //int i = get_icode(icode_file); // force byte order
  //return (i << 8) + get_icode(icode_file);
  return getshort();
}

int getwordconst(void) {
  int i, c;
  int word = 0;
  for (i = 0; i < 4; i++) {
    word = word << 8 | (c = get_icode(icode_file));
    assert(c != EOF);
  }
  return word;
}

char *getname(void) { /* A Hack */
  static char local[256];
  int c;
  char *s = local;

  for (;;) {
    c = get_icode(icode_file);
    assert(c != EOF);
    if ((isalpha(c) && isupper(c)) || isdigit(c)) { } else break;
    *s++ = c;
  }
  *s = '\0';
  ungetc(c, icode_file);
  return(local);
}

char *getrawstring(void) {
  static char local[256*2+3];
  int i, c, len;
  char *s = local;
  len = get_icode(icode_file); assert(len != EOF);
  for (i = 0; i < len; i++) {
    c = get_icode(icode_file); assert(c != EOF);
    *s++ = c;
  }
  *s++ = '\0';
  return(local);
}

char *getimpstring(void) {
  static char local[256*2+3];
  int i, c, len;
  char *s = local;
  len = get_icode(icode_file); assert(len != EOF);
  //*s++ = '"';
  for (i = 0; i < len; i++) {
    c = get_icode(icode_file); assert(c != EOF);
    // Working on this at the moment: dump_imp_to_c_string in ast.h
    /*if (c == '"') {
      *s++ = '\\';
      *s++ = c;
    } else if (c == '\n') {
      *s++ = '\\';
      *s++ = 'n';
      } else */ *s++ = c;
  }
  //*s++ = '"';
  *s++ = '\0';
  return(local);
}

char *getmcstring(int *cp) {
  static char local[256*2+3];
  int c;
  char *s = local;
  for (;;) {
    c = get_icode(icode_file); assert(c != EOF);
    if ((c == ' ') || (c == ';')) {
      *s++ = '\0';
      *cp = c;
      return(local);
    }
    *s++ = c;
  }
}

short int getforwardlab_from_tag(short int *tag) {
   /* target for an if (..) goto skip; inst(); skip: */
   int i, c;
   short int lab;
   int word = 0;

   for (i = 0; i < 2; i++) {
      word = word << 8 | (c = get_icode (icode_file));
      assert (c != EOF);
   }
   if (word < 0 || word >= MAX_LABEL_IDS) {
     fprintf(stderr, "word = %d (%08x)\n", word, word);
     assert((word >= 0) && (word+2 < MAX_LABEL_IDS));
   }
   *tag = word;

   lab = label_id[word];
   /* there may be several jumps to this later label */
   if (lab == 0) {
     lab = label_id[word]   = get_next_label_id();
     //           label_id[word+1] = get_next_label_id();
     //           label_id[word+2] = get_next_label_id();
   }
   return lab;
}
