Präsentation herunterladen
Die Präsentation wird geladen. Bitte warten
1
Übersetzertechnik (in Arbeit!!!)
© Günter Riedewald Die Folien sind eine Ergänzung der Vorlesung und nur für den internen Gebrauch konzipiert.
2
Motivation Programmiersprachen als wichtiges Mittel der Softwaretechnik Weiterentwicklung der Softwaretechnik erfordert neue Sprachen einschließlich deren Implementation Programmiersprachen: - universell (Universalsprachen, general purpose languages): allgemein einsetzbar und unabhängig von einem konkreten Einsatzgebiet; Compilerentwicklung durch Spezialisten
3
- spezialisiert (Fachprogrammiersprachen, Spezialsprachen, special purpose languages, domain specific languages): in Syntax und Semantik zugeschnitten auf ein bestimmtes Fachgebiet; wegen stetig wachsendem Bedarf Entwicklung von Compilern/Interpretern auch durch Nichtspezialisten Probleme des Übersetzerbaus treten auch in anderen Gebieten der Informatik auf (z.B. XML) Abstrakte Betrachtung einer Übersetzung: - Analyse der Struktur der Eingabedaten - Strukturabhängige Erzeugung der Ausgabedaten
4
Gute Kenntnisse über Programmiersprachen und deren Compiler als Voraussetzung für Qualitätssoftware
Didaktische Gründe: - Exemplarisches Vorgehen für die Entwicklung größerer Softwaresysteme: klarer logischer Aufbau, Modularisierung, Nutzung von Werkzeugen, Wartbarkeit, Wiederverwendbarkeit - Fachübergreifende Rolle bzgl. Voraussetzungen und eingesetzten Techniken: Automatentheorie, Theorie der formalen Sprachen, Theorie der Programmiersprachen, Prinzipien der Softwaretechnik, Rechnerarchitektur/ Rechnersysteme ...
5
- Enger Zusammenhang zwischen Theorie und Praxis: gute theoretische Basis als Voraussetzung der Automatisierung der Compilerentwicklung Vorbildcharakter für andere Informatikbereiche
6
Literatur A.V. Aho, J.D. Ullman: The Theory of Parsing, Translation and Compiling, Prentice Hall, 1972 A.V. Aho, J.D. Ullman: Principles of Compiler Design Addison-Wesley, 1977 A.V. Aho, R. Sethi, J.D. Ullman (2007 zusätzlich: M. S. Lam): Compilers Principles, Techniques and Tools, (Drachenbuch), Addison Wesley, 1986, 2007
7
A.V. Aho, R. Sethi, J.D. Ullman: Compilerbau, (Drachenbuch), Addison-Wesley, 1988, 1990
H. Alblas, A. Nymeyer: Practice and Principles of Compiler Building with C, Prentice Hall, 1996 A. W. Appel: modern compiler implementation in Java (in C) – basic techniques, Cambridge University Press, 1997 J. Elder: Compiler Construction – A Recursive Descent Model, Prentice Hall, 1994 D. Gries: Compiler Construction for Digital Computers, Wiley, 1971 In Russ.: Konstruirovanije kompiljatorov dlja cifrovych vyčislitelnych mašin, Mir, 1975
8
J. Holmes: Object-Oriented Compiler Construction, Prentice-Hall, 1995
U. Kastens: Übersetzerbau, Oldenbourg Verlag, 1990 H. Loeper, W. Otter, H.-J. Jäkel: Compiler und Interpreter für höhere Programmiersprachen, Akademie-Verlag, 1987 K. C. Louden: Compiler Construction – Principles and Practice, PWS Publ. Com., 1997 S. S. Muchnik: Advanced Compiler Design and Implementation, Morgan Kaufmann Publishers, 1997
9
S. Naumann, H. Langer: Parsing, Teubner Stuttgart, 1994
P. Rechenberg, M. Mössenbeck: Ein Compiler-Generator für Mikrocomputer, Hanser Verlag, 1985 W.M. Waite, G. Goos: Compiler Construction, Springer, 1984 D.A. Watt: Programming Language Processors, Prentice Hall International Series in Computer Science, 1993 D.A. Watt, D. F. Brown: Programming Language Processors in Java – Compilers and Interpreters, Prentice-Hall, 2000
10
R. Wilhelm, D. Maurer: Übersetzerbau – Theorie, Konstruktion, Generierung, Springer-Lehrbuch, 1992
N. Wirth: Compilerbau, Teubner Studienbücher Informatik, Teubner Stuttgart, 1986 P. D. Terry: Compilers & Compiler Generators – An Introduction with C++, Intern. Thomson Computer Press, 1997 H. Zima: Compilerbau I, II , BI Mannheim, Reihe Informatik 36,37, 1982, 1983
11
Translatoren - Arten Assemblierer (Assembler): übersetzt aus einer Sprache niederen Niveaus (Sprache mit symbolischer Adressierung, Assemblersprache) in Maschinensprache meist im Verhältnis 1:1 Makroassembler: übersetzt aus einer Sprache niederen Niveaus in Maschinensprache meist im Verhältnis 1:n mit n 1 Compiler: übersetzt aus Sprache von hohem Niveau in Maschinensprache (letztendlich)
12
Präprozessor: übersetzt aus Obermenge zu einer Sprache in Ausgangssprache
Translator auf hohem Niveau: übersetzt aus Sprache hohen Niveaus in andere Sprache hohen Niveaus Decompiler (Disassembler): Regeneriert Quellcode aus Zielcode Self-resident translator: Erzeugung von Zielcode für die Wirtsmaschine (host) Cross-translator: Erzeugung von Zielcode für andere Maschine Interpreter: anweisungsweise Übersetzung und sofortige Ausführung von Quellcode
13
Interpretativer Compiler: Übersetzung aus einer Sprache hohen Niveaus in eine Zwischensprache mit anschließender Interpretation Emulator: Interpretation des Codes einer anderen Maschine
14
1 Übersetzerbau - Einführung
1.1 Symbolische Darstellungen Übersetzer Übersetzung Programm P Übersetzer Programm P von P in Quell- in I in Zielsprache Z sprache Q Abarbeitung Eingabe- P Ausgabe- von P daten in Z daten
15
Interpretation Programm P Inter- Ausgabedaten von P in Quell- preter sprache Q Eingabedaten T-Diagramme (tombstones) Übersetzer P P Q Q Z Z I
16
Abarbeitung eines Programms E P A Z Interpreter Q
17
Modifikationen der T-Diagramme
Programm P in L geschrieben P L Maschine M M Bezeichneter Compiler <Name>
18
1.2 Einführungsbeispiel Übersetzung von Pascal in P-Code
P-Code: - Sprache der P-Maschine (abstrakter Rechner) - Zwischensprache in Compilern P P P Pascal Pascal P-Code P-Code P-Code M M M M
19
1.2.1 Implementierungsprinzipien für ausgewählte imperative Sprachkonzepte
Imperative Konzepte Variablenkonzept: - Variable als Modell für einen Speicherplatz - Möglichkeit des Lesens und der Wertänderung (Schreiben) Compilersicht: Speicherplatzzuordnung + Zugriff zum Wert als Ganzes oder in Teilen + Lebensdauer + Gültigkeitsbereich (Zugriffsrechte) Strukturierungskonzept für Datenstrukturen Compilersicht: Abspeicherungskonzept + Zugriff
20
Sprachkonzepte zur Ablaufsteuerung
Compilersicht: Umsetzung in Sprünge unterschiedlicher Art Prozedurkonzept: - Nichtrekursive Prozedur Compilersicht: Ersetzen des Aufrufs durch Anweisungen der Prozedur oder Sprünge mit Rückkehr zur Anweisungsfolge - Rekursive Prozedur Compilersicht: mehrere gleichzeitige Aufrufe erfordern mehrere Inkarnationen des Speicherbereichs der Prozedur (Verwendung von Kellertechnik) - Parameterübergabe Compilersicht: zusätzliche Anweisungen
21
Programmspeicher CODE
P-Maschine Datenspeicher STORE 0 SP maxstr Programmspeicher CODE PC codemax Befehlsausführung: Steuerung durch Steuerschleife do PC := PC + 1; Ausführung des Befehls in CODE[PC-1] od - Initialisierung PC := 0
22
1.2.2 Ausgewählte Sprachkonstrukte und ihre Übersetzung
Voraussetzungen: Die Kontextbedingungen sind erfüllt (durch semantische Analyse geprüft). Alle Konstrukte sind syntaktisch eindeutig zerlegbar (Durchführung durch syntaktische Analyse). Ausdrücke Übersetzungsfunktion: - code: Ausdruck x Umgebung P-Code (Umgebung: u: Variablen Adressen)
23
Unterschiedliche Ausdruckbehandlung auf linker und rechter Seite einer Zuweisung
codeR : Übersetzung in Befehle zur Berechnung eines Werts codeL : Übersetzung in Befehle zur Berechnung einer Adresse Wertzuweisung code〚x := e〛u = codeL〚x〛u ; codeR〚e〛u ; sto T T Typ; u Umgebung; x Variable; e Ausdruck
24
Adresse von x (u(x) = ); w Wert von e STORE nach w
Wirkung von sto: STORE vor w Abarbeitung SP-2 SP Adresse von x (u(x) = ); w Wert von e STORE nach w SP
25
codeR〚e1 + e2〛u = codeR〚e1〛u; codeR〚e2〛u; add T
T Typ; e1, e2 Ausdrücke Wirkung von add: STORE vor w1 w2 Abarbeitung SP STORE nach w Abarbeitung w = w1 + w2
26
codeR〚c〛u = ldc T c, c Konstante vom Typ T STORE vor Abarbeitung
SP STORE nach c
27
codeL〚x〛u = ldc a u(x) , x Variable STORE vor Abarbeitung
SP STORE nach u(x)
28
codeR〚x〛u = codeL〚x〛u; ind T = ldc a u(x); ind T , x Variable
STORE vor w Abarbeitung u(x) = SP STORE nach w Abarbeitung von ldc a u(x) SP STORE nach w w von ind T SP
29
Beispiel: Übersetzung von x := (x + (3 + y)) , x, y vom Typ i code〚 x := (x + (3 + y))〛u = codeL〚 x〛u; codeR〚(x + (3 + y))〛u; sto i = ldc a u(x); codeR〚 x〛u; codeR〚(3 + y)〛u; add i; sto i = ldc a u(x); ldc a u(x); ind i; codeR〚3〛u; codeR〚y〛u; add i; add i; sto i = ldc a u(x); ldc a u(x); ind i; ldc i 3; ldc a u(y); ind i; add i; add i; sto i
30
Abarbeitungsschritte:
u(x) = , u(y) = , w1 Wert von x, w2 Wert von y, w3 = 3 + w2, w4 = w1 + w3 STORE-Zustände w1 w2 k w1 w2 k w1 w2 k w1 w2 k w1 w1 w2 k w1 3 w1 w2 k w w1 w2 k w w2 w1 w2 k w1 w3 w1 w2 k w4 w4 w2 k
31
Bedingte Anweisungen code〚if e then st1 else st2 fi〛u = codeR〚e〛u; fjp l1; code〚st1〛u; ujp l2; l1: code〚st2〛u; l2:... Wirkung von fjp l1: k false k PC := l1 k true k Wirkung von ujp l2: PC := l2 Anweisungsfolgen code〚st1; st2〛u = code〚st1〛u; code〚st2〛u
32
code〚while e do st od〛u =
Wiederholungen code〚while e do st od〛u = l1: codeR〚e〛u; fjp l2; code〚st〛u; ujp l1; l2:... Beispiel: code〚while a > b do a := a - b od〛u = l1: codeR〚a > b〛u; fjp l2; code〚 a := a - b 〛u; ujp l1; l2:...= l1: ldc a u(a); ind i; ldc a u(b); ind i; grt i; fjp l2; ldc a u(a); ldc a u(a); ind i; ldc a u(b); ind i; sub i; sto i; ujp l1; l2:...
33
1.3 Logische Compilerstruktur Physische Compilerstruktur
Treiber Syntaktische Semantische Semantische Analyse Analyse Synthese Lexikalische Analyse
34
Physische Compilerstruktur (Fortsetzung)
Treiber Syntaktische Analyse Lexikalische Semantische Semantische Analyse Analyse Synthese
35
Logische Compilerstruktur (1)
Quellprogramm Analyse Lexikalischer Datentabellen Analysator Codierte Terminalfolge Syntaktischer Datenmodule Syntaxbaum Semantischer Dekorierter Semantische Synthese Zielprogramm
36
Logische Compilerstruktur (2)
Quellprogramm Lexikalische Analyse Symbol- Syntaktische Fehlerbehandlung tabellen- Analyse verwaltung Semantische Zwischencode- Code- Code- Erzeugung Optimierung Erzeugung Zielprogramm
37
2 Lexikalischer Analysator
Aufgabe: Transformation des Quellprogramms aus einer Zeichenfolge in eine codierte Folge von Terminalen (Tokenfolge, Grundsymbolfolge) mit Sammlung spezieller Informationen in Tabellen Teilaufgaben: Auffinden und Erkennen eines Lexems (≙ Terminal) Codierung der Lexeme Auslassung überflüssiger Zeichenfolgen Erstellung von Datentabellen
38
2.1 Auffinden und Erkennen von Lexemen
Fakt: Lexeme sind überwiegend durch reguläre Grammatikregeln beschreibbar. Es existieren endliche Automaten, die genau diese Lexeme akzeptieren. Beispiel: <ganze Zahl> ::= 0|1|...|9|0 <ganze Zahl>|...|9 <ganze Zahl> <Identifikator> ::= A|...|Z|A <Id1>|...|Z <Id1> <Id1> ::= A|...|Z|0|...|9| A <Id1>|...|9 <Id1> <Beschränker> ::= +|-|(|)|/|/ <schräg>|* <Stern>|: <gleich>|;|, <schräg> ::= / <Stern> ::= * <gleich> ::= =
39
Endliche Automaten zu den Regeln: 0,. ,9 S gZ 0,. ,9 A,. ,Z S Id A,
Endliche Automaten zu den Regeln: 0,...,9 S gZ 0,...,9 A,...,Z S Id A,...,9 + - ( ) ; , * * S S St / / : = S gl
40
Endlicher Automat für Akzeptanz aller Lexeme:
A,...,Z A,...,Z,0,...,9 0,...,9 + - ( ) ; , * * / : =
41
2.2 Kodierung der Lexeme 1 Identifikator 9 ** 2 ganze Zahl 10 (
Kodierung Lexem Kodierung Lexem 1 Identifikator 9 ** 2 ganze Zahl 10 ( 3 BEGIN ) 4 END // 5 REAL := 6 / ; 8 -
42
Semantische Aktionen ADD Aufsammeln von Zeichen eines Lexems in einer Puffervariablen A GC Lesen des nächsten Quellprogrammzeichens, Zwischenablage in der Variablen Char sowie Bestimmung der Art des Zeichens LOOKUP Bestimmung der Kodierung des in A abgelegten Lexems gemäß Tabelle der internen Kodierung (Kodierung 1 bei Nichtvorhandensein) OUT(C,A) Ausgabe eines Lexems (in A) zusammen mit seiner Kodierung (in C) GPC Überlesen aller bedeutungslosen Zeichen und Fortsetzung wie GC sowie Löschen von A
43
Endlicher Automat mit semantischen Aktionen:
A,...,Z LOOKUP(A,C);OUT(C,A) ADD;GC A,...,Z,0,...,9 ADD;GC 0,...,9 OUT(2,A) ADD;GC 0,...,9 GPC ADD;GC + - ( ) ; , ADD;GC LOOKUP(A,C);OUT(C,A) * * ADD;GC ADD;GC OUT(9,A) / ADD;GC / OUT(6,A) ADD;GC OUT(12,A) : = ADD;GC ADD;GC OUT(13,A)
44
2.5 Automatische Erzeugung von lexikalischen Analysatoren
Lexembeschreibung Lexikalischer (reguläre Ausdrücke, Analysator - semantische Rahmensystem Aktionen) Generator Steuerung
45
Lex-Spezifikation <Deklarationsteil> %% <regulärer Ausdruck> {<semantische Aktion in C>} ... <Nutzerunterprogramme>
46
Beispiel: # include ´´y.tab.h´´ extern int yyz, yyli;
extern symbol *lookup(), *install(); %% ´´\n´´ {yyli ++;} [ ] ; [0-9][0-9]* {symbol *s; if ((s=lookup(yytext))==0) s=install(yytext); ...; return (ZAHL);} if {return (IF);} ... true {keys *k; k=lookkey(yytext); yylval.yyk=k; return (TRUE);} [a-z][a-z 0-9]* {symbol *s; if ((s=lookup(yytext))==0) s=install(yytext); yylval.yysym=s; return (IDENTIFIKATOR);}
47
3 Syntaktische Analyse Beispiel: Aus Id ( Aus ) Aus Id [ Aus ]
Id f Id z
48
Syntaxbaum von f(a[z]) Aus Top-down Analyse 11 Id Aus Id Aus Id Bottom-up Analyse 16 f ( a [ z ] )
49
3.1 Kellerspeicher in der Syntaxanalyse Top-down Analyse - Grundalgorithmus
Voraussetzung: Verwendung eines Analysekellers Schritte des Algorithmus´: Startsymbol in den Keller Wiederholung folgender Schritte bis zum Erreichen eines leeren Kellers: - Nichtterminal an Kellerspitze: Expansion (Ersetzen des Nichtterminals durch rechte Seite einer geeigneten Syntaxregel) - Terminal an Kellerspitze: Vergleich mit aktuellem Element des analysierten Wortes; bei Gleichheit Streichen aus dem Keller, nächstes Element des Wortes wird aktuelles Element; bei Ungleichheit Backtracking
50
Beispiel:Top-down Analyse von f(a[z]) Aktuelles Element Keller (Spitze links) Operation f(a[z]) Aus Aus Id ( Aus ) f(a[z]) Id ( Aus ) Id f f(a[z]) f ( Aus ) 2x Vergleich a[z]) Aus ) Aus Id [ Aus ] a[z]) Id [ Aus ] ) Id a a[z]) a [ Aus ] ) 2x Vergleich z]) Aus ] ) Aus Id z z]) z] ) 3x Vergleich
51
Bottom-up Analyse - Grundalgorithmus
Schritte des Algorithmus´: Start mit leerem Keller Wiederholung folgender Schritte, bis das Startsymbol allein im Keller ist: - Reduktion: nur möglich, wenn an der Kellerspitze die rechte Seite einer Regel ist ( Ersetzen durch linke Seite) - Einlesen (Verschiebung): Einlesen des nächsten Elements des Wortes in den Keller
52
Beispiel: Bottom-up Analyse von f(a[z])
Restwort Keller (Spitze rechts) Operation f(a[z]) Lesen f (a[z]) f Reduktion f zu Id (a[z]) Id Lesen (a [z]) Id (a Reduktion a zu Id [z]) Id ( Id Lesen [z ]) Id ( Id [z Reduktionen z zu Id, Id zu Aus ]) Id ( Id [ Aus Lesen ] ) Id ( Id [ Aus ] Reduktion Id [ Aus ] zu Aus ) Id ( Aus Lesen ) Id ( Aus ) Reduktion Id ( Aus ) zu Aus Aus
53
3. 2 Deterministische Syntaxanalyse 3. 2
3.2 Deterministische Syntaxanalyse Top-down Verfahren - Methode des rekursiven Abstiegs Grundmethode: Idee: Syntaktische Regel A ...wird als Prozedur zur Erkennung von Zeichenketten aus L(A) betrachtet, wobei die rechte Seite der Regel die Struktur vorgibt: Terminal: erwartetes Terminal Nichtterminal: Aufruf der entsprechenden Prozedur Alternativen: Code-Alternativen in der Prozedur
54
Beispiel: Prozedur zur Regel T ( Aus )| [ Aus ] procedure T; begin case token of (: match( ( ); Aus; match( ) ); [: match( [ ); Aus; match( ] ); else error; end case; end T; Vor.: token enthält aktuelles Terminal der zu analysierenden Zeichenkette
55
Definition der Prozedur match: procedure match(expectok); begin if token = expectok then gettoken else error fi; end match; gettoken liest das nächste Zeichen aus der Zeichenkette und ordnet es token zu.
56
Konstruktion der Zerlegungsprozeduren
N X : procedure N; <parse X> <parse X> bedeutet Anweisungen zur Erkennung von X, wobei - X = einer Leeranweisung - X = t (Terminal, token) match(t) - X = M (Nichtterminal) M (Aufruf der Prozedur) - X = A B <parse A>; <parse B>
57
- X = A| B case token of e1: <parse A>; e2: <parse B>; else error; end case; e1 DS(N, A), e2 DS(N, B) - X = A* while token DS(N, A) do <parse A> od entspricht.
58
Definition der Entscheidungsmenge (director set) Vor. : A 1|
Definition der Entscheidungsmenge (director set) Vor.: A 1| ...| n DS(A, i) = {a T| a FIRST1(i) ∨ (i * ⋀ a FOLLOW1(A))} Beispiel: 1 A I T 11/12/13 T ( A )| [ A ]| 14/15/16 I a| f| z DS(T, 1) = { ( } DS(I, 1) = {a} DS(T, 2) = { [ } DS(I, 2) = {f} DS(T, 3) = { ], ), } DS(I, 3) = {z}
59
Top-down Analyse von f(a[z])
Keller () Zeichenkette Keller Zeichenkette A f(a[z]) [ A ] ) I T A ] ) z]) f T I T ] ) T (a[z]) z T ] ) ( A ) T ] ) ]) A ) a[z]) ] ) I T ) ) ) a T ) T ) [z])
60
LL(k)-Grammatik G = (N, T, P, S)
G ist eine kontextfreie Grammatik Für beliebige Paare von Linksableitungen S + A * x S + A * y mit FIRSTk(x) = FIRSTk(y) gilt = .
61
Starke LL(k)-Grammatik G = (N, T, P, S)
Für jedes Paar von Regeln aus P A x und A y (A x | y) gilt FIRSTk(x FOLLOWk(A)) FIRSTk(y FOLLOWk(A)) =
62
Tabellengesteuerte LL(1)-Analyse
Analysealgorithmus: Eingabe: Analysetabelle M, Zeichenkette w T* Ausgabe: Fehlermeldung oder Regelnummernfolge Startkonfiguration: (w, S#, ) Schritte: 1. (ax, A, r) ⊢ (ax, , r i) für M(A, a) = (, i) 2. (ax, a, r) ⊢ (x, , r), a T 3. (, #, r) erfolgreicher Abschluss 4. Fehler sonst
63
Analysetabelle für obige Grammatik und Analyse von f(a[z]) a f z ( [ ) ] A IT,1 IT,1 IT,1 T (A),11 [A],12 ,13 ,13 , 13 I a,14 f,15 z,16 (f(a[z]), A#, ) ⊢ (f(a[z]), IT#, (1)) ⊢ (f(a[z]), fT#, (1 15)) ⊢ ((a[z]), T#, (1 15)) ⊢ ((a[z]), (A)#, ( )) ⊢ (a[z]), A)#, ( )) ⊢ (a[z]), IT)#, ( )) ⊢ (a[z]), aT)#, ( )) ⊢ ([z]), T)#, ( )) ⊢
64
([z]), T)#, ( )) ⊢ ([z]),[A])#, ( )) ⊢ (z]), A])#, ( )) ⊢ (z]), IT])#, ( )) ⊢ (z]), zT])#, ( )) ⊢ (]), T])#, ( )) ⊢ (]), ])#, ( )) ⊢ (), )#, ( )) ⊢ (, #, ( ))
65
Deterministische Syntaxanalyse 3. 2
Deterministische Syntaxanalyse Bottom-up Verfahren - Einfache Präzedenz Einfache Präzedenz Relationen: R <∙ S: Es existiert eine Regel U ...R V ... und V + S R ≐ S: Es existiert eine Regel U ...R S... . R ∙> S: Es existiert eine Regel U ...V W... Und V + ...R sowie W * S
66
Präzedenzmatrix für Beispielgrammatik
Aus Id ( ) [ ] a f z Aus ≐ ≐ Id ≐ ∙> ≐ ∙> ( ≐ <∙ <∙ <∙ <∙ ) ∙> ∙> [ ≐ <∙ <∙ <∙ <∙ ] ∙> ∙> a ∙> ∙> ∙> ∙> f ∙> ∙> ∙> ∙> z ∙> ∙> ∙> ∙>
67
Analyseprozess unter Nutzung der Präzedenzmatrix Wiederholung folgender Schritte: 1. Einspeicherung der Zeichen der Zeichenkette in den Keller, bis an der Kellerspitze ein Zeichen E steht , das in der Relation ∙> mit dem nächsten einzulesenden Zeichen steht 2. Abstieg im Keller bis zum Erreichen des ersten Zeichens A mit y <∙ A, dabei befindet sich y im Keller direkt unter A 3. Reduktion der Zeichenkette A...E im Keller gemäß syntaktischen Regeln
68
Analyse von f(a[z]) Keller Restwort <∙ f ∙> ( a [ z ] )
<∙ Id ≐ ( <∙ a ∙> [ z ] ) <∙ Id ≐ ( <∙ Id ≐ [ <∙ z ∙> ] ) <∙ Id ≐ ( <∙ Id ≐ [ <∙Id ∙> ] ) <∙ Id ≐ ( <∙ Id ≐ [≐ Aus ≐ ] ∙> ) <∙ Id ≐ ( ≐ Aus ≐ ) ∙> Aus
69
LR(k)- Analyse Charakterisierung:
Entspricht Grundverfahren modifiziert durch Vorausschau auf k Elemente Darstellung durch eine Zustandsmenge zusammen mit Übergangsfunktion in Form einer Analysetabelle, bestehend aus Aktionstabelle (Einlesen und Reduktion) und Sprungtabelle (Fortsetzung nach Reduktion)
70
Beispiel: Konstruktion der Analysetabelle für
A I ( A )| I [ A ]| I I a| f| z Zustände und Übergänge des charakteristischen endlichen Automaten Zustand Q0: Zustand Q1: Zustand Q2: T . A ⊣ T A .⊣ A I .( A ) A .I ( A ) A I .[ A ] A .I [ A ] A I. A .I Zustand Q3: Zustand Q4: I .a I a. I f. I .f I .z Zustand Q5: I z.
71
Zustand Q6: Zustand Q7: Zustand Q8: A I ( .A ) A I [ .A ] A I ( A .) A .I ( A ) A .I ( A ) A .I [ A ] A .I [ A ] Zustand Q9: A .I A .I A I [ A .] I .a I .a I .f I .f Zustand Q10: I .z I .z A I ( A ). Zustand Q11: A I [ A ].
72
Q0 A I Q1 a f z Q2 Q3 Q4 Q5 [ ( I Q7 a f z A I a f z Q9 Q6 Q2 Q3 Q4 Q5 A ] Q8 ) Q11 Q10 Charakteristischer endlicher Automat
73
Analysetabelle ( [ a f z ] ) ⊣ A I Q0 Q3 Q4 Q5 Q1 Q2 Q1 T A⊣
Q2 Q6 Q A I ... Q I a ... Q I f ... Q I z ... Q6 Q3 Q4 Q Q8 Q2 Q7 Q3 Q4 Q Q9 Q2 Q Q10 Q Q11 Q A I ( A ) ... Q A I [ A ] ...
74
Syntaxanalyse unter Verwendung einer Analysetabelle (AT):
Verwendung zweier Keller: Elementekeller (EK) wie im Grundalgorithmus und Zustandskeller (ZK) Start der Analyse: Q0 im Zustandskeller Ende der Analyse: Altes Startsymbol im Elementekeller; Endezeichen als aktuelles Zeichen Schritte: 1. Einlesen: Aktuelles Zeichen der Eingabe in EK und neuer Zustand gemäß AT (bestimmt aus altem Zustand und Zeichen) in ZK 2. Reduktion:- Reduktion an EK-Spitze gemäß Regel aus AT (bestimmt durch alten Zustand und aktuelles Zeichen) - Entfernen von Zuständen aus ZK (Anzahl gleich Anzahl der Elemente auf r. S. der Regel) - Neuer Zustand gemäß AT (bestimmt durch Zustand an ZK-Spitze und Nichtterminal auf l. S. der Regel) in ZK
75
Beispiel: Analyse von f ( a [ z ] ) ⊣
Elementekeller Restwort Zustandskeller Aktion f(a[z])⊣ Q Einlesen f (a[z])⊣ Q0Q4 Reduktion I (a[z])⊣ Q0Q2 Einlesen I ( a[z])⊣ Q0Q2Q6 Einlesen I ( a [z])⊣ Q0Q2Q6Q3 Reduktion I ( I [z])⊣ Q0Q2Q6Q2 Einlesen I ( I [ z])⊣ Q0Q2Q6Q2Q7 Einlesen I ( I [ z ])⊣ Q0Q2Q6Q2Q7Q5 Reduktion I ( I [ I ])⊣ Q0Q2Q6Q2Q7Q2 Reduktion I ( I [ A ])⊣ Q0Q2Q6Q2Q7Q9 Einlesen I ( I [ A ] )⊣ Q0Q2Q6Q2Q7Q9Q11 Reduktion I ( A )⊣ Q0Q2Q6Q8 Einlesen I ( A ) ⊣ Q0Q2Q6Q8Q10 Reduktion A ⊣ Q0Q1
76
Konflikte im charakteristischen endlichen Automaten
Reduktion-Reduktion: zwei unterschiedliche Reduktionen im gleichen Zustand Beispiel: T S ⊣ S a A b A A b A c T . S ⊣ a S a .A b A S a A .b b S a A b. S .a A b A .A b A A .b A A b. A .c S c T S. ⊣ A c.
77
Reduktion-Einlesen: Aus einem Zustand mit einer Reduktion führt eine mit einem Terminal bewertete Kante. Beispiel: siehe Zustand Q2 im charakteristischen endlichen Automaten des Standardbeispiels Grammatikklassifizierung LR(0)-Grammatik: Der charakteristische endliche Automat ist konfliktfrei. SLR(1)-Grammatik: Konflikte lassen sich auf der Basis von einem Element Vorausschau unter Nutzung der FOLLOW-Mengen auflösen.
78
Zustand Q2 im Standardbeispiel
Beispiele: Zustand Q2 im Standardbeispiel A I .( A ) Einlesen (benötigt werden ( oder [ ) oder A I .[ A ] Reduktion von I zu A? A I. FOLLOW1(A) = { ), ], ⊣ }, (, [ ∉ FOLLOW1(A) - Ist das aktuelle Zeichen ( oder [, dann erfolgt Einlesen. - Ist das aktuelle Zeichen aus FOLLOW1(A), dann erfolgt Reduktion. - Sonst liegt ein syntaktischer Fehler vor. Obiger Reduktion-Reduktion-Konflikt läßt sich auflösen: FOLLOW1(S) = { ⊣ } FOLLOW1(A) = { b }
79
LALR(1)-Grammatik: analog zur SLR(1)-Grammatik, aber mit „Verfeinerung“ der FOLLOW-Mengen
Beispiel: d S T S .⊣ c A A c FOLLOW1(A) = { a, b} FOLLOW1 1 (A) = { b } A c A c. FOLLOW1 2 (A) = { a } a b a b S d c a. S d A b. S A a S c b.
80
LR(k)-Grammatik (-frei)
Für beliebige Paare von Ableitungsfolgen S * w1 z w2 w1 v w2 , z v P, w2 T* S * w1´ z´ w2´ w1´ v´ w2´ , z´ v´ P, w2´ T* mit w1 v = w1´ v´ und FIRSTk(w2) = FIRSTk(w2´) Folgt z = z´ und v = v´.
81
Zustände des charakteristischen endlichen Automaten für LR(k)-Grammatiken
Ergänzung einer „Situation“ A x. X z durch einen Kontext K, wobei folgende Eigenschaften erfüllt sein müssen: Anfangszustand enthält Situation S .w ⊣ Zustand q enthalte Situation A u .X, K und zu X existieren die Regeln X w1 ; ...; X wn , dann enthält q ebenfalls X .w1 , K´; ...; X wn , K´ mit K´= FIRSTk( K)
82
Enthält der Zustand q die Situation A u
Enthält der Zustand q die Situation A u. x , K , dann erfolgt ein Übergang in einen Zustand mit der Situation A u. x , K Konflikte im charakteristischen endlichen Automaten: Reduktion-Reduktion: Ein Zustand enthält die Situationen A u. , K1 und A v. , K2 mit A ≠ B oder u ≠ v, aber t K1 K2 Reduktion-Einlesen: Ein Zustand enthält die Situation A u. , K und besitzt einen Übergang mit dem Terminal t und t K .
83
Beispiel: LR(1)-Zustände für Standardbeispiele (Auswahl) Q0: T
Beispiel: LR(1)-Zustände für Standardbeispiele (Auswahl) Q0: T .A ⊣ Q0 Q2: A I.(A) , ⊣ A .I(A) , ⊣ A I.[A] , ⊣ A .I[A] , ⊣ A I. , ⊣ A .I , ⊣ I .a , {(, [, ⊣} I .f , {(, [, ⊣} I .z , {(, [, ⊣}
84
3.4 Syntaktische Fehler Aufgaben der Fehlerbehandlung:
Lokalisierung des Fehlers Klassifizierung des Fehlers Fehlernachricht: - Fehlerposition - Grad oder Art des Fehlers - Genauere Angaben zum Fehler Stabilisierung und Fortsetzung der Analyse
85
Fehlerposition: w T* und es existiert w´ T* , wobei w w´ L(G) (w lässt sich durch w´ zum Wort aus L(G) ergänzen) Für w x, x T, existiert keine Ergänzung v T* , so dass w x v L(G). x ist eine Fehlerposition Beispiel: In x * (3 – z / y ; ist das „;“ eine Fehlerposition, da x * (3 – z / y richtig ergänzt werden kann, aber x * (3 – z / y ; nicht.
86
Bemerkungen: Bei LL(1)- und LR(1)-Verfahren der syntaktischen Analyse wird ein Fehler immer an einer Fehlerposition erkannt. Der Fehler muss nicht durch das Zeichen an der Fehlerposition verursacht worden sein.
87
3.5 Automatische Erzeugung von Syntaxanalysatoren
Kontextfreie Grammatik Analysator Rahmen programm Generator Tabellen
88
yacc-Spezifikation <Deklarationen> %% <Syntaxregeln und Semantik> <Programmteil>
89
4 Semantische Analyse 4.1 Symboltabellen Einfache Struktur
Hashtabelle mit Verkettungstechnik Beispiel: 1 DE A1B 0 3 CAESAR 4 FAUL F 0 6 D1 0 C5 0 frei
90
Symboltabellen mit abgetrennter Schlüsselliste
Hashtabelle mit Verkettungstechnik und abgetrennter Schlüsselliste Beispiel: 1 3 4 frei 2 D E 3 A 1 B 6 C A E S A R 4 F A U L 1 F 2 D C 5
91
Beispiel: Programm mit Blockstruktur
BEGIN REAL a, b, c, d; ... BEGIN REAL c, f; L1:... END; BEGIN REAL g, d; L2: BEGIN REAL a; L3:... END
92
Symboltabelle mit Blockstruktur 1
Beispiel: Symboltabelle für obiges Programm L1 Blocknummer f c Übergeordneter Block a L3 Anzahl Eintragungen L2 d Adresse g c b a
93
Symboltabelle mit Blockstruktur 2
Form der Listenelemente: Deklarationen Block Zeiger auf Verkettung Verkettung nummer Information im Block Identifikatoren Blockstruktur Block Anfang Übergeordneter nummer Blockkette Block
94
Beispiel: Symboltabelle zum obigen Programm
c / / d / 5 f / g / / 8 L / L / L /
95
Blockstrukturtabelle 1 1 4 / 2 2 9 1 3 3 11 1 4 4 1 3
96
4.2 Realisierung der semantischen Analyse
Beispiel: Attributierte Grammatik für Deklarationsfolgen Kontextfreie Basisgrammatik <decl list> ::= VAR <id decl> ; <dec list> <dec list>0 ::= <id decl> ; <dec list>1 <dec list> ::= <id decl> ::= <type> <id> <type> ::= BOOL <type> ::= INT Kontextbedingung: Kein Identifikator darf mehrfach deklariert werden.
97
Zuordnung der Attribute Attribut Art Bedeutung Zuordnung Sv Symboltabelle <dec list> vorläufig Sn Symboltabelle neu <dec list>, <decl list> IT (Identifikator, Typ) <id decl> T Typ <type> I Identifikator <id> error true, false <decl list>, <dec list>
98
Semantische Regeln 1 <decl list>.Sn := <dec list>.Sn
<decl list>.error := <dec list>.error <dec list>.Sv := INIT(<id decl>.IT) 2 <dec list>0.Sn := <dec list>1.Sn <dec list>0.error := <dec list>1.error IN(<dec list>0.Sv, <id decl>.IT) <dec list>1.Sv := ENTRY(<dec list>0.Sv, <id decl>.IT), wenn ¬ IN(<dec list>0.Sv, <id decl>.IT) 3 <dec list>.Sn := <dec list>.Sv <dec list>.error := false 4 <id decl>.IT := IDDECL(<id>.I, <type>.T) 5 <type>.T := ´bool´ <type>.T := ínt´
99
Dekorierter Syntaxbaum von VAR INT x; BOOL y;
<decl list> {(´x´,´int´),(´y´,´bool´)}, false VAR <id decl> ; <dec list> (´x´,´int´) {(´x´,´int´)}, {(´x´,´int´),(´y´,´bool´)}, false <type> <id> <id decl> ; ´int´ ´x´ (´y´,´bool´) <dec list> {(´x´,´int´),(´y´,´bool)}, INT x <type> <id> {(´x´,´int´),(´y´,´bool´)}, ´bool´ ´y´ false BOOL y
100
Schachtelung von Programmeinheiten
Beispiel: Programm PROGRAM H; PROC B; PROC D; ; call C; END B; END D; call B; PROC A; END A; PROC C; ; call A;...; call D;... ...; call D; END H; END C;
101
Statische Schachtelung mit Schachtelungstiefe
D/1 A/1 C/2 B/2 Dynamische Schachtelung H A D B C D
102
Datenbereich (Prozedurschachtel, Kellerrahmen) einer Prozedur (eines Blocks) zur Laufzeit
Allgemeiner Aufbau Funktions Statischer Dynamischer alter EP Rücksprung wert Vorgänger Vorgänger Wert adresse MP Parameter Lokale Felder Zwischen (statisch) Variablen (semidyn.) ergebnisse SP EP
103
Variablenadressierung: (Schachtelungstiefe, Relativadresse)
Beispiel: PROGRAM H; Adressierung: VAR x1, y; In H: x (0, 5) PROC p; y (0, 6) VAR i, x1, k; In p: i (1, 5) ...x x (1, 6) ...k k (1, 7) ...y... END p; call p; ...x1... END H;
104
Aktionen bei Eintritt in eine Prozedur q (p ruft q auf)
Setzen des statischen Vorgängers von q Setzen des dynamischen Vorgängers von q (Anfangsadresse des Datenbereichs von p – alter MP-Wert) Retten des alten EP-Wertes Berechnung der aktuellen Parameter Setzen des MP-Registers auf Anfangsadresse des Datenbereiches von q (SP + 1)
105
Abspeicherung der Rückkehradresse
Ausführung des Sprungs auf ersten Befehl des übersetzten q-Programms Setzen des SP-Registers Berechnung des EP-Wertes und Setzen des EP-Registers sowie Überprüfung auf mögliche Kollision zwischen Keller und Halde
106
Aktionen bei Verlassen der Prozedur q (Rückkehr nach p)
Freigabe des Datenbereichs bis auf eventuellen Funktionswert Setzen der MP-, EP- und SP-Register für die Prozedur p Rückkehr nach p
107
Beispiel: rekursiver Funktionsaufruf
PROGRAM Fak; VAR r : integer; FUNCTION F(n: integer): integer; IF n = 1 THEN F := 1 ELSE F := n * F(n – 1); END F; r := F(3); END Fak; Adressierung r (0, 5) n (1, 5) F (1, 0)
108
Übersetzung von Fak <Befehle für Aufbau des DB>; lda i 0 6; <Übersetzung des Aufrufs F(3)>; M1: sto i; <Befehle für Abbau des DB> Übersetzung von F(n) <Befehle für Aufbau des DB>; lod i 0 5; ldc i 1; equ i; fjp l1; lda i 0 0; ldc i 1; sto i; ujp l2; l1: lda i 0 0;lod i 0 5; <Übersetzung des Aufrufs F(n – 1)>; M2: mul i; sto i; l2: <Befehle für Abbau des DB und Rückkehr>
109
Abspeicherung von Datenstrukturen Mehrdimensionale Felder
A: ARRAY [u1.. o1, ..., un.. on] OF <type> Speicherabbildungsfunktion Adresse(A[i1, ..., in]) = Adresse(A[u1, ..., un]) + (i1 – u1) * d2 * ...* dn + (i2 – u2) * d3 * ...* dn + ... + (in – un) = k + v (di = oi – ui + 1)
110
Semidynamische Felder
Beispiel: semidynamische Felder in ALGOL 68 begin ... n := ...; ...; m := ...; ... begin [n] int A; [m] int B; A[i] := B[j+3] * k; end
111
Schablone (Felddeskriptor) eines semidynamischen Feldes
A: ARRAY [u1.. o1, ..., un.. on] OF <type> u1 o1 d1 ... un on dn n k´ adr adr = Adresse(A[u1, ..., un]) k´= u1 * d2 * dn + u2 * d3 * dn un
112
Datenbereich für inneren Block
Schablone für A Schablone für B Voraussetzung: Zur Laufzeit gilt n = 4 und m = 5 .
113
Erzeugte Befehlsfolgen (im Beispiel):
Aufbau des DB einschließlich der teilweise gefüllten Schablonen Berechnung von n und der fehlenden Elemente der Schablone für A Neuberechnung der ersten freien Adresse des freien dynamischen Speicherteils Berechnung von m und der fehlenden Elemente der Schablone für B Adressberechnung für A[i] aus der Schablone für A Adressberechnung für B[j+3] aus der Schablone für B
114
Datenmüllbeseitigung (garbage collection)
Arbeitsschritte: Zeigerverfolgung und Markierung besetzter Speicherbereiche Speicherkarte Herstellung eines Adressbuchs (alte Adressen, neue Adressen) Zeigertransformation (auf neue Adressen) Komprimierung des Speichers (Auslassung von Müllbereichen)
115
Parameterübergaben Referenzaufruf (call by reference):
PROC del(VAR t: Elem;...); Befehlsfolgen: BEGIN ...t := ...END; - Berechnung Abspeicherung von auf del(T,...); Platz von t T t LD LD DB aufrufende Prozedur DB von del
116
Werteaufruf (call by value):
PROC del1 (k: Key;...); Befehlsfolgen: BEGIN...z := k;...END; - Berechnung von w aus a del1(a,...); Abspeicherung von k w auf Platz von k LD w w Wert von a DB von del1
117
Werte-Resultatsaufruf (call by value-result):
Kombination von call by reference und call by value mit Änderung des aktuellen Parameters erst bei Rückkehr (zusätzlicher Umspeicherungsbefehl) T t LD w LD w Aufruf LD w´ LD w´ Rückkehr DB aufrufende Prozedur DB aufgerufene Prozedur
118
Namensaufruf (call by name):
Beispiele: ALGOL 60 procedure p(x); integer x; begin ... i := 2; x := 9; ... end; array a[1 : 9]; Realisierung: integer i; begin ... i := 2; a[i] := 9; i := 1; p(a[i]); end
119
procedure R(X, I); begin I := 2; X := 5; I := 3; X := 1 end; ... R(B[J * 2], J); Realisierung: begin J := 2; B[J * 2] := 5; J := 3; B[J * 2] := 1 end
120
Konkreter Syntaxbaum – abstrakter Syntaxbaum Beispiel: Ausdruck 5 * a
Konkreter Syntaxbaum Abstrakte Syntaxbäume <int expr> * <term> num(5) id(a) <term> <int op> <elem> <elem> * <var> * num(5) id(a) <num> a 5
121
Quadrupel (Dreiadresscode)
Allgemeine Form: [<Operator>, <Operand1>, <Operand2>, <Resultat>] mit Operand, Resultat: - Bezeichner (deklarierte oder temporäre Variable) - Zahl (Konstante, Sprungziel) - leer (ohne Bedeutung)
122
Unbedingter Sprung: [ujp, <Marke>]
Ausdrücke: [<Operator>, <Variable/Konstante>, <Variable/Konstante>, <temporäre Variable>] Beispiel: [add-int, t1, t2, h] Zuweisung: [sto-T, <Konstante/Variable>, , <Variable>] , T Typ Beispiel: [sto-int, x, , y] Unbedingter Sprung: [ujp, <Marke>] Bedingter Sprung: [fjp, <Variable>, <Marke>] Ausführung des Sprungs zur Anweisung mit der Marke, wenn der Wert der Variablen false ist
123
If-Anweisung IF e THEN st1 ELSE st2 FI:
Quad(e) Quadrupel zur Berechnung von e; Wert von e wird h1 zugewiesen [fjp, h1, l1] Quad(st1) Quadrupelfolge für st1 [ujp, l2] l1: Quad(st2) Quadrupelfolge für st2 l2: ... Andere Darstellung von Marken: [label, <Marke>]
124
Beispiel: IF a < b THEN a := a + 1 ELSE b := b + 1 FI [les-int, a, b, h1] [fjp, h1, l1] [add-int, a, 1, h1] [sto-int, h1, a] [ujp, l2] l1: [add-int, b, 1, h1] [sto-int, h1, b] l2: ...
125
Tripel (Binärbaum) Allgemeine Form:
(<Operator>, <Operand1>, <Operand2>) Repräsentation des Ergebnisses durch das Tripel selbst Graphische Darstellung: Operator Operand Operand2
126
Beispiel: IF a < b THEN a := a + 1 ELSE b := b + 1 FI (1) (les-int, a, b) (2) (fjp, (1), l1) (3) (add-int, a, 1) (4) (sto-int, a, (3)) (5) (ujp, l2) l1: (6) (add-int, b, 1) (7) (sto-int, b, (6)) l2: (8) ...
127
Erzeugung von Zwischensprachrepräsentationen
Methoden: Aufruf semantischer Routinen in Verbindung mit syntaktischer Analyse Verwendung attributierter Grammatiken Verwendung attributierter Translationsgrammatiken Baumtransformation
128
Speicherbedarf: Die Befehle ldc i, ldc a, ind i, add i,
Beispiel: Voraussetzungen: Bezeichnungen: P Feld für P-Code mit Zeiger p auf nächste Eintragstelle, S Analysekeller mit Spitze i Speicherbedarf: Die Befehle ldc i, ldc a, ind i, add i, mul i, neg i benötigen (kodiert) nur je 1 Speicherplatz. Bezeichner und Konstanten brauchen 2 Speicherplätze (Kenncode, Adresse in entsprechender Tabelle). Regeln: <Z> ::= <E> <E> ::= <T>
129
<E> ::= <E> + <T>
P[p] := ´ add i´; p := p + 1; P[p] := ´;´; p := p + 1; <E> ::= - <T> P[p] := ´ neg i´; p := p + 1; P[p] := ´;´; p := p + 1; <T> ::= <F> <T> ::= <T> * <F> P[p] := ´ mul i´; p := p + 1; P[p] := ´;´; p := p + 1;
130
<F> ::= <Bez>
P[p] := ´ ldc a´; p := p + 1; P[p] := S[i]; p := p + 2; P[p] := ´;´; p := p + 1; P[p] := ´ ind i´; p := p + 1; P[p] := ´;´; p := p + 1; <F> ::= <Kon> P[p] := ´ ldc i´; p := p + 1; P[p] := S[i]; p := p + 2; P[p] := ´;´; p := p + 1; 9 <F> ::= (<E>)
131
Beispiel: Syntaxanalyse und Erzeugung von P-Code Ausdruck: a * (b + 5)
Tokenfolge (symbolisch): Beza * ( Bezb + Kon5) Analysekeller S Regel P[p] Beza 7 ldc a a; ind i; <F> 5 <T> * (Bezb 7 ldc a b; ind i; <T> * (<F> 5, 2 <T> * (<E> + Kon5 8 ldc i 5; <T> * (<E> + <F> 5 <T> * (<E> + <T> 3 add i; <T> * (<E>) 9 <T> * <F> 6 mul i <T> 2, 1 <Z>
132
Beispiel: vorheriges Beispiel unter Verwendung einer
attributierten Grammatik Attribute: P synthetisiert P-Code I synthetisiert Bezeichner K synthetisiert Konstante Syntaktische Regeln: s.o. Semantische Regeln: P(<Z>) := P(<E>) P(<E>) := P(<T>) P(<E>0) := CONCAT(P(<E>1), P(<T>), ´add i;´)
133
P(<E>) := CONCAT(P(<T>), ´neg i;´)
5 P(<T>) := P(<F>) 6 P(<T>0) := CONCAT(P(<T>1), P(<F>), ´mul i;´) 7 P(<F>) := CONCAT(´ldc a ´, I(<Bez>), ´; ind i;´) 8 P(<F>) := CONCAT(´ldc i ´, K(<Kon>), ´;´) 9 P(<F>) := P(<E>)
134
Beispiel: Z ABCDE E T ABCDE T * F BCD F A ( E BCD ) Bez a E + T
A ldc a a; ind i; B ldc a b; ind i; T F C C ldc i 5; D add i; F B Kon 5 E mul i; Bez b
135
Beispiel: Attributierte Translationsgrammatik für arithmetische
Beispiel: Attributierte Translationsgrammatik für arithmetische Ausdrücke <Z>x <E>p x := p <E>x <T>p x := p <E>x <E>q + <T>r ADDy,z,p <x,p> := NEWT; y := q; z := r <E>x - <T>q NEGy,p <x,p> := NEWT; y := q <T>x <F>p x := p <T>x <T>q * <F>r MULTy,z,p <x,p> := NEWT; y := q; z := r
136
<F>x <Bez>p x := p
<F>x <Kon>p x := p <F>x (<E>p) x := p Attributwerte: Speicheradressen <a, b> :=NEWT: a und b wird die Adresse eines freien Speicherplatzes im Speicher T zugewiesen Translation (ohne Attribute): Bez * (Bez + Kon) ADD MULT
137
Codeerzeugung im engeren Sinne
Arten von Zielcode: Maschinenprogramm mit absoluten Adressen (Load-and-go-Compiler) Maschinenprogramm mit relativen Adressen (relocatable Code) Bearbeitung vor Abarbeitung: - Zusammenstellung unabhängig voneinander übersetzter Programmkomponenten mit externen Referenzen aufeinander zu einem Lademodul (load module) - Auflösung der externen Referenzen durch Binder (linker) - Überführung in absolut adressiertes, ausführbares Programm durch Ladeprogramm (loader)
138
Programm in Assemblersprache Notwendigkeit eines Assemblerlaufes
Programm in Programmiersprache einer abstrakten Maschine zweistufige Übersetzung: Quellsprache Sprache der abstrakten Maschine Zielsprache Beispiel: Übersetzung von Pascal in P-Code (Code der P-Maschine) und Übersetzung des P-Codes in Zielsprache
139
Übersetzung Zwischensprache – Zielsprache Grundlegende Techniken
Voraussetzungen: Befehle der Zielmaschine LOAD R O <O> R STORE R O <R> O STORE O1 O2 <O1> O2 ADD-I R O <R> + <O> R SUB-I R O <R> - <O> R <a> Inhalt von Speicherplatz a a Abspeicherung auf Speicherplatz a
140
R Registeradresse (im Falle 1 Registers ACC) O kann sein: Registeradresse <Registeradresse> Hauptspeicheradresse <Hauptspeicheradresse> = Konstante (Direktoperand) STACK Adresse der Spitze des Kellerspeichers
141
Beispiel: Tabellengesteuerte Codeerzeugung
Voraussetzungen: Übersetzung aus Tripeldarstellung in Befehle obiger Zielmaschine gen(a) erzeugt Befehl a code(t) vertritt Befehlsfolge, die durch Übersetzung des Teilbaums t entstand LB linker Teilbaum RB rechter Teilbaum Eine Variable in den erzeugten Befehlen vertritt den ihr im Hauptspeicher zugeordneten Speicherplatz.
142
Tabelle für SUB-I (bzw. DIV-I)
Variable/Konstante Unterbaum Var. gen( LOAD ACC LB ) code( RB ) / gen( SUB-I ACC RB ) gen( STORE ACC STACK ) Kon. gen( LOAD ACC LB ) gen( SUB-I ACC STACK ) Un code( LB ) code( RB ) ter gen( SUB-I ACC RB ) gen( STORE ACC STACK ) ba code( LB ) um gen( SUB-I ACC STACK )
143
Tabelle für ADD-I (bzw. MUL-I)
Variable/Konstante Unterbaum Var. gen( LOAD ACC LB ) code( RB ) / gen( ADD-I ACC RB ) gen( ADD-I ACC LB ) Kon. Un code( LB ) code( LB ) ter gen( ADD-I ACC RB ) gen( STORE ACC STACK ) ba code( RB ) um gen( ADD-I ACC STACK )
144
Tabelle für Zuweisung Variable/Konstante Unterbaum
Var. gen( STORE RB LB ) code( RB ) gen( STORE ACC LB ) Un code( LB ) code( RB ) ter gen( STORE RB <ACC> ) gen( STORE ACC STACK ) ba code( LB ) um gen( STORE STACK <ACC>)
145
Beispiel: Zuweisung h := a * ((c + 5 * a) – (c * d)) Tripel (mul-int, 5, a) (add-int, c, (1)) (mul-int, c, d) (sub-int, (2), (3)) (mul-int, a, (4)) (sto-int, (5), h)
146
Tripel als Binärbaum := (6) h * (5) a - (4) + (2) * (3) c * (1) c d 5 a
147
Erzeugte Befehlsfolgen
LOAD ACC =5 code((1)) code((4)) code((5)) MUL-I ACC a MUL-I ACC a code((1)) code((2)) code((5)) code((6)) ADD-I ACC c STORE ACC h LOAD ACC c code((3)) MUL-I ACC d code((3)) code((4)) STORE ACC STACK code((2)) SUB-I ACC STACK
148
Generatoren für Codegeneratoren Verwendung von Baumgrammatiken
Vorgehensweise: Beschreibung der Codeerzeugung: - Regeln der Baumgrammatik beschreiben die Zwischensprache: <Baumknoten> ::= <Baummuster> - Zuordnung von Schablonenfolgen für Erzeugung der Zielsprachbefehle zu Regeln
149
Erzeugung des Codegenerators aus vorheriger Beschreibung
Codeerzeugung durch Codegenerator: - Überdeckung des Baums zum Zwischensprachprogramm durch Baummuster (in Form von Termen); Auflösung von Mehrdeutigkeiten durch Kostenfunktion - Erzeugung von Zielcode aus Schablonenfolgen gemäß Überdeckung
150
Beispiel: Baumgrammatikregeln mit Schablonen
1 r.2 ::= word( d.1 ) { LOAD R.2 D.1 } 2 r.1 ::= iadd( r.1, r.2 ) { ADD-I R.1 R.2 } 3 ::= store( word( d.1 ), r.2 ) { STORE R.2 D.1 } r.i Registeradresse; d.i Hauptspeicheradresse einer deklarierten Variable word, iadd, store Operatoren der Zwischensprache (Präfixform)
151
Quellsprache Zwischensprache A := A + B store(word(d. a), iadd(word(d
Quellsprache Zwischensprache A := A + B store(word(d.a), iadd(word(d.a), word(d.b))) Überdeckungsbaum store word iadd d.a word word d.a d.b
152
Objektorientierte Compilerstruktur (nach D. A. Watt, D. F
Objektorientierte Compilerstruktur (nach D. A. Watt, D. F. Brown: Programming Language Processors in Java) Compilertreiber Treiber Parser Checker Encoder Scanner
153
Compilertreiber public class Compiler {
public static void compileProgram(...) { //Generierung des Parsers Parser parser = new Parser(...); //Generierung des semantischen Analysators Checker checker = new Checker(...); //Generierung des Zielcodegenerators Encoder generator = new Encoder(...);
154
//Aufruf des Parsers mit Erzeugung des abstrakten Syntaxbaums //AST Program theAST = parser.parse(); //Aufruf des semantischen Analysators mit Dekoration von AST checker.check(theAST); //Aufruf des Codegenerators mit Erzeugung des Zielprogramms generator.encode(theAST); } public static void main(String[] args) {...compileProgram(...); ...}
155
Pakete: AbstractSyntaxTrees: - Klassen zur Definition der AST-Datenstrukturen Je Klasse: Konstruktor zum AST-Aufbau und visitor-Methode zur Verknüpfung mit semantischer Analyse (contextual analyzer) und Codeerzeugung (code generator) - Manipulation der AST-Felder SyntacticAnalyzer: - Parserklassen zur syntaktischen Analyse (Methode des rekursiven Abstiegs) und zur AST-Konstruktion - Hilfsklassen
156
ContextualAnalyzer: Checker-Klasse zur Durchführung der semantischen Analyse CodeGenerator: Encoder-Klasse führt ausgehend vom AST Speicherzuteilung durch und erzeugt Zielcode
157
Parser public class Parser{
//Aktuelles Symbol im analysierten Programm private Token currentToken; //Vergleich aktuelles Symbol – erwartetes Symbol private void accept(byte expectedKind){ if (currentToken.kind == expectedKind) currentToken = scanner.scan(); else Fehlermeldung;}
158
//Nächstes Symbol wird zum aktuellen Symbol
private void acceptIt(){ currentToken = scanner.scan();} //Hilfsmethoden //Parsingmethoden private Program parseProgram(){ //Instanzvariable für AST //Syntaxanalyse für Programme //AST-Erzeugung für Programme return //AST für Programm } ...
159
public Program parse(){ currentToken = scanner
public Program parse(){ currentToken = scanner.scan(); Program progAST = parseProgram(); if (currentToken.kind != Token.EOT) Fehlermeldung return progAST} ... }
160
AST-Konstruktor der Klasse AssignCommand
Abstrakte Klasse für AST: public abstract class AST{...} AST-Knoten als Unterklassen der AST-Klasse Abstrakte Klasse für Expression: public abstract class Expression extends AST{...} Konkrete Klassen mit Konstruktor für AST Beispiel: AST-Konstruktor der Klasse AssignCommand public AssignCommand(Vname V, Expression E){ this.V = V; this.E = E;}
161
Lexikalische Analyse public class Scanner{ ...
private boolean isDigit(char c){...} //true, falls c eine Ziffer ist public Token scan(){ return new Token(currentKind, currentSpelling.toString());} } public class Token{...} //Lexembeschreibungen in Aufbau und Codierung
162
Semantische Analyse Anwendung des visitor pattern: 1
Semantische Analyse Anwendung des visitor pattern: 1. Einrichtung einer Schnittstelle Visitor 2. Für jeden konkreten AST einer Unterklasse A Verwendung einer Visitor-Methode visitA 3. Anreicherung der abstrakten AST-Klasse mit der visit-Methode zum Besuch von AST-Knoten 4. Implementation von visit in jeder Unterklasse 5. Implementation der eigentlichen semantischen Analyseprozeduren im Checker (semantischer Analysator)
163
Schnittstelle Visitor
public interface Visitor{ //visitA-Methoden public Object visitProgram(Program prog, Object arg); ... public Object visitAssignCommand(AssignCommand com, Object arg);}
164
Implementierung von Visitor in Checker
public final class Checker implements Visitor{ //Symboltabelle private IdentificationTable idTable; //Visitor-Methoden public Object visitAssignCommand(Assigncommand com, Object arg){ Type vType = (Type) com.V.visit(this, null); Type eType = (Type) com.E.visit(this, null); if(! eType.equals(vType)) Fehlermeldung return null; }
165
... //Start der semantischen Analyse public void check(Program prog){ //Initialisierung der Symboltabelle idTable = new IdentificationTable(); prog.visit(this, null); }
166
Erweiterung der AST-Klasse
public abstract class AST{ ... public abstract Object visit(Visitor v, Object arg); } Implementierung von visit in den AST-Unterklassen public class A extends ...{ public Object visit(Visitor v, Object arg){ return v.visitA(this, arg);}
167
Codeerzeugung Nutzung des visitor patterns mit Implementierung der Visitor-Methoden in der Klasse Encoder: public final class Encoder implements Visitor{ ... //Visitor-Methoden public Object visitAssignCommand(AssignCommand com, Object arg){ com.E.visit(this, arg); encodeAssign(com.V); return null;} public void encode(Program prog){ prog.visit(this, null);} }
Ähnliche Präsentationen
© 2024 SlidePlayer.org Inc.
All rights reserved.