#include <perms.h>

//          Edinburgh IMP77 Compiler - Version 8.4
//
//     1  %record %format Global Fm ( %integer Blocks %or

struct GLOBALFM {
  union {
    struct {
      int BLOCKS;
    };
    struct {
      int PAD[20];
    };
  };
};

//     2+    %integer %array Pad(1:20) )
//     3
//     4  %const %integer Max Vars = 16_0 FFFF
//     5
//     6  %record %format Var Fm ( %integer a, b, c )

struct VARFM {
  union {
    struct {
      int A;
      int B;
      int C;
    };
  };
};

//     7
//     8  %routine Fail ( %string(255) S )

static void FAIL(_imp_string255 S) {
  //     9     Print String(S);  Newline

  _imp_PRINTSTRING(
      *({
        __typeof__(_imp_string255) tmp = S /*q*/;
        (_imp_string255 *)&tmp;
      })
  );
  _imp_NEWLINE();

  //    10     %stop

  _imp_stop(0);

  //    11  %end

} /* end of FAIL */

//    12
//    13  %begin

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

  //    14
  //    15     %recordformat Varsfm(%record(Varfm)%array Var(0:255))

  struct VARSFM {
    union {
      struct {
        struct VARFM VAR[256];
      };
    };
  };

  //    16     %constrecord(Varsfm)%name Varsfm Type == 0

  const struct VARSFM *VARSFMTYPE = 0;

  //    17     %recordformat Varpfm(%record(Varsfm)%name P)

  struct VARPFM {
    union {
      struct {
        struct VARSFM *P;
      };
    };
  };

  //    18     %record(Varpfm)%array Varp(0:Max Vars>>8)

  struct VARPFM VARP[((unsigned int)65535 >> 8) + 1];

  //    19
  //    20     %record(Varfm)%map Var(%integer Index)

  struct VARFM *VAR(int INDEX)
  {

    //    21        %own %record(Var Fm) Special Case Var

    static struct VARFM SPECIALCASEVAR;

    //    22        %result == Special Case Var %if Index = -1

    if (INDEX != -1) goto L_0001;
    return /*?*/ &SPECIALCASEVAR;
  L_0001:;

  //    23        Print String("Entered Var(");  Write(Index, 0)

    _imp_PRINTSTRING(_imp_str_literal("Entered Var("));
    _imp_WRITE(INDEX, 0);

    //    24        Print Symbol(')');  Newline

    _imp_PRINTSYMBOL(41);
    _imp_NEWLINE();

    //    25        Fail("P2/77") %unless 0 <= Index <= Max Vars

    {
// Double-sided test on INDEX (Part I)
      int tmp;
      if (0 > (tmp = INDEX)) goto L_0002;
// Double-sided test on INDEX (Part II)
      if (tmp <= 65535) goto L_0003;
    }
  L_0002:;
    FAIL(_imp_str_literal("P2/77"));
  L_0003:;

  //    26        %record(Varpfm)%name V == Varp(Index>>8)

    struct VARPFM *V;
    V = (struct VARPFM *)/*?*/ &VARP[(unsigned int)INDEX >> 8];

    //    27        %if V_P == Nil %start

    if (_imp_ADDR((void *)(V->P)) != _imp_ADDR((void *)(NIL))) goto L_0004;

      //    28           V_P == NEW(Varsfm Type)

    V->P = (struct VARPFM *)_imp_NEW(VARSFMTYPE);

    //    29        %finish

  L_0004:;

  //    30        %result == V_P_Var(Index&255)

    return /*?*/ &V->P->VAR[INDEX & 255];

    //    31     %end

  } /* end of VAR */

  //    32
  //    33     %integer J

  int J;

  //    34
  //    35     VarP(J)_P == Nil %for J = 0, 1, Max Vars >>8

  // %for J = 0, 1, (unsigned int)65535 >> 8 %cycle
  {
    int _final = (unsigned int)65535 >> 8;
    if (invalid_for_loop(0, 1, _final)) _imp_signal(5, 1, 0, "Illegal cycle J = 0, 1, (unsigned int)65535 >> 8");
    J = -1;
  L_0005:
    if (J == _final) goto L_0006;
    J += 1;
    VARP[J].P = (struct VARPFM *)NIL;
    goto L_0005;
  }

L_0006:;

//    36     Var(0) = 0

  *VAR(0) = (struct VARFM){0};

  //    37     Print String("Back from Var(0)");  Newline

  _imp_PRINTSTRING(_imp_str_literal("Back from Var(0)"));
  _imp_NEWLINE();

  //    38
  //    39  %end %of %program

  _imp_stop(0);
  return 0;
end_0:;
}