I’d welcome feedback on some new stuff in a development version of SPAG which is currently on the stocks. There are 2 new restructuring mechanisms which, in conjunction with the existing facilities, remove all(*) GOTO constructs in even the most convoluted legacy code.
In the first construct, the source code is divided into separately addressable blocks, which are executed in the correct sequence under control of a dispatch loop.
DispatchLoop : DO
SELECT CASE (DispatchVariable)
CASE (1)
block 1
CASE (2)
block 2
CASE (3)
block 3
...
END SELECT
ENDDO DispatchLoop
GOTOs are replaced by an appropriate assignment to DispatchVariable followed by CYCLE DispatchLoop. DO loops are treated as unbreakable units, but each DO may contain its own dispatch loop, which occasionally leads to nested dispatch loops. I think that overall, it works well, and the imposed structure often helps to clarify what the code is doing.
The second construct is similar, but in this case the code blocks are placed in recursive internal subroutines, and GOTOs are replaced by calls to those routines, followed by a RETURN to ensure the recursion unwinds correctly.
This second approach can lead to very deep recursion, and that worries me. However, no data is passed with each new call (the internal subroutines have no arguments or local variables). To date, we have seen no noticeable degradation in performance or memory use using this approach, but in one case we had to make a modest increase to the stack size. In simple cases, for example when different strands use the same tidying up code, this approach seems ideal, but for more complex cases, I think I find it less clear than using dispatch loops. I also worry that compilers may baulk at it, or produce code that is likely to run out of resources at runtime. Many more tests, including a huge F77 engineering code, are planned.
What do you guys think - which approach do you prefer (if either)? I’ve attached an example of a very convoluted program for solving chess problems, and the output produced using the the current release (v0) and with the above new features (v1 and v2).
(*) Either approach works well for the most common spaghetti Fortran constructs (GOTO, arithmetic IF, computed GOTO), but not so easily with ASSIGNed GOTO, alternate returns, and END= etc in I/O statements.