Parser Combinators

Eher durch Zufall bin ich letztens auf einen auch sehr interessanten Ansatz für einen Parsing Algorithmus gekommen, der mal so gar nichts mit dem was ich bisher so gemacht habe zu tun hat: Parser Combinators.

Die Idee dahinter: Man definiert Anstatt einer Grammatik mehrere, ineinander verschachtelte Mini-Parser, wobei ein Parser entweder ein Zeichen absorbiert (LIT, CCL) oder aber mehrere Parser entsprechend so Kombiniert, das man damit Alternativen (OR), Sequenzen (AND, SEQ) und semantische Operationen (JOIN) umsetzen kann. Der Aufruf der Funktionen definiert dann also die syntaktikalische Struktur, und es werden entsprechende Ergebnisse zurückgeliefert.

Sehr schön ist das ganze z.B. hier von Daniel Holden erklärt. Auf Basis dieses Blog-Eintrags habe ich mal einen Ansatz für eine Parser Combinator Library in Python in unter 100 Zeilen programmiert.

Es ist verblüffend: Man erhält bereits aus der Eingabe 1337+42*23+5 die Ausgabe
[‘1337’, ‘+’, [[’42’, ‘*’, ’23’], ‘+’, ‘5’]], was ja quasi schon einem Syntaxbaum entspricht.

Daniel hat auch die C-Library mpc (Micro Parser Combinators) geschrieben, welche das ganze für C umsetzt. Und da wären wir schon wieder beim nächsten Problem: Die Sache ist eigentlich so elegant, das ich mir wieder die Frage stelle, ob die ganze Arbeit die ich bisher in die Phorward Library gesteckt habe es überhaupt noch Wert ist… oder ob man vielleicht sich einfach aus Spaß lieber damit beschäftigen sollte. Ernstaft nutzen würde es sowieso keiner, das musste ich ja schon inzwischen mehrfach schmerzlich feststellen. Aber naja, vielleicht muss man sich dabei einfach mal von dem Gedanken trennen, mit sowas erfolgreich zu sein… oder was heißt erfolgreich sein, es hat Spaß gemacht das zu programmieren, aber wenn es keiner nutzt und es eigentlich gar keinen Nutzen hat ausser das es einfach da ist und nicht genutzt wird, das ist irgendwie extrem demotivierend und ärgerlich.

Es gibt natürlich auch Paper dazu, wie man Parser Combinators sogar generalisiert hinbekommt. Also sozusagen das, was ich bereits mit GLR parsing mal im Ansatz versucht hatte zu verstehen (und kläglich gescheitert bin), nur eben genau anders herum (GLL).

Vielversprechende Papers dazu:

Denn wie auch Fefe in seinem Blog letztens schrieb, und was auch auf mich persönlich sehr stark zutrifft, und ich mit libphorward, UniCC, JS/CC, pynetree und min_lalr1 inzwischen eigentlich bis zur Gänze ausgereizt haben sollte:

Ich habe meine libc auch nicht geschrieben, damit ich eine libc habe (obwohl das ein schöner Seiteneffekt ist). Ich habe die geschrieben, damit ich das Problemumfeld verstanden habe. Und das habe ich jetzt. Genau so mit dem Webserver und dem LDAP-Server. Du merkst, ob du etwas verstanden hast, wenn du es jemand anderem erklären konntest. Und Programmieren ist ja am Ende wie jemand anderem was erklären, nur dass derjenige sehr maschinenlesbare Erklärungen braucht. 🙂

Ich treffe immer wieder Leute, die denken, man programmiert Open Source-Software, um Teil einer Community zu sein. Oder um am Ende die Software zu haben. Nein. Du programmierst, damit du am Ende das Problem verstanden hast.

Ich habe in meiner Karriere ein-zwei Mal Quellcode bei Plattenausfällen oder versehentlichem Löschen verloren. Das fühlt sich an wie eine Katastrophe, ist es aber nicht. Wenn du für die erste Version ein Jahr brauchtest, geht das nochmal hinschreiben in 1-2 Monaten. Denn diesmal hast du ja das Problemfeld verstanden. DAS ist die eigentliche Währung im Leben. Problemfelder verstanden haben.

Na denn… vielleicht auf zu neuen Ufern, und den Kram nun mal hinter sich lassen?