Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Jaccie-Beispiele Lothar Schmitz 1
[email protected] 20. Juli 2004
Startseite
JJ
II
J
I
Seite 1 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
1 gemeinsam
mit Teilnehmern an der Vorlesung ¨ uber Syntaxbasierte Programmierwerkzeuge an der Universit¨ at der Bundeswehr M¨ unchen im Wintertrimester 2004
Die Beispielsammlung umfasst zwei große und drei kleine Gruppen von Beispielen:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
• Die kleine Gruppe der Bin¨arzahlen-Beispiele geht zur¨uck auf ein Beispiel, mit dem Prof. D. E. Knuth, der Erfinder der Attributierten Grammatiken, seine neue Technik erl¨auterte. Hier demonstrieren wir insbesondere
Geschachtelte Rechtecke Scanner mit Aktionen
– dass sich bei einer Erweiterung der Syntax die Attributierung homogen“ erg¨anzen l¨asst; ” – das Zusammenspiel zwischen ererbten und synthetisierten Attributen; – die Modularisierung einer Attributierung in eine gleichwertige Sequenz von Attributierungen. • Die große Gruppe mit Beispielen zu arithmetischen Ausdr¨ucken zeigt exemplarisch die breite Palette unterschiedlicher Jaccie-Anwendungsm¨oglichkeiten: – – – – –
Ausdr¨ucke mit Variablen interaktiv auswerten; ¨ Ubersetzung in verschiedene Maschinensprachen (MI und Postscript); Erzeugung unterschiedlicher textueller und grafischer Darstellungen; Umwandlung in Postfix-Syntax und zur¨uck; diverse Spracherweiterungen.
• Die große Gruppe mit Beispielen zu geschachtelten Rechtecken zeigt – die schrittweise Berechnung verschiedener grafischer Formate; – geometrische Transformationen am Quelltext.
Startseite
JJ
II
J
I
• Die kleine Gruppe der Telegramme demonstriert die Vielseitigkeit von Scannern mit Aktionsbl¨ocken: – Man kann Telegramme aus Klartext in Morse-Code umwandeln und umgekehrt. – Die Kosten eines Telegramms lassen sich ebenfalls bestimmen. • Die kleine Gruppe der Spracherkennungs-Beispiele demonstriert die M¨achtigkeit von Scannern mit Aktionsbl¨ocken: – Typ-2-Sprachen wie Klammergebirge“ k¨onnen erkannt werden. ” – Typ-2-Sprachen wie {an bn | n ≥ 1} und sogar Typ-1-Sprachen wie {an bn an | n ≥ 1} lassen sich erkennen. Schon diese kleinen Beispiele belegen, welch unterschiedliche Aufgaben man mit unserem Compiler-Compiler Jaccie bearbeiten kann.
Seite 1 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
1. Bin¨ arzahlen
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
1.1. Ganzzahlige Bin¨ arzahlen auswerten
Geschachtelte Rechtecke Scanner mit Aktionen
Lexikalische und syntaktische Struktur festlegen Ganzzahlige Bin¨arzahlen sind Folgen von Nullen und Einsen. In Grammatiken, die attributiert werden sollen, d¨urfen als Tokenbezeichnungen nur Namen verwendet werden, die regul¨are Java-Bezeichner sind, weil in der Attributierung automatisch zu jedem Token namens X ein Pseudoattribut X_string abgeleitet wird. Als lexikalische Elemente verwenden wir hier die englischen Ziffernbezeichnungen (¨uberhaupt verwenden wir ausschließlich englische Bezeichnungen f¨ur Grammatiksymbole und Attribute): Tokendefinitionen: := $0 := $1
Von den folgenden Grammatikregeln dient die erste als Startregel“, in deren Kontext ererbte Attribute initialisiert ” werden k¨onnen: Grammatikregeln: Number -> Digits Digits -> Digits Digit Digits -> Digit Digit Digit
-> zero -> one
Startseite
JJ
II
J
I
Seite 2 von 100
Zur¨ uck
Attribute festlegen Der Wert einer Bin¨arzahl ergibt sich aus den Werten seiner Ziffern, wobei deren Stellengewichte in die Berechnung eingehen. Werte werden von den Bl¨attern zur Wurzel des Syntaxbaums hin berechnet (also in synthetisierten Attributen), Stellengewichte von der Wurzel in Richtung der Bl¨atter (also in ererbten Attributen). Da wir in einem Folgeschritt auch gebrochene Bin¨arzahlen behandeln wollen, verwenden wir den Java-Typ double f¨ur Werte und Gewichte.
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
Attribute und ihre Typen: >value : double Digits Digits_weight = 1; Number_value = Digits_value; Digits -> Digits Digit Digits2_weight = Digits1_weight * 2.0; Digit_weight = Digits1_weight; Digits1_value = Digits2_value + Digit_value; Digits -> Digit Digit_weight = Digits_weight; Digits_value = Digit_value; Digit -> zero Digit_value = 0; Digit -> one Digit_value = Digit_weight;
Startseite
JJ
II
J
I
Seite 3 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Ein Testlauf
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Wir verarbeiten die Ziffernfolge 10101.
Geschachtelte Rechtecke
Der Scanner macht daraus die Tokenfolge
Scanner mit Aktionen
one "1" zero "0" one "1" zero "0" one "1"
Der Parser baut aus der Tokenfolge den Syntaxbaum mit der textuellen Darstellung Number Digits Digits Digits Digit one - string: "1" Digit zero - string: "0" Digit one - string: "1"
Startseite
JJ
II
J
I
Seite 4 von 100
und der Evaluator verziert“ den Baum wie folgt mit Attributwerten ”
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
Number -value:5.0 Digits -weight:1.0 -value:5.0 Digits -weight:2.0 -value:4.0 Digits -weight:4.0 -value:4.0 Digit -weight:4.0 -value:4.0 one -string:1 Digit -weight:null -value:0.0 zero -string:0 Digit -weight:1.0 -value:1.0 one -string:1
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 5 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
1.2. Gebrochene Bin¨ arzahlen auswerten
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Erg¨ anzung der Syntax
Geschachtelte Rechtecke Scanner mit Aktionen
Bei gebrochenen Bin¨arzahlen kommt der Punkt als Token hinzu: := $.
Die Grammatik wird um eine weitere Startregel“erg¨anzt: ” Grammatikregeln: Number -> Digits point Digits
Ein neues Attribut Das Stellengewicht des Nachkommateils h¨angt ab von der L¨ange des Nachkommateils. L¨angen werden von den Bl¨attern zur Wurzel des Syntaxbaums hin berechnet (also in synthetisierten Attributen) und sind ganzzahlig, d.h. vom Java-Typ int. >length : int
L¨angen beziehen sich auf Ziffernfolgen. Daher ergibt sich insgesamt die folgende Zuordnung. Nonterminals und ihre Attribute: Number : value Digits : value weight length Digit : value weight
Startseite
JJ
II
J
I
Seite 6 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Zus¨ atzliche Attributauswertungsregeln
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Durch die neue Grammatikregel und das neue Attribut kommen ein paar Auswertungsregeln hinzu (man beachte, dass die fr¨uheren unver¨andert erhalten bleiben - Attributierungen k¨onnen im positiven Sinn modular aufgebaut sein!)
Geschachtelte Rechtecke Scanner mit Aktionen
Attributauswertungsregeln: Number -> Digits point Digits Digits1_weight = 1; Digits2_weight = 1.0 / exp(2.0, Digits2_length); Number_value = Digits1_value + Digits2_value; Number -> Digits Number_value = Digits_value; Digits -> Digits Digit Digits1_length = Digits2_length + 1; Digits -> Digit Digits_length = 1;
Zur Berechnung von Digits2_weight wird ein Exponentiationsoperator ben¨otigt, den es in Java standardm¨aßig nicht gibt und deshalb (im Unterbereich Evaluator - Definition - Actions - Java“) wie folgt implementiert wird: ” public static double exp (double b, int e) { double result = 1.0; while (e 0) { result = result * b; e = e - 1; } return result; }
Startseite
JJ
II
J
I
Seite 7 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Ein Testlauf Aus der Ziffernfolge 1.11 erhalten wir mit Scanner, Parser und Evaluator:
Beenden
Bin¨ arzahlen
Number -value:1.75 Digits -length:null -weight:1.0 -value:1.0 Digit -weight:1.0 -value:1.0 one -string:1 point -string:. Digits -length:2 -weight:0.25 -value:0.75 Digits -length:1 -weight:0.5 -value:0.5 Digit -weight:0.5 -value:0.5 one -string:1 Digit -weight:0.25 -value:0.25 one -string:1
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 8 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
1.3. Modularisierung der Attributierung
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Die bisher entwickelte Attributierung l¨asst sich bequem in drei Teilattributierungen aufteilen: • die erste Teilattributierung wertet nur das length-Attribut aus • die zweite Teilattributierung wertet nur das weight-Attribut aus • die dritte Teilattributierung wertet nur das value-Attribut aus
Geschachtelte Rechtecke Scanner mit Aktionen
Auf diese Weise lassen sich große Attributierungen in inhaltlich zusammengeh¨orige“ Teilattributierungen aufteilen ” und dadurch besser u¨berblicken. Außerdem k¨onnen Teilattributierungen evtl. wiederverwendet werden.
1.4. Eine g¨ unstigere Syntax Wir haben das Beispiel unn¨otig kompliziert behandelt (und damit missbraucht“), um Begriffe und Techniken zu ” demonstrieren. Wenn man die Syntax ein wenig anpasst, kommt man hier mit einen einzigen Attribut gut aus: Grammatik- und Attributauswertungsregeln: Number -> LeftDigits point RightDigits Number_value = LeftDigits_value + RightDigits_value; Number -> LeftDigits Number_value = LeftDigits_value; LeftDigits -> LeftDigits Digit LeftDigits1_value = LeftDigits2_value*2.0 + Digit_value; LeftDigits -> Digit LeftDigits_value = Digit_value;
Startseite
JJ
II
J
I
Seite 9 von 100
Zur¨ uck
RightDigits -> Digit RightDigits RightDigits1_value = (RightDigits2_value + Digit_value)/2.0; RightDigits -> Digit RightDigits_value = Digit_value/2.0; Digit -> bit Digit_value = (bit_string.equals("0") ? 0 : 1);
Vollbild ein/aus
Schließen
Beenden
2. Arithmetische Ausdru ¨ cke
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Die folgende Syntax ist Basis verschiedener, darauf aufbauender Attributierungen.
Geschachtelte Rechtecke Scanner mit Aktionen
2.1. Syntaxbeschreibung Lexikalische Ebene Neben der Angabe Standard bei Separators“ besteht die Scannerdefinition i.W. aus Tokendefinitionen, die auf ” folgenden regul¨ aren Hilfsausdr¨ ucken (benannten Patterns“) beruhen: ” Patterns:
:= := := := := := := :=
($+ | $-) ($* | $/) $( $) ({$a-$z}|{$A-$Z}) {$0-$9} ( | )[0-*] [1-*]
Namensmuster beginnen also mit einem Buchstaben, auf den beliebig viele Buchstaben und/oder Ziffern folgen. Ein Zahlmuster ist einfach eine nicht-leere Folge von Ziffern. Die folgenden Tokendefinitionen f¨uhren die Namen der Token ein, die in der kontextfreien Grammatik als terminale Zeichen erscheinen.
Startseite
JJ
II
J
I
Seite 10 von 100
Zur¨ uck
Tokens:
:= := := := := :=
Vollbild ein/aus
Schließen
Beenden
Kontextfreie Grammatik
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Die folgende kontextfreie Grammatik enth¨alt genau die oben eingef¨uhrten Token als terminale Zeichen. Es handelt sich um die aus der Literatur wohlbekannte Grammatik, welche die Pr¨azedenzen der Operatoren richtig und eindeutig wiedergibt. Das zus¨atzliche Startsymbol Arithmetic sowie die zugeh¨orige Startregel“ dienen als Aufh¨anger f¨ur die ” Initialisierung ererbter Attribute.
Geschachtelte Rechtecke Scanner mit Aktionen
Terminals: name number addOp multOp openingBracket closingBracket Nonterminals: Arithmetic Expression Term Factor
Startseite
Startsymbol: Arithmetic
JJ
II
Rules: Arithmetic -> Expression
J
I
Seite 11 von 100
Expression -> Expression addOp Term -> Term Term
-> Term multOp Factor -> Factor
Zur¨ uck
Vollbild ein/aus
Schließen
Factor
-> openingBracket Expression closingBracket -> number -> name
Beenden
2.2. Arithmetische Ausdr¨ ucke interaktiv auswerten
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Wir wollen arithmetische Ausdr¨ucke ohne Informationsverlust“ auswerten und das Ergebnis als gek¨urzten Bruch ” ausgeben. Da Java den ben¨otigten Typ nicht standardm¨aßig zur Verf¨ugung stellt, arbeiten wir mit der StringDarstellung von Zahlen und implementieren darauf die vier Grundrechnungsarten (und das K¨urzen) selbst. Die folgenden Methoden werden unter Evaluator - Definition - Java - Methods“ auszuprogrammieren sein (die vollst¨andigen ” Methodentexte findet man in der Datei ArithEvaluator.edef).
Geschachtelte Rechtecke Scanner mit Aktionen
static String addOp(String op, String left, String right); static String multOp(String op, String left, String right); static String kuerzen(int a, int b);
Die Zahlwerte von (Teil-)Ausdr¨ucken werden also in synthetisierten value-Attributen vom Typ String gehalten. Laut Syntax d¨urfen Ausdr¨ucke auch (Variablen-)Namen enthalten. Selbstverst¨andlich stehen gleiche Namen f¨ur gleiche Werte. Vor Auswertung des Ausdrucks m¨ussen die Variablen Werte erhalten. Wir sammeln dazu s¨amtliche im Ausdruck vorkommenden Namen u¨ber synthetisierte, mengenwertige Attribute variables vom Typ HashSet auf. F¨ur jeden im Gesamtbaum vorkommenden Namen erfragen wir vom Benutzer einen ganzzahligen Wert. Anschließend propagieren wir die so entstandene Menge von (Name, Wert)-Paaren u¨ber ererbte environment-Attribute vom Typ HashMap in den ganzen Baum, so dass die Werte f¨ur die Auswertung u¨berall verf¨ugbar sind. Wir haben also drei Arten von Attributen (> kennzeichnet ein synthetisiertes, < ein ererbtes Attribut). Attribute und ihre Typen: >value : String >variables : HashSet number Factor_variables = new HashSet();
Scanner mit Aktionen
Factor -> name Factor_variables = new HashSet(); Factor_variables.add(name_string);
Diese Mengen werden f¨ur zusammengesetzte Ausdr¨ucke vereinigt: Term1 -> Term2 multOp Factor Term1_variables = new HashSet(); Term1_variables.addAll(Term2_variables); Term1_variables.addAll(Factor_variables);
Analog bei der Regel Expression1 -> Expression2 addOp Term. Schließlich wird f¨ur jeden im obersten ExpressionKnoten angekommenen Namen vom Benutzer ein Wert erfragt und so das Attribut Expression_environment berechnet (dessen Wert dann unver¨andert nach unten propagiert wird): Arithmetic -> Expression Iterator variablesIterator = Expression_variables.iterator(); Expression_environment = new HashMap(); while (variablesIterator.hasNext()) { String variableName = (String) variablesIterator.next(); String inputValue = null; boolean ok = false; while (!ok) { inputValue = JOptionPane.showInputDialog( "Please input a value for " + variableName); try{Integer.parseInt(inputValue); ok=true;} catch (Exception e) {ok = false;} } Expression_environment.put(variableName, inputValue); }
Startseite
JJ
II
J
I
Seite 13 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Die Berechnung der Zahlwerte beginnt wieder im Kontext der zwei Factor-Regeln:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Factor -> number Factor_value = number_string;
Geschachtelte Rechtecke Scanner mit Aktionen
Factor -> name Factor_value = (String) Factor_environment.get(name_string);
Dann werden die Teilausdr¨ucke arithmetisch verkn¨upft: Expression -> Expression addOp Term Expression1_value = addOp(addOp_string, Expression2_value, Term_value); Term -> Term multOp Factor Term1_value = multOp(multOp_string, Term2_value, Factor_value);
und die Werte ansonsten bis zur Wurzel des Syntaxbaums durchgereicht. S¨amtliche Attributauswertungsregeln findet man in der Datei ArithEvaluator.edef.
Startseite
JJ
II
J
I
Seite 14 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
2.3. Textuelle Darstellungen
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Konversion in Pr¨ afix- und Postfix-Darstellung – Thomas G¨ otzinger
Geschachtelte Rechtecke Scanner mit Aktionen
Zum arithmetischen Ausdruck mit der Infix-Darstellung a*a - (a-2)*b + b*(b+1)
erh¨alt man die (klammerfreie!) Pr¨afix-Darstellung + - * a a * - a 2 b * b + b 1
und die Postfix-Darstellung (auch ohne Klammern!) a a * a 2 - b * - b b 1 + * +
Um die Struktur des Ergebnisses zu verdeutlichen, sollen • die Operatoren, Namen und Zahlen jeweils in eine eigene Zeile geschrieben werden; • Teilausdr¨ucke gegen¨uber ihren Operatoren jeweils eine Stufe (drei Blanks) weiter einger¨uckt werden. Das ergibt die Pr¨afix-Darstellung +
Startseite
* a a
JJ
II
J
I
* Seite 15 von 100
a 2
Zur¨ uck
b Vollbild ein/aus
* b +
Schließen
b 1
Beenden
und analog eine Postfix-Darstellung.
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
a a
Geschachtelte Rechtecke
*
Scanner mit Aktionen
a 2 b * b b 1 + * +
F¨ur die erste Attributierung, die zum Infix-Ausdruck den einger¨uckten Pr¨afix-Ausdruck aufbaut, ben¨otigen wir zwei Attribute: Den Pr¨ afix-Ausdruck bauen wir in einem Attribut prefix vom Typ String auf. Da die Berechnung von den Bl¨attern hin zur Wurzel erfolgen wird, handelt es sich um ein synthetisiertes Attribut. F¨ur das Einr¨ ucken verwenden wir ein zweites Attribut, indentation vom Typ String, in dem wir zu jedem Teilausdruck einen passenden Einr¨uckstring erzeugen. Der Einr¨uckstring des Gesamtausdrucks ist leer. Von einem Ausdruck zu seinen unmittelbaren Teilausdr¨ucken verl¨angert sich die Einr¨uckung um jeweils drei Leerzeichen. Da die Berechnung von der Wurzel in Richtung der Bl¨atter hin l¨auft, handelt es sich um ein ererbtes Attribut.
Startseite
JJ
II
J
I
Seite 16 von 100
Wir haben also f¨ur diesen Teil der Aufgabe zwei Attribute: >prefix : Expression Expression_identation = "";
Nach der Initialisierung erfolgt der weitere Aufbau nach verschiedenen Regeln: Wird ein Nonterminal nur auf ein weiteres Nonterminal abgebildet, ver¨andert sich der Einr¨uckstring nicht. Expression -> Term Term_identation = Expression_identation; Term -> Factor Factor_identation = Term_identation; Factor -> openingBracket Expression closingBracket Expression_identation = Factor_identation;
Wird der Ausdruck aus mehreren Teilausdr¨ucken gebildet, so wird der Einr¨uckstring der Teilausdr¨ucke aus dem aktuellen Einr¨uckstring konkateniert mit drei Blanks gebildet. Expression1 -> Expression2 addOp Term Expression2_identation = " " + Expression1_identation; Term_identation = " " + Expression1_identation; Term1 -> Term2 multOp Factor Term2_identation = " " + Term1_identation; Factor_identation = " " + Term1_identation;
Startseite
JJ
II
J
I
Seite 17 von 100
Zur¨ uck
Vollbild ein/aus
Nach dem der Aufbau des Einr¨uckstrings erl¨autert wurde, soll nun der Prefixterm erzeugt werden. Dies erfolgt von den Bl¨attern hin zur Wurzel. Die Zahlen und Variablen werden durch das Nonterminal Factor in den Prefixterm aufgenommen. Dabei wird jeweils der Einr¨uckstring vorangestellt.
Schließen
Beenden
Bin¨ arzahlen
Factor -> number Factor_prefix = Factor_identation + number_string;
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Factor -> name Factor_prefix = Factor_identation + name_string;
Wird ein Nonterminal nur auf ein weiteres Nonterminal abgebildet, ver¨andert sich der Prefix nicht. Factor ->openingBracket Expression closingBracket Factor_prefix = Expression_prefix; Term -> Factor Term_prefix = Factor_prefix; Expression -> Term Expression_prefix = Term_prefix; Arithmetic -> Expression Arithmetic_prefix = Expression_prefix;
Wird der Prefixausdruck eines Nonterminals aus mehreren Teilausdr¨ucken gebildet, so wird der Prefix des Nonterminals wie folgt zusammengesetzt (zum Verst¨andnis siehe auch Notation eines Prefix in der Aufgabenstellung): Expression1 -> Expression2 addOp Term Expression1_prefix = Expression1_identation + addOp_string + "\n" + Expression2_prefix + "\n" + Term_prefix; Term1 -> Term2 multOp Factor Term1_prefix = Term1_identation + multOp_string + "\n" + Term2_prefix + "\n" + Factor_prefix;
Startseite
JJ
II
J
I
Seite 18 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Nach der Beschreibung des Aufbaus der Attributierung von Infix zu Prefix ergibt sich die Postfixnotation v¨ollig analog: Man ben¨otigt ein zus¨atzliches Attribut postfix vom Typ String. Da dieses ebenfalls zu Wurzel hin ausgewertet wird, handelt es sich um ein synthetisiertes Attribut: >postfix
:
String
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Zu der im ersten Teil der Aufgabe angegebenen Zuordnung von Nonterminalen zu Attributen ergibt sich durch das Hinzuf¨ugen eines weiteren Attributes folgende Sicht: Arithmetic Expression Term Factor
: : : :
prefix postfix identation prefix postfix identation prefix postfix identation prefix postfix
An dem im ersten Teil der Aufgabe erl¨auterten Berechnung des Attribute identation ¨andert sich hier nichts. Der Aufbau des Postfixterms ist analog zum Prefixterm. Die ver¨anderte Reihenfolge ergibt aus folgenden Regeln: Expression1 -> Expression2 addOp Term Expression1_postfix = Expression2_postfix + "\n" + Term_postfix + "\n" + Expression1_identation + addOp_string; Term1 -> Term2 multOp Factor Term1_postfix = Term2_postfix + "\n" + Factor_postfix + "\n" + Term1_identation + multOp_string;
Startseite
JJ
II
J
I
Seite 19 von 100
Zur¨ uck
S¨amtliche Auswertungsregeln findet man auch in der Datei infix2prepostfix.edef. Vollbild ein/aus
Schließen
Beenden
Konversion von Pr¨ afix nach Infix – Roman Goltz
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Zur Syntax: Auf der lexikalischen Ebene unterscheidet sich die Pr¨afix-Form von der Infix-Form durch das Fehlen von Klammern. Es ist aber durchaus m¨oglich, einfach den Scanner f¨ur die Infix-Form zu verwenden.
Geschachtelte Rechtecke Scanner mit Aktionen
Die kontextfreie Grammatik ist aber deutlich einfacher, da nicht nur die Klammern fehlen, sondern auch die Bindungen der Operatoren durch ihre Reihenfolge komplett festgelegt sind. Die Regeln der Grammatik lauten: Rules: Prefix
-> PrefixExpression
PrefixExpression -> PrefixOperator PrefixExpression PrefixExpression -> PrefixFactor PrefixFactor
-> name -> number
PrefixOperator
-> addOP -> multOp
Der Grammatik-Check ergibt f¨ur alle Parser-Typen, dass die Grammatik deterministisch ist. ¨ Unser erstes Ziel ist die Ubersetzung eines Pr¨afix-Ausdrucks in einen vollst¨ andig geklammerten Infix-Ausdruck. F¨ur den Pr¨afix-Ausdruck
Startseite
JJ
II
J
I
Seite 20 von 100
+ - * a a * - a 2 b * b + b 1 Zur¨ uck
erg¨abe das die Infix-Darstellung Vollbild ein/aus
(((a * a) - ((a - 2) * b)) + (b * (b + 1))) Schließen
mit vielen u¨berfl¨ussigen Klammern. Beenden
Die Attributierung kommt mit einem einzigen synthetisierten Attribut infix vom Typ String aus, da Einr¨uckungen nicht erforderlich sind.
Diese Attributierung ist eigentlich sehr u¨berschaubar. Man f¨angt bei den Grundelementen an, in unserem Fall die Terminale name, number, addOp und multOp. Diese stammen alle vom PrefixFactor ab und geben dem PrefixFactor.infix jeweils ihren eigenen String Wert.
Bin¨ arzahlen
Nun muss man nur noch die PrefixFactoren zu Expressions zusammenf¨ugen.Ist der PrefixExpression nur ein Prefixfactor, wird der Infix-Wert nur eine Ebene h¨ohergereicht, ohne ver¨andert zu werden.
Scanner mit Aktionen
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
Am interessantesten sind zusammengestzte Prefixexpressions. Die Regel f¨ur deren infix-Wert ist: PrefixExpression1_infix = "(" + PrefixExpression2_infix + PrefixOperator_infix + PrefixExpression3_infix + ")";
Wenn man in der vollst¨andig geklammerten Infix-Darstellung (((a * a) - ((a - 2) * b)) + (b * (b + 1)))
die ¨außeren Klammern streicht und auch die Klammern um Teilausdr¨ucke, deren Operator eine h¨ohere Priorit¨at hat als der Operator des unmittelbar umgebenden Ausdrucks, dann erh¨alt man die reduzierte Infix-Darstellung (a * a - (a - 2) * b) + b * (b + 1)
die wir in einer zweiten Attributierung herstellen wollen. Dazu ordnen wir den Operatoren als level die Priorit¨aten • 1 (f¨ur den addOp +),
Startseite
JJ
II
J
I
Seite 21 von 100
Zur¨ uck
• 2 (f¨ur den addOp -), • 3 (f¨ur den multOp *) und • 4 (f¨ur den multOp /) zu. Die Ausdr¨ucke erhalten als enclosingLevel die Priorit¨aten ihrer umgebenden Ausdr¨ucke:
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
Prefix -> PrefixExpression PrefixExpression_enclosingLevel = 0; PrefixOperator -> addOP PrefixOperator_level = (addOp_string.equals("+")?1:2);
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
PrefixOperator -> multOp PrefixOperator_level = (multOp_string.equals("*")?3:4); PrefixExpression -> PrefixOperator PrefixExpression PrefixExpression PrefixExpression2_enclosingLevel = PrefixOperator_level; PrefixExpression3_enclosingLevel = PrefixOperator_level;
Man beachte, dass bei dieser Zuordnung assoziative Operatoren eine ungerade Priorit¨at haben. Und: Die nichtassoziativen Operatoren der gleichen Tokenklasse haben eine um eins h¨ohere Priorit¨at. Nach dieser Vorarbeit ist der letzte Schritt nicht mehr schwer: Der Knackpunkt ist die Berechnung des Attributs infix im Zusammenhang mit der letzten Grammatikregel. Hier muss man die Wertigkeiten der verschiedenen Prefixoperatoren nach den vorgegebenen Regeln einarbeiten. Dies geschieht im folgenden Anweisungsblock, der entscheidet, ob die Klammern ben¨otigt werden oder nicht: PrefixExpression -> PrefixOperator PrefixExpression PrefixExpression boolean lessThan = ( PrefixExpression1_enclosingLevel < PrefixOperator_level ); boolean isEqual = ( PrefixExpression1_enclosingLevel == PrefixOperator_level ); boolean isAssoc = ( PrefixOperator_level % 2 == 1 ); boolean omit = ( lessThan || ( isEqual && isAssoc ) ); PrefixExpression1_infix = ( omit ? "" : "(" ) + PrefixExpression2_infix + PrefixOperator_infix + PrefixExpression3_infix + ( omit ? "" : ")" );
Startseite
JJ
II
J
I
Seite 22 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Klammern k¨onnen genau dann weggelassen werden, wenn der umgebende Ausdruck ein geringeres Pr¨azedenzniveau hat als der betrachtete oder wenn beide das gleiche Pr¨azedenzniveau haben und der aktuelle Operator assoziativ ist.
Dazu als Beispiel die Eingabezeichenreihe:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
- * 10 + 1 2 * * a 50 - a b
Geschachtelte Rechtecke Scanner mit Aktionen
Auswertung ergibt: Prefix -infix:10*(1+2)-a*50*(a-b)
Startseite
JJ
II
J
I
Seite 23 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Konversion Infix nach MathML – Alexander Loechel
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Jetzt wollen wir eine Konversion von arithmetischen Ausdr¨ucken in den XML Subset MathML betrachten.
Geschachtelte Rechtecke Scanner mit Aktionen
MathML 2.0 ist eine W3C Recommendation vom 21. Februar 2001. Sie wurde f¨ur die Pr¨asentation und Beschreibung mathematischer Ausdr¨ucke entwickelt. F¨ur die Arithmetischen Ausdr¨ucke ben¨otigen wir die MathML-Tags: • + : • - : • * : • / : Die Syntax von MathML wird in Polnischer Notation geschrieben. In MathML wird jede Anwendung eines Operators im (durch Einr¨uckungen hervorgehobene) Format: Startseite
kenntlich gemacht. Zahlkonstanten werden in Tag-Paare ... eingeschlossen, Variablen-Namen in TagPaare .... Ein Beispiel zeigt uns, wie die MathMl-Form zu einem arithmetischen Ausdruck gebildet wird: (a + 2) ∗ (a − 2) 2∗b lautet in MathML-Form
JJ
II
J
I
Seite 24 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
a 2 a 2 2 b
In diesem Fall k¨onnen wir die bereits beschriebenen Scanner und Parser f¨ur arithmetische Ausdr¨ucke weiterverwenden und m¨ussen nur einen neuen Evaluator erzeugen. Den MathML-Code k¨onnen wir durch Baumtransformation am Ergebnis des Parser erzeugen. In Jaccie wird dies durch Attributierung getan. Den MathML-Code bauen wir in einem Attribut mathML vom Typ String auf. Da die Berechnung von den Bl¨attern hin zur Wurzel erfolgen wird, handelt es sich um ein synthetisiertes Attribut.
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 25 von 100
Zur¨ uck
Vollbild ein/aus
F¨ur das Einr¨ ucken verwenden wir ein zweites Attribut, indentation vom Typ String, in dem wir zu jedem Teilausdruck einen passenden Einr¨uckstring erzeugen. Der Einr¨uckstring des Gesamtausdrucks ist leer. Von einem Ausdruck zu seinen unmittelbaren Teilausdr¨ucken verl¨angert sich die Einr¨uckung um jeweils drei Leerzeichen. Da die Berechnung von der Wurzel in Richtung der Bl¨atter hin l¨auft, handelt es sich um ein ererbtes Attribut.
Schließen
Beenden
Zur Startregel
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Arithmetik -> Expression
Geschachtelte Rechtecke Scanner mit Aktionen
sind die entsprechenden Attributauswertungsregeln: Arithmetic_mathML = "" + "\n" + "" + "\n" + "" + "\n" + Expression_mathML + "\n" + ""; Expression_indentation = "";
Wie oben besprochen wird hier das indentation Attribut mit "" initialisiert. Das MathML-Code Attribut mathML von Arithmetik wird hier ausf¨uhrlich und komplett mit dem XML-Header erzeugt. Die kurze Form Startseite
Arithmetic_mathML = "" + "\n" + Expression_mathML + "\n" + "";
w¨urde zwar gen¨ugen, um das Resultat in andere XML Dokumente einzubetten, so ist es aber schon selber ein vollst¨andiges Dokument, welches getestet werden kann.
JJ
II
J
I
Seite 26 von 100
Zur¨ uck
Sehr interessant sind bei der Konversion von arithmetischen Ausdr¨ucken die zwei Regeln, in denen Operatoren vorkommen.
Vollbild ein/aus
Bei Schließen
Term -> Term multOp Factor
Beenden
sind drei Attribute gem¨aß folgenden Attributauswertungsregeln zu berechnen:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Term2_indentation = Term1_indentation + "
";
Geschachtelte Rechtecke Scanner mit Aktionen
Factor_indentation = Term1_indentation + "
";
String opM = multOp_string.equals("*")?"":""; Term1_mathML = Term1_indentation + "" + "\n" + Term2_indentation + opM + "\n" + Term2_mathML + "\n" + Factor_mathML + "\n" + Term1_indentation + "";
Interessant ist vor allem die dritte Auswertungsregel, die mit der Berechnung der Hilfsvariablen op beginnt. op enth¨alt , wenn der Operator im eingegebenen arithmetischen Ausdruck ein * war, sonst . In der Zuweisung an Term1_mathML wird jede aufgebaute Zeile mit dem Zeilenendestring "\n" abgeschlossen. Den Zeilen mit den Apply-Tags wird der passende Einr¨uckstring vorangestellt. Die eingef¨ugten Teilausdr¨ucke (Term2_mathML und Factor_mathML) bringen ihre Einr¨uckungen (und interne Zeilenwechsel) selber mit. Analog dazu die folgenden Regeln:
Startseite
Expression1 -> Expression2 addOp Term Expression2_indentation = Expression1_indentation + " Term_indentation = Expression1_indentation + "
";
";
String op = addOp_string.equals("+")?"":""; Expression1_mathML = Expression1_indentation + "" + "\n" + Expression2_indentation + op + "\n" + Expression2_mathML + "\n" + Term_mathML + "\n" + Expression1_indentation + "";
JJ
II
J
I
Seite 27 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
¨ was einer direkten Ubertragung der Regeln f¨ur den multOp entspricht.
Abschliessend m¨ussen nur noch die Blattelemente des Syntaxbaums mit Attributregeln versehen werden, wobei nur die f¨ur MathML gew¨unschte Kennzeichnung umschliessend hinzugef¨ugt wird:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
Factor -> number Factor_mathML = Factor_indentation + "" + number_string + "";
Scanner mit Aktionen
Factor -> name Factor_mathML = Factor_indentation + "" + name_string + "";
Die restlichen Attributauswertungsregeln sind Transfer“-Regeln, die Attributwerte unver¨andert weiterreichen (das ” einzig beachtenswerte hierbei ist, dass Klammern ignoriert werden k¨onnen, da MathML ja die Polnische Notation benutzt). Mit diesem Regelsatz kann jetzt jeder beliebige arithmetische Ausdruck in ein MathML Dokument transfomiert werden, diese Dokumente k¨onnen jetzt mit modernen Browsern bzw. mit gewissen PlugIn versehenen Tools angesehen werden.
Startseite
JJ
II
J
I
Seite 28 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Konversion MathML nach Infix– Andreas Jaehmlich
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Der MathML-Scanner muss die Tags der MathML-Darstellung als Token erkennen. Dazu die folgenden Tokendefinitionen:
Geschachtelte Rechtecke Scanner mit Aktionen
Hier erst einmal die Pattern, die dann den Token zugewiesen werden:
:= := := := := := := := := := := :=
"" "" "" "" "" "" "" | "" " | "" ({a-z}|{A-Z}) {0-9} ( | )[0-*] (1-*) Startseite
Nun die Token:
:= := := := := := := :=
JJ
II
J
I
Seite 29 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Als MathML-Parser-Definition wird eine Grammatik mit folgenden Regeln verwendet:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
MathML
-> Expression
Geschachtelte Rechtecke Scanner mit Aktionen
MathMLExpression -> applyBegin MathMLOperator MathMLExpression MathMLExpression applyEnd -> MathMLFactor MathMLFactor
-> ciBegin name ciEnd -> cnBegin number cnEnd
MathMLOperator
-> plusOp -> multOp
Die Attributierung kommt mit einem einzigen synthetisierten Attribut aus, da Einr¨uckungen nicht erforderlich sind und weil wir der Einfachheit halber den Infix-Ausdruck vollst¨andig geklammert erzeugen. Das schon erw¨ahnte einzige Attribut ist das synthetisiertes Attribut Ausdruck vom Typ String. Synthetisiert, weil wir an den Wurzeln beginnend den gesamten Ausdruck zusammensetzen. Jedem Nonterminal ist das Attribut Ausdruck genau einmal zugewiesen: MathMl : >Ausdruck Expression : >Ausdruck Operator : >Ausdruck Factor : >Ausdruck
Startseite
JJ
II
J
I
Seite 30 von 100
Zur¨ uck
Vollbild ein/aus
Attributauswertungsregeln sind eigentlich nur an einer Stelle interessant, n¨amlich bei der Regel: Schließen
Expression -> applyBegin Operator Expression Expression applyEnd Beenden
wo sie die Reihenfolge von Prefix (MathMl) auf Infix umstellen.
Das leistet die folgende Auswertungsregel
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Expression1_Ausdruck = "(" + Expression2_Ausdruck + Operator_Ausdruck + Expression3_Ausdruck + ")";
Geschachtelte Rechtecke Scanner mit Aktionen
Die Reihenfolge wird “gedreht“und f¨ur und werden ¨offnende bzw. schließende Klammern gesetzt. Nur noch bei einer Regel wird etwas ausgewertet, n¨amlich die Operatoren selbst. z.B.: Operator -> multOp
Hier ist zu entscheiden ob multipliziert oder dividiert werden soll. Dazu wird in einem If-Konstrukt das Operationszeichen in einen Zwischen- String gelesen, der dann an den Operator_Ausdruck u¨bergeben wird: String op = plusOp_string.equals("")?"+":"-"; Operator_Ausdruck = op;
An anderer Stelle wird der Wert nur “durchgeschleift“, aber ¨andert sich nicht. R¨uck¨ubersetzung der im letzen Abschnitt erzeugten MathML-Formel ergibt
Startseite
JJ
II
J
I
(((a+2)*(a-2))/(2*b)) Seite 31 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Kantorovic-Baum – von Richard Schack und Thorsten Urban
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Der folgende arithmetische Ausdruck a*a - 2*a*b + b*b
Geschachtelte Rechtecke Scanner mit Aktionen
hat die Kantorovic-Baum-Darstellung + |\ | * | |\ | | b | | | b | |\ | * | |\ | | b | | | * | |\ | | a | | | 2 | * |\ | a | a
Beachte: Der linke Operand steht jeweils weiter unten als der rechte!
Startseite
JJ
II
J
I
Seite 32 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bei der Erzeugung des Kantorovic-Baums entsteht die String-Darstellung des kompletten Baums aus den Textdarstellungen der Teilb¨aume. Dabei gilt es genau aufzupassen: Der linke Teilbaum folgt jeweils am unteren Ende(!) nach dem rechten Teilbaum, der rechte zwei Zeilen nach dem Operator-Symbol. Der Darstellung des rechten Teilbaums geht links jeweils ein St¨uck des senkrechten Strichs voran, der zum linken Teilbaum f¨uhrt.
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Wegen der rekursiven Schachtelung von Teilausdr¨ucken empfiehlt es sich, zwei Arten von Attributen zu verwenden: text-Attribute vom Typ String zum Aufbau der Texte der Teilb¨aume und prefix-Attribute vom Typ String, in denen die (korrekt einger¨uckten) Strichfolgen stehen, die zu weiter unten folgenden, linken Teilausdr¨ucken f¨uhren. Die text-Attribute ordnen wir allen nichtterminalen Symbolen zu, die prefix-Attribute nur den Symbolen f¨ur (einzur¨uckende) Teilausdr¨ucke. Die text-Attribute werden wie die Attribute der ersten Attributierung von den Bl¨attern zur Wurzel hin“ berechnet, ” sind also synthetisiert. Die prefix-Attribute dagegen werden von der Wurzel zu den Bl¨attern hin“ aufgebaut, sind ” also ererbt. Insgesamt erhalten wir (> kennzeichnet ein synthetisiertes, < ein ererbtes Attribut): Nonterminals: Expression Term Factor S
>text text text text
Startseite
Die Regeln zu Factor sind praktisch selbsterkl¨arend:
JJ
II
Factor -> number Factor_text = Factor_prefix + number_string;
J
I
Seite 33 von 100
Factor -> name Factor_text = Factor_prefix + name_string; Factor -> openingBracket Expression closingBracket Factor_text = Expression_text; Expression_prefix = Factor_prefix;
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Besonders interessant sind die Auswertungsregeln zur ersten Grammatikregel zu E:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Expression -> Expression addOp Term Expression1_text = Expression1_prefix + addOp_string + "\n" + Expression1_prefix + "|" + "\\" + "\n" + Term_text + "\n" + Expression1_prefix + "|" + "\n" + Expression2_text; Expression2_prefix = Expression1_prefix; Term_prefix = Expression1_prefix + "| ";
Geschachtelte Rechtecke Scanner mit Aktionen
Die Textdarstellung des Expression1-Ausdrucks beginnt in der ersten Zeile mit dem Operatorsymbol, dem die Linienst¨ucke noch auf Expression1 folgender Ausdr¨ucke vorangestellt sind. In der zweiten Zeile folgt hinter dem gemeinsamen Pr¨afix (von Expression1) die Gabelung zwischen den beiden Teilausdr¨ucken. In den n¨achsten Zeilen folgt der rechte Teilausdruck Term, dem zus¨atzlich zum gemeinsamen Pr¨afix die senkrechten Striche hin zu Expression2 vorangehen (das entnimmt man der Auswertungsregel zu Term.prefix). In der vorletzten Zeile von Expression1.text folgt das letzte St¨uck des Strichs zum Teilausdruck Expression2, der ganz unten angef¨ugt wird. Die Auswertungsregel zu Expression2.prefix zeigt, dass Expression2 gleich weit einger¨uckt ist wie Expression1. Startseite
Die Auswertungsregeln zur zweiten Grammatikregel zu Expression besteht aus Transferregeln“, die Informationen ” in beide Richtungen unver¨andert weiterreichen: Expression -> Term Expression_text = Term_text; Term_prefix = Expression_prefix;
JJ
II
J
I
Seite 34 von 100
Zur¨ uck
Die Regeln zu Term sind vollst¨andig analog.
Vollbild ein/aus
Schließen
Beenden
2.4. Code-Erzeugung
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
MI-Code-Generierung – Andreas H¨ anel
Geschachtelte Rechtecke Scanner mit Aktionen
Der folgende arithmetische Ausdruck a*a - 2*a*b + b*b
l¨asst sich durch Ausf¨uhrung des folgenden MI-Codes auswerten b: DD 17 a: DD 4 MOVE MOVE MULT MOVE MOVE MULT MOVE MULT SUB MOVE MOVE MULT ADD
W W W W W W W W W W W W W
a , -!SP a , -!SP !SP+, !SP+, I 2 , -!SP a , -!SP !SP+, !SP+, b , -!SP !SP+, !SP+, !SP+, !SP+, b , -!SP b , -!SP !SP+, !SP+, !SP+, !SP+,
-!SP
-!SP -!SP -!SP
-!SP -!SP
Startseite
JJ
II
J
I
Seite 35 von 100
Die ersten vier Zeilen reservieren Speicherplatz f¨ur die beiden Variablen und initialisieren sie. Die Variablen-Werte (17 f¨ur b und 4 f¨ur a) werden – ¨ahnlich wie beim Auswerter – vom Benutzer erfragt, nachdem die Menge der im Ausdruck vorkommenden Variablen bestimmt wurde und bevor die eigentliche Code-Generierung beginnt.
Zur¨ uck
Vollbild ein/aus
Ein MOVE-Befehl schiebt den Wert einer Variablen oder die direkt angegebene Zahlkonstante 2 in den Keller.
Schließen
Die arithmetischen Befehle (ADD, SUB, MULT) entnehmen die Operanden dem Keller und ersetzen sie dort durch das Operationsergebnis.
Beenden
¨ Bei der Ubersetzung in Maschinensprache entsteht das komplette Programm aus Code-St¨ucken. Wir verwenden daher code-Attribute vom Typ String und ordnen diese allen nichtterminalen Symbolen der Grammatik zu. StringKonstanten werden mit doppelten Hochkommata geschrieben. Unsere Ausdr¨ucke enthalten Variablen, f¨ur die zu Beginn der Code-Sequenz Speicherplatz beschafft werden soll – f¨ur jede Variable genau ein Speicherwort. Um alle Variablen, die im Ausdruck vorkommen aufzusammeln, verwenden wir ein Attribut variables vom Typ Set of String (es handelt sich um Mengen von Namen). Beide Attribute werden von den Bl¨attern zur Wurzel hin“ ” berechnet, sind also beide synthetisiert.
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Insgesamt erhalten wir also ( kennzeichnet ein synthetisiertes Attribut): Nonterminals: E code variables T code variables F code variables S code
In den folgenden Attributauswertungsregeln bezeichnet codeE2 das code-Attribut des zweiten Vorkommens der syntaktischen Variablen E in der Grammatikregel, variablesF das variables-Attribut des einzigen Vorkommens der syntaktischen Variablen F in der Grammatikregel, usw. Im Kontext der ersten Grammatikregel zu E erhalten wir folgende Attributauswertungsregeln (Der Code zu E1 besteht aus dem Code zu E2, gefolgt vom Code zu T, gefolgt vom richtigen“ Befehl. Wenn man die Variablen in E2 und T ” vereinigt, dann erh¨alt man die von E1.): E -> E addOp T if (addOp_string.charAt(0)==’+’){ Expression1_code=Expression2_code+"\n"+Term_code+"\n else { Expression1_code=Expression2_code+"\n"+Term_code+"\n Expression1_variables = new HashSet(); Expression1_variables.addAll(Expression2_variables); Expression1_variables.addAll(Term_variables);
Die Attributauswertungsregeln zu E -> T sind trivial, die zu T v¨ollig analog. E -> T Expression_code=Term_code; Expression_variables=Term_variables;
Startseite
JJ
II
J
I
ADD W !SP+, !SP+, -!SP"; } Seite 36 von 100
SUB W !SP+, !SP+, -!SP"; } Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Die interessanteren der Attributauswertungsregeln zu F lauten:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
F -> variable Factor_code=" MOVE W "+name_string+" ,-!SP"; Factor_variables = new HashSet(); Factor_variables.add(name_string);
Geschachtelte Rechtecke Scanner mit Aktionen
F -> number Factor_code=" MOVE W I "+number_string+" ,-!SP"; Factor_variables = new HashSet();
Im Kontext der hinzugef¨ugten Startregel wird f¨ur jede der in variablesE aufgesammelten Variablen eine (zweizeilige) Speicherplatzreservierung erzeugt. Dann werden die Speicherplatzreservierungen vor den Auswertungscode gestellt: S -> E [String h = new String(); String inputValue = new String(); Iterator it = Expression_variables.iterator(); while (it.hasNext()){ String cv = (String)it.next(); boolean ok = false; while (!ok) { inputValue = JOptionPane.showInputDialog("Please input a value for " + cv); try {Integer.parseInt(inputValue); ok=true;} catch (Exception e) {ok = false;} } h=cv+":\n"+" DD "+inputValue+"\n"+h; } h="\n"+h; Arithmetic_code=h+Expression_code;]
Da S nur ein Attribut hat, braucht man auch nur eine Attributauswertungsregel.
Startseite
JJ
II
J
I
Seite 37 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Postscript-Code-Generierung– Martin Fuchs
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Das weitverbreitete Postscript-Format ist nicht nur eine Seitenbeschreibungssprache f¨ur die Bildschirm- und Druckausgabe, sondern kann auch als Programmiersprache genutzt werden. Postscript ist eine Stack-basierte Sprache in Reverse Polish Notation (RPN), der arithmetische Ausdruck
Geschachtelte Rechtecke Scanner mit Aktionen
a*a - 2*a*b + b*b
l¨asst sich in einem Postscript-Interpreter durch Ausf¨uhrung des folgenden Postscript-Codes auswerten: /a 4 def /b 17 def a a mul 2 a mul b mul sub b b mul add ==
¨ Dabei wurden die im Ausdruck vorkommenden Variablen mit 17 bzw 4 initialisiert (Zeile 1 bis 6) und der Ubersichtlichkeit halber eine Darstellung gew¨ahlt, bei der jeder Befehl in einer neuen Zeile steht, grunds¨atzlich ist auch eine Eingabe des kompletten Programmes in einer einzigen Zeile m¨oglich. F¨ur die Umsetzung einfacher arithmetischer Ausdr¨ucke werden nur Bezeichner (Variablen), Ganzzahlen, die Operatoren add, sub, mul, idiv und der Befehl == f¨ur die Programmausf¨uhrung ben¨otigt.
Startseite
JJ
II
J
I
Seite 38 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Zur Erzeugung eines Postscript-Code-Generators mit Jaccie muss nur der Evaluator ge¨andert werden, Scanner und Parser k¨onnen unver¨andert (siehe Syntaxbeschreibung) u¨bernommen werden.
Bin¨ arzahlen
F¨ur die Nonterminale wurde folgende Attributierung gew¨ahlt:
Geschachtelte Rechtecke
Arithmetische Ausdr¨ ucke
Scanner mit Aktionen
Nonterminals: Arithmetic Expression Term Factor
postscript postscript postscript postscript
variables variables variables variables
environment
Alle verwendeten Attribute sind synthesized; sie haben die folgende Bedeutung: • variables ist eine Datenstruktur, in der alle im zugeordneten Knoten und dessen direkten und indirekten Nachkommen vorkommenden Variablen enthalten sind. variables wird als Set vereinbart, in der eigentlichen Realisierung wird eine HashSet verwendet, ein Austausch gegen eine andere Datenstruktur, die das Set-Interface implementiert, ist leicht m¨oglich. • environment ist eine als Map vereinbarte und als HashMap realisierte Datenstruktur, die Variablen auf ihre vom Benutzer eingegebenen Belegungen abbildet. Startseite
• postscript ist ein String, der den Postscript-Code des Unterbaums mit dem entsprechenden Knoten als Wurzel darstellt. Berechnung der Attribute Die Berechnung der Attribute variables und environment erfolgt wie in der allerersten Attributierung zu den arithmetischen Ausdr¨ucken. Das environment-Attribut wird hier aber nicht nach unten propagiert.
JJ
II
J
I
Seite 39 von 100
Zur¨ uck
Das Attribut postscript wird wie folgt berechnet: Vollbild ein/aus
Factor -> number Factor_postscript = number_string + " ";
Schließen
Beenden
Factor -> name Factor_postscript = name_string + " ";
Wie oben wird stets ein Zwischenraum als Trenner nach einem Postscript-Token angef¨ugt. Da der Wert einer Variablen erst zur Laufzeit des Postscript-Interpreters beschafft wird, reicht es aus, Namen wie Zahlkonstanten direkt ” hinzuschreiben“.
Bin¨ arzahlen
Hier sieht man, wie Operator-Ausdr¨ucke in Postscriptform gebracht werden:
Scanner mit Aktionen
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
Expression -> Expression addOp Term Expression1_postscript = Expression2_postscript + Term_postscript + (addOp_string.equals("+")?"add ":"sub "); Term -> Term multOp Factor Term1_postscript = Term2_postscript + Factor_postscript + (multOp_string.equals("*")?"mul ":"idiv ");
Bei der Startregel Startseite
Arithmetic -> Expression Arithmetic_postscript = ""; for (Iterator it2 = Arithmetic_variables.iterator();it2.hasNext();) { String current = (String) it2.next(); String value = (String) (Arithmetic_environment.get(current)); Arithmetic_postscript = (Arithmetic_postscript + "/ " + current + " " + value + " def "); } Arithmetic_postscript += Expression_postscript;
wird f¨ur jede Variable eine Postscript-Definition mit dem vom Benutzer (beim Anlegen des Environments) erfragten Wert erzeugt.
JJ
II
J
I
Seite 40 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Alle nicht explizit gezeigten Attributauswertungsregeln sind Transferregeln, die Attributwerte unver¨andert weiterreichen.
Ein Beispiel
Bin¨ arzahlen
F¨ur den arithmetischen Ausdruck a*a-2*a*b+b*b ergibt sich die eingangs gezeigte Postscript-Sequenz (nur ohne Zeilenumbr¨uche). Unten wird der attributierte Syntaxbaum des kleineren arithmetischen Ausdrucks a*17+4 gezeigt, der sich ergibt, wenn der Variablen a der Wert 11 zugeordnet wird:
Arithmetische Ausdr¨ ucke
Arithmetic -postscript:/ a 11 def a 17 mul 4 add -variables:[a] -environment:{a=11} Expression -postscript:a 17 mul 4 add -variables:[a] Expression -postscript:a 17 mul -variables:[a] Term -postscript:a 17 mul -variables:[a] Term -postscript:a -variables:[a] Factor -postscript:a -variables:[a] name -string:a multOp -string:* Factor -postscript:17 -variables:[] number -string:17 addOp -string:+
Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 41 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
Term -postscript:4 -variables:[] Factor -postscript:4 -variables:[] number -string:4
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 42 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
2.5. Grafische Darstellung
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Syntax-Baum als Postscript-Grafik – Ansatz von Peter Pangerl & Co. u ¨berarbeitet
Geschachtelte Rechtecke Scanner mit Aktionen
Der folgende arithmetische Ausdruck 2 * alpha - 3
hat die Syntaxbaum-Darstellung
Arithmetic Expression Expression
addOp -
Term Term
multOp *
Factor
Term Factor
Factor
number 3
name alpha
number 2
Die Grafik stellt die gew¨unschten Proportionen dar: Startseite
1. Knotenbeschriftungen (wie Arithmetic, Expression, addOp, alpha und andere) stehen stets zentriert in einem Feld der L¨ange 10 (bei ungerader L¨ange wird vor dem Zentrieren auf gerade L¨ange aufgerundet). 2. Die rechten Seiten der Grammatik der arithmetischen Ausdr¨ucke haben alle eine ungerade L¨ange und damit stets ein mittleres Symbol. Dieses mittlere Symbol steht zentriert unter dem Vaterknoten.
JJ
II
J
I
Seite 43 von 100
3. Denken wir uns die Knotenbeschriftungen in der Maximall¨ange 10, dann gilt f¨ur Produktionsregeln der L¨ange 3, dass der linke und der rechte Teilbaum von der mittleren S¨aule durch Streifen von je einem Zeichen Breite getrennt sind. Die genauen horizontalen Positionen der Wurzeln des linken und rechten Teilbaums ergeben sich durch rekursive Anwendung dieser Vorschrift auf alle Teilb¨aume.
Zur¨ uck
Vollbild ein/aus
4. Die vertikalen Abst¨ande sind fest gew¨ahlt (in etwa so wie oben).
Schließen
5. Die senkrechten Linien sollen in der Mitte der S¨aule laufen, die schr¨agen Linien von der S¨aulenmitte des Vaterknotens zur S¨aulenmitte des Sohnknotens.
Beenden
Zur L¨ osung:
Bin¨ arzahlen
Zun¨achst werden wie vorgeschlagen folgende Hilfsklassen eingef¨ugt: MyLine und MyNode. MyLine hat vier Attribute: x1,y1, x2, y2, die die Koordinaten des Anfangs- und Endpunktes der Linie definieren. Neben dem Konstruktor besitzt MyLine noch die Methoden getX1(), getY1(),getX2() und getY2() sowie toString():
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
public class MyLine{ private int x1,x2,y1,y2; public public public public
int int int int
getX1(){ getY1(){ getX2(){ getY2(){
return return return return
x1;} y1;} x2;} y2;}
public MyLine(int x1, int y1, int x2, int y2){ this.x1=x1; this.y1=y1; this.x2=x2; this.y2=y2; } public String toString(){ return "\nMyLine(x1:"+x1+", y1:"+y1+", x2:"+x2+", y2:"+y2+")"; } }
Die Klasse MyNode ist analog aufgebaut und wird daher nicht eigens gezeigt. Sie besitzt f¨ur die grafische Darstellung von beschrifteten Knoten drei Attribute: x1, y1, contents, wobei contents die Knotenbeschriftung enth¨alt, x1,y1 die Koordinaten der Beschriftung. Analog zu MyLine hat MyNode die Methoden getX1(), getY1(), getContents() und toString(). Wir ben¨otigen folgende Konstanten:
Startseite
JJ
II
J
I
Seite 44 von 100
Zur¨ uck
Vollbild ein/aus
public public public public public
static static static static static
int int int int int
xDist yTop yInk xGap fontsize
= 36; = 736; = -12; = 1; = 12;
// // // // //
halbe Saeule (in Pixel) oberer Seitenrand (in Pixel) ein Zeilenabstand ein horizontaler Minimalabstand die Fontgroesse
Schließen
Beenden
Zum Einf¨ugen f¨uhrender Blanks (Auff¨ullen auf Spaltenbreite) verwenden wir:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
public static String padded(String s){ String result = s; int blanks = (10-s.length()+1)/2; for (int i = 0; i < blanks; i++) s = " " + s; return s; }
Geschachtelte Rechtecke Scanner mit Aktionen
Wie vorgegeben wurden folgende Attribute f¨ur die graphische Darstellung verwendet: • Ein ererbtes Attribut y mit der vertikalen Koordinate der linken, oberen Ecke eines Knotenfelds (der L¨ange 10 Zeichenbreiten). Ererbt ist dieses Attribut, weil die Berechnung von der Wurzel in Richtung der Bl¨atter l¨auft: Wurzel ganz oben, n¨achste Schicht in festem Abstand darunter, u.s.w. • Ein synthetisiertes Attribut width mit der Breite des Teilbaums, dessen Wurzel der Knoten ist. • Ein ererbtes Attribute left mit der x-Koordinate des linken Teilbaums, dessen Wurzel der Knoten ist. • Ein synthetisiertes Attribut x mit der horizontalen Koordinate der linken, oberen Ecke eines Knotenfelds. • Ein synthetisiertes Attribut nodes enth¨alt die Menge aller MyNode-Informationen zu allen Knoten im durch den Knoten bestimmten Teilbaum (bei Factor-Knoten sind das zwei MyNodes!) • Ein synthetisiertes Attribut lines enth¨alt die Menge aller MyLine-Informationen zu allen Kanten im durch den Knoten bestimmten Teilbaum (bei Factor-Knoten ist das eine MyLine!) • Der Wurzelknoten hat ein synthetisiertes Attribut postscript mit der aus den Mengen der MyLine-und MyNode-Informationen berechneten Postscript-Darstellung des Baums.
Startseite
JJ
II
J
I
Seite 45 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Diese Attribute werden wie folgt berechnet (stellvertretend f¨ur alle Attributauswertungsregeln betrachten wir hier nur die zur Startregel und die zur Regel, die Addition modelliert - Erl¨auterungen in Form von Kommentaren eingestreut):
Beenden
Bin¨ arzahlen
Arithmetic -> Expression
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
Arithmetic_width = Expression_width; // Transfer rule
Scanner mit Aktionen
Arithmetic_x = Expression_x; // Transfer rule Expression_y = yTop + 2 * yInk; // Arithmetic is at top margin on paper Expression_left = 5; // left margin on paper chosen arbitrarily // Set of nodes of Arithmetic ... Arithmetic_nodes = new ArrayList(); // contains all nodes from Expression ... Arithmetic_nodes.addAll(Expression_nodes); // plus the Arithmetic node itself: Arithmetic_nodes.add(new MyNode(Arithmetic_x, yTop, "Arithmetic")); // Set of lines of Arithmetic ... Arithmetic_lines = new ArrayList(); // contains all lines below Expression ... Arithmetic_lines.addAll(Expression_lines); // plus the line from Arithmetic to Expression: Arithmetic_lines.add(new MyLine(Arithmetic_x + xDist, yTop - 2, Arithmetic_x + xDist, yTop + yInk));
Startseite
JJ
II
J
I
Seite 46 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
// This page shows the *one* valuation rule that computes // the Postscript code for the whole tree:
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
// generated Postscript code starts with three fixed lines: Arithmetic_postscript = "\n/fntsize " + fontsize + " def\n" + "/Courier findfont " + fontsize + " scalefont setfont\n" + "newpath "; // then for each node its Postscript code is produced: Iterator n_iterator = Arithmetic_nodes.iterator(); while(n_iterator.hasNext()) { MyNode n = (MyNode)n_iterator.next(); Arithmetic_postscript = Arithmetic_postscript + "\n " + n.getX1() + " " + n.getY1() + " moveto " + " (" + n.getContents() + ") show "; }; // and similarly the Postscript code for each line: Iterator l_iterator = Arithmetic_lines.iterator(); while(l_iterator.hasNext()) { MyLine l = (MyLine)l_iterator.next(); Arithmetic_postscript = Arithmetic_postscript + "\n " + l.getX1() + " " + l.getY1() + " moveto" + " " + l.getX2() + " " + l.getY2() + " lineto"; };
Startseite
JJ
II
J
I
Seite 47 von 100
Zur¨ uck
// finally, two more fixed lines are appended: Arithmetic_postscript = Arithmetic_postscript + "\nstroke" + "\n" + "showpage";
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
Expression -> Expression addOp Term
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
Expression1_width = Expression2_width + 2 * (xGap + xDist) + Term_width; // 2*xDist is the with of the middle column which has 2 gaps around it
Scanner mit Aktionen
Expression1_x = Expression1_left + Expression2_width + xGap; // beetween the left margin of the Expression1 tree and its horizontal // root position there is the complete left hand subtree and one gap Expression2_y = Expression1_y + 2*yInk; // Expression2 is two fontsizes below Expression1 Term_y = Expression1_y + 2 * yInk; // Term is two fontsizes below Expression1, too Term_left = Expression1_left + Expression2_width + 2 * (xGap + xDist); // beetween the left margin of the Expression1 tree and the left margin // of its Term subtree there is the complete Expression2 subtree // plus the width 2*xDist of the middle column plus two gaps Startseite
// The nodes of the Expression1 tree ... Expression1_nodes = new ArrayList(); // are those from the Expression2 subtree ... Expression1_nodes.addAll(Expression2_nodes); // plus those from the Term subtree ... Expression1_nodes.addAll(Term_nodes); // plus directly generated nodes for left hand side (Expression1) // and for token "addOp" and the token string below it: Expression1_nodes.add(new MyNode(Expression1_x, Expression1_y, "Expression")); Expression1_nodes.add(new MyNode(Expression1_x, Expression1_y + 2 * yInk, " addOp")); Expression1_nodes.add(new MyNode(Expression1_x, Expression1_y + 3 * yInk, " "+addOp_string));
JJ
II
J
I
Seite 48 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
// The lines of the Expression1 tree ... Expression1_lines = new ArrayList(); // are those from the Expression2 subtree ... Expression1_lines.addAll(Expression2_lines); // plus those from the Term subtree ... Expression1_lines.addAll(Term_lines); // plus a line towards leftmost operand (Expression2): Expression1_lines.add(new MyLine(Expression1_x + xDist, Expression1_y - 2, Expression2_x + xDist, Expression2_y - yInk)); // plus a line towards rightmost operand (Term): Expression1_lines.add(new MyLine(Expression1_x + xDist, Expression1_y - 2, Term_x + xDist, Term_y - yInk)); // plus a vertical line towards addOp: Expression1_lines.add(new MyLine(Expression1_x + xDist, Expression1_y - 2, Expression1_x + xDist, Expression2_y - yInk)); Expression2_left = Expression1_left; // Transfer rule
F¨ur das Eingangsbeispiel ergeben sich (stark gek¨urzt) die Knoten und Linien ... -nodes:[ MyNode(x1:5, y1:616, string: Factor), MyNode(x1:5, y1:592, string: number), MyNode(x1:5, y1:580, string: 2), ... MyNode(x1:224, y1:736, string:Arithmetic)] -lines:[ MyLine(x1:41, y1:614, x2:41, y2:604), MyLine(x1:41, y1:638, x2:41, y2:628), ... MyLine(x1:260, y1:734, x2:260, y2:724)]
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 49 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
... sowie der (ebenfalls gek¨urzte) Postscript-Code zu der eingangs gezeigten Grafik:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
/fntsize 12 def /Courier findfont 12 scalefont setfont newpath 5 616 moveto ( Factor) show 5 592 moveto ( number) show 5 580 moveto ( 2) show 5 640 moveto ( Term) show 151 640 moveto ( Factor) show 151 616 moveto ( name) show 151 604 moveto ( alpha) show 78 664 moveto ( Term) show 78 640 moveto ( multOp) show 78 628 moveto ( *) show ... 297 688 moveto ( Term) show 224 712 moveto (Expression) show 224 688 moveto ( addOp) show 224 676 moveto ( -) show 224 736 moveto (Arithmetic) show 41 614 moveto 41 604 lineto 41 638 moveto 41 628 lineto 187 638 moveto 187 628 lineto 114 662 moveto 41 652 lineto 114 662 moveto 114 652 lineto .... 260 710 moveto 114 700 lineto 260 710 moveto 333 700 lineto 260 710 moveto 260 700 lineto 260 734 moveto 260 724 lineto stroke showpage
Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 50 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
2.6. Spracherweiterungen
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Vektor-Ausdru ¨ cke – Marc Akkermann und Matthias Ru ¨cker Wir fassen die Werte arithmetischer Ausdr¨ucke nun auf als die Koordinaten von 2-dimensionalen Vektoren in der kartesischen Zeichenebene. Der Operator @ verbindet zwei Koordinaten zu einem Vektor, welcher in Klammern geschrieben wird (z.B. (3@4) ). Solche Vektoren lassen sich addieren (+) bzw. subtrahieren (-) und von rechts her mit einem Skalar multiplizieren (*) (bzw. dividieren (/) ). Von Vektoren kann man den Betrag bilden, indem man den Vektor zwischen senkrechte Striche setzt. Und schließlich kann man von zwei Vektoren das Skalarprodukt (#) bilden. Ein paar Beispiele: (3@4) + (4@(0-3))
ergibt dasselbe wie (7@1)
|(3@4)|
ergibt ebenso wie |(4@(0-3))| den Wert 5
|(3@4) / |(3@4)||
ergibt 1 (den Betrag eines durch seinen Betrag geteilten Vektors)
(3@4) # (3@4)
ergibt nach Definition des Skalarprodukts den Wert 25
(3@4) # (4@(0-3))
Skalarprodukt senkrecht auf einander stehender Vektoren ergibt den Wert 0
Da arithmetische Ausdr¨ucke auch Variablen enthalten d¨urfen, deren konkrete Werte zur Auswertungszeit vom Benutzer erfragt werden, k¨onnen wir abstraktere“ Formeln formulieren – hier zwei Formeln, die sich auf die x- und ” y-Koordinaten von drei Punkten (A, B und C) beziehen: ((xB@yB) - (xA@yA)) + ((xC@yC) - (xB@yB)) + ((xA@yA) - (xC@yC)) eine geschlossene Vektorkette, ergibt dasselbe wie (0@0)
Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 51 von 100
((xA@yA)-(xB@yB))/|(xA@yA)-(xB@yB)| + ((xC@yC)-(xB@yB))/|(xC@yC)-(xB@yB)| winkelhalbierender Vektor zum Winkel ABC (als Summe der Einheitsvektoren zu BA und BC)
Zur¨ uck
Vollbild ein/aus
Wir betrachten die zugeh¨origen Grammatikerg¨ anzungen: Schließen
(1) Factor -> bar VectorExpression bar (2) Factor -> VectorFactor vecMultOp VectorFactor
(1) Der Betrag eines Vektors geht als Factorin einen arithmetischen Ausdruck ein. (2) Das Skalarprodukt ebenfalls.
Beenden
Bei den Vektor-wertigen Ausdr¨ucken haben wir drei Pr¨azedenzebenen (normale Vektoraddition (+) und -subtraktion (-); Produkt mit Skalar (*); Bildung Vektor aus Koordinaten ( (Koord@Koord) ): VectorExpression -> VectorExpression addOp VectorTerm VectorExpression -> VectorTerm
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
VectorTerm -> VectorTerm multOp Factor VectorTerm -> VectorFactor VectorFactor -> openingBracket Factor ampersand Factor closingBracket VectorFactor -> openingBracket VectorExpression closingBracket
Außerdem ist die Startregel zu erg¨anzen mit: Arithmetic -> VectorExpression
¨ In der Realisierung dieser Anderungen ergeben sich f¨ur (3@4) # (3@4)
folgende Zwischen- und Endergebnisse in Jaccie:
Startseite
a) Scanner-Ergebnis:
JJ
II
openingBracket number "3" ampersand "@" number "4" closingBracket vecMultOp "#" openingBracket number "3" ampersand "@" number "4" closingBracket
J
I
"("
Seite 52 von 100
")"
Zur¨ uck
"("
Vollbild ein/aus
Schließen
")"
Beenden
Bin¨ arzahlen
b) Parser-Ergebnis:
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
Arithmetic VectorExpression VectorExpression VectorTerm VectorFactor openingBracket - string: "(" Factor number - string: "3" ampersand - string: "@" Factor number - string: "4" closingBracket - string: ")" addOp - string: "+" VectorTerm VectorFactor openingBracket - string: "(" Factor number - string: "4" ampersand - string: "@" Factor openingBracket - string: "(" Expression Expression Term Factor number - string: "0" addOp - string: "-" Term Factor number - string: "3" closingBracket - string: ")" closingBracket - string: ")"
Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 53 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
c) Endergebnis :
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
Arithmetic -result:(
[email protected])
Scanner mit Aktionen
F¨ur den Winkelhalbierenden-Ausdruck (s.o.) ((xA@yA)-(xB@yB))/|(xA@yA)-(xB@yB)| + ((xC@yC)-(xB@yB))/|(xC@yC)-(xB@yB)|
ergeben sich bei verschiedenen Variablenbelegungen folgende Endergebnisse in Jaccie: Endergebnis f¨ ur [xA,yA,xB,yB,xC,yC] = [0,6,0,0,3,0] : Arithmetic -result:(
[email protected])
Endergebnis f¨ ur [xA,yA,xB,yB,xC,yC] = [1,8,6,2,5,3] : Startseite
Arithmetic -result:(
[email protected])
Die Attributierung enth¨alt ¨ahnliche Attribute zum Aufsammeln der vorkommenden Variablen und zum Propagieren der Name-Wert-Paare in den Syntaxbaum wie die Attributierung zur Auswertung einfacher arithmetischer Ausdr¨ucke.
JJ
II
J
I
Seite 54 von 100
Zur¨ uck
Anders als dort rechnen wir hier nicht mit gek¨urzten Br¨uchen (die als Strings gespeichert werden), sondern mit Javadouble-Werten (die zum Speichern in HashMaps in Double-Objekte verpackt“werden m¨ ussen, weil Java-Collections ” nur echte Objekte aufnehmen k¨onnen und keine einfachen double-Werte). F¨ur double-Werte steht uns die ganze Palette von arithmetischen Operationen aus Java zur Verf¨ugung, insbesondere auch die sqrt, die zur Ermittlung des Betrags eines Vektors ben¨otigt wird.
Vollbild ein/aus
Schließen
Beenden
Eine typische Attributierungsregeln ist dann auch die zur Ermittlung des Betrags eines Vektors:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Factor -> bar VectorExpression bar // erst zwei Hilfsvariablen ... double x = java.lang.Math.abs(VectorExpression_vecValX); double y = java.lang.Math.abs(VectorExpression_vecValY); // ... und dann die Berechnung des Attributwerts: Factor_value = java.lang.Math.sqrt((x*x)+(y*y));
Geschachtelte Rechtecke Scanner mit Aktionen
Andere typische Attributierungsregeln implementieren die Vektor-Addition koordinatenweise (getrennt f¨ur x und y): VectorExpression1 -> VectorExpression2 addOp VectorTerm // die x-Koordinaten ... if (addOp_string.equals("+")) { VectorExpression1_vecValX = VectorExpression2_vecValX + VectorTerm_vecValX; else { VectorExpression1_vecValX = VectorExpression2_vecValX - VectorTerm_vecValX; // ... und die y-Koordinaten: if (addOp_string.equals("+")) { VectorExpression1_vecValY = VectorExpression2_vecValY + VectorTerm_vecValY; else { VectorExpression1_vecValY = VectorExpression2_vecValY - VectorTerm_vecValY;
}
}
}
Startseite
JJ
II
J
I
Seite 55 von 100
} Zur¨ uck
Die Fallunterscheidungen sind notwendig, weil ein addOp ja auch ein - sein kann.
Vollbild ein/aus
Schließen
Beenden
Bedingte Ausdru ¨ cke – Dennis Koch und Maximilian Winkler
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Hier soll die zuletzt um Vektor-Ausdr¨ucke erweiterte Syntax arithmetischer Ausdr¨ucke nochmals erweitert werden um
Geschachtelte Rechtecke Scanner mit Aktionen
• Einf¨uhrung von initialisierten Variablen (im mathematischen Sinn) mit geschachtelten G¨ultigkeitsbereichen in einem let-Konstrukt • Boolesche Ausdr¨ucke und Vergleichsausdr¨ucke • Bedingte Audr¨ucke in C-/Java-Syntax • Rekursive Verwebung dieser Teilausdr¨ucke Was damit genau gemeint ist, wird am schnellsten an der zugeh¨origen Grammatikerg¨ anzung klar: Factor -> let name becomes Expression in Expression end BooleExpression -> BooleExpression orOp BooleTerm BooleExpression -> BooleTerm BooleTerm -> BooleTerm andOp BooleFactor BooleTerm -> BooleFactor BooleFactor -> notOp BooleFactor BooleFactor -> Expression relOP Expression
Startseite
JJ
II
J
I
Seite 56 von 100
Expression -> openingBracket BooleExpression questionMark Expression colon Expression closingBracket
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Diese Grammatikerg¨anzung erfordert eine Erweiterung der Scanner-Definition um folgende Patterns und Token:
Bin¨ arzahlen
Patterns:
Tokens:
:= := := := := := := := := :=
Arithmetische Ausdr¨ ucke
:= := := := := := := := := := := := := := :=
$>$= $ $< $!$= $? $: $i$n $l$e$t $e$n$d $&$& $~ ( | | | | | )
Es ist darauf zu achten, dass in, let und end vor der name-Token-Definition eingetragen werden m¨ussen, weil wir vorrangig Schl¨usselw¨orter erkennen wollen.
Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 57 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Zu den so erweiterten Ausdr¨ucken soll – aufbauend auf der Auswerter-Attributierung aus 2.2 – ein interaktiver Auswerter erstellt werden, der auf das Erfragen von Variablenwerten verzichtet, sofern sie in let-Konstrukten ihren Wert erhalten. F¨ur Vergleichsausdr¨ucke und Boolsche Ausdr¨ucke verwenden wir ein Attribut boolValue:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Attributes: boolValue : boolean boolValue ist ein synthetisiertes Attribut und dient zur Wertermittlung in booleschen Ausdr¨ ucken wie z.B. in folgender
Regel, in der der Wert eines bedingten Ausdrucks berechnet wird: Expression1 -> openingBracket BooleExpression questionMark Expression2 colon Expression3 closingBracket if (BooleExpression_boolValue) Expression1_value = Expression2_value; else Expression1_value = Expression3_value;
Im Attribut variables werden nur diejenigen Namen gesammelt, die noch nicht durch let-Konstrukte gebunden wurden: Factor -> let name becomes Expression1 in Expression2 end Iterator variablesIterator = Expression2_variables.iterator(); while (variablesIterator.hasNext()) { String name = new String(name_string); if (name.equals(variablesIterator.next())) { variablesIterator.remove(); break; } }
Startseite
JJ
II
J
I
Seite 58 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Im Kontext der gleichen Grammatikregel wird von dem ererbten environment eine Kopie gezogen und vor dem Weiterreichen nach unten“ ein neuer Eintrag f¨ur den gerade gebundenen Namen erzeugt: ” Factor -> let name becomes Expression1 in Expression2 end Expression2_environment = new HashMap(Factor_environment); Expression2_environment.put(name_string, Expression1_value);
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Beispiele f¨ ur solche Ausdr¨ ucke: 17 + 4 = ergibt wie immer 21 let a := 3 in let b := 4 in a*a + b*b end end => ergibt 25 Startseite
let a := 3 in a*a end + let b := 4 in b*b end => ergibt ebenfalls 25 let a := 5 in let b := 2*a in let c := 2*(a-b) in ( a < c ? a : ( c < b ? c : b)) end end end => ergibt -10, weil a=5, b=10, c=-10 und weil davon das Minimum bestimmt wird
JJ
II
J
I
Seite 59 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
let a := 5 in let b := 2*a in let b := (0-2)*a in let c := 2*(a-b) in let a := (0-8) in ( a < c ? a : ( c < b ? c : b)) end end end end end => ergibt -8
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
G¨ultigkeitsbereiche kann man in syntaktisch korrekter, aber inhaltlich unsinniger Weise verwenden: let a := 3 in let b := 4 in 17 + 4 end end => ergibt immer noch 21 let b := 3 in a*a end + let a := 4 in b*b end => ergibt keinesfalls 25!!
Startseite
JJ
II
J
I
Seite 60 von 100
let a := b in let b := a in a + b end end => ergibt ?!?
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
In einer weiteren Attributierung ließe sich pr¨ufen, ob solche inhaltlichen Fehler vorliegen.
3. Geschachtelte Rechtecke
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Im Buch Syntaxbasierte Programmierwerkzeuge“ wird ab S. 14 ein Beispiel beschrieben, bei dem es um die Er” zeugung von Grafiken aus textuellen Beschreibungen geht. Konkret handelt es sich um Bilder aus achsenparallelen Rechtecken, sogenannten Boxen:
Geschachtelte Rechtecke Scanner mit Aktionen
• Eine Box hat eine frei bestimmbare Breite und H¨ohe. • Eine Box kann ein Teilbild umrahmen. • Teilbilder und Boxen k¨onnen senkrecht angeordnet werden. Dann werden sie – unter Wahrung des Mindestabstands – von oben nach unten um eine senkrechte Mittelachse zentriert angeordnet. • Teilbilder und Boxen k¨onnen waagerecht angeordnet werden. Dann werden sie – unter Wahrung des Mindestabstands – von links nach rechts um eine waagerechte Mittelachse zentriert angeordnet. Der Mindestabstand wird f¨ur die gesamte Zeichnung global festgelegt. Im Buch findet man dazu i.W. folgende Syntax: Token definitions:
Startseite
JJ
II
J
I
:= $( := $)
:= $[ := $]
:= ({$0-$9}[1-*]
:= $> := $V
Schließen
:= $@
Beenden
Seite 61 von 100
Zur¨ uck
Vollbild ein/aus
(Der @-Operator wird erst sp¨ater ben¨otigt.)
Bin¨ arzahlen
Grammar rules: Drawing -> Picture
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Picture Picture Picture Picture
-> -> -> ->
Box Picture right Box Picture down Box openB Picture closeB
Box Box
-> openB Width Height closeB -> openP Picture closeP
Width
-> number
Height
-> number
Das zus¨atzliche Startsymbol Drawing und seine zugeh¨orige Startregel wurden wie u¨blich als Aufh¨anger von Wurzelattributen und Ort der Initialisierung von ererbten Attributen hinzugef¨ugt. Die anderen Regeln spiegeln die vorher beschriebenen Bildungsgesetze wider (man interpretiere eckige Klammerpaare als Rahmen von Rechtecken). Nur die zweite Regel zu Box folgt nicht direkt: Sie ist zum Gruppieren von Teilbildern notwendig. Bei dieser Syntax d¨urfen – ¨ahnlich wie bei arithmetischen Ausdr¨ucken – u¨berfl¨ussige runde Klammerpaare fast nach Belieben eingef¨ugt werden. Die Enden einer vertikalen oder einer horizontalen Folge werden in der Eingabe nicht durch Klammerung hervorgehoben. Wir verwenden daher in der Jaccie-Implementierung parallel zur alten Grammatik eine neue Grammatik, die zwar umfangreicher ist, aber die genannten Nachteile behebt.
Startseite
JJ
II
J
I
Seite 62 von 100
Zur¨ uck
Alte Syntax und Attribute portieren – Dominik Oesterreich Vollbild ein/aus
Eine unter Evaluator – Definition – Java – Methods“ angelegte Hilfsklasse MyRectangle hat vier Attribute vom Typ ” int, die ein achsenparalleles Rechteck komplett beschreiben: top und left bestimmen die linke obere Ecke, bottom und right die gegen¨uberliegende. MyRectangle hat einen Konstruktor mit vier Parametern (die Attributwerte in der oben angegebenen Reihenfolge), eine toString()-Methode sowie vier Methoden zum Erfragen der Attributwerte: int top() u.s.w.
Schließen
Beenden
Bin¨ arzahlen
public class MyRectangle { protected int top; protected int left; protected int bottom; protected int right; MyRectangle (int t, int l, int b, int r) { top = t; left = l; bottom = b; right = r; } public public public public
int int int int
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
top() { return top; } left() { return left; } right() { return right; } bottom() { return bottom; }
public String toString() { return "\n[top="+top+", left="+left+", right="+right+", bottom="+bottom+"]"; } }
Dort ist auch eine globale Variable mit dem Mindestabstand zwischen Boxen (als Attribut der Scanner-Klasse) vereinbart und initialisiert: int gap = 2;
Von den folgenden Attributen entsprechen left und top zusammen dem position-Attribut aus dem Buch (genauer entspricht left dem Wert position.x und top dem Wert position.y).
Startseite
JJ
II
J
I
Seite 63 von 100
Zur¨ uck
Vollbild ein/aus
Attribute und ihre Typen: >width : int >height : int Picture Drawing_rectangles = Picture_rectangles; Picture_left = 0; Picture_top = 0; Picture -> Picture right Box Picture1_rectangles = Picture2_rectangles; Picture1_rectangles.addAll(Box_rectangles); Picture1_width = Picture2_width + gap + Box_width; Picture1_height = Math.max (Picture2_height, Box_height); int yPos = Picture1_top; int yDiff = Box_height - Picture2_height; Picture2_top = yPos; if (yDiff > 0) {Picture2_top = Picture2_top + yDiff/2;};
Startseite
JJ
II
J
I
Seite 64 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
Box_left = Picture1_left + gap + Picture2_width;
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
int yPos = Picture1_top; int yDiff = Picture2_height - Box_height; if (yDiff > 0) {yPos = yPos + (yDiff/2);}; Box_top = yPos;
Scanner mit Aktionen
Picture -> Picture down Box Picture1_rectangles = Picture2_rectangles; Picture1_rectangles.addAll(Box_rectangles); Picture1_width = Math.max(Picture2_width, Box_width); Picture1_height = Picture2_height + gap + Box_height; int xPos = Picture1_left; int xDiff = Box_width - Picture2_width; if (xDiff > 0) {xPos = xPos + xDiff/2;}; Picture2_left = xPos; Startseite
int xPos = Picture1_left; int xDiff = Picture2_width - Box_width; if (xDiff > 0) {xPos = xPos + xDiff/2;}; Box_left = xPos;
JJ
II
J
I
Seite 65 von 100
Box_top = Picture1_top + gap + Picture2_height; Zur¨ uck
Picture -> openB Picture closeB Picture1_rectangles = Picture2_rectangles; Picture1_rectangles.add(new MyRectangle (Picture1_top, Picture1_left, Picture1_top + Picture1_height, Picture1_left + Picture1_width));
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
Picture1_width = 2*gap + Picture2_width;
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
Picture1_height = 2*gap + Picture2_height;
Scanner mit Aktionen
Picture2_left = Picture1_left + gap; Picture2_top = Picture1_top + gap; Box -> openB Width Height closeB Box_rectangles = new HashSet(); Box_rectangles.add(new MyRectangle (Box_top, Box_left, Box_top + Box_height, Box_left + Box_width)); Width -> number Width_width = (new Integer(number_string)).intValue(); Height -> number Height_height = (new Integer(number_string)).intValue();
Wir wenden unseren Compiler an auf die Eingabezeichenreihe
Startseite
JJ
II
J
I
Seite 66 von 100
[5 11] > ( [15 15] v [40 10] ) Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Der Scanner macht daraus die Tokenfolge
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
openB "[" number "5" number "11" closeB "]" right ">" openP "(" openB "[" number "15" number "15" closeB "]" down "v" openB "[" number "40" number "10" closeB "]" closeP ")"
Der Parser baut aus der Tokenfolge den Syntaxbaum mit der textuellen Darstellung Drawing Picture Picture Box openB - string: "[" Width number - string: "5" Height number - string: "11" closeB - string: "]" right - string: ">"
Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 67 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
Box openP - string: "(" Picture Picture Box openB - string: "[" Width number - string: "15" Height number - string: "15" closeB - string: "]" down - string: "v" Box openB - string: "[" Width number - string: "40" Height number - string: "10" closeB - string: "]" closeP - string: ")"
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
und der Evaluator berechnet daraus das Wurzel-Attribut Drawing -rectangles:[ [top=8, left=0, right=5, bottom=19], [top=17, left=7, right=47, bottom=27], [top=0, left=19, right=34, bottom=15]]
Seite 68 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Grafische Darstellungen – Sebastian Bergatt und Stefan Keil
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Hier geht es darum, die im Attribut Drawing_rectangles aufgesammelten Rechtecke grafisch anzuzeigen, und zwar
Geschachtelte Rechtecke Scanner mit Aktionen
• Teilattributierung Java“: in einem Java-Grafik-Fenster; ” • Teilattributierung Postscript“: als druckbares Postscript-File. ” Jede der beiden Teilattributierungen umfasst genau ein Attribut, das nur dem Startsymbol der Grammatik zugeordnet ist und daher auch nur im Kontext der Startregel ausgewertet wird. Daher enth¨alt jede Teilattributierungen auch nur eine einzige Attributauswertungsregel. Zun¨achst die formalen Teile: Attribute und ihre Typen: >window : int >postscript : String
¨ W¨ahrend das window ein reines Dummy-Attribut ist – wichtig ist nur der Nebeneffekt: das Offnen eines Java-Fensters mit der Grafik –, wird im Attribut postscript tats¨achlich der Postscript-Text erzeugt, den der Drucker entsprechend ausgeben kann.
Startseite
Die Attributauswertungsregel f¨ur window lautet:
JJ
II
Drawing_window = 1; // irrelevanter Attributwert
J
I
// Das Ausgabefenster, in dem die Rechtecke gezeichnet werden, // ¨ ubernimmt ein DrawRectangle-Objekt, welches alle Rechtecke // (HashSet) und den Titel des Ausgabefensters enth¨ alt: JFrame window = new DrawRectangle(Drawing_rectangles, "Boxes");
Seite 69 von 100
Zur¨ uck
Vollbild ein/aus
// Bestimmem der Gr¨ oße des Ausgabefensters: window.setSize(Picture_width+10, Picture_height+30); // Anzeigen des Ausgabefensters: window.setVisible(true);
Schließen
Beenden
Die eigentliche Zeichenarbeit“ erledigt die ausf¨uhrlich kommentierte Methode paint() der folgenden Hilfsklasse, ” die in Jaccie unter Evaluator - Definition - Actions - Java“ definiert wird: ” import java.awt.*; import java.awt.geom.*; import javax.swing.*;
// viele der 2D-Klassen sind hier untergebracht // wird f¨ ur das JFrame ben¨ otigt
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
public class DrawRectangle extends JFrame { HashSet rect; public DrawRectangle(HashSet r, String title) { super(title); rect = r; } public void paint (Graphics g) { super.paint(g); /* grafische Objekte werden gezeichnet, indem f¨ ur alle Komponenten die paint()-Methode mit passendem Grafikkontext aufgerufen wird. Der Grafikkontext wurde mit der Klasse Graphics2D erweitert.. deshalb wird hier von Graphics auf Graphics2D gecastet, um die erweiterte Funktionalit¨ at nutzen zu k¨ onen. Graphics2D ist Unterklasse von Graphics. */
Startseite
JJ
II
J
I
Graphics2D g2 = (Graphics2D) g; Seite 70 von 100
/* Da die Ausgabe normalerweise nicht gegl¨ attet wird, schalten wir Antialiasing an, nun werden alle Grafikobjekte weichgezeichnet: */ g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
/* Anlegen eines Iterators, um alle Rechtecke zu erfassen: */ Iterator r_iterator = rect.iterator(); while(r_iterator.hasNext()) { MyRectangle r = (MyRectangle)r_iterator.next();
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
/* Die draw-Methode aus der Graphics2D-Klasse nimmt Shape-Objecte und zeichnet diese. Shape-Objecte sind z.B. Rectangle, Polygon, Line2D ... Point: der Startpunkt, von dem gezeichnet wird (beim Rechteck die linke obere Ecke) Er wird aus techn. Gr¨ unden noch um 5 nach rechts und 25 nach unten verschoben, da das Objekt sonst direkt auf dem Rand des Ausgabefensters beginnen w¨ urde. Diese Verschiebunghat ausschließlich optische Gr¨ unde. */ g2.draw(new Rectangle(new Point(r.left()+5,r.top()+25), new Dimension(r.right()-r.left(),r.bottom()-r.top()))); } } } Startseite
JJ
II
J
I
Seite 71 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Die Attributauswertungsregel f¨ur postscript lautet:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Drawing_postscript = "\n" + "/box {" + "\n" + " /bwidth exch def" + "\n" + " /bheight exch def" + "\n" + " 0 bwidth rlineto" + "\n" + " bheight 0 rlineto" + "\n" + " 0 bwidth neg rlineto" + "\n" + " closepath" + "\n" + "} def" + "\n" + "newpath" + "\n"; // erzeugt den immer gleichen Vorspann, in // dem die Zeichenprozedur box(width,height) // definiert wird (beim Aufruf kommen erst // die Parameter, dann der Prozedurname "box") Iterator r_iterator = Drawing_rectangles.iterator(); // erzeugt einen Iterator der den Inhalt von // Drawing_rectangles durchl¨ auft while(r_iterator.hasNext()) { MyRectangle r = (MyRectangle)r_iterator.next(); // nun wird f¨ ur jedes gefundene MyRectangle-Objekt // eine Zeile der Form : // " moveto box" // erzeugt und an den String Drawing_postscript angeh¨ angt Drawing_postscript = Drawing_postscript + (" " + (r.left() + " " + r.top() + " moveto " + (r.right()-r.left()) + " " + (r.bottom()-r.top()) + " box" + "\n")); }
Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 72 von 100
Zur¨ uck
Vollbild ein/aus
Drawing_postscript = Drawing_postscript + "stroke" + "\n" + "showpage"; // erzeugt den immer gleichen Nachspann
Schließen
Beenden
Die Beispieldaten
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
[([[50 60]] > [30 100] > ([[50 60]])) v [200 25]]
ergeben das Auswertungsergebnis (zwecks Lesbarkeit von Hand einger¨uckt): Drawing -rectangles:[ , , , , , ,
Geschachtelte Rechtecke Scanner mit Aktionen
[top=0, left=0, right=210, bottom=139] [top=20, left=26, right=86, bottom=90] [top=20, left=124, right=184, bottom=90] [top=5, left=90, right=120, bottom=105] [top=109, left=5, right=205, bottom=134] [top=25, left=31, right=81, bottom=85] [top=25, left=129, right=179, bottom=85]
] -postscript: /box { /bwidth exch def /bheight exch def 0 bwidth rlineto bheight 0 rlineto 0 bwidth neg rlineto closepath } def newpath 90 5 moveto 30 100 box 0 0 moveto 210 139 box 124 20 moveto 60 70 box 31 25 moveto 50 60 box 129 25 moveto 50 60 box 26 20 moveto 60 70 box 5 109 moveto 200 25 box stroke showpage -window:1
Startseite
JJ
II
J
I
Seite 73 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
und das Fenster
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 74 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Neue Syntax attributieren – Marc Kru ¨ger und Alexander Schmitz
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Die neue Grammatik lautet (Startsymbol ist Drawing):
Geschachtelte Rechtecke Scanner mit Aktionen
Drawing
-> Picture
Picture Picture
-> openP Directed closeP -> Undirected
Undirected -> number ampersand number Undirected -> openB Picture closeB Directed Directed
-> Horizontal right HorPart -> Vertical down VerPart
Horizontal -> Horizontal right HorPart Horizontal -> HorPart HorPart HorPart
-> openP Vertical down VerPart closeP -> Undirected
Vertical Vertical
-> Vertical down VerPart -> VerPart
VerPart VerPart
-> openP Horizontal right HorPart closeP -> Undirected
Die neue Grammatik wird mit den gleichen Attributen wie bisher versehen.
Startseite
JJ
II
J
I
Seite 75 von 100
Zur¨ uck
Vollbild ein/aus
Attribute und ihre Typen: >width : int >height : int oldSyntax : String >topDown : String >turned90 : String
Erzeugung der alten Syntax: Da die alte Syntax weniger standardisiert“ ist als die neue, kann man neue Syntax besser in alte Syntax u¨bertragen ” als umgekehrt. Hierbei liegt der wesentliche Arbeitsaufwand darin, Ausdr¨ucke der Form number1 ampersand number2 so umzuwandeln, dass das @ in der alten Syntax nicht auftaucht. In allen anderen F¨allen, wird daS Attribut von unten nach oben durchgereicht, wobei hier jeweils die Ausdr¨ucke in Strings umgewandelt werden m¨ussen. Nachfolgend die Attributauswertungsregeln in ihrem jeweilen Kontext (dabei sind die einfachen Transfer“-Regeln, die Attributwerte ” unver¨andert weiterreichen nebst ihren Kontexten weggelassen worden): Picture -> openP Directed closeP Picture_oldSyntax = openP_string + Directed_oldSyntax + closeP_string;
Startseite
JJ
II
J
I
Seite 80 von 100
Zur¨ uck
Vollbild ein/aus
Undirected -> number ampersand number Undirected_oldSyntax = "[ " + Number1_oldSyntax + " " + Number2_oldSyntax + " ]"; Undirected -> openB Picture closeB Undirected_oldSyntax = openB_string + Picture_oldSyntax + closeB_string;
Schließen
Beenden
Bin¨ arzahlen
Directed -> Horizontal right HorPart Directed_oldSyntax = Horizontal_oldSyntax + right_string + HorPart_oldSyntax;
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Directed -> Vertical down VerPart Directed_oldSyntax = Vertical_oldSyntax + down_string + VerPart_oldSyntax; Horizontal -> Horizontal right HorPart Horizontal1_oldSyntax = Horizontal2_oldSyntax + right_string + HorPart_oldSyntax; Vertical -> Vertical down VerPart Vertical1_oldSyntax = Vertical2_oldSyntax + down_string + VerPart_oldSyntax; HorPart -> openP Vertical down VerPart closeP HorPart_oldSyntax = openP_string + Vertical_oldSyntax + down_string + VerPart_oldSyntax + closeP_string; VerPart -> openP Horizontal right HorPart closeP VerPart_oldSyntax = openP_string + Horizontal_oldSyntax + right_string + HorPart_oldSyntax + closeP_string; Startseite
Angewandt auf die Eingabe (in neuer Syntax) ( ( [ 10 @ 10 ] > 10 @ 50 >
JJ
II
J
I
[ 10 @ 10 ] ) V 120 @ 20 ) Seite 81 von 100
ergibt sich die alte Syntax: (([[ 10 10 ]]>[ 10 50 ]>[[ 10 10 ]])V[ 120 20 ])
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Vertikale Spiegelung:
Bin¨ arzahlen
Offenbar ver¨andert die TopDown-Attributierung nur die Vertikalen und l¨asst die Horizontalen unver¨andert. Im folgenden ist nur der Kontext aufgef¨uhrt, in dem die eigentliche Arbeit passiert.
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Directed -> Vertical down VerPart Directed_topDown = VerPart_topDown + down_string + Vertical_topDown; Vertical -> Vertical down VerPart Vertical1_topDown = VerPart_topDown + down_string + Vertical2_topDown;
Angewandt auf die Eingabe ( ( [ 10 @ 10 ] > 10 @ 50 >
[ 10 @ 10 ] ) V 120 @ 20 )
ergibt sich die auf den Kopf gestellte“ Eingabe: ” (120@20V([10@10]>10@50>[10@10])) Startseite
Angewandt auf die Eingabe (120@20V([10@10]>10@50>[10@10]))
ergibt sich die nochmals auf den Kopf gestellte“ Eingabe: ”
JJ
II
J
I
Seite 82 von 100
Zur¨ uck
(([10@10]>10@50>[10@10])V120@20) Vollbild ein/aus
d.h. die urspr¨ungliche Eingabe (ohne Zwischenr¨aume)! Schließen
Bemerkung: Auch die in der n¨achsten Attributierung erzeugte Drehung um 90 Grad l¨asst sich in dieser Weise iterieren und f¨uhrt nach viermaliger Anwendung zur urspr¨unglichen Zeichenreihe zur¨uck.
Beenden
Drehung um 90 Grad:
Bin¨ arzahlen
Bei der Turned90-Attributierung tauschen die Vertikalen und die Horizontalen ihre Rollen. W¨ahrend die Elemente einer Horizontalen in der Vertikalen in genau der gleichen Reihenfolge erscheinen, kehrt sich die Reihenfolge der Elemente in Vertikalen, die zu Horizontalen werden, genau um. Dabei ist darauf zu achten, dass bei einer gedrehten Box die Gr¨oße und Breite vertauscht ist.
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Undirected -> Number ampersand Number Undirected_turned90 = number2_string + ampersand_string + number1_string; Directed -> Horizontal right HorPart Directed_turned90 = Horizontal_turned90 + "V" + HorPart_turned90; Directed -> Vertical down VerPart Directed_turned90 = VerPart_turned90 + ">" + Vertical_turned90; Horizontal -> Horizontal right HorPart Horizontal1_turned90 = Horizontal2_turned90 + "V" + HorPart_turned90; Vertical -> Vertical down VerPart Vertical1_turned90 = VerPart_turned90 + ">" + Vertical2_turned90; Startseite
HorPart -> openP Vertical down VerPart closeP HorPart_turned90 = openP_string + VerPart_turned90 + ">" + Vertical_turned90 + closeP_string; VerPart -> openP Horizontal right HorPart closeP VerPart_turned90 = openP_string + Horizontal_turned90 + "V" + HorPart_turned90 + closeP_string;
Angewandt auf die Eingabe ( ( [ 10 @ 10 ] > 10 @ 50 >
JJ
II
J
I
Seite 83 von 100
Zur¨ uck
[ 10 @ 10 ] ) V 120 @ 20 )
ergibt sich die um 90 Grad gedrehte“ Eingabe: ”
Vollbild ein/aus
Schließen
Beenden
(20@120>([10@10]V50@10V[10@10]))
Compiler erstellen – Ein Bearbeiter
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 84 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Aufgabe: Erstellen Sie entweder zur alten oder zur neuen Syntax aus allen entwickelten Komponenten einen lauff¨ ahigen Compiler in Form eines ausf¨uhrbaren jar-Files. Der Compiler soll
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
• eine textuelle Beschreibung einer Boxen-Grafik aus einer Datei XXX.sinp einlesen (Name XXX dazu erfragen),
Scanner mit Aktionen
• die Grafik in einem Fenster anzeigen und • eine Datei XXX.ps mit der Postscript-Form der Grafik erzeugen (bzw. u¨berschreiben). Bitte alle Schritte ausf¨uhrlich am Beispiel darstellen! (Dieser Inhalt soll sp¨ater ins Jaccie-Handbuch eingearbeitet werden.)
Startseite
JJ
II
J
I
Seite 85 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
4. Scanner mit Aktionen
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
4.1. Telegramme
Scanner mit Aktionen
Unsere Telegrammverschl¨usselung basiert auf den drei Grundzeichen: Punkt ( .“), Strich ( -“) und Zwischenraum ” ” ( “ oder ). ” Die verschl¨ usselten Symbole sind Buchstaben, Ziffern oder Sonderzeichen. Der Morse-Code ist gegeben durch: a a ¨ b c ch d e f g h i j k l m
..-.-... -.-. ----.. . ..-. --. .... .. .---..-.. --
n o o ¨ p q r s t u u ¨ v w x y z
-. -----. .--. --..-. ... ....-....--..-.---..
0 1 2 3 4 5 6 7 8 9
----.---..--...-......... -.... --... ---.. ----.
. , ? EOM
.-.-.--..-..--.. .-.-.
Startseite
JJ
II
J
I
Seite 86 von 100
In der Verschl¨usselung trennt ein Zwischenraum je zwei Symbole, zwei Zwischenr¨aume trennen W¨orter von einander.
Zur¨ uck
Jede verschl¨usselte Nachricht endet mit dem End-of-Message-Sonderzeichen, das im Klartext als EOM wiedergegeben wird.
Vollbild ein/aus
Schließen
Beenden
Klartext in Morse-Code umwandeln - Philipp Appelhoff
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Inhalt dieser Aufgabe ist es, einen Verschl¨usseler zu erstellen, der Texte ins Morsealphabet u¨bersetzt. Zwei Symbole werden durch ein Leerzeichen getrennt. Zwei Leerzeichen stellen damit die Trennung zweier Worte dar. Jede Nachricht ¨ endet mit dem End-of-Message-Sonderzeichen, das im Klartext als EOM dargestellt wird. Neben der Ubersetzung von Klartext in Morse-Code sollen auch die Kosten f¨ur eine Nachricht berechnet werden:
Geschachtelte Rechtecke Scanner mit Aktionen
• W¨orter kosten 2ct pro Zeichen • Die ersten 3 Zeichen pro Wort sind frei • Jeder Satz kostet pauschal 5ct Um die Aufgabe nur mit einem Scanners zu l¨osen, wird ein Token f¨ur jedes Zeichen, also a bis z, 0 bis 9, die Satzzeichen , . und ?, das Leerzeichen und die Endmarke ben¨otigt. Die Token der Zeichen ch, a-z, 0-9 und der Umlaute sind nach folgendem Muster erstellt worden. Man beachte, dass nach dem Morsealphabet auch ch als ein Zeichen interpretiert wird. := "z" Action: telegramm = telegramm + [Morsecode als String]; payChar(); add(scannerService.getString()); [\]
Diese Definition bedient sich einiger Besonderheiten. Zum einen wird den Token eine Aktion zugewiesen. Dabei wird der Variable telegramm der Morsecode des Zeichens angeh¨angt. Zudem werden zwei Methoden aufgerufen, um die Kosten zu berechnen und den Eingabestring in einer weiteren variable zusammenzusetzen. Die Variablen sind genau wie die aufgerufenen Methoden im Punkt Global declarations“ von Jaccie eingetragen. Folgende Deklarationen sind ” darin enthalten:
Startseite
JJ
II
J
I
Seite 87 von 100
Zur¨ uck
Vollbild ein/aus
String telegramm = ""; String origin = ""; int n = 0; int cost = 0;
Schließen
Beenden
Bin¨ arzahlen
public void payChar() { if (n2) cost = cost + 2; n++; }
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
public void paySentence() { % cost = cost + 5; n = 0; } public void add(String s) { origin = origin + s; }
Neben der Variablendeklaration sind hier auch drei Methoden definiert: Die Methode payChar() addiert 2ct f¨ur den Buchstaben, falls bereits mehr als 3 Buchstaben im Wort sind. Gleichzeitig wird der Z¨ahler n hochgesetzt. Dementsprechend muß der Token eines Leerzeichens n wieder auf Null setzen. Die Methode paySentence() nutzen wir beim Vorkommen eines Punkts oder Fragezeichen. Die Token f¨ur . und ? sind daher: := "z" Action: telegramm = telegramm + ; paySentence(); add(scannerService.getString()); [\]
Wie schon erw¨ahnt, wird der Buchstabenz¨ahler beim Leerzeichen zur¨uckgesetzt und dem Morsecode ein Leerzeichen hinzugef¨ugt. Dadurch ergeben sich als Worttrenner zwei Leerzeichen. := " " Action: telegramm = telegramm + " "; n = 0; // Ein Leerzeichen setzt den Buchstabenz¨ ahler auf Null [\]
Startseite
JJ
II
J
I
Seite 88 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Damit unser Ergebnis aber auch ausgegeben wird, muss beim letzten Token der u¨bersetzte Text ausgegeben werden. Er ist wie folgt definiert:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
:= "EOM" Action: telegramm = telegramm + ".-.-."; String[] out = { telegramm, origin, new String("Message costs: ").concat(cost+"ct") }; JOptionPane.showMessageDialog(null,out,"Entschluessler", JOptionPane.INFORMATION_MESSAGE); telegramm = ""; [\]
Scanner mit Aktionen
Der Test ergibt:
Startseite
JJ
II
J
I
Seite 89 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Morse-Code in Klartext umwandeln - Axel Betschinski
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
F¨ur die Scannerdefinition ben¨otigen wir ein Token f¨ur jedes im Morse-Code darstellbare Symbol. Wenn ein Symbol vom Scanner erkannt wurde, f¨ugen wir das entsprechende Zeichen einem String hinzu und generieren so den Ausgabetext.
Geschachtelte Rechtecke Scanner mit Aktionen
Tokens: := ".- " Action: telegramm = telegramm + "a"; eingabe = eingabe + ".- "; := "-... " Action: telegramm = telegramm + "¨ a"; eingabe = eingabe + "-... "; := "-... " Action: telegramm = telegramm + "b"; eingabe = eingabe + "-... "; := "-.-. " Action: telegramm = telegramm + "c"; eingabe = eingabe + "-.-. "; := "---- " Action: telegramm = telegramm + "ch"; eingabe = eingabe + "---- "; := "-.. " Action: telegramm = telegramm + "d"; eingabe = eingabe + "-.. ";
Analog zu diesen Symbolen definieren wir die Token f¨ur die restlichen Symbole.
Startseite
JJ
II
J
I
Seite 90 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Nach Abarbeitung der Eingabe enth¨alt der String telegramm den entschl¨usselten Telegrammtext; der String eingabe enth¨alt die Eingabe im Morse-Code.
Bin¨ arzahlen
Jetzt wollen wir zus¨atzlich eine Kostenberechnung nach folgender Vorschrift hinzuf¨ugen:
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
• Jeder Punkt und jeder Strich kosten einen Cent.
Scanner mit Aktionen
• W¨orter kosten zus¨atzlich 10 Cents. • Sonderzeichen (einschließlich des obligaten EOM) kosten pauschal 5 Cents. Daf¨ur ben¨otigen wir eine Variable vom Typ Float. Wir addieren f¨ur jedes Zeichen den entsprechenden Betrag hinzu und dividieren die Summe vor der Ausgabe durch 100. := "---- " Action: telegramm = telegramm + "ch"; eingabe = eingabe + "---- "; kosten = kosten + 4; [\] := "-.. " Action: telegramm = telegramm + "d"; eingabe = eingabe + "-.. "; kosten = kosten + 3; [\] := ". " Action: telegramm = telegramm + "e"; eingabe = eingabe + ". "; kosten = kosten + 1; [\]
Startseite
JJ
II
J
I
Seite 91 von 100
...
Zur¨ uck
Vollbild ein/aus
:= ".---- " Action: telegramm = telegramm + "1"; eingabe = eingabe + ".---- "; kosten = kosten + 5; [\]
Schließen
Beenden
Bin¨ arzahlen
:= "..--- " Action: telegramm = telegramm + "2"; eingabe = eingabe + "..--- "; kosten = kosten + 5; [\]
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
... := "--..-- " Action: telegramm = telegramm + ","; eingabe = eingabe + "--..-- "; kosten = kosten + 5; [\] := "..--.. " Action: telegramm = telegramm + "?"; eingabe = eingabe + "..--.. "; kosten = kosten + 5; [\] := " " Action: telegramm = telegramm + " "; eingabe = eingabe + " "; kosten = kosten + 10; [\] := ".-.-." Action: telegramm = telegramm + "EOM"; eingabe = eingabe + ".-.-."; kosten = kosten + 5;
Startseite
JJ
II
J
I
Seite 92 von 100
Zur¨ uck
Float ko = new Float(kosten/100); preis = "Kosten: " + ko.toString() + "EUR";
Vollbild ein/aus
Schließen
Beenden
Nach Abarbeitung der Eingabe haben wir also die Preisinformation im String preis abgelegt. Die Ausgabe erfolgt u¨ber ein JOptionPane, welches ein Array aus den Strings telegramm, eingabe und preis enth¨alt:
Bin¨ arzahlen Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
sa = new String[3]; sa[0]=telegramm; sa[1]=eingabe; sa[2]=preis; JOptionPane.showMessageDialog(null,sa,"Entschluessler", JOptionPane.INFORMATION_MESSAGE);
Scanner mit Aktionen
Zum Test codieren wir per Hand den Satz quidquid agas, age prudenter et respice finem.“ in Morse-Code und ” verwenden diesen als Eingabe f¨ur den Scanner. --.- ..- .. -.. --.- ..- .. -.. .- --. .- ... --..-- .- --. . .--. .-. ..- -.. . -. - . .-. . - .-. . ... .--. .. -.-. . ..-. .. -. . -- .-.-.- .-.-.
Das Resultat des Scannerdurchlaufs ist folgende Ausgabe: q "--.- " u "..- " i ".. " d "-.. " q "--.- " u "..- " i ".. " d "-.. " worttrenner " " a ".- " g "--. " a ".- " s "... " , "--..-- " worttrenner " "
Startseite
JJ
II
J
I
Seite 93 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
...
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke
worttrenner " " f "..-. " i ".. " n "-. " e ". " m "-- " . ".-.-.- " worttrenner " " schluss ".-.-."
Scanner mit Aktionen
Startseite
JJ
II
J
I
Seite 94 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
4.2. Spracherkennung
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Klammergebirge & Co – Alexander Talaska
Geschachtelte Rechtecke Scanner mit Aktionen
Ein Klammergebirge“ ist die Folge aus ¨offnenden und schließenden Klammern, die u¨brigbleibt, wenn man aus ” einem beliebigen arithmetischen Ausdruck alle Zeichen außer den Klammern streicht. Die Menge aller m¨oglichen Klammergebirge ist die formale Sprache der Klammergebirge. Wie im Beispielband beispieleScreen.pdf erw¨ahnt, l¨asst sich diese Sprache z.B. durch eine kontextfreie Grammatik mit nur zwei Regeln beschreiben: S → (S)S | Die Sprache der Klammergebirge ist eine Teilmenge der Sprache der balancierten Klammerfolgen, die definiert ist durch (die Notation w : a bezeichnet die Anzahl der as in w): { w ∈ {(, )}∗ | w : ( = w :) } Die Sprache der balancierten Klammerfolgen wiederum ist offenbar eine Teilmenge der Sprache aller Klammerfolgen, die definiert ist durch {(, )}∗ . Von den drei Sprachen ist die umfangreichste (d.h. gr¨obste“), die Sprache aller Klammerfolgen, eine Typ-3-Sprache ” und damit von einem endlichen Automaten zu erkennen. Die beiden anderen sind Typ-2-, aber nicht Typ-3 und damit prinzipiell nicht von endlichen Automaten erkennbar. W¨ahrend Jaccie-Scanner im Prinzip auf endlichen Automaten beruhen, werden sie durch die M¨oglichkeit, beim Erkennen eines Tokens eine Aktion, d.h. ein beliebiges Java-Programmst¨uck, auszuf¨uhren, sehr viel m¨achtiger als endliche Automaten. Wir demonstrieren das mit einem Jaccie-Scanner, der Klammerfolgen verarbeitet und nach jedem gelesenen Token (also nach jedem Klammersymbol) in einem Dialogfenster meldet, ob das bisher gelesene Anfangsst¨uck der Folge
Startseite
JJ
II
J
I
Seite 95 von 100
Zur¨ uck
1. gerade balanciert ist 2. Anfangsst¨uck eines Klammergebirges ist Das zweite Kriterium ist erf¨ullt, wenn im Anfangsst¨uck (und in jedem seiner Anfangsst¨ucke) die Anzahl der schließenden Klammern nicht gr¨oßer ist als die Anzahl der o¨ffnenden Klammern.
Vollbild ein/aus
Schließen
Beenden
Um die Eigenschaften des Terms korrekt zu bestimmen ist es notwendig, Informationen u¨ber den bereits abgearbeiteten Abschnitt zu behalten. Dazu f¨uhrt man Variablen ein:
Bin¨ arzahlen
In der ganzzahlige Variablen openB wird die Differenz der ¨offnenden und schließenden Klammern gehalten. Sie erh¨oht bzw. erniedrigt sich mit jeder gelesenen ¨offnenden bzw. schließenden Klammer um 1 .
Geschachtelte Rechtecke
Arithmetische Ausdr¨ ucke
Scanner mit Aktionen
Die Bedingung 1. ist also genau dann erf¨ullt, wenn die Differenz Null ist. Bedingung 2. ist solange erf¨ullt, bis die Differenz einen negativen Wert annimmt, denn dann ist die Anzahl der schließenden Klammern gr¨osser als die der ¨offnenden. Ausserdem folgt aus der Forderung, dass f¨ur ein Anfangsst¨uck eines Klammergebirges die Bedingung 2. auch f¨ur s¨amtliche Pr¨afixe gelten soll. Also kann ein Ausdruck, in dem die Bedingung einmal veletzt wurde, nicht mehr Anfangsst¨uck eines Klammergebirges werden. Diese Information wird hier in dem String sgeb gespeichert. Da dieser auch f¨ur die Ausgabe verwendet wird, nimmt er bei negativer Differenz den Wert "kein " an, sonst ist er leer. In gleicher Weise nutzt man den String sbal, der bei Balanciertheit leer ist und sonst den Wert "nicht " annimmt. Der String kExpr zeichnet den bisher abgearbeiteten Teilausdruck auf. Er erscheint im Titel des Dialogs, der die Eigenschaften des Teilausdrucks angibt. Die Information u¨ber den Teilausdruck ist folgendermaßen zusammengesetzt: "Der Teilausdruck ist " + sbal + "balanciert und " + sgeb + "Anfang eines Klammergebirges."
Der Ablauf an einem Beispiel: Beispiel: --------1.
Ausdruck = ())(
| V ())( openB = 1 = sbal = "nicht ", sgeb = "" Also: "Der Teilausdruck ist nicht balanciert und Anfang eines Klammergebirges."
Startseite
JJ
II
J
I
Seite 96 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Bin¨ arzahlen
2.
| V ())(
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
openB = 0 = sbal = "", sgeb = "" Also: "Der Teilausdruck ist balanciert und Anfang eines Klammergebirges."
3.
| V ())( openB = -1 = sbal = "nicht ", sgeb = "kein " Also: "Der Teilausdruck ist nicht balanciert und kein Anfang eines Klammergebirges." Startseite
4.
| V ())( openB = 0 = sbal = "", sgeb = "kein " Also: "Der Teilausdruck ist balanciert und kein Anfang eines Klammergebirges."
JJ
II
J
I
Seite 97 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden
Typ-2 und Typ-1 erkennen – Stefan Harwarth
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Ein bekanntes Beispiel f¨ur eine Typ-2-Sprache, die nicht Typ-3 ist: {an bn | n ≥ 1}
Geschachtelte Rechtecke Scanner mit Aktionen
n n n
Ein ebenso bekanntes Beispiel f¨ur eine Typ-1-Sprache, die nicht Typ-2 ist: {a b a | n ≥ 1} Der Sachverhalt ¨andert sich nicht, wenn man an jedes Wort der beiden genannten Sprachen ein Endezeichen (#) anh¨angt. F¨ur unser Vorhaben ist es aber n¨utzlich, da wir so ein Token haben, bei dem die Abrechnung gemacht“ ” werden kann. W¨ahrend Jaccie-Scanner im Prinzip auf endlichen Automaten beruhen, also Typ-3-Sprachen erkennen, werden sie durch die M¨oglichkeit, beim Erkennen eines Tokens eine Aktion, d.h. ein beliebiges Java-Programmst¨uck, auszuf¨uhren, sehr viel m¨achtiger als endliche Automaten. Wir demonstrieren das mit zwei Jaccie-Scannern, die jeweils Folgen von as und bs mit Endesymbol # verarbeiten und beim Erkennen des Endesymbols in einem Dialogfenster melden, ob das Wort zur Sprache {an bn | n ≥ 1} (bzw. zur Sprache {an bn an | n ≥ 1}) geh¨ort. L¨ osung: Bei der Aufgabe ist zu beachten, dass hier nur ein Scanner entwickelt werden soll, der bereits in der Lage ist, die beiden angegebenen Sprachen zu erkennen. Beide Sprachen sind Teilmengen von {a | b} ∗ #. Die beiden Scanner sind bis auf eine Codezeile identisch, daher nun zun¨achst der gemeinsame Teil:
Startseite
Definiert sind als Token des Scanners:
JJ
II
:= $a Action: a1++; [\]
J
I
Seite 98 von 100
:= $b Action: b++; [\]
Zur¨ uck
Vollbild ein/aus
:= $a Start: (b > 0); [\] Action: a2++; [\]
Schließen
Beenden
:= $# Action: (siehe unten)
In der Action des endToken, die weiter unten gezeigt wird, liegt der Unterschied der beiden Scanner.
Bin¨ arzahlen
Jedem Token der Scanner ist eine Action zugeordnet. Das ist ein beliebiges Java-Codest¨uck (bei dem jede Codezeile mit [\] abgeschlossen ist), das bei Erreichen des Tokens ausgef¨uhrt wird und damit die endlichen Automaten des Jaccie-Scanners viel m¨achtiger macht. In den Actions der Token wird nichts weiter gemacht, als 3 Variablen zu inkrementieren, die jeweils die Anzahl der a vor dem ersten b, die nach dem ersten b und die Anzahl der b wiederspiegelt.
Arithmetische Ausdr¨ ucke Geschachtelte Rechtecke Scanner mit Aktionen
Daneben hat das aNachB-Token eine Start-Bedingung, die als Vorbedingung f¨ur das Erreichen dieses Tokens erf¨ullt sein muss. Der aufmerksame Beobachter hat schon gesehen, dass sich aToken und aNachB nur in dieser Bedingung unterscheiden. Das heisst, Jaccie pr¨uft bei der Ausf¨uhrung die Bedingung von aNachB und matcht - falls erf¨ullt dieses Token, oder - falls nicht erf¨ullt - das Token aToken. F¨ur die Action Codest¨ucke ist es n¨otig, die verwendeten Variablen zu deklarieren und initialisieren. Dies geschieht im Abschnitt Global Declarations: Global Declarations: int a1 = 0; int a2 = 0; int b = 0; Startseite
Ferner ist es n¨otig f¨ur die unten gezeigte Ausgabe der Benachrichtigung an den Benutzer einige Teile des JavaFramework einzubinden, was im Import-Abschnitt geschieht: Import: import java.util.*; import javax.swing.*;
JJ
II
J
I
Seite 99 von 100
Zur¨ uck
Abschließend nun die beiden endToken, in denen die Variablen ausgewertet und anhand ihrer Werte der Typ der Sprache ermittelt wird. Wichtig ist hier auch die Pr¨ufung, ob u¨berhaupt Zeichen gez¨ahlt wurden, da die beiden Sprachen eine L¨ange n ≥ 1 erwarten. Die abschließende R¨ucksetzung der Variablen ist n¨otig, da sonst der Scanner vor jedem Lauf neu kompiliert werden m¨usste - it’s not a bug, it’s a feature?
Vollbild ein/aus
Schließen
Beenden
Typ-2-Sprache
Bin¨ arzahlen Arithmetische Ausdr¨ ucke
Action: String s = "Nicht in der Sprache: a^n b^n | n >= 1"; if ((a1 >= 1) && (a1 == b) && (a2 == 0)) s = "Wort der Sprache: a^n b^n | n >= 1"; JOptionPane.showMessageDialog(null, s, "Scanner", JOptionPane.INFORMATION_MESSAGE); a1 = a2 = b = 0; [\]
Geschachtelte Rechtecke Scanner mit Aktionen
Typ-1-Sprache Action: String s = "Nicht in der Sprache: a^n b^n a^n | n >= 1"; if ((a1 >= 1) && (a1 == b) && (a2 == a1)) s = "Wort der Sprache: a^n b^n a^n | n >= 1"; JOptionPane.showMessageDialog(null, s, "Scanner", JOptionPane.INFORMATION_MESSAGE); a1 = a2 = b = 0; [\]
Bei Eingabe von aaabbbaaa#
Startseite
JJ
II
J
I
ergibt sich erwartungsgem¨aß: Seite 100 von 100
Zur¨ uck
Vollbild ein/aus
Schließen
Beenden