! i77 collatz.imp

! ./collatz
! 837799
! ./collatz
! 8400511

! https://www.reddit.com/r/C_Programming/comments/1eoc0v3/does_any_c_compiler_other_than_gcc_support_nested/

! This is an imp77 source that corresponds more or less to
! the example C source in the accompanying ccollatz.c file.

begin
  integer odd1 = 1, odd2 = 2
  const integer final value = 0, MAX FACTOR = (((~0)>>1)-1)//3
                                  ! The integer overflow test here will trigger
                                  ! at 0x7FFFFFFF rather than 0xFFFFFFFF because
                                  ! this imp77 does not support unsigned 32-bit
                                  ! integers.  Other than that case, this code
                                  ! should give the same results as the C version.
                                  
  const integer terminating value = 1

  routine show collatz length(integer i, integername max)
    ! Returns 0 for the length if there was an integer overflow.
    
    integer base value = final value + 1
    
    integerfnspec odd collatz(integer i);   ! mutual recursion requires a forward declaration!

    integerfn even collatz(integer i)
      if i < terminating value then result = final value
      if i > max then max = i
      if i&odd2 # 0 start ;  ! 'optimization' :-)
        result = base value+odd collatz(i>>1);  !  (really just an excuse to justify this use of mutual recursion)
      finish else start
        result = base value+even collatz(i>>1)
      finish
    end

    integerfn odd collatz(integer i)
      if i <= terminating value then result = final value
      if i > max then max = i
      if i > MAX FACTOR then signal 15,1,1;    ! next call would cause integer overflow...
      result = base value+even collatz((i<<1)+i+1)
    end

    print string("The Collatz sequence for")
    write(i, 1)
    print string(" takes")

    onevent 15 start
      print string(" an unknown number of steps (we hit an integer overflow)")
      newline
      return
    finish

    if i&odd1 # 0 then write(odd collatz(i), 1) else write(even collatz(i), 1)
    print string(" steps and the largest value reached was")
    write(max, 1)
    newline
  end

  integer highest, seed

  prompt("Integer seed value: ")
  read(seed)

  if seed < 0 start
    print string("Parameter must be a positive integer."); newline
    stop
  finish

  highest = 0; show collatz length(seed-1, highest)
  highest = 0; show collatz length(seed,   highest)
  highest = 0; show collatz length(seed+1, highest)

endofprogram