#include <perms.h>

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

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

  //     2
  //     3  !
  //     4  ! Precedence of operators
  //     5  !
  //     6  ! Highest: 1. \ (complement, unary not)
  //     7  !          2. \, \\, <<, >>
  //     8  !          3. *, /, //, &
  //     9  ! Lowest:  4. +, - (unary and binary), !, !!
  //    10  !
  //    11  ! In general, sub-expressions with operators of equal precedence are evaluated from left to right.
  //    12  !
  //    13  ! The one exception to the left-hand precedence rule is that consecutive
  //    14  ! exponentiations are evaluated from right to left; thus A**B**C is
  //    15  ! evaluated as A**(B**C), not as (A**B)**C.  (Imp80 documentation)
  //    16
  //    17  ! Arithmetic operators:
  //    18
  //    19  ! |...| modulus              also: !...!  (deprecated some time ago)
  //    20
  //    21  ! !  inclusive or
  //    22  ! !! exclusive or
  //    23  ! &  and
  //    24
  //    25  ! \  real exponentiation     also:  ^  (Imp77)  or  **    (ERCC compilers)
  //    26  ! \\ integer exponentiation  also:  ^^ (Imp77)  or  ****
  //    27
  //    28  ! *  multiply
  //    29  ! /  real division
  //    30  ! // integer division
  //    31
  //    32  ! << left shift
  //    33  ! >> right shift
  //    34
  //    35  ! +  plus
  //    36  ! -  minus
  //    37
  //    38  ! +  unary +
  //    39  ! -  unary -
  //    40  ! \  unary not               also ~ (can be *displayed* as: ¬ (&not;))
  //    41
  //    42  ! .  string concatenation
  //    43
  //    44  ! Comparison operators:
  //    45  ! =  eq
  //    46  ! #  not equals              also \= and <> (Imp80 documentation)
  //    47  ! == address equals
  //    48  ! ## address not equals      also \==
  //    49  ! -> string resolution       (a difficult to classify hybrid of a comparison and an assignment operator)
  //    50  ! <= less than or equals
  //    51  ! <  less than
  //    52  ! >= greater than or equals
  //    53  ! >
  //    54
  //    55  ! Assignment operators:
  //    56  ! =  assignment
  //    57  ! == pointer assignment
  //    58  ! <- jam transfer
  //    59  ! -> string resolution
  //    60
  //    61  ! Data structure operators:
  //    62  ! _  record field
  //    63  ! () array indexing
  //    64  ! [] pointer increment       (a Hamish extension in 68000 Imp only)
  //    65
  //    66  ! Other:
  //    67  ! @  may be considered an operator in %real literals, usually handled by a BIP.
  //    68
  //    69
  //    70    %const %integer a = 19, b = 17, c = 5, d = 3
  //    71    %integer x = a * b // c * d

  int X;
  X = ((long)(19 * 17) / (long)5) * 3;

  //    72    print string("Imp77 precedence and associativity test."); newlines(2)

  _imp_PRINTSTRING(_imp_str_literal("Imp77 precedence and associativity test."));
  _imp_NEWLINES(2);

  //    73    %if x = 21 %start

  if (X != 21) goto L_0001;

    //    74      print string("In a * b // c * d, '*' has higher priority than '/'."); newline

  _imp_PRINTSTRING(_imp_str_literal("In a * b // c * d, '*' has higher priority than '/'."));
  _imp_NEWLINE();

  //    75      print string("A second test with '/' will be needed to determine associativity:"); newline

  _imp_PRINTSTRING(_imp_str_literal("A second test with '/' will be needed to determine associativity:"));
  _imp_NEWLINE();

  //    76      x = a // c // d

  X = ((long)(((long)19 / (long)5)) / (long)3);

  //    77      %if x = 1 %start

  if (X != 1) goto L_0002;

    //    78        print string("a // c // d is right associative, i.e. a // (b // c)"); newline

  _imp_PRINTSTRING(_imp_str_literal("a // c // d is right associative, i.e. a // (b // c)"));
  _imp_NEWLINE();

  //    79      %else %if x = 19

  goto L_0003;
L_0002:;
  if (X != 19) goto L_0004;

    //    80        print string("a // c // d is left associative, i.e. (a // b) // c"); newline

  _imp_PRINTSTRING(_imp_str_literal("a // c // d is left associative, i.e. (a // b) // c"));
  _imp_NEWLINE();

  //    81      %else

  goto L_0003;
L_0004:;

//    82        print string("a // c // d is something weird!  I give up."); newline

  _imp_PRINTSTRING(_imp_str_literal("a // c // d is something weird!  I give up."));
  _imp_NEWLINE();

  //    83      %finish

L_0003:;

//    84    %else %if x = 19

  goto L_0005;
L_0001:;
  if (X != 19) goto L_0006;

    //    85      print string("a * b // c * d is right associative and with equal precedence, i.e. a * (b // (c * d))"); newline

  _imp_PRINTSTRING(
      _imp_str_literal("a * b // c * d is right associative and with equal precedence, i.e. a * (b // (c * d))"));
  _imp_NEWLINE();

  //    86      newline

  _imp_NEWLINE();

  //    87      print string("This grammar would support the above:"); newline

  _imp_PRINTSTRING(_imp_str_literal("This grammar would support the above:"));
  _imp_NEWLINE();

  //    88      newline

  _imp_NEWLINE();

  //    89      print string("P<expr> = <term> <op-term-list> ;"); newline

  _imp_PRINTSTRING(_imp_str_literal("P<expr> = <term> <op-term-list> ;"));
  _imp_NEWLINE();

  //    90      print string("P<op-term-list> = <op-term> <op-term-list> | ;"); newline

  _imp_PRINTSTRING(_imp_str_literal("P<op-term-list> = <op-term> <op-term-list> | ;"));
  _imp_NEWLINE();

  //    91      print string("P<op-term> = <op> <term> ;"); newline

  _imp_PRINTSTRING(_imp_str_literal("P<op-term> = <op> <term> ;"));
  _imp_NEWLINE();

  //    92    %else %if x = 192

  goto L_0005;
L_0006:;
  if (X != 192) goto L_0007;

    //    93      print string("a * b // c * d is left associative and with equal precedence, i.e. ((a * b) // c) * d"); newline

  _imp_PRINTSTRING(
      _imp_str_literal("a * b // c * d is left associative and with equal precedence, i.e. ((a * b) // c) * d"));
  _imp_NEWLINE();

  //    94      newline

  _imp_NEWLINE();

  //    95      print string("This grammar would support the above:"); newline

  _imp_PRINTSTRING(_imp_str_literal("This grammar would support the above:"));
  _imp_NEWLINE();

  //    96      newline

  _imp_NEWLINE();

  //    97      print string("P<expr> = <term-op-list> <term> ;"); newline

  _imp_PRINTSTRING(_imp_str_literal("P<expr> = <term-op-list> <term> ;"));
  _imp_NEWLINE();

  //    98      print string("P<term-op-list> = <term-op> <term-op-list> | ;"); newline

  _imp_PRINTSTRING(_imp_str_literal("P<term-op-list> = <term-op> <term-op-list> | ;"));
  _imp_NEWLINE();

  //    99      print string("P<term-op> = <term> <op> ;"); newline

  _imp_PRINTSTRING(_imp_str_literal("P<term-op> = <term> <op> ;"));
  _imp_NEWLINE();

  //   100    %else

  goto L_0005;
L_0007:;

//   101      print string("a * b // c * d uses some weird non-standard combination of precedence and associativity!"); newline

  _imp_PRINTSTRING(
      _imp_str_literal("a * b // c * d uses some weird non-standard combination of precedence and associativity!"));
  _imp_NEWLINE();

  //   102    %finish

L_0005:;

//   103    newline

  _imp_NEWLINE();

  //   104
  //   105
  //   106    %const %integer p = 4, q = 3, r = 2
  //   107    %integer y

  int Y;

  //   108
  //   109    y = p ^^ q ^^ r

  Y = _imp_IEXP(_imp_IEXP(4, 3), 2);

  //   110
  //   111    %if y = 262144 %start

  if (Y != 262144) goto L_0008;

    //   112      print string("p ^^ q ^^ r is right associative, i.e. p ^^ (q ^^ r)"); newline

  _imp_PRINTSTRING(_imp_str_literal("p ^^ q ^^ r is right associative, i.e. p ^^ (q ^^ r)"));
  _imp_NEWLINE();

  //   113      newline

  _imp_NEWLINE();

  //   114      print string("This grammar would support the above:"); newline

  _imp_PRINTSTRING(_imp_str_literal("This grammar would support the above:"));
  _imp_NEWLINE();

  //   115      newline

  _imp_NEWLINE();

  //   116      print string("P<expr> = <term> <exp-term-list> ;"); newline

  _imp_PRINTSTRING(_imp_str_literal("P<expr> = <term> <exp-term-list> ;"));
  _imp_NEWLINE();

  //   117      print string("P<exp-term-list> = <exp-term> <exp-term-list> | ;"); newline

  _imp_PRINTSTRING(_imp_str_literal("P<exp-term-list> = <exp-term> <exp-term-list> | ;"));
  _imp_NEWLINE();

  //   118      print string("P<exp-term> = ""^^"" <term> ;"); newline

  _imp_PRINTSTRING(_imp_str_literal("P<exp-term> = \"^^\" <term> ;"));
  _imp_NEWLINE();

  //   119    %else %if y = 4096

  goto L_0009;
L_0008:;
  if (Y != 4096) goto L_000A;

    //   120      print string("p ^^ q ^^ r is left associative, i.e. (p ^^ q) ^^ r"); newline

  _imp_PRINTSTRING(_imp_str_literal("p ^^ q ^^ r is left associative, i.e. (p ^^ q) ^^ r"));
  _imp_NEWLINE();

  //   121      newline

  _imp_NEWLINE();

  //   122      print string("This grammar would support the above:"); newline

  _imp_PRINTSTRING(_imp_str_literal("This grammar would support the above:"));
  _imp_NEWLINE();

  //   123      newline

  _imp_NEWLINE();

  //   124      print string("P<expr> = <term-exp-list> <term> ;"); newline

  _imp_PRINTSTRING(_imp_str_literal("P<expr> = <term-exp-list> <term> ;"));
  _imp_NEWLINE();

  //   125      print string("P<term-exp-list> = <term-exp> <term-exp-list> | ;"); newline

  _imp_PRINTSTRING(_imp_str_literal("P<term-exp-list> = <term-exp> <term-exp-list> | ;"));
  _imp_NEWLINE();

  //   126      print string("P<term-exp> = <term> ""^^"" ;"); newline

  _imp_PRINTSTRING(_imp_str_literal("P<term-exp> = <term> \"^^\" ;"));
  _imp_NEWLINE();

  //   127    %else

  goto L_0009;
L_000A:;

//   128      print string("p ^^ q ^^ r is something weird! ("); write(y, 0); print string(") - I give up."); newline

  _imp_PRINTSTRING(_imp_str_literal("p ^^ q ^^ r is something weird! ("));
  _imp_WRITE(Y, 0);
  _imp_PRINTSTRING(_imp_str_literal(") - I give up."));
  _imp_NEWLINE();

  //   129    %finish

L_0009:;

//   130    newline

  _imp_NEWLINE();

  //   131
  //   132  ! The remaining issue to be checked is how left/right associativity interact when the precedence is the same,
  //   133  ! which is only the case for exponentiation and shifts together, eg
  //   134  !
  //   135  ! a << b << c ^^ d ^^ e   or   a ^^ b ^^ c >> d >> e
  //   136  !
  //   137
  //   138  %endofprogram

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