The following list shows the builtins defined by the Yodl
converters define and which can be used in Yodl documents. Refer to the Yodl
user guide, distributed with the Yodl package, for a full description.
The following list shows all builtins of the package in
alphabetical order.
- `Yodl’s builtin commands’
- As mentioned previously, YODL’s input consists of text and of
commands. YODL supports a number of built-in commands which may either be
used in a YODL document, or which can be used to create a macro
package.
- Don’t despair if you find that the description of this section is
too technical. Exactly for this reason, YODL supports the macro packages
to make the life of a documentation writer easier. E.g., see chapter
`[MACROPACKAGE]’ that describes a macro package for YODL.
- Most built-in functions and macros expand the information they receive the
way they receive the information. I.e., the information itself is only
evaluated by the time it is eventually inserted into an output medium
(usually a file). However, some builtin functions evaluate their
argument(s) once the argument is processed. They are:
- o
- The `ERROR’ built-in function (see section `[ERROR]’);
- o
- The `EVAL’ built-in function (see section `[EVAL]’);
- o
- The `FPUTS’ built-in function (see section `[FPUTS]’);
- o
- The `INTERNALINDEX’ built-in function (see section
`[INTERNALINDEX]’);
- o
- The `PUSHSUBST’ built-in function (see section
`[PUSHSUBST]’);
- o
- The `TYPEOUT’ built-in function (see section
`[TYPEOUT]’);
- o
- The `UPPERCASE’ built-in function (see section
`[UPPERCASE]’);
- o
- The `WARNING’ built-in function (see section
`[WARNING]’);
- o
- The `XXSUBST’ internal use only built-in function; All other
built-in functions will not evaluate their arguments. See the
mentioned functions for details, and in particular `EVAL()’ for a
description of this evaluation process.
- `ADDTOCOUNTER’
- The `ADDTOCOUNTER’ function adds a given value to a counter. It
expects two arguments: the counter name, and an additive expression
defining the value to add. The counter must be previously created with
`DEFINECOUNTER’.
- The additive expression may not contain blank spaces and may use + and -
operators, its operands may either be integral numeric values or names of
(defined) counters. The resulting value can be negative; in that case, a
value is subtracted from the destination counter.
- For example, if `one’ and `two’ are counters, then
ADDTOCOUNTER(one)(-two)\// subtracts two’s value from one
ADDTOCOUNTER(one)(two+two)\// adds 2 x two’s value to one
- See further section `[COUNTERS]’.
- `ADDTOSYMBOL’
- Since Yodl version 2.00 symbols can be manipulated. To add text to an
existing symbol the builtin `ADDTOSYMBOL’ is available. It expects
two parameter lists: the symbol’s name, and the text to add to the
symbol. The symbol must have been created earlier using DEFINECOUNTER (see
section `[DEFINECOUNTER]’). The macro’s second argument is
not evaluated while `ADDTOSYMBOL’ is processed. Therefore, it is
easy to add the text of another symbol or the expansion of a macro to a
symbol value. E.g.,
ADDTOSYMBOL(one)(SYMBOLVALUE(two)XXnl())
This adds the text of symbol `two’, followed by a new line, to the
contents of symbol `one’ only when symbol `one’ is
evaluated, not when `ADDTOSYMBOL’ is evaluated.
- Example:
ADDTOSYMBOL(LOCATION)(this is appended to LOCATION)
- `ATEXIT’
- `ATEXIT’ expects one argument. The argument is appended to the
output file. Note that this text is subject to character table
translations etc..
- An example using this function is the following. A document in the LaTeX
typesetting language requires `\end{document}’ to occur at the end
of the document. To automatically append this string to the output file,
the following specification can be used:
ATEXIT(NOEXPAND(\end{document}))
Several `ATEXIT’ lists can be defined. They are appended to the
output file in the reverse order of specification; i.e., the first
`ATEXIT’ list is appended to the output file last. That means that
in general the `ATEXIT’ text should be specified when a
`matching’ starting command is sent to the output file; as in:
COMMENT(Start the LaTeX document.)
NOEXPAND(\begin{document})
COMMENT(Ensure its proper ending.)
ATEXIT(NOEXPAND(\end{document}))
- `CHAR’
- The command `CHAR’ takes one argument, a number or a character, and
outputs its corresponding ASCII character to the final output file. This
command is built for `emergency situations’, where you need to
typeset a character despite the fact that it may be redefined in the
current character table (for a discussion of character tables, see
`[CHARTABLES]’). Also, the `CHAR’ function can be used to
circumvent Yodl’s requirement that open- and close-parentheses must
match.
- The following arguments may be specified with `CHAR’ (attempted in
this order):
- o
- A decimal number indicating the number of the character in the ascii-table
(for example `CHAR’`(41)’);
- o
- A plain, single character (for example `CHAR’`(#)’).
- So, when you’re sure that you want to send a printable character
that is not a closing parenthesis to the output file, you can use the form
`CHAR’`(c)’, `c’ being the character (as in,
`CHAR’`(;)’). To send a non-printable character or a closing
parenthesis to the output file, look up the ASCII number of the character,
and supply that number as argument to the `CHAR’ command.
- Example: The following two statements send an `A’ to the output
file.
CHAR(65)
CHAR(A)
The following statement sends a closing parenthesis:
CHAR(41)
Another way to send a string to the output file without expansion by
character tables or by macro interpretation, is by using the function
`NOTRANS’ (see section `[NOTRANS]’). If you want to send a
string to the output without macro interpretation, but with
character table translation, use `NOEXPAND’ (see section
`[NOEXPAND]’).
- `CHDIR’
- The command `CHDIR’ takes one argument, a directory to change to.
This command is implemented to simplify the working with
`includefile’ (see `includefile’ in `yodlmacros(7)’).
As a demonstration, consider the following fragment:
includefile(subdir/onefile)
includefile(subdir/anotherfile)
includefile(subdir/yetanotherfile)
This fragment can be changed to:
CHDIR(subdir)
includefile(onefile)
includefile(anotherfile)
includefile(yetanotherfile)
CHDIR(..)
The current directory, as given to `CHDIR’, only affects how
`includefile’ searches for its files.
- Note that this example assumes that the current working directory is a
member of Yodl’s include-path specification (cf., Yodl’s
`--include’ option).
- `COMMENT’
- The `COMMENT’ function defines one parameter list. The text that is
passed as argument is treated as comment. I.e., it is ignored; it is not
copied to the final output file.
- As an alternative to (short) `COMMENT’ the triplet
`\’`//’ can be used. It starts `end of line’ comment,
ignoring all characters on a line starting at `\’`//’ up to
the first non-blank character encountered on the next line. If the next
line’s first non-blank characters are `\’`//’, then
that begins another end of line comment, which will therefore also be
skipped.
- To actually write `\’`//’ or, using the current font: \// in
a yodl-converted document, write, e.g., `tt(\)tt(//)’ or, using the
current font: nop(/)// in a yodl-source file, and write
`\CHAR’`(/)/’ in `verb’ sections.
- Example:
Hello world\// producess Hello world, skipping the rest
\// this line is completely ignored
s\// at this point Hello worlds has been produced.
- `COUNTERVALUE’
- `COUNTERVALUE’s’ argument expands to the value of a counter.
Its single argument must contain the name of a counter. The counter must
have been created earlier using the builtin `DEFINECOUNTER’.
Example:
The counter has value COUNTERVALUE(MYCOUNTER).
See also section `[COUNTERS]’.
- `DECWSLEVEL’
- `DECWSLEVEL’ requires one (empty) argument. It reduces the current
white-space level. The white-space level typically is used in files that
only define Yodl macros. When no output should be generated while
processing these files, the white-space level can be used to check for
this. If the white-space level exceeds zero, a warning is generated if the
file produces non-whitespace output. The builtin function
`DECWSLEVEL’ is used to reduce the whitespace level following a
previous call of `INCWSLEVEL’.
- Once the white space level exceeds zero, no output will be generated.
White space, therefore effectively is ignored. The white space level
cannot be reduced to negative values. A warning is issued if that would
have happened if it were allowed.
- Example:
INCWSLEVEL()
DEFINESYMBOL(....)
DEFINEMACRO(...)(...)(...)
DECWSLEVEL()
Without the `INCWSLEVEL’ and `DECWSLEVEL’, calls, the above
definition would generate four empty lines to the output stream.
- The `INCWSLEVEL’ and `DECWSLEVEL’ calls may be nested. The
best approach is to put an `INCWSLEVEL’ at the first line of a
macro-defining Yodl-file, and a matching `DECWSLEVEL’ call at the
very last line.
- `DEFINECHARTABLE’
- `DEFINECHARTABLE’ is used to define a character translation table.
The function expects two parameterlists, containing the name of the
character table and character table translations on separate lines. These
character table translations are of the form
character = quoted-string
Here, character is always a value within single quotes. It may be a single
character, an octal character value or a hexadecimal character value. The
single character may be prefixed by a \-character (e.g.,
`’\\’’). The octal character value must start with a
backslash, followed by three octal digits (e.g.,
`’\045’’. The hexadecimal character value starts with
`0x’, followed by two hexadecimal characters. E.g.,
`’0xbe’’. The double quoted string may contain
anything (but the string must be on one line), possibly containing
escape-sequences as well: in the double quoted string the standard
C escape sequences `\a’ (alert), `\b’ (beep),
`\f’ (formfeed), `\n’ (newline), `\r’ (carriage
return), `\t’ (tab), and `\v’ (vertical tab) are recognized
and automatically converted to their special meanings. Starting with Yodl
2.14.0 octal and hexadecimal constants may also be used. E.g., character
`Y’ may also be specified using the octal value `\131’ or
the hexadecimal value `\x59’. Any other character following a
backslash character (`\’) defines itself: `\\’ represents a
single backslash character.
- Example:
DEFINECHARTABLE(demotable)(
’&’ = "&"
’\\’ = "\\backslash"
’\045’ = "oct(45)"
’0xa4’ = "hex(a4)"
)
The builtin function `DEFINECHARTABLE’ does not activate the
table. The table is merely defined. To activate the character translation
table, use `USECHARTABLE’. The discussion of character tables is
postponed to section `[CHARTABLES]’.
- `DEFINECOUNTER’
- `DEFINECOUNTER’ creates a new counter. This builtin function
expects two arguments: the name of the counter and an additive expression
whose value is used to initialize the counter.
- The additive expression may not contain blank spaces and may use + and -
operators, its operands may either be integral numeric values or names of
(defined) counters. The resulting value can be negative; in that case, a
value is subtracted from the destination counter.
- Examples:
DEFINECOUNTER(year)(1950)
DEFINECOUNTER(nTimes)(year+12)\// initializes nTimes to 1962
- See also section `[COUNTERS]’ and the `USECOUNTER’ and
`ADDTOCOUNTER’ builtin functions.
- `DEFINEMACRO’
- `DEFINEMACRO’ is used to define new macros. This function expects
three arguments:
- o
- An identifier, being the name of the macro to define. This identifier may
only consist of uppercase or lowercase characters. Note that it can
not contain numbers, nor underscore characters.
- o
- A number, stating the number of arguments that the macro will require once
it’s used. The number must be in the range 0 to 61.
- o
- The text that the macro expands to, once used. This text may contain the
strings `ARG’x, x being 1, 2, etc.. At these places
the arguments to the macro are pasted in. The numbers that identify the
arguments are 1 to 9, then A to Z and finally a to z. This gives a range
of 61 expandable arguments, which is enough for all real-life
applications. For example, the following fragment defines a macro
`bookref’, which can be used to typeset a reference to a book. It
requires three arguments; say, an author, a title and the name of a
publisher:
DEFINEMACRO(bookref)(3)(
Author(s): ARG1
Book title: ARG2
Published by: ARG3
)
Such a macro could be used as follows:
bookref(Sobotta/Becher)
(Atlas der Anatomie des Menschen)
(Urban und Schwarzenberg, Berlin, 1972)
When called, it would produce the following output:
Author(s): Sobotta/Becher
Book title: Atlas der Anatomie des Menschen
Published by: Urban und Schwarzenberg, Berlin, 1972
While applying a macro, the values of the three arguments are pasted to the
places where `ARG1’, `ARG2’ etc. occur in the
definition.
- Note the following when defining new macros:
- o
- The argument containing the name of the new macro, `(bookref)’ in
the above example, must occur right after `DEFINEMACRO’. No spaces
are allowed in between. Space characters and newlines may however occur
following this first argument.
- This behavior of the `yodl’ program is similar to the usage of the
defined macro: the author information must, enclosed in parentheses,
follow right after the `bookref’ identifier. I implemented this
feature to improve the distinguishing between macros and real text. E.g.,
a macro `me’ might be defined, but the text
I like me (but so do you)
still is simple text; the macro `me’ only is activated when a
parenthesis immediately follows it.
- o
- Be careful when placing newlines or spaces in the definition of a new
macro. E.g., the definition, as given:
DEFINEMACRO(bookref)(3)(
Author(s): ARG1
Book title: ARG2
Published by: ARG3
)
introduces extra newlines at the beginning and ending of the macro, which
are copied to the output each time the macro is used. The extra newline
occurs, of course, right before the sequence `Author(s):’ and
following the evaluation of `ARG3’. A simple backslash character at
the end of the `DEFINEMACRO’ line would prevent the insertion of
extra newline characters:
DEFINEMACRO(bookref)(3)(\
Author(s): ARG1
Book title: ARG2
Published by: ARG3
)
- o
- Note that when a macro is used which requires no arguments at all, one
empty argument still must be specified. E.g., my macro package (see
chapter `[MACROPACKAGE]’) defines a macro `it’ that starts a
bullet item in a list. The macro takes no arguments, but still must be
typed as `it()’.
- This behavior is consistent: it helps distinguish which identifiers are
macros and which are simple text.
- o
- Macro arguments may evaluate to text. When a \ is appended to the
macro-argument, or in the default input handling within a non-zero
white-space level (see section `[INCWSLEVEL]’) this may invalidate
a subsequent macro call. E.g., the macro
DEFINEMACRO(oops)(1)(
ARG1
XXnl()
)
when called as `oops(hello world)’, produces the output:
hello worldXXnl()
To prevent this gluing to arguments to subsequent macros, a single
`+’ should be prepended to the macro call:
DEFINEMACRO(oops)(1)(
ARG1
+XXnl()
)
See also section `[PLUSIDENT]’ obout the
`+identifier’-sequence.
- o
- Note the preferred layout of macro definitions and macro calls. Adhere to
this form, to prevent drowning in too many parentheses. In
particular:
- o
- Put all elements of the macro definition on one line, except for the
macro-expansion itself. Each expansion element should be on a line by
itself.
- o
- When calling macros put the macro’s arguments underneath each
other. If the macrolists themselves contain macro-calls, put each call
again on a line of its own, indenting one tab-position beyond the location
of the opening parenthesis of the argument.
- o
- No continnuation backslashes are required between arguments.
- o
- With complex calls, indent just the arguments, and put the parentheses in
their required of logical locations. Example of a complex call:
complex(
first(
ARG1
)(
ARG2
+XXnl()
)
ARG3
+nop()
ARG4
+XXnl()
)
- o
- Macro expansion proceeds as follows:
- o
- The arguments are read from the input
- o
- The contents of the arguments then replace their `ARGx’ references
in the macro’s definition (in some exceptional cases, clearly
indicated as such when applicable, the arguments themselves are evaluated
first, and then these evaluated arguments are used as replacements for
their corresponding `ARGx’ references).
- o
- The now modified macro is read by Yodl’s lexical scanner. This may
result in yet another macro expansion, which will then be evaluated
recursively.
- o
- Eventually, all expansion is completed (well, should complete, since Yodl
doesn’t test for eternal recursion) and scanning of the input
continues beyond the original macro call. For example, assume we have the
following two macros:
DEFINEMACRO(First)(1)(
Hello ARG1
+XXnl()
)
DEFINEMACRO(Second)(1)(
First(ARG1)
First(ARG1)
)
and the following call is issued:
Second(Yodl)
then the following happens:
- o
- `Second(Yodl)’ is read as encountered.
- o
- `ARG1’ in `Second’ is replaced by YODL, and the resulting
macro body is sent to the lexical scanner for evaluation: It will see:
First(Yodl)First(Yodl)
- o
- The first call to `First()’ is now evaluated. This puts (after
replacing `ARG1’ by YODL) the following on the scanner’s
input:
Hello Yodl+XXnl()First(Yodl)
- o
- `Hello Yodl’ contains no macro call, so it is written to the output
stream. Remains:
+XXnl()First(Yodl)
- o
- Assume `XXnl()’ merely contains a newline (represented by
`\n’, here), so `+XXnl()’ is now replaced by `\n’.
This results in the following input for the lexical scanner:
\nFirst(Yodl)
- o
- The `\n’ is now written to the output stream, and the scanner sees:
First(Yodl)
- o
- The second call to `First()’ is now evaluated. This puts the
following on the scanner’s input:
Hello Yodl+XXnl()
- o
- `Hello Yodl’ is written to the output stream. Remains:
+XXnl()
- o
- `+XXnl()’ is now replaced by `\n’. The lexical scanner sees:
\n
- o
- The newline is printed and we’re done.
- `DEFINESYMBOL’
- `DEFINESYMBOL’ expects two arguments. An identifier, which is the
name of the symbol to define, and the textual value of the symbol. If the
second argument is empty, the symbol is defined, but has an empty
value.
- The earlier interpretation of a Yodl symbol as a logical flag can still be
used, but allowing it to obtain textual values greatly simplifies various
Yodl macros.
- Example:
DEFINESYMBOL(Yodl)(Your own document language)
DEFINESYMBOL(Options)()
- `DELETECHARTABLE’
- `DELETECHARTABLE’ removes a definition of a character table that
was defined by `DEFINECHARTABLE’. This function expects one
argument: the name of the character table remove.
- It’s an error to attempt to delete a character table that is
currently in use or to attempt to delete a non-existing character
table.
- Example:
DELETECHARTABLE(mytable)
- `DELETECOUNTER’
- `DELETECOUNTER’ removes a definition of a counter that was defined
by `DEFINECOUNTER’. This function expects one argument: the name of
the counter to remove.
- If the counter does not exist, a warning is issued. It is not considered
an error to try to delete a counter that has not been defined
earlier.
- Example:
DELETECOUNTER(mycounter)
- `DELETEMACRO’
- `DELETEMACRO’ removes a definition of a macro that was defined by
`DEFINEMACRO’. This function takes one argument: the macro name to
remove.
- There is no error condition (except for syntax errors): when no macro with
a matching name was previously defined, no action is taken.
- For example, the safe way to define a macro is by first undefining it.
This ensures that possible previous definitions are removed first:
- Example:
DELETEMACRO(mymacro)
- `DELETENOUSERMACRO’
- `DELETENOUSERMACRO’ removes a `nousermacro’ definition. The
function expects one argument: the name of the `nousermacro’
identifier to be removed from the nousermacro-set.
- There is no error condition (except for syntax errors): when the
identifier wasn’t stored as a `nousermacro’ no action is
taken.
- Example:
DELETENOUSERMACRO(mymacro)
- `DELETESYMBOL’
- `DELETESYMBOL’ removes the definition of a symbol variable. It
expects one argument, holding the name of the variable to deleted.
- This macro has no error condition (except for syntax errors): the symbol
in question may be previously defined, but that is not necessary.
- Example:
DELETESYMBOL(Options)
- `ERROR’
- The `ERROR’ function takes one argument: text to display to the
standard error stream. The current input file and line number are also
displayed. After displaying the text, the `yodl’ program aborts
with an exit status of 1.
- The text passed to the function is expanded first. See the example.
- The `ERROR’ function is an example of a function that evaluates its
argument itself.
- This command can be used, e.g., in a macro package when an incorrect macro
is expanded. In my macro package (see chapter `[MACROPACKAGE]’) the
`ERROR’ function is used when the sectioning command
`chapter()’ is used in an `article’ document (in the
package, `chapter’’s are only available in `book’s or
`report’s).
- An analogous builtin function is `WARNING’, which also prints a
message but does not exit (see section `[WARNING]’).
- Example: In the following call, `COUNTERVALUE(NTRIES)’ is replaced
by its actual value:
ERROR(Stopping after COUNTERVALUE(NTRIES) attempts)
- `EVAL’
- The `EVAL’ function takes one argument: the text to be evaluated.
This function allows you to perform an indirect evaluation of Yodl
commands. Assume that there is a symbol `varnam’ containing the
name of a counter variable, then the following displays the
counter’s value, after having incremented it:
EVAL(NOTRANS(USECOUNTER)(SYMBOLVALUE(varnam)))
- Here, `EVAL’ performs the following steps:
- o
- First, `NOTRANS(USECOUNTER)’ is evaluated, producing
`USECOUNTER’.
- o
- Next, the open parenthesis is processed, producing the open parenthesis
itself
- o
- Then, `SYMBOLVALUE(varnam)’ is evaluated, producing the name of a
counter, e.g. ``counter’’.
- o
- The closing parentheis is processed, producing the closing parenthesis
itself.
- o
- All this results in the text
USECOUNTER(counter)
- o
- This text is presented to Yodl’s lexical scanner, resulting in
incrementing the counter, and displaying its incremented value.
- b(Caveat): macro arguments themselves are usually not evaluated. So, a
construction like
USECOUNTER(EVAL(SYMBOLVALUE(varnam)))
fails, as ``EVAL(SYMBOLVALUE(varnam))’’ is not a legal name
for a counter. Here the `EVAL()’ call is used as an argument, and
is therefore not expanded.
- The distinction is subtle, and is a consequence of the fact that builtin
functions receive unprocessed arguments. Builtin functions may impose
certain requirements on their arguments (like `USECOUNTER’
requiring the name of a counter) and these requirements are checked on the
arguments as received.
- Summarizing: `EVAL’ acts as follows:
- o
- Its argument is presented to Yodl’s lexical scanner
- o
- The output produced by the processing of the argument is then inserted
into the input stream in lieu of the original `EVAL’ call.
- Most built-in functions do not evaluate their arguments. In fact,
only `ERROR, EVAL, FPUTS, INTERNALINDEX, PUSHSUBST, TYPEOUT, UPPERCASE,
WARNING’ and the iinternally used `XXSUBST’ functions
evaluate their arguments.
- Postponing evaluations allows you to write:
DEFINESYMBOL(later)(SYMBOLVALUE(earlier))
Eventually, and not when `later’ is defined, a statement like
SYMBOLVALUE(later)
produces the value of `earlier’ at the moment
`SYMBOLVALUE(later)’ is processed. This is, in all its complex
consequences, what would be expected in most cases. It allows us to write
general macros producing output that is only evaluated when the text of
symbols and values of arguments become eventually, rather than when the
macro is defined, available.
- Decisions like these invariably result in questions like `what if I have
to define variables using values of other variables?’ In those
cases `EVAL()’ must be used. The following example shows the
definition of three symbols: `one’ receives an initial value,
`two’ returns `one’’s actual value when
`two’’s value is displayed, `three’, using
`EVAL()’, stores `one’’s initial value.
- The example also shows yet another way to suppress macro calls, using the
macro `nop()’ which is defined in the all standard conversion
types:
DEFINESYMBOL(one)(One’s first value)
DEFINESYMBOL(two)(SYMBOLVALUE(one))
EVAL(DEFINESYMBOL+nop()(three)(SYMBOLVALUE(one)))
SETSYMBOL(one)(One’s second value)
"SYMBOLVALUE(two)" COMMENT(displays "One’s second value")
"SYMBOLVALUE(three)" COMMENT(displays "One’s first value")
- `FILENAME’
- The function `FILENAME()’ produces an absolute path to the
currently processed Yodl file. This is not necessarily the
canonical path name, as it may contain current- and parent-path
directories.
- `FPUTS’
- The function `FPUTS’ expects two arguments: the first argument is
information to be appended to a file, whose name is given as the second
argument. The first argument is processed by Yodl before it is appended to
the requested filename, so it may contain macro calls.
- For example, the following statement appends a countervalue to the
mentioned file:
FPUTS(There have been COUNTERVALUE(attempts) attempts)(/tmp/logfile)
The second argument (name of the file) is not evaluated, but is used as
received.
- `IFBUILTIN’
- The `IFBUILTIN’ function tests whether its first argument is the
name of a builtin function. If so, the second argument is evaluated, else,
the third argument is evaluated. All three arguments (the variable, the
true-list and the false-list) must be present; though the true-list and/or
the false-list may be empty.
- Example:
IFBUILTIN(IFBUILTIN)(\
`BUILTIN’ is a builtin - function
)(\
`BUILTIN’ is NOT a builtin - function
)
Please note the preferred layout: The first argument immediately follows the
function name, then the second argument (the true list) is
indented, as is the false list. The layout closely follows the
preferred layout of `if-else’ statements of many programming
languages.
- `IFCHARTABLE’
- The `IFCHARTABLE’ function tests whether its first argument is the
name of a character table. The character table needs not be active. If the
name is the name of a character table, the second argument is evaluated,
else, the third argument is evaluated. All three arguments (the name, the
true list and the false list) must be present; though the true list and/or
the false list may be empty.
- Example:
IFCHARTABLE(standard)(\
`standard’ is a character tablebuiltin - function
)(\
`standard’ is NOT a character tablebuiltin - function
)
Please note the preferred layout: The first argument immediately follows the
function name, then the second argument (the true list) is
indented, as is the false list. The layout closely follows the
preferred layout of `if-else’ statements of many programming
languages.
- `IFDEF’
- The `IFDEF’ function tests for the definition status of the
argument in its first argument. If it is a defined entity, the second
argument is evaluated, else, the third argument is evaluated. All three
arguments (the entity, the true list and the false list) must be present;
though the true list and/or the false list may be empty.
- The true list is evaluated if the first argument is the name of:
- o
- a built-in function, or
- o
- a character table, or
- o
- a counter, or
- o
- a no-user-macro symbol, or
- o
- a symbol, or
- o
- a user-defined macro, or Example:
IFDEF(someName)(\
`someName’ is a defined entity
)(\
`someName is not defined.
)
Please note the preferred layout: The first argument immediately follows the
function name, then the second argument (the true list) is
indented, as is the false list. The layout closely follows the
preferred layout of `if-else’ statements of many programming
languages.
- `IFEMPTY’
- `IFEMPTY’ expects three arguments: a symbol, a true-list and a
false-list. `IFEMPTY’ evaluates to the true-list if the symbol is
an empty string; otherwise, it evaluates to the false-list.
- The function does not further evaluate its argument. Its use is primarily
to test whether a macro has received an argument or not. If the intent is
to check whether a symbol’s value is empty or not, IFSTREQUAL
`[IFSTREQUAL]’ should be used, where the first argument is the name
of a symbol, and the second argument is empty.
- Example:
IFEMPTY(something)(\
`something’ is empty...
)(\
`something’ is not an empty string
)
In the same way, `IFEMPTY’ can be used to test whether an argument
expands to a non-empty string. A more elaborate example follows below. Say
you want to define a `bookref’ macro to typeset information about
an author, a book title and about the publisher. The publisher information
may be absent, the macro then typesets `unknown’:
\
DEFINEMACRO(bookref)(3)(\
Author(s): ARG1
Title: ARG2
Published by: \
IFEMPTY(ARG3)
(\
Unknown\
)(\
ARG3\
)
)
Using the macro, as in:
\
bookref(Helmut Leonhardt)
(Histologie, Zytologie und Microanatomie des Menschen)
()
would now result in the text `Unknown’ behind the `Published
by:’ line.
- Please note the preferred layout: The first argument immediately follows
the function name, then the second argument (the true list) is
indented, as is the false list. The layout closely follows the
preferred layout of `if-else’ statements of many programming
languages.
- `IFEQUAL’
- `IFEQUAL’ expects four argument lists. It tests whether its first
argument is equal to its second argument. If so, the third argument is
evaluated, else, the fourth argument is evaluated. All four argument lists
must be present, though all can be empty.
- The first two arguments of `IFEQUAL’ should be integral numeric
arguments. In order to determine whether the first two arguments are
equal, their values are determined:
- o
- If the argument starts with an integral numerical value, that value is the
value of the argument.
- o
- If the argument is the name of a counter, the counter’s value is
the value of the argument
- o
- If the values of the first two arguments van be determined accordingly,
their equality determines whether the true list (when the values are
equal) or the false list (when the values are unequal) will be
evaluated.
- o
- Otherwise, `IFEQUAL’ evaluates the false list.
- Example:
IFEQUAL(0)()(\
0 and an empty string are equal
)(\
0 and an empty string are not equal
)
Please note the preferred layout: The first argument immediately follows the
function name, then the second argument (the true list) is
indented, as is the false list. The layout closely follows the
preferred layout of `if-else’ statements of many programming
languages.
- `IFGREATER’
- `IFGREATER’ expects four argument lists. It tests whether its first
argument is greater than its second argument. If so, the third parameter
list is evaluated, otherwise its fourth argument is evaluated. All four
argument lists must be present, though all can be empty.
- The first two arguments of `IFGREATER’ should be integral numeric
arguments. In order to determine whether the first two arguments are
equal, their values are determined:
- o
- If the argument starts with an integral numerical value, that value is the
value of the argument.
- o
- If the argument is the name of a counter, the counter’s value is
the value of the argument
- o
- If the values of the first two arguments van be determined accordingly,
their order relation determines whether the true list (when the first
value is greater than the second value) or the false list (when the first
value is smaller or equal than the second value) is evaluated.
- o
- Otherwise, `IFGREATER’ evaluates the false list.
- Example:
IFGREATER(counter)(5)(\
counter exceeds the value 5
)(\
counter does not exceeds the value 5, or counter is no Yodl-counter.
)
Please note the preferred layout: The first argument immediately follows the
function name, then the second argument (the true list) is
indented, as is the false list. The layout closely follows the
preferred layout of `if-else’ statements of many programming
languages.
- `IFMACRO’
- The `IFMACRO’ function tests whether its first argument is the name
of a macro. If the name is the name of a macro, the second argument is
evaluated, else, the third argument is evaluated. All three arguments (the
name, the true list and the false list) must be present; though the true
list and/or the false list may be empty.
- Example:
IFMACRO(nested)(\
`nested’ is the name of a macro
)(\
There is no macro named `nested’
)
Please note the preferred layout: The first argument immediately follows the
function name, then the second argument (the true list) is
indented, as is the false list. The layout closely follows the
preferred layout of `if-else’ statements of many programming
languages.
- `IFSMALLER’
- `IFSMALLER’ expects four argument lists. It tests whether its first
argument is smaller than its second argument. If so, the third parameter
list is evaluated, otherwise its fourth argument is evaluated. All four
argument lists must be present, though all can be empty.
- The first two arguments of `IFSMALLER’ should be integral numeric
arguments. In order to determine whether the first two arguments are
equal, their values are determined:
- o
- If the argument starts with an integral numerical value, that value is the
value of the argument.
- o
- If the argument is the name of a counter, the counter’s value is
the value of the argument
- o
- If the values of the first two arguments van be determined accordingly,
their order relation determines whether the true list (when the first
value is smaller than the second value) or the false list (when the first
value is greater than or equal to the second value) is evaluated.
- o
- Otherwise, `IFSMALLER’ evaluates the false list.
- Example:
IFSMALLER(counter)(5)(\
counter is smaller than the value 5, or counter is no Yodl-counter
)(\
counter exceeds the value 5
)
Please note the preferred layout: The first argument immediately follows the
function name, then the second argument (the true list) is
indented, as is the false list. The layout closely follows the
preferred layout of `if-else’ statements of many programming
languages.
- `IFSTREQUAL’
- `IFSTREQUAL’ tests for the equality of two strings. It expects four
arguments: two strings to match, a true list and a false list. The true
list is only evaluated when the contents of the two string arguments
exactly match.
- The first two arguments of `IFSTREQUAL’ are partially
evaluated:
- o
- If the argument is the name of a symbol, the symbol’s value is the
value of the argument
- o
- Otherwise, the argument itself is used.
- In the degenerate case where the string to be compared is actually the
name of a `SYMBOL’, use a temporary `SYMBOL’ variable
containing the name of that symbol, and compare it to whatever you want to
compare it with. Alternatively, write a blank space behind the arguments,
since the arguments are then interpreted `as is’. In practice, the
need for these constructions seem to arise seldom, however.
- Example:
IFSTREQUAL(MYSYMBOL)(Hello world)(
The symbol `MYSYMBOL’ holds the value `Hello world’
)(
The symbol `MYSYMBOL’ doesn’t hold the value `Hello world’
)
- `IFSTRSUB’
- `IFSTRSUB’ tests whether a string is a sub-string of another
string. It acts similar to IFSTREQUAL, but it tests whether the second
string is part of the first one.
- The first two arguments of `IFSTREQULA’ are partially
evaluated:
- o
- If the argument is the name of a symbol, the symbol’s value is the
value of the argument
- o
- Otherwise, the argument itself is used.
- In the degenerate case where the string to be compared is actually the
name of a `SYMBOL’, use a temporary `SYMBOL’ variable
containing the name of that symbol, and compare it to whatever you want to
compare it with. Alternatively, write a blank space behind the arguments,
since the arguments are then interpreted `as is’. In practice, the
need for these constructions seem to arise seldom, however.
- Example:
IFSTRSUB(haystack)(needle)(
`needle’ was found in `haystack’
)(
`needle’ was not found in `haystack’
)
Note that both `haystack’ and `needle’ may be the names of
symbols. If they are, their contents are is compared, rather than the
literal names `haystack’ and `needle’
- `IFSYMBOL’
- The `IFSYMBOL’ function tests whether its first argument is the
name of a symbol. If it is the name of a symbol, the second argument is
evaluated, otherwise the third argument is evaluated. All three arguments
(the name, the true list and the false list) must be present; though the
true list and/or the false list may be empty.
- Example:
IFSYMBOL(nested)(\
`nested’ is the name of a symbol
)(\
There is no symbol named `nested’
)
Please note the preferred layout: The first argument immediately follows the
function name, then the second argument (the true list) is
indented, as is the false list. The layout closely follows the
preferred layout of `if-else’ statements of many programming
languages.
- C( FBB consider additive expressions )
- `IFZERO’
- `IFZERO’ expects three arguments. If the first argument is zero (0)
the function expands to the true list (the second argument). Otherwise it
expands to the false list (the third argument).
- The first argument of `IFZERO’ should be an integral numeric value.
Its value is determined as follows:
- o
- If the argument starts with an integral numerical value, that value is the
value of the argument.
- o
- If the argument is the name of a counter, the counter’s value is
the value of the argument
- o
- Otherwise, the first arguments evaluates as 0, and the false list is used.
- Note that, starting with Yodl version 2.00 the first argument is not
evaluated. So `COUNTERVALUE(somecounter)’ always evaluates as 0. If
the value of a counter is required, simply provide its name as the first
argument of the `IFZERO’ function.
- Example:
DEFINEMACRO(environment)(2)(\
IFZERO(ARG2)(\
NOEXPAND(\end{ARG1})\
)(\
NOEXPAND(\begin{ARG1})\
)\
)
Such a macro may be used as follows:
environment(center)(1)
Now comes centered text.
environment(center)(0)
which would of course lead to `\begin’ and `\end{center}’. The
numeric second argument is used here as a on/off switch.
- `INCLUDEFILE’
- `INCLUDEFILE’ takes one argument, a filename. The file is processed
by Yodl. If a file should be inserted without processing the builtin
function NOEXPANDINCLUDE `[NOEXPANDINCLUDE]’ or NOEXPANDPATHINCLUDE
`[NOEXPANDPATHINCLUDE]’ should be used.
- The `yodl’ program supplies, when necessary, an extension to the
filename. The supplied extension is `.yo’, unless defined otherwise
during the compilation of the program.
- Furthermore, Yodl tries to locate the file in the Yodl’s include
path (which may be set using the `--include’ option). The actual
value of the include path is shown in the usage information, displayed
when Yodl is started without arguments.
- Example:
INCLUDEFILE(latex)
Here, Yodl attempts to include the file `latex’ or `latex.yo’
from the current include path. When the file is not found, Yodl
aborts.
- `INCWSLEVEL’
- `INCWSLEVEL’ requires one (empty) argument.
- It increments the current white-space level. The white-space level
typically is used in files that only define Yodl macros. When no output
should be generated while processing these files, the white-space level
can be used to check for this. If the white-space level exceeds zero, a
warning is generated if the file produces non-whitespace output. The
builtin function `DECWSLEVEL’ is used to decrement the whitespace
level following a previous `INCWSLEVEL’ call.
- Once the white space level exceeds zero, no output is generated. White
space, therefore is effectively ignored. The white space level cannot be
reduced to negative values. A warning is issued if that would have
happened if it were allowed.
- Example:
INCWSLEVEL()
DEFINESYMBOL(....)
DEFINEMACRO(...)(...)(...)
DECWSLEVEL()
Without the `INCWSLEVEL’ and `DECWSLEVEL’, calls, the above
definition would generate four empty lines to the output stream.
- The `INCWSLEVEL’ and `DECWSLEVEL’ calls may be nested. The
best approach is to put an `INCWSLEVEL’ at the first line of a
macro-defining Yodl-file, and a matching `DECWSLEVEL’ call at the
very last line.
- `INTERNALINDEX’
- `INTERNALINDEX’ expects one argument list. The argument list is
evaluated and written to the index file.
- The index file is defined since Yodl version 2.00, and contains the fixup
information which was previously written to Yodl’s output as the
`.YODLTAGSTART. ... .YODLTAGEND.’ sequence.
- The index file allows for greater processing speed, at the expense of an
additional file. The associated `yodlpost’ postprocessing program
reads and processes the index file, and modifies the corresponding
yodl-output accordingly.
- The index file is not created when output is written to the standard
output name, since Yodl is unable to request the system for the current
file offset.
- The entries of the index file always fit on one line.
`INTERNALINDEX’ changes newline characters in its argument into
single blank spaces. Each line starts with the current offset of
Yodl’s output file, thus indicating the exact location where a
fixup is requested. An example of a produced fixup line could be
3004 ref MACROPACKAGE
indicating that at offset 3004 in the produced output file a reference to
the label `MACROPACKAGE’ is requested. Assuming a html conversion,
The postprocessor thereupon writes something like
<a href="outfile04.html#MACROPACKAGE">4.3.2.</a>
into the actual output file while processing Yodl’s output up to
offset location 3004.
- Consequently, producing Yodl-output normally consists of two steps:
- o
- First, Yodl itself is started, producing, e.g., `out.idx’ (the
index file) and `out.yodl’ (Yodl’s raw output).
- o
- Then, Yodl’s post-processor processes `out.idx’ and
`out.yodl’, producing one or more final output files, in which the
elements of the index file have been properly handled. This may result in
multiple output file, like `report.html, report01.html,
report02.html’ etc.
- `NOEXPAND’
- `NOEXPAND’ is used to send text to the final output file without
being expanded by Yodl (the other methods are the `CHAR’ macro, see
section `[CHAR]’, and the `NOTRANS’ macro, see section
`[NOTRANS]’). `NOEXPAND’ takes one argument, the text in
question. Whatever occurs in the argument is not subject to parsing or
expansion by Yodl, but is simply copied to the output file (except for
`CHAR’ and (iinternally used) `XXSUBST’ functions in the
argument, which are expanded. If `CHAR’-expansion is not
required either NOTRANS `[NOTRANS]’ can be used).
- Furthermore, the contents of the argument are also subject to character
table translations, using the currently active table. This should come as
no surprise. Ignoring character tables would make both the processing of
`CHAR’ calls and the `NOTRANS’ function superfluous.
- So, the following situations are recognized:
|
support chartables |
|
and CHAR |
Macro expansion |
yes |
no |
Yes |
(standard) |
Push chartable |
|
|
(standard) |
|
|
Pop chartable |
No |
NOEXPAND |
NOTRANS |
E.g., let’s assume that you need to write in your document the
following text:
INCLUDEFILE(something or the other)
IFDEF(onething)(
...
)(
....
)
NOEXPAND(whatever)
- The way to accomplish this is by prefixing the text by `NOEXPAND’
followed by an open parenthesis, and by postfixing it by a closing
parenthesis. Otherwise, the text would be expanded by Yodl while
processing it (and would lead to syntax errors, since the text
isn’t correct in the sense of the Yodl language).
- For this function, keep the following caveats in mind:
- o
- There is only one thing that a `NOEXPAND’ cannot protect from
expansion: an `ARG’x in a macro definition. The argument
specifier is always processed. E.g., after
DEFINEMACRO(thatsit)(1)(
That is --> NOEXPAND(ARG1) <-- it!
)
thatsit(after all)
the `ARG1’ inside the `NOEXPAND’ statement is replaced with
`after all’.
- o
- The `NOEXPAND’ function must, as all functions, be followed by a
argument. The parentheses of the list must therefore be `balanced’.
For unbalanced lists, use `CHAR(40)’ to set an open parenthesis, or
`CHAR(41)’ to typeset a closing parenthesis.
- `NOEXPANDINCLUDE’
- `NOEXPANDINCLUDE’ takes one argument, a filename. The file is
included.
- The filename is uses as specified. The include path is not used when
locating this file.
- The argument to `NOEXPANDINCLUDE’ is partially evaluated:
- o
- If the argument is the name of a symbol, the symbol’s value is the
value of the argument
- o
- Otherwise, the argument itself is used. The thus obtained file name is not
further evaluated: in particular, it is not affected by available
character translations.
- The contents of the file are included literally, not subject to macro
expansion. Character translations are performed, though. If character
translations are not appropriate, PUSHCHARTABLE can be used to suppress
character table translations temporarily.
- The purpose of NOEXPANDINCLUDE is to include source code literally in the
document, as in:
NOEXPANDINCLUDE(literal.c)
The function NOEXPANDPATHINCLUDE can be used to insert a file which
is located in one of the directories specified in Yodl’s
include path.
- `NOEXPANDPATHINCLUDE’
- `NOEXPANDPATHINCLUDE’ takes one argument, a filename. The file is
included. The file is searched for in the directories specified in
Yodl’s includepath.
- The argument to `NOEXPANDPATHINCLUDE’ is partially evaluated:
- o
- If the argument is the name of a symbol, the symbol’s value is the
value of the argument
- o
- Otherwise, the argument itself is used. The thus obtained file name is not
further evaluated: in particular, it is not affected by available
character translations.
- Like the `NOEXPANDINCLUDE’ function, the contents of the file are
included literally, not subject to macro expansion. Character translations
are performed, though. If character translations are not appropriate,
PUSHCHARTABLE `[PUSHCHARTABLE]’ can be used to suppress character
table translations temporarily.
- The purpose of NOEXPANDPATHINCLUDE is to include source code as defined in
a macro package literally into the document, as in:
NOEXPANDPATHINCLUDE(rug-menubegin.xml)
- `NOTRANS’
- `NOTRANS’ copies its one argument literally to the output file,
without expanding macros in it and without translating the characters with
the current translation table. The `NOTRANS’ function is typically
used to send commands for the output format to the output file.
- For example, consider the following code fragment:
COMMENT(--- Define character translations for \, { and } in LaTeX. ---)
DEFINECHARTABLE(standard)(
’\\’ = "$\\backslash$"
’{’ = "\\verb+{+"
’}’ = "\\verb+}+"
)
COMMENT(--- Activate the translation table. ---)
USECHARTABLE(standard)
COMMENT(--- Now two tests: ---)
NOEXPAND(\input{epsf.tex})
NOTRANS(\input{epsf.tex})
`NOEXPAND’ sends
$\backslash$input\verb+{+epsf.tex\verb+}+
since the characters in its argument are translated with the
`standard’ translation table. In contrast, `NOTRANS’ sends
`\input{epsf.tex}’.
- The argument of `NOTRANS’ must be balanced with respect to
its parentheses. When using an unbalanced set of parentheses, use
`CHAR(40)’ to send a literal (, or `CHAR(41)’ to send a
`)’.
- While converting Yodl-documents to target document types Yodl frequently
uses the (not further documented) builtin function `XXSUBST’. In
the unlikely event that the text `XXSUBST(...)’ must be written in
a document, the sequence
XXSUBST+CHAR(40)...CHAR(41)
can be used.
- The NOEXPAND description summarizes all combinations of character
translations and/or macro expansion, and how they are handled and realized
by Yodl.
- `NOUSERMACRO’
- `NOUSERMACRO’ controls `yodl’’s warnings in the
following way: When Yodl is started with the `-w’ flag on the
command line, warnings are generated when Yodl encounters a possible macro
name, i.e., a name that is followed by a parenthesized argument, while no
macro by that name has been defined. Yodl then prints something like
`cannot expand possible user macro’.
- Examples of such sequences are, `The necessary file(s) are in
/usr/local/lib/yodl’, or `see the manual page for sed(1)’.
The candidate macros are `file’ and `sed’; these names could
just as well be `valid’ user macros followed by their
argument.
- When a corresponding `NOUSERMACRO’ statement appears before
`yodl’ encounters the candidate macros, no warning is generated. A
fragment might therefore be:
NOUSERMACRO(file sed)
The necessary file(s) are in ...
See the manual page for sed(1).
The `NOUSERMACRO’ accepts one or more names in its argument,
separated by white space, commas, colons, or semi-colons.
- `OUTBASE’
- `OUTBASE’ inserts the current basename of the output file into the
output file. The basename is the name of the file of which the directory
components and extension were stripped.
- If the output file is the standard output file, `-’ is
inserted.
- `OUTDIR’
- `OUTDIR’ inserts the current path name of the output file into the
output file. The path name is a, not necessarily absolute, designator of
the directory in which the output file is located. If the output file is
indicated as, e.g., `-o out’, then `OUTDIR’ simply inserts a
dot.
- If the output file is the standard output file, a dot is inserted
too.
- `OUTFILENAME’
- `OUTFILENAME’ inserts the current filename of the output file into
the output file. The filename is the name of the file of which the
directory components were stripped.
- If the output file is the standard output file, `-’ is
inserted.
- `PARAGRAPH’
- `PARAGRAPH’ isn’t really a builtin function, but as Yodl
handles paragraphs in a special way it is probably useful to describe
paragraph handling here nonetheless. Starting with Yodl 2.00
`PARAGRAPH’ operates as follows:
- If the macro is not defined, new paragraphs, defined as series of
consecutive empty lines written to the output stream, are not handled
different from any other series of characters sent to the output stream.
I.e., they are inserted into that stream.
- However, if the macro has been defined, Yodl calls it whenever a new
paragraph (defined as a series of at least two blank lines) has been
recognized.
- The empty lines that were actually recognized may be obtained inside the
`PARAGRAPH’ macro from the `XXparagraph’ symbol, if
this symbol has been be defined by that time. If defined, it contains the
white space that caused Yodl to call the `PARAGRAPH’ macro.
- Note that, in order to inspect `XXparagraph’ it must have been
defined first. Yodl itself does not define this symbol itself.
- The `PARAGRAPH’ macro should be defined as a macro not expecting
arguments. The macro is thus given a chance to process the paragraph in a
way that’s fitting for the particular conversion type. If the
`PARAGRAPH’ macro produces series of empty lines itself, then those
empty lines do not cause Yodl to activate `PARAGRAPH’. So,
Yodl itself will not recursively call `PARAGRAPH’, although the
macro could call itself recursively. Of course, such recursive activcation
of `PARAGRAPH’ is then the sole responsibility of the
macro’s author, and not Yodl’s.
- Some document languages do not need paragraph starts; e.g., LaTeX handles
its own paragraphs. Other document languages do need it: typically,
`PARAGRAPH’ is then defined in a macro file to trigger some special
action. E.g., a HTML converter might define a paragraph as:
DEFINEMACRO(PARAGRAPH)(0)(
XXnl()
NOTRANS(<p>)
)
A system like `xml’ has more strict requirements. Paragraphs here
must be opened and closed using pairs of `<p>’ and
`</p>’ tags. In those cases an auxiliary counter can be used
to indicate whether there is an open paragraph or not. The
`PARAGRAPH’ macro could check for this as follows, assuming the
availability of a counter `XXp’:
DEFINEMACRO(PARAGRAPH)(0)(
XXnl()
IFZERO(XXp)(
)(
NOTRANS(</p>)
)
NOTRANS(<p>)
SETCOUNTER(XXp)(1)
)
Note that the above fragment exemplifies an approach, not necessarily
the implementation of the `PARAGRAPH’ macro for an
xml-converter.
- `PIPETHROUGH’
- The builtin function `PIPETHROUGH’ is, besides `SYSTEM’, the
second function with which a Yodl document can affect its environment.
`PIPETHROUGH’ can be very useful. It uses an external program to
accomplish special features. The idea is that an external command is
started, to which a block of text from within a Yodl document is
`piped’. The output of that child program is piped back into the
Yodl document; hence, a block of text is `piped through’ an
external program. Whatever is received again in the Yodl run, is further
processed.
- The `PIPETHROUGH’ function takes two arguments:
- o
- the command to run, and
- o
- the text to send to that command.
- Functionally, the occurrence of the `PIPETHROUGH’ function and of
its two arguments is replaced by whatever the child program produces on
its standard output.
- An example might be the inclusion of the current date, as in:
-
The current date is:
PIPETHROUGH(date)()
- In this example the command is `date’ and the text to send to that
program is empty.
- The main purpose of this function is to provide a way by which external
programs can be used to create, e.g., tables or figures for a given output
format. Further releases of Yodl may contain such dedicated programs for
the output formats.
- `POPCHARTABLE’
- Character tables which are pushed onto the table stack using
`PUSHCHARTABLE()’ are restored (popped) using
`POPCHARTABLE()’. For a description of this mechanism please refer
to section `[PUSHINGTABLES]’.
- `POPCOUNTER’
- `POPCOUNTER’ is used to remove the topmost counter from the counter
stack. The values of counters may be pushed on a stack using PUSHCOUNTER
`[PUSHCOUNTER]’. To remove the topmost element of a
counter’s stack `POPCOUNTER’ is available.
`POPCOUNTER’ expects one argument: the name of the counter to pop.
The previously pushed value then becomes the new value of the counter. A
counter’s value may be popped after defining it, whereafter the
stack is empty, but the counter will still be defined. In that case, using
the counter’s value is considered an error.
- Examples:
DEFINECOUNTER(YEAR)(1950)
POPCOUNTER(YEAR)
COMMENT(YEAR now has an undefined value)
See also section `[COUNTERS]’.
- `POPMACRO’
- `POPMACRO’ is used to remove the actual macro definition, restoring
a previously pushed definition. The values of macros may be pushed on a
stack using PUSHMACRO.
- To remove the topmost element of a macro’s stack `POPMACRO’
is available. `POPMACRO’ expects one argument: the name of the
macro to pop. The previously pushed value then becomes the new value of
the macro.
- A macro’s value may be popped after defining it, after which its
stack is empty. In that case, using the macro (although the macro’s
name is still defined) is considered an error.
- Example:
DEFINEMACRO(Hello)(1)(Hello, ARG1, this is a macro definition)
Hello(Karel)
PUSHMACRO(Hello)(1)(Hello, ARG1, this is the new definition)
Hello(Karel)
POPMACRO(Hello)
Hello(Karel)
COMMENT(The third activation of Hello() produces the same output
as the first activation)
- `POPSUBST’
- `POPSUBST’ is used to revert to a previous level of interpretation
of `SUBST’ definitions. Refer to the descriptions of the
`PUSHSUBST’ and `SUBST’ builtin commands below for
details.
- There is no limit to the number of times `POPSUBST’ can be called.
Once the ``PUSHSUBST’ stack’ is empty `SUBST’
definitions are automatically interpreted (so no stack-underflow error is
ever encountered).
- `POPSYMBOL’
- `POPSYMBOL’ is used to remove the topmost symbol from the symbol
stack. The values of symbols may be pushed on a stack using PUSHSYMBOL
`[PUSHSYMBOL]’. To remove the topmost element of a symbol’s
stack `POPSYMBOL’ is available.
- `POPSYMBOL’ expects one argument: the name of the symbol to pop.
The previously pushed value then becomes the new value of the symbol.
- A symbol’s value may be popped after defining it, after which its
stack is empty. In that case, using the symbol (although the
symbol’s name is still defined) is considered an error.
- Example:
DEFINESYMBOL(YEAR)(This happened in 1950)
POPSYMBOL(YEAR)
COMMENT(YEAR now has an undefined value)
- `POPWSLEVEL’
- `POPWSLEVEL’ is used to remove the topmost wslevel from the wslevel
stack. The values of wslevels may be pushed on a stack using PUSHWSLEVEL
`[PUSHWSLEVEL]’. See also section DECWSLEVEL
`[DECWSLEVEL]’
- To remove the topmost element of a wslevel’s stack
`POPWSLEVEL’ is available. `POPWSLEVEL’ expects one
argument: the name of the wslevel to pop. The previously pushed value then
becomes the new value of the wslevel. A wslevel’s value may be
popped after defining it, emptying the stack, but the wslevel will still
be defined. In that case, using the wslevel’s value is considered
an error.
- Example:
COMMENT(Assume WS level is zero)
PUSHWSLEVEL(1)
COMMENT(WS level now equals 1)
POPWSLEVEL()
COMMENT(WS level now equals 0 again)
- `PUSHCHARTABLE’
- Once a character table has been defined, it can be pushed onto a
stack using `PUSHCHARTABLE’. The pushed chartable may be
popped later. `PUSHCHARTABLE’ is described in more detail in
section `[PUSHINGTABLES]’.
- `PUSHCOUNTER’
- `PUSHCOUNTER’ is used to start another lifetime for a counter,
pushing its current value on a stack. A stack is available for each
individual counter.
- `PUSHCOUNTER’ expects two arguments: the name of the counter to
push and an additive expression whose value becomes the counter’s
new value (after pushing the current value)
- The additive expression may not contain blank spaces and may use + and -
operators, its operands may either be integral numeric values or names of
(defined) counters. The resulting value can be negative; in that case, a
value is subtracted from the destination counter.
- When the second argument is empty, then the new value will be zero.
Specify the name of the counter twice to merely push its value, without
modifying its current value.
- Examples:
DEFINECOUNTER(YEAR)(1950)
PUSHCOUNTER(YEAR)(1962)
COMMENT(YEAR now has the value 1962, and a pushed value of 1950)
See also section `[COUNTERS]’.
- `PUSHMACRO’
- `PUSHMACRO’ is used to start another lifetime for a macro, pushing
its current definition on a stack. A stack is available for each
individual macro.
- `PUSHMACRO’ expects three arguments: the name of the macro to push,
the number of its arguments after pushing (which may be different from the
number of arguments interpreted by the pushed macro) and its new
definition.
- So, `PUSHMACRO’ is used exactly like DEFINEMACRO, but redefines a
current macro (or define a new macro if no macro was defined by the name
specified as its first argument.
- Example:
DEFINEMACRO(Hello)(1)(Hello, ARG1, this is a macro definition)
Hello(Karel)
PUSHMACRO(Hello)(1)(Hello, ARG1, this is the new definition)
Hello(Karel)
POPMACRO(Hello)
Hello(Karel)
COMMENT(The third activation of Hello() produces the same output
as the first activation)
- `PUSHSUBST’
- `PUSHSUBST’ can be used to (temporarily) suppress the
interpretation of `SUBST’ definitions (the `SUBST’ built-in
command is covered below, refer to its description for an example).
- `PUSHSUBST’ expects one argument: an integral number which is
either 0 or non-zero (commonly: 1). After calling
`PUSHSUBST’`(0)’ `SUBST’ definitions are not
interpreted anymore; use `POPSUBST’`()’ to revert to the
previous type of interpretation. Alternatively,
`PUSHSUBST’`(0)’ can be used to stack another level of
`SUBST’ interpretations on top of the last-used one.
- On a 64-bit computer the `PUSHSUBST’ stack can hold slightly more
than 60 `SUBST’ interpretation levels. When more levels are pushed,
the oldest levels are silently forgotten. Calling `POPSUBST’ once
the `PUSHSUBST’ stack is empty results in activating the
`SUBST’ interpretations (and so a stack-underflow error will not be
encountered).
- `PUSHSYMBOL’
- `PUSHSYMBOL’ is used to start another lifetime for a symbol,
pushing its current value on a stack. A stack is available for each
individual symbol.
- `PUSHSYMBOL’ expects two arguments: the name of the symbol to push
and its new text after pushing. When the second argument is an empty
argument, the new text will be empty. The new text may be specified as a
literal text, or as the name of an existing symbol. Specify the name of
the symbol twice to merely push its value, without modifying its current
value.
- Examples:
DEFINESYMBOL(YEAR)(This happened in 1950)
PUSHSYMBOL(YEAR)(This happened in 1962)
COMMENT(YEAR now has the value `This happened in 1962’ and a
pushed value of `This happened in 1950’)
- `PUSHWSLEVEL’
- `PUSHWSLEVEL’ is used to start another lifetime of the white-space
level pushing the level’s current value on a stack. See also
section INCWSLEVEL `[INCWSLEVEL]’
- `PUSHWSLEVEL’ expects one argument, the new value of the
white-space level. This value may be specified as a numerical value or as
the name of a counter. The argument may be empty, in which case the new
value will be zero.
- Example:
COMMENT(Assume WS level is zero)
PUSHWSLEVEL(1)
COMMENT(WS level now equals 1)
POPWSLEVEL()
COMMENT(WS level now equals 0 again)
- `RENAMEMACRO’
- `RENAMEMACRO’ takes two arguments: the name of a built-in macro
(such as `INCLUDEFILE’) and its new name.
- E.g., after
RENAMEMACRO(INCLUDEFILE)(include)
- a file must be included by `include(file)’.
`INCLUDEFILE’ can no longer be used for this: following the
`RENAMEMACRO’ action, the old name can no longer be used; it
becomes an undefined symbol.
- If you want to make an alias for a built-in command, do it with
`DEFINEMACRO’. E.g., after:
DEFINEMACRO(include)(1)(INCLUDEFILE(ARG1))
both `INCLUDEFILE’ and `include’ can be used to include a
file.
- `SETCOUNTER’
- `SETCOUNTER’ expects two arguments: the name of a counter, and an
additive expression defining the value to assign. The counter must be
previously created with `DEFINECOUNTER’.
- The additive expression may not contain blank spaces and may use + and -
operators, its operands may either be integral numeric values or names of
(defined) counters. The resulting value can be negative; in that case, a
negative value is assigned to the destination counter.
- For example, if `one’ and `two’ are counters, then
SETTOCOUNTER(one)(-two)\// assigns -two’s value to one
SETTOCOUNTER(one)(two+two)\// assigns 2 x two’s value to one
- See also section `[COUNTERS]’.
- `SETSYMBOL’
- `SETSYMBOL’ expects two arguments: the name of a symbol, and the
text to assign to the named symbol. The symbol must previously have been
defined by `DEFINESYMBOL’.
- `SUBST’
- `SUBST’ is a general-purpose substitution mechanism for strings
appearing in the input. `SUBST’ takes two arguments: a search
string and a substitution string. E.g., after
SUBST(VERSION)(1.00)
YODL transforms all occurrences of `VERSION’ in its input into
`1.00’.
- `SUBST’ is also useful in situations where multi-character
sequences should be converted to accented characters. E.g., a LaTeX
converter might define:
SUBST(’e)(+NOTRANS(\’{e}))
Each `’e’ in the input will subsequently be converted to
`e’.
- `SUBST’ may be used in combination with the command line flag
`-P’, as in a invocation
yodl2html -P’SUBST(VERSION)(1.00)’ myfile.yo
- Another useful substitution might be:
SUBST(_OP_)(CHAR(40))
SUBST(_CP_)(CHAR(41))
- which defines an opening parenthesis (`_OP_’) and a closing
parenthesis (`_CP_’) as mapped to the `CHAR’ function. The
strings `_OP_’ and `_CP_’ might then be used to produce
unbalanced arguments.
- Note that:
- o
- The first argument of the `SUBST’ command, the search string, is
taken literally. Yodl does not expand it; the string must be literally
matched in the input.
- o
- The second argument, the replacement, is further processed by Yodl.
Protect this text by `NOTRANS’ or `NOEXPAND’ where
appropriate.
- Substitutions occur extremely early while YODL processes its input files.
In order to process its input files, YODL takes the following steps:
- 1.
- It requests input from its lexical scanner (so-called tokens)
- 2.
- Its parser processes the tokens produced by the lexical scanner
- 3.
- Its parser may send text to an output `object’, which eventually
appears in the output file generated by YODL. YODL performs all macro
substitutions in step 2, and all character table conversions in step 3.
However, the lexical scanner has access to the `SUBST’ definitions:
as soon as its lexical analyzer detects a series of characters matching
the defining sequence of a `SUBST’ definition, it replaces that
defining sequence by its definition. That definition is then again read by
the lexical scanner. Of course, this definition may, in turn, contain
defining sequences of other `SUBST’ definitions: these are then
replaced by their definitions as well. This implies:
- o
- Circular definitions may cause the lexical scanner to get stuck in a
replacement loop. It is the responsibility of the author defining
`SUBST’ definitions to make sure that this doesn’t
happen.
- o
- Neither the parser, nor the output object ever sees the `SUBST’
defining character sequences: they only see their definitions.
- In some cases substitutions must be suppressed. Consider double quoted
text strings that are frequently used in programming languages. E.g.,
`"hello world"’. The text inside the string should not be
converted by Yodl, but unless substitutions can be suppressed the string
"\"evil code"
appears as
"evil code"
To suppress the interpretation of `SUBST’ definitions
`PUSHSUBST’, introduced earlier, can be used. The predefined macro
`verb’ suppresses the interpretation of `SUBST’ definitions
by starting with `PUSHSUBST’`(0)’ and ending with
`POPSUBST’`()’.
- `SYMBOLVALUE’
- `SYMBOLVALUE’ expands to the value of a symbol. Its single argument
must be the name of a symbol. The symbol must have been created earlier
using `DEFINESYMBOL’.
Example:
The symbol has value SYMBOLVALUE(MYSYMBOL).
- `SYSTEM’
- `SYSTEM’ takes one argument: a command to execute. The command is
run via the standard C function `system’.
- `SYSTEM’ can be useful in many ways. E.g., you might want to log
when someone processes your document, as in:
SYSTEM(echo Document processed! | mail myself@my.host)
Note that `SYSTEM’ merely performs an system-related task.
It’s a process that is separated from the YODL process itself. One
of the consequences of this is that any output generated by
`SYSTEM’ not normally appears into YODL’s output file. If
the output of a subprocess should be inserted into YODL’s output
file, either use PIPETHROUGH `[PIPETHROUGH]’, or insert a temporary
file as shown in the following example:
SYSTEM(date > datefile)
The current date is:
INCLUDEFILE(datefile)
SYSTEM(rm datefile)
- `TYPEOUT’
- `TYPEOUT’ requires one argument. The text of the list is sent to
the standard error stream, followed by a newline. This feature can be
handy to show, e.g., messages such as version numbers in macro package
files.
- Example: The following macro includes a file and writes to the screen that
this file is currently processed.
DEFINEMACRO(includefile)(1)(
TYPEOUT(About to process document: ARG1)
INCLUDEFILE(ARG1)
)
- `UPPERCASE’
- `UPPERCASE’ converts a string or a part of it to upper case. It has
two arguments:
- o
- The string to convert;
- o
- A length, indicating how many characters (starting from the beginning of
the string) should be converted. The length indicator can be smaller than
one or larger than the length of the string; in that case, the whole
string is convertered.
- Example:
UPPERCASE(hello world)(1)
UPPERCASE(hello world)(5)
UPPERCASE(hello world)(0)
This code sample expands to:
Hello world
HELLO world
HELLO WORLD
- `USECHARTABLE’
- `USECHARTABLE’ takes one argument: the name of a translation table
to activate. The table must previously have been defined using
`DEFINECHARTABLE’. See section `[CHARTABLES]’ for a
description of character translation tables.
- Alternatively, the name may be empty in which case the default character
mapping is restored.
- `USECOUNTER’
- `USECOUNTER’ is a combination of `ADDTOCOUNTER’ and
`COUNTERVALUE’. It expects one argument: the name of an defined
counter (see DEFINECOUNTER `[DEFINECOUNTER]’).
- The counter is first incremented by 1. Then the function expands to the
counter’s value.
- See also section `[COUNTERS]’.
- `VERBOSITY’
- `VERBOSITY’ expects two arguments, and may be used to change the
verbosity level inside YODL files. The function may be used profitably for
debugging purposes, to debug the expansion of a macro or the processing of
a YODL input file.
- The first argument indicates the processing mode of the second argument,
and it may be:
- o
- Empty, in which case the message-level is set to the value specified in
the second argument;
- o
- `+’, in which case the value specified in the second argument
augments the current message level;
- o
- `-’, in which case the value specified in the second argument
augments is removed from the current message level
- The second argument specifies one or more, separated by blanks, message
level names or it may be set to a hexadecimal value (starting with
`0x’), using hexadecimal values to represent message levels. Also,
`NONE’ may be used, to specify no message level, or `ALL’
can be used to specify all message levels.
- The following message levels are defined:
- o
- ALERT (0x40). When an alert-error occurs, Yodl terminates. Here Yodl
requests something of the system (like a `get_cwd()’), but the
system fails.
- o
- CRITICAL (0x20). When a critical error occurs, Yodl terminates. The
message itself can be suppressed, but exiting can’t. A critical
condition is, e.g., the omission of an open parenthesis at a location
where a parenthesized argument should appear, or a non-existing file in an
`INCLUDEFILE’ specification (as this file should be parsed). A
non-existing file with a `NOEXPANDINCLUDE’ specification is a plain
(non-critical) error.
- o
- DEBUG (0x01). Probably too much info, like getting information about each
character that was read by Yodl.
- o
- ERROR (0x10). An error (like doubly defined symbols). Error messages will
not stop the parsing of the input (up to a maximum number of errors), but
no output is generated.
- o
- INFO (0x02). Not as detailed as `debug’, but still very much info,
like information about media switches.
- o
- NOTICE (0x04). Information about, e.g., calls to the builtin function
calls.
- o
- WARNING (0x08). Something you should know about, but probably not
affecting Yodl’s proper functioning
- There also exists a level EMERG (0x80) which cannot be suppressed.
- The value `0x00’ represents `NONE’, the value `0xff’
represents `ALL’.
- When specifying multiple message levels using the hexadecimal form, their
hexadecimal values should be binary-or-ed: adding them is ok, as long as
you don’t specify `ALL’:
VERBOSITY()(0x06)
COMMENT(this specifies `INFO’ and `NOTICE’)
When specifying message levels by their names, the names may be truncated at
a unique point. However, the message level names are interpreted case
sensitively, so `INF’ for `INFO’ is recognized as such, but
`info’ for `INFO’ isn’t. The following examples all
specify verbosity levels INFO and NOTICE:
VERBOSITY()(I N)
VERBOSITY()(N I)
VERBOSITY()(NOT IN)
VERBOSITY()(INFO NOTICE)
- `WARNING’
- `WARNING’ takes one argument: text to display as a warning. The
`yodl’ program makes sure that before showing the text, the current
file and line number are printed. Other than this, `WARNING’ works
just as `TYPEOUT’ (see section `[TYPEOUT]’).
- Note that an analogous function `ERROR’ exists, which prints a
message and then terminates the program (see section
`[ERROR]’).