#include <perms.h>

//          Edinburgh IMP77 Compiler - Version 8.4
//
//     1  %begin

int main(int argc, char **argv) { /*%begin*/
  _imp_initialise(argc, argv);

  //     2  %realfn eval    {evaluate sub-expression}

  float EVAL(void) {
    auto void PUSHOPD(float VAL);

    auto void PUSHOP(int OP);

    auto float POPOPD(void);

    auto int POPOP(void);

    auto float NEXTOPD(void);

    auto int NEXTOP(void);

    auto void OPERATE(void);

    //     3  %routinespec pushopd(%real val)
    //     4  %routinespec pushop(%integer op)
    //     5  %realfnspec popopd
    //     6  %integerfnspec popop
    //     7  %realfnspec nextopd
    //     8  %integerfnspec nextop
    //     9  %routinespec operate
    //    10  %constinteger plus=1,minus=2,times=3,divide=4,exp=5,assign=6,end=7,space=' '
    //    11  %constintegerarray prec(plus:assign)=1,1,2,2,3,0

    const int PREC[6] = {1, 1, 2, 2, 3, 0};

    //    12  %realarray opds(0:4)    {operand stack}

    float OPDS[5];

    //    13  %integerarray ops(0:3)    {operator stack}

    int OPS[4];

    //    14  %ownrealarray vars('a':'z')=0(*)

    static float VARS[26] = {[0 ... 25] = 0};

    //    15  %ownintegerarray vara('a':'z')=0(*)

    static int VARA[26] = {[0 ... 25] = 0};

    //    16  %integer op,opdsp,opsp,var

    int OP;
    int OPDSP;
    int OPSP;
    int VAR;

    //    17    opdsp=0 ; opsp=0    {init stack pointers}

    OPDSP = 0;
    OPSP = 0;

    //    18    pushopd(nextopd)    {first operand}

    PUSHOPD(NEXTOPD());

    //    19    %cycle    {for each operator}

  L_0001:;

  //    20      op=nextop

    OP = NEXTOP();

    //    21      %if op=end %then %exit

    if (OP != 7) goto L_0002;
    goto L_0003;
  L_0002:;

  //    22      operate %while opsp>0 %and prec(ops(opsp))>=prec(op)

  L_0004:;
    if (OPSP <= 0) goto L_0005;
    if (PREC[OPS[OPSP] - 1] < PREC[OP - 1]) goto L_0005;
    OPERATE();
    goto L_0004;
  L_0005:;

  //    23      %if op=assign %then %start

    if (OP != 6) goto L_0006;

      //    24        read symbol(var)

    _imp_READSYMBOL(/*?*/ &VAR);

    //    25        %unless 'a'<=var<='z' %or 'A'<=var<='Z' %then print symbol(var) %c

    {
// Double-sided test on VAR (Part I)
      int tmp;
      if (97 > (tmp = VAR)) goto L_0007;
// Double-sided test on VAR (Part II)
      if (tmp <= 122) goto L_0008;
    }
  L_0007:;
    {
// Double-sided test on VAR (Part I)
      int tmp;
      if (65 > (tmp = VAR)) goto L_0009;
// Double-sided test on VAR (Part II)
      if (tmp <= 90) goto L_0008;
    }
  L_0009:;
    _imp_PRINTSYMBOL(VAR);
    _imp_PRINTSTRING(_imp_str_literal(" variable"));
    _imp_signal(15, 0, 0, "");
  L_0008:;

  //    26+         %and print string(" variable") %and %signal 15
  //    27        %if 'A'<=var<='Z' %then var=var-'A'+'a'

    {
// Double-sided test on VAR (Part I)
      int tmp;
      if (65 > (tmp = VAR)) goto L_000A;
// Double-sided test on VAR (Part II)
      if (tmp > 90) goto L_000A;
    }
    VAR = VAR - 65 + 97;
  L_000A:;

  //    28        vars(var)=opds(opdsp)

    VARS[VAR - 97] = OPDS[OPDSP];

    //    29        vara(var)=1    {assigned}

    VARA[VAR - 97] = 1;

    //    30        %continue

    goto L_000B;

    //    31      %finish

  L_0006:;

  //    32      pushop(op)

    PUSHOP(OP);

    //    33      pushopd(nextopd)

    PUSHOPD(NEXTOPD());

    //    34    %repeat

  L_000B:;
    goto L_0001;
  L_0003:;

  //    35    operate %while opsp>0

  L_000C:;
    if (OPSP <= 0) goto L_000D;
    OPERATE();
    goto L_000C;
  L_000D:;

  //    36    %result=popopd

    return POPOPD();

    //    37  !
    //    38  %routine pushopd(%real val)

    void PUSHOPD(float VAL) {
      //    39    opdsp=opdsp+1

      OPDSP = OPDSP + 1;

      //    40    opds(opdsp)=val

      OPDS[OPDSP] = VAL;

      //    41  %end

      return;
    } /* end of PUSHOPD */

    //    42  !
    //    43  %routine pushop(%integer op)

    void PUSHOP(int OP) {
      //    44    opsp=opsp+1

      OPSP = OPSP + 1;

      //    45    ops(opsp)=op

      OPS[OPSP] = OP;

      //    46  %end

      return;
    } /* end of PUSHOP */

    //    47  !
    //    48  %realfn popopd

    float POPOPD(void) {
      //    49  %real val

      float VAL;

      //    50    val=opds(opdsp)

      VAL = OPDS[OPDSP];

      //    51    opdsp=opdsp-1

      OPDSP = OPDSP - 1;

      //    52    %result=val

      return VAL;

      //    53  %end

    } /* end of POPOPD */

    //    54  !
    //    55  %integerfn popop

    int POPOP(void) {
      //    56  %integer op

      int OP;

      //    57    op=ops(opsp)

      OP = OPS[OPSP];

      //    58    opsp=opsp-1

      OPSP = OPSP - 1;

      //    59    %result=op

      return OP;

      //    60  %end

    } /* end of POPOP */

    //    61  !
    //    62  %realfn nextopd

    float NEXTOPD(void) {
      //    63  %integer var

      int VAR;

      //    64  %real opd

      float OPD;

      //    65    skip symbol %while next symbol=space %or next symbol=nl

    L_000E:;
      if (_imp_NEXTSYMBOL() == 32) goto L_000F;
      if (_imp_NEXTSYMBOL() != 10) goto L_0010;
    L_000F:;
      _imp_SKIPSYMBOL();
      goto L_000E;
    L_0010:;

    //    66    %if '0'<=next symbol<='9' %or next symbol='-' %or next symbol='.' %c

      {
// Double-sided test on _imp_NEXTSYMBOL() (Part I)
        int tmp;
        if (48 > (tmp = _imp_NEXTSYMBOL())) goto L_0011;
// Double-sided test on _imp_NEXTSYMBOL() (Part II)
        if (tmp <= 57) goto L_0012;
      }
    L_0011:;
      if (_imp_NEXTSYMBOL() == 45) goto L_0012;
      if (_imp_NEXTSYMBOL() != 46) goto L_0013;
    L_0012:;
      _imp_READ(/*?*/ &OPD);
      return OPD;
    L_0013:;

    //    67+      %then read(opd) %and %result=opd
    //    68    %if next symbol='(' %then skip symbol %and %result=eval

      if (_imp_NEXTSYMBOL() != 40) goto L_0014;
      _imp_SKIPSYMBOL();
      return EVAL();
    L_0014:;

    //    69    %if 'a'<=next symbol<='z' %or 'A'<=next symbol<='Z' %then %start

      {
// Double-sided test on _imp_NEXTSYMBOL() (Part I)
        int tmp;
        if (97 > (tmp = _imp_NEXTSYMBOL())) goto L_0015;
// Double-sided test on _imp_NEXTSYMBOL() (Part II)
        if (tmp <= 122) goto L_0016;
      }
    L_0015:;
      {
// Double-sided test on _imp_NEXTSYMBOL() (Part I)
        int tmp;
        if (65 > (tmp = _imp_NEXTSYMBOL())) goto L_0017;
// Double-sided test on _imp_NEXTSYMBOL() (Part II)
        if (tmp > 90) goto L_0017;
      }
    L_0016:;

    //    70      read symbol(var)

      _imp_READSYMBOL(/*?*/ &VAR);

      //    71      %if 'A'<=var<='Z' %then var=var-'A'+'a'

      {
// Double-sided test on VAR (Part I)
        int tmp;
        if (65 > (tmp = VAR)) goto L_0018;
// Double-sided test on VAR (Part II)
        if (tmp > 90) goto L_0018;
      }
      VAR = VAR - 65 + 97;
    L_0018:;

    //    72      %if vara(var)=0 %then print symbol(var) %and %c

      if (VARA[VAR - 97] != 0) goto L_0019;
      _imp_PRINTSYMBOL(VAR);
      _imp_PRINTSTRING(_imp_str_literal(" unassigned"));
      _imp_signal(15, 0, 0, "");
    L_0019:;

    //    73+       print string(" unassigned") %and %signal 15
    //    74      %result=vars(var)

      return VARS[VAR - 97];

      //    75    %finish

    L_0017:;

    //    76    read symbol(var)

      _imp_READSYMBOL(/*?*/ &VAR);

      //    77    print symbol(var)

      _imp_PRINTSYMBOL(VAR);

      //    78    print string(" operand")

      _imp_PRINTSTRING(_imp_str_literal(" operand"));

      //    79    %signal 15

      _imp_signal(15, 0, 0, "");

      //    80  %end

      _imp_signal(8, 4, 0, "result missing");
    } /* end of NEXTOPD */

    //    81  !
    //    82  %integerfn nextop

    int NEXTOP(void) {
      //    83  %integer sym

      int SYM;

      //    84    skip symbol %while next symbol=space

    L_001A:;
      if (_imp_NEXTSYMBOL() != 32) goto L_001B;
      _imp_SKIPSYMBOL();
      goto L_001A;
    L_001B:;

    //    85    read symbol(sym)

      _imp_READSYMBOL(/*?*/ &SYM);

      //    86    %if sym='+' %then %result=plus

      if (SYM != 43) goto L_001C;
      return 1;
    L_001C:;

    //    87    %if sym='-' %then %result=minus

      if (SYM != 45) goto L_001D;
      return 2;
    L_001D:;

    //    88    %if sym='*' %then %result=times

      if (SYM != 42) goto L_001E;
      return 3;
    L_001E:;

    //    89    %if sym='/' %then %result=divide

      if (SYM != 47) goto L_001F;
      return 4;
    L_001F:;

    //    90    %if sym='^' %then %result=exp

      if (SYM != 94) goto L_0020;
      return 5;
    L_0020:;

    //    91    %if sym=':' %then %result=assign

      if (SYM != 58) goto L_0021;
      return 6;
    L_0021:;

    //    92    %if sym=')' %or sym=nl %then %result=end

      if (SYM == 41) goto L_0022;
      if (SYM != 10) goto L_0023;
    L_0022:;
      return 7;
    L_0023:;

    //    93    print symbol(sym)

      _imp_PRINTSYMBOL(SYM);

      //    94    print string(" operator")

      _imp_PRINTSTRING(_imp_str_literal(" operator"));

      //    95    %signal 15

      _imp_signal(15, 0, 0, "");

      //    96  %end

      _imp_signal(8, 4, 0, "result missing");
    } /* end of NEXTOP */

    //    97  !
    //    98  %routine operate

    void OPERATE(void) {
      //    99  %real opd1,opd2

      float OPD1;
      float OPD2;

      //   100  %switch opn(plus:exp)

      int OPN_index;
      int OPN_line;
      char *OPN_file;
      static const void *OPN[5] = {&&case_OPN_1, &&case_OPN_2, &&case_OPN_3, &&case_OPN_4, &&case_OPN_5};

      //   101    opd2=popopd

      OPD2 = POPOPD();

      //   102    opd1=popopd

      OPD1 = POPOPD();

      //   103    ->opn(popop)

      OPN_line = __LINE__;
      OPN_file = __FILE__;
      OPN_index = POPOP();
      goto case_OPN_dispatch;

      //   104  opn(plus):pushopd(opd1+opd2) ; %return

    case_OPN_1:;
      PUSHOPD(OPD1 + OPD2);
      return;

      //   105  opn(minus):pushopd(opd1-opd2) ; %return

    case_OPN_2:;
      PUSHOPD(OPD1 - OPD2);
      return;

      //   106  opn(times):pushopd(opd1*opd2) ; %return

    case_OPN_3:;
      PUSHOPD(OPD1 * OPD2);
      return;

      //   107  opn(divide):%if opd2=0 %then print string("divide by zero") %and %signal 15

    case_OPN_4:;
      if (OPD2 != 0) goto L_0025;
      _imp_PRINTSTRING(_imp_str_literal("divide by zero"));
      _imp_signal(15, 0, 0, "");
    L_0025:;

    //   108              pushopd(opd1/opd2) ; %return

      PUSHOPD((double)(OPD1 / OPD2));
      return;

      //   109  opn(exp):pushopd(opd1^int(opd2))

    case_OPN_5:;
      PUSHOPD(_imp_REXP(OPD1, _imp_INT(OPD2)));

      //   110  %end

      return;

    case_OPN_dispatch:
      if (OPN_index < 1 || OPN_index > 5)
        _imp_signalf(6, 3, OPN_index, "->OPN(%d) out of bounds at %s line %d", OPN_index, OPN_file, OPN_line);
      goto *OPN[OPN_index - 1];
    } /* end of OPERATE */

    //   111  !
    //   112  %end  {of eval}

    _imp_signal(8, 4, 0, "result missing");
  } /* end of EVAL */

  //   113  %real val

  float VAL;

  //   114
  //   115    %on %event 9,15 %start    {to trap everything}

  if (!_imp_on_event(9, 15)) goto L_0026;

    //   116  {*} %stop %if Event_Event = 9

  if (_imp_EVENT().EVENT != 9) goto L_0027;
  _imp_stop(0);
L_0027:;

//   117      print string("?

  _imp_PRINTSTRING(_imp_str_literal("?\n"));

  //   118+ ")
  //   119     ->again ; %finish

  goto U_1000;
L_0026:;

//   120
//   121  select input(0); select output(0)

  _imp_SELECTINPUT(0);
  _imp_SELECTOUTPUT(0);

  //   122        prompt("eval:")

  _imp_PROMPT(_imp_str_literal_size(15, "eval:"));

  //   123  again:val=eval

U_1000:;
  VAL = EVAL();

  //   124        %if val=int(val) %then write(int(val),0) { imp77 perms missing} {%else print(val,0,4)}

  if (VAL != _imp_INT(VAL)) goto L_0028;
  _imp_WRITE(_imp_INT(VAL), 0);
L_0028:;

//   125        newline

  _imp_NEWLINE();

  //   126        ->again

  goto U_1000;

  //   127
  //   128  %endofprogram

end_0:;
}