#ifndef __SHOWICODE_C__
#define __SHOWICODE_C__ 1

// This module does not alter any data structures.  It is solely for debugging output.

#include "icode2ast.h"
#include "icode2ast_data.h"
#include "showicode.h"
#include "stack.h"
#include "errorf.h"

static char *indent(int lev) {
  static char s[256];
return "";  
  if (lev > 40) lev = 40;
  sprintf(s, "%*s", lev * 2, "");
  
  //char *sp = s;
  //*sp = '\0';
  //lev += 1;
  //if (lev > 64) lev = 64;
  //while (lev --> 0) {
  //  *sp++ = ' '; *sp++ = ' ';
  //}
  //*sp = '\0';
  
  return s;
}

static int blocklevel;
void init_show_icode(void) {
  blocklevel = 0;
}

void generic(FILE *out, IMPAST *this) {
  //int tf = this->generic.tf; // a
  //int format = this->generic.format; // b
  //int ostate = this->generic.ostate; // c
  int linkage = this->generic.linkage;
  int type = this->generic.type;
  int form = this->generic.form;
  int special = this->generic.special;
  
  fprintf(out,
          " a/tf=0x%04x b/format=0x%04x c/ostate=0x%04x"
          "  type=%d (%s) form=%d (%s) special=%d (%s)"
          "  linkage=%d (%s) spec=%d indirect=%d no_unass_check=%d LINE %d ",
          this->generic.tf, this->generic.format, this->generic.ostate,
          type, typedesc[type],
          form, formdesc[form],
          special, specialdesc[special],
          linkage, linkagedesc[linkage],
          IS_SPEC(this), IS_INDIRECT(this), NO_UNASS_CHECK(this),
          this->generic.line == NULL ? 0 : this->generic.line->line.lineno
         );
}

void show_icode(IMPAST *this, FILE *out) {

  
  if (this == NULL) {
    
    return;
  }

  //debugf("show_icode: this = %p\n");
  
  if (this->generic.seqno > next_free_astid) {
    errorf("This is AST entry %d but next_free_astid = %d\n", this->generic.seqno, next_free_astid);
  }
  
  int opcode = this->generic.opcode;

  if (opcode >= LAST_OP) {
    fprintf(stderr, "* showicode.c: [%05d] Bad opcode: %x(0x%08x)\n", this->generic.seqno, opcode, opcode);
    exit(EXIT_FAILURE);
  }

  blocklevel = this->generic.blocklevel;
  
  fprintf(out, "[%0d] {next=%05d} ", blocklevel, (this->generic.next_icode == NULL ? 0 : this->generic.next_icode->generic.seqno));
  switch(opcode) {

  case ASTOP_PERMS:
      fprintf(out, "%s [%05d] ! %s <perms>", indent(blocklevel), this->perms.seqno, icode_name[opcode]);
      break;

  case ASTOP_RECFMSPEC:
    break;
    
  case ASTOP_DELETED:
      fprintf(out, "%s [%05d] ! %s <DELETED OPERATION>", indent(blocklevel), this->deleted.seqno, icode_name[opcode]);
      break;
      
  case ASTOP_ADDRESS_OF:
      fprintf(out, "%s [%05d] ! %s <C: ADDRESS OF>", indent(blocklevel), this->deleted.seqno, icode_name[opcode]);
      break;
      
  case ASTOP_INDIRECT_THROUGH:
      fprintf(out, "%s [%05d] ! %s <C: INDIRECT THROUGH>", indent(blocklevel), this->deleted.seqno, icode_name[opcode]);
      break;

  case ASTOP_CAST:
      fprintf(out, "%s [%05d] ! %s <C: CAST>", indent(blocklevel), this->deleted.seqno, icode_name[opcode]);
      break;

  case ASTOP_BRACKETS:
      fprintf(out, "%s [%05d] ! %s <C: BRACKETS>", indent(blocklevel), this->deleted.seqno, icode_name[opcode]);
      break;

  case ASTOP_ARRAYINDEX:
      fprintf(out, "%s [%05d] ! %s <C: ARRAY INDEX>", indent(blocklevel), this->deleted.seqno, icode_name[opcode]);
      break;

  case ASTOP_PARAM:
      fprintf(out, "%s [%05d] ! %s <C: PARAM>", indent(blocklevel), this->deleted.seqno, icode_name[opcode]);
      break;
    
  case '\n': break; // end of file

  case OP_END: // ';': /* END */
            fprintf(out, "%s [%05d] %c %s %s {lev=%d --> %d}", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->end.imp_id, blocklevel+1, blocklevel);
            break;

  case OP_ALTALT: // '~':
            {
              int pending = this->altalt.alttype;

              if ((' ' + 1 <= pending) && (pending <= '~')) {
                if (pending == 'A') {
                  fprintf(out, "%s [%05d] %c %s ~A %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], "ALTBEG");
                } else if (pending == 'B') {
                  fprintf(out, "%s [%05d] %c %s ~B %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], "ALTEND");
                } else if (pending == 'C') {
                  fprintf(out, "%s [%05d] %c %s ~C %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], "ALT");
                } else {
                  fprintf(out, "%s [%05d] %c %s ??? %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], "ALTALT1");
                }
              } else {
                fprintf(out, "%s [%05d] %c %s pending=%d %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], pending, "ALTALT2");
              }
            }
            break;

  case OP_BEGIN: // 'H': /* BEGIN */
            fprintf(out, "%s [%05d] %c %s %s {lev=%d --> %d}\n", indent(blocklevel-1), this->generic.seqno, opcode, icode_name[opcode], this->begin.imp_id, blocklevel-1, blocklevel);
            //blocklevel += 1;
            //#ifdef SHOW_CHILDREN
            IMPAST *block = this->begin.body;
            while (block != NULL) {
              show_icode(block, out); fprintf(out, "\n");
              block = block->generic.next_icode;
            }
            //#endif
            //blocklevel -= 1;
            break;

  case OP_START: // '{': /* START */
            {
            fprintf(out, "%s [%05d] %c %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
            fprintf(out, "{lev=%d -> %d}", blocklevel-1, blocklevel);
            //blocklevel += 1;
            }
            break;

  case OP_ALT: // '|': /* ALT */
            // Only relevant to record definitions, not parameter lists.
            fprintf(out, "%s [%05d] %c %s", indent(blocklevel-1), this->generic.seqno, opcode, icode_name[opcode]);
            break;

  case OP_FINISH: // '}': /* FINISH */
            {
            //blocklevel -= 1;
            fprintf(out, "%s [%05d] %c %s ", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
            fprintf(out, "{lev=%d -> %d}", blocklevel+1, blocklevel);
            }
            break;

  case OP_DEF: // '$': case 'g': /* {RE}DEF TAG TEXT TYPE FORM SIZE SPEC PREFIX */
            {
            int tf, format, ostate;
            int linkage, type, form;
            int special;
            
            DEFTAG[this->def.tag] = this;
            

            //fprintf(out, "%s [%05d] %c ", indent(IS_PROCEDURE(this) && !IS_SPEC(this) ? blocklevel-1 : blocklevel), this->def.seqno, opcode);
            fprintf(out, "%s [%05d] %c ", indent(blocklevel), this->def.seqno, opcode);

            tf = this->def.tf; // a
            format = this->def.format; // b
            ostate = this->def.ostate; // c

            linkage = ostate&7;
            type = (tf >> 4) & 0xF;
            form = tf & 0xF;

            /* handle bizarre type encoding scheme!: */
            special = SPECIAL_DEFAULT;
            if (type == T_INTEGER) {
              if (format == 2)
                special = SPECIAL_BYTE_INT;
              else if (format == 3)
                special = SPECIAL_SHORT_INT;
            } else if (type == T_REAL /* BUG? was T_STRING? */ && format == 4) {
              special = SPECIAL_LONG_REAL;
            } else if (type == T_STRING) {
            } else if (type == T_RECORD) {
            }
            
            fprintf(out, "%s %s tag=0x%04x (UNIQUE_TAG=0x%04x)", icode_name[opcode], this->def.imp_id, this->def.tag, this->def.unique_tag);
            generic(out, this);
            
#ifdef NEVER

            fprintf(out,
                    "%s %s tag=0x%04x (UNIQUE_TAG=0x%04x) a/tf=0x%04x b/format=0x%04x c/ostate=0x%04x"
                    "  type=%d (%s) form=%d (%s) special=%d (%s)"
                    " linkage=%d (%s) spec=%d indirect=%d no_unass_check=%d (NEXT ICODE=%05d) ",
                    icode_name[opcode],
                    this->def.imp_id, this->def.tag, this->def.unique_tag,
                    this->def.a, this->def.b, this->def.c,
                    type, typedesc[type],
                    form, formdesc[form],
                    special, specialdesc[special],
                    linkage, linkagedesc[ostate&7],
                    IS_SPEC(this), IS_INDIRECT(this), NO_UNASS_CHECK(this),
                    (this->def.next_icode == NULL ? 0 : this->def.next_icode->generic.seqno));
#endif

            //            /*
            if (this->def.alias         != NULL) fprintf(out, " (ALIAS: \"%s\")",     this->def.alias->alias.alias           );
            if (this->def.bounds_list   != NULL) fprintf(out, " (BOUNDS=%05d)",       this->def.bounds_list->generic.seqno   );
            if (this->def.init          != NULL) fprintf(out, " (INIT=%05d)",         this->def.init->generic.seqno          );
            if (this->def.formal_params != NULL) fprintf(out, " (FPARAMS=%05d)",      this->def.formal_params->generic.seqno );
            if (this->def.actual_params != NULL) fprintf(out, " (APARAMS=%05d)",      this->def.actual_params->generic.seqno );
            if (this->def.body          != NULL) fprintf(out, " (BODY=%05d)",         this->def.body->generic.seqno          );
            if (this->def.recordformatdef  != NULL) fprintf(out, " (RECORDFORMAT=%05d)", this->def.recordformatdef->generic.seqno  );
            //            */
            
            if (!IS_SPEC(this) && this->def.body != NULL) {

#ifdef SHOW_CHILDREN            
              IMPAST *param = this->def.formal_params; // params no longer embedded in body
              blocklevel += 1;
              fprintf(out, "\n");
              fprintf(out, "%s%s Formal Parameter list:", indent(blocklevel), this->def.imp_id);
              while (param != NULL) {
                fprintf(out, "\n%s", indent(blocklevel));
                show_icode(param, out);
                param = param->generic.next_icode;
              }
              blocklevel -= 1;
#endif            
              IMPAST *body = this->def.body;
              blocklevel += 1;
              fprintf(out, "\n");
              fprintf(out, "%s%s BODY:", indent(blocklevel), this->def.imp_id);
              while (body != NULL) {
                fprintf(out, "\n%s", indent(blocklevel));
                show_icode(body, out);
                body = body->generic.next_icode;
              }
              fprintf(out, "\n");
              blocklevel -= 1;
            }
            
#ifdef SHOW_CHILDREN            
            if (this->def.alias         != NULL) {
              fprintf(out, "\n%sALIAS: \"%s\"\n", indent(blocklevel),     this->def.alias->alias.alias           );
              show_icode(this->def.alias, out);
            }
            if (this->def.bounds_list   != NULL) {
              fprintf(out, "\n%sBOUNDS=%05d\n", indent(blocklevel),       this->def.bounds_list->generic.seqno   );
              show_icode(this->def.bounds_list, out);
            }
#endif
            if (this->def.init          != NULL) {
              //fprintf(out, "\n%sINIT=%05d\n", indent(blocklevel),         this->def.init->generic.seqno          );
              fprintf(out, "\n INIT: "); show_icode(this->def.init, out);
            }
#ifdef SHOW_CHILDREN            
            if (this->def.actual_params != NULL) {
              fprintf(out, "\n%sAPARAMS=%05d\n", indent(blocklevel),      this->def.actual_params->generic.seqno );
              show_icode(this->def.actual_params, out);
            }
            if (this->def.recordformat_field_list  != NULL) {
              fprintf(out, "\n%sRECORDFORMATFIELDS=%05d\n", indent(blocklevel), this->def.recordformat_field_list->generic.seqno  );
              if (OP(this->def.recordformatdef) == OP_START) {
                // skip the unneeded START opcode in the record format definition
                blocklevel += 2;
                show_icode(this->def.recordformat_field_list->generic.next_icode, out);
                blocklevel -= 2;
              } else {
                blocklevel += 2;
                show_icode(this->def.recordformat_field_list, out);
                blocklevel -= 2;
              }
            }
#endif            
            fprintf(out, "(NEXT ICODE=%05d) ", (this->def.next_icode == NULL ? 0 : this->def.next_icode->generic.seqno));

            }
            break;

  case OP_JUMPIFD: // '"': /* JUMPIFD cond label */

            fprintf(out, "%s [%05d] %c %s %c lab=0x%04x %s", indent(blocklevel), this->generic.seqno, (char)opcode, icode_name[opcode], this->jumpifd.cond, this->jumpifd.label, this->jumpifd.printable_label);
            
#ifdef SHOW_CHILDREN
            if (this->jumpifd.opd1 && this->jumpifd.opd1->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->jumpifd.opd1, out);
            }
            if (this->jumpifd.opd2 && this->jumpifd.opd2->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->jumpifd.opd2, out);
            }
#endif            
            break;
            
  case OP_JUMPIF: // '?': /* JUMPIF cond label */

            fprintf(out, "%s [%05d] %c %s %c lab=0x%04x %s", indent(blocklevel), this->generic.seqno, (char)opcode, icode_name[opcode], this->jumpif.cond, this->jumpif.label, this->jumpif.printable_label);

#ifdef SHOW_CHILDREN
            if (this->jumpif.opd1 && this->jumpif.opd1->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->jumpif.opd1, out);
            }
            if (this->jumpif.opd2 && this->jumpif.opd2->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->jumpif.opd2, out);
            }
#endif            
            break;

  case OP_JUMPIFA: // 'C': /* JUMPIFA cond label */

            fprintf(out, "%s [%05d] %c %s %c lab=0x%04x %s", indent(blocklevel), this->generic.seqno, (char)opcode, icode_name[opcode], this->jumpifa.cond, this->jumpifa.label, this->jumpifa.printable_label);
            
#ifdef SHOW_CHILDREN
            if (this->jumpifa.opd1 && this->jumpifa.opd1->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->jumpifa.opd1, out);
            }
            if (this->jumpifa.opd2 && this->jumpifa.opd2->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->jumpifa.opd2, out);
            }
#endif            
            break;
            
  case OP_BF: // 'k': /* BF label */

            fprintf(out, "%s [%05d] %c %s lab=0x%04x %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->bf.label, this->bf.printable_label);
            break;
            
  case OP_BT: // 't': /* BT label */

            fprintf(out, "%s [%05d] %c %s lab=0x%04x %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->bt.label, this->bt.printable_label);
            break;

  case OP_PUSHS: // '\'': /* PUSHS sconst */

            {
              fprintf(out, "%s [%05d] %c %s ", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
              char *s = this->pushs.string_value;
              fprintf(out, "\"");
              for (;;) {
                int c = *s++;
                if (c == '\0') break;
                // there are a lot more C escape sequences but this will do for now.
                if (c == '\n') {
                  fprintf(out, "\\n");
                } else if (c == '"') {
                  fprintf(out, "\\\"");
                } else {
                  fprintf(out, "%c", c);
                }
              }
              fprintf(out, "\"");
            }
            break;

  case OP_ALIAS: // 'G': /* ALIAS */

            fprintf(out, "%s [%05d] %c %s %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->alias.alias);
            break;

  case OP_PUSHR: // 'D': /* PUSHR rconst */

            fprintf(out, "%s [%05d] %c %s ", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
            fprintf(out, "code=%d \"%s", this->pushr.code, this->pushr.str);
            if (this->pushr.exponent != 0) {
              fprintf(out, " @ (signed short)0x%04d", this->pushr.exponent);
            }
            fprintf(out, "\"");
            break;

  case OP_PUSHI: // 'N': /* PUSHI iconst */

            fprintf(out, "%s [%05d] %c %s %d", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], (int)this->pushi.value);
            generic(out, this);
            break;

  case OP_LOCATE: // ':': /* LOCATE label */

            fprintf(out, "%s [%05d] %c %s lab=0x%04x %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->locate.label, this->locate.printable_label);
            break;
            
  case OP_REPEAT: // 'B': /* REPEAT label */

            fprintf(out, "%s [%05d] %c %s CYCLE: lab=0x%04x %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->repeat.label, this->repeat.printable_forlab);
            break;
            
  case OP_GOTO: // 'F': /* GOTO label */

            fprintf(out, "%s [%05d] %c %s lab=0x%04x %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->igoto.label, this->igoto.printable_label);
            break;
            
  case OP_JUMP: // 'J': /* JUMP label */

            fprintf(out, "%s [%05d] %c %s lab=0x%04x %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->jump.label, this->jump.printable_label);
            break;
            
  case OP_LABEL: // 'L': /* LABEL label */

            fprintf(out, "%s [%05d] %c %s lab=0x%04x %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->label.label, this->label.printable_label);
            break;
            
  case OP_FOR: // 'f': /* FOR label (label was missing from thesis description) */

    fprintf(out, "%s [%05d] %c %s lab=0x%04x FOR: %s" /*" EXIT: %s CONTINUE: %s"*/, indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->ifor.label, this->ifor.printable_forlab/*, this->ifor.printable_exitlab, this->ifor.printable_continuelab*/);
            if (this->ifor.initial != NULL) {
              fprintf(out, " INITIAL=%05d INCREMENT=%05d FINAL=%05d CONTROL=%05d", this->ifor.initial->generic.seqno, this->ifor.increment->generic.seqno, this->ifor.final->generic.seqno, this->ifor.control->generic.seqno);
            }
            break;

  case OP_LINE: // 'O': /* LINE decimal */

            //suppress_perms = FALSE;
            // EXTENSION FOR C-PASS1:
            /*if (opt_extended_line) fname = this->line.filename; */
            fprintf(out, "%s [%05d] %c %s %d %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->line.lineno, this->line.filename);
            break;

  case OP_PUSH: // '@': /* PUSH tag */

            fprintf(out, "%s [%05d] %c %s   %s    tag=0x%04x unique_tag=0x%04x",
                    indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode],
                    DEFTAG[this->push.tag]->def.c_id,
                    this->push.tag, this->push.unique_tag);
            generic(out, this);
            break;
            
  case OP_PROC: // '^': /* PROC tag */

            fprintf(out, "%s [%05d] %c %s tag=0x%04x", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->proc.tag);
            generic(out, this);
            break;

  case OP_SELECT: // 'n': /* SELECT tag */

            fprintf(out, "%s [%05d] %c %s   fieldname=%s   field index tag=%d",
                    indent(blocklevel), this->generic.seqno, opcode,
                    icode_name[opcode],
                    (this->select.fielddef == NULL ? "<NULL>" : this->select.fielddef->def.c_id),
                    this->select.fieldtag);
            generic(out, this);
            
            if (this->select.parent_record != NULL) {
              fprintf(out, "{RECORD=%05d} ", this->select.parent_record->generic.seqno);
            } else fprintf(out, "{RECORD=NULL} ");
            if (this->select.recordformatdef != NULL) {
              fprintf(out, "{RECORDFORMATDEF=%05d} ", this->select.recordformatdef->generic.seqno);
            } else fprintf(out, "{RECORDFORMATDEF=NULL} ");
            if (this->select.fielddef != NULL) {
              fprintf(out, "{FIELD=%05d} ", this->select.fielddef->generic.seqno);
            } else fprintf(out, "{FIELD=NULL} ");
            
#ifdef SHOW_CHILDREN
            if (this->select.parent_record && this->select.parent_record->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->select.parent_record, out);
            }
            if (this->select.recordformatdef && this->select.recordformatdef->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->select.recordformatdef, out);
            }
            if (this->select.fielddef && this->select.fielddef->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->select.fielddef, out);
            }
#endif
            break;

  case OP_DEFSW: // '`': /* defsw */         // EXTENSION FOR C-PASS1: default switch label

            fprintf(out, "%s [%05d] %c %s lab=0x%04x", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->defsw.label);
            break;
            
  case OP_SJUMP: // 'W': /* SJUMP sd */

            fprintf(out, "%s [%05d] %c %s lab=0x%04x", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->sjump.label);
            break;
            
  case OP_SLABEL: // '_': /* SLABEL sd */

            fprintf(out, "%s [%05d] %c %s lab=0x%04x", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->slabel.label);
            break;

  case OP_DIM: // 'd': /* DIM short,short */

            fprintf(out, "%s [%05d] %c %s dims %d #arrays %d", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->dim.dimens, this->dim.arrays);
            break;

  case OP_DEFAULT: // 'Y': /* DEFAULT short */
 
            fprintf(out, "%s [%05d] %c %s %d", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->idefault.data);
            break;
            
  case OP_INIT: // 'A': /* INIT short */

            fprintf(out, "%s [%05d] %c %s repeats=%d ", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->init.repeats);
            generic(out, this);
            if (this->init.data != NULL) {
              fprintf(out, "(DATA=[%05d]) ", this->init.data->generic.seqno);
            } else {
              fprintf(out, "(DATA=NULL) ");
            }
            if (this->init.next_init != NULL) {
              fprintf(out, "(NEXT_INIT=[%05d]) ", this->init.next_init->generic.seqno);
            } else {
              fprintf(out, "(NEXT_INIT=NULL) ");
            }
            if (this->init.next_icode != NULL) {
              fprintf(out, "(NEXT_ICODE=[%05d]) ", this->init.next_icode->generic.seqno);
            } else {
              fprintf(out, "(NEXT_ICODE=NULL) ");
            }
            if (this->init.data != NULL) {
              show_icode(this->init.data, out);
            }
            break;

  case OP_DIAG: // 'y': /* DIAG short */

            fprintf(out, "%s [%05d] %c %s 0x%04X", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->diag.data);
            DIAGNOSE = this->diag.data;
            
            break;
            
  case OP_CONTROL: // 'z': /* CONTROL short */
            /*
                    (lsb)   Bit 0  ::  Unassigned variable           (%CONTROL X'00000001')
                                1  ::  String capacity               (%CONTROL X'00000002')
                                2  ::  %for loop                     (%CONTROL X'00000004')
                                3  ::  Array bound                   (%CONTROL X'00000008')
                                4  ::  Integer overflow              (%CONTROL X'00000010')
                               28  ::  Decode wanted in listing file (%CONTROL X'10000000')
             */
    
            fprintf(out, "%s [%05d] %c %s 0x%04X", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->control.data);
            CONTROL = this->control.data;
            
            break;
            
  case OP_EVENT: // 'e': /* EVENT short */

            fprintf(out, "%s [%05d] %c %s 0x%04X", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->event.event);
            break;
            
  case OP_LANG: // 'l': /* LANG short */

            fprintf(out, "%s [%05d] %c %s 0x%04X", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->lang.language);
            break;

  case OP_ON: // 'o': /* ON byte short label */ /* BUG! wrong data */

            fprintf(out, "%s [%05d] %c %s MASK=0x%04X lab=0x%04x %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->on.mask, this->on.label, this->on.printable_label);
            break;

  case OP_RESOLVE: // 'r': /* RESOLVE m */

            // result is tested by BF or BT!
            fprintf(out, "%s [%05d] %c %s flags=%04x", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode], this->resolve.flags);
            generic(out, this);
            break;

  case OP_MCODE1: // 'c': /* MCODE */

#ifdef NEVER
            {
              int i1;
              short int h1;
              fprintf(out, "%s [%05d] %c %s ", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
              for (;;) {
                p1 = getmcstring(&i1);
                fprintf(out, " %s", p1);
                if (i1 == ';') break;
                p2 = getshort();
                fprintf(out, " tag_%s", p2);
              }
            }
#endif
            break;

  case OP_CALL: // 'E': /* CALL */
    {
            fprintf(out, "%s [%05d] %c %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);      
            generic(out, this);
#ifdef SHOW_CHILDREN
            if (this->call.def && this->call.def->generic.seqno != 0) { fprintf(out, "\n   "); show_icode(this->call.def, out); }
#endif
    }
    break;

  case OP_ASSVAL: // 'S': /* ASSVAL */
            fprintf(out, "%s [%05d] %c %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
            generic(out, this);
            if (this->assval.dest != NULL && this->assval.source != NULL)
              fprintf(out, " DEST=%05d SOURCE=%05d (NEXT ICODE=%05d)",
              this->assval.dest->generic.seqno,
              this->assval.source->generic.seqno,
              (this->assval.next_icode == NULL ? 0 : this->assval.next_icode->generic.seqno));
//#ifdef SHOW_CHILDREN
            if (this->assval.dest && this->assval.dest->generic.seqno != 0) { fprintf(out, "\n   "); show_icode(this->assval.dest, out); }
            if (this->assval.source && this->assval.source->generic.seqno != 0) { fprintf(out, "\n   "); show_icode(this->assval.source, out); }
//#endif
            break;

  case OP_ASSREF: // 'Z': /* ASSREF */
            fprintf(out, "%s [%05d] %c %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
            generic(out, this);
            if (this->assref.dest != NULL && this->assref.source != NULL)
              fprintf(out, " DEST=%05d SOURCE=%05d (NEXT ICODE=%05d)",
              this->assref.dest->generic.seqno,
              this->assref.source->generic.seqno,
              (this->assref.next_icode == NULL ? 0 : this->assref.next_icode->generic.seqno));
#ifdef SHOW_CHILDREN
            if (this->assref.dest && this->assref.dest->generic.seqno != 0) { fprintf(out, "\n   "); show_icode(this->assref.dest, out); }
            if (this->assref.source && this->assref.source->generic.seqno != 0) { fprintf(out, "\n   "); show_icode(this->assref.source, out); }
#endif
            break;

  case OP_JAM: // 'j': /* JAM */
            fprintf(out, "%s [%05d] %c %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
            generic(out, this);
            if (this->jam.dest != NULL && this->jam.source != NULL)
              fprintf(out, " DEST=%05d SOURCE=%05d",
              this->jam.dest->generic.seqno,
              this->jam.source->generic.seqno);
            break;


  case OP_ADD: // '+': /* ADD */
            fprintf(out, "%s [%05d] %c %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
            generic(out, this);
            
#ifdef SHOW_CHILDREN
            if (this->add.opd1 && this->add.opd1->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->add.opd1, out);
            }
            if (this->add.opd2 && this->add.opd2->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->add.opd2, out);
            }
#endif
            break;

            
  case OP_AND: // '&': /* AND */
            fprintf(out, "%s [%05d] %c %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
            generic(out, this);
            
#ifdef SHOW_CHILDREN
            if (this->and.opd1 && this->and.opd1->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->and.opd1, out);
            }
            if (this->and.opd2 && this->and.opd2->generic.seqno != 0) {
              fprintf(out, "\n   "); show_icode(this->and.opd2, out);
            }
#endif
            break;


  case OP_ACCESS: // 'a': /* ACCESS */
            fprintf(out, "%s [%05d] %c %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
            generic(out, this);
            if (this->access.base != NULL) fprintf(out, " (ARRAY=[%05d])", this->access.base->generic.seqno);
            if (this->access.index != NULL) fprintf(out, " (INDEX=[%05d])", this->access.index->generic.seqno);
            blocklevel += 1;
//#ifdef SHOW_CHILDREN
            fprintf(out, "\n   "); show_icode(this->access.base, out);
            fprintf(out, "\n   "); show_icode(this->access.index, out);
//#endif
            blocklevel -= 1;
            break;

            
  case OP_NEGATE: // 'U': /* NEGATE */
  case OP_NOT: // '\\': /* NOT */
  case OP_MOD: // 'v': /* MOD */

  case OP_OR: // '!': /* OR */
//case '#': /* BNE */
  case OP_XOR: // '%': /* XOR */
  case OP_MUL: // '*': /* MUL */
  case OP_SUB: // '-': /* SUB */
  case OP_CONCAT: // '.': /* CONCAT */
  case OP_QUOT: // '/': /* QUOT */
  case OP_FALSE: // 'K': /* FALSE */
  case OP_MAP: // 'M': /* MAP */
  case OP_PLANT: // 'P': /* PLANT */
  case OP_DIVIDE: // 'Q': /* DIVIDE */
  case OP_RETURN: // 'R': /* RETURN */
  case OP_TRUE: // 'T': /* TRUE */
  case OP_RESULT: // 'V': /* RESULT */
  case OP_IEXP: // 'X': /* IEXP */
  case OP_LSH: // '[': /* LSH */
  case OP_RSH: // ']': /* RSH */
  case OP_BOUNDSPAIR: // 'b': /* BOUNDS */
  case OP_ALTBEG: // 'h': /* ALTBEG */
  case OP_INDEX: // 'i': /* INDEX */
  case OP_MONITOR: // 'm': /* MONITOR */
  case OP_ASSPAR: // 'p': /* ASSPAR */
  case OP_SUBA: // 'q': /* SUBA */
  case OP_STOP: // 's': /* STOP */
  case OP_ADDA: // 'u': /* ADDA */
  case OP_MCODE2: // 'w': /* MCODE2 */
  case OP_REXP: // 'x': /* REXP */

            fprintf(out, "%s [%05d] %c %s", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
            generic(out, this);
            break;

  default:

    if (opcode < 0 || opcode > 255 || icode_name[opcode] == NULL) {
      fprintf(out, "? showicode.c: %s [%05d] OPCODE %d (0x%08x)\n", indent(blocklevel), this->generic.seqno, opcode, opcode);
    } else {
      fprintf(out, "? showicode.c: %s [%05d] %c %s\n", indent(blocklevel), this->generic.seqno, opcode, icode_name[opcode]);
    }
    break;
  }
  
}

void dump_ast(FILE *out, IMPAST *icode, const char *desc) {
  fprintf(out, "\n==================================== After %s ====================================\n\n", desc);

  init_show_icode();
  while (icode != NULL) {
    show_icode(icode, out); fprintf(out, "\n");
    icode = icode->generic.next_icode;
  }

}

void dump_icodes(FILE *out, IMPAST *icode, char *desc) {
  fprintf(out, "\n==================================== %s ====================================\n\n", desc);
  int seqno = 0;
  
  init_show_icode();
  if (icode != NULL) {
    seqno = icode->generic.seqno;
  }
  for (;;) {
    if (used[seqno]) fprintf(out, "// ");
    show_icode(astid[seqno], out); fprintf(out, "\n");
    if (seqno == next_free_astid) return;
    seqno += 1;
  }
}


#endif // !__SHOWICODE_C__
