Go to the first, previous, next, last section, table of contents.


MACROS and PREPROCESSING

@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

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

@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.

Various features of @FWEB{} macros

@FWEB{} macros with variable arguments

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.

Recursion

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!

Protecting macros against redefinition

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).

Special tokens

The following special tokens may be used in the text of @FWEB{} macro definitions:

ANSI C-compatible tokens

 ##          --- 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");'

Extensions to ANSI C macro syntax

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

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.

Strings and quotes

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),

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.

Redefining built-in functions

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 terminal

In 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 logarithms

The 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

`$EXP(x)' returns

$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 conditional

This 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 conditional

This 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 conditional

This 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 conditional

The 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 keyword

For 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 language

This 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 keyword Locker

    Equivalent to `$KEYWORD(Locker)'. See section $KEYWORD: Value of global RCS-like keyword.

    $LOG: Natural logarithm

    `$LOG(x)' returns

    $LOG10: Logarithm to the base 10

    `$LOG10(x)' returns

    $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 present web 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 keyword Name

    Equivalent to `$KEYWORD(Name)'. See section $KEYWORD: Value of global RCS-like keyword.

    $OUTPUT_LINE: Current line number of tangled output

    This 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 endif
    

    Another 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: Pi

    The 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 keyword Revision

    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 keyword Source

    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 keyword State

    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 module

    When 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: Transliteration

    The 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 the web 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 operator defined 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.