NAME
yodlbuiltins - Builtins for the Yodl converters
SYNOPSIS
This manual page lists the standard builtins of the Yodl package.
DESCRIPTION
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 will 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 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]); 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 parameter lists: the counter name, and the value to
add. The counter must be previously created with DEFINECOUNTER.
The value to add can be negative; in that case, a value is of
course subtracted from the counter.
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 will add 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 takes one parameter list as argument. The text of the
parameter list 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 way of matching
parentheses in a parameter list.
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 by example, 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 will search 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 takes one parameter list. The text in the
list is treated as comment. I.e., it is ignored. The text is not
copied to the final output file.
COUNTERVALUE
COUNTERVALUE expands to the value of a counter. Its single
parameter list 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) parameter list. 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 will be 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 will effectively be 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
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, to be subsequently used by,
e.g, the USECOUNTER function. DEFINECOUNTER expects two
parameter list: the name of the counter to create and an
optional initial value. By default the counter will be
initialized to zero.
Examples:
DEFINECOUNTER(YEAR)(1950)
DEFINECOUNTER(NTIMES)()
See also section [COUNTERS].
DEFINEMACRO
DEFINEMACRO is used to define new macros. This function requires
three parameter lists:
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 used. The number must be in the range 0 to 61.
o The text that the macro will expand to, once used. This text may
contain the strings ARGx, x being 1, 2, etc.. At these places
the arguments to the macro will be 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 three parameter lists are pasted to
the places where ARG1, ARG2 etc. occur in the definition.
Note the following when defining new macros:
o The parameter list 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 parameter
list.
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 will be 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 parameter list 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()
)
will, when called as oops(hello world), produce 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 parameter lists 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 parameter
lists. So, do not use them there to prevent unnecessary clutter.
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 parameter lists are read from the input
o The contents of the parameters then replace their ARGx
references in the macro’s definition (in some exceptional cases,
clearly indicated as such when applicable, the arguments will
themselves be 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 will happen:
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 will put (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 will put 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
NOTE: this function has changed at the release of Yodl 2.00. It
now expects two parameter lists, rather than one
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 parameter list, 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)
DUMMY This function is obsolete. It does nothing, and may be removed
in future versions of Yodl.
ENDDEF ENDDEF is obsolete, and should be replaced by DECWSLEVEL. It
may be removed in future versions of Yodl.
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 parameter list 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 books or reports).
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 will display
the value of the counter, incrementing it first:
EVAL(NOTRANS(USECOUNTER)(SYMBOLVALUE(varnam)))
The actions of the EVAL function can be described as follows:
o First, the NOTRANS(USECOUNTER) is evaluated, producing
USECOUNTER.
o Next, the open parentheses is processed, producing the open
parenthesis itself
o Then, SYMBOLVALUE(varnam) is evaluated, producing the name of a
counter, e.g. ‘counter’.
o Eventually the closing parentheis is processed, producing the
closing parenthesis itself.
o All this results in the text
USECOUNTER(counter)
o This text is now presented to Yodl’s lexical scanner, resulting
in incrementing the counter, and displaying its incremented
value. It should be realized that macro arguments themselves
are usually not evaluated. So, a construction like
USECOUNTER(EVAL(SYMBOLVALUE(varnam)))
will fail, since EVAL(SYMBOLVALUE(varnam)) is not a legal name
for a counter: the EVAL() call is used here as an argument,
which is not expanded. The distinction is subtle, and is caused
by the fact that builtin functions receive unprocessed
arguments, and may impose certain requirements on them (like
USECOUNTER requiring the name of a counter).
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.
Mosy built-in functions will not evaluate their arguments. In
fact, only ERROR, EVAL, FPUTS, INTERNALINDEX, TYPEOUT, UPPERCASE
and WARNING() will 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)
will produce 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 keep original values in some situation?’ In those
situations EVAL() must be used. The following example shows the
definition of three symbols: one receives an initial value, two
will return one’s actual value when two’s value is displayed,
three will, using EVAL(), store one’s initial value. The example
also shows yet another way to suppress macro calls. It uses the
macro nop() which is defined in the all standard conversion
types.
DEFINESYMBOL(one)(This is one, before)
DEFINESYMBOL(two)(SYMBOLVALUE(one))
EVAL(DEFINESYMBOL+nop()(three)(SYMBOLVALUE(one)))
SETSYMBOL(one)(this is one, after)
SYMBOLVALUE(two)
SYMBOLVALUE(three)
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 argment 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 will append 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 parameter list is
evaluated, else, the third parameter list is evaluated. All
three parameter lists (the variable, the true-list and the
false-list) must be present; though the true-list and/or the
false-list may be empty parameter lists.
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 parameter list is evaluated, else, the third parameter
list is evaluated. All three parameter lists (the name, the true
list and the false list) must be present; though the true list
and/or the false list may be empty parameter lists.
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 parameter list. If it is a defined entity,
the second parameter list is evaluated, else, the third
parameter list is evaluated. All three parameter lists (the
entity, the true list and the false list) must be present;
though the true list and/or the false list may be empty
parameter lists.
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
parameter list is evaluated, else, the fourth parameter list is
evaluated. All four argument lists must be present, though all
can be empty lists.
The first two arguments of IFEQUAL should be integral numerical
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 will determine whether the true list
(when the values are equal) or the false list (when the values
are unequal) will be evaluated.
o Otherwise, IFEQUAL will evaluate 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 to its second argument. If so, the
third parameter list is evaluated, else, the fourth parameter
list is evaluated. All four argument lists must be present,
though all can be empty lists.
The first two arguments of IFGREATER should be integral
numerical 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 will determine 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) will be evaluated.
o Otherwise, IFGREATER will evaluate 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
parameter list is evaluated, else, the third parameter list is
evaluated. All three parameter lists (the name, the true list
and the false list) must be present; though the true list and/or
the false list may be empty parameter lists.
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 to its second argument. If so, the
third parameter list is evaluated, else, the fourth parameter
list is evaluated. All four argument lists must be present,
though all can be empty lists.
The first two arguments of IFSMALLER should be integral
numerical 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 will determine 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) will be evaluated.
o Otherwise, IFSMALLER will evaluate 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 seldomly, 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 seldomly, 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
parameter list is evaluated, else, the third parameter list is
evaluated. All three parameter lists (the name, the true list
and the false list) must be present; though the true list and/or
the false list may be empty parameter lists.
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.
IFZERO IFZERO expects three parameter lists. The first argument defines
whether the whole function expands to the true list or to the
false list.
The first argument of IFZERO should be an integral numerical
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, IFZERO will evaluate the false list.
Note that, starting with Yodl version 2.00 the first argument is
not evaluated any further. So, COUNTERVALUE(somecounter) will
always be evaluated 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)
will try to include the file latex or latex.yo from the current
include parth. When the file is not found, Yodl aborts.
INCLUDELIT, INCLUDELITERAL
INCLUDELIT and INCLUDELITERAL are obsolete. NOEXPANDINCLUDE
[NOEXPANDINCLUDE] or NOEXPANDPATHINCLUDE [NOEXPANDPATHINCLUDE]
should be used instead.
INCWSLEVEL
INCWSLEVEL requires one (empty) parameter list. It increases
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 will be 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 will effectively be 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 greated processing speed, at the
expense of an additional file. The associated yodlpost
postprocessing program will read and process the index file, and
will fixup 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 will alter 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 will thereupon write
something like
<a href="outfile.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, report.html,
report.html etc.
NEWCOUNTER
NEWCOUNTER is obsolete. DEFINECOUNTER [DEFINECOUNTER] should be
used instead.
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 parameter list, 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 functions in the argument, which are
expanded. If CHAR-expansion is not required either NOTRANS
[NOTRANS] can be used).
Furthermore, the contents of the parameter list 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 sence 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 ARGx 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
parameter list. 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 is’. 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 will not be
subject to 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 will not be
subject to 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 will send
$\backslash$input\verb+{+epsf.tex\verb+}+
since the characters in its argument are translated with the
standard translation table. In contrast, NOTRANS will send
\input{epsf.tex}.
The parameter list 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 ).
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, then
warnings are generated when Yodl encounters a possible macro
name, followed by a parameter list, without finding a macro by
that name. 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 parameter list.
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 it is handled
especially by Yodl, it is described 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 will call it
whenever a new paragraph (defined as a series of at least two
blank lines) was 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 will
contain 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 will 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 will 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 sytem 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-convertor.
PIPETHROUGH
The builtin function PIPETHROUGH is, besides SYSTEM, the second
function with which a Yodl document can affect its environment.
Therefore, the danger of ‘live data’ exists which is also
described in the section about SYSTEM (see section [SYSTEM]).
Nevertheless, PIPETHROUGH can be very useful. It is intended to
use external programs 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 will be 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, whereafter the
stack will be empty, but the macro will still be defined. In
that case, using the macro 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)
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,
whereafter the stack will be empty, but the symbol will still be
defined. In that case, using the symbol’s value 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, whereafter the stack will be empty, 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 its new value after pushing. When the second argument
is an empty parameter list, the new value will be zero. The new
value may be specified as a numerical value, or as the name of
an existing counter. 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 will
redefine 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)
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 value after pushing. When the second argument is an
empty parameter list, the new value will be zero. The new value
may be specified as a numerical value, 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 happended in 1962)
COMMENT(YEAR now has the value ‘This happended 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 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 parameter lists: the name of a counter,
and a numeric value or the name of another counter.
The corresponding counter (which must be previously created with
NEWCOUNTER) is set to, respectively, the numeric value or the
value of the other counter.
See also section [COUNTERS].
SETSYMBOL
SETSYMBOL expects two parameter lists: the name of a symbol, and
the text to assign to the named symbol.
STARTDEF
STARTDEF is obsolete. Instead, INCWSLEVEL [INCWSLEVEL] should be
used.
SUBST SUBST is a general-purpose substitution mechanism for strings in
the input. SUBST takes two arguments: a search string and a
substitution string. E.g., after
SUBST(VERSION)(1.00)
YODL will transorm all occurrences of VERSION in its input into
1.00.
SUBST is also useful in situations where multi-character
sequences should be converted to accent characters. E.g., a
LaTeX converter might define:
SUBST(’e)(NOTRANS(\’{e}))
Each ’e in the input will then be converted to e.
SUBST may be useed 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 parameter
lists.
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 processs its input files, YODL takes
the following basic 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 will
eventually appear in the output file generated by YODL. YODL
will perform 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 will replace 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 will then be 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 will only see their
definitions.
SYMBOLVALUE
SYMBOLVALUE expands to the value of a symbol. Its single
parameter list must contain the name of a symbol. The symbol
must have been created earlier using the builtin 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. The presence of this
function in the Yodl language introduces the danger of live
data. Imagine someone sending you a document containing
SYSTEM(rm *)
To avoid such malevolent side effects, YODL has a flag -l to
define the ‘live data policy’. By default, -l0 is implied which
suppresses the SYSTEM function and the related PIPETHROUGH
function. See also section [USING].
Despite the potential danger, 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
will not normally appear 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 parameter list. 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)
)
UNDEFINEMACRO
UNDEFINEMACRO is deprecated. Use DELETEMACRO [DELETEMACRO]
instead.
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 parameter list: 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 parameter list: 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 procesing 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 parameter list 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]).
WRITEOUT
WRITEOUT is deprecated, use FPUTS [FPUTS] instead.
FILES
The files in /usr/share/yodl define the converter’s macro packages. The
scripts yodl2tex, yodl2html, yodl2man etc. perform the conversions.
SEE ALSO
yodlstriproff(1), yodl(1), yodlconverters(1), yodlletter(7),
yodlmacros(7), yodlmanpage(7), yodlpost(1), yodlverbinsert(1).
BUGS
--
AUTHOR
Frank B. Brokken (f.b.brokken@rug.nl),