← Back to context

Comment by PaulHoule

4 days ago

Mainframe-era systems often used fixed-size or limited-size buffers and data structures, based on those 80-character punched cards, most addressing modes on the 360 add 12-bit immediate displacements to pointers held in registers [1] bytes and such.

It is easy to laugh but C programmers have demonstrated that they can't handle variable-sized buffers on the stack, malloc(), free() and all that.

Early versions of FORTRAN [2] didn't even have a stack, like you couldn't write recursive functions, the program would take parameters for array sizes when it boots and the memory layout would all be figured out at the beginning. When I was developing a display controller for persistence of vision displays for the AVR-8 it drove me nuts how the C compiler kept moving the stack pointer around all the time for no real reason when an assembly program could move data to and from statically allocated structures. [3]

FORTRAN and COBOL came out around the time Syntactic Structures did so of course there was not an established theory for how to parse grammars, no parser generators, etc. No Dragon Book, but the heroic techniques used to develop compilers in that age are legendary if not quite lost.

I wrote some FORTRAN programs in high school on a VAX, in a comparative programming languages class in college, converted a lot of FORTRAN algorithms into statically allocated Java in grad school in 1990 and in my postdoc I wrote a generator that wrote JNI bindings for LAPACK.

[1] ... e.g. the typical struct is < 4096 bytes

[2] before the FORTRAN 90 standard though you could set the /RECURSIVE flag on DEC FORTRAN

[3] we were done such a disservice by all those "it's so elegant to compute Fibonacci in a better programming language than BASIC" articles in Creative Computing because recursion is one of those things, like C's memory management, that most programmers can't really handle.

DEC VAX/VMS Fortran 77, ca. mid-1980s, did use the process stack for call, return and arguments; all the compilers DEC supplied on that platform did, because there was a common calling sequence among all the languages and you could call any language from any other.

I dimly remember the reason for it not being recursive by default was it didn’t put local variables on the stack, and I guess /RECURSIVE (which I don’t remember) controlled that. Probably there was some SYSGEN parameter which limited stack size. There were people who would declare giant arrays as locals rather than putting them in named COMMON, so the user-friendly compiler default was to put them in a fixed PSECT because those same people would never be using recursion.

  • To this day some Fortran compilers put large local variables into static storage rather than the stack. Because many old Fortran programs were written with the assumption that all procedure variables were statically allocated, and thus having huge arrays as local variables wasn't an issue.

    This kind of code then easily breaks by overflowing the stack if the compiler allocates them there.

    But this then doesn't work that well if the procedure is called recursively, or concurrently from multiple threads.

    Making this even worse, in a recent Fortran standard (2008?) this was reversed such that procedures must be explicitly marked with NON_RECURSIVE in order to allow the compiler to allocate variables statically. Undoubtedly the right decision given the increasing prevalence of threads as well as recursive algorithms, but a gotcha for compiling old dusty deck code.

Fortran (before 90) ignored characters after column 72 because the IBM 704 had a 36-bit word and read each row of a card into two words. (The card reader could be wired with a plugboard to select any 72 of 80 columns from the card.)