compiler und interpreter klaus becker 2010. 2 compiler und interpreter

78
Compiler und Interpreter Klaus Becker 2010

Upload: adalwulf-streck

Post on 05-Apr-2015

125 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

Compiler und Interpreter

Klaus Becker

2010

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

2 Compiler und Interpreter

Page 3: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

3 Teil 1

Syntax und Semantik im Überblick

Page 4: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

4 Karol / Myka

Karol

MyKa(rol)

Page 5: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 6: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 7: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 8: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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?

Page 9: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 10: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 11: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 12: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 13: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

13 Teil 2

Scanner und Parser im Überblick

Page 14: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

14 Myka

syntaktisch korrektes Programm Programm

mit Syntaxfehler

Struktur-darstellung

d. Programms

Page 15: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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?

Page 16: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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']]]]

Page 17: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 18: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 19: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

19 Teil 3

Interpreter und Compiler im Überblick

Page 20: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

20 Myka

Ausführung von

MyKaList-Programmen

Übersetzen von

MyKaList-Programmen

Page 21: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 22: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 23: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 24: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 25: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 26: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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'])]

Page 27: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

27 Teil 4

Entwicklung eines Compilers - MyWhile

Page 28: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 29: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 30: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 31: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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?

Page 32: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 33: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 34: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 35: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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?

Page 36: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 37: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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)...

Page 38: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 39: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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;};

Page 40: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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,':')...

Page 41: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 42: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 43: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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...

Page 44: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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!

Page 45: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 46: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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;};

Page 47: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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,':')...

Page 48: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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]

Page 49: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 50: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 51: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 52: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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')]]]]]

Page 53: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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.

Page 54: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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;};

Page 55: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 56: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 57: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 58: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 59: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 60: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 61: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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('---------------------------')

Page 62: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

62 Aufgabe

Aufgabe:

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

Page 63: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 64: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 65: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 66: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 67: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 68: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 69: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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)

Page 70: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

70 Aufgabe

Aufgabe:

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

Page 71: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 72: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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}

Page 73: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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}

Page 74: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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}

Page 75: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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

Page 76: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

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)

Page 77: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

77 Aufgabe

Aufgabe:

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

Page 78: Compiler und Interpreter Klaus Becker 2010. 2 Compiler und Interpreter

78 Station - Simulationsprogramm