Lexikalische Analyse (englisch Lexical Analysis, oft kurz Lexing oder Scanning) ist die erste Phase der Compiler-Pipeline: Sie zerlegt den Quelltext - einen Strom einzelner Zeichen - in eine Folge von Tokens, den Bausteinen der Programmiersprache.

Tokens: Die Bausteine der Sprache

Ein Token ist die kleinste bedeutungstragende Einheit eines Programms. Typische Token-Klassen sind:

  • Schlüsselwörter: if, while, return - feste Wörter mit fester Bedeutung.
  • Bezeichner: Namen von Variablen, Funktionen und Klassen, z. B. anzahl.
  • Literale: Zahlen (42, 3.14) und Zeichenketten ("Hallo").
  • Operatoren: +, -, ==, &&.
  • Begrenzer: {, }, (, ), ;.

Jeder Token trägt zusätzlich seinen Typ, seine Position (Zeile und Spalte) und oft den Originaltext - für gute Fehlermeldungen und spätere Phasen.

So arbeitet ein Lexer

Der Lexer (auch Scanner genannt) liest den Quelltext zeichenweise und wendet pro Schritt die passende Token-Regel an. Drei Dinge erledigt er nebenbei: Er überspringt Leerraum und Kommentare, er wendet das Prinzip des längsten Treffers (maximal munch) an - aus ++ wird nie + plus + - und er meldet unbekannte Zeichen als Fehler mit exakter Position. Das Ergebnis ist ein Tokenstrom, der an die nächste Phase übergeben wird.

Reguläre Ausdrücke und endliche Automaten

Token-Regeln lassen sich fast immer als reguläre Ausdrücke formulieren: Ein Bezeichner ist etwa [A-Za-z_][A-Za-z0-9_]*. Scanner-Generatoren wie Lex, Flex oder re2c übersetzen solche Regeln in einen deterministischen endlichen Automaten (DFA), der den Zeichenstrom in einem Zug durchläuft. Auch handgeschriebene Lexer arbeiten intern wie ein DFA - der Automat ist das mathematische Herz fast jedes Lexers.

Zusammenarbeit mit dem Parser

Der erzeugte Tokenstrom ist die Eingabe des Parsers, der daraus die Programmstruktur - den Syntaxbaum - aufbaut. Die Arbeitsteilung ist klar: Der Lexer erkennt einzelne Wörter und Symbole, der Parser prüft die Syntax, also ob die Reihenfolge der Tokens der Grammatik entspricht. Diese Trennung hält beide Phasen einfach. Alternativen ohne eigene Lexer-Phase (Scannerless Parsing) existieren, sind aber seltener.

Handgeschrieben oder generiert?

Manuelle Lexer sind flexibel, leicht verständlich und liefern präzise Fehlermeldungen - die meisten modernen Compiler (etwa GCC, Clang, Rust) bauen sie von Hand. Generierte Lexer (Flex, re2c) sind dagegen schnell zu pflegen und sehr schnell zur Laufzeit; sie dominieren bei kleinen Werkzeugen und Prototypen. In JIT-Compilern sind handgeschriebene Lexer üblich, weil sie wenig Platz brauchen und gut in den Rest der Laufzeitumgebung integriert werden können. Compiler und Interpreter teilen sich diese erste Phase - beide müssen den Quelltext zuerst in Tokens zerlegen, bevor sie ihn verarbeiten.

Hinweis: Die Tokens eines Lexers haben nichts mit den Tokens moderner Sprachmodelle gemein - KI-Tokens sind statistisch ermittelte Teilwörter, keine festen Sprachbausteine. Die Namensgleichheit ist reiner Zufall.

Verwandte Grundlagen: Parser, Syntaxbaum, Syntax, Compiler, Interpreter, Regex-Befehle.