RATFOR & FLECS - Language Features
Hi and welcome back. Today let’s continue our exploration of RATFOR and FLECS by comparing the language features they add to vanilla FORTRAN. The quotes below are from the RATFOR paper and FLECS manual, links to which are provided at the end of this post. Code samples for FORTRAN and FLECS are shown in upper case, RATFOR in lower case.
Design
RATFOR attempts to retain the merits of FORTRAN (universality, portability, efficiency) while hiding the worst FORTRAN inadequacies. The language is FORTRAN except for two aspects - [control flow and syntactic sugar] … Throughout, the design principle which has determined what should be in RATFOR and what should not has been RATFOR doesn’t know any FORTRAN.
RATFOR focuses on control flow - if statements, blocks, looping - and cosmetics such as free form input, comments and other features that make FORTRAN more pleasant to write. By not knowing any FORTRAN, the design limits what features can be made available but also keeps it simple to implement and reduces the temptation to change FORTRAN into a different language altogether.
FLECS is a language extension of FORTRAN which has additional control mechanisms . These mechanisms make it easier to write FORTRAN by eliminating much of the clerical detail associated with constructing FORTRAN programs. FLECS is also easier to read and comprehend than FORTRAN.
FLECS also tries ti improve FORTRAN’s control statements, taking ideas from several different languages including Pascal and Lisp. It has less cosmetic additions than RATFOR but adds the concept of internal procedures and includes features in the translator that help the programmer see the structure of their program.
Structure
RATFOR allows blocks of statements to be introduced within braces where FORTRAN would only allow a single statement. The fixed column format in classic FORTRAN is relaxed so any indentation is allowed. Multiple statements can appear on the same line if they are separated by semicolons.
if (x > 100) {
call error(x)
err = 1; return
}
FLECS also has blocks which extend from the start of a control statement to the keyword FIN
. It retains the fixed formatting of FORTRAN but prints a nicely indented view of the program when translating. So the example above would be entered as this in FLECS:
IF (X .GT. 100)
CALL ERROR(X)
ERR = 1
FIN
and the translator would print
IF (X .GT. 100)
. CALL ERROR(X)
. ERR = 1
...FIN
This is useful when entering programs via cards where it is difficult to get indentation right.
It’s possible to have a single statement after a control structure in which case the FIN
is not needed:
IF (X .GT. 100) CALL ERROR(X)
RATFOR comments are introduced with #
and apply from that point to the end of the line, less restrictive than C
in FORTRAN and FLECS which must be in the first column.
%
will stop RATFOR processing the rest of the line, passing it through to FORTRAN directly. FLECS will look for a FLECS statement in column 7 and if found will translate the line; if not found it will pass through the whole line to FORTRAN.
Textual substitution
RATFOR allows constants to be set with define SYMBOL VALUE
; any use of SYMBOL
in the RATFOR program will be replaced with VALUE
in the generated FORTRAN program.
include FILE
will insert a copy of FILE
at that point in the program, just like C’s #include
.
Operators
RATFOR allows the now-familiar symbols <
, <=
, !=
, |
etc to be used instead of .LT.
, .LE.
, .NE.
, .OR.
etc. FLECS retains the FORTRAN operators.
Strings
Text in RATFOR programs in single or double quotes is converted to FORTRAN nH strings. Backslash escapes the next character. FLECS keeps FORTRAN strings.
Conditionals
FORTRAN has a simple iF
statement where only one statement can be executed if the condition is true. RATFOR extends this by allowing else
and nested ifs. An else clause is attached to the nearest if.
if (x > 0) {
if (x > 10)
write(6, 1) x
else
write(6, 2) x
else
weite(6, 3)
FLECS has IF
and for negative tests UNLESS
. It also has WHEN
… ELSE
for a single positive and negative test.
The switch
statement added in RATFOR looks like C but does not have break
; the switch is exited after each case
or default
is executed. FLECS’s equivalent is SELECT
, so comparing the two:
switch (x) {
case 1: y=3
case 2, 3: y=5
default y=0
}
SELECT (X)
(1) Y=3
(2) Y=5
(3) Y=5
(OTHERWISE) Y=0
FIN
FLECS has CONDITIONAL
which looks a lot like LISP’s cond
:
CONDITIONAL
(X.LT.-5.0) U = U+W
(X.LE.1.0) U = U+W+Z
(X.LE.10.5) U = U-Z
(OTHERWISE) U = 0
FIN
Looping
The FORTRAN DO
loop has to have a line number marking the point where the loop will restart:
DO 10 i = 1, n
x(i) = 0.0
y(i) = 0.0
z(i) = 0.0
10 CONTINUE
RATFOR replaces this with a block:
do i = 1, n {
x(i) = 0.0
y(i) = 0.0
z(i) = 0.0
}
It also allows break
to exit a loop early and next
to restart the loop like C’s continue
. It can be followed by an integer to say how many levels to apply, so break 2
would move out of a two level do
statement immediately.
RATFOR also adds a while
and for
statement that look like C’s - these allow immediate exit from the statement if the condition is true on entry, unlike in FORTRAN DO
where the statement is always executed at least once (in the IBM implementation at least) and the conditional is tested at the end of the statement. A version of C’s do
… while
is provided as repeat
… until
.
The FLECS equivalent for the above do
loop would be:
DO (I = 1, N)
X(I) = 0.0
Y(I) = 0.0
Z(I) = 0.0
FIN
FLEC’s WHILE
construct is similar to RATFOR’s, with the conditional tested before the loop starts. By using REPEAT WHILE
the body of the loop is executed at least once and the test made at the end of the loop. UNTIL
can be used instead of WHILE
in both cases to indicate that the loop ends when the conditional becomes true
X = 0
UNTIL (X.EQ.5)
X = X + 1
FIN
Return
To return a value from a function in FORTRAN and FLECS you must assign a value to the name of the function:
INTEGER FUNCTION DECREMENT(I)
INTEGER I
DECREMENT = I - 1
RETURN
END
In the RATFOR paper it says you can give return
a value:
integer function decrement(i)
integer i
return (i-1)
end
However, note this is not supported in the version supplied with MTS - it will just pass through such a return
statement causing an error from the FORTRAN compiler.
Internal procedures
FLECS allows a group of statements to be defined as a procedure with TO
which can then be called by giving its name. No parameters are passed - it uses global variables to communicate. The below example will print 5.
INTEGER X
X = 1
INCREMENT-IT
DOUBLE-AND-INCREMENT
WRITE(6,50) X
STOP
50 FORMAT(I10)
TO INCREMENT-IT X = X + 1
TO DOUBLE-AND-INCREMENT
X = X * 2
INCREMENT
FIN
END
Procedure names must include at least one hyphen and recursion is not allowed.
Operation
RATFOR runs as a simple translator, taking a RATFOR input file and producing a FORTRAN output file that must then be fed to the FORTRAN compiler. FLECS, as modified at UM, will both translate and call the FORTRAN compiler, producing machine code output that can be run directly.
Error handling
RATFOR will catch some errors, such as missing closing braces, but will otherwise delegate problems with the program to the FORTRAN compiler to catch, as it does not understand FORTRAN syntax. This could be difficult to trace back to the source of the error as the FORTRAN compiler would show the error in the generated FORTRAN, not the RATFOR original.
FLECS will find syntax errors and remove them from the program, allowing translation to continue at the cost of possibly causing further errors; it will not move on to compilation in this case.
Implementation
Not surprisingly given its authors’ roots, RATFOR was originally written in around 1000 lines of C using yacc. The authors say it took less than a week to implement. As C was not widely available in the mid 70’s, a version of RATFOR in RATFOR was produced that would generate around 2500 lines of basic FORTRAN so it could be used anywhere.
The FLECS implementation comes in at around 2200 lines of FLECS and took around six months to develop according to comments in the source code.
Further information
See Kernighan’s RATFOR paper or the FLECS User’s Manual (in component 673/22; I’ve uploaded a copy here) for more information on the languages.