Ziel ist es, einen Präprozessor für die C-Sprache zu erstellen, der hinsichtlich der Quellcodegröße in Byte so klein wie möglich ist und in der von Ihnen bevorzugten Sprache vorliegt . Seine Eingabe ist eine C-Quelldatei, und seine Ausgabe ist der vorverarbeitete Quellcode.
Folgende Elemente müssen verarbeitet werden können: Entfernen von Kommentaren (Zeile / Block), # include-Anweisungen (durch Öffnen von Dateien in relativen Pfaden und Ersetzen von Text an der erforderlichen Stelle), #define, #undef, #if, #elif, #else, #endif, #ifdef, #ifndef und defined (). Andere C-Präprozessor-Direktiven wie #pragmas oder #errors werden möglicherweise ignoriert.
Es ist nicht erforderlich, arithmetische Ausdrücke oder Vergleichsoperatoren in # if-Direktiven zu berechnen. Wir gehen davon aus, dass der Ausdruck als wahr ausgewertet wird, solange er eine Ganzzahl ungleich Null enthält (seine Hauptverwendung liegt bei der defined () -Direktive). Es folgen Beispiele für mögliche Ein- und Ausgaben (mögliche zusätzliche Leerzeichen in Ausgabedateien wurden für eine bessere Darstellung gekürzt, Ihr Code muss dies nicht tun). Ein Programm, das die folgenden Beispiele ordnungsgemäß verarbeiten kann, wird als ausreichend angesehen.
----Input file: foo.c (main file being preprocessed)
#include "bar.h" // Line may or may not exist
#ifdef NEEDS_BAZZER
#include "baz.h"
#endif // NEEDS_BAZZER
#ifdef _BAZ_H_
int main(int argc, char ** argv)
{
/* Main function.
In case that bar.h defined NEEDS_BAZ as true,
we call baz.h's macro BAZZER with the length of the
program's argument list. */
return BAZZER(argc);
}
#elif defined(_BAR_H_)
// In case that bar.h was included but didn't define NEEDS_BAZ.
#undef _BAR_H_
#define NEEDS_BARRER
#include "bar.h"
int main(int argc, char ** argv)
{
return BARRER(argc);
}
#else
// In case that bar.h wasn't included at all.
int main()
{return 0;}
#endif // _BAZ_H_
----Input file bar.h (Included header)
#ifndef _BAR_H_
#define _BAR_H_
#ifdef NEEDS_BARRER
int bar(int * i)
{
*i += 4 + *i;
return *i;
}
#define BARRER(i) (bar(&i), i*=2, bar(&i))
#else
#define NEEDS_BAZZER // Line may or may not exist
#endif // NEEDS_BARRER
#endif // _BAR_H_
----Input file baz.h (Included header)
#ifndef _BAZ_H_
#define _BAZ_H_
int baz(int * i)
{
*i = 4 * (*i + 2);
return *i;
}
#define BAZZER(i) (baz(&i), i+=2, baz(&i))
#endif // _BAZ_H_
----Output file foopp.c (no edits)
int baz(int * i)
{
*i = 4 * (*i + 2);
return *i;
}
int main(int argc, char ** argv)
{
return (baz(&argc), argc+=2, baz(&argc));
}
----Output file foopp2.c (with foo.c's first line removed)
int main()
{return 0;}
----Output file foopp3.c (with bar.h's line "#define NEEDS_BAZZER" removed)
int bar(int * i)
{
*i += 4 + *i;
return *i;
}
int main(int argc, char ** argv)
{
return (bar(&argc), argc*=2, bar(&argc));
}
#if
muss unterstützt werden? dh muss der Präprozessor Ausdrücke mit arithmetischen, bitweisen Operationen usw. unterstützen?Antworten:
Flex, 1170 + 4 = 1174
1170 Zeichen im Flexcode + 4 Zeichen für ein Kompilierungsflag. Führen Sie aus, um eine ausführbare Datei zu erstellen
flex pre.l ; gcc lex.yy.c -lfl
.Der Eintrag verliert den Speicher wie ein Sieb und schließt eingeschlossene Dateien nicht.Ansonsten sollte es jedoch gemäß der Spezifikation voll funktionsfähig sein.Einige Erklärungen:
a
undb
sind Temps, um Strings von der Eingabe zu halten.a
wird auch als Parameter für die Funktion verwendetf
.v
V
Enthält die Namen von Makros und die 'V'-Werte von Makrost
undT
sind 't'emporary Inhaber für, wenn wir wachsenv
undV
i
ist ein i'ncrementer für Loopss
ist die Größe des Makro-Arrayso
ist die Anzahl der offenen Stellenif
in einer falschen Bedingungg()
'g'rows die Makro-Arraysf()
'f'indet ein Makro mit demselben Wertv
wiea
d(y)
'd'rops die letzteny
Zeichen aus der aktuellen EingabeD
steht für inside a 'D'efineF
dient zum Ignorieren einer 'F'-BedingungI
ist für 'I'gnoringelse
/elif
nachdem eine echte Bedingung gefunden wurde.EDIT1: Bereinigt viele Speicherlecks und implementiert das Schließen von Dateien
EDIT2: Code geändert, um verschachtelte Makros korrekter zu behandeln
EDIT3: unglaublich viel Golf
EDIT4: mehr Golf
EDIT5: mehr Golfen; Mir ist auch aufgefallen, dass mein Aufruf von fclose () auf einigen Computern Probleme verursacht.
quelle
#include
ausgegeben, aber ich denke, dies hängt mit dem Fehler in Bearbeitung 5 zusammen. Außerdem ersetzt es keine Makros, obwohl es die # if-Blöcke erfolgreich verarbeitet - es sei denn, ich mache etwas falsch ... aber im Allgemeinen sieht es sehr gut aus und es gibt eine ungefähre Vorstellung davon, was ein Lexer seitdem tun kann Ich kann es sogar in seiner Golfform verstehen. Versuchen Sie zu sehen, ob die Fehler behoben werden können. Wenn dies nicht in Ordnung ist, wie der Code selbst gut erklärt, wird dies wahrscheinlich als Antwort gewählt, da es keine anderen Einträge gibt.