This section is meant for people who do most of their programming in FORTRAN. FORTRAN has the distinction of being essentially the earliest higher level programming language, developed about 1957 by a group at IBM. Since then it and its derivatives have become established as the primary language for scientific and engineering computation. But, with our greater understanding of the process of creating programs has come a realization of the deficiencies of FORTRAN. Creating a program is properly thought of as taking a real world problem and translating it into a computer solution. Concepts in the real world such as a geneology tree or a queue of airplanes must be translated into computer concepts. A language is good if it enables one to describe these abstractions of the real world in a natural way. Perhaps because of its very early development, FORTRAN lacks many such features. In this appendix we explore the idea of writing a preprocessor for FORTRAN which inexpensively adds some of these missing features.
A preprocessor is a program which translates statements written in a language X into FORTRAN. In our case X is called SPARKS. Such a program is normally called a compiler so why give it the special name preprocessor? A preprocessor is distinguished from a compiler in the following way: the source and target language have many statements in common.
Such a translator has many advantages. Most importantly it preserves a close connection with FORTRAN. Despite FORTRAN's many negative attributes, it has several practical pluses: 1) it is almost always available and compilers are often good, 2) there is a language standard which allows a degree of portability not obtainable with other languages, 3) there are extensive subroutine libraries, and 4) there is a large labor force familiar with it. These reasons give FORTRAN a strong hold in the industrial marketplace. A structured FORTRAN translator preserves these virtues while it augments the language with improved syntactical constructs and other useful features.
Another consideration is that at many installations a nicely structured language is unavailable. In this event a translator provides a simple means for supplementing an existing FORTRAN capability. The translator to be described here can be obtained by writing to the address given at the end of this appendix.
In order to see the difference between FORTRAN and SPARKS consider writing a program which searches for X in the sorted array of integers A (N), N
This may not be the "best" way to write this program, but it is a reasonable attempt. Now we write this algorithm in SPARKS.
The difference between these two algorithms may not be dramatic, but it is significant. The WHILE and CASE statements allow the algorithm to be described in a more natural way. The program can be read from top to bottom without your eyes constantly jumping up and down the page. When such improvements are consistently adopted in a large software project, the resulting code is bound to be easier to comprehend.
We begin by defining precisely the SPARKS language. A distinction is made between FORTRAN statements and SPARKS statements. The latter are recognized by certain keywords and/or delimiters. All other statements are regarded as FORTRAN and are passed directly to the FORTRAN compiler without alteration. Thus, SPARKS is compatible with FORTRAN and a FORTRAN program is a SPARKS program. SPARKS statements cause the translator to produce ANSI FORTRAN statements which accomplish the equivalent computation. Hence, the local compiler ultimately defines the semantics of all SPARKS statements.
The reserved words and special symbols are:
Reserved words must always be surrounded by blanks. Reserved means they cannot be used by the programmer as variables.
We now define the SPARKS statements by giving their FORTRAN equivalents. In the following any reference to the term "statements" is meant to include both SPARKS and FORTRAN statements. There are six basic SPARKS statements, two which improve the testing of cases and four which improve the description of looping.
S1 and S2 are arbitrary size groups of statements. Cond must be a legal FORTRAN conditional. The ELSE clause is optional but the ENDIF is required and it always terminates the innermost IF.
S1,S2, ...,Sn+1 are arbitrary size groups of statements. Cond1, cond2, ..., condn are legal FORTRAN conditionals. The symbol ELSE surrounded by colons designates that Sn+l will be automatically executed if all previous conditions are false. This part of the case statement is optional.
The four looping statements are:
S is an arbitrary group of statements and cond a legal FORTRAN conditional.
S and cond are the same as for the while statement immediately preceding.
S is an arbitrary size group of statements.
This has a translation of:
The three expressions exp1, exp2, exp3 are allowed to be arbitrary FORTRAN arithmetic expressions of any type. Similarly vble may be of any type. However, the comparison test is made against integer zero. Since exp2 and exp3 are re-evaluated each time through the loop, care must be taken in its use.
EXIT is a SPARKS statement which causes a transfer of control to the first statement outside of the innermost LOOP-REPEAT statement which contains it. One example of its use is:
A generalization of this statement allows EXIT to be used within any of the four SPARKS looping statements: WHILE, LOOP, LOOP-UNTIL and FOR. When executed, EXIT branches to the statement immediately following the innermost looping statement which contains it.
The statement CYCLE is also used within any SPARKS looping statement. Its execution causes a branch to the end of the innermost loop which contains it. A test may be made and if passed the next iteration is taken. An example of the use of EXIT and CYCLE follow.
EOJ or end of job must appear at the end of the entire SPARKS program. As a statement, it must appear somewhere in columns 7 through 72 and surrounded by blanks.
ENDIF is used to terminate the IF and ENDCASE to terminate the CASE statement. REPEAT terminates the looping statements WHILE, LOOP and FOR.
Labels follow the FORTRAN convention of being numeric and in columns one to five.
The use of doubleslash is as a delimiter for comments. Thus one can write
//This is a comment//
and all characters within the double slashes will be ignored. Comments are restricted to one line and FORTRAN comments are allowed.
The semi-colon can be used to include more than one statement on a single line For example, beginning in column one the statement
99999 A = B + C; C = D + E; X = A
would be legal in SPARKS. To include a semicolon in a hollerith field it should be followed by a second semicolon. This will be deleted in the resulting FORTRAN.
We are now ready to describe the operation of the translator. Two design approaches are feasible. The first is a table-driven method which scans a program and recognizes keywords. This approach is essentially the way a compiler works in that it requires a scanner, a symbol table (though limited), very limited parsing and the generation of object (FORTRAN) code. A second approach is to write a general macro preprocessor and then to define each SPARKS statement as a new macro. Such a processor is usually small and allows the user to easily define new constructs. However, these processors tend to be slower than the approach of direct translation. Moreover, it is hard to build in the appropriate error detection and recovery facilities which are sorely needed if SPARKS is to be used seriously. Therefore, we have chosen the first approach. Figure A.1 contains a flow description of the translator.
The main processing loop consists of determining the next statement and branching within a large CASE. This does whatever translation into FORTRAN is necessary. When EOJ is found the loop is broken and the program is concluded.
The SPARKS translator was first written in SPARKS. The original version was hand translated into FORTRAN to produce our first running system. Since that time it has been used by a variety of people and classes. Thus it is running far better than the original version. Nevertheless, the translator has not been proved correct and so it must be used with caution.
Below is a list of possible extensions for SPARKS. Some are relatively easy to implement, while others require a great deal of effort.
E.1 Special cases of the CASE statement
The first gets translated into the FORTRAN arithmetic IF statement. The second form is translated into a FORTRAN computed go to.
E.2 A simple form of the FOR statement would look like
where exp is an expression which evaluates to a non-negative integer. The statements meaning can be described by the SPARKS for statement:
An internal integer variable ITEMP must be created.
E.3 If F appears in column one then all subsequent cards are assumed to be pure FORTRAN. They are passed directly to the output until an F is encountered in column one.
E.4 Add the capability of profiling a program by determining the number of executions of each loop during a single execution and the value of conditional expressions.
HINT: For each subroutine declare a set of variables which can be inserted after encountering a WHILE, LOOP, REPEAT, FOR, THEN or ELSE statement. At the end of each subroutine a write statement prints the values of these counters.
E.5 Add the multiple replacement statement so that
A = B = C = D + E
is translated into
C = D + E; B = C; A = B
E.6 Add the vector replacement statement so that
(A,B,C) = (X + Y, 10,2*E)
produces A = X + Y: B = 10 ; C = 2*E
E.7 Add an array "fill" statement so that
NAME(*)
gets translated into
NAME(1) = exp1; NAME(2) = exp2; NAME(3) = exp3
E.8 Introduce appropriate syntax and reasonable conventions so that SPARKs programs can be recursive.
HINT: Mutually recursive programs are gathered together in a module, MODULE (X(A,B,C)(100)) whose name is X, whose parameters are A,B,C and whose stack size should be 100.
E.9 Add a character string capability to SPARKS.
E.10 Add an internal procedure capability to aid the programmer in doing top-down program refinement.
E.11 Attach sequence numbers to the resulting FORTRAN output which relates each statement back to the original SPARKS statement which generated it. This is particularly helpful for debugging.
E.12 Along with the indented SPARKS source print a number which represents the level of nesting of each statement.
E.13 Generalize the EXIT statement so that upon its execution it can be assigned a value, e.g.,
will assign either expl or exp2 as the value of the variable EXIT.
E.14 Supply a simplified read and write statement. For example, allow for hollerith strings to be included within quotes and translated to the nH x1 ... xn format.
All further questions about the definition of SPARKS should be addressed to:
Chairman, SPARKS Users Group
Computer Science, Powell Hall
University of Southern California
Los Angeles, California 9007
To receive a complete ANSI FORTRAN version of SPARKS send $20.00 (for postage and handling) to Dr. Ellis Horowitz at the above address.
100. The output is the integer J which is either zero if X is not found or A(J) = X, 1
J
N. The method used here is the well known binary search algorithm. The FORTRAN version looks something like this:
SUBROUTINE BINS (A,N,X,J)
IMPLICIT INTEGER (A - Z)
DIMENSION A(100)
BOT= 1
TOP= N
J = 0
100 IF (BOT. GT. TOP) RETURN
MID = (BOT + TOP)/2
IF (X. GE. A (MID)) GO TO 101
TOP = MID - 1
GO TO 100
101 IF (X. EQ. A (MID)) GO TO 102
BOT = MID + 1
GO TO 100
102 J = MID
RETURN
END
SUBROUTINE BINS (A,N,X,J)
IMPLICIT INTEGER (A - Z)
DIMENSION A(100)
BOT = 1; TOP = N; J = 0
WHILE BOT. LE. TOP DO
MID = (BOT + TOP)/2
CASE
: X. LT. A(MID): TOP = MID - 1
: X. GT. A(MID): BOT = MID + 1
:ELSE: J = MID; RETURN
ENDCASE
REPEAT
RETURN
END
BY CASE CYCLE DO ELSE ENDCASE
ENDIF EOJ EXIT FOR IF LOOP
REPEAT UNTIL WHILE TO THEN :
; //
IF cond THEN IF(.NOT. (cond)) GO TO 100
S1 S1
ELSE GO TO 101
S2 100 S2
ENDIF 101 CONTINUE
WHILE cond DO 100 IF(.NOT. (cond)) GO TO 101
S S
REPEAT GO TO 100
101 CONTINUE
LOOP 100 CONTINUE
S S
UNTIL cond REPEAT IF(.NOT. (cond)) GO TO 100
LOOP 100 CONTINUE
S S
REPEAT GO TO 100
101 CONTINUE
FOR vble = expl TO exp2 BY exp3 DO
S
REPEAT
vble = expl
GO TO 100
102 vble = vble + exp3
100 IF ((vble - (exp2))*(exp3).GT. 0) GO TO 101
S
GO TO 102
101 CONTINUE
LOOP 100 CONTINUE
S1 S1
IF cond THEN EXIT IF(.NOT. (cond)) GO TO 102
ENDIF GO TO 101
S2 102 CONTINUE
REPEAT S2
GO TO 100
101 CONTINUE
LOOP 100 CONTINUE
S1 S1
CASE IF(.NOT. (cond1) GO TO 103
: cond1 : EXIT GO TO 102
: cond2 : CYCLE IF(.NOT. (cond2)) GO TO 104
ENDCASE 103 GO TO 101
S2 CONTINUE
REPEAT 104 S2
GO TO 100
101 CONTINUE
102
Figure A.1: Overview of SPARKS Translator
Extensions
CASE SGN : exp: CASE: integer variable:
: .EQ.0 : S1 : 1 : S1
: .LT.0 : S2 and : 2 : S2
: .GT.0 : S3
ENDCASE : n : Sn
ENDCASE
LOOP exp TIMES
S
REPEAT
FOR ITEMP = 1 TO exp DO
S
REPEAT
exp1,exp2,exp3
LOOP
S1
IF condl THEN EXIT : exp1: ENDIF
S2
IF cond2 THEN EXIT : exp2: ENDIF
S3
REPEAT