 |
|
| |
Yodl builtin functions(7) |
Your Own Document Language |
Yodl builtin functions(7) |
yodlbuiltins - Builtins for the Yodl converters
This manual page lists the standard builtins of the Yodl
package.
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.
NOTE: Starting with Yodl version 3.00.0 Yodl’s
default file inclusion behavior has changed. The current working directory
no longer remains fixed at the directory in which Yodl is called, but is
volatile, changing to the directory in which a yodl-file is located. This
has the advantage that Yodl’s file inclusion behavior now matches the
way C’s #include directive operates;
it has the disadvantage that it may break some current documents.
Conversion, however is simple but can be avoided altogether if Yodl’s
-L (--legacy-include) option
is used. The builtins INCLUDEFILE, NOEXPANDINCLUDE
and NOEXPANDPATHINCLUDE are affected by this new
behavior.
- 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 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 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 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, 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).
- 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 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 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 is 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
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 ARGx, 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 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
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 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()
)
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 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 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
- 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)
- 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 displays the counter’s value, after having
incremented it:
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)))
fails, 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.
- 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 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 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. 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 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 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 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 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 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 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 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 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 evaluates the false list.
- Note that, starting with Yodl version 2.00 the first argument is not
evaluated any further. So,
COUNTERVALUE(somecounter) is always 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.
- NOTE: Starting with Yodl version 3.00.0 Yodl’s default file
inclusion behavior has changed. The current working directory no longer
remains fixed at the directory in which Yodl is called, but is volatile,
changing to the directory in which a yodl-file is located. This has the
advantage that Yodl’s file inclusion behavior now matches the way
C’s #include directive operates; it
has the disadvantage that it may break some current documents. Conversion,
however is simple and can be avoided altogether if Yodl’s
-L (--legacy-include)
option is used.
- 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) 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 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 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 greated 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 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 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 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 specified. The include path is not used when
locating this file.
- NOTE: Starting with Yodl version 3.00.0 Yodl’s default file
inclusion behavior has changed. The current working directory no longer
remains fixed at the directory in which Yodl is called, but is volatile,
changing to the directory in which a yodl-file is located. This has the
advantage that Yodl’s file inclusion behavior now matches the way
C’s #include directive operates; it
has the disadvantage that it may break some current documents. Conversion,
however is simple and can be avoided altogether if Yodl’s
-L (--legacy-include)
option is used.
- 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.
- NOTE: Starting with Yodl version 3.00.0 Yodl’s default file
inclusion behavior has changed. The current working directory no longer
remains fixed at the directory in which Yodl is called, but is volatile,
changing to the directory in which a yodl-file is located. This has the
advantage that Yodl’s file inclusion behavior now matches the way
C’s #include directive operates; it
has the disadvantage that it may break some current documents. Conversion,
however is simple and can be avoided altogether if Yodl’s
-L (--legacy-include)
option is used.
- 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 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 ).
- 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, 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 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 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 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 interpreations on
top of the last-used one.
- On a 64-bit computer the PUSHSUBST stack can hold
slightly more than 60 SUBST interpreation 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 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 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 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.
- 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 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 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 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.
- 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 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)
)
- 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]).
The files in tmp/wip/macros define the converter’s
macro packages. The scripts yodl2tex, yodl2html,
yodl2man etc. perform the conversions.
yodlstriproff(1), yodl(1), yodlconverters(1),
yodlletter(7), yodlmacros(7), yodlmanpage(7),
yodlpost(1), yodlverbinsert(1).
Frank B. Brokken (f.b.brokken@rug.nl),
Visit the GSP FreeBSD Man Page Interface. Output converted with ManDoc.
|