YODL V1.14

Chapter 2: YODL User Guide

This section describes the yodl program from the point of a meta-user, one who is interested in how macro files work, or one who wants to write a new converter. If you're just interested in using YODL with the pre-existing converters and macro files, skip this chapter and continue with the macro package description (chapter 3).

The yodl program the main converter of the YODL package. The basic usage of the yodl program, yodl's built-in macros, and the syntax of the YODL language is described here.

2.1: Using the yodl program

The yodl program is reads one or more input files, interprets the commands therein, and writes one output file. The program is started as:

yodl flags inputfile [inputfile...]

In this specification, the flags are optional and may be:

The inputfile elements on the command line specify which files YODL should process. All names are supplied with an extension (this extension is defined in the installation of YODL and is usually .yo). The files are then searched for `as-is', or in the system-wide include directory.

Note that all filenames on the command line are input files. To define an output file, either use the -o flag or redirect the output.

2.2: The YODL grammar

The grammar which is used by the YODL system mixes `real' text that should appear on the output with commands for YODL. The commands must follow a certain grammar, which is described in this section.

2.2.1: Language elements

The basic elements of the YODL grammar are identifiers, names, numbers and parameter lists.

Basically, YODL only does `something special' when it encounters a recognized identifier, followed by a parameter list. Sometimes an identifier may be followed by more than one parameter list, in that case, the action requires more than one argument. The grammar of YODL requires that the identifier and its first parameter list follow right after each other, without intervening spaces. That means that

somemacro (argument)

will not start any YODL action (supposing that somemacro is the name of a defined macro), since the parameter list and the identifier are separated by a space. The YODL grammar is very strict in this sence; this rule however simplifies the parsing process of the input.

To make life easier for those who write documentation using YODL, there may be spaces or newlines between the parameter lists (i.e., between the first and second parameter list, between the second and third, and so on). Therefore, assuming that somemacro now is defined as a macro having three arguments, the following will work:

somemacro(argument one) (and another argument, number two) (and the last one)

Summarized, an identified macro is only expanded by YODL when it is followed by a parameter list without spaces in between. Further parameter lists may follow separated by spaces, tabs or newline characters. All required parameter lists must however be in the same input file.

2.2.1.1: Unbalanced parameter lists

YODL recognizes the arguments to a macro as parameter lists, i.e., delimited by ( and ). As long as the number of opening and closing parentheses matches, YODL will correctly recognize the list. E.g., given a hypothetical macro somemacro, the following code sample shows the macro followed by one parameter list:

somemacro(Here is a chunk of text.) somemacro(Here is a some (more) text.)

A problem arises when the number of parentheses is unbalanced: i.e., when the parameter list consists of more opening than closing parentheses or v.v.. To handle such situations, YODL offers a `literal-character' mechanism (see the CHAR macro in 2.3.3) and a `global substitution' mechanism (see the SUBST macro in 2.3.30). For example, to send the text

here's a ")" closing parenthesis

as an argument to our hypothetical macro somemacro, the following can be used:

COMMENT(-- Alternative 1: using CHAR --) somemacro(here's a "CHAR(41)" closing parenthesis) COMMENT(-- Alternative 2: using SUBST --) SUBST(closepar)(CHAR(41)) . . somemacro(here's a "closepar" closing parenthesis)

Both methods have disadvantages: the CHAR method requires you to remember that an ASCII 41 is a closing parenthesis. The SUBST method defines a string closepar that is always expanded to a closing parenthesis, wherever in the text it occurs. Nevertheless, unbalanced parameter lists can be handled by YODL. (If the here described method proves to be too much of a pain, I'll think of something. As for myself, I've never yet have felt the need to use an unbalanced parameter list -- except in this document..) Also, remember that unbalanced parenthesis pairs are only relevant in argument lists. YODL handles parentheses in normal text as ordinary characters.

2.2.2: Line continuation

To make the typing of input easier, YODL allows you to end a line with a backslash character \ and to continue it on the next line. That way you can split long lines to fit your screen. When processing its input, YODL will treat these lines as one long line, and will of course ignore the \ character. This feature only works when the \ character is the last one on the line (no spaces may follow).

When the line following the one with the \ character has leading spaces, then these are omitted. This allows you to `indent' a file as you wish, while the space characters of the indentation are ignored by the yodl program.

A trivial example is the following:

Grampa and\ grandma are sitting on the sofa.

Due to the occurrence of the \ character in the sequence and\, YODL will combine the lines into

Grampa andgrandma are sitting on the sofa.

Note that the spaces before grandma are ignored, since this is the second line following a \ character.

If you do want one or more spaces while joining lines with \, put the spaces before the \ character.

Summarized:

The question is of course, how do you accomplish that a line really ends with a \, when you do not want YODL to merge it with the following line? In such a case, type a space character following your \: YODL won't combine the lines. Or set the \ character as CHAR(\) or CHAR(92) (see section 2.3.3 for the CHAR macro). In my opinion, the ease of line continuation in YODL files outweighs the extra necessary actions to typeset a real \ character at the end of a line.

2.2.3: The +identifier sequence

One more feature of the YODL language remains to be described. There may be situations in which you must type a macro name right after a sequence of characters, while YODL should recognize this. Imagine that someone wrote a great macro footnote for you (someone did, in fact, see the next chapter), to typeset footnotes. If you'd type in a document:

The C Programming Languagefootnote(as defined by Kernighan and Ritchie) ...

then of course YODL would fail to see the start of a macro in the sequence Languagefootnote. You could say

The C Programming Language footnote(as defined by Kernighan and Ritchie) ...

but that would introduce a space between Language and the footnote. Probably you don't want that, since spaces between a word and a footnote number look awful and because of the fact that the footnote number might be typeset on the following line.

For these special situations, YODL recognizes the +identifier sequence as the start of a macro, while the + sign is effectively ignored. In the above example you could therefore use

The C Programming Language+footnote(as defined by Kernighan and Ritchie) ...

The +identifier recognition only works when the identifier following the + sign is a macro. In all other situations, a + is just a plus-sign.

(The +identifier sequence furthermore plays an important role in macro packages. If you're interested, see the file shared.yo which is by default installed to /usr/local/lib/yodl.)

2.3: 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 3 that describes a macro package for YODL.

2.3.1: ADDTOCOUNTER

The ADDTOCOUNTER macro 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 NEWCOUNTER.

The value to add can be negative; in that case, a value is of course subtracted from the counter.

See further section 2.6.

2.3.2: ATEXIT

The macro 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..

A good example of the usage of this macro 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(Make sure that the ending is on time.) ATEXIT(NOEXPAND(\end{document}))

2.3.3: 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 2.4). Also, the CHAR macro can be used to circumvent YODL's way of matching parentheses in a parameter list.

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 macro NOTRANS (see section 2.3.22). If you want to send a string to the output without macro interpretation, but with character table translation, use NOEXPAND (see section 2.3.21).

2.3.4: CHDIR

The command CHDIR takes one argument, a directory to change to. This command is implemented to simplify the working with INCLUDEFILE (see section 2.3.18). 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.

2.3.5: COMMENT

The COMMENT macro takes one parameter list. The text in the list is treated as comment; i.e., nothing is done with it. The text is not copied to the final output file; this command is meant as comment for YODL files only.

2.3.6: COUNTERVALUE

The macro COUNTERVALUE expands to the value of a counter. Its only parameter list is a counter name. The counter must be previously created by NEWCOUNTER.

See further section 2.6.

2.3.7: DEFINECHARTABLE

The macro DEFINECHARTABLE is used to define a character translation table. Its complement, USECHARTABLE, activates the table. The discussion of character tables is postponed to section 2.4.

2.3.8: DEFINEMACRO

The macro DEFINEMACRO lets you define new macros. This macro requires three parameter lists:

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:

bookref(Sobotta/Becher) (Atlas der Anatomie des Menschen) (Urban und Schwarzenberg, Berlin, 1972)

It would of course lead to:

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.

A few caveats when defining new macros are:

2.3.9: DEFINESYMBOL

The macro DEFINESYMBOL takes one argument, an identifier, which is treated as a symbol that is set to the logic value `true'. The true-ness or false-ness of this symbol may subsequently be tested with IFDEF (see section 2.3.13).

The corresponding macro UNDEFINESYMBOL removes the definition of a symbol.

Example:

Definining "somesymbol"... DEFINESYMBOL(somesymbol) IFDEF(somesymbol) (Symbol "somesymbol" is true.) (Symbol "somesymbol" is false.) Removing definition of "somesymbol"... UNDEFINESYMBOL(somesymbol) IFDEF(somesymbol) (Symbol "somesymbol" is true.) (Symbol "somesymbol" is false.)

This produces output similar to:

Definining "somesymbol"... Symbol "somesymbol" is true. Removing definition of "somesymbol"... Symbol "somesymbol" is false.

2.3.10: DUMMY

This macro takes one argument, which is not interpreted. The macro is a real dummy, it does nothing.

(I implemented the macro in order to provide a simple debugging hook. After inserting DUMMY() somewhere in the macro file, I can start the yodl program under a debugger and set a breakpoint in the dummy-routine; then watch what happens from there.)

2.3.11: ENDDEF

The macro ENDDEF takes one (empty) parameter list. It signals the ending of a YODL definition section. See the description of STARTDEF, 2.3.31.

2.3.12: ERROR

The ERROR macro 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.

This command can be used, e.g., in a macro package when an incorrect macro is expanded. In my macro package (see chapter 3) the ERROR macro 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 macro is WARNING, which also prints a message but does not exit (see section 2.3.39).

2.3.13: IFDEF

The IFDEF macro tests for the logical true value of the argument in its first parameter list. If `true', 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.

The variable in the first parameter list evaluates the macro to `true' when the first argument is:

For an example, see the description of DEFINESYMBOL, section 2.3.9.

2.3.14: IFEMPTY

The macro IFEMPTY expects three arguments: a symbol, a true-list and a false-list. The macro evaluates to the true-list if the symbol is an empty string; otherwise, it evaluates to the false-list.

A trivial example is the following:

IFEMPTY(something) \ ("something" is supposedly nothing ?!?") ("something" is not an empty string)

In the same way, IFEMPTY can be used to test whether a macro 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 of course supply Unknown in the Published by: line.

2.3.15: IFSTREQUAL

The macro 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 two string arguments match exactly.

2.3.16: IFSTRSUB

The IFSTRSUB macro tests whether a string is a sub-string of another string. It is similar to IFSTREQUAL (see section 2.3.15), except that the test is whether the second string is part of the first one. Hence:

IFSTRSUB(some piece of text)(ce o) (truelist) (falselist)

evaluates to truelist.

2.3.17: IFZERO

The IFZERO macro expects three parameter lists, just as the other IF... macros: a symbol, a true-list and a false-list.

The first argument defines whether the whole macro expands to the true-list or to the false-list. The first argument may be:

You can use COUNTERVALUE(somecounter) as the argument to IFZERO, it is treated in the same manner as the corresponding counter name.

Example: The IFZERO macro offers a very simple way to pass a flag-argument (an on/off switch) to a macro. E.g., in LaTeX you start environments with \begin{environment} and end them with \end{environment}; environment being e.g., center, flushright, flushleft. A possible meta-macro for the environments might be:

DEFINEMACRO(environment)(2)(\ IFZERO(ARG2)\ NOEXPAND(\end{ARG1})\ NOEXPAND(\begin{ARG1}))

Such a macro may be used as:

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.

2.3.18: INCLUDEFILE

The command INCLUDEFILE takes one argument, a filename. The file is included.

The yodl program supplies, when necessary, an extension to the filename. The supplied extension is .yo, unless defined otherwise in the compilation of the program. Furthermore, yodl prefixes the file with the system-wide include directory if necessary. This directory is normally /usr/local/lib/yodl, unless overruled by the command line flag -I or defined otherwise in the compilation.

E.g., if you install a macro package in a file latex.yo in the directory /usr/local/lib/yodl, then the command

INCLUDEFILE(latex)

will include it.

2.3.19: INCLUDELITERAL

The command INCLUDELITERAL takes one argument, a filename. The file is included.

The filename is not changed in any way.

Furthermore the contents of the file is included without any modification.

The purpose of INCLUDELITERAL is to include source code literally in the document, as in:

INCLUDELITERAL(literal.c)

This example shows how to put the contents of C file literal.c into the document.

2.3.20: NEWCOUNTER

The macro NEWCOUNTER creates a new counter, to be subsequently used by, e.g, the USECOUNTER macro. NEWCOUNTER expects one parameter list: the name of the counter to create. See further section 2.6.

2.3.21: NOEXPAND

The macro NOEXPAND is one of the ways in which text can be sent to the final output file without being expanded by YODL (the other methods are the CHAR macro, see section 2.3.3, and the NOTRANS macro, see section 2.3.22). The macro 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 macros in the argument, which are expanded). The contents of the parameter list are subject to character table translations, using the currently active table (see section 2.4).

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 macro, keep the following caveats in mind:

2.3.22: NOTRANS

The macro NOTRANS copies its one argument literally to the output file, without expanding macros in it (except for CHAR, which is expanded) and without translating the characters with the current translation table. The NOTRANS macro 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 \{} 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})

The NOEXPAND macro in this example will send

$\backslash$input\verb+{+epsf.tex\verb+}+

since the characters in its argument are translated with the standard translation table. In contrast, the NOTRANS macro, will send literally \input{epsf.tex}.

The parameter list of the NOTRANS macro must be balanced in respect to its parentheses. When using an unbalanced number of parentheses, use CHAR(40) to send a literal (, or CHAR(41) to send a ).

2.3.23: NOUSERMACRO

The macro NOUSERMACRO controls yodl's warnings in the following respect. 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, but fails to lookup the macro. The yodl program 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 hee 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 spaces, commas, colons, or semi-colons.

2.3.24: PARAGRAPH

The PARAGRAPH macro is defined by the YODL program, but is had normally no actions. The macro works as follows.

If you define the macro, then YODL's parser will trigger it whenever a new paragraph is started. The macro must be defined as one with zero arguments, but leading to some (necessary) action. New paragraphs are -by definition- indicated in the source file as two or more consecutive newline characters, optionally separated by spaces. I.e., in the text

Here is a line of text. And here's another one.

one new paragraph occurs: the first line is terminated by a newline, then one newline follows right behind. Given such input, the PARAGRAPH macro is triggered right before the parsing process of the line starting with And.

Some macro packages do not need paragraph starts; e.g., LaTeX does its own paragraph handling. Other macro packages 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)(<p>)

Note that the definition of the action of the PARAGRAPH macro is again parsed and expanded by YODL. Therefore, if you put two consecutive newlines in the definition itself, the definition will again trigger the PARAGRAPH macro, etcetera, ad infinitum. If you want the PARAGRAPH redefinition to insert a blank line, protect the line in a NOEXPAND, as in:

DEFINEMACRO(PARAGRAPH)(0)(NOEXPAND( )<p>)

2.3.25: PIPETHROUGH

The builtin macro PIPETHROUGH is, besides SYSTEM, the second macro 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 2.3.32). 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 PIPETHROGUH macro takes two arguments:

Functionally, the occurrence of the PIPETHROUGH macro 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: PIPETHROGH(date)()

In this example the command is date and the text to send to that program is empty.

The main purpose of this macro 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.

2.3.26: 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 2.4.3.

2.3.27: PUSHCHARTABLE

After a character table has been defined, it can be "pushed" onto a stack; to be "popped" later. This discussion is postponed to section 2.4.3.

2.3.28: RENAMEMACRO

The command 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), and no longer using INCLUDEFILE.

Note that following the RENAMEMACRO action, the old name can no longer be used; it is then an unknown 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 read in a file.

2.3.29: SETCOUNTER

The SETCOUNTER macro expects two parameter lists: one counter name, and one numeric value. The corresponding counter (which must be previously created with NEWCOUNTER) is set to the numeric value.

See also section 2.6.

2.3.30: SUBST

The SUBST macro is a general-purpose substitution mechanism for strings in the input. It takes two arguments: a search string and a substitution string. E.g., after

SUBST(VERSION)(1.00)

the yodl program will output 1.00 for each occurence of VERSION in its input.

The SUBST macro is also useful in situations where multi-character sequeces should be converted to accent characters. E.g., a LaTeX converter might define:

SUBST('e)(NOTRANS(\'{e}))

Each 'e in the input would then be converted to +é.

The SUBST macro may also be useful in combination with the command line flag -P, as in a invocation

yodl2html -P'SUBST(VERSION)(1.00)' myfile.yo

A further useful substitution may be the following:

SUBST(_OP_)(CHAR(40)) SUBST(_CP_)(CHAR(41))

which defines an opening parenthesis (_OP_) and a closing parenthesis (_CP_) as mapped to the CHAR macro. The strings _OP_ and _CP_ might then be used in unbalanced parameter lists.

Note that:

2.3.31: STARTDEF

The STARTDEF macro typically occurs in files that define a macro package for YODL. The macro signals the yodl program that the following input holds only the definitions of macros, symbols etc..

When yodl is inside a definition, the generation of empty lines on the output is suppressed, and yodl warns when non-whitespace output is generated. Using STARTDEF is never obligatory, but it is useful in a macro file. Macro files tend to define a lot of symbols or commands, leading to unnecessary spaces and newlines.

The definition section is ended with the ENDDEF macro.

Example:

STARTDEF() DEFINESYMBOL(....) DEFINEMACRO(...)(...)(...) ENDDEF()

Without the STARTDEF and ENDDEF, the above definition would generate four empty lines in the output.

2.3.32: SYSTEM

The SYSTEM macro takes one argument: a command to execute. The command is run via the standard C function system. The presence of this macro in the YODL language introduces the danger of live data; imagine someone sending you a document with

SYSTEM(rm *)

in it. To avoid such malevolent side effects, the yodl program has a flag -l to define the `live data policy'. By default, -l0 is implied which suppresses the SYSTEM macro and the related PIPETHROUGH macro. See also section 2.1.

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)

2.3.33: TYPEOUT

The macro 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))

2.3.34: UNDEFINEMACRO

The macro UNDEFINEMACRO removes a definition of a macro that was defined by DEFINEMACRO. This macro 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:

UNDEFINEMACRO(mymacro) DEFINEMACRO(mymacro)(1)(This is my macro with argument ARG1.)

2.3.35: UNDEFINESYMBOL

The macro UNDEFINESYMBOL removes the definition of a logical symbol. It expects one parameter list, holding the variable to undefined.

This macro has no error condition (except for syntax errors): the symbol in question may be previously defined, but that is not necessary.

2.3.36: UPPERCASE

The UPPERCASE macro convderts a string or a part of it to upper case. It has two arguments:

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

2.3.37: USECHARTABLE

The macro USECHARTABLE takes one parameter list: the name of a translation table to activate. The table must be previously defined using DEFINECHARTABLE. See section 2.4 for a description of character translation tables.

Alternatively, the name may be empty in which case the default character mapping is restored.

2.3.38: USECOUNTER

The macro USECOUNTER is a combination of ADDTOCOUNTER and COUNTERVALUE. It expects one parameter list: a counter name, that must be previously created with NEWCOUNTER.

The counter is first increased by 1. Then the macro expands to the number of the counter.

See also section 2.6.

2.3.39: WARNING

The WARNING macro 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 2.3.33).

Note that an analogous macro ERROR exists, which prints a message and then terminates the program (see section 2.3.12).

2.4: Character tables

The YODL language provides a way to define character translation tables, to activate them, and to deactivate them. A character translation table defines how a character in the input will appear in the output.

There are two main reasons for the need of character translation tables. First, a document language becomes much easier to use when you can type an asterisk as * instead of $*$ or \verb/*/ (these are sequences from the LaTeX document language). Hence, a mechanism that expands a * in the input to to \verb/*/ on the output, saves the users a lot of typing.

Second, forcing users to type weird sequences won't work if you're planning on converting the same YODL document to a different output format. If the user types \verb/*/ in the input to typeset an asterisk in the output, how should he or she arrive at a single * in the output in another output format?

The solution is of course to define the translation for an input character like * given the output format.

2.4.1: Defining a translation table

The built-in macro DEFINECHARTABLE defines a character translation table. It takes two parameter lists: the name of the table and the character translations. Hence, each table is defined by its own name.

As an example of a table, consider the following fragment. It defines a table that translates the upper case characters A to E to their lower case equivalents:

DEFINECHARTABLE(tolower)( 'A' = "a" 'B' = "b" 'C' = "c" 'D' = "d" 'E' = "e" )

Each DEFINECHARTABLE statement must have a non-empty second parameter. "Empty" character tables cannot be defined, though one non-translation table is built-in.

The syntaxis of the second parameter list is as follows:

Translations which are not specified in the table are left to the default, which is to output the character as-is.

Note that the character table translation is something that the yodl program does as one of its last actions, just before sending text to the output file. The expansion text is not further processed by yodl, except for the conversion of C-type escape sequences to ordinary characters. The expansion text should therefore not be protected by, e.g., NOTRANS (unless of course you want some character to generate the text NOTRANS on the output).

2.4.2: Using a translation table

A defined translation table is activated by the macro USECHARTABLE. This macro takes one parameter list, which may be:

The default mapping, selected when an empty parameter list is given, means that YODL enters its `zero translation state', meaning no character translation at all.

2.4.3: Pushing and popping character tables

Besides the previously described macro USECHARTABLE(), Yodl has one other mechanism of activating and deactivating character translation tables. This mechanism uses a stack, and hence, the related macros are appropriately named PUSHCHARTABLE() and POPCHARTABLE().

Using the push/pop mechanism is handy when a table must be temporarily activated, but when it is not known which table exacty is active prior to the temporary activation. E.g., imagine that you need to use a character table called listing to typeset a listing, but that you do not know the current table. The pushing and popping mechanism is then used as follows:

COMMENT(First, we save the current table on the stack and we activate our "listing" table.) PUSHCHARTABLE(listing) COMMENT(Now the text is question is typeset.) ... COMMENT(The previously active table is re-activated, whatever its name.) POPCHARTABLE()

2.5: Sending literal text to the output

The YODL program has three built-in macros to send literal text to the output file. The macros are listed in the above section 2.3 and are furthermore described here.

To illustrate the need for the distinction between NOTRANS and NOEXPAND, consider the following. The HTML converter (described in chapter 3) must be able to send HTML commands to the output file, but must also be able to send literal text (e.g., a source file listing). The HTML commands of course must be neither translated with any character table, nor must they be expanded in regard to macros. In contrast, a source file listing must be subject to character translations: the &, < and > characters can cause difficulties. Two possible macros for a HTML converter are:

COMMENT(--- htmlcommand(cmd) sends its argument as a HTML command to the output ---) DEFINEMACRO(htmlcommand)(1)(NOTRANS(ARG1)) COMMENT(--- verb(listing) sends the listing to the output ---) DEFINECHARTABLE(list)( '&' = "&amp;" '<' = "&lt;" '>' = "&gt;" ) DEFINEMACRO(verb)(1)( \ USECHARTABLE(list) \ NOTRANS(<listing>) \ NOEXPAND(ARG1) \ NOTRANS(</listing>) \ USECHARTABLE(standard))

In this example it is assumed that a character translation table standard exists, defining the `normal' translations. This table is re-activated in the verb macro.

2.6: Counters

Some document languages (notably LaTeX) automatically prefix numbers when typesetting sections, subsections, tables, figures etc.. Other document languages (e.g. HTML) unfortunately don't.

Therefore, a macro package that converts a YODL document to LaTeX doesn't need to provide the numbering of sections etc.. However, if you do want the numbering and if you want to convert documents to, say, HTML, then you must take care of the numbering yourself.

This section describes the counters in YODL: how to create a new counter, how to use it, etc..

2.6.1: Creating a counter

Before a counter can be used, it must be created with the macro NEWCOUNTER. This macro expects one parameter list: the name of the counter. The initial value of the counter is set to zero.

As for an example, let's say that our macro package should provide two sectioning commands: section and subsection. The sections should be numbered 1, 2, etc., and the subsections 1.1, 1.2, 1.3 etc.. Hence we'd need two counters:

NEWCOUNTER(sectcounter) NEWCOUNTER(subsectcounter)

2.6.2: Using counters

YODL has four macros to modify and/or to set the values of counters. The macros are:

Given the numbering requirements of the hypothetical commands section and subsection (see the previous section), we can now complete the definitions:

NEWCOUNTER(sectcounter) NEWCOUNTER(subsectcounter) DEFINEMACRO(section)(1)(\ SETCOUNTER(subsectcounter)(0)\ USECOUNTER(sectcounter) ARG1) DEFINEMACRO(subsection)(1)(\ COUNTERVALUE(sectcounter).USECOUNTER(subsectcounter) ARG1)