@FWEB{} offers a built-in preprocessor facility, especially useful for FORTRAN programmers. It is closely patterned after the C/C++ preprocessor, but with some extensions such as variable numbers of arguments. In addition, there are some built-in functions that provide functionality that cannot be emulated by user-defined macros.
When working with a language such as C that has its own preprocessor, the question arises when to use that and when to use @FWEB{}'s facilities. The answer generally comes with experience. Remember that @FWEB{}'s macros have been expanded by the time the tangled output file is produced, whereas language-specific preprocessor commands are just passed through to that file.
If you're a FORTRAN programmer, strongly consider the use of @FWEB{}'s macro facilities; they will simplify your present and future life by creating more legible codes and reducing programming errors by eliminating redundant pieces of code. C/C++ programmers may also appreciate the preprocessor extensions.
In addition to conventional macro processing, @FWEB{} also offers the convenience of certain built-in functions that behave in many ways like macros. As a trivial example, the value of @PI{} is available through the built-in function `$PI'. Built-in functions are described in section Built-in functions. They can be useful to programmers in all languages.
@FWEB{} recognizes two kinds of macros: outer macros, and @dfn{WEB macros} (inner macros). Control codes associated with either of these kinds normally begin the definition part. However, @FWEB{} macros are sometimes allowed in the code part as well; see section @FWEB{} macros.
Macros are expanded by @FTANGLE{} only; @FWEAVE{} merely prints them as they occur in the source file.
Outer macros provide a shorthand way of invoking macro definitions in the source language; they are not expanded by @FWEB{}. Outer macros are defined by `@d' (see section `@d': Define outer macro, and mark) or `@D' (see section `@D': Define outer macro). They may be placed in any definition part. @FTANGLE{} collects them during phase 1; during phase 2, they are simply copied in order of their appearance to the beginning of the output file. This is most useful for C or C++ codes; it's a quick way of typing `#define' when the positioning of the `#define' is unimportant.
As an example,
@c @ @d YES 1 @d NO 0 @a main() {} @ @d BUF_LEN 100 @a ...
The keyword into which the `@d' is translated is language-dependent; it is controlled by the style-file parameter `outer_def'. See section Miscellaneous style-file parameters.
Outer macros can be undefined by `@u'. The translation is controlled by the style-file parameter `outer_undef'. See section Miscellaneous style-file parameters.
The default behavior, in which the outer macro definitions are just
copied to the top of the output file, is fine for simple applications.
However, often C programmers prefer to maintain their macro definitions
in a header file such as `test.h'. One way of accomplishing this is to
redirect @FTANGLE{}'s output from the command line, as in
`ftangle test -=test.h', then use an `@O' command immediately
after the first `@a' in the web
file to open up
`test.c'. A more complicated variant of this allows additional
information to be placed into the header file, as in the following example:
@c @* INTRO. We assume command-line redirection into \.{test.h} (`\.{-=test.h}'). @d A 1 // This will go into \.{test.h}. @a @<Header material@>@; // Also goes into \.{test.h}. @O test.c // Remaining unnamed sections go into \.{test.c}. @ Header material may be defined as needed throughout the code, but with this design it will all go into \.{test.h}. @<Header material@>= @<Includes@>@; @<Typedefs@>@; @<Global variables@>@;
@FWEB{} macros (sometimes called inner macros) are defined by `@m' (see section `@m': Define @FWEB{} macro, and mark) or `@M' (see section `@M': Define @FWEB{} macro). These should normally be placed in the definition part, as in
@n @ Documentation... @m CUBE(x) (x)**3 @a z3 = CUBE(x) + CUBE(y)
(the appearance of an `@m' in the documentation part begins the definition part). They are collected during @FTANGLE{}'s phase 1 and effectively placed at the top of the unnamed section, so they are all known during the output in phase 2.
In unusual situations when macros are being conditionally defined and/or undefined, the order of processing a macro definition becomes significant. If the command-line option `-TD' is used, then @FWEB{} macros may be used in the code part as well; they are then called deferred macros. These definitions will be processed during phase 2 in the order that the code sections are processed, which may not be the same as the physical order in the source file.
The use of deferred macros is highly discouraged, for the following reason. @FWEB{} macros are often used in conjunction with the @FWEB{} preprocessor commands. @emph{Preprocessor commands are always processed during phase 1}, so they do not interact properly with deferred macros. It is for this reason that deferred macros are normally prohibited from appearing in the code part.
- Fundamentally, @FWEB{} macros follow the syntax for ANSI C. There are also a few extensions, notably the possibility of variable (optional) arguments (see section @FWEB{} macros with variable arguments) and some additional preprocessing tokens (see section Special tokens).
- Adjacent strings in macro text are automatically concatenated.
An important extension to the ANSI-C syntax is to allow macros with variable (optional) arguments. @FWEB{} macros with a variable number of arguments are indicated by an ellipsis, as in
@m VAR(x,y,z,...) text
The tokens `#0' (number of variable arguments), `#n' (value of the nth optional argument), and `#.' (comma-delimited list of the optional arguments) are useful in this context.
ANSI C does not permit recursive macros (for good reason). Thus, in the example
@m recurse recurse
the identifier recurse
simply expands as `recurse
', not as
an infinite loop. However, in @FWEB{} recursion may be useful in
conjunction with some of the built-in functions
(see section Built-in functions). To permit a macro to be recursive, say `@m*'.
No formal support is provided for recursive macros! If they don't work, or suddenly stop working in a new release, you're on your own!
Normally an @FWEB{} macro can be redefined at will. The example
@m PI 3.14159 @m PI (-3)
is permissible, but probably not a good idea. If you want to ensure that a crucial macro definition is never redefined inadvertently, say `@m!', as in
@m! PI 3.14159
That is called protecting the macro.
@FWEB{}'s built-in functions and macros (beginning with `$') are protected by default; see section Redefining built-in functions. To override that protection, use the command-line options `-Tb' (section `-Tb': Permit built-functions to be redefined; for built-in functions) or `-Tm' (section `-Tm': Permit user macros to be redefined; for macros).
The following special tokens may be used in the text of @FWEB{} macro definitions:
## --- Paste tokens on either side to form a new identifier. #parameter --- Convert parameter to string (without expansion).
For example,
@m FORTRAN(type, name) type _##name() @m TRACE(where) puts("At " #where) @a FORTRAN(int, fcalc); // Expands to `int _fcalc();' TRACE(predictor); // Expands to `puts("At " "predictor");'
The most frequently used extensions are the following ones associated with variable arguments: `#0', `#n', and `#.'. FORTRAN-77 users should also employ `#:0' to allow symbolic rather than numeric statement labels. Try not to use the other extensions; they are experimental, complicated, and unlikely to work in all situations.
In the following list, the forms `#{n}' and `#[n]' may not work correctly in complicated situations. This is a design deficiency that may be corrected someday.
#*param
- Like `#parameter', but pass a quoted string through unchanged.
#!param
- Don't expand argument.
#'param
- Convert parameter to a single-quoted string (no expansion).
#"param
- Convert parameter to a double-quoted string (no expansion).
#0
- Number of variable arguments.
#n
- n-th variable argument, counting from 1.
#{0}
- Like `#0', but the argument may be a macro expression known at run time.
#{n}
- Like `#n', but the argument may be a macro expression.
#[0]
- The total number of arguments (fixed + variable). (The argument inside the brackets may be a macro expression.)
#[n]
- The nth argument (including the fixed ones), counting from 1. (The argument inside the brackets may be a macro expressions.
#.
- Comma-separated list of all variable arguments.
#:0
- Unique statement number (expanded in phase 1).
#:nnn
- Unique statement number for each invocation of this macro (expanded in phase 2).
#<
- Begin a module name.
#,
- Internal comma; doesn't delimit macro argument.
A few examples of the more important of these tokens are as follows:
@c @m FPRINTF(fmt,...) fprintf(fp,fmt,#.) // Use the whole list of variable args. @m B(...) printf("There were %i arguments\n", #0) // Use the number of var args. @n @ @m DONE #:0 // Symbolic statement label in FORTRAN. @a goto DONE ... DONE: call endup
Built-in functions behave in most ways like macros. In some cases they actually are macros, but other times they implement functions that a user could not define. They all begin with a dollar sign and are in upper case.
In using these built-ins, confusion may arise regarding the order of
expansion of various arguments. When they are implemented as macros,
they are subject to the same ANSI-C preprocessor rules as other
@FWEB{} macros, which is that all arguments are fully expanded before
generating the replacement text of the macro. When they are directly
implemented as a primitive function, however, that rule may not apply.
For example, $IF
expands only its first argument during its first
pass of processing; depending on the results of that expansion, it then
expands either its second or third argument, but not both.
The built-in function $DUMPDEF
can be used to understand and
debug the action of the built-in functions. See section $DUMPDEF
: Dump macro definitions to the terminal.
In the original @FWEB{} design, built-in functions began with an underscore. This usage conflicts with the conventions for reserved words in ANSI C, and has been eliminated. All @FWEB{ built-ins now begin with a dollar sign.}
No user-defined macro should begin with a dollar sign! It might interfere with the functioning of some internal built-in function.
Several of the built-in functions expect or return a string argument.
Examples include $STRING
(see section $STRING
: Expand, then stringize), $UNQUOTE
(see section $UNQUOTE
: Remove quotes from string), and $UNSTRING
(see section $UNSTRING
: Convert string into characters).
In understanding the operation of those functions, it is important to
understand just what a string means in the @FWEB{} context. As usual,
it is a vector of characters. However, those need not be
delimited by quotes, although they may be. Internally, a string is
represented by the construction sqc...cqs, where s is a special
string delimiter never seen by the user, q is an optional quote
character (either single or double quote depending on the language), and
c is an ordinary character. Whether or not the quotes are present,
the string delimiters inhibit macro expansion.
The difference between $UNQUOTE
and $UNSTRING
can now be
stated as follows. Given a quoted string such as "abc"
(in C),
abc
(and therefore is not very useful).
$UNSTRING
is primarily used internally.
The built-ins $P
(see section $P
: The C preprocessor symbol) and $PP
(see section $PP
: The C preprocessor symbol), which
both generate the preprocessor character `#', provide a good
illustration of the differences between $UNQUOTE
and
$UNSTRING
. Consider FORTRAN as an example. Essentially,
$P
is defined as `$UNQUOTE('#')', which is internally
s#s. When this single-character string is sent to the output, it is
treated like any other expression and therefore would appear in column 7
or greater even if the construction appeared at the very beginning of
the line. On the other hand, $PP
is (essentially) defined as
`$UNSTRING('#')', which is internally the single character #.
Because this character is not a string, the FORTRAN output driver
treats it as a special control character, defined in this case to force
the character into the first column.
By default, built-in functions are protected---that is, they may not be
redefined by an @m
command. (To do so cavalierly invites many
kinds of weird disasters.) If it is absolutely necessary to redefine a
built-in function, use the command-line option `-Tb' (see section `-Tb': Permit built-functions to be redefined).
Many of @FWEB{}'s "built-in functions" are in fact ordinary macros
that are implemented in terms of lower-level built-ins. An example is
$POW
(see section $POW
: Exponentiation), which is constructed from the built-in
function $EVAL
(see section $EVAL
: Evaluate a macro expression). By default, such macros are also
protected against redefinition; to override, use the option `-Tm'
(see section `-Tm': Permit user macros to be redefined).
$A
: Convert to ASCII`$A(string)' is the built-in equivalent of `@'...'' or `@"..."'. (See section Conversion to ASCII and section `@"': Convert string to ASCII.) Note the extra parentheses required by the built-in.
$A
first expands its argument, in case it is a macro defined as a
string.
$ABS
: Absolute value
`$ABS(expression)' returns the absolute value of the macro
expression. It is a macro implemented in terms of $IF
and $EVAL
.
$ASSERT
: Assert a condition`$ASSERT(expression)' evaluates the macro expression. If the expression is false, an error message is printed and the run aborts.
This built-in is useful for ensuring that @FWEB{} macros required by the code are properly initialized. Because it is expanded during the output phase, it must appear in the code part (not in the definition part).
$AUTHOR
: Value of RCS global keyword Author
Equivalent to `$KEYWORD(Author)'. See section $KEYWORD
: Value of global RCS-like keyword.
$COMMENT
: Generate a comment`$COMMENT'(string) generates a comment in the output file.
This function is sometimes useful in conjunction with the processing of @FWEB{} macros, since ordinary comments are removed when macros are processed. For example, if one says
@c @ @m M "abc" $COMMENT("Test") @a m = M
the tangled output will be `m= "abc"/* Test */'
$DATE
: Today's date
`$DATE' generates a string consisting of the date in the form
"August 16, 2001"
. It is implemented as a macro that calls other
macros and primitive functions.
$DATE_TIME
: Value of RCS global keyword Date
Equivalent to `$KEYWORD(Date)'. See section $KEYWORD
: Value of global RCS-like keyword.
$DAY
: The day
`$DAY' generates a string consisting of the day of the week, such
as "Monday"
. It is implemented as a macro that calls other
macros and primitive functions.
$DECR
: Decrement a macro`$DECR(N)' redefines the numeric macro N to be one less than its previous value. (If N does not simplify to a number, an error results.) In other words, in the language of C the effect is to say `N--'.
The two-argument form `$DECR(N,m)' executes the equivalent of `N -= m'.
$DEFINE
: Deferred macro definition
`$DEFINE' behaves like the @FWEB{} macro command @m
, but
it is intended to appear in the code part, not the definition part (so
it is processed during output, not input). Thus, the code fragment
a = A; $DEFINE(A 1)@% a = A;
tangles to
a= A; a= 1;
(Notice how the `@%' command was used to kill an unwanted newline,
analogous to the `dnl' macro in m4
.)
In the above example, one could also say `$DEFINE(A=1)'. To define a macro with arguments, say something like `$DEFINE(A(x)x*x)'. Do not say `$DEFINE(A(x)=x*x)', as in this case the equals sign will be included in the macro expansion. One must use the equals sign as a means of preventing parentheses from being interpreted as an argument in examples like
$DEFINE(A=(x))
This expands to `(x)'.
A completely equivalent shorthand notation for $DEFINE
is
$M
.
$DO
: Macro do loop`$DO(macro,imin,imax[,di]){...}' repetitively defines macro as would the FORTRAN statement `do macro = imin,imax,di'. For example,
$DO(I,0,2) { a[I] = I; }
generates the three statements
a[0] = 0; a[1] = 1; a[2] = 2;
In general, the macro name used as loop counter should not be
explicitly defined as a macro prior to the $DO
. If it is not, it
will remain undefined after the end of the iteration.
Instead of the delimiting braces, parentheses may be used. These may be useful to help @FWEAVE{} format certain constructions correctly.
Nested delimiters are handled correctly. The delimiters are required even if only a single statement is to expanded.
$DO
is implemented in terms of a command $UNROLL
.
However, if one says something like `$DUMPDEF($UNROLL(0,5,1))',
@FWEB{} will respond that $UNROLL
is not an @FWEB{} macro.
Rather, $UNROLL
is processed like expandable commands in
RATFOR such as while
. This implies that it cannot be
redefined as ordinary macros or built-in functions can be.
$DUMPDEF
: Dump macro definitions to the terminalIn the call `$DUMPDEF(m1, m2, ...)', m1, m2, and so on are macro calls (with arguments if appropriate). Two lines of output are generated for each argument. Line 1 is the macro definition; line 2 is its expansion using the provided arguments.
One can use this built-in to debug one's own macros, or to find out the secrets of @FWEB{}'s built-ins. As an example, if one says
$DUMPDEF($EVAL(2^^4))@%
it responds with the two lines
$EVAL($0) = $$EVAL($0) $EVAL(2**4) = 16
(The $n
notation indicates the n-th argument of the macro.)
If one replaces $EVAL
with $$EVAL
in the above
$DUMPDEF
, it will respond
$$EVAL($0) = <built-in> $$EVAL(2**4) = 16
The purpose of code such as `$EVAL($0) = $$EVAL($0)' is to ensure
that the argument of $EVAL
is expanded if it contains macros; the
primitive function $$EVAL
does not do that expansion
automatically.
Names indicated as `<built-in>' by $DUMPDEF
may be redefined
as ordinary macros, but this is in general a very bad idea; other
parts of @FWEB{} may mysteriously stop working.
$E
: Base of the natural logarithmsThe expression `$E' returns e, the base of the natural logarithms, to the default machine precision. The expression `$E(iprec)' returns e to the decimal precision iprec (which must be less than 50).
$ERROR
: Send error message to output`$ERROR(string)' prints an error message in @FWEB{}'s standard form.
$EVAL
: Evaluate a macro expression`$EVAL(expression)' uses @FWEB{}'s macro-expression evaluator (see section Preprocessing) to reduce the macro expression to its simplest form. An attempt to perform arithmetic on combinations of non-macro identifiers and numbers generates a warning message.
$EXP
: Exponential function$GETENV
: Get value of environment variable`$GETENV(name)' returns a string consisting of the current value of the environment variable name. (Under VMS, logical names behave like environment variables.)
The argument to $GETENV
need not be a string (double-quoted), but
it may be if necessary to avoid the expansion of a macro.
$HEADER
: Value of RCS global keyword Header
Equivalent to `$KEYWORD(Header)'. See section $KEYWORD
: Value of global RCS-like keyword.
$HOME
: The user's home directory`$HOME' is a convenience macro equivalent to `$GETENV(HOME)'.
$ID
: Value of RCS global keyword Id
Equivalent to `$KEYWORD(Id)'. See section $KEYWORD
: Value of global RCS-like keyword.
$IF
: Two-way conditional
$IF
is a primitive function (not a macro) that is the code-part
version of `@#if'.
The syntax is
$IF(expr, action-if-true, action-if-false)
The expr is an @FWEB{} macro expression that must reduce to 0 (false) or 1 (true). First that argument is expanded. If it is true, action-if-true is expanded; otherwise action-if-false is expanded.
There may be peculiarities with this and the other built-in $IF
function having to do with the order of expansion when the actions
contain macros whose arguments themselves are macros. Therefore, do not
use them unless absolutely necessary.
Do not redefine $IF
or any other built-in conditionals, as they
are used internally to @FWEB{}.
$IFCASE
: n-way conditionalThis primitive built-in behaves like TeX's `\ifcase' command. The syntax is
$IFCASE(expr, case-0, case-1, ...,case-n-1, default)
If expr reduces to an integer between 0 and n-1, inclusively, the appropriate case is selected; otherwise, the default case is selected.
As examples,
$IFCASE(2, zero, one, two, default) => `two' $IFCASE(2, zero, one, three) => `three' $IFCASE(2, zero, one) => `one'
$IFDEF
: Two-way conditionalThis built-in primitive is the code-part version of `@#ifdef'. The syntax is
$IFDEF(macro, action-if-defined,action-if-not-defined)
$IFNDEF
: Two-way conditionalThis built-in primitive is the code-part version of `@#ifndef'. The syntax is `$IFNDEF(macro, action-if-not-defined, action-if-defined)'.
$IFELSE
: Two-way conditionalThe syntax of this built-in primitive is `$IFELSE(expr1, expr2, action-if-equal, action-if-not-equal)'. The expansions of expr1 and expr2 are compared on a byte-by-byte basis. If they are equal, the first action is taken, otherwise the second action is taken.
For example,
$M(S="abc")@% $IFELSE("abc", S, yes, no)
evaluates to `yes'.
$INCR
: Increment a macro`$INCR(N)' redefines the numeric macro N to be one greater than its previous value. (If N does not simplify to a number, an error results.) In other words, in the language of C the effect is to say `N++'.
The two-argument form `$INCR(N,m)' executes the equivalent of `N += m'.
$INPUT_LINE
: Line number that begins current section
`$INPUT_LINE' is the number of the line in the web
source file
that begins the current section (not the source line in which the
$INPUT_LINE
command appears). Compare $OUTPUT_LINE
,
section $OUTPUT_LINE
: Current line number of tangled output.
$KEYWORD
: Value of global RCS-like keyword`$KEYWORD' provides a built-in function alternative to the use of `@K' in a code part. (see section `@K': Extract global RCS-like keyword).
`$KEYWORD(Keyword)' extracts (as a character string) the text of an RCS-like keyword defined in the ignorable commentary between `@z' and `@x' at the beginning of the web source file (see section `@z': Begin ignorable material, or terminate change). (RCS stands for "revision-control system.") The general syntax is (UNIX users, see `man ident')
$Keyword: text of keyword $
For example,
@z $Author: krommes $ @x @c @ @a char author[] = $KEYWORD(Author);
This tangles to
char author[] = "krommes";
In this example, `$Author' is one of the standard RCS keywords. However, any keyword that fits the syntax `$keyword: contents $' can be accessed by `$KEYWORD'. (At least one blank is necessary before and after contents.) The argument of `$KEYWORD' need not be quoted, but it may be. In either event, the output is a quoted string.
Keywords extracted from ignorable commentary at the beginning of a web file are called global and are known throughout the code. Distinguish these from local keywords extracted from ignorable commentary at the beginning of an include (`@i') file. Such keywords are known only during the time that file is being read and are accessible via `@k' (see section `@k': Access local RCS-like keyword).
For convenience, built-ins are defined for some standard RCS global keywords. These are
$AUTHOR => $KEYWORD(Author) $DATE_TIME => $KEYWORD(Date) $HEADER => $KEYWORD(Header) $ID => $KEYWORD(Id) $LOCKER => $KEYWORD(Locker) $NAME => $KEYWORD(Name) $RCSFILE => $KEYWORD(RCSfile) $REVISION => $KEYWORD(Revision) $SOURCE => $KEYWORD(Source) $STATE => $KEYWORD(State)
There are no such abbreviations for local keywords, because such abbreviations would be expanded during output whereas it is necessary to recognize and expand the local keywords during input. Presumably such local keywords will be used rarely, if at all.
$L
: Change to lower case`$L(string)' changes string to lower case. The argument is first expanded in case it is a macro.
$L_KEYWORD
: Value of local RCS-like keywordFor most purposes, `$L_KEYWORD' behaves as `@k' (see section `@k': Access local RCS-like keyword). It is still under development and should not be used yet.
`$L_KEYWORD("Keyword")' extracts (as a character string) the text of an RCS-like keyword defined in the ignorable commentary between `@z' and `@x' at the beginning of a file included via `@i'. `$L_KEYWORD("local keyword")' is expanded during input, and the results are known only during the time the include file is being read.
Note that the argument of `$L_KEYWORD' must be a quoted string.
For more discussion of the distinction between local and global
keywords, please see section `@z': Begin ignorable material, or terminate change and section $KEYWORD
: Value of global RCS-like keyword.
It is expected that local keywords will rarely be used, as fundamental revision-control information should presumably be extracted from the top of the master web file.
$LANGUAGE
: Identifier for current languageThis expands to an identifier that denotes the current language, as follows:
Language $LANGUAGE
C $C
C++ $CPP
Fortran $N
Fortran-90 $N90
Ratfor $R
Ratfor-90 $R90
TeX $X
VERBATIM $V
Note that this outputs identifiers, not @FWEB{} macros. They are intended to be used in
$IF
or$IFELSE
statements such as$IF($LANGUAGE==$C, C-text, other-text)For multiway switches, the
$LANGUAGE_NUM
built-in is more useful; see section$LANGUAGE_NUM
: Number of current language.
$LANGUAGE_NUM
: Number of current language`$LANGUAGE_NUM' expands to an integer that uniquely defines the current language, as follows:
Language $LANGUAGE_NUM
C 0
C++ 1
Fortran 2
Fortran-90 3
Ratfor 4
Ratfor-90 5
TeX 6
VERBATIM 7
This built-in is useful in conjunction with an
$IFCASE
construction; see section$IFCASE
: n-way conditional.
$LEN
: Length of string`$LEN(string)' returns the length of string in bytes. If string is not surrounded by quotes, it is interpreted as if it were quoted (so it is not expanded if it is a macro). Thus, in the example
@m SS string $LEN(SS)the value returned is 2, not 5.
To expand the argument before taking the length, one can say something like
@m $XLEN(s) $LEN(s)
$LOCKER
: Value of RCS global keywordLocker
Equivalent to `$KEYWORD(Locker)'. See section
$KEYWORD
: Value of global RCS-like keyword.
$LOG
: Natural logarithm
$LOG10
: Logarithm to the base 10
$M
: Define a deferred macro
$M
is equivalent to$DEFINE
. See section$DEFINE
: Deferred macro definition.
$MAX
: Maximum of a list`$MAX(x1,x2,...)' returns the maximum of the list of arguments. (There must be at least one argument.)
$MIN
: Minimum`$MIN(x1,x2,...)' returns the minimum of the list of arguments. (There must be at least one argument.)
$MODULE_NAME
: Name of presentweb
module`$MODULE_NAME' returns the name of the present
web
module. If the present module is unnamed, it returns the string"unnamed"
.
$MODULES
: Total number of independent modules`$MODULES' gives the total number of independent modules--that is, the number of independent module names, plus 1 for the unnamed module.
$NAME
: Value of RCS global keywordName
Equivalent to `$KEYWORD(Name)'. See section
$KEYWORD
: Value of global RCS-like keyword.
$OUTPUT_LINE
: Current line number of tangled outputThis returns the current line number of the tangled output. Contrast this with
$INPUT_LINE
, section$INPUT_LINE
: Line number that begins current section.
$P
: The C preprocessor symbol
$P
is (essentially) a synonym for `$UNQUOTE("#")' (see section$UNQUOTE
: Remove quotes from string). It is useful for constructing @FWEB{} macro definitions that expand to C preprocessor statements. For example,@m CHECK(flag) $P if(flag) special code; $P endifAnother version of the preprocessor symbol is
$PP
(see section$PP
: The C preprocessor symbol). For most purposes,$P
and$PP
will behave in exactly the same way. The difference between them is that$P
is treated as a string (without surrounding quotes), whereas$PP
is treated as a character. The character nature of$PP
is used by FORTRAN to reset the column number to 1, so C-like preprocessor commands appear there rather than in column 7. For further discussion of strings and the differences between$P
and$PP
, see section Strings and quotes.
$PI
: PiThe expression `$PI' returns @PI{} to the default machine precision. The expression `$PI(iprec)' returns to the decimal precision iprec (which must be less than 50).
$POW
: Exponentiation`$POW(x,y)' generates (It is a macro defined in terms of
$EVAL
(see section$EVAL
: Evaluate a macro expression) and the exponentiation operator.)
$PP
: The C preprocessor symbol
$PP
is shorthand for `$UNSTRING($P)' (see section$P
: The C preprocessor symbol), or (essentially) a synonym for `$UNSTRING("#")' (see section$UNSTRING
: Convert string into characters). It is useful, particularly in FORTRAN, for constructing @FWEB{} macro definitions that expand to C preprocessor statements. For an example, see section$P
: The C preprocessor symbol. For a detailed discussion of the difference between `$P' and `$PP', see section Strings and quotes.
$RCSFILE
: Value of RCS global keyword$RCSfile
Equivalent to `$KEYWORD(RCSfile)'. See section
$KEYWORD
: Value of global RCS-like keyword.
$REVISION
: Value of RCS global keywordRevision
Equivalent to `$KEYWORD(Revision)'. See section
$KEYWORD
: Value of global RCS-like keyword.
$ROUTINE
: Current function (RATFOR only)When RATFOR is the current language,
$ROUTINE
expands to a string built of the name of the current program, function, or subroutine. This function is not useful for other languages, for which it expands to the null string.
$SECTION_NUM
: Number of current @FWEB{} section`$SECTION_NUM' returns an integer greater than 0 that is the integer number of the current
web
section. (This is not the LaTeX section number such as 3.4.)
$SECTIONS
: Maximum section number`$SECTIONS' is the maximum section number as understood by @FWEAVE{}.
$SOURCE
: Value of RCS global keywordSource
Equivalent to `$KEYWORD(Source)'. See section
$KEYWORD
: Value of global RCS-like keyword.
$SQRT
: Square root`$SQRT(x)' returns It is a convenience macro defined in terms of
$POW
. See section$POW
: Exponentiation.
$STATE
: Value of RCS global keywordState
Equivalent to `$KEYWORD(State)'. See section
$KEYWORD
: Value of global RCS-like keyword.
$STRING
: Expand, then stringize`$STRING(s)' expands its argument if it is a macro, then makes the expansion into a quoted string. If the argument is already a quoted string, it is returned unchanged.
$STUB
: Trap for missing moduleWhen a missing module is detected, @FTANGLE{} inserts the command `$STUB(module_name)' into the output code. The built-in
$STUB
expands to a function call appropriate to the current language. For example, in C it expands to `missing_mod', in FORTRAN it expands to `call nomod'.
$TIME
: The time`$TIME' returns a string consisting of the local time in the form
"19:59"
.
$TRANSLIT
: TransliterationThe macro `$TRANSLIT(s, from, to)' interprets each of its arguments as strings (without expanding anything). Then s is modified by replacing any of the characters found in from by the corresponding characters in to. If to is shorter than from, then the excess characters in from are deleted from s. As a limiting case, if to is empty, then all the characters in from are deleted from s. For example, `$TRANSLIT(s, aeiou, 12345)' replaces the vowels in s by the corresponding digits, and `$TRANSLIT(s, aeiou, )' deletes all the vowels. The backslash may be used to escape a character, as in ANSI C. For example, `$TRANSLIT("a\\"\\\\d", "d\\\\a\\"", "D,A'")' translates into `A',D'. Here one had to explicitly enclose strings involving `\\"' in double quotes in order to avoid a complaint about an unterminated string.
$U
: Change to upper case`$U(string)' changes string to upper case.
$UNDEF
: Undefine a macro`$UNDEF(macro)' undefines an @FWEB{} macro.
$UNQUOTE
: Remove quotes from string`$UNQUOTE(string)' returns string without its surrounding quotes. (However, the resulting construction is still treated as a string; no macro expansion is done.)
For a more detailed discussion and a comparison with
$UNSTRING
(see section$UNSTRING
: Convert string into characters), see section Strings and quotes.
$UNSTRING
: Convert string into characters`$UNSTRING(string)' removes quotes from the string, if they are present, and treats the result as a collection of characters. No tokenization is done, so macro expansion does not operate on those characters.
For a more detailed discussion and a comparison with
$UNQUOTE
(see section$UNQUOTE
: Remove quotes from string), see section Strings and quotes.
$VERBATIM
: (Obsolete)This was an old name for
$UNQUOTE
(see section$UNQUOTE
: Remove quotes from string). Please remove all references to this macro from existing codes.
$VERSION
: Present @FWEB{} version number`$VERSION' returns a string built out of the @FWEB{} version number, such as
"1.61"
.Debugging with macros
If an @FWEB{} macro expands to more than one output line, debugging can be a bit confusing if the debugger (e.g.,
gdb
) displays lines in theweb
source file instead of the output file (as it normally does for C and C++). While single-stepping through the code, the debugger will incorrectly step the screen display for each output line even if the macro call occupies just one line in the source file. To localize the debugger's confusion, insert a `@#line' command after the macro call. For example,@c @ Example of a macro that expands to several output lines. @m UPDATE(i, delta_i) i += delta_i; store(i)@; @a main() { UPDATE(j, 5); @#line // More code. The debugger will be in sync from here on. }An alternative for highly confusing situations is to use the `-#' option (see section `-#': Turn off comments about line and section numbers (@FTANGLE{})).
Another potentially confusing situation occurs when `@%' is used to comment out a line. @FWEB{} deals with the line-number problem that arises here automatically; see section `-T#': Don't insert `#line' command after `@%'.
@FWEAVE{} makes a valiant attempt to pretty-print (see section Pretty-printing) the definitions of both outer macros and @FWEB{} macros in a reasonable way. However, this can be a formidable task, because macro syntax can be essentially arbitrary. Consider, for example, the following definition:
@c @d GET(type) type get_##type() @a GET(int){}@; // Expands into `int get_int(){}'.The problem is that the identifier `type' is used in two different ways: as the type of a reserved word (the second `type'), and as an ordinary expression (the third `type'). The first `type' has both meanings simultaneously. Unfortunately, within any particular language @FWEAVE{} associates one unique type or ilk with each identifier.
One solution to this problem is to use the `@R' command (see section `@R': Treat next identifier as integer-like reserved), which changes the ilk of the very next identifier to integer-like. Thus,
@d GET(type) @R type get_##type()@;will format correctly. An alternative solution uses the related command `@E', which changes the ilk of the very next identifier to an ordinary expression. Thus,
@f type int @d GET(type) type get_##@Etype()@;Other types of troublesome situations involve spaces. When @FWEB{} understands the syntax, it inserts spaces automatically to make the output pleasing. Consider, however, the (somewhat contrived) example
@c @d A(x, y) x y @d B s1; @d C s2; @a A(B, C)@;Here @FWEAVE{} will consider `x' and `y' to be ordinary identifiers (simple expressions), and will abut them with no intervening spaces, which is confusing to read. The solution is to insert a space manually with `@,':
@d A(x, y) x @, y(Whether one should write macros like this at all is a separate issue.) For a related example, see the discussion of section Spacing.
Preprocessing
Generally, the @FWEB{} preprocessor commands follow a syntax identical to their C/C++ counterparts. The one exception is the `@#line' command. Whereas the C command takes a line number and file name as arguments, the @FWEB{} command takes no arguments; its expansion automatically inserts the current line number and file name. This command should be necessary only in rare circumstances. One of those involves situations in which an @FWEB{} macro expands to more than one output line; see section Debugging with macros.
The @FWEB{} preprocessor commands may appear in either the definition or the code parts. But BEWARE: No matter where they appear, they are expanded during INPUT, not output. (This is probably a design flaw.) For more discussion, see section @FWEB{} macros.
The syntax of each command is as follows:
@#line
- -- Insert a
#line
command.@#define identifier
- -- Define an FWEB macro; equivalent to `@m'.
@#undef identifier
- -- Undefine an FWEB macro.
@#ifdef identifier
- -- Is FWEB macro defined? Equivalent to `@#if defined identifier'.
@#ifndef identifier
- -- Is FWEB macro not defined? Equivalent to `@#if !defined identifier'.
@#if expression
@#elif expression
@#else
@#endif
In the `@#if' statement, the expression may contain @FWEB{} macros, but must ultimately evaluate to a number. If that number is zero, the expression is false; otherwise, it is true.
The expression following constructions such as `@#if' is evaluated by a built-in expression evaluator that can also be used for other purposes, such as in macro expansion. Its behavior is again motivated by expression evaluation in ANSI C; it is not quite as general, but should be more than adequate. (One design flaw that will be fixed someday is that the order of expression evaluation is not necessarily left-to-right, as it is in C.) It supports both integer and floating-point arithmetic (with type promotion from integer to floating-point if necessary), and the ANSI
defined
operator. Operators with the highest precedence (see table below) are evaluated first; as usual, parentheses override the natural order of evaluation. The unary operatordefined
has the highest precedence; all the other unary operators have the next highest (and equal) precedence; then come the binary operators. When the operator exists in C, the action taken by @FWEB{} is precisely that that the C compiler would take. Arithmetic is done in either long or double variables, as implemented by the C compiler that compiled @FTANGLE{}. (This was the easy choice, not necessarily the most desirable one.)The operators, listed from highest precedence to lowest, are as follows
Go to the first, previous, next, last section, table of contents.