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