.ma 1 ;.in +10;.nf
.ma 2 ;.in -10;.fi
.ma 3 ;.ch $;.ix $
.ma 4 ;.hl 2 $;.ix $
.pl 62
.rm 78
.he RATFOR User Manual|page #
.fo Vitomir Smolej - MPI, Stuttgart
.nc 1
.ce 7
R A T F O R
#
the RATional FORtran pre-processor
#
#
#
Contents
#
.nf
.sl
1	Introduction............................2
#
2	RATFOR Control Statements...............3
2.1	If......................................3
2.2	Grouping Statements.....................3
2.3	If-Else.................................4
2.4	While...................................5
2.5	Repeat..................................5
2.6	Repeat-Until............................6
2.7	For.....................................6
2.8	Do......................................7
2.9	Break...................................8
2.10	Next....................................9
2.11	Nesting.................................9
#
3	Cosmetics..............................10
3.1	Continuation and Statement Format......10
3.2	Comments...............................10
3.3	Semicolons and Null Statements.........11
3.4	Shortforms.............................11
3.5	Define.................................12
3.6	Definelist.............................13
3.7	Include................................15
3.8	Logical Operators && and !!............16
3.9	Return.................................18
#
4	Running RATFOR.........................19
4.1	Command Line...........................19
4.2	Hints and Caveats......................20
#
5	Building RATFOR under CP/M.............21
#
6	Example................................21
#
	Index..................................23
.el
.fi
.m3 Introduction
.fo
 RATFOR (RATional FORtran) is a language based on FORTRAN.
To FORTRAN, RATFOR adds modern control structures including
if-else, while, repeat-until, for, break, and next. There are
also some cosmetic differences between RATFOR and
FORTRAN: RATFOR statements are format-free; there can be more
than one RATFOR statement per line; and the RATFOR continuation
convention is different. Also, the RATFOR Do statement is
slightly different from the FORTRAN Do. Finally, there is no Arithmetic 
If in RATFOR. Apart from these differences, RATFOR is FORTRAN.
 Both the design of the RATFOR language and the structure of
the RATFOR processor program are given by Kernighan and Plauger
in their book "Software Tools" (Addison-Wesley, Don Mills, Ontario, 1976).
 The version of RATFOR described here contains the
following differences from that described in the book:
.sl
.le Three new statements - break group, definelist, and
return (expression) - have been implemented.
.le The continuation convention is slightly different.
.le Only ' can delimit hollerith constants. 
.le >> is the shortform for .GT. and << is the shortform for .LT. 
.el
 Why bother with RATFOR? To answer this question, Kernighan
and Plauger state:
 "You may wonder why we make such an issue of
avoiding goto. After all, you can do anything, and more, with
goto than you can with the RATFOR control statements. It turns
out, though, that the extra freedom permitted by goto is just
what you don't want. By restricting yourself to a small set of
control flow structures, you tend to write code that is better
thought out, more readable, and hence less error prone."
 The RATFOR processor produces a FORTRAN program which may be
compiled with any FORTRAN compiler.

.m3 RATFOR Control Statements
.m4 If
Syntax:
.m1 3
if( logical expression )
	statement
.m2
The logical expression is evaluated, and the statement is performed 
only if the expression is true. The statement may be any RATFOR statement. 
For example:
.m1 3
if( A .LE. B .OR. C .NE. D)
	call tryit(a,b,c,d)
.m2 
.m4 Grouping Statements
 We may wonder what use the If statement is since it looks
like it can control only one statement, just like the FORTRAN
logical If. The trick is that RATFOR allows statements to be
grouped by the brackets [ and ]. These grouped statements are
treated as if they were one statement. For example:
.m1 6
if(a .GT. B) [
	call flip(a,b)
	flipped=.True.
	C=b
	]
.m2 
It does not really matter where the brackets appear. Thus, we can also say :
.m1 5  
if (a .GT. B)
	[call flip(a,b)
	flipped=.True.
	C=b]
.m2
 On a terminal with lower-case letters, you can type letters
{ instead of [ and } instead of ]. Keyboards with German letters 
have A and U instead of [,] (and shifted-out a and u for {,}).
 RATFOR uses brackets to group statements. Some languages
use special keywords like begin and end instead of brackets.
Kernighan and Plauger recommmend that indenting be used to emphasize 
statement grouping or loops, and prefer brackets to keywords
because they are easier to type and less obtrusive. If we like
keywords, the section on the Define statement (3.5) shows how to
use them in RATFOR.
.m4 If-Else
Syntax:
.m1 5
if (logical expression)
	statement1
else
	statement2
.m2
The logical expression is evaluated, and if true statement1 is
performed. Otherwise, statement2 is done. An Else always goes
with the nearest "un-elsed" If. (Note: the Else must start a
new statement.) For example:
.m1 5
if( i .LE. j)
	min =i
else
	min = j
.m2
.m1 9
if( switch .OR. .NOT. (a .LE. b)) [
	call test(a)
	c = atan2(a,b)
	]
else [
	call error
	call exit
	]
.m2
We can also build an If-Else chain to select one case from many:
.m1 11
if(char .EQ. ')' )
	Npar=npar-1
else if (char .EQ. '(')
	Npar=npar+1
else if (char .EQ. ';') [
	npar=0
	call endsta
	]
else
	call error
.m2
This is indented to emphasize the selection of one of many choices.
.m4 While
Syntax:
.m1 3
while( logical expression )
	statement
.m2
The logical expression is evaluated, and the statement is performed 
if, and only if, the expression is true. After the statement is 
performed, the expression is re-evaluated, and the statement 
is done again if the expression is still true. This loop
continues until the expression in the while becomes false. The
statement will not be done at all if the logical expression is initially false.
 For example:
.m1 3
while( buf(i) .NE. index .AND. i .LE. n)
	i=i+1
.m2
.m4 Repeat
Syntax:
.m1 3
repeat
	statement
.m2
This control structure causes the statement to be performed forever 
unless the loop is broken by a statement like the break
statement (section 2.9). For example:
.m1 6
repeat [
	call input
	call xeq
	call output
	]
.m2
.m4 Repeat-Until
Syntax:
.m1 4
repeat
	statement
until (logical expression)
.m2
The statement is performed, and then the logical expression in
the Until is evaluated. If the expression is false, the statement 
is performed again, and this loop continues until the logical 
expression becomes true. For example:
.m1 8
logical done
repeat [
	call input
	call doit(done)
	]
until (done)
.m2
Notice that the statement is always done at least once.
.m4 For
Syntax:
.m1 3
for(initialize; logical expression; re-initialize)
	statement
.m2
 The For statement provides a powerful looping facility. The initialize 
and re-initialize portions of this statement can be any
FORTRAN (not RATFOR) statements; they should be related to control 
of the For loop.
 First, the initialize statement is done. If the logical expression 
is then false, the statement and re-initialize portions
are skipped. Otherwise, first the statement and then the
re-initialize portions are performed. The logical expression is
then re-evaluated, and the process repeats.  This
test-statement-re-initialize loop continues until the logical expression 
becomes false. Of course, the For statement may not be
done at all if the expression is initially false. The For is
equivalent to this While:
.m1 6
initialize
while (logical expression) [
	statement
	re-initialize
	]
.m2
The For is preferable because it gathers all the loop control information 
into one statement.
 Any combination of the initialize, test, or re-initialize
portions may be omitted. If the test is omitted, the result is
an infinite loop. However, if two or more parts are omitted, a
While or Repeat statement is probably a clearer choice.
 At its simplest, the For statement is a Do loop with the
test at the top. By making the test expression compound, we can
(say) go through a whole array and stop either at the end or when
some special element is found. See the first two examples of the
For. The For statement is also handy for controlling loops that
have no inherent arithmetic progression: stepping through linked
lists or hash tables are two examples of this (see the third example 
of the For).
 Some examples:
.m1 3
for(i=1; i .LE. n; i=i+1)
	vec(i)=0
.m2
.m1 3
for(i=1; i .LE. n .AND. Vec(i) .NE. istop; i=i+1)
	call proces(vec(i))
.m2
.m1 3
for(i=h(key); k .LE. tsiz .AND. tab(i) .NE. key; i=reh(i))
	k=k+1
.m2
.m1 3
for(;code .GT. 0; code=done-1)
	call out(chars(code))
.m2
.m1 5
for(i=1;;i=i+1) [
	call doit(i)
	call chkhlt(i)
]
.m2
.m1 3
for(i=1; i .LE. n)
	call bump(i)
.m2
.m4 Do
Syntax:
.m1 3
do limits
	statement
.m2
Here, limits are the standard FORTRAN Do limits, such as "i = 1,n".
This is simply a FORTRAN Do, except that RATFOR takes care
of generating a label, and putting a labelled Continue at the end
of the loop. Just about every Do can be replaced with a For;
the converse is certainly not the case (e.g. the second example
of the For).
 An example of a Do is:
.m1 6
do i=istart, iend [
	k=ivec(i)
	ivec(i)=jvec(i)
	jvec(i)=k
	]
.m2
.m4 Break
Syntax:
.m1 2
break
.m2
The Break statement must always appear within some looping RATFOR
statement (i.e. for, do, repeat, while). When executed, it
causes the loop to be broken, and execution continues with the
statement following the last statement in the loop. For example:
.m1 7
repeat [
	call input(char)
	if(char .EQ. EOF)
	 break
	call handle(char)
	]
.m2
If the Break appears within nested RATFOR loops, only the innermost 
loop is broken. A different form of the Break statement looks like this:
.m1 2
break group
.m2
This does not break loops, but instead breaks bracketted statement 
groups. It must always appear within a group of statements
enclosed by [ and ]. When executed, control goes to the place
immediately before the ], which means that the remaining statements 
in the group are skipped. Like Break, Break group affects
only the innermost group. An example of Break group use is given
in section 3.6. 
.m4 Next
Syntax:
.m1 2
next
.m2
Like the Break, the Next statement always appears within a RATFOR
loop. It causes the remainder of the innermost loop to be
skipped, and goes to the next iteration of this loop. To be
specific, Next goes to:
.sl
.le the start of a Do or bare Repeat,
.le the test expression of an Until or While,
.le the re-initialize of a For.
.el
.m4 Nesting
 This implementation of RATFOR allows RATFOR statements to be
nested to a maximum depth of 50. For example, these For statements 
are nested to a depth of two, and the If-Else brings the
total nesting depth to four:
.m1 7
for(i=1; i .LE. n; i=i+1)
	for(j=1; j .LE. m; j=j+1)
		if( i .EQ. j)
			matrix(i,j)=1
		else
			matrix(i,j)=0
.m2
Notice that there are no brackets grouping the inner For or the
If-Else. Since the For statements each control only one RATFOR
statement, these grouping brackets are optional. They could be
included, if desired. However, the less brackets there are in a
listing, the easier it is to read. Let indenting show the flow
of the program to a reader; the brackets are for the computer.
Often a loop will consist of an If or If-Else like the above For;
the brackets are unneeded in this case. The rule is: a RATFOR
statement controls the immediately following statement and any
statements controlled by this following statement.

.m3 Cosmetics
.m4 Continuation and Statement Format
 RATFOR statements can appear anywhere on the line. If a
statement has a label, it is placed just before the beginning of
the statement and is followed by at least one blank or tab. We
can place a tab in front of all unlabelled statements, if we want.
 RATFOR continuation conventions are different from
FORTRAN's. Any line ending in a ",", "&", or "!" is automatically 
continued. Since continued statements are usually either
lists of things separated by commas (e.g. format) or long logical 
expressions, the automatic continuation is often enough.
Also, any line ending in an underscore ('_') is continued with
the underscore removed. (Notice that the underscore may print as a
back arrow.) There is no limit to the number of continuations,
but the FORTRAN compiler may fail if a lot of FORTRAN continuations 
result from a long RATFOR statement.
.m4 Comments
 RATFOR uses the number sign ("_# ") to indicate comments. If
a _# is found anywhere on the line, including the start, the rest
of that line is ignored. The FORTRAN C comment convention is not
used since RATFOR statements can start in the first column of the line.
 If a line containing a _# is to be continued, pretend that
the _# comment is not there when setting up the continuation. For
example, the commas in the following integer statement provide
automatic continuation as discussed in section 3.1:
.m1 4
Integer sum,	_# the sum of the variables
	small,	_# the smallest member
	averag	_# integer version of the average
.m2
.m4 Semicolons and Null Statements
 RATFOR allows many statements to be on one line if they are
separated by semicolons. For example:
.m1 4
if(switch) [
	temp=vec(i); vec(i) = vec(j); vec(j) = temp
	]
.m2
Any statement starting with a semicolon is a null statement
and produces no FORTRAN code. The null statement can be used as
the body of a loop when all the work required of the loop is done
in the controlling RATFOR statement. For example, this For advances 
to the first non-blank character in text:
.m1 3
for(i=1; text(i) .EQ. ' '; i=i+1)
.m2
The null statement can also be written as [].
.m4 Shortforms
 RATFOR permits the following abbreviations for FORTRAN logical operators:
.m1 10
#.LT.	<<
#.EQ.	==
#.GT.	>>
#.GE.	>= or =>
#.LE.	<= OR =<
#.NE.	<> or >< or ^= or ~=
#.AND.	&
#.OR.	! or | (vertical bar - on German keyboard)
#.NOT.	^ or ~ (tilde - on German keyboard)
.m2
The translation to the regular FORTRAN logical operators does not
occur in quote-type hollerith constants.
.m4 Define
Syntax:
.m1 2
define  name characters
.m2
Name can be any string of letters or digits with blanks
or tabs on both sides. From here on in the program, wherever
Name occurs in the program, it is replaced by the characters.
These characters can be any string of characters not including a
blank or tab. The characters are terminated by the first blank
or tab, or by the end of the line. Alternatively, the characters
can be a hollerith constant which may include blanks or tabs.
Then the hollerith constant replaces 'name' wherever 'name' appears. 
 Two things should be noted: The Define statement is not
put in the FORTRAN output, and the Define statement may not be
continued. When the defined name appears in the program, it must
be surrounded by blanks or other non-alphanumerics to be recognized. 
Definitions are remembered across subprograms.
 There is no limit to the length of name or characters, except 
that the entire define statement must fit into one line.
RATFOR limits the total number of defined names to 257. The
total length of all defined names and replacement text cannot
exceed 2048 characters.
 The following examples illustrate some common uses of Define:
.m1 9
define NEWLINE 010
define BLANK 032
define CHAR logical
define MAXLINE 100
...
CHAR inp(MAXLINE)
call reader(inp)
for(i=1; i<=MAXLINE & inp(i)<>BLANK & inp(i)<>NEWLINE; i=i+1)
.m2
would be translated as if it were written:
.m1 4
logical inp(100)
call reader(inp)
for(i=1; i<=100 & inp(i)<> 032 & inp(i)<> 010; i=i+1)
.m2
Defined names have been used to hide the representation of a "new
line" and the maximum size (dimension) of the vector inp. This
makes it easier to change these values, and easier to understand the program.
 If the characters in the Define text themselves contain a
defined name, it too is replaced. For example, the above definition 
of newline could have been written as:
.m1 3
define NEWLINE LF
define LF  010
.m2
It does not matter in what order the definitions appear; the replacement 
occurs when newline is used, not when it is defined.
 As promised above, here is a way to use keywords instead of
brackets for grouping statements:
.m1 13
define start [
define finish ]
#
if(a >> b)
	start
	  call parta
	  call partaa
	finish
else	start
	  call partb
	  call partbb
	finish
.m2
Of course, we cannot define End, since it has other purposes in FORTRAN.
.m4 Definelist
Syntax:
.m1 2
definelist integer name1 name2 name3 name4 name5 ...
.m2
The integer must be greater than 0 and less than 30000. The
names are separated by blanks or tabs. The Definelist statement
may be continued with the underscore. The action of the statement 
is this: The first name is defined as the integer, the second 
as the integer plus one, and so on. For example:
.m1 2
definelist 1000 alpha beta gamma delta
.m2
is a shortform for this set of Defines:
.m1 5
define alpha 1000
define beta 1001
define gamma 1002
define delta 1003
.m2
The integer part of this statement allows the programmer to
control where the definitions start. If the same names are used
in separately compiled subprograms, this can be used to make sure
that the names are defined to the same value.
 Why provide a Definelist statement? The answer to this
question is best given by an example, and what better example
than the RATFOR processor program itself. Inside this program,
special characters like [ and ], and keywords like If, are encoded 
as integers. For example, if statyp is the integer encoding
of the thing we are now examining, we can see if it is an If
statement as follows:
.m1 3
if(statyp .EQ. 7)
	handle if, etc.
.m2
Encoding things as integers like this could cause problems. It
leads to mistakes (and did several times during RATFOR's debugging)
and makes the program hard to read. With Definelist, we can write:
.m1 3
definelist 1000	 lbrack rbrack semicol eof lexif lexelse_
		 lexwhile lexrepeat lexuntil lexfor lexdo etc.
.m2
Now, we can write:
.m1 6
if( statyp .EQ. Lexif )
	something
else if (statyp .EQ. Lexelse)
	something else
else etc.
.m2
Since the names in the Definelist are assigned ordered values, we can write:
.m1 3
if(statyp .GT. EOF)
	handle if, else, etc.
.m2
This should be used with care, since it can obscure the workings of a program.
 The Definelist and Computed Goto can be used as a Case statement:
.m1 17
define case goto
if( statyp .GT. EOF ) [
	case(lexif, lexelse, lexwhile, etc.), Statyp-eof
	[
	lexif
		call doif
		break group
	lexelse
		if( everything ok)
			call doelse
		else
			call error
		break group
	etc.
	]
	]
.m2
How does this work? Since lexif etc. are defined as integers,
they can be used as statement numbers, too. The Computed Goto
index must start at 1, so first we subtract eof. The Break group
statement is used to separate the different cases, so the entire
block, controlled by Goto, must be grouped with brackets.
 Whenever RATFOR sees a statement consisting only of a statement 
number, it attaches the statement number to a Continue. So,
we can combine cases just by writing the case names on separate
lines. For example, in the above case, we might use something like this:
.m1 5
lexrepeat
lexuntil
	something common to repeat and until
break group
.m2
Another way to do this is to put semicolons after each case name:
.m1 4
lexrepeat; lexuntil
	something common to repeat and until
break group
.m2
Since lexif etc. are used as statement labels in this context, we
must be careful not to duplicate these labels elsewhere in the same subprogram.
.m4 Include
Syntax:
.m1 3
include filename
include filename/l
.m2
The statements in file filename are placed in the FORTRAN output.
The default extension for filename is ".RAT" and the default
drive is "B:". Of course you can use prefix A: any time you need
files from the drive A:.
 No listing of the file is produced. If you need it, you may
use the second form of the Include statement. The file switch /l 
(or /L) causes the file to be listed.
 Include is often used to copy a file containing a common
block definition. We can set up such a file with lots of comments like this:
.m1 6
integer names(257), length(257)
logical*1 text(2048)
common /tables/ names,	 _# hash table pointers
		length,	 _# length of defined names
		text	 _# holds defined names and text
.m2
(Note the use of commas for automatic continuation.) Now if this
file was needed in a subprogram, all we need say is:
.m1 2
include tables
.m2
where tables.rat is the file name. In addition, RATFOR will not
clutter up the listing of this subprogram with these statements.
All RATFOR statements in the included file are processed.
You can use an included file of define statements, for instance.
 Include statements may be nested to a maximum depth of two.
An Include may appear in an included file, but that is as far as it can go.
.m4 Logical Operators && and !!
 The operators && and !! are closely related to & (.AND.)
and ! (.OR.). They can be used in any RATFOR statement that
needs a logical expression (i.e. if, while, for, until). The
important thing about && and !! is that they allow us to control
the order in which a logical expression is evaluated. For example, 
suppose we want to search a vector vec of 10 elements for
the first non-zero element. A first attempt at a solution might be:
.m1 2
for( i=1; i<=10 & vec(i)<>0; i=i+1)
.m2
This will not work. FORTRAN may allow the subexpression
vec(i)<>0 to be evaluated when i is greater than 10. This would
lead to a reference out of the bounds of vec. In RATFOR we can
use && instead of &, and then the part i<=10 will always be done
before vec(i)<>0; furthermore, the subexpression vec(i)<>0 is
evaluated only if i<=10 is true. To be precise, when && used,
the left subexpression is evaluated first, and the right subexpression 
is evaluated only when the left subexpression is true.
A correct solution to the problem is:
.m1 2
for(i=1; i<=10 && vec(i)<>0; i=i+1)
.m2
 Similarly, !! gives us control over the order in which two
logical expressions are ored. A wordier solution to the above problem is:
.m1 6
repeat [
	if(i >> 10 !! vec(i) <> 0)
		break
	i=i+1
	]
.m2
To be precise, when !! is used, the left subexpression is
evaluated and, if true, the remainder of the expression is
skipped. Otherwise, the right subexpression is done.
 An expression is allowed to contain any number of && and !!
symbol pairs. If there are several, the expression is evaluated
strictly from left to right. For example:
.m1 2
a >> b && c << d !! e <> f
.m2
is evaluated like this:
.sl
.le if a <= b no more is done and the expression is false,
.le else, if c << d no more is done and the expression is true,
.le else, the value of the expression is e <> f.
.el
On the other hand,
.m1 2
e <> f !! c << d && a >> b
.m2
is evaluated like this:
.sl
.le if e <> f, the expression is true and no more is done,
.le else if c >= d, no more is done and the expression is false,
.le else the value of the expression is the value of a >> b.
.el
 The operators && and !! cannot appear within parentheses
(except for the outermost parentheses enclosing the expression).
The character pair || can be used for !!.
.m4 Return
Syntax:
.m1 2
return( expression )
.m2
This special Return statement is used in Function subprograms.
When RATFOR finds a Function statement, it remembers the function
name. A return statement like this appearing in a function
causes this FORTRAN code to be produced:
.m1 3
function name = (expression)
return
.m2
The RATFOR Return statement makes it simpler to see what a
function is returning. For example, here is a logical function
search which returns true iff the integer int is in the vector
vec (which has n elements):
.m1 8
logical function search(vec,n,int)
integer vec(n),n,int
for(i=1; i<=n; i=i+1)
	if(vec(i) == int)
		return(.true.)
return(.false.)
end
.m2
RATFOR will only recognize the Function statement if the
word function is surrounded by blanks or tabs. Also, a Function
statement must be the first non-RATFOR statement in a source
file, or the first non-RATFOR statement after an End statement.
This form of the Return should only be used in Function subprograms. 
Of course, we can still use the normal Return statement anywhere.

.m3 Running RATFOR
.m4 Command Line
 You can invoke RATFOR by typing:
.m1 2
A>rat 
.m2
RATFOR will prompt "rat>" for the command line, execute it
and prompt again, until _^C is typed in. (*)
.fn
----------------------------------------------------------------------------
(*)	A special version is "rats". This program uses the program parameter 
	as given in the CCP call of the program file as command line. Thus, 
		>rats =input
	will call the RATFOR pre-processor for file input.
	rats immediately returns to CP/M upon execution.
!!
 The command line for RATFOR takes one of these five forms:
.sl
.le output,list=input1,input2,...
.le output=input1,input2,...
.le ,list=input1,input2,...
.le ,=input1,input2,...
.le =input1,input2....
.el
 The FORTRAN output is written into file output. If this file
name is missing -as in form 3) and 4)-, then the first input file name
is used as default. The lines written to the FORTRAN output file 
contain no padding blanks to spare disk space.
 An optional switch /l (or /L) can be written after the filename
for input files. In this case, RATFOR places (in columns 73-80 of 
the line) the number of the RATFOR statement which produced this
FORTRAN statement. These numbers are used to cross-reference
compile-time error messages produced by the FORTRAN compiler.
Once the typing errors are out of the program, the FORTRAN compiler's
listing is no longer needed. The RATFOR listing should
be used for documentation and debugging. 
 This listing is placed in the file list when this file name
is present. Every RATFOR statement is numbered twice: once with
a RATFOR number, and once with a FORTRAN number. The FORTRAN
number is in parentheses. It is the number of the first FORTRAN
statement produced by this RATFOR statement. What use is this? If
execution-time errors occur, the clean RATFOR listing can be consulted 
to find the bad statement. Sometimes, the number of the
bad statement might not appear on the RATFOR listing; for example, 
we may get an execution-time error in statement 14, and look
at the RATFOR listing only to find:
.m1 3
(12) else if (vec(i) >> 0) [
(15)  call proces(vec(i))
.m2
There is no line 14. The reason is that Else has produced 3 statements, 
and number 14 is one of them. So the error is in the Else If.
 If the fourth or fifth form of the command line is used, RATFOR lists
all RATFOR error messages and the bad RATFOR statements on the
terminal. When many input files are used, they are effectively concatenated.
 The fifth form (just like in the case of F80) can be used 
for routine compilations: no listing, output file has the same 
name as the source file (but, of course, different extension).
Default drive is B:, the default extensions are:
.nf
#
	.RAT for the input file,
	.LST for the RATFOR listing, and 
	.FOR for the output file.
#
.fi
.m4 Hints and Caveats
 In RATFOR, the keywords if, else, repeat, until, do, for,
while, next, and break are reserved words and should not be used
as identifiers. The keywords must be followed by a blank, tab,
'(', or some other special character to be recognized. RATFOR
does not care about the case of keywords; we can write repeat,
REPEAT, or even REPeat. The same applies to names appearing in
Define statements. Also, RATFOR translates any lower case
letters, outside of quote-type holleriths, to upper case so we
can write FORTRAN statements in lower case, too.
 It pays off, however, to use capitals for defined words and 
constants (like NEWLINE, BLANK) and use lower-case letters for the rest.
 RATFOR recognizes only quote-type holleriths. Also, H type
holleriths may be used, but any shortforms like == or !
appearing in them will be translated. Also, quote-type holleriths 
are limited to 100 characters, and may not extend across a
line boundary (even if the line is continued).
 There is no Arithmetic If in RATFOR (good riddance!).
 RATFOR uses FORTRAN labels in the range 23000 through 23999,
so these numbers should be avoided in the user's program.
 RATFOR silently truncates any input lines longer than 100
characters. All blank or empty lines are ignored by RATFOR;
hence white space may be used freely to emphasize loops and to
separate declarations.
 It is difficult to totally eliminate the Goto. It can be
used in code that handles erroneous input. Sometimes, the only
thing the code can do, when it finds uncorrectable input, is to
go to some place at the bottom of the subprogram for error handling. 
By the way, these Gotos are by no means always required.
Often, an If-Else with a Return in the error handling part will
do the trick. Only when there are so many nested If-Elses, that
the code becomes unwieldy, may a Goto be needed.

.m3 Building RATFOR under CP/M (*)
.fn
-------------------------------------------
(*) CP/M is a Trademark of Digital Research 
!!
 RATFOR is built and installed with these commands:
.m1 14
 A>era rat.*
 A>wm rat.for
 *! using WordMaster to preprocess the source file ratx.for
 *yb:cnvrt.rat
 *100qp
 *b
 *! this will take a little longer
 *yb:ratx.for
 *! this will last a little too
 *qx 
 *e
 A>f80 =rat
 A>l80 rat,forlib/S/,rat/n/e
.m2
  Executing the following commands:
.m1 5
 A>b:rat
 rat>,testerr=testerr
 rat>,=testok
 rat>^C
.m2
should produce 24 errors in the first case and none in the case
of the second test file. Try then the file prime (see next chapter).

.m3 Example
 Here is a RATFOR program which computes the first ten twin
primes. Twin primes are consecutive odd numbers that are prime.
Note the heavy use of the For statement in the program; many
loops are naturally expressed by the For.
.m1 21
_# Twin prime printer
#
integer test,count,test2
logical prime
define YES .true.
define NO .false.
#
write(5,1)
1 format(' list of first 10 twin primes' //)
#
for (test=3; count<=10; test=test+2)
	if (prime(test) & prime(test+2))
	[	test2=test+2
		write(5,10) test,test2
		10 format(5x,2i7)
		count=count+1
	]
call exit
end
.m2
.m1 18
_# return true iff n is a prime integer
#
logical function prime(n)
integer n,factor
#
if (n==2)
	return (YES)
else if (n<=1 || mod(n,2)==0)
	return (NO)
else [
	for (factor=3; factor*factor<=n; factor=factor+2)
		if (mod(n,factor)==0)
			return (NO)
	return (YES)
]
end
.m2
.bl 2
.m1 15
list of first 10 twin primes
#
  3  5
  5  7
  11  13
  17  19
  29  31
  41  43
  59  61
  71  73
  101 103
  107 109
  137 139
.m2
.px INDEX


