-
Notifications
You must be signed in to change notification settings - Fork 0
tollhoff/Compilerbau
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Programmieraufgabe
==================
Problemstellung
---------------
Diese Aufgabe dient zur Einfuehrung in
- die Baumdarstellung von Programmen
- die rekursive Bearbeitung solcher Baeume
- den Aufbau von Symboltabellen (Abbildung Name --> Attribute)
und behandelt die Implementierung eines Interpreters fuer die Sprache SLPL.
Die Mini-Programmiersprache SLPL ("Straight-Line Programming Language")
kennt Anweisungen und Ausdruecke. Jede Anweisung bewirkt eine
Zustandsaenderung; jeder Ausdruck repraesentiert einen Wert.
Ein korrektes SLPL-Programm besteht aus genau einer Anweisung.
Im Folgenden steht "ausdruck" fuer einen Ausdruck und "anweisung" fuer
eine Anweisung sowie "Zahl" fuer eine ganze Zahl und "Name" fuer einen
beliebigen Namen.
Die Sprache ist folgendermassen aufgebaut:
1. anweisung --> anweisung ; anweisung ("Folge")
2. anweisung --> Name := ausdruck ("Zuweisung")
3. anweisung --> Zeige(ausdruck) ("Ausgabe")
4. ausdruck --> Zahl ("Literal")
5. ausdruck --> Name ("Variable")
6. ausdruck --> ausdruck + ausdruck ("Summe")
7. ausdruck --> ausdruck - ausdruck ("Differenz")
8. ausdruck --> ausdruck * ausdruck ("Produkt")
9. ausdruck --> ausdruck / ausdruck ("Quotient")
Diese Kurzschreibweise bedeutet folgendes:
1. Das Konstrukt "anweisung1 ; anweisung2" ist eine Anweisung.
Sie bewirkt zuerst die Ausfuehrung von "anweisung1", dann
die Ausfuehrung von "anweisung2".
2. Das Konstrukt "Name := ausdruck" ist eine Anweisung.
Sie bewirkt die Berechnung des Wertes von "ausdruck" und
dann das Speichern dieses Wertes in der Variablen "Name".
3. Das Konstrukt "Zeige(ausdruck)" ist eine Anweisung.
Sie bewirkt die Berechnung des Wertes von "ausdruck" und
dann die Ausgabe dieses Wertes auf dem Bildschirm.
4. "Zahl" ist ein Ausdruck.
Er repraesentiert die Zahl "Zahl".
5. "Name" ist ein Ausdruck.
Er repraesentiert den momentanen Wert der Variablen "Name".
6. Das Konstrukt "ausdruck1 + ausdruck2" ist ein Ausdruck.
Er repraesentiert die Summe aus dem Wert von "ausdruck1"
und dem Wert von "ausdruck2".
7. Genauso wie 6., aber Differenz statt Summe.
8. Genauso wie 6., aber Produkt statt Summe.
9. Genauso wie 6., aber Quotient statt Summe.
Hier ist ein Beispielprogramm in SLPL:
x := 5 + 3 ; Zeige(x) ; y := 7 * x - 2 ; Zeige(y / 2)
Wenn man dieses Programm laufen laesst, erzeugt es folgende Ausgabe:
8 27
Wie sollte man ein solches Programm im Rechner repraesentieren?
Eine Moeglichkeit waere der Quelltext; damit ist aber nicht so
einfach umzugehen. Viel zweckmaessiger ist es, Programme als Baeume
darzustellen. Dazu wird einfach fuer jeden Knoten ein entsprechender
Konstruktor aufgerufen. So wuerde sich z.B. die Folge "Zeige(5) ; Zeige(x)"
darstellen lassen als "Folge(Ausgabe(Literal(5)), Ausgabe(Variable("x")))".
Sie sehen daran, dass jede Anwendung einer der obigen 9 Regeln einem
Aufruf des entsprechenden Knotenkonstruktors entspricht.
Unser kleines Beispielprogramm von oben sieht damit so aus:
Folge(
Zuweisung(
"x",
Summe(
Literal(5),
Literal(3))),
Folge(
Ausgabe(
Variable("x")),
Folge(
Zuweisung(
"y",
Differenz(
Produkt(
Literal(7),
Variable("x")),
Literal(2))),
Ausgabe(
Quotient(
Variable("y"),
Literal(2))))))
Die automatische Umwandlung vom Quelltext in die Baumdarstellung ist
Gegenstand der ersten Haelfte der Compilerbauvorlesung und wird hier
NICHT behandelt. Stattdessen geben wir unsere kleinen SLPL-Programme
direkt in der Baumkonstruktor-Darstellung (und damit als C-Programm)
an.
Vorgegebene Dateien
-------------------
README - die Beschreibung, die Sie gerade lesen
Makefile - ein Makefile zur automatischen Uebersetzung
common.h - haeufig gebrauchte Definitionen
utils.c - haeufig gebrauchte Hilfsfunktionen
utils.h - Interface zu utils.c
slpl.c - die Knotenkonstruktoren
slpl.h - Interface zu slpl.c
prog.c - unser Beispielprogramm
prog.h - Interface zu prog.c
main.c - das Hauptprogramm: hier muessen Sie taetig werden!
table.c - die Symboltabelle: hier muessen Sie taetig werden!
table.h - Interface zu table.c
Aufgaben
--------
1. Machen Sie sich mit den vorgegebenen Dateien vertraut.
Sie muessen deren Inhalte verstehen!
2. Schreiben Sie eine rekursive Funktion void zeigeBaum(Knoten *baum);
die eine lesbare Darstellung des gesamtem an "baum" haengenden Baums
erzeugt. Das Ergebnis kann dann z.B. so aehnlich wie der oben gezeigte
Quelltext aussehen.
3. Schreiben Sie eine rekursive Funktion void interpretiere(Knoten *baum);
die das an "baum" haengende Programm interpretiert. Sie konstruieren
dazu am besten zwei Hilfsfunktionen, je eine fuer Anweisungen und eine
fuer Ausdruecke:
Tabelle *interpretAnweisung(Knoten *baum, Tabelle *tabelle);
int interpretAusdruck(Knoten *baum, Tabelle *tabelle);
"baum" ist das zu interpretierende (Teil-)Programm,
"tabelle" ist eine Tabelle der zu diesem Zeitpunkt bekannten
Variablen und ihrer Werte.
Ergaenzen Sie zu diesem Zweck zunaechst die nicht ausprogrammierten
Funktionen im Tabellen-Modul. Vorschlag: Verwenden Sie eine lineare
Liste von Tabelleneintraegen (auch wenn das nicht besonders effizient
ist).
Bei der Interpretation eines Programms wird jedesmal bei einer Zuweisung
die Tabelle auf den neuesten Stand gebracht und die geaenderte Tabelle
zurueckgegeben; jedesmal bei der Benutzung einer Variablen wird ihr Wert
in der momentan gueltigen Tabelle aufgesucht.
Ihr Interpreter sollte eine Fehlermeldung ausgeben, falls der Wert einer
nichtinitialisierten Variablen gebraucht wird.
About
No description, website, or topics provided.
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published