/*
   Pseudo-disassembler of PDP9/15 Imp compiler output
   RWT September 2002
*/

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

int main (int argc, char **argv) {

int line=1;         /* initial line number, bumped by NL */
int sec='C';        /* section: Code or Data */
int shift=0;        /* shift count for digits in numbers */
int num=0;          /* generic numeric param for everything */
int sym;

void sourceline(int l)
{
  int i;
  static FILE *sfile = NULL;
  static int sline = 0;

  if (sline == 0) {
    sfile = fopen(argv[1], "r");
    if (sfile == NULL) {
      fprintf(stderr, "impdis: %s\n", strerror(errno)); exit(1);
    }
  }

  if (sline < l) {
    for (;;) {
      sline += 1;
      fprintf(stdout, "%4d ", sline);
      for (;;) {
        i = fgetc(sfile); if (i == EOF) exit(0);
        putchar(i);
        if (i == '\n') break;
      }
      if (sline == l) break;
    }
  }
}

void prefix (void) {
  sourceline(line);
  printf("     %c ",sec);
}

void suffix (int n) {
  if (n&0400000) n |= (-01000000);
  if (n<0) {printf("-"); n = -n;}
  printf("%o\n",n);
}

void plain (char *s) {
  prefix(); printf("%s ",s); suffix(num);
}

void normal (char* s) {
static char *mnem[16] = {"?1?","DAC","JMS","DZM",
                         "LAC","XOR","ADD","TAD",
                         "XCT","ISZ","AND","SAD",
                         "JMP","?2?","?3?","?4?"};
  prefix(); printf("%s%s",mnem[sym&15],s); suffix(num);
}

void pseudo (void) {
static char *mnem[4] = {"ADR","DAD","ADA","LAD"};
  prefix(); printf("%s M",mnem[sym&3]); suffix(num);
}

void opr (void) {
static char *skip[16] = {"?5?","SMA","SZA","SMA!SZA",
                         "SNL","SMA!SNL","SZA!SNL","SMA!SZA!SNL",
                         "SKP","SPA","SNA","SPA!SNA",
                         "SZL","SPA!SZL","SNA!SZL","SPA!SNA!SZL"};
static char *rot2[4] = {"?6?","RTL","RTR","SWHA"};
static char *rot1[4] = {"?7?","RAL","RAR","IAC"};
int pend=0;
  void pling (void) {
    if (pend) printf("!"); pend = 1;
  }
  if (num&020000) {num |= 0740000; plain("LAW"); return;}
  prefix(); if (num==0) {printf("NOP\n"); return;}
  if (num&001700) {pling(); printf("%s",skip[(num>>6)&15]);}
  if (num&002000) {pling(); printf(rot2[(num>>3)&3]);}
  if (num&010000) {pling(); printf("CLL");}
  if (num&004000) {pling(); printf("CLA");}
  if ((num&00030)&&(num&02000)==0) {pling(); printf("%s",rot1[(num>>3)&3]);}
  if (num&4) {pling(); printf("OAS");}
  if (num&2) {pling(); printf("CML");}
  if (num&1) {pling(); printf("CMA");}
  if (num&040) {pling(); printf("HLT");}
  printf("\n");
}

  static FILE *ofile = NULL;
  char fname[256];
  char *fp;

  if (argc != 2) {
    fprintf(stderr, "syntax: impdis file.15\n"); exit(2);
  }


  sprintf(fname, argv[1]);
  fp = strrchr(fname, '.');
  sprintf(fp, ".o15");
  ofile = fopen(fname, "r");

  if (ofile == NULL) {
    fprintf(stderr, "impdis: %s\n", strerror(errno)); exit(1);
  }

  printf("\n\n     EUCSD IMP15 COMPILER 2.0\n\n");
  sourceline(1);

  while (1) {
    sym = fgetc(ofile); if (sym<0) return;
    if (sym=='\n') {line++; sourceline(line); continue;}
    sym &= 077;
    if (sym>='0') {
      num += (sym-'0')<<shift; shift += 4; continue;
    }
    shift = 0;
    switch (sym) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:  normal(" M"); break;
case 13:  plain("EAE"); break;
case 14:  plain("IOT"); break;
case 15:  opr(); break;
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
case 26:
case 27:
case 28:  normal("* M"); break;
case 0:   sym = 30;
case 16:
case 29:
case 30:
case 31:  pseudo(); break;
case 32:  plain("ARG"); break;
case 33:  plain("ENTRY POINT"); break;
case 34:  return;
case 35:  plain("LIT"); break;
case 36:
case 37:
case 38:
case 39:
case 42:
case 43:  normal(" #"); break;
case 40:  plain("BLOCK BEGIN"); break;
case 41:  plain("BLOCK END"); break;
case 44:  plain("EXT SPEC"); break;
case 45:  num = -num; continue;
case 46:  plain("DEFINE"); break;
case 47:  sec = 'C'+'D'-sec; break;
    }
    num = 0;
  }
}
