Even without making use of moto's programmatic constructs, the moto preprocessor can
do away with much of the repetition involved in hand coding pages of HTML. It provides
functionality for text file inclusion and macro substitution.
Just as in the C preprocessor the include directive is used to copy the contents of
another file into a moto page at the point in the page where the directive is used.
This directive may be used as a replacement for server side includes
to include image maps or common web page navigation. Moreover, since file inclusion occurs in the
preprocessor phase, included files can contain moto source code. The path to the include is relative to the including page or, if the path begins with a /, is relative to the file system root.
The moto preprocessor also has the capability to do macro expansion within moto pages. Macros are used
like moto constructs in that they also begin with a dollar sign. This document uses macros to format
each of it's examples. The example above was formatted by the following code:
$BEGIN_USAGE
#include(path to include)
$END_USAGE
| |
Macros may require arguments. These arguments need not (and often should not) be quoted as they will be
substituted without modification where they are used in the macro definition. Argument lists are comma
delimited thus if one argument contains a comma (or a close paren ')') it must be escaped with
a backslash '\'. An example of a macro that takes arguments used in the construction of this document is
the macro used for specifying section headers:
$BEGIN_SECTION("Macro Substitution")
| |
The #readdefs preprocessor directive makes the macros contained in a text file (called a macro library)
available for substitution in the preprocessing phase.
#readdefs(path to macro library file)
| |
The path to the macro library can be relative to the page containing the readdefs directive or fully qualified from your root directory. Macro libraries have names ending with '.lib'. The rules for constructing a library file are
as follows:
- Lines beginning with a pound sign '#' are ignored. These are comments in the library file.
- Lines beginning with text (without indentation) begin a macro definition. The first word
on that line is the macro name.
- If the macro is to take arguments, the macro name should be immediately followed by
an open paren '(', then a comma delimited list of argument names,
and finally a close paren ')'.
- Lines beginning with white space are considered part of the current macro definition thus
a macro definition ends when the file ends or the next macro definition begins.
- Macros may be used in the definitions of other macros but self referential macro calls
are prohibited.
- A macro argument is used within the body of a macro as if it were another macro i.e. they are called
by $macro argument name
The macro library used in the creation of this document looks like:
#
# Called at the beginning of a document, this macro sets up the variables
# needed to create and store the outline of that document
#
INIT_FORMAT
$use("codex.util")
$declare(int levelCounter)
$declare(int chapNum = 0)
$declare(Stack outline = new Stack())
$declare(Vector curLevel = new Vector())
$do(outline.push(curLevel))
#
# This macro should be called at the beginning of a section or
# or subsection with the header for that section or subsection. It
# will add the section header to the outline and compute and display
# the appropriate section / subsection number. It will also insert an HTML
# anchor tag so that this section may be linked to from the outline
# (autmatically generated by the DISPLAY_OUTLINE macro)
#
BEGIN_SECTION(section)
$do(curLevel = <Vector>outline.peek())
$do(curLevel.add($section))
$do(curLevel.add(new Vector()))
<h3>
$for(levelCounter=outline.size();levelCounter>1;levelCounter--)
$((<Vector>(outline.peekAt(levelCounter))).size()/2 +
(levelCounter==outline.size()?chapNum:0)).
$endfor
$(curLevel.size()/2 + (levelCounter==outline.size()?chapNum:0))
<a name="$($section)">$($section)</a>
</h3>
$do(outline.push(curLevel.get(curLevel.size()-1)))
#
# This macro should be called at the end of a section or subsection
#
END_SECTION $do(outline.pop())
#
# This macro is used to generate the HTML for a hyperlinked outline of
# a document marked up with the preceding macros
#
GENERATE_OUTLINE(outputFile)
$declare(int curIndex = 0)
$declare(IntStack istck = new IntStack())
$declare(Stack ostck = new Stack())
$declare(StringBuffer obuffer = new StringBuffer())
$do(ostck.push(outline.peek()))
$do(istck.push(0))
$while(ostck.size() > 0 )
$do(curLevel = <Vector>ostck.peek())
$do(curIndex = istck.peek())
$if(curIndex == curLevel.size() )
$do(curLevel = <Vector>ostck.pop())
$do(curIndex = istck.pop())
$if(istck.size()>0)
$do(istck.push(istck.pop()+2))
$endif
$continue
$endif
$for(levelCounter=istck.size();levelCounter>0;levelCounter--)
$do(obuffer.append(istck.peekAt(levelCounter)/2 + 1))
$do(obuffer.append('.'))
$endfor
$do(obuffer.append("<a href=\"docs"))
$do(obuffer.append(istck.peekAt(istck.size())/2 + 1))
$do(obuffer.append(".moto#"))
$do(obuffer.append(<String>curLevel.get(curIndex)))
$do(obuffer.append("\" onClick=\"return targetopener(this)\">"))
$do(obuffer.append("<nobr>"))
$do(obuffer.append(<String>curLevel.get(curIndex)))
$do(obuffer.append("</nobr>"))
$do(obuffer.append("</a><br>\n"))
$do(istck.push(0))
$do(ostck.push(curLevel.get(curIndex+1)))
$endwhile
$do(putFile($outputFile,obuffer.toString()))
| |
Copyright © 2000 - 2003 David Hakim