Eine Sprache ist diejenige wo
... der Umfang der Deklarationen (ein Block) in dieser Sprache wird durch ihre Einrückung ausgedrückt.
Beispiele für solche Sprachen sind Python, Boo, Nemerle, YAML und einige mehr.
Meine Frage ist also: Wie analysiere ich diese? Wie löse ich Probleme mit Tabs und Leerzeichen auf (sind zwei Tabs oder 8 Leerzeichen äquivalent oder nicht)? Sind Parsergeneratoren von irgendwelcher Hilfe hier oder muss ich Lexer / Parser selbst Hand-Code?
Python hat einen Lexer , der Indent und Dementent Tokens erzeugt, die geschweiften Klammern entsprechen ("{", "}") . Es gibt sogar ein Beispiel auf Stack Overflow mit eine einfache Implementierung eines solchen Lexers.
Für Registerkarten und Leerzeichen hat Python nur eine Codierung Konvention : Verwenden Sie vier Leerzeichen pro Einrückung Niveau. Tabs sind jedoch legale Syntax.
Wie löse ich Probleme mit Tabs und Leerzeichen auf (sind zwei Tabs oder 8 Leerzeichen äquivalent oder nicht)?
Es hängt davon ab, wie die Einstellungen des Editors aussehen, wenn zwei Registerkarten acht Leerzeichen enthalten.
Die Offside-Regel, wie sie vom Urheber angegeben wird, erwähnt die relative Positionierung zweier aufeinanderfolgender Codezeilen und nicht die absolute Anzahl der Leerzeichen. Hier ist eine nette Lektüre, die Ihnen hilft, (und einige Zitate) besser zu verstehen:
"Whitespace ist in Python von Bedeutung Quellcode. "
Nein, nicht allgemein. Nur der Einzugsebene Ihrer Aussagen ist signifikant (d. h. der Leerraum bei ganz links von Ihren Aussagen). Überall sonst ist Whitespace nicht signifikant und kann wie Sie verwendet werden wie in jeder anderen Sprache. Sie können auch leere Zeilen einfügen enthalten nichts (oder nur willkürlich Leerzeichen) überall.
Auch die genaue Höhe des Eindrucks spielt überhaupt keine Rolle, sondern nur die relative Einrückung von verschachtelten Blöcken (relativ zueinander). [...]
Der einfachste Weg, das Problem "Tabs versus Leerzeichen" aufzulösen, besteht darin, Kombinationen von Leerzeichen und Tabulatoren zu verbieten (dies geschieht beispielsweise in F #). Jeder moderne Editor ermöglicht die Umwandlung von Tabs in eine bestimmte Anzahl von Leerzeichen.
Ob Sie Parsergeneratoren aufgeben müssen, wahrscheinlich nicht, aber Sie müssen irgendwo die Identifikation der Abseits hacken. Dies kann ein wenig Kreativität auf Ihrer Seite erfordern. Basierend auf dem Durchsuchen der F # -Quelle sieht es so aus, als ob sie einen post-lexing-Schritt verwenden, um zusätzliche Token zu erstellen, die die sprachfernen Elemente darstellen.
Für was es sich lohnt, ist Haskell auch indentationsbasiert und optional {foo; Bar; usw.} für whitespace ist unbequem. Ich schrieb einen einfachen indentation-basierten Parser mit Parsec , es ist beabsichtigt, wie Lisp zu lesen, aber die Einrückung zeigt die Anwendung des Operators an. Klammern können nur in einer Zeile verwendet werden.
%Vor% Hier wird aaa
auf bb
angewendet. Was daraus resultiert, ist eine ternäre Funktion. Es wird auf die Argumente cc
, e
angewendet auf ein Argument und ddd
angewendet. Sehen Sie, wie die Anwendung auf Spaltenausrichtung basiert, und nicht auf X-Leerzeichen.
Der Parser könnte wahrscheinlich auch viel einfacher sein.
Sie haben mehrere Möglichkeiten w.r.t. Tabs und Leerzeichen: entweder das Mischen von Tabulatoren und Leerzeichen, das Annehmen eines festen Verhältnisses von Tabulatoren zu Leerzeichen oder das Erlauben des Programmierers, sich pro Projekt oder pro Quelldatei zu entscheiden (irgendeine Art von "#pragma tab (4)" -Stil-Anweisung zu) erlauben Tabs und / oder ändern die Anzahl der Räume, die sie darstellen).
Parser Generator wie ANTLR 3 kann leicht damit umgehen; Ich spielte selbst mit einem Beispiel und kompilierte zu seinem C # -Ziel. Der Link in DirkGentys Antwort erklärt den Python-Algorithmus, der übersetzt direkt in Code. Mein Ansatz bestand einfach darin, separate Token für Leerzeichen und Zeilenumbrüche zu definieren und die Funktion "Token ausgeben" zu überschreiben, die vom Lexer verwendet wurde, um zusätzliche Einzugs- / Gedrückt-Token im laufenden Betrieb einzufügen. Dies erwies sich als einfacher zu implementieren als andere Ansätze, die ich gesehen habe, welche die Funktion "get last token" überschreiben, aber beide funktionieren ziemlich gut.
Ich habe eine Lösung von mir selbst, die ich den Code genau wie Blöcke für den Schachtelbaum analysiere. Für den Teil der Klammern habe ich nur die normale Methode verwendet.
Hier ist dieser Parser: Ссылка
Tags und Links language-design indentation compiler-theory