Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter.

Ähnliche Präsentationen


Präsentation zum Thema: "Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter."—  Präsentation transkript:

1 Compiler und Interpreter Klaus Becker 2010

2 2 Compiler und Interpreter

3 3 Teil 1 Syntax und Semantik im Überblick

4 4 Karol / Myka Karol MyKa(rol)

5 5 Aufgabe Versuche anhand weiterer Tests die Regeln der Sprache MyKa herauszufinden: (a) Wie können Programme der Sprache aufgebaut werden? links while nichtVorWand: ziegelHinlegen schritt #while if nichtVorWand: if nichtVorZiegel: schritt else: ziegelHinlegen #if else: links #if markeSetzen schritt while nichtAufMarke: while nichtVorWand: schritt #while links #while

6 6 Aufgabe Versuche anhand weiterer Tests die Regeln der Sprache MyKa herauszufinden: (b) Welche Bedeutung haben die Sprachkonstrukte? links while nichtVorWand: ziegelHinlegen schritt #while if nichtVorWand: if nichtVorZiegel: schritt else: ziegelHinlegen #if else: links #if markeSetzen schritt while nichtAufMarke: while nichtVorWand: schritt #while links #while

7 7 Exkurs - MyKa links while nichtVorWand: ziegelHinlegen schritt #while if nichtVorWand: if nichtVorZiegel: schritt else: ziegelHinlegen #if else: links #if markeSetzen schritt while nichtAufMarke: while nichtVorWand: schritt #while links #while Anweisung schritt links rechts ziegelHinlehen ziegelAufheben markeSetzen markeLoeschen pass Bedeutung einen Schritt vorwärts bewegen - sofern möglich um 90° nach links drehen um 90° nach rechts drehen einen Ziegen in das vor dem Roboter liegende Feld hinlegen - sofern möglich einen Ziegen von dem vor dem Roboter liegenden Feld aufheben - sofern möglich eine Marke auf das Feld setzen, auf dem sich der Roboter befindet eine Marke löschen, die sich auf dem Feld des Roboters befindet - sofern möglich mache nichts

8 8 Exkurs - MyKa links while nichtVorWand: ziegelHinlegen schritt #while if nichtVorWand: if nichtVorZiegel: schritt else: ziegelHinlegen #if else: links #if markeSetzen schritt while nichtAufMarke: while nichtVorWand: schritt #while links #while Bedingung vorWand nichtVorWand vorZiegel nichtVorZiegel aufMarke nichtAufMarke Bedeutung Befindet sich der Roboter vor einer Wand? Befindet sich der Roboter nicht vor einer Wand? Befindet sich der Roboter vor einem Ziegel? Befindet sich der Roboter nicht vor einem Ziegel? Befindet sich der Roboter auf einer Marke? Befindet sich der Roboter nicht auf einer Marke?

9 9 Exkurs - MyKa links while nichtVorWand: ziegelHinlegen schritt #while if nichtVorWand: if nichtVorZiegel: schritt else: ziegelHinlegen #if else: links #if markeSetzen schritt while nichtAufMarke: while nichtVorWand: schritt #while links #while Kontrollstruktur Sequenz: "Anweisung" "Anweisung"... "Anweisung" Fallunterscheidung: if "Bedingung": "Anweisungssequenz" else: "Anweisungssequenz" #if Wiederholung: while "Bedingung": "Anweisungssequenz" #while Bedeutung Sequenz: Führe die Anweisungen der Reihe nach aus. Fallunterscheidung: Wenn die Bedingung erfüllt ist, dann führe die erste Anweisungssequenz aus, ansonsten die zweite Anweisungssequenz. Wiederholung: Solange die Bedingung erfüllt ist, führe die Anweisungssequenz aus.

10 10 Exkurs - MyKa links while nichtVorWand: ziegelHinlegen schritt #while if nichtVorWand: if nichtVorZiegel: schritt else: ziegelHinlegen #if else: links #if markeSetzen schritt while nichtAufMarke: while nichtVorWand: schritt #while links #while Syntax und Semantik - informell oder formal? Eine informelle Beschreibung von Syntax und Semantik liefert einen ersten Überblick über die Struktur und Bedeutung der Sprachelemente der Programmiersprache. Bei einer informellen Beschreibung bleiben meist aber noch Fragen offen. Im Fall der Programmiersprache MyKa ist beispielsweise noch nicht geklärt, ob es auch leere Anweisungssequenzen geben kann (z.B. in der Anweisung while nichtVorWand: #while). Ungeklärt ist auch noch, wie sich ein mehrfaches Setzen einer Marke auswirkt. Alle diese Fragen werden geklärt, wenn Syntax und Semantik präzise beschrieben werden. Für die Programmiersprache MyKa wird das in den folgenden Abschnitten nachgeholt.

11 11 Fachkonzept - Syntax Die Syntax einer Sprache beschreibt, welche Kombinationen von Zeichen fehlerfreie Programme der Sprache bilden. myka_syn = {Programm1, Programm2,...} Programmx links while nichtVorWand: ziegelHinlegen schritt #while if nichtVorWand: if nichtVorZiegel: schritt else: ziegelHinlegen #if else: links #if markeSetzen schritt while nichtAufMarke: while nichtVorWand: schritt #while links #while Eine Präzisierung dieser Menge kann z.B. mit Hilfe einer Grammatik vorgenommen werden.

12 12 Fachkonzept - Semantik Die Semantik einer Sprache beschreibt, welche Bedeutung den Einheiten der Sprache zugeordnet wird. myka_sem: (programm, zustand_vorher) --> zustand_nachher Eine Präzisierung dieser Zuordnung kann z.B. mit Hilfe eines Interpreters vorgenommen werden.

13 13 Teil 2 Scanner und Parser im Überblick

14 14 Myka syntaktisch korrektes Programm Programm mit Syntaxfehler Struktur- darstellung d. Programms

15 15 Aufgabe Untersuche verschiedene Programme (siehe inf-schule) auf syntaktische Korrektheit. Schaue dir die Quelltexte zunächst genau an und stelle Vermutungen über Syntaxfehler auf. Gib die vorgegebenen MyKa- Programm-Quelltexte in das linke obere Fenster ein. Erzeuge mit der Schaltfläche [scannen / parsen] ein MyKaList-Programm - das ist eine mit Hilfe von Listen erstellte strukturierte Darstellung des MyKa- Programms. In welchen Fällen funktioniert das, in welchen Fällen nicht? Die Programme 3, 4 und 5 sind aus unterschiedlichen Gründen syntaktisch nicht korrekt. Gegen welche Regeln wird hier wohl verstoßen?

16 16 Aufgabe Versuche anhand weiterer Tests zu erschließen, wie ein syntaktisch korrektes MyKa-Programm mit Hilfe von Listen strukturiert als MyKaList-Programm dargestellt wird. Bei der Erzeugung eines MyKaList- Programms werden zusätzliche Informationen über den Analysevorgang ausgegeben. Diese Informationen im Detail zu verstehen ist schwierig. Vielleicht hast du trotzdem eine Idee, um was es hier geht. links while nichtVorWand: ziegelHinlegen schritt #while Scanner erzeugt: LexToken(ELANW,'links',9,0) LexToken(WH,'while',10,6) LexToken(BED,'nichtVorWand',10,12) LexToken(DP,':',10,24) LexToken(ELANW,'ziegelHinlegen',11,28) LexToken(ELANW,'schritt',12,45) LexToken(WH_ENDE,'#while',13,53) Parser erzeugt: [ ['links'], ['while', ['nichtVorWand'], [['ziegelHinlegen'], ['schritt']]] ]

17 17 Fachkonzept - Scanner Ein (lexikalischer) Scanner ist eine Programmeinheit, die eine Zeichenfolge nach vorgegebenen Mustern in lexikalische Einheiten zerlegt oder anzeigt, dass eine solche Zerlegung nicht möglich ist.

18 18 Fachkonzept - Parser Ein Parser ist eine Programmeinheit, die analysiert, ob eine Tokenfolge zu einem Programmquelltext vorgegebene Grammatikregeln befolgt. Ist das nicht der Fall, so wird eine Fehlermeldung erzeugt. Andernfalls wird eine strukturierte Darstellung des Programmquelltextes erzeugt, die die von den Grammatikregeln verlangte syntaktische Struktur widerspiegelt.

19 19 Teil 3 Interpreter und Compiler im Überblick

20 20 Myka Ausführung von MyKaList- Programmen Übersetzen von MyKaList- Programmen

21 21 Aufgabe Ausführung von MyKaList- Programmen Ein MyKaList-Programm kann man mit der Schaltfläche [Anw. ausführen] schrittweise ausführen. Probiere das mit verschiedenen Testprogrammen aus und beobachte die Entwicklung im MyKaList-Fenster. Beachte, dass der MyKaList-Editor nur zum Anzeigen von MyKaList-Programmen dient. Veränderungen an MyKaList-Programmen kann man hier nicht vornehmen.

22 22 Aufgabe Mit der Schaltfläche [Code erzeugen] lässt sich ein MyKaList-Programm in ein sog. MyKaGoto-Programm übersetzen. Probiere das mit verschiedenen Testprogrammen aus. Versuche mit Hilfe gezielter Experimente die Syntax und Semantik der Code-Sprache MyKaGoto zu erschließen. Übersetzen von MyKaList- Programmen

23 23 Fachkonzept - Interpreter Ein Interpreter für eine Programmiersprache ist ein universelles Programm (Algorithmus), das jedes Programm der zu interpretierenden Programmiersprache schrittweise ausführen kann. MyKaList- Programm

24 24 Exkurs - MyKaGoto links while nichtVorWand: ziegelHinlegen schritt #while links label.L0 if nichtVorWand: goto.L1 else: goto.L2 label.L1 ziegelHinlegen schritt goto.L0 label.L2 [ (None, ['links']) ('.L0', ['noop']) (None, ['if', ['nichtVorWand'], ['goto', '.L1'], ['goto', '.L2']]) ('.L1', ['noop']) (None, ['ziegelHinlegen']) (None, ['schritt']) (None, ['goto', '.L0']) ('.L2', ['noop']) ] MyKa- Programm MyKaGoto- Programm strukturiertes MyKaGoto- Programm benutzt Kontrollstrukturen benutzt Sprungbefehle

25 25 Fachkonzept - Compiler Ein Compiler (im engeren Sinn) ist ein universelles Programm (Algorithmus), das jedes Programm einer Quell-Programmiersprache in ein äquivalentes Programm einer Ziel- Programmiersprache übersetzt. MyKaList- Programm MyKaGoToList- Programm

26 26 Fachkonzept - Compiler Ein Compiler (im weiteren Sinn) ist ein System, das aus Scanner, Parser, Codererzeuger und Codeoptimierer besteht. links while nichtVorWand: ziegelHinlegen schritt #while LexToken(ELANW,'links',9,0) LexToken(WH,'while',10,6) LexToken(BED,'nichtVorWand',10,12) LexToken(DP,':',10,24) LexToken(ELANW,'ziegelHinlegen',11,28) LexToken(ELANW,'schritt',12,45) LexToken(WH_ENDE,'#while',13,53) [ ['links'], ['while', ['nichtVorWand'], [['ziegelHinlegen'], ['schritt']]] ] [ (None, ['links']), ('.L0', ['noop']), (None, ['if', ['nichtVorWand'], ['goto', '.L1'], ['goto', '.L2']]), ('.L1', ['noop']), (None, ['ziegelHinlegen']), (None, ['schritt']), (None, ['goto', '.L0']), ('.L2', ['noop']) ]

27 27 Teil 4 Entwicklung eines Compilers - MyWhile

28 28 Station - MyWhile x = 24 y = 15 d = x - y while d != 0: if d > 0: x = x - y else: y = y - x #if d = x - y #while Die Sprache While ist eine sehr einfache Programmiersprache, die auf vieles verzichtet und nur ganz wenige Konstrukte zur Verfügung stellt. Diese Sprache wird wegen ihrere Einfachheit oft für theoretische Untersuchungen genutzt. Wir benutzen eine Variante von While, die wir MyWhile nennen. Die Sprache MyWhile ist nicht ganz so restriktiv wie die Sprache While, aber dennoch so einfach, dass Funktionsprinzipien von Interpretern und Compilern in einem überschaubaren Kontext verdeutlicht werden können.

29 29 Station - MyWhile elem. Anweisung x = 0 neu = alt x = x + 1 y1 = x0 - 2 z = x + y x = x - y pass Struktur "Variable" = "Zahl" "Variable" = "Variable" "Variable" = "Variable" + "Zahl" "Variable" = "Variable" - "Zahl" "Variable" = "Variable" + "Variable" "Variable" = "Variable" - "Variable" Bedingung x == 0 zahl != 0 x2 > 0 y < 0 Struktur "Variable" == 0 "Variable" != 0 "Variable" > 0 "Variable" < 0 x = 24 y = 15 d = x - y while d != 0: if d > 0: x = x - y else: y = y - x #if d = x - y #while Als Bezeichner von Variablen sind alle Zeichenketten erlaubt, die aus Kleinbuchstaben und Ziffern bestehen und mit einem Buchstaben beginnen. Als Zahlen dürfen hier nur die ganzen Zahlen benutzt werden.

30 30 Station - MyWhile x = 24 y = 15 d = x - y while d != 0: if d > 0: x = x - y else: y = y - x #if d = x - y #while Kontrollstruktur Sequenz: "Anweisung" "Anweisung"... "Anweisung" Fallunterscheidung: if "Bedingung": "Anweisungssequenz" else: "Anweisungssequenz" #if Wiederholung: while "Bedingung": "Anweisungssequenz" #while Bedeutung Sequenz: Führe die Anweisungen der Reihe nach aus. Fallunterscheidung: Wenn die Bedingung erfüllt ist, dann führe die erste Anweisungssequenz aus, ansonsten die zweite Anweisungssequenz. Wiederholung: Solange die Bedingung erfüllt ist, führe die Anweisungssequenz aus.

31 31 Aufgabe x=24 y=15 d=x-y while d != 0 : if d > 0 : x = x - y else: y=y-x#if d=x-y #while Ist das folgende Programm ein syntaktisch korrektes MyWhile-Programm? Warum ist die Klärung der Frage schwierig?

32 32 Station - LEX und YACC LEX ist ein Programm, das Scanner automatisiert erzeugen kann. Gibt man LEX eine genaue Beschreibung der Token vor, so erzeugt LEX einen endlichen Automaten, der Token erkennt. YACC (Akronym für yet another compiler compiler) ist ein Programm, das Parser automatisiert erzeugen kann. Gibt man YACC die Grammatik einer (Programmier-) Sprache vor, so erzeugt YACC einen Shift-Reduce-Parser zur Erkennung der Sprache, die durch die Grammatik beschrieben wird. Wir benutzen im Folgenden die Python-Implementierung PLY von LEX und YACC.

33 33 Station - Scanner Ein (lexikalischer) Scanner ist eine Programmeinheit, die eine Zeichenfolge nach vorgegebenen Mustern in lexikalische Einheiten zerlegt oder anzeigt, dass eine solche Zerlegung nicht möglich ist. x = 24 y = 15 d = x - y while d != 0: if d > 0: x = x - y else: y = y - x #if d = x - y #while (VAR,'x') (ZUW,'=') (ZAHL,'24') (VAR,'y') (ZUW,'=') (ZAHL,'15') (VAR,'d') (ZUW,'=') (VAR,'x') (MINUS,'-') (VAR,'y') (WHILE,'while') (VAR,'d') (UG,'!=') (NULL,'0') (DP,':')... Scanner Quelltext Tokenfolge / Fehlermeldung

34 34 Station - Scanner # Beschreibung der Token t_VAR = r'[a-z][a-z0-9]*' t_ZAHL = r'[\+|-]?[1-9][0-9]*' t_NULL = r'0' t_WHILE = r'while' t_IF = r'if' t_ELSE = r'else' t_PASS = r'pass' t_ENDWH = r'\#while' t_ENDIF = r'\#if' t_ZUW = r'=' t_PLUS = r'\+' t_MINUS = r'-' t_GL = r'==' t_UG = r'!=' t_GR = r'\>' t_KL = r'\<' t_DP = r':' (VAR,'x') (ZUW,'=') (ZAHL,'24') (VAR,'y') (ZUW,'=') (ZAHL,'15') (VAR,'d') (ZUW,'=') (VAR,'x') (MINUS,'-') (VAR,'y') (WHILE,'while') (VAR,'d') (UG,'!=') (NULL,'0') (DP,':') (IF,'if')... Der Aufbau lexikalischer Einheiten wird in der Regel mit Hilfe regulärer Ausdrücke beschrieben. Als Beispiel betrachten wir Variablenbezeichner. Variablenbezeichner beginnen mit einem Kleinbuchstaben. Danach können beliebig viele Kleinbuchstaben oder Ziffern folgen. Dieses Muster lässt sich mit dem regulären Ausdruck [a-z][a-z0-9]* beschreiben. Das Programm LEX ist in der Lage, ausgehend von einer Tokenbeschreibung in Form regulärer Ausdrücke ein System zur lexikalischen Analyse zu erzeugen. Letztlich generiert LEX aus den regulären Ausdrücken endliche Automaten, die die Analyse von Zeichenketten vornehmen.

35 35 Aufgabe # Beschreibung der Token t_VAR = r'[a-z][a-z0-9]*' t_ZAHL = r'[\+|-]?[1-9][0-9]*' t_NULL = r'0' t_WHILE = r'while' t_IF = r'if' t_ELSE = r'else' t_PASS = r'pass' t_ENDWH = r'\#while' t_ENDIF = r'\#if' t_ZUW = r'=' t_PLUS = r'\+' t_MINUS = r'-' t_GL = r'==' t_UG = r'!=' t_GR = r'\>' t_KL = r'\<' t_DP = r':' (VAR,'x') (ZUW,'=') (ZAHL,'24') (VAR,'y') (ZUW,'=') (ZAHL,'15') (VAR,'d') (ZUW,'=') (VAR,'x') (MINUS,'-') (VAR,'y') (WHILE,'while') (VAR,'d') (UG,'!=') (NULL,'0') (DP,':') (IF,'if')... Aufgabe: (a) Welche Zeichenketten passen auf das Token-Muster ZAHL?. Gib Beispiele für solche Zeichenketten an. Beachte die Sonderrolle der Zahl Null, für die ein eigenes Token-Muster vorgesehen ist. (b) Die Festlegung der Token-Muster ist in der vorliegenden Form nicht eindeutig. So passt z.B. die Zeichenkette 'if' auf zwei verschiedene Token-Muster. Welche sind das? Gibt es weitere problematische Zeichenketten?

36 36 Station - Scanner # reservierte Wörter reserved = { 'if' : 'IF', 'else' : 'ELSE', 'while' : 'WHILE', 'pass': 'PASS' } # Namen der Token tokens = ['VAR', 'ZAHL', 'NULL', 'ZUW', 'PLUS', 'MINUS', 'GL', 'UG', 'GR', 'KL', 'DP', 'ENDWH', 'ENDIF'] tokens = tokens + list(reserved.values()) # Beschreibung der Token def t_VAR(t): r'[a-z][a-z0-9]*' t.type = reserved.get(t.value, 'VAR') # Überprüfung auf reservierte Wörter return t t_ZAHL = r'[\+|-]?[1-9][0-9]*' t_NULL = r'0' t_ZUW = r'=' t_PLUS = r'\+' t_MINUS = r'-' t_GL = r'==' t_UG = r'!=' t_GR = r'\>' t_KL = r'\<' t_DP = r':' t_ENDWH = r'\#while' t_ENDIF = r'\#if'... Token-Muster von MyWhile

37 37 Station - Scanner import ply.lex as lex from syntaxWhile import * # Testprogramm programm = ''' x = 24 y = 15 d = x - y while d != 0: if d > 0: x = x - y else: y = y - x #if d = x - y #while ''' # Erzeugung des Scanners scanner = lex.lex(debug=0) # lexikalische Analyse mit Erzeugung der Token scanner.input(programm) token = [] tok = scanner.token() while tok: token = token + [tok] tok = scanner.token() # Ausgabe for tok in token: print(tok) >>> LexToken(VAR,'x',2,1) LexToken(ZUW,'=',2,3) LexToken(ZAHL,'24',2,5) LexToken(VAR,'y',3,8) LexToken(ZUW,'=',3,10) LexToken(ZAHL,'15',3,12) LexToken(VAR,'d',4,15) LexToken(ZUW,'=',4,17) LexToken(VAR,'x',4,19) LexToken(MINUS,'-',4,21) LexToken(VAR,'y',4,23) LexToken(WHILE,'while',5,25) LexToken(VAR,'d',5,31) LexToken(UG,'!=',5,33) LexToken(NULL,'0',5,36) LexToken(DP,':',5,37) LexToken(IF,'if',6,43) LexToken(VAR,'d',6,46) LexToken(GR,'>',6,48) LexToken(NULL,'0',6,50) LexToken(DP,':',6,51) LexToken(VAR,'x',7,61) LexToken(ZUW,'=',7,63) LexToken(VAR,'x',7,65) LexToken(MINUS,'-',7,67) LexToken(VAR,'y',7,69) LexToken(ELSE,'else',8,75) LexToken(DP,':',8,79) LexToken(VAR,'y',9,89)...

38 38 Aufgabe Aufgabe: (a) Probiere das selbst einmal aus. Teste auch andere Quelltexte. Teste u.a. den Quelltext: x=24y=15d=x-ywhiled!=0:ifd>0:x=x-yelse:y=y-x#ifd=x-y#while Teste auch solche Quelltexte, die sich nicht in die vorgegebenen Token zerlegen lassen. Wie reagiert der Scanner auf Variablenbezeichner der Gestalt 007? Hast du eine Vermutung? Was macht der Scanner mit einem unsinnigen Quelltext wie z.B. :while 7:? Hast du eine Vermutung? (b) Versuche, durch Tests herauszufinden, welche Bedeutung die zusätzlichen Zahlangaben in den Token haben. (c) Ändere selbst die Beschreibung der Token in sinnvoller Weise ab und teste die neuen Festlegungen.

39 39 Aufgabe Aufgabe: Das oben gezeigte MyWhile-Programm könnte man auch in einer Java-ähnlichen Schreibweise darstellen. Ändere die Beschreibung der Token so ab, dass sie auf die Java-ähnliche Schweibweise passt. x = 24; y = 15; d = x - y; while (d != 0) { if (d > 0) { x = x - y; } else { y = y - x; }; d = x - y; };

40 40 Station - Parser / Syntaxanalyse Ein Parser ist eine Programmeinheit, die analysiert, ob eine Tokenfolge zu einem Programmquelltext vorgegebene Grammatikregeln befolgt. Ist das nicht der Fall, so wird eine Fehlermeldung erzeugt. Andernfalls wird eine strukturierte Darstellung des Programmquelltextes erzeugt, die die von den Grammatikregeln verlangte syntaktische Struktur widerspiegelt. Parser ok Tokenfolge Struktur / Fehlermeldung (VAR,'x') (ZUW,'=') (ZAHL,'24') (VAR,'y') (ZUW,'=') (ZAHL,'15') (VAR,'d') (ZUW,'=') (VAR,'x') (MINUS,'-') (VAR,'y') (WHILE,'while') (VAR,'d') (UG,'!=') (NULL,'0') (DP,':')...

41 41 Station - Parser / Syntaxanalyse x = 24 y = 15 d = x - y while d != 0: if d > 0: x = x - y else: y = y - x #if d = x - y #while Zunächst muss die Grammatik der Sprache MyWhile festgelegt werden. Die Terminalsymbole der Grammatik sind die Tokennamen. Die Nichtterminalsymbole ergeben sich aus den linken Seiten der folgenden Produktionen. Startsymbol ist das Symbol auf der linken Seite der ersten Produktion. VAR ZUW ZAHL VAR ZUW VAR MINUS VAR WHILE VAR UG NULL DP IF VAR GR NULL DP VAR ZUW VAR MINUS VAR ELSE DP VAR ZUW VAR MINUS VAR ENDIF VAR ZUW VAR MINUS VAR ENDWH # Produktionen anweisungsfolge -> anweisung anweisungsfolge anweisungsfolge -> anweisung anweisung -> zuweisung anweisung -> PASS anweisung -> WHILE bedingung DP anweisungsfolge ENDWH anweisung -> IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIF zuweisung -> VAR ZUW term term -> VAR op zahl term -> VAR op VAR term -> zahl term -> VAR zahl -> NULL zahl -> ZAHL op -> PLUS op -> MINUS bedingung -> VAR rel NULL rel -> GL rel -> UG rel -> GR rel -> KL Grammatik von MyWhile

42 42 Aufgabe x = 4 while x > 0: x = x - 1 #while Aufgabe: Zeige, dass man mit den Produktionen der Grammatik eine Ableitung der Tokenfolge zum Demo-Programm erzeugen kann. VAR ZUW ZAHL WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH # Produktionen anweisungsfolge -> anweisung anweisungsfolge anweisungsfolge -> anweisung anweisung -> zuweisung anweisung -> PASS anweisung -> WHILE bedingung DP anweisungsfolge ENDWH anweisung -> IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIF zuweisung -> VAR ZUW term term -> VAR op zahl term -> VAR op VAR term -> zahl term -> VAR zahl -> NULL zahl -> ZAHL op -> PLUS op -> MINUS bedingung -> VAR rel NULL rel -> GL rel -> UG rel -> GR rel -> KL Grammatik von MyWhile

43 43 Station - Parser / Syntaxanalyse def p_anweisungsfolge_anweisung_anweisungsfolge(p): 'anweisungsfolge : anweisung anweisungsfolge' p[0] = None def p_anweisungsfolge_anweisung(p): 'anweisungsfolge : anweisung' p[0] = None def p_anweisung_zuw(p): 'anweisung : zuweisung' p[0] = None def p_anweisung_pass(p): 'anweisung : PASS' p[0] = None def p_anweisung_wh(p): 'anweisung : WHILE bedingung DP anweisungsfolge ENDWH' p[0] = None def p_anweisung_if(p): 'anweisung : IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIF' p[0] = None def p_zuweisung(p): 'zuweisung : VAR ZUW term' p[0] = None def p_term_var_op_zahl(p): 'term : VAR op zahl' p[0] = None def p_term_var_op_var(p): 'term : VAR op VAR' p[0] = None def p_term_zahl(p): 'term : zahl' p[0] = None... YACC-Implementierung anweisungsfolge -> anweisung anweisungsfolge anweisungsfolge -> anweisung anweisung -> zuweisung anweisung -> PASS anweisung -> WHILE bedingung DP anweisungsfolge ENDWH anweisung -> IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIF zuweisung -> VAR ZUW term term -> VAR op ZAHL term -> VAR op VAR term -> zahl...

44 44 Station - Parser / Syntaxanalyse import ply.lex as lex import ply.yacc as yacc from syntaxWhile import * # Testprogramm programm = ''' x = 24 y = 15 d = x - y while d != 0: if d > 0: x = x - y else: y = y - x #if d = x - y #while ''' # Erzeugung des Scanners scanner = lex.lex(debug=0) # Erzeugung des Parsers parser = yacc.yacc(debug=False) # syntaktische Analyse parser.parse(programm, debug=0) # Ausgabe print("ok!") >>> ok!

45 45 Aufgabe Aufgabe: (a) Probiere das selbst einmal aus. Teste Quelltexte, die den Syntaxregeln von MyWhile entsprechen und teste auch fehlerhafte Quelltexte. Wie zeigt sich in der vorliegenden Implementierung, ob der Quelltext fehlerfrei ist? (b) Du kannst ja auch einmal versuchen, die Grammatik von MyWhile in sinnvoller Weise zu ergänzen oder abzuändern.

46 46 Aufgabe Aufgabe: Ändere die Grammatik (und Tokenbeschreibungen) so ab, dass folgendes Programm erkannt wird: x = 24; y = 15; d = x - y; while (d != 0) { if (d > 0) { x = x - y; } else { y = y - x; }; d = x - y; };

47 47 Station - Parser / Strukturgerüst Ein Parser ist eine Programmeinheit, die analysiert, ob eine Tokenfolge zu einem Programmquelltext vorgegebene Grammatikregeln befolgt. Ist das nicht der Fall, so wird eine Fehlermeldung erzeugt. Andernfalls wird eine strukturierte Darstellung des Programmquelltextes erzeugt, die die von den Grammatikregeln verlangte syntaktische Struktur widerspiegelt. Parser [ ['=', ('VAR', 'x'), [('ZAHL', '24')]], ['=', ('VAR', 'y'), [('ZAHL', '15')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]], ['while', ['!=', ('VAR', 'd'), ('ZAHL', '0')], [ ['if', ['>', ('VAR', 'd'), ('ZAHL', '0')], [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ], [ ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]] ] ], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ] Tokenfolge Struktur / Fehlermeldung (VAR,'x') (ZUW,'=') (ZAHL,'24') (VAR,'y') (ZUW,'=') (ZAHL,'15') (VAR,'d') (ZUW,'=') (VAR,'x') (MINUS,'-') (VAR,'y') (WHILE,'while') (VAR,'d') (UG,'!=') (NULL,'0') (DP,':')...

48 48 Station - Parser / Strukturgerüst Idee: Die Grammatikregeln werden um Beschreibungen zur Erzeugung des Strukturgerüsts erweitert. # Produktionen anweisungsfolge -> anweisung anweisungsfolge anweisungsfolge -> anweisung anweisung -> zuweisung anweisung -> PASS anweisung -> WHILE bedingung DP anweisungsfolge ENDWH anweisung -> IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIF zuweisung -> VAR ZUW term term -> VAR op zahl term -> VAR op VAR term -> zahl term -> VAR zahl -> NULL zahl -> ZAHL op -> PLUS op -> MINUS bedingung -> VAR rel NULL rel -> GL rel -> UG rel -> GR rel -> KL # erweiterte Produktionen... zahl -> ZAHL | | p[0] p[1] p[0] = p[1] term -> zahl | | p[0] p[1] p[0] = [('ZAHL', p[1])] zuweisung -> VAR ZUW term | | | | p[0] p[1]p[2]p[3] p[0] = [p[2], ('VAR', p[1]), p[3]] anweisung -> zuweisung | | p[0] p[1] p[0] = p[1]

49 49 anweisungsfolge -> anweisung anweisungsfolge -> anweisung anweisung -> anweisung WHILE bedingung DP anweisungsfolge ENDWH -> anweisung WHILE bedingung DP anweisung ENDWH -> anweisung WHILE bedingung DP zuweisung ENDWH -> anweisung WHILE bedingung DP VAR ZUW term ENDWH -> anweisung WHILE bedingung DP VAR ZUW VAR op ZAHL ENDWH -> anweisung WHILE bedingung DP VAR ZUW VAR MINUS ZAHL ENDWH -> anweisung WHILE VAR rel NULL DP VAR ZUW VAR MINUS ZAHL ENDWH -> anweisung WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH -> # anweisung -> zuweisung zuweisung WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH -> # zuweisung -> VAR ZUW term VAR ZUW term WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH -> # term -> zahl VAR ZUW zahl WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH -> # zahl -> ZAHL VAR ZUW ZAHL WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH Station - Parser / Strukturgerüst x = 4 while x > 0: x = x - 1 #while VAR ZUW ZAHL WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH Rechtsableitung der Tokenfolge Quelltext Tokenfolge Grammatikregeln

50 50 Station - Parser / Strukturgerüst Grammatik von MyWhile VAR ZUW ZAHL WHILE VAR GR NULL DP VAR ZUW VAR MINUS VAR ENDWH zahl -> ZAHL | | p[0] p[1] p[0] = p[1] zahl: '4' VAR ZUW zahl WHILE VAR GR NULL DP VAR ZUW VAR MINUS VAR ENDWH term -> zahl | | p[0] p[1] p[0] = [('ZAHL', p[1])] term: [('ZAHL', '4')] VAR ZUW term WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH zuweisung -> VAR ZUW term | | | | p[0] p[1]p[2]p[3] p[0] = [p[2], ('VAR', p[1]), p[3]] zuweisung: ['=', ('VAR', 'x'), [('ZAHL', '4')]] zuweisung WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH anweisung -> zuweisung | | p[0] p[1] p[0] = p[1] anweisung: ['=', ('VAR', 'x'), [('ZAHL', '4')]] x = 4 while x > 0: x = x - 1 #while VAR ZUW ZAHL WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH [ ['=', ('VAR', 'x'), [('ZAHL', '4')]], ['while', ['>', ('VAR', 'x'), ('ZAHL', '0')], [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('ZAHL', '1')]] ] erweiterte Grammatikregel produzierte Struktur Rechtsableitung der Tokenfolge ( rückwärts betrachtet) - erweitert um die Erzeugung des Strukturgerüsts

51 51 Station - Parser / Strukturgerüst # erweiterte Produktionen def p_anweisungsfolge_anweisung_anweisungsfolge(p): 'anweisungsfolge : anweisung anweisungsfolge' p[0] = [p[1]] + p[2] def p_anweisungsfolge_anweisung(p): 'anweisungsfolge : anweisung' p[0] = [p[1]] def p_anweisung_zuw(p): 'anweisung : zuweisung' p[0] = p[1] def p_anweisung_pass(p): 'anweisung : PASS' p[0] = [p[1]] def p_anweisung_wh(p): 'anweisung : WHILE bedingung DP anweisungsfolge ENDWH' p[0] = [p[1]] + [p[2]] + [p[4]] def p_anweisung_if(p): 'anweisung : IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIF' p[0] = [p[1]] + [p[2]] + [p[4]] + [p[7]] def p_zuweisung(p): 'zuweisung : VAR ZUW term' p[0] = [p[2], ('VAR', p[1]), p[3]]... YACC-Implementierung

52 52 Station - Parser / Strukturgerüst import ply.lex as lex import ply.yacc as yacc from syntaxWhile import * # Testprogramm programm = ''' x = 4 while x > 0: x = x - 1 #while ''' # Erzeugung des Scanners scanner = lex.lex(debug=0) # Erzeugung des Parsers parser = yacc.yacc(debug=False) # syntaktische Analyse mit Erzeugung des Strukturbaums if len(programm) != 0: strukturbaum = parser.parse(programm, debug=0) else: strukturbaum = [] # Ausgabe print(strukturbaum) >>> [['=', ('VAR', 'x'), [('ZAHL', '4')]], ['while', ['>', ('VAR', 'x'), ('ZAHL', '0')], [['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('ZAHL', '1')]]]]]

53 53 Aufgabe (a) Probiere das selbst einmal aus. Teste verschiedene Quelltexte, die syntaktisch korrekt sind. (b) Was liefert der Parser, wenn ein syntaktischer Fehler vorliegt? (c) Versuche auch einmal, die Strukturelemente anders zu gestalten.

54 54 Aufgabe Aufgabe: Erweitere die Grammatik zur Java-ähnlichen Syntax um Erzeugungsregeln für ein Strukturgerüst. Konzipiere die Erzeugungsregeln so, dass das gleiche Strukturgerüst wie bei der Python-ähnlichen Syntax entsteht. Parser [ ['=', ('VAR', 'x'), [('ZAHL', '4')]], ['while', ['>', ('VAR', 'x'), ('ZAHL', '0')], [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('ZAHL', '1')]] ] Tokenfolge Struktur / Fehlermeldung (VAR,'x') (ZUW,'=') (ZAHL,'4') (SEM, ';') (WHILE,'while') (KL_AUF, '(') (VAR, 'X') (GR, '>') (NULL, '0') (KL_ZU, ')') (WH_BEGINN, '{')... x = 4; while (x > 0) { x = x - 1; };

55 55 Station - Interpreter [ ['=', ('VAR', 'x'), [('NAT', '24')]], ['=', ('VAR', 'y'), [('NAT', '15')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]], ['while', ['!=', ('VAR', 'd'), ('NAT', '0')], [... ] {} [ ['=', ('VAR', 'y'), [('NAT', '15')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]], ['while', ['!=', ('VAR', 'd'), ('NAT', '0')], [... ] {'x' -> 24} Restprogramm Variablenzustand Zuweisung ausführen neues Restprogramm neuer Variablenzustand

56 56 Station - Interpreter [ ['while', ['!=', ('VAR', 'd'), ('ZAHL', '0')], [ ['if', ['>', ('VAR', 'd'), ('ZAHL', '0')], [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ], [ ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]] ] ], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ] {'x' -> 24, 'y' -> 15, 'd' -> 9} [ ['if', ['>', ('VAR', 'd'), ('NAT', '0')], [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ], [ ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]] ] ], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]], ['while', ['!=', ('VAR', 'd'), ('NAT', '0')], [ ['if', ['>', ('VAR', 'd'), ('NAT', '0')], [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ], [ ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]] ] ], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ] {'x' -> 24, 'y' -> 15, 'd' -> 9} Wiederholung ausführen Bedingung True

57 57 Station - Interpreter [ ['if', ['>', ('VAR', 'd'), ('NAT', '0')], [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ], [ ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]] ] ], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]],... ] {'x' -> 24, 'y' -> 15, 'd' -> 9} [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]],... ] {'x' -> 24, 'y' -> 15, 'd' -> 9} Fallunterscheidung ausführen Bedingung True

58 58 Station - Interpreter [ ['if', ['>', ('VAR', 'd'), ('NAT', '0')], [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ], [ ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]] ] ], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]],... ] {'x' -> 9, 'y' -> 15, 'd' -> -6} [ ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]],... ] {'x' -> 9, 'y' -> 15, 'd' -> -6} Fallunterscheidung ausführen Bedingung False

59 59 Station - Interpreter [ ['while', ['!=', ('VAR', 'd'), ('ZAHL', '0')], [ ['if', ['>', ('VAR', 'd'), ('ZAHL', '0')], [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ], [ ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]] ] ], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ] {'x' -> 3, 'y' -> 3, 'd' -> 0} [][] Wiederholung ausführen Bedingung False

60 60 Station - Interpreter class InterpreterWhileList(object): def __init__(self, v): self.programm = None self.variablenzustand = v... def anweisungAusfuehren(self): if self.programm != []: anweisung = self.programm[0] bezeichner = anweisung[0] if bezeichner == "=": self.verarbeiteZuweisung(anweisung) self.programm = self.programm[1:] if bezeichner == "pass": self.programm = self.programm[1:] elif bezeichner == "while": bedingung = anweisung[1] if self.verarbeiteBedingung(bedingung): self.programm = anweisung[2] + self.programm else: self.programm = self.programm[1:] elif bezeichner == "if": bedingung = anweisung[1] if self.verarbeiteBedingung(bedingung): self.programm = anweisung[2] + self.programm[1:] else: self.programm = anweisung[3] + self.programm[1:]... Implementierung

61 61 Station - Interpreter from variablenzustand import * # Testprogramm programm = [ ['=', ('VAR', 'x'), [('ZAHL', '24')]], ['=', ('VAR', 'y'), [('ZAHL', '15')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]], #... ] # Erzeugung des Interpreters variablenzustand = Variablenzustand() interpreter = InterpreterWhileList(variablenzustand) # Initialisierung des Programms interpreter.setProgramm(programm) # Ausführung des Programms und Ausgabe der Zustände print('Programm:') print(interpreter.programm) print('Variablenzustand') print(variablenzustand.variablen) print(' ') while interpreter.getProgramm() != []: interpreter.anweisungAusfuehren() print('Programm:') print(interpreter.programm) print('Variablenzustand') print(variablenzustand.variablen) print(' ')

62 62 Aufgabe Aufgabe: Probiere das selbst einmal aus. Teste verschiedene strukturierte MyWhile-Programme.

63 63 Station - Code-Erzeuger [ (None, ['=', ('VAR', 'x'), [('NAT', '24')]]), (None, ['=', ('VAR', 'y'), [('NAT', '15')]]), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), ('.L3', ['noop']), (None, ['if', ['!=', ('VAR', 'd'), ('NAT', '0')], ['goto', '.L4'], ['goto', '.L5']]), ('.L4', ['noop']), (None, ['if', ['>', ('VAR', 'd'), ('NAT', '0')], ['goto', '.L0'], ['goto', '.L1']]), ('.L0', ['noop']), (None, ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), (None, ['goto', '.L2']), ('.L1', ['noop']), (None, ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]]), ('.L2', ['noop']), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), (None, ['goto', '.L3']), ('.L5', ['noop']) ] Ein Compiler (im engeren Sinn) ist ein universelles Programm (Algorithmus), das jedes Programm einer Quell-Programmiersprache in ein äquivalentes Programm einer Ziel- Programmiersprache übersetzt. [ ['=', ('VAR', 'x'), [('ZAHL', '24')]], ['=', ('VAR', 'y'), [('ZAHL', '15')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]], ['while', ['!=', ('VAR', 'd'), ('ZAHL', '0')], [ ['if', ['>', ('VAR', 'd'), ('ZAHL', '0')], [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ], [ ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]] ] ], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ] QuellcodeZielcode

64 64 Station - Code-Erzeuger [ (None, ['=', ('VAR', 'x'), [('NAT', '24')]]), (None, ['=', ('VAR', 'y'), [('NAT', '15')]]), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), ('.L3', ['noop']), (None, ['if', ['!=', ('VAR', 'd'), ('NAT', '0')], ['goto', '.L4'], ['goto', '.L5']]), ('.L4', ['noop']), (None, ['if', ['>', ('VAR', 'd'), ('NAT', '0')], ['goto', '.L0'], ['goto', '.L1']]), ('.L0', ['noop']), (None, ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), (None, ['goto', '.L2']), ('.L1', ['noop']), (None, ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]]), ('.L2', ['noop']), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), (None, ['goto', '.L3']), ('.L5', ['noop']) ] [ ['=', ('VAR', 'x'), [('ZAHL', '24')]], ['=', ('VAR', 'y'), [('ZAHL', '15')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]], ['while', ['!=', ('VAR', 'd'), ('ZAHL', '0')], [ ['if', ['>', ('VAR', 'd'), ('ZAHL', '0')], [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ], [ ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]] ] ], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]] ] QuellcodeZielcode x = 24 y = 15 d = x - y while d != 0: if d > 0: x = x - y else: y = y - x #if d = x - y #while x=24 y=15 d=x-y label.L3 if d!=0: goto.L4 else: goto.L5 label.L4 if d>0: goto.L0 else: goto.L1 label.L0 x=x-y goto.L2 label.L1 y=y-x label.L2 d=x-y goto.L3 label.L5

65 65 Station - Code-Erzeuger x = 1 if x1 != 0: y = x else: y = 0 #if x=1 if x1!=0: # Auswertung der Bedingung goto.L0 # Sprung zum wahr-Fall else: goto.L1 # Sprung zum falsch-Fall label.L0 # wahr-Fall y=x goto.L2 # Sprung zum Ende der Fallunterscheidung label.L1 # wahr-Fall y=0 label.L2 # Ende der Fallunterscheidung Fallunterscheidung übersetzen

66 66 Station - Code-Erzeuger x = 5 while x != 0: x = x - 1 #while x=5 label.L0 # Beginn der Schleife if x!=0: # Auswertung der Bedingung goto.L1 # Sprung zum Schleifenkörper else: goto.L2 # Sprung aus der Schleife label.L1 # Beginn des Schleifenkörpers x=x-1 goto.L0 # Sprung zum Beginn der schleife label.L2 # Ende der Schleife Wiederholung übersetzen

67 67 Station - Code-Erzeuger class UebersetzerWhileList(object): def __init__(self): self.quellcode = None def setQuellcode(self, q): self.quellcode = q def uebersetzen(self): def c_programm(p): 'programm : anweisungsfolge' return c_anweisungsfolge(p) def c_anweisungsfolge(p): '''anweisungsfolge : anweisung anweisungsfolge | anweisung''' if len(p) > 1: return c_anweisung(p[0]) + c_anweisungsfolge(p[1:]) else: return c_anweisung(p[0]) def c_anweisung(p): '''anweisung : VAR ZUW term | PASS | WHILE bedingung DP anweisungsfolge ENDWH | IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIF'''... self.zaehler = 0 if self.quellcode != None: return c_programm(self.quellcode) else: return [] Implementierung

68 68 Station - Code-Erzeuger... def c_anweisung(p): if p[0] == "=": return [(None, p)] elif p[0] == "pass": return [(None, ['noop'])] elif p[0] == 'while': ergebnis_true = c_anweisungsfolge(p[2]) ergebnis_wh = [('.L' + str(self.zaehler), ['noop']), \ (None, ['if', p[1], ['goto', '.L' + str(self.zaehler+1)], \ ['goto', '.L' + str(self.zaehler+2)]]), \ ('.L' + str(self.zaehler+1), ['noop'])] + \ ergebnis_true + \ [(None, ['goto', '.L' + str(self.zaehler)]), \ ('.L' + str(self.zaehler+2), ['noop'])] self.zaehler = self.zaehler + 3 return ergebnis_wh elif p[0] == 'if': ergebnis_true = c_anweisungsfolge(p[2]) ergebnis_false = c_anweisungsfolge(p[3]) ergebnis_if = [(None, ['if', p[1], ['goto', '.L' + str(self.zaehler)], \ ['goto', '.L' + str(self.zaehler+1)]]), \ ('.L' + str(self.zaehler), ['noop'])] + \ ergebnis_true + \ [(None, ['goto', '.L' + str(self.zaehler+2)])] + \ [('.L' + str(self.zaehler+1), ['noop'])]+ \ ergebnis_false + \ [('.L' + str(self.zaehler+2), ['noop'])] self.zaehler = self.zaehler + 3 return ergebnis_if... Implementierung

69 69 Station - Code-Erzeuger from uebersetzerWhileList import * # Testprogramm quellcode = [ ['=', ('VAR', 'x'), [('ZAHL', '24')]], ['=', ('VAR', 'y'), [('ZAHL', '15')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]], #... ] codeerzeuger = UebersetzerWhileList() # Erzeugung des Zielcodes codeerzeuger.setQuellcode(quellcode) zielcode = codeerzeuger.uebersetzen() # Ausführung des Programms und Ausgabe der Zustände print('Quellcode:') print() for zeile in quellcode: print(zeile) print() print('Zielcode:') print() for zeile in zielcode: print(zeile)

70 70 Aufgabe Aufgabe: Probiere das selbst einmal aus. Übersetze verschiedene strukturierte MyWhile-Programme.

71 71 Station - CodeInterpreter [ (None, ['=', ('VAR', 'x'), [('NAT', '24')]]), (None, ['=', ('VAR', 'y'), [('NAT', '15')]]), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), ('.L3', ['noop']), (None, ['if', ['!=', ('VAR', 'd'), ('NAT', '0')], ['goto', '.L4'], ['goto', '.L5']]), ('.L4', ['noop']), (None, ['if', ['>', ('VAR', 'd'), ('NAT', '0')], ['goto', '.L0'], ['goto', '.L1']]), ('.L0', ['noop']), (None, ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), (None, ['goto', '.L2']), ('.L1', ['noop']), (None, ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]]), ('.L2', ['noop']), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), (None, ['goto', '.L3']), ('.L5', ['noop']) ] pc -> 0 Zuweisung ausführen {}{} [ (None, ['=', ('VAR', 'x'), [('NAT', '24')]]), (None, ['=', ('VAR', 'y'), [('NAT', '15')]]), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), ('.L3', ['noop']), (None, ['if', ['!=', ('VAR', 'd'), ('NAT', '0')], ['goto', '.L4'], ['goto', '.L5']]), ('.L4', ['noop']), (None, ['if', ['>', ('VAR', 'd'), ('NAT', '0')], ['goto', '.L0'], ['goto', '.L1']]), ('.L0', ['noop']), (None, ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), (None, ['goto', '.L2']), ('.L1', ['noop']), (None, ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]]), ('.L2', ['noop']), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), (None, ['goto', '.L3']), ('.L5', ['noop']) ] pc -> 1 { 'x' -> 1, } Programmzähler Variablenzustand Programmzähler Variablenzustand

72 72 Station - CodeInterpreter >x=24 y=15 d=x-y label.L3 if d!=0: goto.L4 else: goto.L5 label.L4 if d>0: goto.L0 else: goto.L1 label.L0 x=x-y goto.L2 label.L1 y=y-x label.L2 d=x-y goto.L3 label.L5 {}{} Zuweisung ausführen x=24 >y=15 d=x-y label.L3 if d!=0: goto.L4 else: goto.L5 label.L4 if d>0: goto.L0 else: goto.L1 label.L0 x=x-y goto.L2 label.L1 y=y-x label.L2 d=x-y goto.L3 label.L5 { 'x' -> 24 }

73 73 Station - CodeInterpreter x=24 y=15 d=x-y label.L3 >if d!=0: goto.L4 else: goto.L5 label.L4 if d>0: goto.L0 else: goto.L1 label.L0 x=x-y goto.L2 label.L1 y=y-x label.L2 d=x-y goto.L3 label.L5 { 'x' -> 24, 'y' -> 15, 'd' -> 9 } bedingter Sprung ausführen x=24 >y=15 d=x-y label.L3 if d!=0: goto.L4 else: goto.L5 >label.L4 if d>0: goto.L0 else: goto.L1 label.L0 x=x-y goto.L2 label.L1 y=y-x label.L2 d=x-y goto.L3 label.L5 { 'x' -> 24, 'y' -> 15, 'd' -> 9 }

74 74 Station - CodeInterpreter x=24 y=15 d=x-y label.L3 if d!=0: goto.L4 else: goto.L5 label.L4 if d>0: goto.L0 else: goto.L1 label.L0 x=x-y >goto.L2 label.L1 y=y-x label.L2 d=x-y goto.L3 label.L5 { 'x' -> 9, 'y' -> 15, 'd' -> 9 } unbedingter Sprung ausführen x=24 >y=15 d=x-y label.L3 if d!=0: goto.L4 else: goto.L5 label.L4 if d>0: goto.L0 else: goto.L1 label.L0 x=x-y goto.L2 label.L1 y=y-x >label.L2 d=x-y goto.L3 label.L5 { 'x' -> 9, 'y' -> 15, 'd' -> 9 }

75 75 Station - Interpreter class InterpreterGoto(object):... def anweisungAusfuehren(self): if self.pc < len(self.programm): zeile = self.programm[self.pc] label = zeile[0] if label != None: self.pc = self.pc + 1 else: anweisung = zeile[1] if anweisung[0] == "=": self.verarbeiteZuweisung(anweisung) self.pc = self.pc + 1 elif anweisung[0] == "if": if self.verarbeiteBedingung(anweisung[1]): self.verarbeiteGoto(anweisung[2]) else: self.verarbeiteGoto(anweisung[3]) elif anweisung[0] == "goto": self.verarbeiteGoto(anweisung) elif anweisung[0] == "noop": self.pc = self.pc + 1 elif anweisung[0] == "stop": self.pc = self.pc Implementierung

76 76 Station - Interpreter from interpreterGoto import * from variablenzustand import * # Testprogramm programm = [ (None, ['=', ('VAR', 'x'), [('ZAHL', '24')]]), (None, ['=', ('VAR', 'y'), [('ZAHL', '15')]]), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), ('.L3', ['noop']), (None, ['if', ['!=', ('VAR', 'd'), ('ZAHL', '0')], ['goto', '.L4'], ['goto', '.L5']]), ('.L4', ['noop']), (None, ['if', ['>', ('VAR', 'd'), ('ZAHL', '0')], ['goto', '.L0'], ['goto', '.L1']]), ('.L0', ['noop']),... ] # Erzeugung des Interpreters variablenzustand = Variablenzustand() interpreterGoto = InterpreterGoto(variablenzustand) # Initialisierung des Programms interpreterGoto.initProgramm(programm) # Ausführung des Programms und Ausgabe der Zustände print('Variablenzustand vorher') print(variablenzustand.variablen) print() while interpreterGoto.getPC() < len(interpreterGoto.getProgramm()): interpreterGoto.anweisungAusfuehren() print('Variablenzustand nachher') print(variablenzustand.variablen)

77 77 Aufgabe Aufgabe: Probiere das selbst einmal aus. Teste verschiedene strukturierte MyGoto-Programme.

78 78 Station - Simulationsprogramm


Herunterladen ppt "Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter."

Ähnliche Präsentationen


Google-Anzeigen