Als Beispiel für das Einbinden von Quelltext ist in diesem Anhang der
Quelltext einer Parser-Grammatik dokumentiert. Für die Darstellung
des Quelltextes wird das Paket listings und das darin
enthaltenen Makro \lstinputlisting{} verwendet. Durch
\lstinputlisting{} kann eine separate Datei mit Quelltext
eingebunden werden. Alternativ kann der Quelltext direkt in der
LATEX-Datei innerhalb der Umgebung lstlisting angegeben
werden.
Weil die HTML-Ausgabe mittels LATEX2HTML das Pakt
listings nicht unterstützt, ist hierfür eine separate
Ausgabe des Quelltextes innerhalb einer verbatim-Umgebung
notwendig. Hier kann das Makro \verbatiminput{} aus dem
Paket verbatim verwendet werden, um eine separate Datei
einzulesen. Für die direkte angabe von Quelltext innerhalb der
LATEX-Datei kann die gewohnte verbatim-Umgebung
verwendet werden.
Zuerst wird an dieser Stelle die vom Parser zum Einlesen von gültigen Zeichen benötigte Datei scanner.lex für die lexikalische Analyse durch JLex aufgeführt (vgl. Berk, 2000):
package yacs.parser;
import java_cup.runtime.Symbol;
%%
%cup
%public
ALPHA=[A-Za-z]
DIGIT=[0-9]
%%
";" {return new Symbol(sym.SEMI);}
"," {return new Symbol(sym.COMMA);}
"=" {return new Symbol(sym.EQUAL);}
"!=" {return new Symbol(sym.NOT_EQUAL);}
">" {return new Symbol(sym.GREATER);}
"<" {return new Symbol(sym.LOWER);}
">=" {return new Symbol(sym.GREATER_EQUAL);}
"<=" {return new Symbol(sym.LOWER_EQUAL);}
"+" {return new Symbol(sym.PLUS);}
"-" {return new Symbol(sym.MINUS);}
"*" {return new Symbol(sym.TIMES);}
"/" {return new Symbol(sym.DIVIDE);}
"(" {return new Symbol(sym.LPAREN);}
")" {return new Symbol(sym.RPAREN);}
"[" {return new Symbol(sym.LBRACKET);}
"]" {return new Symbol(sym.RBRACKET);}
{DIGIT}+ {return new Symbol(sym.NUMBER,
new Integer(yytext()));}
{DIGIT}+"."{DIGIT}+ {return new Symbol(sym.FLOAT,
new Double(yytext()));}
{ALPHA}({ALPHA}|{DIGIT}|_|".")* {return new Symbol(sym.VARIABLE, yytext());}
[ \t\r\n\f\b] {/* ignore white space. */}
. {System.err.println("Illegal character: "
+yytext());}
Von Scanner erfasste Zeichen werden an den Parser weitergegeben und anhand der Java-CUP-Grammatik in der Datei parser.cup ausgewertet (vgl. Hudson, 1999):
package yacs.parser;
import java.util.HashMap;
import yacs.domain.*;
import java_cup.runtime.*;
action code {:
/* this is where the action code goes */
/** der erzeugte Ausdruck */
public Expression expression;
/** HashtMap zum "Wiederfinden" der generierten Variablen */
public HashMap actionVariablesMap = new HashMap();
/** temporaere Variable zum Zwischenspeichern */
public Variable tmpVariable;
:};
parser code {:
/* this is where the parser code goes */
/** HashtMap zum Zwischenspeichern der bereits vorhandenen Variablen */
public HashMap parserVariablesMap = new HashMap();
/**
* Hinzufuegen bereits vorhandener Variablen. Anstatt neue Variablen
* zu erzeugen, werden so die Referenzen bestehender Objekte
* verwendet.
* @param variablesMap HashMap
*/
public void addVariablesMap(HashMap variablesMap) {
this.parserVariablesMap.putAll(variablesMap);
}
/**
* Gibt den gescannten und geparsten Ausdruck als Expression zurueck.
* @return Expression
*/
public Expression expression() {
return action_obj.expression;
}
:};
init with {:
// Die in "parser" bereits befindlichen Variablenreferenzen in das
// "action_obj" uebertragen. Dies muss hier separat geschehen, da
// erst waehrend der "init"-Phase das "action_obj" instantiiert ist.
action_obj.actionVariablesMap.putAll(this.parserVariablesMap);
:};
/* Terminals (tokens returned by the scanner). */
terminal UMINUS, SEMI, LPAREN, RPAREN, COMMA, LBRACKET, RBRACKET;
terminal PLUS, MINUS, TIMES, DIVIDE;
terminal EQUAL, NOT_EQUAL, GREATER, LOWER, GREATER_EQUAL, LOWER_EQUAL;
terminal Integer NUMBER;
terminal Double FLOAT;
terminal String VARIABLE;
/* Non Terminals */
non terminal expr_all;
non terminal Expression expr_list, expr, expr_part;
/* Precedences */
precedence left EQUAL, NOT_EQUAL, GREATER, LOWER, GREATER_EQUAL, LOWER_EQUAL;
precedence left PLUS, MINUS;
precedence left TIMES, DIVIDE;
precedence left UMINUS;
/* The grammar */
expr_all ::= expr_list:e
{:
System.out.println(" => "+e.toString());
this.expression = e;
:}
;
expr_list ::= expr:e
{: RESULT = e; :}
| expr_list:l expr:r
{: RESULT = new BinaryOperator(sym.SEMI, ";", l, r); :}
;
expr ::= expr_part:l EQUAL expr_part:r SEMI
{: RESULT = new BinaryOperator(sym.EQUAL, "=", l, r); :}
| expr_part:l NOT_EQUAL expr_part:r SEMI
{: RESULT = new BinaryOperator(sym.NOT_EQUAL, "!=", l, r); :}
| expr_part:l GREATER expr_part:r SEMI
{: RESULT = new BinaryOperator(sym.GREATER, ">", l, r); :}
| expr_part:l LOWER expr_part:r SEMI
{: RESULT = new BinaryOperator(sym.LOWER, "<", l, r); :}
| expr_part:l GREATER_EQUAL expr_part:r SEMI
{: RESULT = new BinaryOperator(sym.GREATER_EQUAL, ">=", l, r); :}
| expr_part:l LOWER_EQUAL expr_part:r SEMI
{: RESULT = new BinaryOperator(sym.LOWER_EQUAL, "<=", l, r); :}
;
expr_part ::= NUMBER:n
{: RESULT = new Constant(n); :}
| LBRACKET FLOAT:lo COMMA FLOAT:hi RBRACKET
{: RESULT = new Constant(lo, hi); :}
| LBRACKET NUMBER:lo COMMA NUMBER:hi RBRACKET
{: RESULT = new Constant(lo.doubleValue(), hi.doubleValue()); :}
| LBRACKET FLOAT:lo COMMA NUMBER:hi RBRACKET
{: RESULT = new Constant(lo.doubleValue(), hi.doubleValue()); :}
| LBRACKET NUMBER:lo COMMA FLOAT:hi RBRACKET
{: RESULT = new Constant(lo.doubleValue(), hi.doubleValue()); :}
| VARIABLE:v
{: tmpVariable = (Variable)actionVariablesMap.get(v);
if (tmpVariable == null) {
// Variable mit leerer Domaene instantiieren:
tmpVariable = new Variable(v, new Domain());
actionVariablesMap.put(v, tmpVariable);
}
RESULT = tmpVariable;
:}
| expr_part:l PLUS expr_part:r
{: RESULT = new BinaryOperator(sym.PLUS, "+", l, r); :}
| expr_part:l MINUS expr_part:r
{: RESULT = new BinaryOperator(sym.MINUS, "-", l, r); :}
| expr_part:l TIMES expr_part:r
{: RESULT = new BinaryOperator(sym.TIMES, "*", l, r); :}
| expr_part:l DIVIDE expr_part:r
{: RESULT = new BinaryOperator(sym.DIVIDE, "/", l, r); :}
| MINUS expr_part:e
{: RESULT = new UnaryOperator(sym.UMINUS, "-", e); :}
%prec UMINUS
| LPAREN expr_part:e RPAREN
{: RESULT = e; :}
;