Software Paradigmen 2007

Größe: px
Ab Seite anzeigen:

Download "Software Paradigmen 2007"

Transkript

1 Software Paradigmen 2007

2 Software-Paradigmen Skriptum zur Lehrveranstaltung (SS 2007) PROF. DR. FRANZ WOTAWA Technische Universität Graz, Institut für Softwaretechnologie A-8010 Graz, Inffeldgasse 16b/2, Austria Tel.: +43 (0) Fax: +43 (0) Seite 1

3 Vorwort Die Kenntnis von Syntax und Semantik von Programmiersprachen ist für Informatikerinnen und Informatiker von großer Wichtigkeit. Das Schreiben von Programmen, die einerseits korrekt hinsichtlich der Kompilierung und andererseits ebenfalls korrekt in Bezug auf deren Ausführung sind, ist eine Fertigkeit, die Sie im Rahmen Ihres Studiums erlernt haben und in der Praxis auch anwenden müssen. In der Lehrveranstaltung Software Paradigmen beschäftigen wir uns mit der Fragestellung wie die Kompilierung von Programmen erfolgen kann und wie man Bedeutungen zu Programmfragmenten wie zum Beispiel Ausdrücken und einfachen Befehlen definieren kann. Gerade die Fragestellung der Bedeutung von Sprachausdrücken ist eine sehr wichtige. Betrachten wir zum Beispiel folgendes Bedingung (x++ == x++)und überlegen wir uns welches Resultat bei der Ausführung dieser Bedingung herauskommen sollte. Rein mathematisch gesehen befinden sich auf der linken und rechten Seite des Vergleichs die selben Ausdrücke. Also erscheint die Ausgabe von TRUE hier sicherlich angemessen. Allerdings wird durch den ++ Operator der Wert von x geändert. Somit sollten die Werte doch unterschiedlich sein und wir können genau so gut FALSE als Ergebnis zurückliefern. In der Tat tritt dieses Problem auch in der Praxis auf. So evaluiert der Ausdruck in der Programmiersprache Java zu FALSE und in C++ zu TRUE. Eine exakte Definition der Semantik einer Programmiersprache hilft hier Aussagen zu treffen und ermöglicht es somit unterschiedliche Interpretationen zu vermeiden. Seite 2

4 Inhaltsverzeichnis Einleitung 4 Teil 1 Syntax 6 Syntaxanalyse von Programmiersprachen 6 Grammatiken und Sprachen 7 Compilerbau 18 Lexikalische Analyse 21 Grammatikalische Analyse 27 Teil 2 - Semantik von Programmiersprachen 40 Funktionale Programmiersprachen 42 Einfache Arithmetische Ausdrücke 43 Einfache Sprachen mit Variablen 46 Datentypen 47 Sprache der Terme T 51 Sprache der Konditionale COND 55 Rekursive Programme 56 Der Datentyp der Listen 63 Erweiterungen von Datentypen 67 Ein Interpreter für EXP in EXP(L) 70 Codierung von EXP in L 72 Der Interpreter IX 73 Das Halteproblem 78 Prädikatenlogische Ausdrücke 80 Assignmentsprachen 84 Logische Programmierung 89 Schlussfolgerungen in der Aussagenlogik 96 Die Sprache LP 101 Zusammenfassung 108 Seite 3

5 Einleitung Die Lehrveranstaltung Software Paradigmen verfolgt 2 Lehrziele. Zum einen soll ein Grundverständnis der Funktionsweise von Compiler vermittelt werden. Zum anderen wollen wir uns mit grundlegenden Konzepten von Programmiersprachen beschäftigen. Der Compilerbau ist eine verhältnismäßig alte Disziplin der Informatik. Er beschäftigt sich mit dem Entwurf und der Implementierung von Programmen, die eine Programmiersprache in eine andere Programmiersprache umwandeln. Compiler findet man in der Praxis sehr häufig. So muss zum Beispiel ein Web-Browser HTML-Code in eine darstellbare Form konvertieren. Zu diesem Zweck muss der Web-Browser HTML- Code lesen können. Andere Beispiele sind Programme, die Eingabewerte analysieren und entsprechend verarbeiten müssen. Solche Programme müssen erkennen ob ein Eingabewert ein String oder eine Zahl darstellt um diese dann entsprechend in ein internes Format zu konvertieren. Konzepte von Programmiersprachen, wie wir sie in der Lehrveranstaltung behandeln, beschreiben das Verhalten von Programmen. Dabei werden wir zwischen funktionalen, imperativen und logik-orientierten Verhalten unterscheiden. Diese 3 Programmiersprachenparadigmen bilden die Grundlage von fast allen Programmiersprachen. Eine grundlegende Kenntnis der Paradigmen hilft neue Programmiersprachen schnell zu verstehen beziehungsweise Programmiersprachen selber zu entwerfen. Ein weiterer Aspekt bei der Beschreibung von Konzepten von Programmiersprachen ist das Erlernen von Methoden zur Verhaltensbeschreibung. Zu wissen, wie sich Programmiersprachen verhalten und wie man die dazu notwendigen Definition erstellt ist ebenfalls notwendig um Compiler zu schreiben, da jede Programmiersprache aus 2 Teilen besteht: der Syntax und der Semantik. Die Syntax von Programmiersprachen beschreibt grob gesagt, das Aussehen der Sprache. Welche Wörter dürfen in der Sprache vorkommen? In welcher Reihenfolge müssen diese Wörter vorkommen? Diese Fragen werden in der Definition der Syntax einer Sprache behandelt. In der Lehrveranstaltung werden wir den Begriff der Seite 4

6 Grammatik einführen, um die Syntax von Sprachen zu definieren. Wir werden sehen, dass wir Grammatiken vergleichen und entsprechend klassifizieren können. Die Semantik einer Programmiersprache legt das Verhalten der Sprache fest. Was passiert, wenn ein Programm mit Hilfe der Verwendung von Eingabewerten ausgeführt wird? Wie werden Ausgangswerte berechnet? Solche Fragen stellt man sich bei der Beschreibung des Verhaltens. In der Lehrveranstaltung werden wir uns dabei auf die Ausführungssemantik von Programmiersprachen beschränken. Diese Semantik hilft geeignete Laufzeitsysteme zur Verfügung zu stellen, in denen Programme ausgeführt werden können. Bei herkömmlichen Computern ist das Laufzeitsystem der Mikroprozessor (gemeinsam mit seiner Peripherie). Ein Compiler wandelt in diesem Fall ein Programm, das in einer bestimmten Sprache geschrieben wurde, in eine für den Mikroprozessor verständliche Form um. Seite 5

7 Teil 1 Syntax Die folgenden Unterkapitel, die sich mit der Syntaxanalyse beschäftigen sind teilweise folgenden Büchern entnommen. Diese Bücher behandeln die Thematik Compilerbau ausführlich. [1] Alfred V. Aho, Ravi Sethi, and Jeffrey D. Ullman, Compilers - Principles, Techniques, and Tools, Addison-Wesley, 1986, ISBN [2] Jean-Paul Tremblay and Paul G. Sorenson, The Theory and Practice of Compiler Writing, McGraw-Hill, 1985, ISBN Syntaxanalyse von Programmiersprachen Um die syntaktische Korrektheit von Programmen, die in einer Programmiersprache geschrieben wurden, zu überprüfen werden Compiler verwendet. Compiler sind Programme, die Programme, die in einer Programmiersprache A geschrieben wurden, in Programme der Programmiersprache B umwandeln. Da Compiler selber ebenfalls in einer Sprache verfasst wurden, ist es möglich einen Compiler zu schreiben, der sich selber in eine andere Programmiersprache übersetzt. Um dies zu machen, benötigt man jedoch eine Laufzeitumgebung, in der der Compiler selber ausgeführt werden kann. Wie bereits erwähnt, findet man Compiler in fast allen Applikationen. Je nach Anwendungsgebiet sind diese jedoch mehr oder weniger komplex aufgebaut. Trotz dieser Unterschiede gibt es Grundbestandteile von Compilern, die in vielen Bereichen wichtig sind und verwendet werden. Natürlich macht es in Applikationen mit eingeschränktem Umfang keinen Sinn, einen vollständigen Compiler mit all seinen Bestandteilen zu verwenden. Eine Kenntnis der Teile hilft jedoch, eine entsprechende Auswahl zu treffen und auch zu argumentieren. Im Prinzip besteht ein Compiler aus 2 Teilen, die wiederum in Unterteile zerlegt werden können. Diese 2 Teile sind die Analyse- und die Synthese-Phase. In der Analyse wird der Compiler-Input, d.h. ein Programm beziehungsweise ein Text hinsichtlich der grammatikalischen Korrektheit überprüft und in Einzelteile zerlegt. Die Einzelteile Seite 6

8 werden dann in der Synthese-Phase hergenommen und in ihre neue Form übergeführt. Diesen Prozess kann man sich ähnlich wie bei der Übersetzung von einer Sprache (z.b. Deutsch) in eine andere Sprache (z.b. Englisch) vorstellen. In vielen Anwendungsgebieten ist die Synthese-Phase nicht vorhanden beziehungsweise sehr einfach gehalten. Um die grammatikalische Korrektheit in der Analyse-Phase zu überprüfen, brauchen wir Methoden, die uns helfen, die Grammatik einer Sprache zu definieren und Techniken, die uns erlauben zu überprüfen, ob ein gegebenes Wort Element der Sprache ist. Dies ist analog zur Überprüfung, ob ein Wort in einer natürlichen Sprache ist. Zum Beispiel ist das Wort Sprache Element der deutschen Sprache, das Wort Sprachf jedoch nicht. Ebenfalls kein deutscher Satz ist Kunst der ihre Freiheit. obwohl jedes einzelne Wort Element der Sprache ist. Die formale Definition von Grammatik und Sprache wird im nächsten Teilkapitel eingeführt. Grammatiken und Sprachen Grammatiken beschreiben Sprachen. Im Speziellen werden durch Grammatiken mögliche Wörter, sowie deren Sätze festgelegt. Dabei geht man natürlich nicht so vor, dass man alle möglichen Sätze einer Sprache niederschreibt. Man wird versuchen, Regeln aufzustellen, wie aus Wörtern Sätze aufgebaut sind. Somit kann man mit einer endlichen Anzahl von Wörtern und Regeln eine unendliche Anzahl von möglichen Sätzen bilden. Betrachten wir zum Beispiel die Sprache der binären Zahlen. Jede Binärzahl besteht nur aus 0 oder 1 in beliebiger Reihenfolge. In Analogie zu dem bereits erwähnten, repräsentieren die Zahlen 0 und 1 Wörter und Binärzahlen Sätze. Um Regeln aufzustellen, die es uns erlauben, Sätze zu beschreiben, brauchen wir Variablen. Regeln definieren wir als Umwandlungsregeln, die uns erlauben Variablen beziehungsweise Wörter durch andere Variablen beziehungsweise Wörter auszutauschen. Somit können wir von einer Startvariablen mögliche Sätze ableiten. In der folgenden Definition Seite 7

9 verwenden wir nun nicht die Begriffe Wörter und Sätze sondern Terminale (Terminalsymbole) und Nonterminale (Nonterminalsymbole). Definition: Eine Grammatik ist ein 4-Tupel (V N, V T, S,Φ) mit: 1. V N... endliche Menge von Nonterminalen 2. V T... endliche Menge von Terminalen 3. S V N... Startsymbol 4. Φ={ β α α (V N V T )* V N (V N V T )*, β (V N V T )* }... endliche Menge von Produktionsregeln Anmerkung: In der Grammatikdefinition wird der Operator * für Mengen verwendet. Dabei bedeutet *, dass ein Element der Menge beliebig oft ausgewählt wird. Dies kann auch 0-mal der Fall sein. Zum Beispiel führt {a,b}* zu einer beliebigen Sequenz von a s und b s (a,ab,ba,..) beziehungsweise zur leeren Sequenz, die durch ε gekennzeichnet wird. Ausgehend von der Grammatikdefinition können wir nun einfach eine Grammatik zur Beschreibung von Binärzahlen anfertigen. Wir verwenden dabei als Startsymbol B und als Terminale (=Wörter) die Symbole 0 und 1. Die Grammatik hat nun folgendes Aussehen: G BIN =({B},{0,1},B,{B 0B, B 1B, B ε}) Die Idee hinter den Produktionsregeln ist es, die linke Seite durch die rechte Seite zu ersetzen. Das heißt, wenn in einem Wort die linke Seite einer Regel als Teil vorkommt, kann dieses Vorkommnis durch die rechte Seite der Regel ersetzt werden. Durch Anwendung dieser Ersetzungsregel kommt man dann vom Startsymbol zu einem Satz, der durch die Grammatik gegeben ist. Die folgende Definition führt dazu den Begriff der Ableitung ein. Seite 8

10 Definition: Sei (V N, V T, S,Φ) eine Grammatik und α,β (V N V T )*. β kann direkt (in einem Schritt) von α abgeleitet werden (α β), wenn es 2 Strings τ und ω gibt, so dass α = τ A ω, β = τ B ω und A B Φ. Aus G BIN und dem Startsymbol B können wir somit direkt 0B ableiten. Es gilt also B 0B. Durch wiederholte Anwendung der Ableitung kommen wir zur Ableitung in n- Schritten laut folgender Definition. Definition: Sei (V N, V T, S,Φ) eine Grammatik. β kann von α (in n-schritten) abgeleitet werden(α + β ), wenn es n Strings ω 1,.., ω n gibt, so dass α ω 1, ω 1 ω 2,..., ω n-1 ω n, ω n β In 2 Schritten können wir zum Beispiel 0, 1 aber auch 00B, 01B, 10B, und 11B aus B in G BIN ableiten. Da die Definition der 1-Schritt- beziehungsweise n-schritt-ableitung nicht den Fall zulässt, dass die Ableitung auch in 0-Schritten erfolgen kann, führen wir nun folgende Definition ein. Definition: α * β, dann und nur dann wenn α + β oder α=β (Reflexive, Transitive Hülle) Diese Definition deckt nun alle Fälle der Ableitung ab. Mit Hilfe der Definition der Ableitung können wir nun ausgehend vom Startsymbol beliebige Ausdrücke ableiten. Manche von diesen Ausdrücken enthalten Nonterminale, andere enthalten nur noch Terminalsymbole. Betrachten wir nun wieder die Analogie zur natürlichen Sprache. Sätze bestehen dort nur aus Terminalen (=Wörter). Somit definieren wir als Sprache, die durch eine Grammatik spezifiziert wird, eine Menge von Sätzen, die nur aus Terminalsymbolen bestehen. Die folgende Definition trägt diesen Gedanken Rechnung. Definition: Sei (V N, V T, S,Φ) eine Grammatik G. G akzeptiert folgende Sprache L(G) = { ω S * ω, ωv T * } Seite 9

11 Die Sprache aller Binärzahlen ist somit gegeben durch L(G BIN )={ε,0,1,00,01,10,11, }. Die Sprache enthält unendlich viele Sätze und wird durch eine endliche Anzahl von Bestimmungsstücken definiert. Die bisherigen Definitionen gehen von einer Grammatik aus und zeigen, wie Sprachen aus der Grammatik folgen, beziehungsweise wie Sätze aus der Grammatik abgeleitet werden können. Die Aufgabe eines Compilers ist es jedoch zu überprüfen, ob ein gegebener Satz in der Sprache ist, die durch eine bestimmte Grammatik gegeben ist. Das heißt, ein Compiler sucht nach einer Ableitungsreihenfolge die vom Startsymbol zum gegebenen Satz führt. Bevor wir uns dieser Problematik annehmen, untersuchen wir die Ausdrucksstärke von Grammatikdefinitionen. Die Frage, die hinter der Analyse der Ausdrucksstärke liegt, ist ob die Grammatikdefinition Auswirkungen auf die möglichen Sprachen hat. Angenommen, wir suchen nach einer Sprache, die aus Sätzen der Form 1 n 01 n besteht. Das heißt, alle Wörter beginnen mit n 1-er und enden mit ebenfalls n 1-er wobei n 0 ist. Wie sieht nun die einfachste Grammatik aus, die diese Sprache definiert? Um diese Frage zu beantworten, müssen wir den Begriff Einfachheit von Grammatiken klären. Grammatiken unterscheiden sich dabei nicht durch die Terminale, Nonterminale und das Startsymbol, sondern durch die Definition der Produktionen. In der Definition von Grammatiken wurden Produktionen sehr allgemein verwendet. Im Prinzip ist nun jede Regel der Form α β eine Produktion. Einfacher wird nun eine Produktion dann sein, wenn sie weniger Elemente in α beziehungsweise β hat. Darüber hinaus können noch andere Regeln aufgestellt werden, die die Beziehung zwischen α und β regelt. Die folgende Definition einer Sprachhierarchie macht sich diese Überlegungen zu Nutze. Chomsky-Sprachhierarchie: Unrestricted Grammars (Allgemeine Grammatiken) G: Keine Restriktionen bezüglich β α Seite 10

12 Context-sensitive Grammars (Kontextsensitive Grammatiken) G sens : α β Context-free Grammars (Kontextfreie Grammatiken) G free : α β, α V N Regular Grammars (Reguläre Grammatiken) G reg : α β, α V N, β hat Form aa oder a, mit a V T {ε}, A V N Als Beispiel kann man sich überlegen, wie die Grammatiken für Sprachen, die die folgenden Sätze zulassen, aussehen. 1. a*b* 2. a n b n 3. a n c n b n 4. a n c m b n mit m<n In welche Klasse der Sprachhierarchie fallen diese Grammatiken? Für die 1. Sprache können wir folgende Grammatik erstellen: G 1 = ({A,B},{a,b},A, {A aa, A bb, A ε, B bb, B ε}) Für die 2. Sprache reicht sogar eine einfachere Grammatik aus: G 2 = ({S},{a,b},S,{S asb, S ε}) Wie man einfach nachprüfen kann, beschreibt G 1 eine reguläre Sprache während G 2 eine kontextfreie Sprache beschreibt. Als Übung empfiehlt es sich, für die zwei anderen Sprachen entsprechende Grammatiken zu erstellen. Was uns noch fehlt, ist zu zeigen, dass es sich bei der Chomsky-Sprachhierarchie wirklich um eine Hierarchie handelt. Die Definition von Hierarchien legt fest, dass Elemente der Hierarchie, die weiter oben in der Hierarchie liegen, immer Übermenge von Elementen, die weiter unten liegen, sein müssen. Somit muss in unserem Fall Seite 11

13 gelten, dass L(G) L(G sens ) L(G free ) L(G reg ). In diesem Fall schreiben wir auch G G sens G free G reg. Um zu zeigen, dass es sich bei der Chomsky-Sprachhierarchie wirklich um eine Hierarchie handelt, können wir folgende Idee verwenden. Um A B zu beweisen, zeigt man: 1. Für alle x B, folgt x A 2. Es gibt ein x A für das wir zeigen müssen, dass x B Punkt 1 zu zeigen ist aufgrund der Definitionen der einzelnen Sprachen in der Hierarchie trivial. Zwischen jeder Grammatikdefinition erfolgt eine weitere Einschränkung. Somit ist jedes Element von G reg sicherlich auch in G free, jedes Element von G free sicherlich auch in G sens und jedes Element von G sens auch in G. Der zweite Schritt ist hier nicht trivial. In der Literatur gibt es hierzu Beweise. Als Übung werden wir den Beweis für L(G free ) L(G reg ) führen. Was wir benötigen, ist eine Sprache für die wir zeigen, dass diese nur in G free aber nicht in G reg formuliert werden kann. Wir nehmen dazu folgende Sprache: {a n ba n n N 0 }. Mit Hilfe der kontextfreien Grammatik kann diese Sprache wie folgt grammatikalisch definiert werden: G = ({S}, {a,b}, S, {S asa, S b}) Wir müssen nun zeigen, dass es nicht möglich ist, die selbe Sprache mit Hilfe einer regulären Grammatik zu definieren. Wie wir wissen, haben reguläre Grammatiken Produktionen folgender Form: X aa beziehungsweise X a. Um nun genau n-mal a zu generieren, benötigen wir somit n Nonterminale. Somit ist es nicht möglich, eine reguläre Grammatik für die Sprache bei beliebigen n zu finden. Als Anmerkung sei erwähnt, dass wir für ein spezielles n eine reguläre Grammatik finden können. Die folgende Grammatik reicht hierfür aus: G = ({A 0,..,A n,b 0,..B n },{a,b},a 0,Φ) wobei die einzelnen Produktion wie folgt definiert sind: A 0 aa 1, A 1 aa 2,.., A n-1 aa n, A n bb 0, B 0 ab 1, B 1 ab 2,.., B n-1 ab n,b n ε. Seite 12

14 Einen ähnlichen Beweis führt man, um zu zeigen, dass L(G sens ) L(G free ). In diesem Fall verwendet man die Sprache {a n b m a n b m ccc n,m 1}. Für den Beweis von L(G) L(G sens ) geht man hingegen anders vor. Man zeigt, dass es eine Entscheidungsprozedur für L(G sens ) aber nicht für L(G) gibt. Diese Entscheidungsprozedur ist eine Funktion, die immer sagen kann, ob ein bestimmter Satz in der angeführten Sprache ist. Neben der Klassifikation von Sprachen hinsichtlich ihrer Grammatik, kann man Grammatiken hinsichtlich weiterer Faktoren analysieren und bewerten. Diese Faktoren werden in den nachfolgenden Kapiteln über Compilerbau verwendet. Wichtige Faktoren dabei sind die Eindeutigkeit und die Verwendung beziehungsweise Vermeidung von Linksrekursionen. Definition (Mehrdeutig, Eindeutig): Gegeben ist eine Grammatik G mit dem Startsymbol S. G ist mehrdeutig, wenn es für einen Satz s L(G) mehrere unterschiedliche Ableitungssequenzen gibt, d.h. es gibt ω i (i=1,..,n) mit S ω 1, ω 1 ω 2,..., ω n-1 ω n, ω n s und υ j (j=1,..,m) mit S υ 1, υ 1 υ 2,..., υ m-1 υ m, υ m s und < ω 1,..., ω n > ist ungleich zu <υ 1,..., υ m >. Ist eine Grammatik nicht mehrdeutig, dann ist sie eindeutig. Definition (Linksrekursion): Eine Grammatik G ist (direkt) linksrekursiv, wenn diese eine Produktion der Form Aα Aβ enthält, wobei A ein Nonterminal und α, β eine Abfolge von beliebigen Terminalen und Nonterminalen darstellt. G ist linksrekursiv, wenn G direkt linksrekursiv ist oder wenn G Produktionen der Form Aα A 1 β, A 1 α 1 A 2 β 1,, A n-1 α n-1 A n β n-1, A n α n Aβ n enthält. Um das Kapitel über Grammatiken abschließen zu können, werden wir uns noch mit folgenden offenen Fragen beschäftigen: Wie kann man zeigen, dass ein gegebener Satz in einer Sprache ist? Warum verwenden wir nicht immer die generellste Grammatikdefinition zur Definition einer Sprache? Zuerst werden wir die erste Frage Seite 13

15 beantworten, indem wir einen Algorithmus beschreiben, der bei einer gegebenen Grammatik überprüft, ob ein gegebener Satz in der durch die Grammatik definierten Sprache enthalten ist. Solche Algorithmen beziehungsweise besser gesagt, die Implementierung solcher Algorithmen nennt man auch Parser. Um einen Parser für Unrestricted Grammars zu definieren, nehmen wir an, dass eine Grammatik G=(V N,V T,S,Φ) und ein Satz s V T * gegeben sind. Wir suchen dann eine Antwort auf die Frage, ob s L(G) ist. Die Antwort soll Ja sein, dann und nur dann wenn s L(G). Andernfalls soll die Antwort Nein lauten ( s L(G)). Um einen solchen Parser zu beschreiben verwenden wir folgende Idee. Wir wenden die Ableitungsfunktion so oft an, bis s aus dem Startsymbol S abgeleitet werden kann. Da es in manchen Schritten mehrere Möglichkeiten gibt, die Ableitung weiter voran zu treiben, werden wir alle Möglichkeiten berücksichtigen. Im Algorithmus verwenden wir einen Baum zur Speicherung aller Möglichkeiten. Der Wurzelknoten (Root) enthält nur das Startsymbol der Grammatik G. Die Nachfolgeknoten eines Knotens n enthalten das aktuelle Resultat der Anwendung einer Produktion auf n. Ist dieses Resultat gleich s, dann hat man eine Lösung gefunden. Andernfalls muss man in der nächsten Ableitungsebene weitersuchen. Der vorgestellte Algorithmus BPARSE verwendet nun Breitensuche für die Suche nach einer Lösung. BPARSE (G,s) 1. Sei n 0 der Wurzelknoten mit label(n0)=s und setze N={n 0 } 2. N ={}. 3. Für alle Knoten n N mache folgendes: a. Wenn es eine Produktion χ Φ gibt, die auf label(n) anwendbar ist, dann generiere eine Nachfolger n und füge diesen in die Menge N ein. Das label(n ) besteht aus den Elementen, die durch die Anwendung von χ auf label(n) entstanden sind. Ist label(n )=s dann liefere JA zurück. 4. Wenn N ={} dann liefer NEIN zurück. Ansonsten, sei N=N und gehe zu 2. Das folgende Beispiel soll die Funktionsweise von BPARSE erläutern. Gegeben sei folgende Grammatik G=({A,B},{a,b},A, {A aa, A bb, B bb, B ε}). Wir Seite 14

16 wollen nun zeigen, dass folgender Satz: ab Element der Sprache ist, die durch die Grammatik G gegeben ist. Dazu bauen wir den Suchgraph aus. Dies geschieht automatisch durch die Anwendung von BPARSE. Im letzten (für uns relevanten) Schritt erhalten wir folgenden Graphen: 0 A 1 aa bb 2 aaa abb b bbb 3 aaaa aabb abbb ab bb bbbb In diesem Graphen sind auch bereits die Ebenen abgebildet, die nacheinander von BPARSE aufgebaut wurden. Nach dem Aufbau von Ebene 3 sehen wir, dass ab abgeleitet werden kann. Somit ist ab ein Element von L(G). Mit BPARSE haben wir nun einen Algorithmus, der uns sicherlich immer dann eine Antwort geben kann, wenn der angeführte Satz in der Sprache, die durch die Grammatik definiert ist, enthalten ist. BPARSE durchsucht den gesamten Suchraum. Das heißt, wenn es eine Ableitung vom Startsymbol ausgehend zum angeführten Satz gibt, wird diese auch gefunden. Die Situation ändert sich allerdings, wenn der gegebene Satz nicht in der Sprache enthalten ist. In diesem Fall ist es möglich, dass BPARSE nicht terminiert und somit auch keine Antwort geben kann (in endlichen Schritten). Als Beispiel dazu betrachten wir folgende Grammatik ({S},{x,y},S,{S x S, S y}) und folgender Satz x, der offensichtlich nicht abgeleitet werden kann. BPARSE in der beschriebenen Version sucht jedoch immer weiter, obwohl der Satz nie abgeleitet werden kann. Seite 15

17 0 S 1 y xs Unendlicher Ast 2 xy xxs 3 xxy Wie hängt nun diese Beobachtung mit der Beweisidee von vorher, wo gezeigt werden soll, dass L(G) L(G sens ) gilt, zusammen? Die im obigen Beispiel gezeigte Grammatik ist sogar nicht einmal kontextsensitiv! Um das Problem zu lösen, schauen wir uns noch einmal die Definitionen der Chomsky-Sprachhierarchie an. Für kontextsensitive, kontextfreie und reguläre Grammatiken gibt es eine wichtige Einschränkung. Bei Produktionen muss die Länge der linken Seite (=Anzahl der Terminale und Nonterminale) kleiner oder gleich der Länge der rechten Seite sein. Somit können Produktionen für diese Grammatiken keine Sprachkonstrukte (Terminale und Nonterminale) während einer Ableitungssequenz entfernen. Dies ist dahingehend wichtig, da wir so entscheiden können, ob in einer Ableitungssequenz der gegebene Satz überhaupt jemals abgeleitet werden kann. Ist zu einem Zeitpunkt der Ableitung die Anzahl der Sprachkonstrukte (im Label des zugehörigen Knotens) größer als der gegebene Satz, kann diese Ableitungssequenz niemals mehr helfen, den Satz abzuleiten. Bei generellen Grammatiken wäre dies jedoch noch möglich, da auch Konstrukte entfernt werden können. Somit können wir BPARSE modifizieren, um für kontextsensitive, kontextfreie und reguläre Grammatiken immer eine Antwort geben zu können. Der erste Modifikationsschritt ist das Hinzufügen folgender Regel: Seite 16

18 Ist die Länge des Labels des gerade bearbeiteten Knotens n größer als die Länge des Satzes, dann wird n geschlossen. Für solche Knoten wird kein Nachfolgeknoten mehr berechnet. Diese Regel reicht allerdings noch nicht aus. Betrachten wir zum Beispiel folgende Grammatik ({A,B},{x,y},A,{A xb, xb Bx, Bx xb, B y}). Wenn wir nun anfragen, ob yy Element der Sprache ist, wird BPARSE auch für dieses Beispiel nicht terminieren. Abhilfe schaffen kann man, wenn man überprüft, ob ein Knotenlabel bereits von einem früher generierten Knoten verwendet wurde. Ist dies der Fall, kann der aktuelle Knoten wieder geschlossen werden. Wurde das Label des aktuellen Knotens n schon einmal von einem in einen früheren Schritt generierten Knoten verwendet, dann kann der aktuelle Knoten n geschlossen werden. Für geschlossene Knoten werden keine Nachfolger berechnet. Mit den neuen 2 Regeln wird BPARSE zumindest für nicht generelle Grammatiken der Chomsky-Sprachhierarchie entscheidbar. Zum Abschluss des Kapitels über Grammatiken und Sprachen betrachten wir den Zeitund Speicherplatzbedarf von BPARSE. In jeder Ebene werden aufgrund der Produktionen neue Knoten generiert. Angenommen, die durchschnittliche Anzahl von Kindknoten ist b und wir brauchen n Ebenen bis zur Terminierung von BPARSE. In diesem Fall generieren wir b n Knoten (1. Ebene: 1, 2. Ebene: b, 3. Ebene: b 2, ). Somit ist die Speicherplatzkomplexität der Ordnung b n. Dies gilt in diesem Fall natürlich auch für die Zeitkomplexität. Wenn man nun Programmiersprachen wie C, C++, Java betrachtet, die eine große Anzahl von Produktionen aufweisen und Programme ansieht, die ebenfalls sehr groß sind, ist es verständlich, dass aufgrund der Zeit- und Speicherplatzkomplexität BPARSE für die Verwendung in Compiler nicht wirklich geeignet ist. Die Frage, die nun in den Seite 17

19 nachfolgenden Kapiteln beantwortet werden wird, ist nun, ob es andere Algorithmen gibt? Compilerbau Im Compilerbau sind wir an einer schnellen Überprüfung von Programmen hinsichtlich deren grammatikalischen Korrektheit interessiert. Aus diesem Grund werden im Compilerbau nur eingeschränkte Grammatiken verwendet. Darüber hinaus wird der erste Teil der Analysephase in 2 Unterteile zerlegt. In der lexikalischen Analyse werden Programme in eine Sequenz von Tokens umgewandelt. Tokens repräsentieren dabei Teile der Programmstruktur. So unterscheiden wir Schlüsselwörter (Keywords) wie if oder while, Identifier (Namen für Variable, Funktionen), Zahlen und andere Teile, die in der nachfolgenden grammatikalischen Analyse unterschieden werden müssen. Der Vorteil dieser Trennung besteht in der Reduktion der Programmgröße für die nachfolgende Analyse. Somit erhalten wir eine effiziente Implementierung der Analysephase. Ein anderer Grund ist, dass die grammatikalische Analyse einfacher wird, da nicht mehr zwischen Namen unterschieden werden muss. Betrachten wir zum Beispiel folgendes einfaches C-Fragment, das die Addition zweier Integerzahlen basierend, auf dem Inkrement-Operator (++) definiert: int plus ( int a, int b) { int result = b ; int i = 0 ; while (i < a) { result++ ; i++ ; } return result ; } Dieses Programm besteht aus 76 Zeichen (Character), wenn man die White-Spaces (Leerzeichen, Tabulatoren, Return,..) nicht mitrechnet. Ein Compiler nimmt nun diese Seite 18

20 Sequenz von Zeichen und berechnet die Tokens. In Analogie zur Objekt-orientierten Programmierung kann man Tokens Klassen zuordnen, da diese ebenfalls Teile bezeichnet, die eine semantische Einheit bilden. Die Instanzen sind dann die Ausprägungen der Tokens, zum Beispiel die Variable result ist eine Instanz des Tokens <ID>. Wandelt man das einfache C-Programm nun in Tokens um, erhält man folgende Repräsentation: <INT> <FID> <(> <INT> <ID> <,> <INT> <ID> <)> <{> <INT> <ID> = <ID> <;> <INT> <ID> = <NUM> <;> <WHILE> <(> <ID> <ROP> <ID> <)> <{> <ID> <++> <;> <ID> <++> <;> <}> <RETURN> <ID> <;> <}> Diese Repräsentation besteht nur mehr aus 38 Tokens, wobei natürlich die Bezeichnung eines Identifiers beziehungsweise der Wert einer Zahl im entsprechenden Token für eine weitere Bearbeitung gespeichert ist. Der Einfachheit halber haben wir die Tokens im Beispiel unter zwischen Kleiner- und Größerzeichen (<>) gesetzt. Ein weiterer Vorteil der Konvertierung in eine Token-Repräsentation ist, dass die Regeln für die Grammatiküberprüfung ebenfalls kleiner und übersichtlicher werden. So kann man nun einfach sagen, dass eine Zuweisung in C (vereinfacht ausgedrückt) aus einem Identifier (Variablennamen) gefolgt von = und einem Ausdruck besteht. Ein Ausdruck ist vereinfacht ein Identifier, eine Zahl oder ein Operatorenausdruck. Auf diese Art und Weise kann man die gesamte Grammatik einer Sprache definieren. Ein Compiler nimmt nun die Token-Sequenz und wandelt diese in einen Ableitungsbaum (Parse Tree) um, wenn die Token-Sequenz den grammatikalischen Regeln genügt. Ist dies nicht der Fall wird der Compiler einen Fehler melden. Seite 19

21 Definition (Ableitungsbaum, Parse Tree): Sei G eine kontextfreie Grammatik, s ein Satz der Sprache L(G), S das Startsymbol und S ω 1, ω 1 ω 2,..., ω n-1 ω n, ω n s eine Ableitungsreihenfolge. Der zugehörige Parse Tree T ist wie folgt definiert: (1) Für das Startsymbol S generiere einen neuen Knoten n S. (2) Ist n x ein Knoten von T und gibt es eine Ableitung ω i ω i+1 der Form αxβ αδ 1..δ k β in der Ableitungsreihenfolge (α, β beliebige Reihenfolge von Nonterminalen und Terminalen, δ i V T V N ), dann generiere neue Knoten n δi und gerichtet Kanten (n x, n δi ) für T. Als Anmerkung sei erwähnt, dass der Parse Tree ein gerichteter Baum ist, wo es für jedes verwendetet Terminal und Nonterminalsymbol mehrere Knoten geben kann. Als Beispiel nehmen wir an, dass wir die Grammatik der Sprache C in einer entsprechenden Form beschrieben haben und dass die folgenden 4 Produktionen in dieser Beschreibung enthalten sind: S id = E, E id, E num, E E op E. Von S können wir nun sicherlich den Satz id = id op num ableiten. Eine Ableitungssequenz ist hier: S id = E id =E op E id = id op E id = id op num. Der zugehörige Parse Tree hat nun folgendes Aussehen S id = E E op E id num Als Anmerkung sei erwähnt, dass der Teil der Grammatik für C linksrekursiv und mehrdeutig ist. Seite 20

22 Zusammenfassend kann der Aufbau eines Compilers vereinfacht wie folgt dargestellt werden: Programm i f ( Lexikalische Analyse Analyse Tokens Syntax-Analyse <if> <(> Parse Tree Synthese Code-Generierung Programm in der Zielsprache Der Compiler bekommt als Eingangswerte eine Sequenz von Zeichen (Characters). Diese werden in der lexikalischen Analyse in Tokens umgewandelt. In der Syntax- Analyse wird die Sequenz von Tokens hinsichtlich der grammatikalischen Korrektheit überprüft. Man erhält einen Parse Tree. Der Parse Tree wird dann zur weiteren Analyse (Typüberprüfung,..) verwendet. Aus dem Parse Tree wird dann danach das Programm in der Zielsprache generiert. Die dazu notwendigen Schritte und Problemstellungen werden in Compilerbau-Vorlesungen gebracht und sind nicht Teil der Software Paradigmen Lehrveranstaltung. Im Nachfolgenden werden wir uns mit der lexikalischen Analyse und der Syntax-Analyse beschäftigen. Lexikalische Analyse Die lexikalische Analyse dient zur Extraktion von Tokens. Um dies effizient zu bewerkstelligen, werden bei der lexikalischen Analyse nur Reguläre Grammatiken verwendet. Solche Grammatiken können auch über Reguläre Ausdrücke (Regular Seite 21

23 Expressions) dargestellt werden. Reguläre Ausdrücke sind wie folgt definiert, wobei Q und R wiederum Reguläre Ausdrücke sind: Form Bedeutung ε Leerstring A a V T, Terminal, a Q R Vereinigung, entweder Q oder R QR Konkatenation, erst Q und danach R Q* Q Q, Hintereinandersausführung von Q Null bis n-mal. (Q) Q, Klammernsetzung Weiters in Verwendung sind folgende Regulären Ausdrücke, die auf obige Ausdrücke reduziert werden können: Q opt = Q ε (Q kann maximal 1-Mal vorkommen) Q+ = Q Q* (Mindestens 1-Mal muss Q vorkommen. Reguläre Ausdrücke werden nicht nur im Compilerbau verwendet. Sie sind auch hilfreich, wenn man zum Beispiel Teilstrings sucht, die in einem Text vorkommen. Aus diesem Grund werden Reguläre Ausdrücke auch bei der Textanalyse verwendet. Man kann zeigen, dass Reguläre Ausdrücke dieselbe Ausdrucksstärke wie Reguläre Grammatiken haben. Der Einfachheit und der Übersicht halber werden wir nun Reguläre Grammatiken zur Definition von regulären Sprachen verwenden. Um zum Beispiel die Sprache aller Fixkommazahlen zu bestimmen, können wir wie folgt vorgehen. Wir wissen, dass Fixkommazahlen aus einer beliebigen Anzahl der Zahlen 0 bis 9, gefolgt von einen Kommapunkt und wiederum einer Sequenz von 0 bis 9, die mindestens 1 Element lang sein muss, aufgebaut sind. Somit können wir den Regulären Ausdruck aus 3 Teilen aufbauen. Zuerst die beliebige Anzahl von 0 bis 9. Wir schreiben: ( ) * (oder ( ) *, wenn die Reihenfolge klar ersichtlich ist). Danach folgt ein Kommapunkt.. Zu guter Letzt müssen wir noch Seite 22

24 den dritten Teil definieren: ( ) +. Verbinden wir die Teile nun in der richtigen Reihenfolge, erhalten wir eine Definition der Grammatik der Sprache: ( ) *. (0 1 9) + Wir sehen, dass wir in dieser Definition zweimal dieselben Konstrukte verwenden ( ). Es wäre schön, sich hier Schreibarbeit zu ersparen und auch die Definitionen leichter verständlich zu halten. Aus diesem Grund erweitern wir nun Reguläre Ausdrücke und erhalten Reguläre Definitionen. Die Idee ist, dass wir Regulären Ausdrücken Bezeichnungen zuordnen, die wiederum in einem Regulären Ausdruck vorkommen. Wir nehmen nun an, dass B die Menge aller Bezeichnungen ist. Wir definieren einen erweiterten Regulären Ausdruck als einen regulären Ausdruck, der auch Bezeichnungen enthalten kann. Definition [Reguläre Definition] Der Ausdruck b ::= E ist eine Reguläre Definition, wenn b B und E ein erweiterter Regulärer Ausdruck ist. Kommt nun ein b B in einem Ausdruck vor, so können wir dies durch die rechte Seite der Regulären Definition ersetzen. Verwenden wir Reguläre Definitionen, können wir die Fixkommazahlen wie folgt definieren: digit ::= fix_num ::= digit *. digit + Diese Definition ist sicherlich leichter zu verstehen. Sie besagt, dass Fixkommazahlen aus einzelnen Ziffern (digit) aufgebaut sind und ein Komma enthalten müssen. Implementierung der lexikalischen Analyse In den nachfolgenden Überlegungen zur Implementierung einer lexikalischen Analyse nehmen wir an, dass die Sprachen in Form von regulären Definitionen gegeben sind. Weiters nehmen wir an, dass wir nur eine Sprache wie zum Beispiel die Sprache der Seite 23

25 Fixkommazahlen haben. Eine Erweiterung auf den allgemeinen Fall, wie er beim Compilerbau immer vorkommt, ist einfach möglich. Im Compilerbau müssen viele unterschiedliche Tokens (Fliesskommazahlen, Natürliche Zahlen, Strings, Variablen, ) in einem Text gefunden werden. Die Lexikalische Analyse ist das Bindeglied zwischen der Textform und den einzelnen Tokens. Somit müssen wir in der Lage sein, einen Text Zeichen für Zeichen abzuarbeiten. Aus diesem Grund führen wir eine Funktion nextchar() ein, die uns das nächste Zeichen in einem String liefert. Bei der Initialisierung nehmen wir an, dass nextchar() das erste Zeichen des Strings liefert. Die folgende Abbildung zeigt den Initialzustand bei der Analyse des Satzes 10.0: $ nextchar() Endsymbol ( End of string/input ) Abarbeitungsrichtung Die Implementierung der lexikalischen Analyse geht nun Zeichen für Zeichen durch den Eingangsstring und versucht abzuleiten, ob sich die Zeichenkette bezüglich der gegebenen Regulären Definition korrekt verhält. Im obigen Beispiel ist man daran interessiert zu zeigen, dass 10.0 eine Fixkommazahl gemäß der Definition von fix_num ist. Die Überprüfung auf fix_num wird in der Praxis beendet, wenn man ein Zeichen findet, das nicht mehr zur Definition gehört, beziehungsweise wenn man das Ende des Strings erreicht hat. Das Ende des Strings wird durch das Zeichen $ dargestellt. Wie kann man nun prüfen, ob ein String der Definition von fix_num gehorcht? Wir wissen, dass jedes Wort aus fix_num aus einer beliebigen Folge von digit, einem Punkt, und einer beliebigen Folge von digit der Länge größer bzw. gleich 1 besteht. Um Seite 24

26 dies nun zu prüfen, implementieren wir zuerst eine Funktion, die überprüft ob ein Zeichen ein digit ist. Diese Funktion hat folgendes Aussehen (in Pseudocode): function digit(ch) begin: if (ch = 0 or ch = 1 or or ch = 9 ) then return TRUE; else return FALSE; end if; end; Basierend auf dieser Funktion, können wir eine Funktion für fix_num erstellen. Wir erhalten: function fix_num(ch) begin: while (digit(ch)) do: ch = nextchar(); end while; if (ch =. ) then ch = nextchar(); if (digit(ch)) then ch = nextchar(); while (digit(ch)) do: ch = nextchar(); end while; return TRUE; end if; end if; return FALSE; end; Seite 25

27 Vor dem Aufruf der Funktion fix_num muss der Wert von ch bestimmt sein. Dies geschieht zum Beispiel durch den Aufruf von nextchar(). In der obigen Implementierung wird nur geprüft, ob eine Zeichenfolge eine gegebene Grammatik erfüllt. Ist dies der Fall, wird TRUE zurückgeliefert und wir wissen, dass ein Token erkannt wurde. Ein Token ist hierbei ein Satz, der durch die Grammatik definiert ist. In der Praxis speichert man noch zusätzlich den Wert des Tokens ab. Im obigen Fall würde man den Substring bzw. den Zahlenwert speichern. Eine entsprechende Adaption des Pseudocode-Programms ist einfach möglich. Eine weitere Adaption ist notwendig, um Fehler entsprechend abzuarbeiten. Anstelle FALSE zurück zu liefern, kann man auch eine entsprechende Fehlermeldung (inklusive der Angabe der Zeichenposition wo der Fehler aufgetreten ist) ausgeben. Dies kann zum Beispiel einfach über eine Exception implementiert werden. Ohne eine formale Beschreibung der Umwandlung von Regulären Definitionen zu Programmen anzugeben, kann man folgende Schlussfolgerungen aus dem angeführten Beispiel entnehmen: Ein Terminal a wird durch eine If-Abfrage überprüft. Q* wird durch ein Schleifenkonstrukt abgedeckt. Q R bedeutet, dass entweder Q oder R gelten muss. Q R bedeutet, dass als Erstes Q und danach R überprüft werden muss. Ebenfalls wichtig ist es nextchar() immer dann aufzurufen, wenn ein Zeichen erkannt wurde. Somit ist sichergestellt, dass ein Token gefunden wird und dass der Zeiger immer auf einem Zeichen des nächsten Tokens steht. Angenommen, wir haben Strings, die aus Fixkommazahlen getrennt durch Leerzeichen ( _ ) bestehen und wir möchten nun zum Beispiel alle Fixkommazahlen im String $ erkennen. Was wir benötigen ist eine Abfrage für Leerzeichen, gefolgt durch eine Abfrage auf Fixkommazahlen. Diese Abfragen werden dann solange ausgeführt bis ein Fehler erkannt oder das Ende ($) erreicht wurde. Seite 26

28 Es gibt natürlich noch andere Möglichkeiten, einen Parser für Reguläre Definition zu implementieren. Für diese Lehrveranstaltung reicht diese Art der Implementierung aus. Weiterführende Lehrveranstaltungen zeigen, dass Reguläre Grammatiken äquivalent zu endlichen Automaten sind. Diese können dann direkt zur Implementierung verwendet werden. Grammatikalische Analyse Wie bereits erwähnt, folgt die Grammatikalische Analyse (Syntax-Analyse, Parsing) der lexikalischen Analyse. Ausgehend von Tokens wird überprüft, ob diese in der grammatikalisch korrekten Reihenfolge auftreten. Somit stellen die Tokens Terminalsymbole für die Syntax-Analyse dar, die eine vorgegebene Grammatik überprüft. Als Anmerkung sei erwähnt, dass in der lexikalischen Analyse die Zeichen Terminalsymbole sind. Wie ebenfalls bereits gesagt, ist es sinnvoll, eingeschränkte Grammatiken für die Syntax-Analyse zu verwenden, um auch für große Eingangswerte (=Programme) in vernünftiger Zeit grammatikalische Korrektheit zu überprüfen. Aus diesem Grund werden wir uns auf kontextfreie Grammatiken beschränken. Als Beispiel wollen wir nun einfache arithmetische Ausdrücke behandeln. Diese bestehen aus Zahlen, die durch Operatoren (Addition, Multiplikation) miteinander verbunden sind. Weiters lassen wir geklammerte Ausdrücke zu. Solche arithmetischen Ausdrücke können einfach als kontextfreie Grammatiken dargestellt werden. Der Einfachheit halber geben wir nur mehr die Produktionsregeln an. Terminale werden unterstrichen dargestellt. Als Startsymbol verwenden wir E. (1) E E + E (2) E E * E (3) E ( E ) (4) E num Diese 4 Produktionen reichen aus, um die Sprache der arithmetischen Ausdrücke zu definieren. Welche Eigenschaften hat nun die Grammatik? Wie können wir einfach Seite 27

29 feststellen, dass ein gegebener Satz Element der Sprache der arithmetischen Ausdrücke ist? Offensichtlich erfüllt die obige Grammatik alle Eigenschaften einer kontextfreien Grammatikdefinition. Allerdings können wir einfach zeigen, dass die Grammatik linksrekursiv und mehrdeutig ist. Die Linksrekursion ist durch die ersten 2 Produktionen bedingt. Die Mehrdeutigkeit kann man anhand eines Beispiels nachweisen. Man betrachte den Satz num + num * num und zwei der möglichen Ableitungen: E E+E num+e num+e*e num+num*e num+num*num E E+E E+E*E num+e*e num+num*e num+num*num Wenn wir nun nachprüfen wollen, ob ein gegebener Satz grammatikalisch korrekt ist, müssen wir im Prinzip eine Ableitung vom Startsymbol finden. Da wir durch diese Suche vom Startsymbol hin zu Terminalen gehen, nennt man diese Form der Überprüfung auch Top-Down-Parsing. Im Gegensatz dazu gibt es auch den Weg vom Satz hin zum Startsymbol zu gehen (Bottom-Up-Parsing). Diese Methode wird in weiterführenden Lehrveranstaltungen gebracht. Wollen wir nun Top-Down-Parsing effizient implementieren, dann ist offensichtlich, dass Mehrdeutigkeiten in der Ableitung schlecht sind. Darüber hinaus wäre es gut, wenn wir in jedem Schritt wissen, welche Produktionsregel anzuwenden ist. Wollen wir den Satz (num) parsen, ist die Wahl der Produktionen offensichtlich! Dies ist nicht der Fall, wenn wir num+num analysieren, selbst wenn wir bei der Analyse von links beginnen! Das am weitest links stehende Symbol ist num. Sehen wir dieses und wissen wir nicht, ob danach ein + oder * kommt, können wir nicht entscheiden, welche Produktion wir wählen sollen. Aus diesem Grund eignet sich die obige Grammatik nicht für eine effiziente Analyse. Ein weiteres Problem besteht in der Linksrekursion. Diese verhindert, dass wir wissen, wie oft wir die entsprechende Regel (1) oder (2) anwenden müssen. Wir müssen somit Mehrdeutigkeiten und Linksrekursion aus Grammatiken entfernen (wo dies möglich ist), um effizient parsen zu können. Seite 28

30 Ein weiteres Problem der Mehrdeutigkeit ergibt sich, wenn man die Reihenfolge von Operatorenanwendungen betrachtet. Bei 1+2*3 meinen wir, dass zuerst 2*3=6 berechnet werden soll. Dieses Resultat wird mit 1 addiert und wir erhalten 7 als Lösung. In der Grammatik selber wird auf die unterschiedlichen Bindungsstärken von Operatoren keine Rücksicht genommen. Die unterschiedlichen Berechnungen drücken sich auch über die Parse-Trees aus (num+num*num): E E E + E E * E num E * E E + E num num num num num Hat man also Mehrdeutigkeiten in einer Grammatik und unterschiedliche Bindungsstärken von Operatoren, dann muss man überprüfen, ob diese auch durch die Ableitung entsprechend unterstützt wird. Ist dies nicht der Fall (wie im obigen Beispiel), muss die Grammatik umformuliert werden. Diese Umformulierungen können zur Einführung von neuen Produktionen sowie Nonterminalen führen. Folgende Regeln (neben anderen) können dabei verwendet werden: (U1) Gibt es Produktionen der Form A αbβ sowie B χ, dann kann man die Produktion A αχβ einfügen. Diese Regel macht Sinn, um indirekte Linksrekursionen zu finden (wenn α das Leersymbol darstellt). (U2) Linksrekursionen auflösen: Hat man Produktionen der Form A Aα und A β, dann kann man die Linksrekursion durch Umwandlung in Produktionen der Form A βr sowie R αr ε auflösen. Seite 29

31 (U3) Linksfaktorisierung auflösen: Hat man Produktion der Form A αb sowie A αc, wobei α der größte gemeinsame Prefix von αb und αc ist, so können wir diese Produktion durch A αr und R B C ersetzen. Der größte gemeinsame Prefix einer Sequenz von Terminalen und Nonterminalen ist die größte gemeinsame Zeichenkette dieser Sequenzen. Der größte gemeinsame Prefix von if E then E else E und if E then E ist if E then E. Wenn wir nun für unseren einfachen arithmetischen Ausdruck die Linksrekursionen entfernen, erhalten wir folgende Grammatik: (1) E num R (2) E ( E ) (3) R + E R (4) R * E R (5) R ε Durch Anwendung der Umformungsregel können viele Grammatiken in eine einfachere Form umgewandelt werden. Diese Form hilft bei der grammatikalischen Analyse, da immer entschieden werden kann, welche Produktion als nächstes angewendet werden soll. Grammatiken in der angesprochenen Form nennt man LL(1) Grammatiken. Diese sind wie folgt definiert: Definition (LL(1) Grammatik): Eine kontextfreie Grammatik G ist eine LL(1)- Grammatik (ist in LL(1)-Form), wenn folgendes gilt: G enthält keine Linksrekursionen G enthält keine Produktionen mit gleichen Prefixen für die selbe linke Seite Es gibt kann in einem Schritt immer entschieden werden, welche Produktion zur Ableitung verwendet werden kann. Seite 30

32 Eine Grammatik, die die Produktion L L a enthält, ist nicht LL(1), aber auch nicht eine Grammatik mit den Produktionen: L G a und G L b. Eine Grammatik mit den Produktionen L a X gemeinsam mit L a Y ist ebenfalls keine LL(1)-Grammatik. Als Anmerkung sei erwähnt, dass nicht alle Grammatiken in äquivalente LL(1)- Grammatiken umgewandelt werden können. Äquivalenz heißt hier, dass beide Grammatiken, die selbe Sprache definieren müssen. Kann dies mittels Umformungen nicht durchgeführt werden, können LL(1)-Parser für die Analyse nicht verwendet werden. Oft hilft es auch, die Sprache entsprechend zu modifizieren, um eine LL(1)- Grammatikdarstellung zu ermöglichen. Dies muss im Einzelfall jedoch geklärt werden. Die ersten 2 Bedingungen der Definition von LL(1)-Grammatiken sind notwendige (aber nicht hinreichende Bedingungen). Die 3 Bedingung kann einfach über Parser- Tabellen (Parse-Table), die im nachfolgenden Abschnitt beschrieben sind, überprüft werden. Enthält eine Parser-Tabelle einen Mehrfacheintrag, dann ist die Grammatik nicht LL(1). Implementierung der Syntax-Analyse für LL(1)-Grammatiken Nachdem wir Argumente für Einschränkungen von kontextfreien Grammatiken gebracht haben, werden wir uns mit der Implementierung von Parsern für solche Sprachen beschäftigen. Dabei nehmen wir an, dass die vorliegenden Grammatiken LL(1)-Grammatiken sind. Wir werden zuerst uns mit der Programmierung von LL(1)- Parsern beschäftigen, die der Implementierung der Analyse von regulären Definitionen sehr ähnlich sind. Diese Parser heißen auch Predictive Recursive Descend Parser. Neben diesen werden wir uns mit tabellengestützten Parsern beschäftigen. Bei beiden Parsertypen verwenden wir jedoch ebenfalls wie bei der Implementierung von Parsern für Reguläre Definition Hilfsfunktionen und Variablen: nexttoken() Liefert das aktuelle Token und setzt den Zeiger auf das nächste zu lesende Token. token Globale Variable, die das aktuelle Token enthält. Der Aufruf von nexttoken() liefert ein Token. Dies kann das Resultat einer Analyse von regulären Definitionen sein. Auf diese Art kann man die lexikalische Analyse leicht Seite 31

33 mit der Syntax-Analyse koppeln. Immer wenn ein neues Token gelesen werden muss, wird nexttoken() aufgerufen. Diese Methode implementiert die lexikalische Analyse und greift auf diese Art auf das ursprüngliche Programm bzw. den ursprünglichen Eingabestring zu. Predictive Recursive Descend Parser: Betrachtet man die Produktionen einer LL(1)- Grammatik erkennt man, dass diese Ähnlichkeit mit Funktionsaufrufen aufweist. Zum Beispiel E ( E ) und E num R sind 2 Produktionen für arithmetische Ausdrücke, die erklären, wie E aufgebaut sein muss. Entweder E startet mit ( oder mit num. Somit kann man die Produktionen für E darstellen als Funktion, dessen Definition (Body) die entsprechenden Abfragen enthält. Wir müssen nun nur sicherstellen, dass die entsprechenden Tokens abgefragt werden, bzw. dass wir jeweils nach einer Abfrage zum nächsten Token gehen müssen. Für E können wir somit folgende Funktion schreiben: fun E() begin if token = ( then nexttoken(); E(); If token = ) then nexttoken(); else ERROR(); end if; else if token = num then nexttoken(); R(); else ERROR(); end if; end if; end; Seite 32

34 Die Funktion ERROR() übernimmt die Fehlbehandlung im Fall, dass der gegeben Satz nicht der Grammatik entspricht. Eine ähnliche Funktion kann man für die Produktionen, die R auf der rechten Seite haben aufstellen: fun R() begin if token = + then nexttoken(); E(); R(); else if token = * then nexttoken(); E(); R(); end if; end if; end; Bei der Verwendung des Parsers ruft man diesen mit der Funktion, die dem Startsymbol entspricht, auf. Wir nehmen dabei an, dass die globale Variable token bereits das erste Token enthält! Um zum Beispiel den Satz num + num * num$ auf grammatikalische Korrektheit zu überprüfen, ruft man E() auf. Man erhält dann folgende Folge von Funktionsaufrufen: Funktionenaufruf token (vor dem Aufruf der Funktion) E() Num R() + E() Num R() * E() Num R() $ Seite 33

35 Da die Funktionsaufrufe, die durch die Implementierung der Suche nach einer Lösung bedingt sind, vom Startsymbol bis zum eigentlichen Satz hin eine Tiefensuche durchführen, gehören Predictive Recursive Descend Parser zur Kategorie der Top- Down-Parser. Dies gilt auch für die Implementierung eines LL(1)-Parsers in Tabellenform. Auch dort erfolgt die Suche ausgehend vom Startsymbol und somit vom Wurzelknoten hin zu den Blattknoten des Baums aller möglichen Ableitungen. Tabellengestützter LL(1)-Parser: Die Grundidee des tabellengestützten LL(1)-Parsers wird durch folgende Abbildung dargestellt. Stack $ S S aa Satz a a b $ Tabelle Der aktuelle Stand der Ableitung wird auf einem Stack gespeichert. Dieser Stack enthält Symbole, für die noch keine entsprechenden Elemente im Satz gefunden wurden. Aus dem obersten Stack-Element und dem ersten noch nicht verwendeten Zeichen des (Rest- )Satzes, wird in einer Tabelle eine Produktion, die angewendet werden kann, bestimmt. In der obigen Abbildung ist das Symbol am Stack ein S und das erste Zeichen des Satzes ein a. Die Tabelle liefert eine Produktion, die sagt, dass S in aa übergeführt werden kann. Wichtig dabei ist, dass das obere Element des Stacks der linken Seite der Produktion entsprechen muss. Das erste Element der rechten Seite einer Produktion muss hingegen nur die Ableitung des ersten Zeichens gestatten. Angenommen, wir haben 2 Produktionen: S P A und P a. In diesem Fall werden wir zuerst S P A verwenden und danach P a. Um nun zu erkennen, welches Nonterminal bzw. welche Reihenfolge von Nonterminalen und Terminalen die Ableitung eines bestimmten Terminals ermöglicht, führen wir den Begriff der First-Menge ein. FIRST(α) ist dabei eine Menge von Seite 34

Inhalt. VU SWP - Syntax. Sprachen. Strukturbeschreibung. Beispiel. Grammatik. Produktionen Sprachhierarchie Parsing Anmerkungen zum Sprachdesign

Inhalt. VU SWP - Syntax. Sprachen. Strukturbeschreibung. Beispiel. Grammatik. Produktionen Sprachhierarchie Parsing Anmerkungen zum Sprachdesign Inhalt VU SWP - Syntax Franz Wotawa Institut für Softwaretechnologie wotawa@ist.tugraz.at Produktionen Sprachhierarchie Parsing Anmerkungen zum Sprachdesign Syntax 2 Sprachen Strukturbeschreibung Struktur

Mehr

VU Software Paradigmen / SS 2014

VU Software Paradigmen / SS 2014 VU Software Paradigmen 716.060 / SS 2014 Thorsten Ruprechter ruprechter@tugraz.at Institute for Software Technology 1 Organisatorisches Ausgabe: 25.03. (heute) Fragestunde: 22.04. Abgabe: 29.04 (ausgedruckt)

Mehr

Kapitel 5: Syntax-Analyse

Kapitel 5: Syntax-Analyse Kapitel 5: Syntax-Analyse Aufgabe Die Token-Folge wird strukturiert in Anweisungen, Ausdrücke etc., um die Semantische Analyse und Code-Erzeugung zu ermöglichen Themen Kontextfreie Grammatik Äquivalente

Mehr

kontextfreie Grammatiken Theoretische Informatik kontextfreie Grammatiken kontextfreie Grammatiken Rainer Schrader 14. Juli 2009 Gliederung

kontextfreie Grammatiken Theoretische Informatik kontextfreie Grammatiken kontextfreie Grammatiken Rainer Schrader 14. Juli 2009 Gliederung Theoretische Informatik Rainer Schrader Zentrum für Angewandte Informatik Köln 14. Juli 2009 1 / 40 2 / 40 Beispiele: Aus den bisher gemachten Überlegungen ergibt sich: aus der Chomsky-Hierarchie bleiben

Mehr

Übungsskriptum verfasst von Daniel Gruß. Version 29. Juni Fehlerfunde bitte melden an

Übungsskriptum verfasst von Daniel Gruß. Version 29. Juni Fehlerfunde bitte melden an Softwareparadigmen Dieses Skriptum basiert auf der Softwareparadigmen Übung im Sommersemester 2012 und dem Vorlesungsskriptum 2007. Vorlesung von Alexander Felfernig ii Übungsskriptum verfasst von Daniel

Mehr

Kapitel: Die Chomsky Hierarchie. Die Chomsky Hierarchie 1 / 14

Kapitel: Die Chomsky Hierarchie. Die Chomsky Hierarchie 1 / 14 Kapitel: Die Chomsky Hierarchie Die Chomsky Hierarchie 1 / 14 Allgemeine Grammatiken Definition Eine Grammatik G = (Σ, V, S, P) besteht aus: einem endlichen Alphabet Σ, einer endlichen Menge V von Variablen

Mehr

Fachseminar Compilerbau

Fachseminar Compilerbau Fachseminar Compilerbau WS 08/09 Matthias Schiller Syntaktische Analyse 1. Prinzip der Top-Down-Analyse 2. LL(1)-Grammatiken Modell-Vorstellung Der Scanner liefert als Ergebnis der lexikalischen Analyse,

Mehr

Was ist ein Compiler?

Was ist ein Compiler? Was ist ein Compiler? Was ist ein Compiler und worum geht es? Wie ist ein Compiler aufgebaut? Warum beschäftigen wir uns mit Compilerbau? Wie ist die Veranstaltung organisiert? Was interessiert Sie besonders?

Mehr

Grundlagen der Theoretischen Informatik Musterlösungen zu ausgewählten Übungsaufgaben

Grundlagen der Theoretischen Informatik Musterlösungen zu ausgewählten Übungsaufgaben Dieses Dokument soll mehr dazu dienen, Beispiele für die formal korrekt mathematische Bearbeitung von Aufgaben zu liefern, als konkrete Hinweise auf typische Klausuraufgaben zu liefern. Die hier gezeigten

Mehr

Algorithmen mit konstantem Platzbedarf: Die Klasse REG

Algorithmen mit konstantem Platzbedarf: Die Klasse REG Algorithmen mit konstantem Platzbedarf: Die Klasse REG Sommerakademie Rot an der Rot AG 1 Wieviel Platz brauchen Algorithmen wirklich? Daniel Alm Institut für Numerische Simulation Universität Bonn August

Mehr

Vorlesung Theoretische Informatik

Vorlesung Theoretische Informatik Vorlesung Theoretische Informatik Automaten und Formale Sprachen Hochschule Reutlingen Fakultät für Informatik Masterstudiengang Wirtschaftsinformatik überarbeitet von F. Laux (Stand: 09.06.2010) Sommersemester

Mehr

Kontextfreie Grammatiken

Kontextfreie Grammatiken Kontextfreie Grammatiken Bisher haben wir verschiedene Automatenmodelle kennengelernt. Diesen Automaten können Wörter vorgelegt werden, die von den Automaten gelesen und dann akzeptiert oder abgelehnt

Mehr

Formale Sprachen. Grammatiken und die Chomsky-Hierarchie. Rudolf FREUND, Marian KOGLER

Formale Sprachen. Grammatiken und die Chomsky-Hierarchie. Rudolf FREUND, Marian KOGLER Formale Sprachen Grammatiken und die Chomsky-Hierarchie Rudolf FREUND, Marian KOGLER Grammatiken Das fundamentale Modell zur Beschreibung von formalen Sprachen durch Erzeugungsmechanismen sind Grammatiken.

Mehr

Formale Methoden 1. Gerhard Jäger 12. Dezember Uni Bielefeld, WS 2007/2008 1/22

Formale Methoden 1. Gerhard Jäger 12. Dezember Uni Bielefeld, WS 2007/2008 1/22 1/22 Formale Methoden 1 Gerhard Jäger Gerhard.Jaeger@uni-bielefeld.de Uni Bielefeld, WS 2007/2008 12. Dezember 2007 2/22 Bäume Baumdiagramme Ein Baumdiagramm eines Satzes stellt drei Arten von Information

Mehr

Alphabet, formale Sprache

Alphabet, formale Sprache n Alphabet Alphabet, formale Sprache l nichtleere endliche Menge von Zeichen ( Buchstaben, Symbole) n Wort über einem Alphabet l endliche Folge von Buchstaben, die auch leer sein kann ( ε leere Wort) l

Mehr

Theoretische Informatik Mitschrift

Theoretische Informatik Mitschrift Theoretische Informatik Mitschrift 2. Grammatiken und die Chomsky-Hierarchie Beispiel: Syntaxdefinition in BNF :=

Mehr

2.6 Deterministisches Top-Down-Parsen

2.6 Deterministisches Top-Down-Parsen 48 2.6 Deterministisches Top-Down-Parsen Als nächstes wollen wir uns mit Methoden zur syntaktischen Analyse befassen. Der lexikale canner eines Compilers liest die Eingabe Zeichen für Zeichen und erzeugt

Mehr

6 Kontextfreie Grammatiken

6 Kontextfreie Grammatiken 6 Kontextfreie Grammatiken Reguläre Grammatiken und damit auch reguläre Ausdrücke bzw. endliche Automaten haben bezüglich ihres Sprachumfangs Grenzen. Diese Grenzen resultieren aus den inschränkungen,

Mehr

Grammatiken. Eine Grammatik G mit Alphabet Σ besteht aus: Variablen V. Startsymbol S V. Kurzschreibweise G = (V, Σ, P, S)

Grammatiken. Eine Grammatik G mit Alphabet Σ besteht aus: Variablen V. Startsymbol S V. Kurzschreibweise G = (V, Σ, P, S) Grammatiken Eine Grammatik G mit Alphabet Σ besteht aus: Variablen V Startsymbol S V Produktionen P ( (V Σ) \ Σ ) (V Σ) Kurzschreibweise G = (V, Σ, P, S) Schreibweise für Produktion (α, β) P: α β 67 /

Mehr

Grundbegriffe. Grammatiken

Grundbegriffe. Grammatiken Grammatiken Grammatiken in der Informatik sind ähnlich wie Grammatiken für natürliche Sprachen ein Mittel, um alle syntaktisch korrekten Sätze (hier: Wörter) einer Sprache zu erzeugen. Beispiel: Eine vereinfachte

Mehr

Grammatiken und ANTLR

Grammatiken und ANTLR Grammatiken und ANTLR Zusatzfolien zu Algo Blatt 6 Author: Henry Schaefer http://www.majeeks.de/folien_blatt6.pdf Grammatik Definition: syntaktische Beschreibung einer Sprache (H.S.) Definiton Grammatik

Mehr

Interpreter - Gliederung

Interpreter - Gliederung Institut für Informatik Ludwig-Maximilian Universität Interpreter - Gliederung Programmiersprache Syntax Konkrete Syntax Abstrakter Syntax Baum (Abstrakte Syntax) Parser Syntaktische Struktur einer Sprache

Mehr

Kapitel 2: Formale Sprachen Gliederung. 0. Grundbegriffe 1. Endliche Automaten 2. Formale Sprachen 3. Berechnungstheorie 4. Komplexitätstheorie

Kapitel 2: Formale Sprachen Gliederung. 0. Grundbegriffe 1. Endliche Automaten 2. Formale Sprachen 3. Berechnungstheorie 4. Komplexitätstheorie Gliederung 0. Grundbegriffe 1. Endliche Automaten 2. Formale Sprachen 3. Berechnungstheorie 4. Komplexitätstheorie 2.1. 2.2. Reguläre Sprachen 2.3. Kontextfreie Sprachen 2/1, Folie 1 2015 Prof. Steffen

Mehr

Motivation. Formale Grundlagen der Informatik 1 Kapitel 5 Kontextfreie Sprachen. Informales Beispiel. Informales Beispiel.

Motivation. Formale Grundlagen der Informatik 1 Kapitel 5 Kontextfreie Sprachen. Informales Beispiel. Informales Beispiel. Kontextfreie Kontextfreie Motivation Formale rundlagen der Informatik 1 Kapitel 5 Kontextfreie Sprachen Bisher hatten wir Automaten, die Wörter akzeptieren Frank Heitmann heitmann@informatik.uni-hamburg.de

Mehr

Universität Karlsruhe (TH)

Universität Karlsruhe (TH) Universität Karlsruhe (TH) Lehrstuhl für Programmierparadigmen prachtechnologie und Compiler W 2008/2009 http://pp.info.uni-karlsruhe.de/ Dozent: Prof. Dr.-Ing. G. nelting snelting@ipd.info.uni-karlsruhe.de

Mehr

Automaten und formale Sprachen. Lösungen zu den Übungsblättern

Automaten und formale Sprachen. Lösungen zu den Übungsblättern Automaten und formale Sprachen zu den Übungsblättern Übungsblatt Aufgabe. (Sipser, exercise.3) M = ({q, q2, q3, q4, q5}, {u, d}, δ, q3, {q3}) δ: u d q q q 2 q 2 q q 3 q 3 q 2 q 4 q 4 q 3 q 5 q 5 q 4 q

Mehr

Beschreibungskomplexität von Grammatiken Definitionen

Beschreibungskomplexität von Grammatiken Definitionen Beschreibungskomplexität von Grammatiken Definitionen Für eine Grammatik G = (N, T, P, S) führen wir die folgenden drei Komplexitätsmaße ein: Var(G) = #(N), Prod(G) = #(P ), Symb(G) = ( α + β + 1). α β

Mehr

Grundlagen der Theoretischen Informatik

Grundlagen der Theoretischen Informatik Grundlagen der Theoretischen Informatik Sommersemester 2015 23.04.2015 Viorica Sofronie-Stokkermans e-mail: sofronie@uni-koblenz.de 1 Bis jetzt 1. Terminologie 2. Endliche Automaten und reguläre Sprachen

Mehr

Einführung in die Informatik Grammars & Parsers

Einführung in die Informatik Grammars & Parsers Einführung in die Informatik Grammars & Parsers Grammatiken, Parsen von Texten Wolfram Burgard Cyrill Stachniss 12.1 Einleitung Wir haben in den vorangehenden Kapiteln meistens vollständige Java- Programme

Mehr

Von der Grammatik zum AST

Von der Grammatik zum AST Von der Grammatik zum AST Welche Eigenschaften soll ein Parser haben? Wann ist eine Grammatik eindeutig? Wie sollte eine Grammatik aussehen? Theoretischer Hin tergrund: FIRST, FOLLOW Einschränkungen von

Mehr

Programmierung WS12/13 Lösung - Übung 1 M. Brockschmidt, F. Emmes, C. Otto, T. Ströder

Programmierung WS12/13 Lösung - Übung 1 M. Brockschmidt, F. Emmes, C. Otto, T. Ströder Prof. aa Dr. J. Giesl Programmierung WS12/13 M. Brockschmidt, F. Emmes, C. Otto, T. Ströder Tutoraufgabe 1 (Syntax und Semantik): 1. Was ist Syntax? Was ist Semantik? Erläutern Sie den Unterschied. 2.

Mehr

Formale Sprachen und Grammatiken

Formale Sprachen und Grammatiken Formale Sprachen und Grammatiken Jede Sprache besitzt die Aspekte Semantik (Bedeutung) und Syntax (formaler Aufbau). Die zulässige und korrekte Form der Wörter und Sätze einer Sprache wird durch die Syntax

Mehr

2.11 Kontextfreie Grammatiken und Parsebäume

2.11 Kontextfreie Grammatiken und Parsebäume 2.11 Kontextfreie Grammatiken und Parsebäume Beispiel: Beispiel (Teil 3): Beweis für L(G) L: Alle Strings aus L der Länge 0 und 2 sind auch in L(G). Als Induktionsannahme gehen wir davon aus, dass alle

Mehr

Syntaxanalyse Ausgangspunkt und Ziel

Syntaxanalyse Ausgangspunkt und Ziel Syntaxanalyse Ausgangspunkt und Ziel Ausgangspunkt: Kontextfreie Grammatik Im Normalfall BNF, manchmal EBNF BNF = Backus-Naur-Form = Produktionsregeln EBNF = erweiterte BNF (+ reguläre Ausdrücke) Prüfung

Mehr

LL(k)-Analyse. (y) folgt α = β. (x) = start k. (=l> ist ein Linksableitungsschritt)

LL(k)-Analyse. (y) folgt α = β. (x) = start k. (=l> ist ein Linksableitungsschritt) LL(k)-Analyse Eine KFG G = (N,T,P,S) heisst LL(k)-Grammatik, wenn für alle w,x,y T*, α,β,σ (N U T)* und A N mit 1. S =l>* waσ =l> wασ =l>* wx, 2. S =l>* waσ = > wβσ =l>* wy, 3. start k (x) = start k (y)

Mehr

Grundbegriffe der Informatik

Grundbegriffe der Informatik Grundbegriffe der Informatik Einheit 8: kontextfreie Grammatiken Thomas Worsch Karlsruher Institut für Technologie, Fakultät für Informatik Wintersemester 2009/2010 1/37 Überblick Kontextfreie Grammatiken

Mehr

Übungsaufgaben zu Formalen Sprachen und Automaten

Übungsaufgaben zu Formalen Sprachen und Automaten Universität Freiburg PD Dr. A. Jakoby Sommer 27 Übungen zum Repetitorium Informatik III Übungsaufgaben zu Formalen Sprachen und Automaten. Untersuchen Sie das folgende Spiel: A B x x 2 x 3 C D Eine Murmel

Mehr

Sprachen und Programmiersprachen

Sprachen und Programmiersprachen Sprachen und Programmiersprachen Natürliche Sprachen versus Programmiersprachen / Spezifikationssprachen Syntax legt die grammatikalische Korrektheit fest. Semantik legt die Bedeutung von syntaktisch korrekten

Mehr

Theorie der Informatik

Theorie der Informatik Theorie der Informatik 6. Formale Sprachen und Grammatiken Malte Helmert Gabriele Röger Universität Basel 17. März 2014 Einführung Beispiel: Aussagenlogische Formeln Aus dem Logikteil: Definition (Syntax

Mehr

1. Der Begriff Informatik 2. Syntax und Semantik von Programmiersprachen. I.2. I.2. Grundlagen von von Programmiersprachen.

1. Der Begriff Informatik 2. Syntax und Semantik von Programmiersprachen. I.2. I.2. Grundlagen von von Programmiersprachen. 1. Der Begriff Informatik 2. Syntax und Semantik von Programmiersprachen I.2. I.2. Grundlagen von von Programmiersprachen. - 1 - 1. Der Begriff Informatik "Informatik" = Kunstwort aus Information und Mathematik

Mehr

Was bisher geschah: Formale Sprachen

Was bisher geschah: Formale Sprachen Was bisher geschah: Formale Sprachen Alphabet, Wort, Sprache Operationen und Relationen auf Wörtern und Sprachen Darstellung unendlicher Sprachen durch reguläre Ausdrücke (Syntax, Semantik, Äquivalenz)

Mehr

Umformung NTM DTM. Charakterisierung rek. aufz. Spr. Chomsky-3-Grammatiken (T5.3) Chomsky-0-Grammatik Rek. Aufz.

Umformung NTM DTM. Charakterisierung rek. aufz. Spr. Chomsky-3-Grammatiken (T5.3) Chomsky-0-Grammatik Rek. Aufz. Chomsky-0-Grammatik Rek. Aufz. Satz T5.2.2: Wenn L durch eine Chomsky-0- Grammatik G beschrieben wird, gibt es eine NTM M, die L akzeptiert. Beweis: Algo von M: Schreibe S auf freie Spur. Iteriere: Führe

Mehr

Theoretische Informatik I

Theoretische Informatik I Theoretische nformatik inheit 3 Kontextfreie Sprachen 1. Kontextfreie Grammatiken 2. Pushdown Automaten 3. igenschaften kontextfreier Sprachen Theoretische nformatik inheit 3.1 Kontextfreie Grammatiken

Mehr

Formale Sprachen. Script, Kapitel 4. Grammatiken

Formale Sprachen. Script, Kapitel 4. Grammatiken Formale Sprachen Grammatiken Script, Kapitel 4 erzeugen Sprachen eingeführt von Chomsky zur Beschreibung natürlicher Sprache bedeutend für die Syntaxdefinition und -analyse von Programmiersprachen Automaten

Mehr

Überführung regulärer Ausdrücke in endliche Automaten

Überführung regulärer Ausdrücke in endliche Automaten Der Algorithmus von Thompson Karin Haenelt 9.5.2010 1 Inhalt Quelle Prinzip des Algorithmus Algorithmus Konstruktion des Automaten Basisausdrücke Vereinigung, Konkatenation, Hülle Beispiel Implementierung

Mehr

Grundlagen der Theoretischen Informatik

Grundlagen der Theoretischen Informatik Grundlagen der Theoretischen Informatik Sommersemester 2016 20.04.2016 Viorica Sofronie-Stokkermans e-mail: sofronie@uni-koblenz.de 1 Bis jetzt 1. Terminologie 2. Endliche Automaten und reguläre Sprachen

Mehr

9 Theoretische Informatik und Compilerbau

9 Theoretische Informatik und Compilerbau 9 Theoretische Informatik und Compilerbau Theoretische Informatik und Mathematik schaffen die Basis für viele der technischen Entwicklungen, die wir in diesem Buch besprechen. Die boolesche Algebra (S.

Mehr

Theoretische Grundlagen des Software Engineering

Theoretische Grundlagen des Software Engineering Theoretische Grundlagen des Software Engineering 5: Reguläre Ausdrücke und Grammatiken schulz@eprover.org Software Systems Engineering Reguläre Sprachen Bisher: Charakterisierung von Sprachen über Automaten

Mehr

Grundlagen der Theoretischen Informatik

Grundlagen der Theoretischen Informatik Grundlagen der Theoretischen Informatik Sommersemester 2015 22.04.2015 Viorica Sofronie-Stokkermans e-mail: sofronie@uni-koblenz.de 1 Bis jetzt 1. Terminologie 2. Endliche Automaten und reguläre Sprachen

Mehr

Dank. 1 Ableitungsbäume. 2 Umformung von Grammatiken. 3 Normalformen. 4 Pumping-Lemma für kontextfreie Sprachen. 5 Pushdown-Automaten (PDAs)

Dank. 1 Ableitungsbäume. 2 Umformung von Grammatiken. 3 Normalformen. 4 Pumping-Lemma für kontextfreie Sprachen. 5 Pushdown-Automaten (PDAs) ank Vorlesung Grundlagen der Theoretischen Informatik / Einführung in die Theoretische Informatik I Bernhard Beckert iese Vorlesungsmaterialien basieren ganz wesentlich auf den Folien zu den Vorlesungen

Mehr

Programmiersprachen und Übersetzer

Programmiersprachen und Übersetzer Programmiersprachen und Übersetzer Sommersemester 2010 19. April 2010 Theoretische Grundlagen Problem Wie kann man eine unendliche Menge von (syntaktisch) korrekten Programmen definieren? Lösung Wie auch

Mehr

ARBEITSBLATT ZU FORMALEN SPRACHEN

ARBEITSBLATT ZU FORMALEN SPRACHEN ARBEITSBLATT ZU FORMALEN SPRACHEN Aufgabe 1: Gegeben ist die folgende Formale Sprache L(G) mit G = (T, N, P, S). Die Produktionen lauten ZUWEISUNG ::= name zuweisungsoperator AUSDRUCK semikolon AUSDRUCK

Mehr

Grundlagen der Informatik II. Teil I: Formale Modelle der Informatik

Grundlagen der Informatik II. Teil I: Formale Modelle der Informatik Grundlagen der Informatik II Teil I: Formale Modelle der Informatik 1 Einführung GdInfoII 1-2 Ziele/Fragestellungen der Theoretischen Informatik 1. Einführung abstrakter Modelle für informationsverarbeitende

Mehr

Lemma Für jede monotone Grammatik G gibt es eine kontextsensitive

Lemma Für jede monotone Grammatik G gibt es eine kontextsensitive Lemma Für jede monotone Grammatik G gibt es eine kontextsensitive Grammatik G mit L(G) = L(G ). Beweis im Beispiel (2.): G = (V,Σ, P, S) : P = {S asbc, S abc, CB BC, ab ab, bb bb, bc bc, cc cc}. (i) G

Mehr

Werkzeuge zur Programmentwicklung

Werkzeuge zur Programmentwicklung Werkzeuge zur Programmentwicklung B-15 Bibliothek Modulschnittstellen vorübersetzte Module Eingabe Editor Übersetzer (Compiler) Binder (Linker) Rechner mit Systemsoftware Quellmodul (Source) Zielmodul

Mehr

Fachseminar WS 2008/09

Fachseminar WS 2008/09 Fachseminar WS 2008/09 Fachgebiet: Compilerbau Thema: Lexikalische Analyse (Scanner) Referent: Ali Sediq Betreuer: Prof. Dr. Helmut Weber 1 Inhaltsverzeichnis Lexikalische Analyse 1.0 Grundprobleme der

Mehr

Rekursiv aufzählbare Sprachen

Rekursiv aufzählbare Sprachen Kapitel 4 Rekursiv aufzählbare Sprachen 4.1 Grammatiken und die Chomsky-Hierarchie Durch Zulassung komplexer Ableitungsregeln können mit Grammatiken größere Klassen als die kontextfreien Sprachen beschrieben

Mehr

Vorkurs Mathematik und Informatik Mengen, natürliche Zahlen, Induktion

Vorkurs Mathematik und Informatik Mengen, natürliche Zahlen, Induktion Vorkurs Mathematik und Informatik Mengen, natürliche Zahlen, Induktion Saskia Klaus 07.10.016 1 Motivation In den ersten beiden Vorträgen des Vorkurses haben wir gesehen, wie man aus schon bekannten Wahrheiten

Mehr

EINFÜHRUNG IN DIE THEORETISCHE INFORMATIK

EINFÜHRUNG IN DIE THEORETISCHE INFORMATIK EINFÜHRUNG IN DIE THEORETISCHE INFORMATIK Prof. Dr. Klaus Ambos-Spies Sommersemester 2011 17. DIE CHOMSKY-HIERARCHIE Theoretische Informatik (SoSe 2011) 17. Die Chomsky-Hierarchie 1 / 15 Einleitung Die

Mehr

7. Formale Sprachen und Grammatiken

7. Formale Sprachen und Grammatiken 7. Formale Sprachen und Grammatiken Computer verwenden zur Verarbeitung von Daten und Informationen künstliche, formale Sprachen (Maschinenspr., Assemblerspachen, Programmierspr., Datenbankspr., Wissensrepräsentationsspr.,...)

Mehr

JavaScript. Dies ist normales HTML. Hallo Welt! Dies ist JavaScript. Wieder normales HTML.

JavaScript. Dies ist normales HTML. Hallo Welt! Dies ist JavaScript. Wieder normales HTML. JavaScript JavaScript wird direkt in HTML-Dokumente eingebunden. Gib folgende Zeilen mit einem Texteditor (Notepad) ein: (Falls der Editor nicht gefunden wird, öffne im Browser eine Datei mit der Endung

Mehr

Informatik I WS 07/08 Tutorium 24

Informatik I WS 07/08 Tutorium 24 Info I Tutorium 24 Informatik I WS 07/08 Tutorium 24 20.12.07 Bastian Molkenthin E-Mail: infotut@sunshine2k.de Web: http://infotut.sunshine2k.de Rückblick Semi-Thue-Systeme Ein Semi-Thue-System besteht

Mehr

(Prüfungs-)Aufgaben zu formale Sprachen

(Prüfungs-)Aufgaben zu formale Sprachen (Prüfungs-)Aufgaben zu formale Sprachen (siehe auch bei den Aufgaben zu endlichen Automaten) 1) Eine Grammatik G sei gegeben durch: N = {S, A}, T = {a, b, c, d}, P = { (S, Sa), (S, ba), (A, ba), (A, c),

Mehr

Theoretische Grundlagen der Informatik

Theoretische Grundlagen der Informatik Theoretische Grundlagen der Informatik Vorlesung am 12.01.2012 INSTITUT FÜR THEORETISCHE 0 KIT 12.01.2012 Universität des Dorothea Landes Baden-Württemberg Wagner - Theoretische und Grundlagen der Informatik

Mehr

FORMALE SYSTEME. Sprachen beschreiben. Wiederholung. Wie kann man Sprachen beschreiben? 2. Vorlesung: Grammatiken und die Chomsky-Hierarchie

FORMALE SYSTEME. Sprachen beschreiben. Wiederholung. Wie kann man Sprachen beschreiben? 2. Vorlesung: Grammatiken und die Chomsky-Hierarchie Wiederholung FORMALE SYSTEME 2. Vorlesung: Grammatiken und die Chomsky-Hierarchie Markus Krötzsch Formale Sprachen sind in Praxis und Theorie sehr wichtig Ein Alphabet ist eine nichtleere, endliche Menge

Mehr

Musterlösung zur Hauptklausur Theoretische Grundlagen der Informatik Wintersemester 2013/14

Musterlösung zur Hauptklausur Theoretische Grundlagen der Informatik Wintersemester 2013/14 Institut für Theoretische Informatik Prof. Dr. Jörn Müller-Quade Musterlösung zur Hauptklausur Theoretische Grundlagen der Informatik Wintersemester 23/4 Vorname Nachname Matrikelnummer Hinweise Für die

Mehr

Einführung in die Theoretische Informatik

Einführung in die Theoretische Informatik echnische Universität München Fakultät für Informatik Prof. obias Nipkow, Ph.D. ascha öhme, Lars Noschinski ommersemester 2011 Lösungsblatt 5 6. Juni 2011 Einführung in die heoretische Informatik Hinweis:

Mehr

1. Erläutern Sie die Aufgaben von Datentypen in der imperativen Programmierung.

1. Erläutern Sie die Aufgaben von Datentypen in der imperativen Programmierung. 1. Erläutern Sie die Aufgaben von Datentypen in der imperativen Programmierung. Beschreiben Sie ferner je einen frei gewählten Datentyp aus der Gruppe der skalaren und einen aus der Gruppe der strukturierten

Mehr

Thomas Behr. 17. November 2011

Thomas Behr. 17. November 2011 in in Fakultät für Mathematik und Informatik Datenbanksysteme für neue Anwendungen FernUniversität in Hagen 17. November 2011 c 2011 FernUniversität in Hagen Outline in 1 2 3 4 5 6 - Was ist das? in über

Mehr

1. Gruppen. 1. Gruppen 7

1. Gruppen. 1. Gruppen 7 1. Gruppen 7 1. Gruppen Wie schon in der Einleitung erläutert wollen wir uns in dieser Vorlesung mit Mengen beschäftigen, auf denen algebraische Verknüpfungen mit gewissen Eigenschaften definiert sind.

Mehr

Programmieren I. Kapitel 5. Kontrollfluss

Programmieren I. Kapitel 5. Kontrollfluss Programmieren I Kapitel 5. Kontrollfluss Kapitel 5: Kontrollfluss Ziel: Komplexere Berechnungen im Methodenrumpf Ausdrücke und Anweisungen Fallunterscheidungen (if, switch) Wiederholte Ausführung (for,

Mehr

Kapitel 3: Reguläre Grammatiken und Endliche. Automaten

Kapitel 3: Reguläre Grammatiken und Endliche. Automaten Kapitel 3: Reguläre Grammatiken und Endliche Automaten Prof.-Dr. Peter Brezany Institut für Softwarewissenschaft Universität Wien, Liechtensteinstraße 22 090 Wien Tel. : 0/4277 38825 E-mail : brezany@par.univie.ac.at

Mehr

Strukturelle Rekursion und Induktion

Strukturelle Rekursion und Induktion Kapitel 2 Strukturelle Rekursion und Induktion Rekursion ist eine konstruktive Technik für die Beschreibung unendlicher Mengen (und damit insbesondere für die Beschreibung unendliche Funktionen). Induktion

Mehr

Theoretische Informatik I (Grundzüge der Informatik I)

Theoretische Informatik I (Grundzüge der Informatik I) Theoretische Informatik I (Grundzüge der Informatik I) Literatur: Buch zur Vorlesung: Uwe Schöning, Theoretische Informatik - kurzgefasst. Spektrum Akademischer Verlag, Heidelberg/Berlin, 4. Auflage, 2001.

Mehr

Formale Sprachen, reguläre und kontextfreie Grammatiken

Formale Sprachen, reguläre und kontextfreie Grammatiken Formale Sprachen, reguläre und kontextfreie Grammatiken Alphabet A: endliche Menge von Zeichen Wort über A: endliche Folge von Zeichen aus A A : volle Sprache über A: Menge der A-Worte formale Sprache

Mehr

Technische Universität Wien Institut für Computergraphik und Algorithmen Arbeitsbereich für Algorithmen und Datenstrukturen

Technische Universität Wien Institut für Computergraphik und Algorithmen Arbeitsbereich für Algorithmen und Datenstrukturen Technische Universität Wien Institut für Computergraphik und Algorithmen Arbeitsbereich für Algorithmen und Datenstrukturen 186.172 Algorithmen und Datenstrukturen 1 VL 4.0 Übungsblatt 4 für die Übung

Mehr

6 F O R M A L E S P R A C H E N. 6.1 formale sprachen

6 F O R M A L E S P R A C H E N. 6.1 formale sprachen 6.1 formale sprachen 6 F O R M A L E S P R A C H E N Eine natürliche Sprache umfasst mehrere Aspekte, z. B. Aussprache und Stil, also z. B. Wortwahl und Satzbau. Dafür ist es auch notwendig zu wissen,

Mehr

Welche Informatik-Kenntnisse bringen Sie mit?

Welche Informatik-Kenntnisse bringen Sie mit? Welche Informatik-Kenntnisse bringen Sie mit? So gehen Sie vor! Lösen Sie die Aufgaben der Reihe nach von 1 bis 20, ohne das Lösungsblatt zur Hilfe zu nehmen. Der Schwierigkeitsgrad der Aufgaben nimmt

Mehr

PHP 5.4 ISBN 978-3-86249-327-2. Stephan Heller, Andreas Dittfurth 1. Ausgabe, September 2012. Grundlagen zur Erstellung dynamischer Webseiten GPHP54

PHP 5.4 ISBN 978-3-86249-327-2. Stephan Heller, Andreas Dittfurth 1. Ausgabe, September 2012. Grundlagen zur Erstellung dynamischer Webseiten GPHP54 PHP 5.4 Stephan Heller, Andreas Dittfurth 1. Ausgabe, September 2012 Grundlagen zur Erstellung dynamischer Webseiten ISBN 978-3-86249-327-2 GPHP54 5 PHP 5.4 - Grundlagen zur Erstellung dynamischer Webseiten

Mehr

Einführung in die Informatik I (autip)

Einführung in die Informatik I (autip) Einführung in die Informatik I (autip) Dr. Stefan Lewandowski Fakultät 5: Informatik, Elektrotechnik und Informationstechnik Abteilung Formale Konzepte Universität Stuttgart 24. Oktober 2007 Was Sie bis

Mehr

Diskrete Strukturen Kapitel 2: Grundlagen (Beweise)

Diskrete Strukturen Kapitel 2: Grundlagen (Beweise) WS 2014/15 Diskrete Strukturen Kapitel 2: Grundlagen (Beweise) Hans-Joachim Bungartz Lehrstuhl für wissenschaftliches Rechnen Fakultät für Informatik Technische Universität München http://www5.in.tum.de/wiki/index.php/diskrete_strukturen_-_winter_14

Mehr

2. Symmetrische Gruppen

2. Symmetrische Gruppen 14 Andreas Gathmann 2 Symmetrische Gruppen Im letzten Kapitel haben wir Gruppen eingeführt und ihre elementaren Eigenschaften untersucht Wir wollen nun eine neue wichtige Klasse von Beispielen von Gruppen

Mehr

Theoretische Informatik 2 (WS 2006/07) Automatentheorie und Formale Sprachen 19

Theoretische Informatik 2 (WS 2006/07) Automatentheorie und Formale Sprachen 19 Inhalt 1 inführung 2 Automatentheorie und ormale prachen Grammatiken Reguläre prachen und endliche Automaten Kontextfreie prachen und Kellerautomaten Kontextsensitive und yp 0-prachen 3 Berechenbarkeitstheorie

Mehr

Deterministische endliche Automaten - Wiederholung

Deterministische endliche Automaten - Wiederholung Deterministische endliche Automaten - Wiederholung Die folgende Klasse Zahl stellt einen endlichen Automaten dar. Ermittle die Größen des Automaten und zeichne den Zustandsgraphen. Gib Zeichenfolgen an,

Mehr

7 Endliche Automaten. Reimund Albers Papierfalten Kapitel 7 Endliche Automaten 103

7 Endliche Automaten. Reimund Albers Papierfalten Kapitel 7 Endliche Automaten 103 Reimund Albers Papierfalten Kapitel 7 Endliche Automaten 103 7 Endliche Automaten Ein erstes Beispiel Ganz im Sinn der vorangegangenen Kapitel machen wir wieder Anleihen in einem wohl etablierten Gebiet.

Mehr

Kapitel 4: Syntaxdiagramme und Grammatikregeln

Kapitel 4: Syntaxdiagramme und Grammatikregeln 4. Syntaxdiagramme und Grammatikregeln 4-1 Objektorientierte Programmierung (Winter 2006/2007) Kapitel 4: Syntaxdiagramme und Grammatikregeln Syntaxdiagramme Grammatikregeln (kontextfrei) Beispiele: Lexikalische

Mehr

EINFÜHRUNG IN DIE THEORETISCHE INFORMATIK

EINFÜHRUNG IN DIE THEORETISCHE INFORMATIK EINFÜHRUNG IN DIE THEORETISCHE INFORMATIK Prof. Dr. Klaus Ambos-Spies Sommersemester 2012 17. DIE KONTEXTFREIEN SPRACHEN II: ABSCHLUSSEIGENSCHAFTEN, MASCHINENCHARAKTERISIERUNG, KOMPLEXITÄT Theoretische

Mehr

I.5. Kontextfreie Sprachen

I.5. Kontextfreie Sprachen I.5. Kontextfreie prachen Zieht man in Betracht, dass BNF-yteme gerade so beschaffen sind, dass auf der linken eite immer genau ein Nichtterminal steht, so sind das also gerade die Ableitungsregeln einer

Mehr

Formale Sprachen. Formale Grundlagen (WIN) 2008S, F. Binder. Vorlesung im 2008S

Formale Sprachen. Formale Grundlagen (WIN) 2008S, F. Binder. Vorlesung im 2008S Formale Grundlagen (WIN) Franz Binder Institut für Algebra Johannes Kepler Universität Linz Vorlesung im 2008S http://www.algebra.uni-linz.ac.at/students/win/fg Inhalt Das Alphabet Σ sei eine endliche

Mehr

Softwareparadigmen EXP-Compiler Dokumentation v1.1 ( )

Softwareparadigmen EXP-Compiler Dokumentation v1.1 ( ) Softwareparadigmen EXP-Compiler Dokumentation v1.1 (8.5.2016) Stephan Frühwirt Inhaltsverzeichnis 1 Aufbau, Tools und Ausführung 2 1.1 Ausführung....................................... 2 2 Sprachdefinition

Mehr

Einführung Grundbegriffe

Einführung Grundbegriffe Einführung Grundbegriffe 1.1 Der Modellbegriff Broy: Informatik 1, Springer 1998 (2) Die Modellbildung der Informatik zielt auf die Darstellung der unter dem Gesichtspunkt einer gegebenen Aufgabenstellung

Mehr

11.1 Kontextsensitive und allgemeine Grammatiken

11.1 Kontextsensitive und allgemeine Grammatiken Theorie der Informatik 7. April 2014 11. Kontextsensitive und Typ-0-Sprachen Theorie der Informatik 11. Kontextsensitive und Typ-0-Sprachen 11.1 Kontextsensitive und allgemeine Grammatiken Malte Helmert

Mehr

Theoretische Informatik. Grammatiken. Grammatiken. Grammatiken. Rainer Schrader. 9. Juli 2009

Theoretische Informatik. Grammatiken. Grammatiken. Grammatiken. Rainer Schrader. 9. Juli 2009 Theoretische Informatik Rainer Schrader Institut für Informatik 9. Juli 2009 1 / 41 2 / 41 Gliederung die Chomsky-Hierarchie Typ 0- Typ 3- Typ 1- Die Programmierung eines Rechners in einer höheren Programmiersprache

Mehr

Einfache Ausdrücke Datentypen Rekursive funktionale Sprache Franz Wotawa Institut für Softwaretechnologie wotawa@ist.tugraz.at

Einfache Ausdrücke Datentypen Rekursive funktionale Sprache Franz Wotawa Institut für Softwaretechnologie wotawa@ist.tugraz.at Inhalt SWP Funktionale Programme (2. Teil) Einfache Ausdrücke Datentypen Rekursive funktionale Sprache Franz Wotawa Institut für Softwaretechnologie wotawa@ist.tugraz.at Interpreter für funktionale Sprache

Mehr

JAVA-Datentypen und deren Wertebereich

JAVA-Datentypen und deren Wertebereich Folge 8 Variablen & Operatoren JAVA 8.1 Variablen JAVA nutzt zum Ablegen (Zwischenspeichern) von Daten Variablen. (Dies funktioniert wie beim Taschenrechner. Dort können Sie mit der Taste eine Zahl zwischenspeichern).

Mehr

Automaten und Formale Sprachen

Automaten und Formale Sprachen Automaten und Formale Sprachen Prof. Dr. Dietrich Kuske FG Theoretische Informatik, TU Ilmenau Wintersemester 2011/12 WS 11/12 1 Organisatorisches zur Vorlesung Informationen, aktuelle Version der Folien

Mehr

14. Rot-Schwarz-Bäume

14. Rot-Schwarz-Bäume Bislang: Wörterbuchoperationen bei binären Suchbäume effizient durchführbar, falls Höhe des Baums klein. Rot-Schwarz-Bäume spezielle Suchbäume. Rot-Schwarz-Baum mit n Knoten hat Höhe höchstens 2 log(n+1).

Mehr

Informatik I Übung, Woche 40

Informatik I Übung, Woche 40 Giuseppe Accaputo 2. Oktober, 2014 Plan für heute 1. Fragen & Nachbesprechung Übung 2 2. Zusammenfassung der bisherigen Vorlesungsslides 3. Tipps zur Übung 3 Informatik 1 (D-BAUG) Giuseppe Accaputo 2 Nachbesprechung

Mehr

6 Modellierung von Strukturen 6.1 Kontextfreie Grammatiken

6 Modellierung von Strukturen 6.1 Kontextfreie Grammatiken 6 Modellierung von Strukturen 6.1 Kontextfreie Grammatiken Mod-6.1 Kontextfreie Grammatik (KFG): formaler Kalkül, Ersetzungssystem; definiert Sprache als Menge von Sätzen; jeder Satz ist eine Folge von

Mehr