#ifndef __ICODE2AST_H__
#define __ICODE2AST_H__ 1

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

#ifndef FALSE
#define TRUE (0==0)
#define FALSE (0!=0)
#endif

extern int opt_verbose;
extern int opt_trace;
//extern int debug;

extern int gdb_trace_active;  // Global tracing flag when running icode2ast (0: don't log; 1: log all calls) 
                              // invoke with: gdb -nx -nh -q -x auto_log.py --args ./icode2ast pass2test/pass2.icd

extern int DIAGNOSE; // %diagnose nnnn in the imp source
extern int CONTROL;  // %control  nnnn ditto.

//extern FILE *c_out;

typedef struct IMPAST IMPAST;
#define FIXED_FIELDS                                                 \
  int opcode;                                                        \
  IMPAST *next_icode;                                                \
  int seqno;                                                         \
  IMPAST *line;                                                      \
  int blocklevel;                                                    \
  int tf; int format; int ostate; /* These may be removed soon! */   \
  IMPAST *recordformatdef;                                           \
  int maxstring; /* 0 for '*', otherwise %string (maxstring) s */    \
  int linkage, type, form, special,                                  \
      is_spec, is_indirect, no_unass_check; /* derived from the compact representation above */

#define IS_SPEC(icode)         (((icode)->def.is_spec) != 0)
#define IS_INDIRECT(icode)     (((icode)->def.is_indirect) != 0)
#define NO_UNASS_CHECK(icode)  (((icode)->def.no_unass_check) != 0)

/* (According to JDM's doc, not sure what the original source was:)
An indirect object (I=1) differs from F=2 in that F=2 implies that the actual object
created will be a pointer and will be dereferenced whenever used unless explicit
action is taken (e.g. use of Assign-Reference).
If I=1 a pointer will be created (usually as an integer) and will be treated as an
integer (or address) with no automatic dereferencing taking place.
 */

#define REQUIRES_AUTO_DEREFERENCE(icode) ((FORM(((IMPAST *)icode)) == F_NAME \
                                      /*|| FORM(((IMPAST *)icode)) == F_ARRAY_NAME*/ \
                                        || FORM(((IMPAST *)icode)) == F_NAME_ARRAY_NAME \
                                        || FORM(((IMPAST *)icode)) == F_MAP) \
                                           && !IS_INDIRECT(((IMPAST *)icode)))
// Note sure if this is correct or needed:    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

// Although the AST is a linked list, it will sometimes be useful to refer to AST entries
// using an index number, especially when debugging.  The astid[] array is effectively the
// same as the icode file, in linear order.  Combined IAST pseudo-icodes are added after
// the initial icodes from the .icd file.

#define MAX_AST_ENTRIES 0x100000
extern int next_free_astid;
extern IMPAST *astid[MAX_AST_ENTRIES];

// These are done this way to only allocate the space needed for a particular variant:
#define new_icode(INSTR) ({astid[++next_free_astid] = (IMPAST *)calloc(1, sizeof(ICODE_ ## INSTR)); \
                           astid[next_free_astid]->generic.seqno = next_free_astid; \
                           astid[next_free_astid]->generic.opcode = OP_ ## INSTR;   \
                           astid[next_free_astid];})
#define new_iast(INSTR)  ({astid[++next_free_astid] = (IMPAST *)calloc(1, sizeof(IAST_  ## INSTR)); \
                           astid[next_free_astid]->generic.seqno = next_free_astid; \
                           astid[next_free_astid]->generic.opcode = ASTOP_ ## INSTR; \
                           astid[next_free_astid];})

// In AST form, ICODE_* AST objects have:
//   fixed fields that all icodes have
//   original fields per-icode extracted from the .icd file
//   derived fields added by this code

// There are also new AST objects which are compatible with an IMPAST, i.e. IAST_*

#define MAX_ARRAY_DIMS 7  // N-dimensional arrays can't have more than 6 dimensions (imp77 restriction, not mine)

typedef struct ICODE_generic       {  FIXED_FIELDS;  } ICODE_generic;

typedef struct ICODE_OR            {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_OR;

typedef struct ICODE_JUMPIFD       {
  FIXED_FIELDS;
  int cond, label;
  //-----------
  char *printable_label;
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_JUMPIFD;

typedef struct ICODE_DEF           {
  FIXED_FIELDS;
  int tag, unique_tag;
  IMPAST *deftag; // DEFTAG[tag]
  IMPAST *defuniquetag; // DEFUNIQUETAG[tag]
  char *imp_id;
  char *c_id;
  //-----------
  int suppress; // if set, do not output this DEF.
  char *printable_label;  // for %label declarations

  // I'm considering adding a backpointer to a %spec here as well.  If it is needed and helpful.
  IMPAST *previous_def;
  
  IMPAST *alias;
  
  IMPAST *formal_params;
  
  // ICodes should not in general have stack-based items attached to them unless those
  // items are always the same, eg an instance of OP_ADD will always have the same two
  // operands, determined at compile time in stack.c
  // So opcodes like DEF which *should* occur only once at the point of declaration
  // really should not have fields like 'actual_params' below which vary at the point
  // of call.  The actual_params (and similarly the indices of an array) really should
  // not be attached to the DEF here, but to the specific CALL (or ARRAYINDEX) tuple.
  // It only works here because I hacked in a stack to this actual_params, so that
  // function calls such as fred(fred(1,2,3), fred(4,5,6), fred(7,8,9)) do not mess up.
  // But it is bad design and should be restructured later.  But for now it works:
  IMPAST *actual_params; // ASSPAR attaches TOS to this linked list.
  
  IMPAST *body;

  IMPAST *recordformat_field_list; // when it is a recordformat definition, the field list
                                   // goes here, *not* in the 'recordformat' fixed field,
                                   // which always points to the recordformat definition.
  
  IMPAST *init;                    // scalar and array initialisation values

  IMPAST **switch_list; // If this DEF is declaring a %switch, this holds the array
                        // of switch labels.  If an entry is NULL, use default_switch
                        // *or* if default_switch is NULL, issue an error at runtime.
  IMPAST *default_switch;
  
  int dims; // save here to avoid counting number of boundpairs every time
  IMPAST *bounds_list; // linked list of bounds for 1- or more-D arrays,
                       // or single boundspair for a switch

  int lower_bound; // copy of data extracted from boundspair when
  int upper_bound; // it is a switch or a 1-D array, for convenience
                   // rather thsn having to poke around in a linked list.
  
  // ***TEMPORARY*** place to store actual array indices when an array is accessed.
  // However A [1] [A[2][4][6]] [3] will undoubtedly screw up so this is just for testing.
  // Probably the right place for this is the OP_PUSH of this def's tag, or the recently-
  // added ARRAYINDEX tuple. (See comment above re procedure parameters.  This is the same.)
  IMPAST *index_list; // linked list of bounds for 1- or more-D arrays,
                      // or single boundspair for a switch.  As with procedure
                      // parameter lists, I've forced it to work by treating it as a stack.
                      // The items on these stacks are just held there temporarily as they
                      // are accumlated, until we have the full set, at which pount they're
                      // transferred to the CALL or ARRAYINDEX tuples.
  
} ICODE_DEF;

typedef struct ICODE_XOR           {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_XOR;

typedef struct ICODE_AND           {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_AND;

typedef struct ICODE_PUSHS         {
  FIXED_FIELDS;
  //-----------
  int maxlen;
  int string_length;
  char *string_value;
} ICODE_PUSHS;

typedef struct ICODE_MUL           {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_MUL;

typedef struct ICODE_ADD           {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_ADD;

typedef struct ICODE_PLUS          {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_PLUS;

typedef struct ICODE_SUB           {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_SUB;

typedef struct ICODE_CONCAT        {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_CONCAT;

typedef struct ICODE_QUOT          {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_QUOT;

typedef struct ICODE_LOCATE        {
  FIXED_FIELDS;
  int label;
  //-----------
  char *printable_label;
} ICODE_LOCATE;

typedef struct ICODE_END           {
  FIXED_FIELDS;
  //-----------
  IMPAST *startblock; // back pointer to the block of which this is the end.
  char *imp_id;
  char *c_id;

} ICODE_END;

// unused in current Imp77 but unused OP_B?? are needed to make numerical values of ICodes match the .icd files.
typedef struct ICODE_BNE           {  FIXED_FIELDS;  } ICODE_BNE;
typedef struct ICODE_BLT           {  FIXED_FIELDS;  } ICODE_BLT;
typedef struct ICODE_BLE           {  FIXED_FIELDS;  } ICODE_BLE;
typedef struct ICODE_BGE           {  FIXED_FIELDS;  } ICODE_BGE;
typedef struct ICODE_BEQ           {  FIXED_FIELDS;  } ICODE_BEQ;
typedef struct ICODE_BGT           {  FIXED_FIELDS;  } ICODE_BGT;

typedef struct ICODE_JUMPIF        {
  FIXED_FIELDS;
  int cond, label;
  //-----------
  char *printable_label;
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_JUMPIF;

typedef struct ICODE_PUSH          {
  FIXED_FIELDS;
  int tag;
  int unique_tag;
} ICODE_PUSH;

typedef struct ICODE_INIT          {
  FIXED_FIELDS;
  int repeats;
  //-----------
  IMPAST *data;  // NULL means default, eg 0, 0.0, "" ...
  IMPAST *next_init;
} ICODE_INIT;

typedef struct ICODE_REPEAT        {
  FIXED_FIELDS;
  int label;
  //-----------
  //char *printable_label;
  char *printable_forlab;
  ////char *printable_exitlab;
  ////char *printable_continuelab;
} ICODE_REPEAT;

typedef struct ICODE_JUMPIFA       {
  FIXED_FIELDS;
  int cond, label;
  //-----------
  char *printable_label;
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_JUMPIFA;

typedef struct ICODE_PUSHR         {
  FIXED_FIELDS;
  int code, exponent;
  double value;
  char *str;
} ICODE_PUSHR;

typedef struct ICODE_CALL          {
  FIXED_FIELDS;
  //-----------
  int is_function;    // these are not filled in yet...
  IMPAST *def;
  IMPAST *formal_params; // copied here for convenience but also in the def
  IMPAST *actual_params;
  // we might add a 'num params' here some time too?
} ICODE_CALL;

typedef struct ICODE_GOTO          {
  FIXED_FIELDS;
  int label;
  //-----------
  char *printable_label;
} ICODE_GOTO;

typedef struct ICODE_ALIAS         {
  FIXED_FIELDS;
  char *alias;
} ICODE_ALIAS;

typedef struct ICODE_BEGIN         {
  FIXED_FIELDS;
  //-----------
  int is_main;              // is_main = true if begin/endofprogram or begin/end at external level.
  int uniqueid;
  int blockno; // filled in by genc.c if needed
  char *imp_id;
  char *c_id;
  IMPAST *body;
} ICODE_BEGIN;

typedef struct ICODE_SELECTINPUT2  {  FIXED_FIELDS;  } ICODE_SELECTINPUT2; // unused

typedef struct ICODE_JUMP          {
  FIXED_FIELDS;
  int label;
  //-----------
  char *printable_label;
} ICODE_JUMP;

typedef struct ICODE_FALSE         {  FIXED_FIELDS;  } ICODE_FALSE;

typedef struct ICODE_LABEL         {
  FIXED_FIELDS;
  int label;
  //-----------
  char *printable_label;
} ICODE_LABEL;

typedef struct ICODE_MAP           {
  FIXED_FIELDS;
  //-----------
   // %result== needs to know the type of the map (or function) whose result it is returning:
  IMPAST *mapdef;
  IMPAST *opd;
} ICODE_MAP;

typedef struct ICODE_PUSHI         {
  FIXED_FIELDS;
  long int value;
} ICODE_PUSHI;

typedef struct ICODE_LINE          {
  FIXED_FIELDS;
  int lineno;
  char *filename;
} ICODE_LINE;

typedef struct ICODE_PLANT         {
  FIXED_FIELDS;
  //-----------
  unsigned char byte;
} ICODE_PLANT;

typedef struct ICODE_DIVIDE        {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_DIVIDE;

typedef struct ICODE_RETURN        {
  FIXED_FIELDS;
  //-----------
  // back pointer to the block of which this is the end.
  // (Similar to result.fndef or map.mapdef or end.startblock. Yes I know I've been
  //  both duplicative and inconsistent :-(  Will tidy up later.)
  IMPAST *startblock;
} ICODE_RETURN;

typedef struct ICODE_ASSVAL        {
  FIXED_FIELDS;
  //-----------
  IMPAST *dest;
  IMPAST *source;
} ICODE_ASSVAL;

typedef struct ICODE_TRUE          {  FIXED_FIELDS;  } ICODE_TRUE;

typedef struct ICODE_NEGATE        {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd;
} ICODE_NEGATE;

typedef struct ICODE_RESULT        {
  FIXED_FIELDS;
  //-----------
  // %result= needs to know the type of the function (or map) whose result it is returning:
  IMPAST *fndef;
  IMPAST *opd;
} ICODE_RESULT;

typedef struct ICODE_SJUMP         {
  FIXED_FIELDS;
  int label;
  //-----------
  char *printable_label; // msy not be needed. Included here for consistency for now.
  IMPAST *index;
} ICODE_SJUMP;

typedef struct ICODE_IEXP          {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_IEXP;

typedef struct ICODE_DEFAULT       { // unused
  FIXED_FIELDS;
  int data;
} ICODE_DEFAULT;

typedef struct ICODE_ASSREF        {
  FIXED_FIELDS;
  //-----------
  IMPAST *dest;
  IMPAST *source;
} ICODE_ASSREF;

typedef struct ICODE_LSH           {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_LSH;

typedef struct ICODE_NOT           {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd;
} ICODE_NOT;

typedef struct ICODE_RSH           {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_RSH;

typedef struct ICODE_PROC          { // unused
  FIXED_FIELDS;
  int tag;
} ICODE_PROC;

typedef struct ICODE_SLABEL        {
  FIXED_FIELDS;
  int label;
  //-----------
  char *printable_label;   // may not be needed. included here for consistency for now.
  IMPAST *declaration; // points to te DEF of the %switch of which this is a label entry
  IMPAST *index; // numerical value of switch label
} ICODE_SLABEL;

typedef struct ICODE_DEFSW         { // old ICode restored for my pass1 and C
  FIXED_FIELDS;
  int label;
  //-----------
  char *printable_label;   // may not be needed. included here for consistency for now.
  IMPAST *declaration;
} ICODE_DEFSW;

typedef struct ICODE_BOUNDSPAIR        {
  FIXED_FIELDS;
  //--------
  IMPAST *lb, *ub;
  IMPAST *next_bound;
} ICODE_BOUNDSPAIR;

typedef struct ICODE_MCODE1        {  FIXED_FIELDS;  } ICODE_MCODE1; // so far, unimplemented

typedef struct ICODE_DIM           {
  FIXED_FIELDS;
  int dimens, arrays;
  IMPAST *bounds_list;
} ICODE_DIM;

typedef struct ICODE_EVENT         {
  FIXED_FIELDS;
  int event;
  IMPAST *subevent;
  IMPAST *extra;
} ICODE_EVENT;

typedef struct ICODE_FOR           {
  FIXED_FIELDS;
  int label;
  //-----------
  char *printable_forlab;
  char *printable_exitlab;
  char *printable_continuelab;
  //char *printable_label;   // may not be needed. included here for consistency for now.
  IMPAST *initial;
  IMPAST *final;
  IMPAST *increment;
  IMPAST *control;
} ICODE_FOR;

typedef struct ICODE_REDEF         {  FIXED_FIELDS;  } ICODE_REDEF; // invented for i2c, and now looks like not needed.

typedef struct ICODE_ALTBEG        {  FIXED_FIELDS;  } ICODE_ALTBEG;

typedef struct ICODE_INDEX         {
  FIXED_FIELDS;
  //-----------
  IMPAST *base;
  IMPAST *index;
  IMPAST *boundspair;
} ICODE_INDEX;

typedef struct ICODE_ACCESS        {
  FIXED_FIELDS;
  //-----------
  IMPAST *base;
  IMPAST *index;
  IMPAST *boundspair;
} ICODE_ACCESS;

typedef struct ICODE_JAM           {
  FIXED_FIELDS;
  //-----------
  IMPAST *dest;
  IMPAST *source;
} ICODE_JAM;

typedef struct ICODE_BF            {
  FIXED_FIELDS;
  int label;
  //-----------
  char *printable_label;
  IMPAST *opd;
} ICODE_BF;

typedef struct ICODE_LANG          {
  FIXED_FIELDS;
  int language;
} ICODE_LANG;

typedef struct ICODE_MONITOR       {  FIXED_FIELDS;  } ICODE_MONITOR;

typedef struct ICODE_SELECT        {
  FIXED_FIELDS;
  int fieldtag;
  //-----------
  int use_pointer;
  IMPAST *parent_record;
  IMPAST *fielddef;      // the DEF type of the field on the RHS of the '_' operator
  //IMPAST *recordformat_field_list;
  // when it is a recordformat definition, the field list goes here,
  // *not* in the 'recordformat' fixed field, which always points to
  // the recordformat definition
} ICODE_SELECT;

typedef struct ICODE_ON            {
  FIXED_FIELDS;
  int label, mask;
  //-----------
  char *printable_label;  // May not be needed? But including here for consistency
} ICODE_ON;

typedef struct ICODE_ASSPAR        {
  FIXED_FIELDS;
  //-----------
  IMPAST *param;
  IMPAST *formal_param; // Adding this (not used yet) so that actual param
                        // can be type-checked and cast if necessary against
                        // the formal param when CALLing.
  IMPAST *next_param;
} ICODE_ASSPAR;

typedef struct ICODE_SUBA          {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_SUBA;

typedef struct ICODE_RESOLVE       {
  FIXED_FIELDS;
  int flags;
  //-----------
  int conditional;
  IMPAST *opd1;
  IMPAST *opd2;
  IMPAST *string;
  IMPAST *match;
} ICODE_RESOLVE;

typedef struct ICODE_STOP          {  FIXED_FIELDS;  } ICODE_STOP;

typedef struct ICODE_BT            {
  FIXED_FIELDS;
  int label;
  //-----------
  char *printable_label;
  IMPAST *opd;
} ICODE_BT;

typedef struct ICODE_ADDA          {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_ADDA;

typedef struct ICODE_MOD           {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd;
} ICODE_MOD;

typedef struct ICODE_MCODE2        {  FIXED_FIELDS;  } ICODE_MCODE2; // so far, unimplemented

typedef struct ICODE_REXP          {
  FIXED_FIELDS;
  //-----------
  IMPAST *opd1;
  IMPAST *opd2;
} ICODE_REXP;

typedef struct ICODE_DIAG          {
  FIXED_FIELDS;
  int data;
} ICODE_DIAG;

typedef struct ICODE_CONTROL       {
  FIXED_FIELDS;
  int data;
} ICODE_CONTROL;

typedef struct ICODE_START         {
  FIXED_FIELDS;
  //-----------
  char *imp_id;
  char *c_id;
} ICODE_START;

typedef struct ICODE_ALT           {  FIXED_FIELDS;  } ICODE_ALT; // may not be used in this version of ICode

typedef struct ICODE_FINISH        {
  FIXED_FIELDS;
  //-----------
  char *imp_id;
  char *c_id;
} ICODE_FINISH;

typedef struct ICODE_ALTALT {
  FIXED_FIELDS;
  unsigned char alttype;
} ICODE_ALTALT;

typedef struct ICODE               {  FIXED_FIELDS;  } ICODE;


// Extended ICodes will be added under IAST_* ... so far I'm managing to do without them,
// though I suspect some will be needed once I start generating C output.


typedef struct IAST_PERMS {   // All the icodes from the perms which precede the user program
  FIXED_FIELDS;               // (which we locate from the first occurance of a LINE directive)
  IMPAST *perms;
} IAST_PERMS;

typedef struct IAST_RECFMSPEC { // a hacky version of %recordformatspec without all the 
  FIXED_FIELDS;                 // parameters of a proper DEF.
  char *imp_id;
  char *c_id;
  IMPAST *def;
  int tag;
  int unique_tag; // not yet used
} IAST_RECFMSPEC;


typedef struct IAST_DELETED { // A bit of a hack but sometimes we really need to suppress an ICode
  FIXED_FIELDS;               // but can't unlink it from the chain or use the used[] hack in stack.c
} IAST_DELETED;

typedef struct IAST_ADDRESS_OF { 
  FIXED_FIELDS;
  IMPAST *opd;
} IAST_ADDRESS_OF;

typedef struct IAST_INDIRECT_THROUGH {
  FIXED_FIELDS;              
  IMPAST *opd;
} IAST_INDIRECT_THROUGH;

typedef struct IAST_CAST {
  FIXED_FIELDS;              
  IMPAST *opd;
  IMPAST *def;
} IAST_CAST;

typedef struct IAST_BRACKETS {
  FIXED_FIELDS;              
  IMPAST *opd;
} IAST_BRACKETS;

typedef struct IAST_ARRAYINDEX { // being added right now.
  FIXED_FIELDS;
  IMPAST *array_def;
  IMPAST *array_base;
  IMPAST *index_value; // a single index value
  IMPAST *boundspair; // bounds for that value
  IMPAST *next_index;
} IAST_ARRAYINDEX;

typedef struct IAST_PARAM { // not yet used
  FIXED_FIELDS;              
  IMPAST *formal_parameter;
  IMPAST *actual_parameter;
} IAST_PARAM;


typedef struct IMPAST {
  union {

    ICODE_generic       generic;

    // The first group are all true ICodes:
    
    ICODE_OR            or;
    ICODE_JUMPIFD       jumpifd;
    ICODE_BNE           bne;
    ICODE_DEF           def;
    ICODE_XOR           xor;
    ICODE_AND           and;
    ICODE_PUSHS         pushs;
    ICODE_BLE           ble;
    ICODE_BGE           bge;
    ICODE_MUL           mul;
    ICODE_ADD           add;
    ICODE_PLUS          plus;
    ICODE_SUB           sub;
    ICODE_CONCAT        concat;
    ICODE_QUOT          quot;
    ICODE_LOCATE        locate;
    ICODE_END           end;
    ICODE_BLT           blt;
    ICODE_BEQ           beq;
    ICODE_BGT           bgt;
    ICODE_JUMPIF        jumpif;
    ICODE_PUSH          push;
    ICODE_INIT          init;
    ICODE_REPEAT        repeat;
    ICODE_JUMPIFA       jumpifa;
    ICODE_PUSHR         pushr;
    ICODE_CALL          call;
    ICODE_GOTO          igoto;
    ICODE_ALIAS         alias;
    ICODE_BEGIN         begin;
    ICODE_SELECTINPUT2  selectinput2;
    ICODE_JUMP          jump;
    ICODE_FALSE         ifalse;
    ICODE_LABEL         label;
    ICODE_MAP           map;
    ICODE_PUSHI         pushi;
    ICODE_LINE          line;
    ICODE_PLANT         plant;
    ICODE_DIVIDE        divide;
    ICODE_RETURN        ireturn;
    ICODE_ASSVAL        assval;
    ICODE_TRUE          itrue;
    ICODE_NEGATE        negate;
    ICODE_RESULT        result;
    ICODE_SJUMP         sjump;
    ICODE_IEXP          iexp;
    ICODE_DEFAULT       idefault;
    ICODE_ASSREF        assref;
    ICODE_LSH           lsh;
    ICODE_NOT           not;
    ICODE_RSH           rsh;
    ICODE_PROC          proc;
    ICODE_SLABEL        slabel;
    ICODE_DEFSW         defsw;
    ICODE_ACCESS        access;      // a
    ICODE_BOUNDSPAIR    boundspair;  // b
    ICODE_MCODE1        mcode1;      // c
    ICODE_DIM           dim;
    ICODE_EVENT         event;
    ICODE_FOR           ifor;
    ICODE_REDEF         redef;
    ICODE_ALTBEG        altbeg;
    ICODE_INDEX         index;
    ICODE_JAM           jam;
    ICODE_BF            bf;
    ICODE_LANG          lang;
    ICODE_MONITOR       monitor;
    ICODE_SELECT        select;
    ICODE_ON            on;
    ICODE_ASSPAR        asspar;  // p
    ICODE_SUBA          suba;    // q -                       .
    ICODE_RESOLVE       resolve; // r  \                      .
    ICODE_STOP          stop;    // s   \                     .
    ICODE_BT            bt;      // t    |--- check! swap?    .
    ICODE_ADDA          adda;    // u   /                     .
    ICODE_MOD           mod;     // v  /                      .
    ICODE_MCODE2        mcode2;  // w -                       .
    ICODE_REXP          rexp;
    ICODE_DIAG          diag;
    ICODE_CONTROL       control;
    ICODE_START         start;
    ICODE_ALT           alt;
    ICODE_FINISH        finish;
    ICODE_ALTALT        altalt;

    // From here down, not true icodes, but higher-level AST items
    // constructed by this code to make C generation easier.
    
    IAST_PERMS          perms;
    IAST_RECFMSPEC      recfmspec;
    IAST_DELETED        deleted;
    IAST_ADDRESS_OF     address_of;
    IAST_INDIRECT_THROUGH indirect_through;
    IAST_CAST           cast;
    IAST_BRACKETS       brackets;
    IAST_ARRAYINDEX     array_index;
    IAST_PARAM          param;
  };
} IMPAST;

enum OP { // these *must* match the numeric order of icodes, starting at 0, no gaps
  OP_0,
  OP_1,
  OP_2,
  OP_3,
  OP_4,
  OP_5,
  OP_6,
  OP_7,
  OP_8,
  OP_9,
  OP_10,
  OP_11,
  OP_12,
  OP_13,
  OP_14,
  OP_15,
  OP_16,
  OP_17,
  OP_18,
  OP_19,
  OP_20,
  OP_21,
  OP_22,
  OP_23,
  OP_24,
  OP_25,
  OP_26,
  OP_27,
  OP_28,
  OP_29,
  OP_30,
  OP_31,
  OP_32,
  OP_OR,
  OP_JUMPIFD,
  OP_BNE,
  OP_DEF,
  OP_XOR,
  OP_AND,
  OP_PUSHS,
  OP_BLE,
  OP_BGE,
  OP_MUL,
  OP_ADD,
  OP_PLUS,
  OP_SUB,
  OP_CONCAT,
  OP_QUOT,
  OP_SYM0,
  OP_SYM1,
  OP_SYM2,
  OP_SYM3,
  OP_SYM4,
  OP_SYM5,
  OP_SYM6,
  OP_SYM7,
  OP_SYM8,
  OP_SYM9,
  OP_LOCATE,
  OP_END,
  OP_BLT,
  OP_BEQ,
  OP_BGT,
  OP_JUMPIF,
  OP_PUSH,
  OP_INIT      = 'A',
  OP_REPEAT    = 'B',
  OP_JUMPIFA   = 'C',
  OP_PUSHR     = 'D',
  OP_CALL      = 'E',
  OP_GOTO      = 'F',
  OP_ALIAS     = 'G',
  OP_BEGIN     = 'H',
  OP_SELECTINPUT2 = 'I',
  OP_JUMP      = 'J',
  OP_FALSE     = 'K',
  OP_LABEL     = 'L',
  OP_MAP       = 'M',
  OP_PUSHI     = 'N',
  OP_LINE      = 'O',
  OP_PLANT     = 'P',
  OP_DIVIDE    = 'Q',
  OP_RETURN    = 'R',
  OP_ASSVAL    = 'S',
  OP_TRUE      = 'T',
  OP_NEGATE    = 'U',
  OP_RESULT    = 'V',
  OP_SJUMP     = 'W',
  OP_IEXP      = 'X',
  OP_DEFAULT   = 'Y',
  OP_ASSREF    = 'Z',
  OP_LSH,
  OP_NOT,
  OP_RSH,
  OP_PROC,
  OP_SLABEL,
  OP_DEFSW,
  OP_ACCESS     = 'a',
  OP_BOUNDSPAIR = 'b',
  OP_MCODE1     = 'c',
  OP_DIM        = 'd',
  OP_EVENT      = 'e',
  OP_FOR        = 'f',

  OP_REDEF      = 'g',
  // replacement for DEF in rewritten icode so that it is not output as C
  // This is for the procedure parameter procedure which is repeated inside
  // the procedure after the abbreviated version was in the FP list.
  // This rewrite puts the full version inside the parameter list as well
  // as following it: the first instance is for being output in C and
  // the second instance is for i2c to use when calling the passed procedure
  // inside the enclosing procedure.  So 'REDEF' is an invisible 'DEF' -
  // handled exactly as DEF was before, but not printed out.

  OP_ALTBEG     = 'h',
  OP_INDEX      = 'i',
  OP_JAM        = 'j',
  OP_BF         = 'k',
  OP_LANG       = 'l',
  OP_MONITOR    = 'm',
  OP_SELECT     = 'n',
  OP_ON         = 'o',
  OP_ASSPAR     = 'p',
  OP_SUBA       = 'q',
  OP_RESOLVE    = 'r',
  OP_STOP       = 's',
  OP_BT         = 't',
  OP_ADDA       = 'u',
  OP_MOD        = 'v',
  OP_MCODE2     = 'w',
  OP_REXP       = 'x',
  OP_DIAG       = 'y',
  OP_CONTROL    = 'z',
  OP_START,
  OP_ALT,
  OP_FINISH,
  OP_ALTALT,
  OP_127,

  // reserved for later versions of ICode:

  op_128, op_129, op_130, op_131, op_132, op_133, op_134, op_135,
  op_136, op_137, op_138, op_139, op_140, op_141, op_142, op_143,
  op_144, op_145, op_146, op_147, op_148, op_149, op_150, op_151,
  op_152, op_153, op_154, op_155, op_156, op_157, op_158, op_159,
  op_160, op_161, op_162, op_163, op_164, op_165, op_166, op_167,
  op_168, op_169, op_170, op_171, op_172, op_173, op_174, op_175,
  op_176, op_177, op_178, op_179, op_180, op_181, op_182, op_183,
  op_184, op_185, op_186, op_187, op_188, op_189, op_190, op_191,
  op_192, op_193, op_194, op_195, op_196, op_197, op_198, op_199,
  op_200, op_201, op_202, op_203, op_204, op_205, op_206, op_207,
  op_208, op_209, op_210, op_211, op_212, op_213, op_214, op_215,
  op_216, op_217, op_218, op_219, op_220, op_221, op_222, op_223,
  op_224, op_225, op_226, op_227, op_228, op_229, op_230, op_231,
  op_232, op_233, op_234, op_235, op_236, op_237, op_238, op_239,
  op_240, op_241, op_242, op_243, op_244, op_245, op_246, op_247,
  op_248, op_249, op_250, op_251, op_252, op_253, op_254, op_255,
  
  // From here down, these are pseudo-icodes for higher-level objects
  // constructed from the input ICodes.

  ASTOP_PERMS,
  ASTOP_RECFMSPEC,
  ASTOP_DELETED,
  ASTOP_ADDRESS_OF,
  ASTOP_INDIRECT_THROUGH,
  ASTOP_CAST,
  ASTOP_BRACKETS,
  ASTOP_ARRAYINDEX, // a tuple of the index value and the appropriate bounds for that index
  ASTOP_PARAM, // not yet used 
  // and an unused code to self-determine thesize of this enumeration:
  LAST_OP
};

// Type
#define T_NONE 0
#define T_INTEGER 1
#define T_REAL 2
#define T_STRING 3
#define T_RECORD 4
#define T_BOOLEAN 5
#define T_SET 6
#define T_BYTE_ENUMERATED 7
#define T_SHORT_ENUMERATED 8
#define T_POINTER 9
#define T_CHAR 10
#define T_GENERAL 15

// Special
#define SPECIAL_DEFAULT 0
#define SPECIAL_BYTE_INT 1
#define SPECIAL_SHORT_INT 2
#define SPECIAL_LONG_REAL 3
#define SPECIAL_LONG_INT 3 // gt addition

// Form
#define F_VOID 0
#define F_SIMPLE 1
#define F_NAME 2
#define F_LABEL 3
#define F_RECORDFORMAT 4
#define F_SWITCH 6
#define F_ROUTINE 7
#define F_FN 8
#define F_MAP 9
#define F_PREDICATE 10
#define F_ARRAY 11
#define F_ARRAY_NAME 12
#define F_NAME_ARRAY 13
#define F_NAME_ARRAY_NAME 14
#define F_EXPR 15                  // Invented code to use for composite nodes...

// Linkage
#define L_AUTO 0
#define L_OWN 1
#define L_CONSTANT 2
#define L_EXTERNAL 3
#define L_SYSTEM 4
#define L_DYNAMIC 5
#define L_PRIM 6
#define L_PERM 7

#define FORM(icode) (((icode) == NULL) ? 0 : (icode)->generic.form)
#define TYPE(icode) (((icode) == NULL) ? 0 : (icode)->generic.type)

#define IS_PROCEDURE(icode) ((icode) == NULL ? 0 : (         \
                                (FORM(icode) == F_ROUTINE)   \
                             || (FORM(icode) == F_FN)        \
                             || (FORM(icode) == F_MAP)       \
                             || (FORM(icode) == F_PREDICATE)))

//#define IN_ENCLOSING_PROCEDURE (forms[next_free_form-1] != F_RECORDFORMAT)


#define OP(icode)   ((icode) == NULL ? 0    : (icode)->generic.opcode)
#define NEXT(icode) ((icode) == NULL ? NULL : (icode)->generic.next_icode)

#define MAX_CHUNKS (16*1024)

/* Headers for icode2ast.c */
extern IMPAST *read_one_icode(void); 
extern IMPAST *load_icode_file(void); 

extern void push_spec(int spec); 
extern int pop_spec(void);

//extern int next_free_form;
//extern int forms[MAX_CHUNKS];
extern void push_form(int form); 
extern int pop_form(void);

extern int DEFINE_UNIQUE_TAG(int raw_tag, IMPAST *def);
extern int LOOKUP_UNIQUE_TAG(int raw_tag);

extern void control(int bits);
extern void diagnose(int bits);

/* End of headers for icode2ast.c */
#endif // !__ICODE2AST_H__
