100 likes | 214 Views
Lexikalische Analyse mit Lex. 05.05.2000, Martin Schneider. Vom regulären Ausdruck zum Programm. Reguläre Sprachen sind am einfachsten mit Hilfe von regulären Ausdrücken zu spezifizieren.
E N D
Lexikalische Analyse mit Lex 05.05.2000, Martin Schneider
Vom regulären Ausdruck zum Programm • Reguläre Sprachen sind am einfachsten mit Hilfe von regulären Ausdrücken zu spezifizieren. • Die Erkennung von regulären Sprachen läßt sich am einfachsten über die Transitionstabelle eines DFA programmieren. Nach der bisher geleisteten Theorie empfiehlt sich also folgende Vorgehensweise : Spezifikation mittels regulärer Ausdrücke 1. Konstruktion eines entsprechenden NFA 2. Konstruktion eines äquivalenten DFA 3. Zustandsminimalisierung 4. Tabellengesteuertes Programm 5.
Anwendungen regulärer Sprachen • Natürliche Sprachen wie auch Programmiersprachen sind zweistufig aufgebaut: • aus Zeichen bildet man Worte • aus Worten bildet man Sätze Deutsch Die Menge aller Worte, WDeutsch, ist eine Sprache über = { a, ... ,z,A, ... ,Z,ä,ö,ü,ß}. Diese Sprache ist endlich * ( Inhalt des Duden + Deklinationen und Konjugationen ) PASCAL Die Menge aller Worte, WPascal, ist eine Sprache über = { a, ... ,z,A, ... ,Z,_, 0,1, ..., 9, *, + , / ,( , ), <, >, =, [ , ] , ‘ , : , ; , . , ^, $ }. Diese Sprache ist unendlich . Insbesondere gilt : WPascalVariablennamen Zahlenkonstanten *wenn man von deutschen Wortungetümzusammensetzungsunsitten absieht
Lexikalische Analyse - Scanner • Die Menge aller Wörter einer Sprache heißt “lexikalischer Anteil” der Sprache. Bei natürlichen Sprachen ist er regulär. • Programmiersprachen werden so entworfen, daß der lexikalische Anteil eine reguläre Sprache ist. Deutsch Ein Automat, der den lexikalischen Teil einer natürlichen Sprache erkennt, heißt “Spelling Checker”. Für eine eventuelle automatische Übersetzung müßten die Worte noch klassifiziert werden, z.B. in Artikel, Nomen, Verb, Adjektiv, Adverb, Pronomen, RelPron, ... PASCAL Ein Automat, der den lexikalischen Teil einer Programmiersprache erkennt, heißt “Scanner”. Ein Scanner klassifiziert darüberhinaus noch die erkannten Worte. Jeder Klasse wird ein “Token” zugeordnet. Beispiele für Pascal Token sind : Identifier, Numeral, BEGIN, END, := , IF, WHILE, REPEAT, UNTIL, BinOp, UnOp, RelOp, Komma, Klammerauf, Klammerzu, etc.
Scanner-Generator • Ein Scanner-Generator ist ein Programm, das aus einer regulären Sprachbeschreibung einen diese Sprache erkennenden Scanner automatisch generiert. Ein bekannter Scanner-Generator ist “lex”. • Ein Scanner Generator führt automatisch die folgenden Schritte durch : Lese die reguläre Beschreibung der Sprache. (Prüfe auf syntaktische Korrektheit der regulären Beschreibung.) 1 Erzeuge den entsprechenden NFA. 2 Erzeuge den äquivalenten DFA. 3 4 Minimiere die Zustände des DFA Erzeuge die Scannertabelle 5 Erzeuge Programm-Code anhand dieser Tabelle. 6
lex * • lex ist ein Scanner Generator, der aus einer regulären Beschreibung der lexikalischen Bestandteile automatisch einen Scanner generiert. • Zu jedem Sprachbestandteil können beliebige Aktionen (in C-Code) spezifiziert werden. Beim Scannen von Programmiersprachen will man meist das dem erkannten Wort zugeordnete Token zurückgeben. In einem ersten Teil können Buchstabenklassen und Abkürzungen definiert werden. # Buchstabenklassen und Abkürzungen letter [a-zA-Z] digit [0-9] digits digit+ %% # reguläre Ausdrücke mit Aktionen : {letter}({letter}|{digit}|_)* return(identifier) ; “:=“ return(assign); (“+”|“*”|“/”) return(binop); (=|<>|<=|>=) return(RelOp) ; etc. ... * Die bessere GNU-Variante heißt flex.
lex(2) lexkann ebenso für die Erkennung natürlicher Sprachen eingesetzt werden. Nach der Buchstabierprüfung können Wörter auch grammatikalisch klassifiziert werden. #define ARTIKEL 0 #define NAME 1 .. etc. .. %% # lex Definition fuer BabyDeutsch [dD](er|ie|as) return(ARTIKEL); (Papa|Mama|Ich) return(NAME); [A-Z][a-z]* return(HAUPTWORT); (ist|hat) return(AUX); [a-z]+ return(VERB); “.” return(PUNKT); Deklaration von C-Konstanten für ein Stand-Alone- Programm not- wendig. Meist wird lex aber in Kombination mit yacc/bison ein- gesetzt. Dann entfällt diese C-Deklaration.
lex- Benutzung C-Datei “lex.yy.c” Reguläre Sprachbe- schreibung flex gcc • lex erzeugt aus dem Inputfile ein File “lex.yy.c”, welches die Scannerroutinen enthält. Mit dem Befehl “gcc lex.yy.c -ll” kompiliert man dieses zu dem fertigen Scanner. • Meist aber beschreibt “lex.yy.c” nur den ersten Teil eines Compilers, die lexikalische Analyse. Klassifizierung : “Papa ist doof.” scanner für BabyDeutsch NAME AUX VERB PUNKT
Andere Anwendungen von lex In den Aktionen können beliebige C-Anweisungen stehen. Beispiel : Das durch die folgende lex-Definition erzeugte Programm - wandelt alle Gross- in Kleinbuchstaben um, - entfernt alle Leerzeichen am Zeilenende, - ersetzt aufeinanderfolgende Leerzeichen durch ein einzelnes. # Dies ist das file “lower.lxi” %% [A-Z] putchar(yytext[0]+’a’-’A’) ; [ ]+$ ; [ ]+ putchar(‘ ‘) ; %% > lex lower.lxi > gcc lex.yy.c -ll > mv a.out prog Erzeuge C-file lex.yy.c Compiliere mit Option Benenne um Benutzung : prog < inputfile > outputfile
Ein Beispiel - HTML Wie lautet der Titel von einem HTML-Dokument? <html> <head> <title>Meine Homepage</title> </head> <body background=„me.jpg“> <table BORDER=10 CELLSPACING=10 CELLPADDING=10> <tr> <td VALIGN=TOP> <h2>Dipl.-Inf. Martin Schneider</h2> <p> Wissenschaftlicher Mitarbeiter (Landesstelle) </p> </td> </tr> </table> </body> </html>