Compiler und Interpreter Klaus Becker 2010 2 Compiler
Compiler und Interpreter Klaus Becker 2010
2 Compiler und Interpreter
3 Teil 1 Syntax und Semantik im Überblick
Karol / Myka 4 Karol My. Ka(rol)
5 Aufgabe links while nicht. Vor. Wand: ziegel. Hinlegen schritt #while Versuche anhand weiterer Tests die Regeln der Sprache My. Ka herauszufinden: (a) Wie können Programme der Sprache aufgebaut werden? if nicht. Vor. Wand: if nicht. Vor. Ziegel: schritt else: ziegel. Hinlegen #if else: links #if marke. Setzen schritt while nicht. Auf. Marke: while nicht. Vor. Wand: schritt #while links #while
6 Aufgabe links while nicht. Vor. Wand: ziegel. Hinlegen schritt #while Versuche anhand weiterer Tests die Regeln der Sprache My. Ka herauszufinden: (b) Welche Bedeutung haben die Sprachkonstrukte? if nicht. Vor. Wand: if nicht. Vor. Ziegel: schritt else: ziegel. Hinlegen #if else: links #if marke. Setzen schritt while nicht. Auf. Marke: while nicht. Vor. Wand: schritt #while links #while
Exkurs - My. Ka 7 Anweisung Bedeutung schritt einen Schritt vorwärts bewegen - sofern möglich links um 90° nach links drehen rechts um 90° nach rechts drehen ziegel. Hinlehen einen Ziegen in das vor dem Roboter liegende Feld hinlegen - sofern möglich ziegel. Aufheben einen Ziegen von dem vor dem Roboter liegenden Feld aufheben - sofern möglich marke. Setzen eine Marke auf das Feld setzen, auf dem sich der Roboter befindet marke. Loeschen eine Marke löschen, die sich auf dem Feld des Roboters befindet - sofern möglich pass mache nichts links while nicht. Vor. Wand: ziegel. Hinlegen schritt #while if nicht. Vor. Wand: if nicht. Vor. Ziegel: schritt else: ziegel. Hinlegen #if else: links #if marke. Setzen schritt while nicht. Auf. Marke: while nicht. Vor. Wand: schritt #while links #while
Exkurs - My. Ka 8 Bedingung Bedeutung vor. Wand Befindet sich der Roboter vor einer Wand? nicht. Vor. Wand Befindet sich der Roboter nicht vor einer Wand? vor. Ziegel Befindet sich der Roboter vor einem Ziegel? nicht. Vor. Ziegel Befindet sich der Roboter nicht vor einem Ziegel? auf. Marke Befindet sich der Roboter auf einer Marke? nicht. Auf. Marke Befindet sich der Roboter nicht auf einer Marke? links while nicht. Vor. Wand: ziegel. Hinlegen schritt #while if nicht. Vor. Wand: if nicht. Vor. Ziegel: schritt else: ziegel. Hinlegen #if else: links #if marke. Setzen schritt while nicht. Auf. Marke: while nicht. Vor. Wand: schritt #while links #while
Exkurs - My. Ka 9 Kontrollstruktur Bedeutung Sequenz: "Anweisung". . . "Anweisung" Führe die Anweisungen der Reihe nach aus. Fallunterscheidung: if "Bedingung": "Anweisungssequenz" else: "Anweisungssequenz" #if Wenn die Bedingung erfüllt ist, dann führe die erste Anweisungssequenz aus, ansonsten die zweite Anweisungssequenz. Wiederholung: while "Bedingung": "Anweisungssequenz" #while Wiederholung: Solange die Bedingung erfüllt ist, führe die Anweisungssequenz aus. links while nicht. Vor. Wand: ziegel. Hinlegen schritt #while if nicht. Vor. Wand: if nicht. Vor. Ziegel: schritt else: ziegel. Hinlegen #if else: links #if marke. Setzen schritt while nicht. Auf. Marke: while nicht. Vor. Wand: schritt #while links #while
10 Exkurs - My. Ka 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 My. Ka ist beispielsweise noch nicht geklärt, ob es auch leere Anweisungssequenzen geben kann (z. B. in der Anweisung while nicht. Vor. Wand: #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 My. Ka wird das in den folgenden Abschnitten nachgeholt. links while nicht. Vor. Wand: ziegel. Hinlegen schritt #while if nicht. Vor. Wand: if nicht. Vor. Ziegel: schritt else: ziegel. Hinlegen #if else: links #if marke. Setzen schritt while nicht. Auf. Marke: while nicht. Vor. Wand: schritt #while links #while
11 Fachkonzept - Syntax Die Syntax einer Sprache beschreibt, welche Kombinationen von Zeichen fehlerfreie Programme der Sprache bilden. myka_syn = {Programm 1, Programm 2, . . . } Eine Präzisierung dieser Menge kann z. B. mit Hilfe einer Grammatik vorgenommen werden. links while nicht. Vor. Wand: ziegel. Hinlegen schritt #while if nicht. Vor. Wand: if nicht. Vor. Ziegel: schritt else: ziegel. Hinlegen #if else: links #if Programmx marke. Setzen schritt while nicht. Auf. Marke: while nicht. Vor. Wand: schritt #while links #while
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 Teil 2 Scanner und Parser im Überblick
Myka 14 syntaktisch korrektes Programm Strukturdarstellung d. Programms Programm mit Syntaxfehler
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 My. Ka. Programm-Quelltexte in das linke obere Fenster ein. Erzeuge mit der Schaltfläche [scannen / parsen] ein My. Ka. List-Programm - das ist eine mit Hilfe von Listen erstellte strukturierte Darstellung des My. Ka. 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 links while nicht. Vor. Wand: ziegel. Hinlegen schritt #while Scanner erzeugt: Lex. Token(ELANW, 'links', 9, 0) Lex. Token(WH, 'while', 10, 6) Lex. Token(BED, 'nicht. Vor. Wand', 10, 12) Lex. Token(DP, ': ', 10, 24) Lex. Token(ELANW, 'ziegel. Hinlegen', 11, 28) Lex. Token(ELANW, 'schritt', 12, 45) Lex. Token(WH_ENDE, '#while', 13, 53) Parser erzeugt: [ ['links'], ['while', ['nicht. Vor. Wand'], [['ziegel. Hinlegen'], ['schritt']]] ] Aufgabe Versuche anhand weiterer Tests zu erschließen, wie ein syntaktisch korrektes My. Ka-Programm mit Hilfe von Listen strukturiert als My. Ka. List-Programm dargestellt wird. Bei der Erzeugung eines My. Ka. List. 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.
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 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 von den Grammatikregeln verlangte syntaktische Struktur widerspiegelt.
19 Teil 3 Interpreter und Compiler im Überblick
Myka 20 Ausführung von My. Ka. List. Programmen Übersetzen von My. Ka. List. Programmen
Aufgabe 21 Ein My. Ka. List-Programm kann man mit der Schaltfläche [Anw. ausführen] schrittweise ausführen. Probiere das mit verschiedenen Testprogrammen aus und beobachte die Entwicklung im My. Ka. List-Fenster. Beachte, dass der My. Ka. List-Editor nur zum Anzeigen von My. Ka. List-Programmen dient. Veränderungen an My. Ka. List-Programmen kann man hier nicht vornehmen. Ausführung von My. Ka. List. Programmen
Aufgabe 22 Mit der Schaltfläche [Code erzeugen] lässt sich ein My. Ka. List-Programm in ein sog. My. Ka. Goto-Programm übersetzen. Probiere das mit verschiedenen Testprogrammen aus. Versuche mit Hilfe gezielter Experimente die Syntax und Semantik der Code-Sprache My. Ka. Goto zu erschließen. Übersetzen von My. Ka. List. Programmen
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. My. Ka. List. Programm
24 links while nicht. Vor. Wand: ziegel. Hinlegen schritt #while benutzt Kontrollstrukturen links label. L 0 if nicht. Vor. Wand: goto. L 1 else: goto. L 2 label. L 1 ziegel. Hinlegen schritt goto. L 0 label. L 2 Exkurs - My. Ka. Goto My. Ka. Programm benutzt Sprungbefehle My. Ka. Goto. Programm [ (None, ['links']) ('. L 0', ['noop']) (None, ['if', ['nicht. Vor. Wand'], ['goto', '. L 1'], ['goto', '. L 2']]) ('. L 1', ['noop']) (None, ['ziegel. Hinlegen']) (None, ['schritt']) (None, ['goto', '. L 0']) ('. L 2', ['noop']) ] strukturiertes My. Ka. Goto. Programm
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. My. Ka. List. Programm My. Ka. Go. To. List. Programm
26 Fachkonzept - Compiler Ein Compiler (im weiteren Sinn) ist ein System, das aus Scanner, Parser, Codererzeuger und Codeoptimierer besteht. links while nicht. Vor. Wand: ziegel. Hinlegen schritt #while Lex. Token(ELANW, 'links', 9, 0) Lex. Token(WH, 'while', 10, 6) Lex. Token(BED, 'nicht. Vor. Wand', 10, 12) Lex. Token(DP, ': ', 10, 24) Lex. Token(ELANW, 'ziegel. Hinlegen', 11, 28) Lex. Token(ELANW, 'schritt', 12, 45) Lex. Token(WH_ENDE, '#while', 13, 53) [ ['links'], ['while', ['nicht. Vor. Wand'], [['ziegel. Hinlegen'], ['schritt']]] ] [ (None, ['links']), ('. L 0', ['noop']), (None, ['if', ['nicht. Vor. Wand'], ['goto', '. L 1'], ['goto', '. L 2']]), ('. L 1', ['noop']), (None, ['ziegel. Hinlegen']), (None, ['schritt']), (None, ['goto', '. L 0']), ('. L 2', ['noop']) ]
27 Teil 4 Entwicklung eines Compilers - My. While
28 Station - My. 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 My. While nennen. Die Sprache My. While 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. 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
Station - My. While 29 elem. Anweisung Struktur x=0 "Variable" = "Zahl" neu = alt "Variable" = "Variable" x=x+1 "Variable" = "Variable" + "Zahl" y 1 = x 0 - 2 "Variable" = "Variable" - "Zahl" z=x+y "Variable" = "Variable" + "Variable" x=x-y "Variable" = "Variable" - "Variable" pass Bedingung Struktur x == 0 "Variable" == 0 zahl != 0 "Variable" != 0 x 2 > 0 "Variable" > 0 y<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.
Station - My. While 30 Kontrollstruktur Bedeutung Sequenz: "Anweisung". . . "Anweisung" Führe die Anweisungen der Reihe nach aus. Fallunterscheidung: if "Bedingung": "Anweisungssequenz" else: "Anweisungssequenz" #if Wenn die Bedingung erfüllt ist, dann führe die erste Anweisungssequenz aus, ansonsten die zweite Anweisungssequenz. Wiederholung: while "Bedingung": "Anweisungssequenz" #while Wiederholung: Solange die Bedingung erfüllt ist, führe die Anweisungssequenz aus. 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
31 Aufgabe Ist das folgende Programm ein syntaktisch korrektes My. While-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 Warum ist die Klärung der Frage schwierig?
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) 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 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 Scanner Quelltext Tokenfolge / 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, ': '). . .
34 Station - Scanner Der Aufbau lexikalischer Einheiten wird in der Regel mit Hilfe regulärer Ausdrücke beschrieben. Als Beispiel betrachten wir 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-z 0 -9]* beschreiben. # Beschreibung der Token t_VAR = r'[a-z][a-z 0 -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'). . . 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 Analyse von Zeichenketten vornehmen.
35 Aufgabe # Beschreibung der Token t_VAR = r'[a-z][a-z 0 -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 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()) Token-Muster von My. While # Beschreibung der Token def t_VAR(t): r'[a-z][a-z 0 -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'. . .
37 Station - Scanner import ply. lex as lex from syntax. While import * # Testprogramm = ''' 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(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) >>> Lex. Token(VAR, 'x', 2, 1) Lex. Token(ZUW, '=', 2, 3) Lex. Token(ZAHL, '24', 2, 5) Lex. Token(VAR, 'y', 3, 8) Lex. Token(ZUW, '=', 3, 10) Lex. Token(ZAHL, '15', 3, 12) Lex. Token(VAR, 'd', 4, 15) Lex. Token(ZUW, '=', 4, 17) Lex. Token(VAR, 'x', 4, 19) Lex. Token(MINUS, '-', 4, 21) Lex. Token(VAR, 'y', 4, 23) Lex. Token(WHILE, 'while', 5, 25) Lex. Token(VAR, 'd', 5, 31) Lex. Token(UG, '!=', 5, 33) Lex. Token(NULL, '0', 5, 36) Lex. Token(DP, ': ', 5, 37) Lex. Token(IF, 'if', 6, 43) Lex. Token(VAR, 'd', 6, 46) Lex. Token(GR, '>', 6, 48) Lex. Token(NULL, '0', 6, 50) Lex. Token(DP, ': ', 6, 51) Lex. Token(VAR, 'x', 7, 61) Lex. Token(ZUW, '=', 7, 63) Lex. Token(VAR, 'x', 7, 65) Lex. Token(MINUS, '-', 7, 67) Lex. Token(VAR, 'y', 7, 69) Lex. Token(ELSE, 'else', 8, 75) Lex. Token(DP, ': ', 8, 79) Lex. Token(VAR, 'y', 9, 89). . .
38 Aufgabe: (a) Probiere das selbst einmal aus. Teste auch andere Quelltexte. Teste u. a. den Quelltext: x=24 y=15 d=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 Aufgabe: Das oben gezeigte My. While-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 != if (d > x = } else { y = }; d = x }; 0) { x - y; y - x; y;
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 von den Grammatikregeln verlangte syntaktische Struktur widerspiegelt. Parser (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, ': '). . . Tokenfolge Struktur / Fehlermeldung ok
41 Station - Parser / Syntaxanalyse Zunächst muss die Grammatik der Sprache My. While 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. # Produktionen anweisungsfolge -> anweisungsfolge -> anweisung -> zuweisung anweisung -> PASS anweisung -> WHILE bedingung DP anweisungsfolge ENDWH anweisung -> IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIF zuweisung -> VAR ZUW 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 Grammatik von My. While rel -> KL 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 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
42 Aufgabe: Zeige, dass man mit den Produktionen der Grammatik eine Ableitung der Tokenfolge zum Demo-Programm erzeugen kann. # Produktionen anweisungsfolge -> anweisungsfolge -> anweisung -> zuweisung anweisung -> PASS anweisung -> WHILE bedingung DP anweisungsfolge ENDWH anweisung -> IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIF zuweisung -> VAR ZUW 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 Grammatik von My. While rel -> KL x = 4 while x > 0: x = x - 1 #while VAR ZUW ZAHL WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH
43 Station - Parser / Syntaxanalyse def p_anweisungsfolge_anweisungsfolge(p): 'anweisungsfolge : anweisungsfolge' YACC-Implementierung 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): anweisungsfolge -> anweisungsfolge 'zuweisung : VAR ZUW term' anweisungsfolge -> anweisung p[0] = None anweisung -> zuweisung def p_term_var_op_zahl(p): anweisung -> PASS 'term : VAR op zahl' anweisung -> WHILE bedingung DP anweisungsfolge ENDWH p[0] = None anweisung -> IF bedingung DP anweisungsfolge ELSE DP def p_term_var_op_var(p): anweisungsfolge ENDIF 'term : VAR op VAR' zuweisung -> VAR ZUW term p[0] = None term -> VAR op ZAHL def p_term_zahl(p): term -> VAR op VAR 'term : zahl' term -> zahl p[0] = None. . .
44 Station - Parser / Syntaxanalyse import ply. lex as lex import ply. yacc as yacc from syntax. While import * # Testprogramm = ''' 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(debug=0) # Erzeugung des Parsers parser = yacc(debug=False) # syntaktische Analyse parser. parse(programm, debug=0) # Ausgabe print("ok!") >>> ok!
45 Aufgabe: (a) Probiere das selbst einmal aus. Teste Quelltexte, die den Syntaxregeln von My. While 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 My. While in sinnvoller Weise zu ergänzen oder abzuändern.
46 Aufgabe: Ändere die Grammatik (und Tokenbeschreibungen) so ab, dass folgendes Programm erkannt wird: x = 24; y = 15; d = x - y; while (d != if (d > x = } else { y = }; d = x }; 0) { x - y; y - x; y;
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 von den Grammatikregeln verlangte syntaktische Struktur widerspiegelt. Parser [ (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, ': '). . . Tokenfolge Struktur / Fehlermeldung ] ['=', ('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')]] ] ]
48 Station - Parser / Strukturgerüst Idee: Die Grammatikregeln werden um Beschreibungen zur Erzeugung des Strukturgerüsts erweitert. # Produktionen anweisungsfolge -> anweisungsfolge -> anweisung -> zuweisung anweisung -> PASS anweisung -> WHILE bedingung DP anweisungsfolge ENDWH anweisung -> IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIF zuweisung -> VAR ZUW 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 x = 4 while x > 0: x = x - 1 #while Station - Parser / Strukturgerüst Quelltext Tokenfolge VAR ZUW ZAHL WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH anweisungsfolge -> Rechtsableitung der anweisungsfolge -> Tokenfolge 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 -> Grammatikregeln 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 WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH -> # zuweisung -> 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
50 Station - Parser / Strukturgerüst 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' erweiterte Grammatikregel produzierte Struktur 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')] 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 ( rückwärts betrachtet) - erweitert um die Erzeugung des Strukturgerüsts Grammatik von My. While 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')]] [ ['=', ('VAR', 'x'), [('ZAHL', '4')]], zuweisung WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH ['while', ['>', ('VAR', 'x'), ('ZAHL', '0')], [ anweisung -> zuweisung ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('ZAHL', '1')]] | | ] p[0] p[1] ] p[0] = p[1] ] anweisung: ['=', ('VAR', 'x'), [('ZAHL', '4')]]
51 Station - Parser / Strukturgerüst # erweiterte Produktionen def p_anweisungsfolge_anweisungsfolge(p): 'anweisungsfolge : anweisungsfolge' p[0] = [p[1]] + p[2] YACC-Implementierung 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]]. . .
52 Station - Parser / Strukturgerüst import ply. lex as lex import ply. yacc as yacc from syntax. While import * # Testprogramm = ''' x = 4 while x > 0: x = x - 1 #while ''' # Erzeugung des Scanners scanner = lex(debug=0) # Erzeugung des Parsers parser = 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 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.
Aufgabe 54 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. x = 4; while (x > 0) { x = x - 1; }; Parser (VAR, 'x') (ZUW, '=') (ZAHL, '4') (SEM, '; ') (WHILE, 'while') (KL_AUF, '(') (VAR, 'X') (GR, '>') (NULL, '0') (KL_ZU, ')') (WH_BEGINN, '{'). . . Tokenfolge [ Struktur / Fehlermeldung ] ['=', ('VAR', 'x'), [('ZAHL', '4')]], ['while', ['>', ('VAR', 'x'), ('ZAHL', '0')], [ ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('ZAHL', '1')]] ] ]
55 Station - Interpreter Zuweisung ausführen [ ] [ ['=', ('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 neues Restprogramm Variablenzustand neuer Variablenzustand
Station - Interpreter 60 class Interpreter. While. List(object): def __init__(self, v): self. programm = None self. variablenzustand = v. . . def anweisung. Ausfuehren(self): if self. programm != []: anweisung = self. programm[0] bezeichner = anweisung[0] if bezeichner == "=": self. verarbeite. Zuweisung(anweisung) self. programm = self. programm[1: ] if bezeichner == "pass": self. programm = self. programm[1: ] elif bezeichner == "while": bedingung = anweisung[1] if self. verarbeite. Bedingung(bedingung): self. programm = anweisung[2] + self. programm else: self. programm = self. programm[1: ] elif bezeichner == "if": bedingung = anweisung[1] if self. verarbeite. Bedingung(bedingung): self. programm = anweisung[2] + self. programm[1: ] else: self. programm = anweisung[3] + self. programm[1: ]. . . Implementierung
61 Station - Interpreter from variablenzustand import * # Testprogramm = [ ['=', ('VAR', 'x'), [('ZAHL', '24')]], ['=', ('VAR', 'y'), [('ZAHL', '15')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]], #. . . ] # Erzeugung des Interpreters variablenzustand = Variablenzustand() interpreter = Interpreter. While. List(variablenzustand) # Initialisierung des Programms interpreter. set. Programm(programm) # Ausführung des Programms und Ausgabe der Zustände print('Programm: ') print(interpreter. programm) print('Variablenzustand') print(variablenzustand. variablen) print('--------------') while interpreter. get. Programm() != []: interpreter. anweisung. Ausfuehren() print('Programm: ') print(interpreter. programm) print('Variablenzustand') print(variablenzustand. variablen) print('--------------')
62 Aufgabe: Probiere das selbst einmal aus. Teste verschiedene strukturierte My. While-Programme.
Station - Code-Erzeuger 63 Ein Compiler (im engeren Sinn) ist ein universelles Programm (Algorithmus), das jedes Programm einer Quell-Programmiersprache in ein äquivalentes Programm einer Ziel. Programmiersprache übersetzt. Quellcode [ ] ['=', ('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')]] ] ] Zielcode [ (None, ['=', ('VAR', 'x'), [('NAT', '24')]]), (None, ['=', ('VAR', 'y'), [('NAT', '15')]]), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), ('. L 3', ['noop']), (None, ['if', ['!=', ('VAR', 'd'), ('NAT', '0')], ['goto', '. L 4'], ['goto', '. L 5']]), ('. L 4', ['noop']), (None, ['if', ['>', ('VAR', 'd'), ('NAT', '0')], ['goto', '. L 0'], ['goto', '. L 1']]), ('. L 0', ['noop']), (None, ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), (None, ['goto', '. L 2']), ('. L 1', ['noop']), (None, ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]]), ('. L 2', ['noop']), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), (None, ['goto', '. L 3']), ('. L 5', ['noop']) ]
Station - Code-Erzeuger 64 Quellcode [ ] Zielcode ['=', ('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')]] ] ] 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 [ (None, ['=', ('VAR', 'x'), [('NAT', '24')]]), (None, ['=', ('VAR', 'y'), [('NAT', '15')]]), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), ('. L 3', ['noop']), (None, ['if', ['!=', ('VAR', 'd'), ('NAT', '0')], ['goto', '. L 4'], ['goto', '. L 5']]), ('. L 4', ['noop']), x=24 (None, ['if', ['>', ('VAR', 'd'), ('NAT', '0')], ['goto', '. L 0'], ['goto', '. L 1']]), y=15 ('. L 0', ['noop']), d=x-y (None, ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), label. L 3 (None, ['goto', '. L 2']), if d!=0: ('. L 1', ['noop']), goto. L 4 (None, ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]]), ('. L 2', ['noop']), else: (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), goto. L 5 (None, ['goto', '. L 3']), label. L 4 ('. L 5', ['noop']) if d>0: ] goto. L 0 else: goto. L 1 label. L 0 x=x-y goto. L 2 label. L 1 y=y-x label. L 2 d=x-y goto. L 3 label. L 5
65 Station - Code-Erzeuger Fallunterscheidung übersetzen x=1 if x 1 != 0: y=x else: y=0 #if x=1 if x 1!=0: # Auswertung der Bedingung goto. L 0 # Sprung zum wahr-Fall else: goto. L 1 # Sprung zum falsch-Fall label. L 0 # wahr-Fall y=x goto. L 2 # Sprung zum Ende der Fallunterscheidung label. L 1 # wahr-Fall y=0 label. L 2 # Ende der Fallunterscheidung
66 Station - Code-Erzeuger Wiederholung übersetzen x=5 while x != 0: x=x-1 #while x=5 label. L 0 if x!=0: goto. L 1 else: goto. L 2 label. L 1 x=x-1 goto. L 0 label. L 2 # Beginn der Schleife # Auswertung der Bedingung # Sprung zum Schleifenkörper # Sprung aus der Schleife # Beginn des Schleifenkörpers # Sprung zum Beginn der schleife # Ende der Schleife
67 Station - Code-Erzeuger class Uebersetzer. While. List(object): def __init__(self): self. quellcode = None Implementierung def set. Quellcode(self, q): self. quellcode = q def uebersetzen(self): def c_programm(p): 'programm : anweisungsfolge' return c_anweisungsfolge(p) def c_anweisungsfolge(p): '''anweisungsfolge : 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 []
68 Station - Code-Erzeuger . . . def c_anweisung(p): Implementierung 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. . .
69 Station - Code-Erzeuger from uebersetzer. While. List import * # Testprogramm quellcode = [ ['=', ('VAR', 'x'), [('ZAHL', '24')]], ['=', ('VAR', 'y'), [('ZAHL', '15')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]], #. . . ] codeerzeuger = Uebersetzer. While. List() # Erzeugung des Zielcodes codeerzeuger. set. Quellcode(quellcode) zielcode = codeerzeuger. uebersetzen() # Ausführung des Programms und Ausgabe der Zustände print('Quellcode: ') print() for zeile in quellcode: print(zeile) print('Zielcode: ') print() for zeile in zielcode: print(zeile)
70 Aufgabe: Probiere das selbst einmal aus. Übersetze verschiedene strukturierte My. While-Programme.
71 Station - Code. Interpreter Zuweisung ausführen [ (None, ['=', ('VAR', 'x'), [('NAT', '24')]]), (None, ['=', ('VAR', 'y'), [('NAT', '15')]]), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), ('. L 3', ['noop']), (None, ['if', ['!=', ('VAR', 'd'), ('NAT', '0')], ['goto', '. L 4'], ['goto', '. L 5']]), ('. L 4', ['noop']), (None, ['if', ['>', ('VAR', 'd'), ('NAT', '0')], ['goto', '. L 0'], ['goto', '. L 1']]), ('. L 0', ['noop']), (None, ['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), (None, ['goto', '. L 2']), ('. L 1', ['noop']), (None, ['=', ('VAR', 'y'), ['-', ('VAR', 'y'), ('VAR', 'x')]]), ('. L 2', ['noop']), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), (None, ['goto', '. L 3']), ('. L 5', ['noop']) ] pc -> 0 pc -> 1 { } Programmzähler Variablenzustand { 'x' -> 1, } Programmzähler Variablenzustand
72 Station - Code. Interpreter Zuweisung ausführen >x=24 y=15 d=x-y label. L 3 if d!=0: goto. L 4 else: goto. L 5 label. L 4 if d>0: goto. L 0 else: goto. L 1 label. L 0 x=x-y goto. L 2 label. L 1 y=y-x label. L 2 d=x-y goto. L 3 label. L 5 { } x=24 >y=15 d=x-y label. L 3 if d!=0: goto. L 4 else: goto. L 5 label. L 4 if d>0: goto. L 0 else: goto. L 1 label. L 0 x=x-y goto. L 2 label. L 1 y=y-x label. L 2 d=x-y goto. L 3 label. L 5 { 'x' -> 24 }
73 Station - Code. Interpreter bedingter Sprung ausführen x=24 y=15 d=x-y label. L 3 >if d!=0: goto. L 4 else: goto. L 5 label. L 4 if d>0: goto. L 0 else: goto. L 1 label. L 0 x=x-y goto. L 2 label. L 1 y=y-x label. L 2 d=x-y goto. L 3 label. L 5 { 'x' -> 24, 'y' -> 15, 'd' -> 9 } x=24 >y=15 d=x-y label. L 3 if d!=0: goto. L 4 else: goto. L 5 >label. L 4 if d>0: goto. L 0 else: goto. L 1 label. L 0 x=x-y goto. L 2 label. L 1 y=y-x label. L 2 d=x-y goto. L 3 label. L 5 { 'x' -> 24, 'y' -> 15, 'd' -> 9 }
74 Station - Code. Interpreter unbedingter Sprung ausführen x=24 y=15 d=x-y label. L 3 if d!=0: goto. L 4 else: goto. L 5 label. L 4 if d>0: goto. L 0 else: goto. L 1 label. L 0 x=x-y >goto. L 2 label. L 1 y=y-x label. L 2 d=x-y goto. L 3 label. L 5 { 'x' -> 9, 'y' -> 15, 'd' -> 9 } x=24 >y=15 d=x-y label. L 3 if d!=0: goto. L 4 else: goto. L 5 label. L 4 if d>0: goto. L 0 else: goto. L 1 label. L 0 x=x-y goto. L 2 label. L 1 y=y-x >label. L 2 d=x-y goto. L 3 label. L 5 { 'x' -> 9, 'y' -> 15, 'd' -> 9 }
Station - Interpreter 75 class Interpreter. Goto(object): . . . def anweisung. Ausfuehren(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. verarbeite. Zuweisung(anweisung) self. pc = self. pc + 1 elif anweisung[0] == "if": if self. verarbeite. Bedingung(anweisung[1]): self. verarbeite. Goto(anweisung[2]) else: self. verarbeite. Goto(anweisung[3]) elif anweisung[0] == "goto": self. verarbeite. Goto(anweisung) elif anweisung[0] == "noop": self. pc = self. pc + 1 elif anweisung[0] == "stop": self. pc = self. pc + 1. . . Implementierung
76 Station - Interpreter from interpreter. Goto import * from variablenzustand import * # Testprogramm = [ (None, ['=', ('VAR', 'x'), [('ZAHL', '24')]]), (None, ['=', ('VAR', 'y'), [('ZAHL', '15')]]), (None, ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]]), ('. L 3', ['noop']), (None, ['if', ['!=', ('VAR', 'd'), ('ZAHL', '0')], ['goto', '. L 4'], ['goto', '. L 5']]), ('. L 4', ['noop']), (None, ['if', ['>', ('VAR', 'd'), ('ZAHL', '0')], ['goto', '. L 0'], ['goto', '. L 1']]), ('. L 0', ['noop']), . . . ] # Erzeugung des Interpreters variablenzustand = Variablenzustand() interpreter. Goto = Interpreter. Goto(variablenzustand) # Initialisierung des Programms interpreter. Goto. init. Programm(programm) # Ausführung des Programms und Ausgabe der Zustände print('Variablenzustand vorher') print(variablenzustand. variablen) print() while interpreter. Goto. get. PC() < len(interpreter. Goto. get. Programm()): interpreter. Goto. anweisung. Ausfuehren() print('Variablenzustand nachher') print(variablenzustand. variablen)
77 Aufgabe: Probiere das selbst einmal aus. Teste verschiedene strukturierte My. Goto-Programme.
78 Station - Simulationsprogramm
- Slides: 78