--- /dev/null
+.SA 1
+.TL "A Brief Tour of the CUPL Internals"
+.AF "Thyrsus Enterprises"
+.AU "Eric S. Raymond" ESR "\&\&22 South Warren Ave, Malvern PA 19355"
+.MT 4
+.nr Pt 1
+.P
+The CUPL implementation is built around YACC and LEX. The rest is
+ANSI and POSIX-conformant C.
+.P
+The YACC grammar just builds a parse tree, which is passed to
+interpret() for interpretation. This method requires that all
+programs are always small enough that the entire tree can be held
+in memory, but it has the advantage that front and back end are very
+well separated. It is a winning strategy on virtual-memory systems.
+.P
+One hack that greatly simplifies the grammar productions is that the
+lexer actually returns parse tree nodes, even for atoms like
+identifiers, strings, and numbers. In fact, the lexical analyzer even
+does label and variable name resolution with the same simple piece of
+code; each IDENTIFIER token is looked up in the identifier list when
+it's recognized, so the parse tree early becomes a DAG. (The -v1 option
+causes the compiler to dump its parse tree for inspection.)
+.P
+Most of the smarts are in interpret() and its sub-functions. Because
+array variables can be re-allocated, the internals have to use a
+dynamic vector/array type with its own indexing machinery.
+.P
+Note that much of this machinery is quite generic and could be re-used
+for other languages with little change.
+