Scannen mit Perl (Lexer)

Scanner
Mit Perl einen Scanner zu schreiben, ist eine einfache Sache, denn Perl hat eine sehr potente Implementierung für reguläre Ausdrücke. Allerdings muss man wissen, welche Modifier erforderlich sind, damit der Lexer auch immer an der Stelle weitermacht, wo er aufgehört hat. Dazu benutzt man den Pattern Matcher mit dem Modifier /g und startet jedes Matching mit dem Anker \G. Durch /g wird erreicht, daß Perl sich die aktuelle Scanposition merkt und mit \G verlangen wir, das bei der nächsten Mustererkennung genau an dieser Stelle weitergemacht werden soll.
Zusätzlich muss der Modifier /c angegeben werden, damit Perl die Position auch dann behält, wenn ein matching-Versuch scheitert und deswegen ein anderes Pattern versucht werden soll (was der häufigste Fall sein wird). Die weiteren Modifier, die verwendet werden sind /s , damit der Scanner mit einem Text umgeht, als wäre es eine einzelne Zeile und manchmal /i, damit “case-insensitiv” gescannt wird.
Von einem Lexer erwarten wir, daß er einen String in Tokens zerlegt und bei jedem Aufruf das nächste erkannte Token zurückgibt. Außerdem brauchen wir von jedem Token das gescannte Lexem. Bei jedem Aufruf bekommen wir also zwei Werte. Wird zum beispiel des Schlüsselwort “select” erkannt, bekommen wir das Wertepaar ['KEYW' , 'select'] geliefert.
Hier also die Implemetierung eines Fragmentes eines SQL-Scanners Das Lexen übernimmt die sub lex. Darunter eine Schleife, die die Ergebnisse ausgibt.
use strict; $_ = <<EOT; select name,alter FROM person where name like \'Kaz%mir\' and alter>20; EOT sub lex { /\G(\s+)/gcs; # spaces wegfuttern. return [$1,'OP'] if /\G"([\*\+\-\/]*)"/gcs; return [uc($1),'KEYW'] if /\G(from|like|select|where)/gcsi; return [$1,'COMM'] if /\G(\,)/gcs; return [$1,'SEMI'] if /\G(\;)/gcs; return [$1,'COMP'] if /\G(>|<|>=|<=|=)/gcs; return [$1,'STRI'] if /\G'([^']*)'/gcs; return [$1,'IDEN'] if /\G([a-zA-Z_]+)/gcs; return [$1,'INTE'] if /\G(\d+)/gcs; return undef if /\G$/; die "lexer error at '",substr(substr($_,pos($_)),0,60),"'"; } while (my $t = lex) { print "$t->[1] '$t->[0]' ",pos(),"\n"; }
Das hier vorgestellte Vorgehen ist einfach zu überblicken und der Scanner arbeitet schnell. Wie man einen einfachen Recursive-Descent-Parser dazu baut, werde ich eventuell ebenfalls einmal hier notieren.
uxpp aejbd free porn videos yrftgv q mj q psa