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

#define OLD_ICODE 1

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

static int debug_input = FALSE;
static char *indent = "        ";
FILE *icode_file;
FILE *source_file;
int source_line = 0;
#define MAX_LINE 1024
char line[MAX_LINE+1];
/*
   This is primarily for the old-style (as described in the thesis) icode,
   with any 'unused' opcodes plugged in with the newer description from
   https://web.archive.org/web/20041216161503/http://www.gtoal.com/athome/edinburgh/imp77/gtoal/icode.html
   ( http://www.gtoal.com/athome/edinburgh/imp/imp77/icode.html )

   Lower case text in the array below means 'new style'.

   There are also all the new opcodes >= 128 which I have not yet
   incorporated - the coding can be found by grepping for ^c\( in file
   https://history.dcs.ed.ac.uk/archive/languages/imp77-acorn-tmp/3l/COMPILERS/bend/imp/pass2
   ( http://www.gtoal.com/athome/edinburgh/acorn/3l/COMPILERS/bend/imp/pass2 )

   I think some of the old-style opcodes were redefined in an incompatible
   way for the new style.  So be careful.  For now this is really just
   old-style only, which I hope is all that is ever generated by the
   Mouses Imp77 V8.4 compiler which ABD is porting.
 */

#ifdef OLD_ICODE

static 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",
"<'('>", "<')'>", "MUL", "ADD", "+  ", "SUB", "CONCAT", "QUOT",
/*   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ? */
"<'0'>", "<'1'>", "<'2'>", "<'3'>", "<'4'>", "<'5'>", "<'6'>", "<'7'>",
"<'8'>", "<'9'>", "LOCATE", "END", "<'<'>", "<'='>", "<'>'>", "JUMPIF",
/*   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O */
"PUSH", "INIT", "REPEAT", "JUMPIFA", "PUSHR", "CALL", "GOTO", "ALIAS",
"BEGIN", "<'I'>", "JUMP", "FALSE", "LABEL", "MAP", "PUSHI", "LINE",
/*   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _ */
"PLANT", "DIVIDE", "RETURN", "ASSVAL", "TRUE", "NEGATE", "RESULT", "SJUMP",
"IEXP", "DEFAULT", "ASSREF", "LSH", "NOT", "RSH", "PROC", "SLABEL",
/*   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o */
"<'`'>", "ACCESS", "BOUNDS", "MCODE", "DIM", "EVENT", "FOR", "<'g'>",
"ALTBEG", "INDEX", "JAM", "BF", "LANG", "MONITOR", "SELECT", "ON",
/*   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~ DEL */
"ASSPAR", "ALTEND", "RESOLVE", "STOP", "BT", "ADDA", "MOD", "SUBA",
"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>",
"<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>",
"<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>",
"<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>",
};

#else /* New Icode */

static 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/compare-double?", "BNE", "DEF", "XOR", "AND", "PUSHS",
"ble", "bge", "MUL", "ADD", "+  ", "SUB", "CONCAT", "QUOT",
/*   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ? */
"<'0'>", "<'1'>", "<'2'>", "<'3'>", "<'4'>", "<'5'>", "<'6'>", "<'7'>",
"<'8'>", "<'9'>", "LOCATE", "END", "blt", "beq", "bgt", "JUMPIF/compare-values?",
/*   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O */
"PUSH", "INIT", "REPEAT", "JUMPIFA/compare-addresses", "PUSHR", "CALL", "GOTO", "ALIAS",
"BEGIN", "select-input-2", "JUMP", "FALSE", "LABEL", "MAP", "PUSHI", "LINE",
/*   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _ */
"PLANT", "DIVIDE", "RETURN", "ASSVAL", "TRUE", "NEGATE", "RESULT", "SJUMP",
"IEXP", "DEFAULT", "ASSREF", "LSH", "NOT", "RSH", "PROC", "SLABEL",
/*   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o */
"<'`'>", "ACCESS", "BOUNDS", "MCODE", "DIM", "EVENT", "FOR", "<'g'>",
"ALTBEG", "INDEX", "JAM", "bf", "LANG", "MONITOR", "SELECT", "ON",
/*   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~ DEL */
"ASSPAR", "ALTEND", "RESOLVE", "STOP", "bt", "ADDA", "MOD", "SUBA",
"REXP", "DIAG", "CONTROL", "START", "ALT", "FINISH", "pending", "<127>",

/*

c('!'):  Operation(ORx);                                       %continue
c('"'):  Compare Double;                                       %continue
c('#'):  Jump Forward(Tag, NE);                                %continue
c('$'):  Define Var;                                           %continue
c('%'):  Operation(XORx);                                      %continue
c('&'):  Operation(ANDx);                                      %continue
c(''''): Input String Value;                                   %continue
c('('):  Jump Forward(Tag, LE);                                %continue
c(')'):  Jump Forward(Tag, GE);                                %continue
c('*'):  Operation(MULx);                                      %continue
c('+'):  Operation(ADDx);                                      %continue
c('-'):  Operation(SUBx);                                      %continue
c('.'):  Operation(CONCx);                                     %continue
c('/'):  Operation(DIVx);                                      %continue
c(':'):  Define Compiler Label(Tag);                           %continue
c(';'):  End of Block;                                 %exit
c('<'):  Jump Forward(Tag, LT);                                %continue
c('='):  Jump Forward(Tag, EQ);                                %continue
c('>'):  Jump Forward(Tag, GT);                                %continue
c('?'):  Compare Values;                                       %continue
c('@'):  Stack Var(Tag);                                       %continue
c('A'):  Init(Tag);                                            %continue
c('B'):  Jump Backward(Tag);                                   %continue
c('C'):  Compare Addresses;                                    %continue
c('D'):  Input Real Value;                                     %continue
c('E'):  Call(0);                                              %continue
c('F'):  Jump Forward(Tag, Always);                            %continue
c('G'):  Get String(Alias);                                    %continue
c('H'):  Compile Begin;                                        %continue
c('I'):  Select Input(Icode In2);  Readsymbol(Pending);        %continue
c('J'):  User Jump(Tag);                                       %continue
c('K'):  Return(False);                                        %continue
c('L'):  Define User Label(Tag);                               %continue
c('M'):  Return(Map);                                          %continue
c('N'):  Input Integer Value(0);                               %continue
c('O'):  Update Line(Tag);                                     %continue
c('P'):  Dump Byte(Popped Value&255);                              %continue
c('Q'):  Operation(RDIVx);                                     %continue
c('R'):  Return(Routine);                                      %continue
c('S'):  Assign(Equals);                                       %continue
c('T'):  Return(True);                                         %continue
c('U'):  Operate(NEGx, Stack, Nil);                            %continue
c('V'):  Return(Fn);                                           %continue
c('W'):  Switch Jump(Tag);                                     %continue
c('X'):  Operation(EXPx);                                      %continue
c('Z'):  Assign(EqualsEquals);                                 %continue
c('['):  Operation(LSHx);                                      %continue
c('\'):  Operate(NOTx, Stack, Nil);                            %continue
c(']'):  Operation(RSHx);                                      %continue
c('^'):  Stack_Format = -Tag;                                  %continue
c('_'):  Switch Label(Tag);                                    %continue
c('a'):  Array Access;                                         %continue
c('b'):  Constant Bounds;                                      %continue
c('c'):  Section = 1;  Get String(Section Id);         %exit
c('d'):  D = Tag;  N = Tag;  Dimension(D, N);                  %continue
c('e'):  Signal Event(Tag);                                    %continue
c('f'):  Compile For(Tag);                                     %continue
c('g'):  Test for NIL;                                         %continue
c('h'):  Special Call(Tag);                                    %continue
c('i'):  Array Index;                                          %continue
c('j'):  Assign(Jam);                                          %continue
c('k'):  Jump Forward(Tag, FF);                                %continue
c('l'):  Language Flags = Tag;                                 %continue
c('m'):  Do(Monitor Id, Monitor Ep, 0);                        %continue
c('n'):  Select(Tag);                                          %continue
c('o'):  Event Trap(Tag);                                      %continue
c('p'):  AssignParameter;                                      %continue
c('q'):  Process Include File;                                 %continue
c('r'):  Resolve(Tag);                                         %continue
c('s'):  To Store(Tag);                                        %continue
c('t'):  Jump Forward(Tag, TT);                                %continue
c('u'):  Aop;                                                  %continue
c('v'):  Operate(ABSx, Stack, Nil);                            %continue
c('w'):  Machine Code;  Forget Everything;                     %continue
c('x'):  Operation(REXPx);                                     %continue
c('y'):  Set CD(Tag, Diag);                                    %continue
c('z'):  Set CD(Tag, Control);                                 %continue
c('{'):  Assemble(DefV,
                  Blocktype,
                  Vars,
                  Local+1,
                  Parameter Mode, Attributes)
            %continue

c('}'):  %exit %if Finish Params
         Do("3L___stack_check", Stack Check, 0) %if Interface_Options&LL Stack # 0
         %continue
c('~'):  N = Pending;  Readsymbol(Pending)
         %exit %if Alternate Format(N);                      %continue
 */

"<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>",
};

/*
  Details of codes >= 128 can be found in
  https://history.dcs.ed.ac.uk/archive/languages/imp77-acorn-tmp/3l/COMPILERS/bend/imp/pass2

   {************ Extra Items **************}

c(128+'"'):  Unsigned = 10;  Stack Condition;                %continue
c(128+'?'):  Unsigned = 10;  Compare Values;                 %continue
c(128+','):  Max Frame = Frame %if Frame > Max Frame
             Frame = Frame Base;                             %continue
c(128+'0'):  N = Tag;  {but no operation}                    %continue
c(128+'1'):  Add Member(0);                                  %continue
c(128+'2'):  Add Member(1);                                  %continue
c(128+'3'):  Set Variant Count(Tag);                         %continue
c(128+'4'):  Test Variant Count(Tag);                        %continue
c(128+'5'):  Check not long NEW;                             %continue
c(128+'6'):  Check Dynamic Bounds;                           %continue

c(128+'/'):  Operation(UDIVx);                               %continue
c(128+'|'):  Operation(UREMx);                               %continue
c(128+'@'):  Decode(0, -1) %if Diag&Mon Code # 0
             Current Line = Tag;                             %continue
c(128+'A'):  Amap(Stack);                                    %continue
c(128+'B'):  %if Pending = 't' %then Pending = '#' -
                               %else Pending = '='
             Test Zero(Stack);  Pop Release and Drop;        %continue
c(128+'C'):  Unsigned = 0;  Stack Condition;                 %continue
c(128+'D'):  Duplicate;                                      %continue
c(128+'E'):  Loadup(Stack) %unless Stack_Form = Address -
                              %and Locked(Stack_Base)   -
                              %and Stack_Record == Nil  -
                              %and Stack_Index  == Nil;      %continue
c(128+'F'):  Stack_Format = -Tag;                            %continue
c(128+'I'):  Compile In(1);                                  %continue
c(128+'L'):  Localise;                                       %continue
c(128+'M'):  Operation(MODx);                                %continue
c(128+'N'):  Operation(REMx);                                %continue
C(128+'O'):  Apply Round(Stack);                             %continue
c(128+'P'):  Pop Release and Drop;                           %continue
c(128+'R'):  Define Range;                                   %continue
c(128+'S'):  Swop;                                           %continue
c(128+'T'):  Apply Trunc(Stack);                             %continue
c(128+'U'):  Use With(Tag);                                  %continue
c(128+'V'):  Vmap(Stack, Tag);                               %continue
c(128+'W'):  Stack Work Variable;                            %continue
C(128+'X'):  Loadup(Stack) %unless Stack_Type = Lreals;      %continue
c(128+'Z'):  Stack Integer(0);  Stack_Type = Sets
                                Stack_Flags = Null Set;      %continue
c(128+'['):  Claim With(Tag);                                %continue
c(128+']'):  Release With(Tag);                              %continue
c(128+'b'):  Input Integer Value(1);                         %continue
c(128+'c'):  General Compare;                                %continue
c(128+'e'):  N = Stack_Type ; Amap(Stack)
             Loadup(Stack) %unless Stack_Form = Address -
                              %and Locked(Stack_Base)   -
                              %and Stack_Index  == Nil  -
                              %and Stack_Record == Nil
             Vmap(Stack, N);                                 %continue
c(128+'f'):  For Range == Var(Tag);                          %continue
c(128+'g'):  Call(1);                                        %continue
c(128+'i'):  Compile In(0);                                  %continue
C(128+'n'):  Apply Int(Stack);                               %continue
c(128+'m'):  General Move;                                   %continue
c(128+'o'):  Owntype = Tag;                                  %continue
c(128+'p'):  Fmap(Tag);                                      %continue
c(128+'r'):  Test Range(Stack, Var(Tag));                    %continue
c(128+'s'):  Set Size or Type(1, Stack);                     %continue
c(128+'t'):  Set Size or Type(2, Stack);                     %continue
c(128+'v'):  Compare Values;  Prim(Test Variant);            %continue
c(128+'w'):  Apply Intpt(Stack);                             %continue
c(128+'z'):  Stack Data Size;                                %continue
c(128+'{'):  Nn = 0
             Assemble(AltV, -2, Vars, Local, -1, Nn)
             Alt Align = Alt Align&Falign;                   %continue
c(128+'}'):  Frame = Max Frame %if Max Frame > Frame
             Falign = Alt Align;                     %exit

 */
#endif

int get_icode(FILE *f)
{
  int c = fgetc(f);
  if (c != EOF) {
    if (debug_input) {
      if ('!' <= c && c <= '~') {
        fprintf(stdout, "'%c':\n", c);
      } else if ((('!'|128) <= (c|128)) && ((c|128) <= ('~'|128))) {
        fprintf(stdout, "128+'%c':\n", c&127);
      } else {
        fprintf(stdout, "%d:\n", c);
      }
    }
  }
  return(c);
}

static 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);
}

static char *getwordconst(void)
{
  static char local[12];
  int i, c;
  int word = 0;
  for (i = 0; i < 4; i++) {
    word = word << 8 | (c = get_icode(icode_file));
    assert(c != EOF);
  }
  sprintf(local, "#0x%08x", word);
  return(local);
}

static char *getbyte(void)
{
  static char local[4];
  int c;
  c = get_icode(icode_file); assert(c != EOF);
  sprintf(local, "%02x", c&255);
  return(local);
}

static char *getcond(void)
{
  static char local[3];
  int c;
  c = get_icode(icode_file); assert(c != EOF); c &= 255;
  if (c == '(') {
    sprintf(local, "<=");
  } else if (c == ')') {
    sprintf(local, ">=");
  } else {
    sprintf(local, "%c", c&255);
  }
  return(local);
}

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

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

static char *getshort(void)
{
  static char local[5];
  int i, c;
  int word = 0;
  for (i = 0; i < 2; i++) {
    word = word << 8 | (c = get_icode(icode_file));
    assert(c != EOF);
  }
  sprintf(local, "%04x", word);
  return(local);
}

static char *getshortdecimal(int *d)
{
  static char local[7];
  int i, c;
  int word = 0;
  for (i = 0; i < 2; i++) {
    word = word << 8 | (c = get_icode(icode_file));
    assert(c != EOF);
  }
  if (d != NULL) *d = word;
  sprintf(local, "%0d", word);
  return(local);
}

static char *getlab(void)
{
  static char local[7];
  int i, c;
  int word = 0;
  for (i = 0; i < 2; i++) {
    word = word << 8 | (c = get_icode(icode_file));
    assert(c != EOF);
  }
  sprintf(local, "L_%04x", word);
  return(local);
}

static char *getvar(void)
{
  static char local[7];
  int i, c;
  int word = 0;
  for (i = 0; i < 2; i++) {
    word = word << 8 | (c = get_icode(icode_file));
    assert(c != EOF);
  }
  sprintf(local, "V_%04x", word);
  return(local);
}

int main(int argc, char **argv)
{
  char *p1, *p2, *p3;
  int opcode, d;
  char icode_filename[256], source_filename[256];

  if (argc >= 2 && strcmp(argv[1], "-d") == 0) {
    debug_input = TRUE;
    argc -= 1; argv += 1;
  }

  if (argc == 1 || argc > 3) {
    fprintf(stderr, "syntax: idec file.icd {file.imp}?  *or*  idec basename (looks for .icd and .imp extensions)\n"); exit(1);
  }

  if (argc == 3) {
    sprintf(icode_filename, "%s", argv[1]);
  } else {
    sprintf(icode_filename, "%s.icd", argv[1]);
  }
  
  icode_file = fopen(icode_filename, "rb");
  if (icode_file == NULL) {
    fprintf(stderr, "idec: cannot open '%s' - %s\n",
                    icode_filename, strerror(errno));
    exit(2);
  }

  if (argc == 3) {
    sprintf(source_filename, "%s", argv[2]);
  } else {
    sprintf(source_filename, "%s.imp", argv[1]);
  }
  source_file = fopen(source_filename, "r");
  if (source_file != NULL) {
    fprintf(stdout, "\n             %s\n\n\n",
                    "Edinburgh IMP77 Compiler - Version 8.4");
  }

  for (;;) {
    opcode = get_icode(icode_file);
    if (opcode == EOF) break;
    switch(opcode) {

    case '\n': break;

    case '$': /* DEF TAG TEXT TYPE FORM SIZE SPEC PREFIX */
              p1 = getvar(); p2 = getname();
              fprintf(stdout, "%s%s %s %s\n",
                indent, icode_name[opcode], p1, p2); break;
    case ',': fprintf(stdout, "%s%s 0x%s\n", /* TEMP HACK */
                indent, icode_name[opcode], getshort()); break;

    case '"': /* JUMPIFD cond label */
    case 'C': /* JUMPIFA cond label */
    case '?': /* JUMPIF cond label */
              p1 = getcond(); p2 = getlab();
              fprintf(stdout, "%s%s %s %s\n",
                indent, icode_name[opcode], p1, p2);
              break;

    case 'k': /* BF label */
    case 't': /* BT label */
              p1 = getlab();
              fprintf(stdout, "%s%s %s\n",
                indent, icode_name[opcode], p1);
              break;

    case '\'': /* PUSHS sconst */
               fprintf(stdout, "%s%s %s\n",
                indent, icode_name[opcode], getimpstring()); break;

    case 'D': /* PUSHR rconst */
              fprintf(stdout, "%s/* TODO */ %s %s\n",
                indent, icode_name[opcode], getwordconst());
              break;

    case 'N': /* PUSHI iconst */
              fprintf(stdout, "%s%s %s\n",
                indent, icode_name[opcode], getwordconst()); break;

    case ':': /* LOCATE label */
    case 'B': /* REPEAT label */
    case 'F': /* GOTO label */
    case 'J': /* JUMP label */
    case 'L': /* LABEL label */
    case 'f': /* FOR label (label was missing from thesis description) */
              fprintf(stdout, "%s%s %s\n",
                indent, icode_name[opcode], getlab());
              break;

    case 'O': /* LINE decimal */
              fprintf(stdout, "%s%s %s\n",
                indent, icode_name[opcode], getshortdecimal(&d));
              /* output source file up to line %d */

              if (source_file != NULL) {
                while (source_line < /*+1*/d) {
                  if (fgets(line, MAX_LINE, source_file) == NULL) break;
                  source_line += 1;
                  fprintf(stdout, "%6d  ", source_line);
                  line[MAX_LINE] = '\0'; fputs(line, stdout);
		}
	      }
              break;

    case '@': /* PUSH tag */
    case '^': /* PROC tag */
    case 'n': /* SELECT tag */
              fprintf(stdout, "%s%s %s\n",
                indent, icode_name[opcode], getvar()); break;

    case 'W': /* SJUMP sd */
    case '_': /* SLABEL sd */
              fprintf(stdout, "%s%s %s\n",
                indent, icode_name[opcode], getshortdecimal(NULL)); break;
              break;

    case 'd': /* DIM short,short */
              p1 = strdup(getshort()); assert(get_icode(icode_file) == ','); p2 = getshort();
              fprintf(stdout, "%s%s %s %s\n",
                indent, icode_name[opcode], p1, p2);
              free(p1);
              break;

    case 'Y': /* DEFAULT short */
    case 'A': /* INIT short */
              fprintf(stdout, "%s%s %s\n",
                indent, icode_name[opcode], getshortdecimal(NULL)); break;

    case 'y': /* DIAG short */
    case 'z': /* CONTROL short */
    case 'e': /* EVENT short */
    case 'l': /* LANG short */
              fprintf(stdout, "%s%s %s\n",
                indent, icode_name[opcode], getshort()); break;

    case 'o': /* ON byte short label */ /* BUG! wrong data */
              p1 = strdup(getshort()); assert(get_icode(icode_file) == ','); p2 = getlab();
              fprintf(stdout, "%s%s MASK=%s %s\n",
                indent, icode_name[opcode], p1, p2); break;

    case 'r': /* RESOLVE m */
              fprintf(stdout, "%s/* TODO */ %s %s\n",
                indent, icode_name[opcode], getbyte()); break;
              break;

    case 'w': /* SUBA - documentation failure??? file uses 'w'  */
              opcode = 'c';
    case 'c': /* MCODE */
              {
              int i1;
              short int h1;
                printf("%s%s ", indent, icode_name[opcode]);
                for (;;) {
                  p1 = getmcstring(&i1);
                  printf(" %s", p1);
                  if (i1 == ';') break;
                  p2 = getshort();
                  printf(" tag_%s", p2);
                }
                printf("\n");
              }
              break;
    case '!': /* OR */
    case '#': /* BNE */
    case '%': /* XOR */
    case '&': /* AND */
    case '*': /* MUL */
    case '+': /* ADD */
    case '-': /* SUB */
    case '.': /* CONCAT */
    case '/': /* QUOT */
    case ';': /* END */
    case 'E': /* CALL */
    case 'G': /* ALIAS */
    case 'H': /* BEGIN */
    case 'K': /* FALSE */
    case 'M': /* MAP */
    case 'P': /* PLANT */
    case 'Q': /* DIVIDE */
    case 'R': /* RETURN */
    case 'S': /* ASSVAL */
    case 'T': /* TRUE */
    case 'U': /* NEGATE */
    case 'V': /* RESULT */
    case 'X': /* IEXP */
    case 'Z': /* ASSREF */
    case '[': /* LSH */
    case '\\': /* NOT */
    case ']': /* RSH */
    case 'a': /* ACCESS */
    case 'b': /* BOUNDS */
    case 'h': /* ALTBEG */
    case 'i': /* INDEX */
    case 'j': /* JAM */
    case 'm': /* MONITOR */
    case 'p': /* ASSPAR */
    case 'q': /* ALTEND */
    case 's': /* STOP */
    case 'u': /* ADDA */
    case 'v': /* MOD */
    case 'x': /* REXP */
    case '{': /* START */
    case '|': /* ALT */
    case '}': /* FINISH */
              fprintf(stdout, "%s%s\n", indent, icode_name[opcode]); break;

    default:  fprintf(stdout, "?%s%s\n", indent, icode_name[opcode]); break;
    }
  }
  exit(0);
  return(0);
}