#include <perms.h>
// Edinburgh IMP77 Compiler - Version 8.4
//
// 1 ! i77 collatz.imp
// 2 ! ./collatz
// 3 ! 837799
// 4 ! ./collatz
// 5 ! 8400511
// 6
// 7 ! https://www.reddit.com/r/C_Programming/comments/1eoc0v3/does_any_c_compiler_other_than_gcc_support_nested/
// 8
// 9 ! This is an imp77 source that corresponds more or less to
// 10 ! the example C source in the accompanying ccollatz.c file.
// 11
// 12 %begin
int main(int argc, char **argv) { /*%begin*/
_imp_initialise(argc, argv);
// 13 %integer odd1 = 1, odd2 = 2
int ODD1;
ODD1 = 1;
int ODD2;
ODD2 = 2;
// 14 %const %integer final value = 0, MAX FACTOR = (((~0)>>1)-1)//3
// 15 ! The integer overflow test here will trigger
// 16 ! at 0x7FFFFFFF rather than 0xFFFFFFFF because
// 17 ! this imp77 does not support unsigned 32-bit
// 18 ! integers. Other than that case, this code
// 19 ! should give the same results as the C version.
// 20
// 21 %const %integer terminating value = 1
// 22
// 23 %routine show collatz length(%integer i, %integername max)
void SHOWCOLLATZLENGTH(int I, int *MAX) {
// 24 ! Returns 0 for the length if there was an integer overflow.
// 25
// 26 %integer base value = final value + 1
int BASEVALUE;
BASEVALUE = 0 + 1;
auto int ODDCOLLATZ(int I);
// 27
// 28 %integerfnspec odd collatz(%integer i); ! mutual recursion requires a forward declaration!
// 29
// 30 %integerfn even collatz(%integer i)
int EVENCOLLATZ(int I) {
// 31 %if i < terminating value %then %result = final value
if (I >= 1) goto L_0001;
return 0;
L_0001:;
// 32 %if i > max %then max = i
if (I <= *MAX) goto L_0002;
*MAX = I;
L_0002:;
// 33 %if i&odd2 # 0 %start ;! 'optimization' :-)
if (I & ODD2 == 0) goto L_0003;
// 34 %result = base value+odd collatz(i>>1); ! (really just an excuse to justify this use of mutual recursion)
return BASEVALUE + ODDCOLLATZ((unsigned int)I >> 1);
// 35 %finish %else %start
L_0003:;
// 36 %result = base value+even collatz(i>>1)
return BASEVALUE + EVENCOLLATZ((unsigned int)I >> 1);
// 37 %finish
// 38 %end
} /* end of EVENCOLLATZ */
// 39
// 40 %integerfn odd collatz(%integer i)
int ODDCOLLATZ(int I) {
// 41 %if i <= terminating value %then %result = final value
if (I > 1) goto L_0004;
return 0;
L_0004:;
// 42 %if i > max %then max = i
if (I <= *MAX) goto L_0005;
*MAX = I;
L_0005:;
// 43 %if i > MAX FACTOR %then %signal 15,1,1; ! next call would cause integer overflow...
if (I <= 715827882) goto L_0006;
_imp_signal(15, 1, 1, "");
L_0006:;
// 44 %result = base value+even collatz((i<<1)+i+1)
return BASEVALUE + EVENCOLLATZ((I << 1) + I + 1);
// 45 %end
} /* end of ODDCOLLATZ */
// 46
// 47 print string("The Collatz sequence for")
_imp_PRINTSTRING(_imp_str_literal("The Collatz sequence for"));
// 48 write(i, 1)
_imp_WRITE(I, 1);
// 49 print string(" takes")
_imp_PRINTSTRING(_imp_str_literal(" takes"));
// 50
// 51 %onevent 15 %start
if (!_imp_on_event(15)) goto L_0007;
// 52 print string(" an unknown number of steps (we hit an integer overflow)")
_imp_PRINTSTRING(_imp_str_literal(" an unknown number of steps (we hit an integer overflow)"));
// 53 newline
_imp_NEWLINE();
// 54 %return
return;
// 55 %finish
L_0007:;
// 56
// 57 %if i&odd1 # 0 %then write(odd collatz(i), 1) %else write(even collatz(i), 1)
if (I & ODD1 == 0) goto L_0008;
_imp_WRITE(ODDCOLLATZ(I), 1);
goto L_0009;
L_0008:;
_imp_WRITE(EVENCOLLATZ(I), 1);
L_0009:;
// 58 print string(" steps and the largest value reached was")
_imp_PRINTSTRING(_imp_str_literal(" steps and the largest value reached was"));
// 59 write(max, 1)
_imp_WRITE(*MAX, 1);
// 60 newline
_imp_NEWLINE();
// 61 %end
return;
} /* end of SHOWCOLLATZLENGTH */
// 62
// 63 %integer highest, seed
int HIGHEST;
int SEED;
// 64
// 65 prompt("Integer seed value: ")
_imp_PROMPT(_imp_str_literal_size(15, "Integer seed value: "));
// 66 read(seed)
_imp_READ(/*?*/ &SEED);
// 67
// 68 %if seed < 0 %start
if (SEED >= 0) goto L_000A;
// 69 print string("Parameter must be a positive integer."); newline
_imp_PRINTSTRING(_imp_str_literal("Parameter must be a positive integer."));
_imp_NEWLINE();
// 70 %stop
_imp_stop(0);
// 71 %finish
L_000A:;
// 72
// 73 highest = 0; show collatz length(seed-1, highest)
HIGHEST = 0;
SHOWCOLLATZLENGTH(SEED - 1, /*?*/ &HIGHEST);
// 74 highest = 0; show collatz length(seed, highest)
HIGHEST = 0;
SHOWCOLLATZLENGTH(SEED, /*?*/ &HIGHEST);
// 75 highest = 0; show collatz length(seed+1, highest)
HIGHEST = 0;
SHOWCOLLATZLENGTH(SEED + 1, /*?*/ &HIGHEST);
// 76
// 77 %endofprogram
_imp_stop(0);
return 0;
end_0:;
}