Expression (arithmetische Ausdrücke) Beispiel $ CLASSPATH=. java Expression2 2+3*4 BinaryAdd 2 BinaryMul 3 4 14.0 Grammatikregeln -- Backus-Naur-Form (BNF) Formal besteht eine Grammatik aus einer Menge von Eingabesymbolen, einer Menge von Grammatikbegriffen, daraus einem Startbegriff, und einer Menge von Regeln, das heißt, bestimmten Paaren von Folgen von Grammatikbegriffen und Eingabesymbolen; alle Mengen und Folgen müssen endlich sein. Typischerweise schreibt man nur die Regeln auf und verlangt bei kontextfreien Grammatiken, daß die linke Seite einer Regel immer ein Grammatikbegriff sein muß. Nach Konvention steht der Startbegriff auf der linken Seite der ersten Regel und man faßt rechte Seiten zum gleichen Grammatikbegriff als Alternativen zusammen. Die Wiederholungen der Syntaxgraphen muß man durch rekursive Verweise modellieren. Für arithmetische Ausdrücke sieht das etwa so aus: sum : product | sum ’+’ product | sum ’-’ product ; product : term | product ’*’ term | product ’/’ term | product ’%’ term ; term : ’+’ term | ’-’ term | ’(’ sum ’)’ | Number ; trennt linke und rechte Seite, | trennt Alternativen, ; steht nach allen rechten Seiten zum gleichen Grammatikbegriff. Eingabesymbole werden mit einfachen Anführungszeichen zitiert. Da Number nicht links vorkommt, muß Number (implizit) eine Klasse von Eingabesymbolen repräsentieren. Man könnte auch folgende Regeln hinzufügen: : Number : digit | Number digit ; digit : ’0’ | ’1’ | ’2’ | ’3’ | ’4’ | ’5’ | ’6’ | ’7’ | ’8’ | ’9’ ; Grammatikregeln -- Erweiterte Backus-Naur-Form (EBNF) Syntaxgraphen korrespondieren wesentlich intuitiver zu Grammatikregeln, wenn man sich auf Schreibweisen für Wiederholungen und relativ standardisierte Graphen einigt, zum Beispiel one alt two alt : ( one | two ) ; ( ) | zur Zusammenfassung für Alternativen { } einmal oder mehrfach [ ] höchstens einmal some body some : { body } ; opt body opt : [ body ] ; many body many : [{ body }] ; kombiniert: beliebig oft EBNF ist als Schreibweise für Wiederholungen eine verkürzende Schreibweise für BNF. Für die meisten Menschen ist EBNF intuitiver als BNF. Die traditionelle Schreibweise für Wiederholungen in EBNF hat Probleme bei 1-n Wiederholungen. Hier muß man Teile der Grammatik verdoppeln. konventionelle Schreibweise: {...} 0-n mal wiederholen [...] 0 oder 1 mal erkennen unsere Schreibweise: {...} 1-n mal wiederholen [...] 0 oder 1 mal erkennen Analog zu den folgenden Syntaxgraphen sehen arithmetische Ausdrücke dann etwa so aus: sum : product [{ (’+’|’-’) product }]; product : term [{ (’*’|’/’|’%’) term }]; term : [{’+’|’-’}] ( Number | ’(’ sum ’)’ ) ; Rekursiver Abstieg Idee: Pro Graph wird eine Funktion implementiert, die diesen Teil der Grammatik erkennt. Die Funktionen rufen sich gegenseitig (auch rekursiv) auf. Man steigt so in Richtung der Blätter (auch rekursiv) in der Erkennung ab. Hat die Funktion einen Teil erkannt, führt sie entsprechende Aktionen aus. Im Expression-Beispiel könnte das Ergebnis des Teilausdrucks sofort berechnet werden, oder es wird wie in der Vorlesung ein Baum gebaut, der die erkannte Informationen repräsentiert. Wenn alle Knoten und Blätter im Baum Unterklassen von java.lang.Number sind, kann der Wert des arithmetischen Ausdrucks über die Methoden der Number-Klasse in verschiedenen Typen berechnet werden. Bäume für arithmetische Ausdrücke Hier zwei Beispiel für Bäume, die einen arithm. Ausdruck speichern. Das Programm gibt nun auch den Baum textuell aus. • 5-6*8: - 5 * 6 8 $ pwd; make stdin ..../lab2/addon/expr $ CLASSPATH=.. java expr.Expression2 5-6*8 tree: BinarySub 5 BinaryMul 6 8 -43.0 • 9-+-9*-(-3*(3-2)) 9 * - - 9 * 3 3 2 $ CLASSPATH=.. java expr.Expression2 5-6*8 BinarySub 9 BinaryMul UnaryMinus 9 UnaryMinus BinaryMul UnaryMinus 3 BinarySub 3 2 36.0