Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Agenda Motivation und Einordnung Syntaxgerichtete Übersetzung

Ähnliche Präsentationen


Präsentation zum Thema: "Agenda Motivation und Einordnung Syntaxgerichtete Übersetzung"—  Präsentation transkript:

0 Syntaxgerichtete Übersetzung und Typüberprüfung
Sommersemester 2009

1 Agenda Motivation und Einordnung Syntaxgerichtete Übersetzung
Syntaxgerichtete Definition Auswertungsreihenfolge für syntaxgerichtete Definition Verfahren zur syntaxgerichteten Übersetzung Implementierung von L-attributierter syntaxgerichteten Definition Typüberprüfung Dynamische und statische Überprüfung Typsysteme Regeln für die Typüberprüfung Fazit

2 Motivation und Einordnung
Von der Quellsprache zur Zielmaschine Erledigt: Quellprogramm kann lexikalisch und syntaktisch analysiert werden, ein Ableitungsbaum kann erstellt werden Zu tun: Semantische Analyse und Erzeugung des Zielprogramms aus dem Ableitungsbaum Idee: Syntaxanalyse steuert semantische und andere Aktionen wie Codeerzeugung

3 Syntaxgerichtete Übersetzung
Syntaxdefinition Syntaxgerichtete Definition Kontextfreie Grammatik Beschreibung der hierarchischen Struktur einer Programmiersprache if (Ausdruck) Anweisung else Anweisung stmt → if (expr) stmt else stmt Kontextfreie Grammatik Grammatiksymbole + Attributen Produktionen + Semantikregeln Produktion E → E1 + T Semantikregel E.code = E1.code|| T.code||‘+‘ Die Syntaxgerichtete Übersetzung beruht auf die Syntaxdefinition. Syntaxdefinition ist ein Kontextfreien Grammatik womit die Syntax einer Sprache festgelegt wird. Mit einer Grammatik wird die hierarchische Struktur der meisten Programmiersprachenkonstrukte auf natürlicher Weise beschrieben. In Java kann eine if else Anweisung beispielsweise wie folgt aussehen. Bei Verwendung der Variablen expr zur Angabe eines Ausdruckes und stmt zur Angabe einer Anweisung kann eine Strukturregel wie folgt aufgestellt werden. (Pfeil bedeutet, kann die form haben) Eine solche Regel wird als Produktion bezeichnet, wobei lexikalische Elemente (if oder Klammern) als Terminale bezeichnet werden und Variablen wie expr und stmt stellen Sequenzen von Terminalen dar und werden als Nichtterminale bezeichnet. Syntaxgerichtete Definition Um eine Syntaxgerichtete Übersetzung durchführen zu können, müssen wir den Sprachkonstrukt (Syntaxdefinition) Informationen zu ordnen. Dazu nehmen wir die Syntaxgerichtete Definition. Eine Syntaxgerichtete Definition ist kontextfreie Grammatik bei der Grammatiksymbole mit Attribute versehen werden und Produktionen mit Sematikregeln. Eine syntaxgerichtete Definition spezifiziert die Werte von Attributen durch Zuordnen semantischer Regeln zu den Grammatikproduktionen. Diese Produktion hat zwei Nichtterminale E und T. Der Index in E unterscheidet das Auftreten von E im Produktionsrumpf vom Auftreten von E als Kopf. Sowohl E als auch T haben ein Attribut code vom Typ string. Die semantische Regel gibt an, dass der String E.code durch die Verkettung von E1.code, T.code und dem Zeichen ‚+‘ gebildet wird. || steht für die stringverkettung.

4 Syntaxgerichtete Übersetzung
Attribute in Grammatiken Synthetisierte Attribut Wert hängt nur vom Nachfolgeknoten ab Ererbtes Attribut Wert hängt von Vorgänger und Geschwistern ab

5 Syntaxgerichtete Übersetzung
Syntaxgerichtete Definition eines einfachen Taschenrechner mit den Operatoren + und *. Sie wertet Ausdrücke aus, die durch ein Endekennzeichnen n abgeschlossen sind. In der syntaxgerichteten Definition hat jedes Nichtterminal ein einziges synthetisiertes Attribut namens val. Wir nehmen auch an, dass das Terminal ziffer ein synthetisiertes Attribut lexval hat, bei dem es sich um einen ganzzahligen Wert handelt, der von der lexikalischen Analyse zurückgegeben wird. Setz L.val = E.val, was dem nummerischen Wert des gesamten Ausdruckes entspricht Attribut val für den Kopf E al Summe der Werte bei E1 und T berechnet. Wert von val als für E als das Gleiche wie den Wert von val bei dem Kind von T definiert wie 2 Und 6 kopieren die Werte für kind 7. Gibt F.val den Wert einer Ziffer, also den numerischen Wert des Tokens ziffer, den die lexikalische Analyse zurückgibt. Syntaxgerichtete Definition eines einfachen Taschenrechners

6 Syntaxgerichtete Übersetzung
Wir sehen hier einen kommentierten Parse-Baum für den Eingabestring 3*5+4. Ein Kommentierter Parse-Baum, ist ein Parse-Baum welche die Werte seiner Attribute zeigt. Es wird angenommen, dass die Werte von lexval von der lexikalischen Analyse geliefert werden. Jeder Knoten für ein Nichtterminal hat ein Attribut val, das in einer Botton up Reihenfolge berechnet wird, wobei wir die mit jedem Knoten verbundenen Ergebniswerten sehen. Kommentierter Parse-Baum für 3*5+4

7 Auswertungsreihenfolge für syntaxgerichtete Definitionen
Abhängigkeitsgraph Informationsfluss zwischen den Attributinstanzen Kanten drücken die durch Semantikregeln auferlegten Einschränkungen aus Abhängigkeitsgraph Informationsfluss zwischen den Attributinstanzen Kanten drücken die durch Semantikregeln auferlegten Einschränkungen aus Abhängigkeitsgraphen sind ein nützliches Werkzeug zur Bestimmung einer Auswertungsreihenfolge für die Attributinstanzen eines gegebenen Parse-Baumes. Während ein kommentierter Parse-Baum die Werte von Attributen zeigt, hilft uns ein Abhängigkeitsgraph bei der Bestimmung, wie sich diese Werte berechnen lassen. Ein Abhängigkeitsgraph stellt den Informationsfluss zwischen den Attributinstanzen eines bestimmten Parse-Baumes dar. Eine Kante von einer Attributinstanz zu einer anderen bedeutet, dass der Wert der ersten benötigt wird, um den der zweiten zu berechnen. Kanten drücken die durch die semantischen Regeln auferlegten Einschränkungen aus. Grammatik (3*5) beginnt mit der Produktion 1. Hier generiert F die Ziffer 3, aber der Operator * wird von T‘ generiert. Der linke Operand 3 erscheint somit in einem anderen Unterbaum des Parse Baumes als *. Deshalb wird ein ererbtes Attribut verwendet, um den Operanden an den Operator zu übergeben. Die Knoten des Abhängigkeitsgraphen, die durch die Zahlen 1 bis 9 dargestellt werden, entsprechen den Attributen im kommentierten Parse Baum. Die Kanten von Knoten 1 zu 3 und von Knoten 2 zu 4 ergeben sich aus der semantischen Regel, die F.val durch digit.lexval definiert. Tatsächlich ist F.val gleich digit.lexval, aber die Kante stellt eine Abhängigkeit und keine Gleichheit dar. Die Knoten 5 und 6 stellen das ererbte Attribut T´.inh dar, das mit jedem Auftreten des Nichtterminals T´ verbunden ist.

8 Auswertungsreihenfolge für syntaxgerichtete Definitionen
S-attributierte Definition Alle Attribute sind synthetisiert Abhängigkeitsgraph mit zirkulären Bezügen wird nicht zugelassen Auswertungsreihenfolge garantiert Auswertung durch Botton Up Reihenfolge postorder (N) { for (jedes Kind C von N von links aus) postorder (C); fasse Attribute von/mit N zusammen; }

9 Auswertungsreihenfolge für syntaxgerichtete Definitionen
L-attributierte Definition Zwischen den mit der Produktion verbundenen Attritbuten verlaufen die Kanten im Abhängigkeitsgraphen nur von links nach rechts Attribute sind synthetisiert oder vererbt (eingeschränkt) Vererbte Attribute sind mit dem Regelkopf verbunden Auswertung durch eine Top Down Reihenfolge dfvisit (N) { for (jeden Nachfolger M von N von links nach rechts) werte ererbte Attribute aus; dfvisit (M); werte die synthetisierten Attribute von N aus; }

10 Anwendung der syntaxgerichtete Übersetzung
Syntaxbaum Verdichteter Parse-Baum Jeder Knoten eines Syntaxbaums stellt ein Konstrukt dar Die Kinder des Knotens repräsentieren die sinnvollen Komponente des Konstrukts Zwischendarstellung

11 Syntaxgerichtete Übersetzungsschemata
Ergänzende Notation zur syntaxgerichteten Definition Kontextfreie Grammatik mit Programmfragmenten die in die Produktionsrümpfe eingebettet sind Programmfragmente (semantische Aktionen) können an jeder Stelle eines Produktionsrumpfes erscheinen. Auswertungsreihenfolge der semantischen Regeln durch Position gegeben Aktionen werden mit {..} eingeschlossen Ergänzende Notation zur syntaxgerichteten Definition Kontextfreie Grammatik mit Programmfragmenten, die in die Produktionsrümpfe eingebettet sind Programmfragmente (semantische Aktionen) können an jeder Stelle eines Produktionsrumpfes erscheinen Auswertungsreihenfolge der semantischen Regeln durch Position gegeben Aktionen werden mit {..} eingeschlossen rest → + term {printf (‚+‘}; rest 1 Ein syntaxgerichtetes Übersetzungsverfahren ist eine Notation, bei der eine Übersetzung festgelegt wird, indem Programmfragmente den Produktionen in einer Grammatik hinzugefügt werden. Mit Ausnahme der Tatsache, dass die Auswertungsreihenfolge der semantischen Regeln ausdrücklich angegeben ist, gleichen Übersetzungsverfahren syntaxgerichteten Definitionen. Beim Zeichen eines Parse Baumes für ein Übersetzungsverfahren wird eine Aktion angezeigt, indem für die Aktion ein Extrakind erstellt und durch eine unterbrochene Linie mit dem Knoten verbunden wird, der dem Kopf der Produktion entspricht. Da knoten für eine semantische Aktion keine Kinder haben, wird die Aktion ausgeführt sobald der Knoten zum ersten mal gesehen wird. Verfahren zur syntaxgerichteten Übersetzung

12 Syntaxgerichtete Übersetzungsschemata
Ausdrücke in Infix-Notation (9-5)+2 oder 9-(5+2) Ausdrücke in Postfix-Notation 9 5 – 5 + oder Beispiel: Übersetzungsschemata Definition um Ausdrücke in Infix Notation in Postfix Notation zu transformieren.

13 Syntaxgerichtete Übersetzungsschemata
( 9 – 5) + 2

14 Syntaxgerichtete Übersetzungsschemata
(9 – 5) + 2 Der Parse Baum hat print Anweisungen auf zusätzlichen Blättern die durch unterbrochene Linien mit innereren Knoten des Parse baums verbunden sind. Diese Ausdrücke werden von den im rumpf einer Produktion eingebettenen Aktionen in eine Postfixnotation übersetzt, vorausgesetzt, wir führen einen Depth first Durchlauf des Baumes von links nach rechts durch und führen jede print Anweisung beim Besuch ihres Blattes aus.

15 Syntaxgerichtete Übersetzungsschemata
(9 – 5) + 2 9 9 5 9 5 – 9 5 – 2 9 5 – 2 + Der Parse Baum hat print Anweisungen auf zusätzlichen Blättern die durch unter

16 Implementierung von L-attributierten syntaxgerichteten Definitionen
Übersetzung beim Durchlaufen eines Parse-Baumes Aufbauen und Kommentieren des Parse-Baumes Aufbauen des Parse-Baumes, Hinzufügen von Aktionen und Ausführen der Aktionen in Postorder Übersetzung während des Parserns Verwenden eines rekursiven absteigenden Parsers Generieren von Code im laufenden Betrieb Implementieren einer syntaxgerichteten Übersetzung zusammen mit einem LL-Parser Implementieren einer syntaxgerichteten Übersetzung zusammen mit einem LR-Parser Übersetzung beim Durchlaufen eines Parse-Baumes Aufbauen und Kommentieren des Parse-Baumes Aufbauen des Parse-Baumes, Hinzufügen von Aktionen und Ausführen der Aktionen in Postorder Übersetzung während des Parserns Verwenden eines rekursiven absteigenden Parsers Generieren von Code im laufenden Betrieb Implementieren einer syntaxgerichteten Übersetzung zusammen mit einem LL-Parser Implementieren einer syntaxgerichteten Übersetzung zusammen mit einem LR-Parser

17 Implementierung von L-attributierten syntaxgerichteten Definitionen
L-attributierte syntaxgerichtete (LL-Grammatik) Aktionen in den Produktionen eingebettet Übersetzung während der LL-Syntaxanalyse Implementierung von L-attributierten syntaxgerichteten Definitionen L-attributierte syntaxgerichtete (LL-Grammatik) Aktionen in den Produktionen eingebettet Übersetzung während der LL-Syntaxanalyse Aktionsdatensatz: Enthält einen Zeiger auf ausführbaren Code (meist Auswertung von ererbten Attributen) Synthetisierungsdatensatz: Enthält Anweisungen zur Synthese von Attributen und Aktionen (kopieren der synthetisierten Attribute in andere Datensätze weiter unten im Stack) Wir können dann die Übersetzung während der LL Syntaxanalyse vornehmen, indem wir den Parserstack erweitern, um aktionen und bestimmte Datenelemente zu halten, die für die Auswertung der Attribute benötigt werden. Zusätzlich zu den Datensätze zur Darstellung von Terminalen und Nichtterminalen enthält der Parserstack Aktionsdatensätze, die die auszuführenden Aktionen darstellen, und Synthetisierungsdatensätze, um die synthetisierte Attribute für Nichtterminalen zu halten. L-attributierte syntaxgerichtete Definitionen und LL-Syntaxanalyse

18 Dynamische und statische Überprüfung
Wir unterscheiden zwischen Statischen Überprüfung (während der Kompilierung) Dynamischen Überprüfung (zur Laufzeit) Statische Überprüfung Typüberprüfung Überprüfung der Kontrollflusses Überprüfung auf Eindeutigkeit Auf Namen bezogene Überprüfung Dynamische Überprüfung Dynamische Typüberprüfung ist erforderlich, wenn der Typ von Variablen und Objekten nur zur Laufzeit bestimmt werden kann Typüberprüfungen Ein Compiler sollte einen Fehler melden wenn einem integer ein string zugewiessenwerden soll. Überprüfungen der Kontrollflusses Es gibt Anweisungen wie z.B das break die den Kontrollfluss eines Konstrukteswie der while-for-Schleife oder switch-Anweisung verlassen ,ein Compiler sollte einen Fehler melden wenn eine solche umschließende Anweisung nicht existiert. Überprüfung auf Eindeutigkeit Sollte der Name einer Variable innerhalb des gleichen Anweisungsblockes definieren, so muss der Compiler eine Fehler melden. Auf Namen bezogene Überprüfung Es gibt gewisse Definitionen die auf bestimmte Namenskonventionen basierender Compiler muss das Überprüfen.

19 Typüberprüfung Was wird überprüft?
Ob Operatoren und Operanden kompatibel sind Welche Programmelemente haben einen Typ? Konstanten Variablen Ausdrücke Parameter Welche Attribute werden durch Typen festgelegt? Werte von Konstanten Wertebereiche / Operationen für Variable, Ausdrücke, Parameter Übergabemechanismus für Parameter Verwendung von Informationen über Typen Ermittlung des Speicherbedarf Erzeugung von Code für die Umwandlung von einem Typ in einen anderen Ermittlung des Resultatttyps

20 Typüberprüfung - Beispiele
x div y → x, y müssen vom Typ integer sein. array [INDEX] of …. → INDEX muss Ordnungstyp sein. procedure p(formal_1: Typ_1, var formal 2: Typ 2); …… p (aktuell_1, aktuell_2); aktuell_1 mit formal_1 verträglich? aktuell_2 mit formal_2 verträglich? aktuell_2 muss eine Variable sein.

21 Typsysteme Was ist ein Typsystem?
Ein Typsystem für eine Programmiersprache ist eine Menge von Regeln, die die korrekte Verwendung von Typen im Kontext bestimmen. Für bestimmte Konstrukte muss der Typ gegeben sein (Definition) und für andere kann der Typ aus der Struktur bestimmt werden. Ein Typsystem heißt stark, wenn alle möglichen statischen Typkonflikte zur Übersetzungszeit erkannt werden können. Ein Typsystem besteht aus gewissen Basistypen (Typnamen) und Konstruktoren, mit denen neue Typen aus vorhandenen konstruiert werden können. Mit den Konstruktoren werden Typausdrücke gebildet

22 Typüberprüfung von Ausdrücke
Defintion einiger Basistypen Der ausdruck, der durch die Anwendung der mod Operation auf zwei Teilausdrücke von Typ interger gebildet wird, hat den Typ interger. Bei einem Fehler kommt es zum Typ In einer Array-Referenz E1[E2] muss der Indexausdruck E2 den Typ integer haben. In dem Fall ist das Ergebnis der Elementtyp t, den man aus dem Typ array(s,t) des Ausdrucks E1 erhält.

23 Typüberprüfung von Anweisung
Da Sprachkonstruktewie Anweisungen typischerweise keine Wertehaben, kann diesen der spezielle einfache Typ void zugewiesen werden. Sollte innerhalb eine Anweisung ein Fehler auftreten, so wird der Anweisung das Typ type_error zugewiesen.

24 Fazit Der allgemeine Ansatz für die syntaxgerichtete Übersetzung besteht darin, einen Parser- oder Syntaxbaum zu konstruieren und dann die Werte der Attribute an dem Knoten des Baumes zu berechnen, indem diese Knoten aufgesucht werden. Zwei Notationen möglich Syntaxgerichtete Definition. Sie verbergen viele Implementierungsdetails und befreien den Benutzer von der expliziten Spezifikation der Reihenfolge, in der die Übersetzung stattfindet Übersetzungsschemata legen die Reihenfolge fest, in der die semantischen Regeln auszuwerten sind, daher erlauben sie es, einige Implementierungsdetails zu zeigen.

25 Fazit

26 if <complex test> the 5 else <type error>
Fazit Typüberprüfung Wichtig, um mögliche Programmfehler fest zu stellen Statische und dynamische Überprüfung if <complex test> the 5 else <type error> Dieser Code (einer gedachten Programmiersprache) ist typkorrekt, da er niemals zu einer problematischen Zuweisung führen kann. Dennoch würde eine statische Typprüfung die Zuweisung eines Strings an eine Integer-Variable normalerweise als Typfehler auffassen und zur Übersetzungszeit scheitern lassen. Es lässt sich leicht überlegen, dass in weniger zugespitzten Fällen Programmcode vom Typsystem zurückgewiesen wird, obwohl er nachweislich typkorrekt ist. Das Typsystem müsste eine erhebliche Komplexität erreichen, um das Laufzeitverhalten von Programmen bei den Typprüfungen zu berücksichtigen, was umgekehrt das Typsystem komplexer und schwerer handhabbar (und damit anfälliger für Fehlverwendungen durch den Programmierer) machen würde. Typsysteme sind daher immer Kompromisse zwischen möglichst strikten statischen Prüfungen und einer die Flexibilität und Ausdrucksstärke der Sprache bewahrenden dynamischen Prüfung.

27 Backup-Folien

28 Implementierung von L-attributierten syntaxgerichteten Definitionen
Syntaxgerichtete Übersetzung für while-Anweisungen Implementierung von L-attributierten syntaxgerichteten Definitionen Syntaxgerichtete Übersetzung für while-Anweisungen Hier ist S das Nichtterminal, das alle Arten von Anweisungen generiert. C steht für einen bedingten Ausdruck ( einen booleschen Ausdruck, der als true oder false ausgewertet wird) das Ererbte Attribut s.next kennzeichnet den Anfang des Codes der ausgeführt werden muss, nachdem s fertig ist. S. Code ist die Folge von Zwieschencodeschritte, die eine Anweisung S implementiert und mit einem Sprung nach s.next enden. c.Code ist die Folge von Zwischencodeschritten, die die Bendigung c implementiert und entweder nach c.true oder nach c.false springe je ob true oder false. A Zeitpunkt an dem wir damit beginnen, die while Produktion zum expandieren von s zu verwenden. Der Datensatz oben auf den Stack ist für S und enthält nur das ererbte Attribut S.next, von dem wir annehmen das es den Wert x hat. Da wir jetzt ein Top Down Parsing vornehmen, zeigen wir das obere Ende des stacks auf der linken seite. B L-attributierte syntaxgerichtete Definitionen und LL-Syntaxanalyse

29 Backup-Folien Attribut Auswertung

30 Backup-Folien Attributierte LR – Grammatik für Ausdrücke (Infix → Postfix)

31 Backup-Folien Attributierte LL – Grammatik für Ausdrücke (Infix → Postfix)

32 Backup-Folien

33 Backup-Folien Typ-Ausdrücke

34 Backup-Folien Grafische Darstellung von Typausdrücke

35 Backup-Folien Syntaxgesteuerte Überprüfung von Typen

36 Backup-Folien Übersetzungsschema für Deklarationen

37 Backup-Folien Übersetzungsschema für Anweisungen

38 Backup-Folien Äquivalenz von Typen
Grundtypen (interger, char, boolean,…) sind immer äquivalent Typkonstruktoren (array, x, pointer,..) Überprüfung der strukturellen Äquivalenz Äquivalenz von Typen

39 Backup – Folien Überprüfung der strukturellen Äquivalenz

40 Backup – Folien Namensäquivalenz

41 Backup – Folien Strukturäquivalenz

42 Backup-Folien Ererbte Attribute - Typdeklarationen

43 Backup-Folien

44 Backup-Folien Wie kommt man zu einen Übersetzungsschema


Herunterladen ppt "Agenda Motivation und Einordnung Syntaxgerichtete Übersetzung"

Ähnliche Präsentationen


Google-Anzeigen