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; :} ;