Compiler und Interpreter
Klaus Becker
2010
2 Compiler und Interpreter
3 Teil 1
Syntax und Semantik im Überblick
4 Karol / Myka
Karol
MyKa(rol)
5 Aufgabe
Versuche anhand weiterer Tests die Regeln der Sprache MyKa herauszufinden:
(a) Wie können Programme der Sprache aufgebaut werden?
linkswhile nichtVorWand: ziegelHinlegen schritt#while
if nichtVorWand: if nichtVorZiegel: schritt schritt schritt schritt else: ziegelHinlegen #ifelse: links#if
markeSetzenschrittwhile nichtAufMarke: while nichtVorWand: schritt #while links#while
6 Aufgabe
Versuche anhand weiterer Tests die Regeln der Sprache MyKa herauszufinden:
(b) Welche Bedeutung haben die Sprachkonstrukte?
linkswhile nichtVorWand: ziegelHinlegen schritt#while
if nichtVorWand: if nichtVorZiegel: schritt schritt schritt schritt else: ziegelHinlegen #ifelse: links#if
markeSetzenschrittwhile nichtAufMarke: while nichtVorWand: schritt #while links#while
7 Exkurs - MyKalinkswhile nichtVorWand: ziegelHinlegen schritt#while
if nichtVorWand: if nichtVorZiegel: schritt schritt schritt schritt else: ziegelHinlegen #ifelse: links#if
markeSetzenschrittwhile 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 Exkurs - MyKalinkswhile nichtVorWand: ziegelHinlegen schritt#while
if nichtVorWand: if nichtVorZiegel: schritt schritt schritt schritt else: ziegelHinlegen #ifelse: links#if
markeSetzenschrittwhile 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 Exkurs - MyKalinkswhile nichtVorWand: ziegelHinlegen schritt#while
if nichtVorWand: if nichtVorZiegel: schritt schritt schritt schritt else: ziegelHinlegen #ifelse: links#if
markeSetzenschrittwhile 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 Exkurs - MyKalinkswhile nichtVorWand: ziegelHinlegen schritt#while
if nichtVorWand: if nichtVorZiegel: schritt schritt schritt schritt else: ziegelHinlegen #ifelse: links#if
markeSetzenschrittwhile 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 Fachkonzept - Syntax
Die Syntax einer Sprache beschreibt, welche Kombinationen von Zeichen fehlerfreie Programme der Sprache bilden.
myka_syn = {Programm1, Programm2, ...}
Programmx
linkswhile nichtVorWand: ziegelHinlegen schritt#while
if nichtVorWand: if nichtVorZiegel: schritt schritt schritt schritt else: ziegelHinlegen #ifelse: links#if
markeSetzenschrittwhile nichtAufMarke: while nichtVorWand: schritt #while links#while
Eine Präzisierung dieser Menge kann z.B. mit Hilfe einer Grammatik vorgenommen werden.
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
14 Myka
syntaktisch korrektes Programm Programm
mit Syntaxfehler
Struktur-darstellung
d. Programms
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 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.
linkswhile 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 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 die von den Grammatikregeln verlangte syntaktische Struktur widerspiegelt.
19 Teil 3
Interpreter und Compiler im Überblick
20 Myka
Ausführung von
MyKaList-Programmen
Übersetzen von
MyKaList-Programmen
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 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 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 Exkurs - MyKaGotolinkswhile nichtVorWand: ziegelHinlegen schritt#while
linkslabel .L0if nichtVorWand: goto .L1else: goto .L2label .L1ziegelHinlegenschrittgoto .L0label .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 Kontrollstruktur
en
benutzt Sprungbefehle
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 Fachkonzept - Compiler
Ein Compiler (im weiteren Sinn) ist ein System, das aus Scanner, Parser, Codererzeuger und Codeoptimierer besteht.
linkswhile 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 Teil 4
Entwicklung eines Compilers - MyWhile
28 Station - MyWhile
x = 24y = 15d = x - ywhile 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 Station - MyWhileelem. 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 = 24y = 15d = x - ywhile 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 Station - MyWhilex = 24y = 15d = x - ywhile 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 Aufgabe
x=24 y=15 d=x-ywhile d != 0 : if d > 0 :x = x - yelse: y=y-x#ifd=x-y#while
Ist das folgende Programm ein syntaktisch korrektes MyWhile-Programm?
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 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 = 24y = 15d = x - ywhile 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 Station - Scanner# Beschreibung der Tokent_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 Aufgabe# Beschreibung der Tokent_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 Station - Scanner# reservierte Wörterreserved = { 'if' : 'IF', 'else' : 'ELSE', 'while' : 'WHILE', 'pass': 'PASS'}
# Namen der Tokentokens = ['VAR', 'ZAHL', 'NULL', 'ZUW', 'PLUS', 'MINUS', 'GL', 'UG', 'GR', 'KL', 'DP', 'ENDWH', 'ENDIF']tokens = tokens + list(reserved.values())
# Beschreibung der Tokendef t_VAR(t): r'[a-z][a-z0-9]*' t.type = reserved.get(t.value, 'VAR') # Überprüfung auf reservierte Wörter return tt_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 Station - Scannerimport ply.lex as lexfrom syntaxWhile import *# Testprogrammprogramm = '''x = 24y = 15d = x - ywhile d != 0: if d > 0: x = x - y else: y = y - x #if d = x - y#while'''
# Erzeugung des Scannersscanner = lex.lex(debug=0)
# lexikalische Analyse mit Erzeugung der Tokenscanner.input(programm)token = []tok = scanner.token()while tok: token = token + [tok] tok = scanner.token()
# Ausgabefor 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 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 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 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 Station - Parser / Syntaxanalyse
x = 24y = 15d = x - ywhile 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 ZAHLVAR ZUW ZAHLVAR ZUW VAR MINUS VARWHILE 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 VARENDWH
# Produktionen
anweisungsfolge -> anweisung anweisungsfolgeanweisungsfolge -> anweisunganweisung -> zuweisunganweisung -> PASSanweisung -> WHILE bedingung DP anweisungsfolge ENDWHanweisung -> IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIFzuweisung -> VAR ZUW termterm -> VAR op zahlterm -> VAR op VARterm -> zahlterm -> VARzahl -> NULLzahl -> ZAHLop -> PLUSop -> MINUSbedingung -> VAR rel NULLrel -> GLrel -> UGrel -> GRrel -> KL
Grammatik von MyWhile
42 Aufgabe
x = 4while 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 ZAHLWHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHLENDWH
# Produktionen
anweisungsfolge -> anweisung anweisungsfolgeanweisungsfolge -> anweisunganweisung -> zuweisunganweisung -> PASSanweisung -> WHILE bedingung DP anweisungsfolge ENDWHanweisung -> IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIFzuweisung -> VAR ZUW termterm -> VAR op zahlterm -> VAR op VARterm -> zahlterm -> VARzahl -> NULLzahl -> ZAHLop -> PLUSop -> MINUSbedingung -> VAR rel NULLrel -> GLrel -> UGrel -> GRrel -> KL
Grammatik von MyWhile
43 Station - Parser / Syntaxanalysedef p_anweisungsfolge_anweisung_anweisungsfolge(p): 'anweisungsfolge : anweisung anweisungsfolge' p[0] = Nonedef p_anweisungsfolge_anweisung(p): 'anweisungsfolge : anweisung' p[0] = Nonedef p_anweisung_zuw(p): 'anweisung : zuweisung' p[0] = Nonedef p_anweisung_pass(p): 'anweisung : PASS' p[0] = Nonedef p_anweisung_wh(p): 'anweisung : WHILE bedingung DP anweisungsfolge ENDWH' p[0] = Nonedef p_anweisung_if(p): 'anweisung : IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIF' p[0] = Nonedef p_zuweisung(p): 'zuweisung : VAR ZUW term' p[0] = Nonedef p_term_var_op_zahl(p): 'term : VAR op zahl' p[0] = Nonedef p_term_var_op_var(p): 'term : VAR op VAR' p[0] = Nonedef p_term_zahl(p): 'term : zahl' p[0] = None...
YACC-Implementierung
anweisungsfolge -> anweisung anweisungsfolgeanweisungsfolge -> anweisunganweisung -> zuweisunganweisung -> PASSanweisung -> WHILE bedingung DP anweisungsfolge ENDWHanweisung -> IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIFzuweisung -> VAR ZUW termterm -> VAR op ZAHLterm -> VAR op VARterm -> zahl...
44 Station - Parser / Syntaxanalyseimport ply.lex as leximport ply.yacc as yaccfrom syntaxWhile import *
# Testprogrammprogramm = '''x = 24y = 15d = x - ywhile d != 0: if d > 0: x = x - y else: y = y - x #if d = x - y#while'''
# Erzeugung des Scannersscanner = lex.lex(debug=0)# Erzeugung des Parsersparser = yacc.yacc(debug=False)
# syntaktische Analyse parser.parse(programm, debug=0)
# Ausgabeprint("ok!")
>>> ok!
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 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 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 Station - Parser / Strukturgerüst
Idee: Die Grammatikregeln werden um Beschreibungen zur Erzeugung des Strukturgerüsts erweitert.
# Produktionen
anweisungsfolge -> anweisung anweisungsfolgeanweisungsfolge -> anweisunganweisung -> zuweisunganweisung -> PASSanweisung -> WHILE bedingung DP anweisungsfolge ENDWHanweisung -> IF bedingung DP anweisungsfolge ELSE DP anweisungsfolge ENDIFzuweisung -> VAR ZUW termterm -> VAR op zahlterm -> VAR op VARterm -> zahlterm -> VARzahl -> NULLzahl -> ZAHLop -> PLUSop -> MINUSbedingung -> VAR rel NULLrel -> GLrel -> UGrel -> GRrel -> 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
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 -> zuweisungzuweisung WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH -> # zuweisung -> VAR ZUW termVAR ZUW term WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH -> # term -> zahlVAR ZUW zahl WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH -> # zahl -> ZAHLVAR ZUW ZAHL WHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHL ENDWH
Station - Parser / Strukturgerüst
x = 4while x > 0: x = x - 1#while
VAR ZUW ZAHLWHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHLENDWH
Rechtsableitung der Tokenfolge
Quelltext
Tokenfolge
Grammatikregeln
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 = 4while x > 0: x = x - 1#while
VAR ZUW ZAHLWHILE VAR GR NULL DP VAR ZUW VAR MINUS ZAHLENDWH
[ ['=', ('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 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 Station - Parser / Strukturgerüstimport ply.lex as leximport ply.yacc as yaccfrom syntaxWhile import *
# Testprogrammprogramm = '''x = 4while x > 0: x = x - 1#while'''
# Erzeugung des Scannersscanner = lex.lex(debug=0)# Erzeugung des Parsersparser = yacc.yacc(debug=False)
# syntaktische Analyse mit Erzeugung des Strukturbaumsif len(programm) != 0: strukturbaum = parser.parse(programm, debug=0)else: strukturbaum = []
# Ausgabeprint(strukturbaum)
>>> [['=', ('VAR', 'x'), [('ZAHL', '4')]], ['while', ['>', ('VAR', 'x'), ('ZAHL', '0')], [['=', ('VAR', 'x'), ['-', ('VAR', 'x'), ('ZAHL', '1')]]]]]
53 Aufgabe
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 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 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 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 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 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 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}
[]
{'x' -> 3, 'y' -> 3, 'd' -> 0}
Wiederholung ausführen
Bedingung
False
60 Station - Interpreterclass 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 Station - Interpreterfrom variablenzustand import *
# Testprogrammprogramm = [ ['=', ('VAR', 'x'), [('ZAHL', '24')]], ['=', ('VAR', 'y'), [('ZAHL', '15')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]], #...]
# Erzeugung des Interpretersvariablenzustand = Variablenzustand()interpreter = InterpreterWhileList(variablenzustand)# Initialisierung des Programmsinterpreter.setProgramm(programm)
# Ausführung des Programms und Ausgabe der Zuständeprint('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 Aufgabe
Aufgabe:
Probiere das selbst einmal aus. Teste verschiedene strukturierte MyWhile-Programme.
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')]] ] ]]
Quellcode Zielcode
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')]] ] ]]
Quellcode Zielcode
x = 24y = 15d = x - ywhile d != 0: if d > 0: x = x - y else: y = y - x #if d = x - y#while
x=24y=15d=x-ylabel .L3if d!=0: goto .L4else: goto .L5label .L4if d>0: goto .L0else: goto .L1label .L0x=x-ygoto .L2label .L1y=y-xlabel .L2d=x-ygoto .L3label .L5
65 Station - Code-Erzeuger
x = 1if x1 != 0: y = xelse: y = 0#if
x=1if x1!=0: # Auswertung der Bedingung goto .L0 # Sprung zum wahr-Fallelse: goto .L1 # Sprung zum falsch-Falllabel .L0 # wahr-Fally=xgoto .L2 # Sprung zum Ende der Fallunterscheidunglabel .L1 # wahr-Fally=0label .L2 # Ende der Fallunterscheidung
Fallunterscheidung übersetzen
66 Station - Code-Erzeuger
x = 5while x != 0: x = x - 1#while
x=5label .L0 # Beginn der Schleifeif x!=0: # Auswertung der Bedingung goto .L1 # Sprung zum Schleifenkörperelse: goto .L2 # Sprung aus der Schleifelabel .L1 # Beginn des Schleifenkörpersx=x-1goto .L0 # Sprung zum Beginn der schleifelabel .L2 # Ende der Schleife
Wiederholung übersetzen
67 Station - Code-Erzeugerclass 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 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 Station - Code-Erzeugerfrom uebersetzerWhileList import *
# Testprogrammquellcode = [ ['=', ('VAR', 'x'), [('ZAHL', '24')]], ['=', ('VAR', 'y'), [('ZAHL', '15')]], ['=', ('VAR', 'd'), ['-', ('VAR', 'x'), ('VAR', 'y')]], # ...]codeerzeuger = UebersetzerWhileList()# Erzeugung des Zielcodescodeerzeuger.setQuellcode(quellcode)zielcode = codeerzeuger.uebersetzen()# Ausführung des Programms und Ausgabe der Zuständeprint('Quellcode:')print()for zeile in quellcode: print(zeile)print()print('Zielcode:')print()for zeile in zielcode: print(zeile)
70 Aufgabe
Aufgabe:
Probiere das selbst einmal aus. Übersetze verschiedene strukturierte MyWhile-Programme.
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 Station - CodeInterpreter
>x=24y=15d=x-ylabel .L3if d!=0: goto .L4else: goto .L5label .L4if d>0: goto .L0else: goto .L1label .L0x=x-ygoto .L2label .L1y=y-xlabel .L2d=x-ygoto .L3label .L5
{}
Zuweisung ausführen
x=24>y=15d=x-ylabel .L3if d!=0: goto .L4else: goto .L5label .L4if d>0: goto .L0else: goto .L1label .L0x=x-ygoto .L2label .L1y=y-xlabel .L2d=x-ygoto .L3label .L5
{'x' -> 24}
73 Station - CodeInterpreter
x=24y=15d=x-ylabel .L3>if d!=0: goto .L4else: goto .L5label .L4if d>0: goto .L0else: goto .L1label .L0x=x-ygoto .L2label .L1y=y-xlabel .L2d=x-ygoto .L3label .L5
{'x' -> 24, 'y' -> 15, 'd' -> 9}
bedingter Sprung ausführen
x=24>y=15d=x-ylabel .L3if d!=0: goto .L4else: goto .L5>label .L4if d>0: goto .L0else: goto .L1label .L0x=x-ygoto .L2label .L1y=y-xlabel .L2d=x-ygoto .L3label .L5
{'x' -> 24, 'y' -> 15, 'd' -> 9}
74 Station - CodeInterpreter
x=24y=15d=x-ylabel .L3if d!=0: goto .L4else: goto .L5label .L4if d>0: goto .L0else: goto .L1label .L0x=x-y>goto .L2label .L1y=y-xlabel .L2d=x-ygoto .L3label .L5
{'x' -> 9, 'y' -> 15, 'd' -> 9}
unbedingter Sprung ausführen
x=24>y=15d=x-ylabel .L3if d!=0: goto .L4else: goto .L5label .L4if d>0: goto .L0else: goto .L1label .L0x=x-ygoto .L2label .L1y=y-x>label .L2d=x-ygoto .L3label .L5
{'x' -> 9, 'y' -> 15, 'd' -> 9}
75 Station - Interpreterclass 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 + 1
...
Implementierung
76 Station - Interpreterfrom interpreterGoto import *from variablenzustand import *
# Testprogrammprogramm = [(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 Interpretersvariablenzustand = Variablenzustand()interpreterGoto = InterpreterGoto(variablenzustand)# Initialisierung des ProgrammsinterpreterGoto.initProgramm(programm)
# Ausführung des Programms und Ausgabe der Zuständeprint('Variablenzustand vorher')print(variablenzustand.variablen)print()while interpreterGoto.getPC() < len(interpreterGoto.getProgramm()): interpreterGoto.anweisungAusfuehren()print('Variablenzustand nachher')print(variablenzustand.variablen)
77 Aufgabe
Aufgabe:
Probiere das selbst einmal aus. Teste verschiedene strukturierte MyGoto-Programme.
78 Station - Simulationsprogramm