Lässt es sich mit cremefarbenem Papier, einer Tönung, mehr Kontrast oder größerer Schrift besser lesen? Wählen Sie Ihre Farben und Ihre Schrift, einmalig für alle Seiten.

Kostenlose Lektion

Fehler finden, die der Parser übersieht (Semantik)

Nach dieser Lektion: Ich kann die Fehler finden, die ein Parser nicht findet.

Lektion, 55 Min.13 BefehleLab für Compilerbau und Rechnerarchitektur: gcc, flex, bison und RISC-V in einer VM

Ein Satz ohne Sinn

Eine Hausverwaltung rechnet Heizkosten mit einem kleinen Skript ab. Die letzte Zeile lautet zeige gesamt + anteil. Die Grammatik hat nichts dagegen, jedes Token passt.

Aber anteil gab es nur in einer Schleife, die längst vorbei ist. Ein Parser prüft die Form eines Satzes, nicht seinen Sinn. Den Sinn prüft der nächste Teil des Compilers.

Am Ende dieser Lektion

Notiz

Ich kann die Fehler finden, die ein Parser nicht findet.

Schlüsselwörter

BegriffWas er bedeutetBeispiel
Semantische Analysedie Prüfung, ob ein Programm Sinn ergibt
Deklarationdie Zeile, die einen Namen einführtint step
Gültigkeitsbereichder Teil eines Programms, in dem ein Name existiert
Symboltabelledie Liste des Compilers mit den gültigen Namen
Typwelche Art Wert etwas enthältint
Warnungeine Meldung, die den Build nicht stoppt

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Der Compiler führt eine Liste der Namen

Während der Compiler den Syntaxbaum durchläuft, führt er eine Symboltabelle. Jedes { legt einen neuen Gültigkeitsbereich oben auf. Jede Deklaration trägt einen Namen in den obersten Bereich ein. Jedes } wirft den obersten Bereich weg.

Für einen Namen sucht der Compiler zuerst oben, dann im Bereich darunter, und so weiter. Ein Name, der nirgends steht, ist nicht deklariert. Die Befehle zeigen, wo step in scope.c lebt.

In den Ordner compiler wechseln

Befehl
cd ~/compiler

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Jede Zeile, in der step vorkommt

Befehl
grep -n "step" scope.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Beispiel: die Symboltabelle von scope.c

ZeileWas passiertGültige Namen
4 und 5main deklariert unused und totalunused, total
6Die Schleife öffnet einen Bereich und deklariert iunused, total | i
7Der Schleifenrumpf deklariert stepunused, total | i | step
9Die Schleife endet, ihre Bereiche fallen wegunused, total
10printf benutzt step: nicht gefundenunused, total

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Ohne zusätzliche Prüfungen kompilieren

Befehl
gcc -c scope.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Jetzt die üblichen Warnungen verlangen

Befehl
gcc -Wall -c scope.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Aufrufe müssen zur Deklaration passen

Der Compiler kennt auch die Deklaration jeder Funktion. square nimmt genau ein Argument vom Typ int. Bei jedem Aufruf vergleicht er Anzahl und Typ.

Die Befehle erzeugen zwei Kopien von hello.c, das Original bleibt unberührt. zuviel.c ruft square(7, 8) auf. typfehler.c ruft square("7") auf: Ein Text in Anführungszeichen ist in C kein int, sondern ein char *.

Eine Kopie mit zwei Argumenten

Befehl
sed 's/square(7)/square(7, 8)/' hello.c > zuviel.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Die Kopie kompilieren

Befehl
gcc -Wall -c zuviel.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Eine Kopie mit falschem Typ

Befehl
sed 's/square(7)/square("7")/' hello.c > typfehler.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Auch diese Kopie kompilieren

Befehl
gcc -Wall -c typfehler.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Fehler stoppen den Build, Warnungen nicht

Die nächste Kopie, format.c, verlangt von printf zwei Zahlen und gibt ihm nur eine. gcc weiß, wie printf sein Format liest, und kann deshalb zählen.

Diesmal kommt nur eine Warnung. Der Build läuft weiter, und ls zeigt, dass format.o geschrieben wurde. Nach einem Fehler entsteht dagegen gar keine Objektdatei.

Eine Kopie, der eine Zahl fehlt

Befehl
sed 's/is %d/is %d %d/' hello.c > format.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Diese Kopie kompilieren

Befehl
gcc -Wall -c format.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Wurde eine Objektdatei geschrieben?

Befehl
ls format.o

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Ein häufiger Fehler

Warnung

Viele glauben, eine Warnung lässt sich übergehen, weil das Programm trotzdem gebaut wird. Eine Warnung heißt: Das ist erlaubt, aber sehr wahrscheinlich falsch. format.c lässt sich bauen und gibt dann eine Zahl aus, die niemand übergeben hat. Lesen Sie jede Warnung und behandeln Sie sie als Fehler, bis Sie wissen, warum sie harmlos ist.

Python prüft erst während des Laufs

C prüft Namen und Typen, bevor das Programm läuft. Das heißt statische Prüfung. Python prüft sie erst, wenn die Zeile ausgeführt wird. Der Fehler erscheint also genau in diesem Moment.

Beide Befehle unten starten das Programm. Keiner der Fehler fällt auf, bevor Python die Stelle erreicht.

Ein Name, den Python nie gesehen hat

Befehl
python3 -c "print(summe)"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Die Länge einer Zahl

Befehl
python3 -c "print(len(5))"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Weiterführend

Ergänzen Sie Ihre Prüfung um eine zweite Liste, unbenutzt. Sie meldet jeden Namen, der deklariert und nie benutzt wurde, mit der Zeile seiner Deklaration.

Prüfen Sie sie an PROGRAMM mit einer zusätzlichen ersten Zeile sei rest = 1. Erklären Sie dann, warum gcc unused nur mit -Wall meldet, step aber immer.

Über dieses Lab und seinen Quellcode: Lab für Compilerbau und Rechnerarchitektur: gcc, flex, bison und RISC-V in einer VM

Sie unterrichten eine Gruppe? Weisen Sie dieses Modul Ihren Studierenden zu, mit Handbuch für Lehrende, automatisch geprüften Aufgaben und einem Lab für jede Person.