The tt(yodl) program is a single-pass interpreter of its input files. The 
program does not build an internal data representation of the text and 
commands that it encounters; therefore, all actions must be completed in one 
pass. The basic way by which tt(yodl) does this, is by reading input, taking 
actions and possibly `pushing back' information on the input.

This is best illustrated with an example. Given the code,

verb(\
DEFINESYMBOL(sym)

IFDEF(sym)
    (Symbol sym is defined!
     DEFINEMACRO(testmac)(0)(Testmac now stands for one thing.)
    )
    (Symbol sym is not defined!
     DEFINEMACRO(testmac)(0)(Testmac now stands for another thing.)
    )
    
testmac())

tt(yodl) will take the following actions:

startit()

    it() The tt(DEFINESYMBOL) command updates an internal table of symbols, no 
    other action is necessary here.
    
    it() When the tt(IFDEF) command is parsed, tt(yodl) eats up all of the 
    necessary parts from the input: the keyword itself, and three parameter 
    lists. The tt(IFDEF) test obviously yields `true', and therefore tt(yodl) 
    `pushes back' the true-list
    
verb(\
Symbol sym is defined!
DEFINEMACRO(testmac)(0)(Testmac now stands for one thing.))

    it() Next, tt(yodl) sees normal text (tt(Symbol) tt(sym) tt(is) etc.). This 
    is sent to the output file.
    
    it() After this, the tt(DEFINEMACRO) statement is seen, which defines 
    tt(testmac()) as a placeholder for tt(one) tt(thing). 
    
    it() Finally, tt(testmac()) is seen. The parser recognizes a user-defined 
    macro having no arguments, which conforms to the definition. The text 
    
verb(Testmac now stands for one thing.)

    is pushed back.
    
    it() Finally, tt(yodl) reads this last string from its input and sends it 
    to the output.

endit()

The most complex part of the program is therefore the tokenizer (lexical
analyzer): that part is responsible for matching tokens such as identifiers in
the input, and for pushing back text. The pushing back is implemented as a
relocatable buffer, which is expanded as text is pushed into it and which
shrinks as the lexical analyzer processes input. I already achieved about 100%
speed gain by optimizing the tokenizer, but this implementation can still be
somewhat of a CPU hog.footnote(But hey, em(premature optimzation is the root of
all evil,) says D.E. Knuth. So why optimize, as long as you don't know whether
you're being premature about it?)

The lexical analyzer is furthermore responsible for the line continuation 
feature (see section ref(continuation)) and for the tt(SUBST) mechanism (see 
section ref(subst)). These mechanisms are also implemented with the push-back 
method.
