home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 22 gnu
/
22-gnu.zip
/
fweb140x.zip
/
demos
/
demo.web
< prev
next >
Wrap
Text File
|
1993-10-30
|
43KB
|
1,142 lines
\Title{DEMO.WEB}
\def\FORTRAN{{\Csc FORTRAN}}
\let\Fortran\FORTRAN
\def\Ratfor{{\Csc RATFOR}}
\def\C{{\Csc C}}
\def\mf{{\Csc m4}}
\def\Weave{{\tt FWEAVE}}\let\WEAVE\Weave
\def\Tangle{{\tt FTANGLE}}\let\TANGLE\Tangle
\def\f77{\FORTRAN--77}
\def\FWEB{{\tt FWEB}}
@n/
@* INTRODUCTION. This is a demo/test program (\It{not} the formal user's
manual; for that, see \.{fwebman.tex}) for a
\Fortran/\Ratfor/C version of Knuth's WEB documentation system. Weave or
tangle this
demo with, for example, the command-line
\.{FWEAVE demo demo -d -m4 -mCMD\_LN\_MACRO=25}
\noindent \It{Note that the tangled output consists of fragments of correct
code mindlessly abutted together; this demo is not intended to be compiled
into a workable program.}
The fundamental idea is to automatically format source code, and to
intermix comments and documentation typeset using the full, sophisticated
powers of \TeX. The system facilitates and encourages writing short,
one-page functions, and provides both a table of contents of the principal
sections of documentation and a complete index of all variables used in the
source code.
The system consists of two processors: \Weave, and \Tangle. Both
operate on a common source file which contains both the documentation
and the code. (Actually, it is better to say that the documentation \It{is}
the code, and vice versa.) The pieces of the source file are
identified by various commands beginning with~`\.{@@}'.
\Weave\ produces documentation like you are reading now; \Tangle\ strips
off the documentation and produces compilable files.
Here is a simple example, consisting of modules~2 through~7. You should
look at the source file `\.{demo.web}' with an editor to see in detail how
this documentation was produced.
@ Typically, the code is divided into various blocks or \It{modules},
indicated, for example, as
\.{@@<Demo@@>}. These blocks can be defined in any order, and need not be
defined all at once. They will be collected and organized by WEB.
To get things started, there is also an \It{unnamed module}, introduced by
the command~`\.{@@a}'.
\It{Fundamentally, the output of \Tangle\ is the contents of the unnamed
module}. This could just consist of straight code, which will be output
essentially unchanged. However, if in the unnamed module there is a
reference to a named module, then \Tangle\ will stop at that point to
output the contents of that module.
Each module consists of three parts: (1)~a \TeX\ part, containing arbitrary
\TeX\ material that explains what is happening in the module, (2)~a
definition/format part, which contains macro definitions and certain format
statements (see below), and (3)~a code part, which will eventually make its
way to a compilable file. In the present example, the \TeX\ part is begun by
the command~`\.{@@\ }',
the definition part is empty, and the code part is begun either by~`\.{@@a}'
(which signifies the unnamed module),
or by a module name followed by an equals sign.
Here, for example, is a simple unnamed module which tells \Tangle\ to
output the contents of all the pieces that are eventually accreted to the
unnamed module, followed by the contents of the three named modules
``\.{Demo}'', ``\.{Ccode}'', and~``\.{R}''. The superscripts to the angle
brackets denote the language in which the module is written. (When the
modules are in the default language, which is \Fortran, the superscripts
are suppressed. Languages will be described in more detail later.) The
code section of this module is begun by the nonprinting command~`\.{@@a}',
which signifies the start of the \It{unnamed} module. Remember: \It{The
unnamed module must always be present, otherwise \Tangle\ will not output
any code.}
@A
@<Demo@> /* Constructions such as `\.{@@<text@@>}' mean insert the
contents of block with name |"text"| here. WEB filled in the module
number~3 automatically, to tell you where to look to find the definition of
the module `\.{Demo}'. There is actually an invisible semicolon after the
module name which was inserted automatically by \Fortran's |auto_semi|
mode. In \Fortran, the semicolons are not printed; however, they are in
other languages. */
@c
/* The next semicolons were inserted by the user,
because~\C\ and \Ratfor\ have the semicolons as an intrinsic part of the
language. */
@<Ccode@>; /* A module in the \C\ language. This will be tangled into
the file ``\.{demo.c}''. */
@r
@<R@>; /* A \Ratfor\ module. This will be tangled into
``\.{demo.rat}'' (if \mf\ is turned off, which is the default), or
``\.{demo.m4}'' (if \mf\ is turned on with the command-line option
`\.{-m4}'). */
@ Here, instead of starting the code section with~`\.{@@a}', we start with
a module name followed by an equals sign---namely, we typed
`\.{@@<Demo@@>=}'. This means that you are defining (or accreting to, if
there's a previous module with this name), this block of code.
@<Demo@>=@[
program main
integer itype
read *,itype
if(itype .eq. 1) then
@<Process type 1.@> /* Arbitrary sections of code can be
included like this. We actually typed ``\.{@@<Process type 1.@@>}''. WEB
filled in the module number~4 automatically to tell you where this module
was first defined. */
else if(itype.eq.2) then
@<Process type 2.@> /* This facility makes each function
much more readable. */
else
@<Process all other types.@> /* You don't need to define
this code before it is used in the function. */
end if
end
@ In general, each code block would be much longer than this. (But,
hopefully, still not longer than about 12~lines (Knuth's guideline).
If it is, then you should use
the \.{@@<...@@>} facility again to highlight the logic better.
@<Process type 1.@>=
call dotype(itype) /* Inside comments, one is in \TeX\ mode, so,
for example, one can have math:
$\sum_{i=0}^{100}$. One can also have code fragments (delimited by
vertical bars), such as |call dotype(itype)|. */
@ Here's a contrived example to show that you can nest inclusions of named
modules.
@<Process type 2.@>=
call dotype(itype**3) /* $\iota^3$.*/
@<Process type 1.@> /* Nothing wrong with physically
inserting the same block twice. */
@ What we actually typed below was ``\.{@@<Process all...@@>}''. If the text
before the dots uniquely identifies the module, WEB will fill in the
rest for you.
@<Process all...@>=
call dotype((itype-3)**5) /* $(\iota-3)^5$. */
@ Here is an example of how to accrete to a block which has already been
defined. What we typed was ``\.{@@<Process type 1.@@>=}''; \Weave\ inserts
the plus sign automatically to tell you that you've already defined the
block, and that you're now accreting to it.
@<Process type 1.@>=
write(6,100) itype
100 format('TYPE = ',i2) /* You don't have to type the colon after numeric
statement labels. (You do for alphanumeric labels; see below.) */
@* FEATURE TEST. We shall first introduce the WEB features informally, by
showing how various constructions look. This also serves as a test program
for the code itself. The formal rules for writing a WEB program can be
found in the user manual \.{fwebman.tex}. Again, until further notice we
are discussing \Fortran\ code exclusively.
@ Before we examine the WEB output, we must get the source code in. This is
annoying because of \FORTRAN's line-oriented syntax. However, WEB tries to
make life somewhat easier for you. (Remember, in all cases, \Tangle\ will
do the right thing and produce a compilable file.)
On input, lines are strings of up to 160~characters. On output, the line
length is \f77's limit of 72~characters. If \TANGLE\ creates an output line
of more than 72~characters, the line will be properly continued. (No
attempt is made to break the line at ``pretty'' places.)
There are several kinds of comments, which we shall call \FORTRAN-style
and C-style.
@^comments@>
The standard \FORTRAN\ variety follows
the VAX rule: a standard comment has a |'C'| (upper or lower case),
or a~|'*'| in column~1. (See the user manual for a discussion of comments
beginning with exclamation points.)
These comments are turned automatically
into the standard C~format |"/*...*/"|. At the moment, if several contiguous
lines are comments, they are concatenated into one comment. You may wish to
argue with this choice.
{\it The \FORTRAN-style comments are retained for compatibility with existing
code. For new codes, it is recommended that one use the C-style format.}
The C-style comments actually come in two varieties: the \It{long} kind,
`{/*\dots*/}', which can be continued across newlines, and the \It{short}
kind, begun by `\.{//}' and terminated by the next newline. (The short
comments must be turned on explicitly with the command-line
option~`\.{-/}', as otherwise they would be understood as string
concatenation. When they are turned on, you can use~`\.{\\/}' for
concatenation.
Comments can also follow program text on a line (``trailing comments'').
These must have the C~format. Thus, here are examples of comments. You
should look in the source file to see exactly how these examples were done.
@a
program main
C This line began with a |'C'| in column~1.
x = y /* A trailing C~comment is delimited as shown. */
a = b
C A trailing \FORTRAN\ comment; this was on the line following `|a=b;|'.
C An example of
* several adjacent lines
C starting with a \FORTRAN\ comment character in column~1.
a(i,j) = 5 /* If you are writing a trailing comment and the editor
breaks your line before you are done, this is what you get. (The line is
actually broken before ``breaks'' and before ``actually''.) */
end
@ In general, when in \Fortran\ mode the concept of column~6 as the
continuation column is retained for compatibility with existing code.
@^continuation@>
Thus, usually
if any character other than~`\.{\ }' or~`\.{0} appears in column~6, the line is
assumed to
be continued from the previous non-comment line. \It{Comments embedded
between continuation lines will
be eaten, never to be seen again!}
An important exception is when you began a C-style trailing comment on
the previous line, but it's broken by your editor and it runs over to
the next line. In this case, WEB does its best to figure this out. See the
example above. However, because the two styles of comments have
fundamentally inconsistent syntaxes, you may someday run into trouble.
If so, please report the difficulty.
Neither \Tangle\ nor \Weave\ attempts to preserve the line breaks during
continuation. All adjacent continuation lines are put into one big buffer,
then fed to the central processor. When \Tangle\ outputs the code, it
writes it out character by character until column~72 is exceeded. Then it
emits a continuation character and continues.
If tab characters are present in the input, they will be expanded into
six spaces, thus ensuring that if you put a tab in column~1, your text will
start in column~7. \It{At the moment, we do not support the VAX extension that
one can follow a tab by a numerical continuation character.}
The following demonstrates one big bunch of continuations.
@A
z =
* 1 +
C Embedded \Fortran\ comment.
* 2 + 3 // Embedded short C~comment.
* +4 + 5 /* Trailing long C comment. The construction was
continued before~``\.{2}'' and before ``\.{+4}''. Some embedded
comments were eaten. */
@ Of course, you have the full power of \TeX\ inside comments. In addition,
you can also switch into code mode by enclosing (generally short) fragments
of code within vertical bars. Here's an example comment. (Actually, we
typed \.{"@@c zeta = alpha**beta"}. Why?)
@A
/* One can often use \TeX's math mode to advantage. For example: To compute
$\zeta = \alpha^\beta$, you write in \Fortran\ |@c zeta = alpha**beta|. */
@ As usual, statement labels can be written in columns 1--5. In fact,
however, you have much more freedom than that.
First, you can optionally follow a label with a colon. \Weave\ retains that
colon (if present), or puts it in for you. \Tangle\ strips it off.
Second, you can use \It{alphanumeric} labels. These \It{must} be followed
by a colon. Such labels must be defined by a macro (see below) to be a
standard \FORTRAN\ numeric label, or your code won't compile. However,
neither \Weave\ nor \Tangle\ cares. \It{Beware: If your alphanumeric label
start with a~``C'' and you start it in column~1, the line will be treated
as a comment.}
Third, in fact, the label need not be in columns 1--5, because if the label
follows the above rules WEB can figure out that you mean it to be a label.
Thus, here are some examples.
@M EXIT 9999 /* Alphanumeric labels must be macros that expand into numbers.
Use of \FWEB's macro processor is explained later. */
@M CONT #:0 /* Actually, you never have to assign a number explicitly. This
construction does it for you. */
@M BAD #:0
@A
1 x = y /* Numeric label in column~1. (Colon optional; wasn't typed.) */
EXIT: x = y /* Alphanumeric label in column~1. (Colon required.) */
12345: continue /* Numeric label in the statement field. (Colon
optional; was typed.) */
CONT: continue /* Alphanumeric label in the statement field. (Colon
required.) */
BAD mess = made /* Mistake: Alphanumeric label not followed by a colon.
(But, amazingly enough, this only messes up the woven formatting; \Tangle\
will do what you wanted!) */
@ In the previous examples you have already seen examples of simple
statements. These statements are actually ended by a semicolon, although
@^semicolons@>
for the convenience of the \Fortran\ user these semicolons are not printed
by default.
The semicolons were not present in the source file; \Weave\ inserted then
automatically. \Fortran\ always operates in this |auto_semi| mode.
The semicolon is used internally by \Weave\ to indicate ends
of statements, so it can do its automatic formatting. A bonus which arises
from this convention is that one can now type several statements on one
line, if they are separated by a semicolon. By default, they will be woven
onto separate lines, although you can override this by the special
command~\.{@@+}. (In all cases, \Tangle\ will write them out properly into
separate lines.) Thus, here are examples of simple expressions.
@A
x = y /* The input file contains the sequence |"\tx = y\n"|,
where |'\t'| and |'\n'| stand for tab and newline, respectively. */
a = b; c = d /* The last two lines were created from
|"\ta = b;\n\tc = d\n"|. */
a = b; @+ c = d /* Created from |"\ta = b; @@+ c = d\n"|. (The
spaces before and after \.{@@+} are optional; \Weave\ inserts its own
space.) */
@ The rules for recognizing identifiers are relaxed somewhat from
\FORTRAN's rules, in order to expedite speedy parsing.
@^identifiers@>
Specifically, identifiers must start with either a letter,
an underscore, a dollar sign, or (on the VAX), |'%'|;
they may also \It{contain} digits, and
they may be of arbitrary length. \It{Upper
and lower case are significant.}
This expedites parsing in languages other than \FORTRAN,
but it means that code which weaves correctly need not compile. In general,
WEB adopts the point of view that it should handle correct code correctly,
but no guarantees are made about incorrect code. \It{WEB is not a compiler!}
\It{You cannot have spaces within identifiers}, with the exception of |go to|,
|else if|, |end if|, and |end do|. \FORTRAN\ allows such spaces, but it
doesn't seem like it's asking too much to give up this ``feature''.
Here are various identifiers. The \.{typewriter} type is used to identifier
a \Fortran\ I/O~keyword, and
the {\bfit boldface italic} font is used to
identify intrinsic library functions.
@A
num, under_score, UpPeR_and_LoWeR_case,dollar$sign,
* a123456789, pi, %loc, NUMBER, cos, $1
y = 5z /* Here's what happens when you forget a binary operator;
the file contained |"5 z"|.
The $5$~is a constant and the $z$~is an identifier. However, \Weave\ has the
rule to just place two expressions side by side, so the space disappears
and it looks like an invalid identifier. */
@ \Weave\ tries to make constants look more readable.
@^constants@>
Floating-point constants such as |"-1.23e-4"| are woven as |-1.23e-4|.
Double- or quadruple-precision constants, such as |"+1.23d10"|, come out
looking like |+1.23d10|. (Note that the unary plus is understood.) If you
don't like the appearance of the floating-point constants, you can change
it with a \TeX\ macro; see \.{fwebmac.web}. Complex numbers are understood
perfectly well, as in |i = (0.0,1.0)|. Logical constants look like
``|.true.|'' or ``|.FALSE.|''. Hollerith constants, such as |"4Hab;d"| are
printed as |4Hab;d|. (Embedded semicolons are handled correctly.)
Similarly, character constants such as |"'ab;d'"| print as |'ab;d'|. The
VAX extensions of hex and octal constants are recognized properly: You type
|"'123'O"| to get |'123'O|, or |"'abcde'X"| to get |'abcde'X|. However,
\FWEB\ has its own way of denoting binary, octal, and hex numbers that is
patterned after~C: you can say `\.{0b10110}', `\.{077}', or `\.{0xFF}'.
Again, if you don't like the formatting conventions, you can change a \TeX\
macro.
Here's a combination of constants:
@A
x = 0123 + 0xabcde + 5 + 3.14529q0 - 1.5
l = .true. || .false. /* Here's how the logical expressions display
by default. */
c = 'abc' \/ 'def' \/ cfcn(8hargument) /* String concatenation. */
@ String constants are given special treatment by \WEAVE.
On output, long strings will
be broken in essentially the same way as \TeX\ hyphenates words (with the
hyphen replaced by a backslash). Long strings will be broken after commas,
or every so many characters.
@A
xchr = " !""#$%&'()*+,-./012345
#6789:;<=>?@@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]
#^_`abcdefghijklmnopqrstuvwxyz{|}~ "
@ WEB understands certain things about arrays. It can certainly understand
simple array references such as |a(i,j)|. It understands the colon
construction in dimension statements: |dimension a(0:100)|. Furthermore, it
understands the constructions associated with character
substrings, such as |c(:5)| or |c(5:)| or |c(:)|. It also understands the
|character| declaration with unspecified length. (However, it is not smart
enough to replace parentheses in array references by square brackets.)
@a
function f(c,d)
character*(*) c
character*10 d
dimension a(0:1,-5:5),b(0:9)
equivalence (a(0,0),b(0))
d(2:4) = c(:3)
end
@ \Weave\ attempts to pretty-up the output by converting anachronistic
constructions such as `\.{.le.}' to more familiar mathematical expressions. It
also allows you to type stuff in in a prettier way.
@^beauty@>
Thus, in the following list, you can type the stuff in the parentheses
instead of the first item. \Weave\ will give you the stuff following~$\to$;
\Tangle\ will convert the prettier input format into the standard \Fortran\
construction in the first column.
$$
\def\i(#1,#2){{\tt #1} \def\temp{#2}\ifx\temp\empty\else({\tt #2})\fi}
\vbox{\halign{#\hfil&$\to \hbox{#}$\hfil\cr
\i(.lt.,<) & |.lt.|\cr
\i(.le.,<=) & |.le.|\cr
\i(.eq.,==) & |.eq.|\cr
\i(.ne.,!=) & |.ne.|\cr
\i(.gt.,>) & |.gt.|\cr
\i(.ge.,>=) & |.ge.|\cr
\i(.and.,\amp\amp) & |.and.|\cr
\i(.or.,\vertbar\vertbar) & |.or.|\cr
\i(.neqv.,) & |.neqv.|\cr
\i(.xor.,) & |.xor.|\cr
\i(.eqv.,) & |.eqv.|\cr
\i(.not.,!) & |.not.|\cr
\noalign{\smallskip}
\i(**,\^) & \.{(a+b)\^(c+d)} $\to (a+b)^{c+d}$\cr
\i(//,\BS/) & |\/|\cr
}}$$
As an example,
@A
if( (x.le.y) && (!computing) ) z = x**y - y^x /* We typed
`|@cx**y - y@t\^@>x|'. */
if( x < y || !(x >= y) .and. (c.eqv.d)) c = a\/b
@ You've already seen many examples of the standard assignment statement
|x = y|. Here are further examples from the VAX manual, which also demonstrate
various stuff about strings and arrays. The very last statement also
demonstrates just how ignorant \Weave\ really is.
@A
file = 'prog2'
revol(1) = 'mar'\/'cia'
loca(3:8) = 'plant5'
text(i,j+1)(2:n-1) = name\/x
assign 99999 to kstop
assign 88888 undivert kstop /* |undivert| is a built-in
function in M4; |to| and |then| are also given |built_in| ilk. */
@ We have the various types of |goto|'s. (Note that WEB understands both
|goto| and |go to|.)
@^goto@>
@m MGOTO 1000
@A
goto 10 /* Unconditional. */
go to (12,24,36), indx /* Computed. */
goto ibeg, (300,340,MGOTO, 25) /* Assigned. */
@ The formatting powers of \Weave\ really come into play with block
structure; it will automatically indent blocks for you.
Since \Weave\ understands the block structure, it can help you out by
telling you which ends go with which beginnings, by inserting numbered
comments. (This feature can be turned on with the command-line option
\.{-b}.)
Here are the various |if| statements. (Note that WEB understands both
|elseif| and |else if|, and both |endif| and |end if|.) You may be annoyed
or puzzled by the appearance of a semicolon after |then| and |else| in the
|if|-|then|-|else| construction. The point is that \Fortran\ also marks
those statements specially, namely by a newline. Since \Weave\ operates
internally in a free-form syntax, it replaces the newlines by semicolons,
consistent with~C and \Ratfor. On printout, it would be possible to strip
them off, but that would be logically inconsistent with showing you what
you would have to type if you were supplying the semicolons yourself. Of
course, \Tangle\ throws away the semicolons. (Actually, it uses them as
sentinels to say when to emit a newline.)
@A
if(expr) 10,20,30 /* Forget this statement for modern codes. */
if( j.gt.4 .or. j.lt.1) goto 250
/* An example from the VAX manual. */
if(a>b) then
d = b
f = a - b
else if (a .gt. c) then
d = c
f = a - c
else
d = 0.0
f = a
end if
/* A further example demonstrating nesting. (The blank lines
surrounding the inner block were put in by the user.) This C-style
comment started in column~1. */
if(a.lt.100) then
inran = inran + 1
if(abs(a-avg) .le. 5.0) then
inavg = inavg + 1
else
outavg = outavg + 1
end if
else
outran = outran + 1
end if
@ Loops are easy when the |do|\dots|enddo| construction is followed.
Statement labels are also handled correctly.
@^loops@>
@^labels@>
Note the semicolons ending the |do|s. See the previous module for discussion.
Note that unlabeled \&{do}s are a VAX extension. \Tangle\ will
convert them into conventional loops with statement labels if you use the
`\.{-d}'~option.
@A
do n = 5,40,4
a(n) = n
do m = -1,1
a(m) = m
enddo
enddo
do 100 k = 1,50,2
b(k) = k**5
do 101 j = 5,0
dummy
101 continue /* Compare the source file with the output here,
noting the position of the statement label. */
100 continue
/* Multiple loops ending on the same statement are indented correctly. */
do 10 i= 1,2
do 10 j = -5,5,2
10 c(i,j) = 0.0
do while(line(i:i) .eq.' ')
i = i + 1
end do
@ WEB has a rudimentary knowledge of program structure.
@^program structure@>
It assumes that
specification statements such as |dimension| come before executable
statements. (|namelist| is treated as a specification statement; |data|
and |@r include|
statements can be interspersed with executable statements.)
It will automatically separate the two sets of statements by a
blank line. It also is able to use the |end| statement to figure out
where the function ends, and attempts to highlight the function by
backspacing the first and the last statements of the function. (This means
that your main program will look funny unless you use the \&{program}
statement, which is recommended anyway.
@a
program main /* Backspaced means that \WEAVE\ understood the
syntax of a complete program unit. */
integer i,j
real a(0:100)
x = y /* No blank line was put in the file here, although it would
be reasonable to do that to make your source more readable. */
data pi/-3.14159/ /* $\pi$?? */
pi = -pi
end
@ Sometimes the first line of the function may not be backspaced as you
expect. This means that there's something syntactically wrong within the
function (or there's a bug in \Weave). You should look through the function
for unusual formatting, such as unwanted spaces. Near there is where the
error probably is. For example, the following example differs by only one
character from the previous one.
@a
program main /* Not backspaced means that \WEAVE\ got confused
somewhere below. */
integer i,j
real a(0:100)
x = y+ /* Check out this line carefully. */
end
@ Of course, we also have the miscellany of |call|, |return|, etc.
@a
program main
call graph(5.0,*10,*20) /* Statement label returns. */
stop 'We''re done'
end
subroutine s(x,*,*)
real x
call curve(-1.0)
pause 'Do you know what you''re doing?'
return 1
end
@ WEB understands the following fundamental data types: |integer|, |real|,
|double precision|, |complex|, |double complex|, |logical|, and
|character|.
@^data types@>
(Not being a compiler,
it will also happily process more bizarre types such as
|complex logical double|.)
Any of these can be suffixed by a length specifier---for
example, |real*8|. WEB doesn't care if you specify a crazy specifier, such
as |real*77|.
In detail, here's how all the specification statements look.
@^statements, specification@>
Here, the
blank lines are inserted explicitly to make the grouping more apparent.
@a
program main
parameter(NN=100, M = 50)
implicit real*8 (a-h,o-z) /* You might quibble with the
typesetting here. */
implicit none
implicit double precision(d), complex(x,y), character*32 (t-v)
integer i,matrix(4,4),sum
real a(0:100),b(-n:n,0:UPPER)
real*8 pi/3.14159/, array(10)/5*0.0,5*1.0/
logical lswitch
character*(4+LENGTH) last,letter(26)
character bubble*(*)
character*32 socsec(100)*9, namety*10/'abcdefghij'/
dimension a1(n1:n2), a2(n3:*), mark(4,4,4,4)
common heat,x /blk1/kilo,q
equivalence (a,b(1)), (table(2,2),triple(1,2,2)), (name(10:13),kd(2:5))
external f1,f2,f3
intrinsic sin,cos /* The names of intrinsic functions are
understood. */
data a,starts/10*0,'****'/, bell,tab,lf,ff /7,9,10,12/ /* |data|
statements may be interspersed with executable statements. */
include "more.for" /* This VAX extension has now become a
\Fortran-90 keyword. It can be put anywhere. */
save a,/blk1/
namelist/input/name,grade,stuff/output/total,name /* At the moment,
|namelist| statements are considered to be type specification statements. */
end
block data blkdat /* An example from the VAX manual. */
integer s,x
logical t,w
double precision u
dimension r(3)
common/area1/r,s,t,u /area2/w,x,y
data r/1.0,2*2.0/,t/.false./,u/0.21453d-7/, w/.true./, y/3.5/
end
@ Subroutines are fairly straightforward, except one must allow for passing
of statement labels. One embellishment is that intrinsic library functions
are displayed in {\bfit boldface italic}.
@^functions, intrinsic@>
(This is true only
if they're in lower case. This allows one to use uppercase for macro names.
The one exception to this is |Real|. Distinguish this intrinsic function
from the type specification |real|.)
@a
subroutine sub(a,*,n,*)
sinh(x) = 0.5*(exp(x) - exp(-x)) /* A statement function which
redefines an intrinsic function. */
call sub(%val(i),*,Real(10),*) /* Note that we handle the VAX extension
|'%'|. */
end
real function f()
return
end
character*10 function char()
return
end
subroutine s(y)
x = y
entry s1(z) /* The |entry| statement is backspaced, with a blank
line preceding it. */
x = z
return
end
@ The most annoying thing about input/output is the |format| statement.
@^format@>
The
innards really ought to be a character variable interpreted at run time. As
it is, the innards must be treated specially so they will look sensible.
For the I/O statements, keywords such as |"UNIT"| are typeset specially if
they're in upper case.
@f namelist common
@a
program test
namelist/control/ title,reset
read(8,end=550) (matrix(k),k=1,100) /* Handles |end| as a keyword. */
write(6,50,err=390) var1,var2,var3
read(1,1250) j,k,array(j,k)
1250 format(i1,1x,i1,1x,4e6.2) /* Note that it didn't write |@e4e6.2|. */
2 format(' k =',f5.2,:,' x =',3e10.5) /* Note that the colon usage is
handled correctly. */
3 FORMAT(' k =',f5.2,:,' x =',3e10.5) /* Reserved words must be in
lower case; here's what you get when \Weave\ doesn't understand it's a
|format| statement. */
write(1,*) a,b,'Hello'
write(4)
read(UNIT=1,NML=control)
accept a,b,c
type *,i,j,k
print 100 i,j,k /* It understands this format both with and without
a comma following the format number. */
call open(UNIT=1,STATUS='new',DISP='submit'\/qual) /* It
handles the case where |open| is treated as a subroutine rather than as a
reserved word of the language. */
close(UNIT=j,STATUS='delete',ERR=99)
inquire(FILE=f,ACCESS=acc)
rewind 10
backspace(15,ERR=9999,IOSTAT=io)
endfile 2
end
@ If you specify the ``\.{-m4}'' option on the command line, WEB will
understand the built-in functions of the M4 macro preprocessor, and
\Tangle\ will change the extension of the output file from ``\.{.for}'' to
``\.{.n4}. (The extension ``\.{.m4}'' is reserved for output from the
\Ratfor\ language.)
Here are samples of those words. Note that, for simplicity at
this point, many of the arguments have just been interpreted as character
strings. (Also note that \FWEB's built-in macro preprocessor supercedes
\.{m4}.)
@<R@>=
changequote([,]); /* Only brackets are guaranteed to work correctly
with \&{changequote}, as far as formatting with \WEAVE\ is concerned. */
define(ARGS,[a,b,c])dnl;
divert(5);
dumpdef([ARGS],[YES]);
errprint("help");
eval(2**n + 1);
ifdef([unix],[define(wordsize,16)]);
ifelse(divnum,5,z = 5.0,z = punt); /* It's too complicated
to format this; we just treat everything as a string. */
include(filename);
define(n1,[incr(n)]);
index(string1,string2);
len((a,b));
maketemp(XXXXX);
sinclude(silent.file);
substr(abcdef,i,5);
syscmd(date);
translit(s,aeiou,12345);
undefine(TEST);
@ WEB contains a powerful, \C-like macro processor.
@^macros@>
If you are a \Fortran\ user not used to macros, the use of macros
is somewhat analogous to the |parameter| statement, but is more
flexible. Macros are expanded by \Tangle\ when it creates the \.{.for}
file, and are global to the entire source; they may have arguments. The
|parameter| statement, by contrast,
is local to a program unit, and arguments are not
allowed. Macros can be defined from the command line. If you want to define
a lower-case macro with no replacement text, just say
`\hbox{\.{-mlower\_case\_macro}}'. Otherwise (if the macro has upper-case
characters in it and/or if there is replacement text), say
`\.{-m"CMD\_LN\_MACRO\ 25"}'.
Here is an example of the use of WEB macros. (Note that macro definitions
come \It{before} the code section.)
@M N 100
@M MM(lower,upper) ((upper) - (lower) + 1)
@M DONE #:0
@a
program main
integer n
real A(MM(-1,5)) /* \Tangle\ will expand this into ``\.{real
A(((5)-(-1)+1));}'' */
n = N /* Expands into ``\.{n = 100;}''. Note that case is
significant for macros. */
if(n > 1000) goto DONE /* You can make your code look more
readable by using macros for statement labels. */
DONE: stop
end
@ In fact, there are two kinds of macros: the \.{@@m} kind, which refer to
internal WEB macros and which are used to expand identifiers during
tangling; and the \.{@@d} kind (called ``outer'' macros). @^macros@>
\Tangle\ does not expand them; it merely copies the latter to the beginning
of the output file, preceded by the identifier \&{define}. \It{(However, if
the outer macro contains a WEB macro identifier, that will be expanded.)}
For \Fortran, The intent is that you might wish to run the M4 preprocessor.
Of course, the \.{@@d} macros should have the proper syntax for the
preprocessor you intend to use. They are most useful for~C, which has its
own built-in preprocessor.
@d (YES,1)
@d (TEST,[$1+$2,$3]) /* An example of an M4 macro with arguments. */
@d (OUTER_FLAG,MFLAG(1,2)) /* This contains a WEB macro. Look at the
\TANGLE d output to see how |OUTER_FLAG| will be defined. */
@M MFLAG(arg1,arg2) ((arg2)-(arg1)) /* A WEB macro with arguments. */
@i macros.hweb /* The more complete macro demo. */
@ In addition to WEB macros, there is a useful preprocessing language,
consisting of the commands `\.{@@\#ifdef}', `\.{@@\#ifndef}',
`\.{@@\#undef}', `\.{@@\#if}',
`\.{@@\#elif}', `\.{@@\#else}', and \.{@@\#endif}'.
@^preprocessing@>
These commands may
appear either in the definition section or in code mode; they must begin in
column~1. You can use them
to conditionally define macros or include text, to comment out code, etc.
See the user manual for more discussion.
Here's an simple example that does something only if you defined the macro
|CMD_LN_MACRO| from the command line.
@A
@#ifdef CMD_LN_MACRO /* Define this from command line. */
write(6,200) CMD_LN_MACRO
@#endif
@ Sometimes you introduce a new identifier that ought to be formatted in
the same way as identifiers which \Weave\ already knows. For example,
although \Weave\ understands that |tanh| is an intrinsic function, it's
never heard of \\{atanh}. You can use the \.{@@f}~command
to tell \Weave\ what to do.
@^formatting@>
Note that \Weave\ uses two passes to do its work; it does the
cross-referencing and formatting on the first pass, then does the
typesetting on the second pass. Thus, all occurences of an identifier in
the code will be formatted the same way, and you don't need to format
something before you use it.
@f atanh tanh
@A
z = atanh(z)
@ The formatting mechanism could be used to handle an annoying situation.
\Fortran\
uses |real| for two entirely different purposes: as a type specification,
and as an intrinsic function. \Weave\ only understands it as a type
specification, but you could use a macro to achieve your goal:
@f areal aimag
@M areal real
@A
real x
x = areal(y)
@ Actually, the previous example need not be used in practice, because
\Weave\ has been told to
understand as a special case the intrinsic function |Real|. (This violates
none of
\Fortran's rules, since \Fortran\ is case-insensitive.)
Thus, you can say, with neither formatting nor macros,
@A
real x
x = Real(y)
@ Module names may be formatted. This gets around the annoyance that named
modules that are intended to play the role of type specifications won't be
understood otherwise; by default, module names are expressions, not type
specifications. Thus, you should say something like this:
@f @<Common blocks@> common
@a
subroutine dummy
@<Com...@>
integer k
executable = stuff
end
/* If you don't format the module name, you get this: */
subroutine dummy
@<Other common blocks@>
integer k
executable = stuff
end
@ The next two modules are included to avoid warning messages about missing
modules.
@<Com...@>=
@
@<Other ...@>=
@ The following tests the metacomment feature.
@^metacomment@>
Text which is to be
commented out but included in the tangled output
can be bracketed by \.{@@(} and \.{@@)};
\Tangle\ will put comment characters in column~1 of the bracketed lines.
(In the source file, the metacomment commands should begin in column~1.)
This feature is no longer very useful with the advent of the preprocessor
language. In general, you should use \.{@@\#if(0)...@@\#endif} to comment
out code. The latter produces nothing in the tangled output, while
metacomments do.
@A
@(
a = b
c = d
@)
@#if(0)
y = z
@#endif
@ WEB understands~\C, \Ratfor, and \Fortran\ syntax. There are several ways
of switching languages.
@^languages@>
First, there is a global language. This is the language which is in effect
at the beginning, \TeX\ part of each module and which is the initial
language of the unnamed module. By default, the global language is
|FORTRAN|. The global language may be set on the command line by the
options \.{-c}, \.{-r}, or~\.{-n}. (Note that we use the \It{last} letter
of the language name as the abbreviation.) It may also be set by any
\.{@@c}, \.{@@r}, or \.{@@n} command (collectively called the language
commands)
issued in limbo (before the start of
the first module). Placing a command in limbo is the recommended way of
setting the global language.
You can also change the language locally at any time by issuing a language
command. If you issue such a command within vertical bars, the command is
localized to the barred region. Thus, the global language for this demo is
\Fortran. However, we can talk about the keyword |@c struct|, which is
known only to~\C, by saying |"|@@c struct|"|.
Named modules inherit the language in effect at the time they were first
referenced. The natural way to do this is to change languages in the
unnamed module. Thus, just before the reference \.{@@<Ccode@@>} in the
first unnamed module above, we have a (nonprinting) language \.{@@c}. You
will note that the name of that module is properly superscripted with
a~`C'. Without further ado (and without issuing any other language
command), you can define the named module \.{@@<Ccode@@>} as always, and
WEB will know that it is to be interpreted in the C~language. Furthermore,
any named modules which are referenced by this module will also be assumed
to be in~C. Here is an example of this, which also tests some features
of~C.
@<Ccode@>=
#include <stdio.h>
main(int num_args,char *args[])
{
typedef struct
{
int i;
float f;
} TEST;
TEST *p,*f(int i,struct s S,...);
void g(void);
p = pp + &ppp; /* Address operator. */
if(hungry) @<Test C block@>@; /* Note that you must use a \It{pseudo-semi}
(`\.{@@;}') here, because the code that will be substituted for the block
is already a complete statement and you don't want an extra semicolon to
appear before the |else|. */
else have_dessert;
}
@ Test of a named C module.
@<Test C block@>=
p = (TEST *)malloc(1000); /* Illustrates typesetting the cast
operation. */
/* Following is the toughest loop to get right.*/
if(x)
if(y) z;
else w;
else
if(w) {}
else done;
for(i=0; i<5; i++)
for(j *= 10; j<100; j/=5)
a(i,j) = i % j;
if(x|w) y; /* Bit-wise \.{or}. */
if(x&w) z; /* Bit-wise \.{and}. */
else if(x) y;
else if(x) z;
else z;
do
{
x = y;
}
while(1);
@ There are separate input drivers for~C, \Fortran, and~\Ratfor. The
C~driver assumes completely free-form syntax. \Fortran\ assumes the
opposite extreme of column-oriented syntax. \Ratfor\ has two syntax modes.
By default, it is entirely free-form, just like~C. In this mode, the user
must insert semicolons to end statements. In the auto-semi mode, introduced
by the command-line option `\.{-;}', the syntax
is intermediate: it is
free-form syntax in that columns have no meaning; however, newlines end the
line except when the statement is ``obviously'' continued---when it ends in
things like plus or underscore (if the underscore isn't obviously part of
an identifier). For example, here is a \Ratfor\ module
which contains several continued lines.
@<R@>=
x =
a +
b _
- c; /* Continued after \.{+} and |b|. */
@ The form of a \Ratfor\ function is \C-like, with braces
enclosing the body of the function.
(\Ratfor\ just throws away the braces,
but they're useful for helping \Weave\ to typeset things in a pretty way.
However, you won't get garbage if you omit them.) It is conventional to
list declarations of function arguments before the braces, and other
declarations after them, just as one does in~C.
@<R@>=
function f(x)
real x;
{
integer k;
real a(0:9);
do k=0,9;
a(k) = Real(k); /* Use of intrinsic function. */
if(x)
if(y)
{z;}
else w;
else
if(y) z;
else if(z) w;
if(x) a;
else if(x) b;
else if(x) c;
else done;
while(j < k)
{
j = j + 1;
}
for(i=1; i<5; i=i+1)
for(j=0; j>0; j=0)
a(i,j) = pi;
repeat
{
if(i > 10) break;
}
repeat
{
if(happy) next;
}
until(tired);
return;
}
@ In the previous examples, the user supplied the semicolons. This is the
preferred input mode, and using it may speed up the processing of your
file. \Ratfor\ just throws away the semicolons.
However, for compatibility with existing code, there is an automatic
semicolon mode, which supplies the semicolons for you. You turn this on by
saying \.{-s} on the command line. (Presently, the \Weave\ output from this
mode is not perfect, but it almost always will do what you want.)
As we stated previously, \Fortran\ is always in the automatic semi mode.
@ WEB supports the notion of a change file.
@^change file@>
See the user manual for
complete details. Here we test the use of the change file `\.{demo.ch}'.
Any lines in the source file may be changed; they don't need to be code.
GARBAGE GARBAGE GARBAGE
@A
aaa = bbb
ccc = ddd
@* INDEX.