L'objectif est de créer un préprocesseur pour le langage C, aussi petit que possible en termes de taille de code source en octets , dans votre langue préférée. Son entrée sera un fichier source C et sa sortie sera le code source prétraité.
Les éléments qu'il devra être en mesure de traiter seront: la suppression des commentaires (ligne / bloc), les directives #include (en ouvrant les fichiers aux chemins relatifs et en remplaçant le texte au point requis), #define, #undef, #if, #elif, #else, #endif, #ifdef, #ifndef et defined (). D'autres directives de préprocesseur C comme #pragmas ou #errors peuvent être ignorées.
Il n'est pas nécessaire de calculer des expressions arithmétiques ou des opérateurs de comparaison dans les directives #if, nous supposons que l'expression sera évaluée à true tant qu'elle contient un entier différent de zéro (son utilisation principale sera pour la directive defined ()). Des exemples d'entrées et de sorties possibles suivent (les éventuels espaces blancs supplémentaires dans les fichiers de sortie ont été coupés pour une meilleure apparence, il n'est pas nécessaire que votre code le fasse). Un programme capable de traiter correctement les exemples suivants sera considéré comme suffisant.
----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
besoins doivent être pris en charge? c'est-à-dire que le préprocesseur doit prendre en charge les expressions avec des opérations arithmétiques, au niveau du bit, etc.?Réponses:
Flex, 1170 + 4 = 1174
1170 caractères dans le code flexible + 4 caractères pour un indicateur de compilation. Pour produire un exécutable, exécutez
flex pre.l ; gcc lex.yy.c -lfl
.L'entrée fuit la mémoire comme un tamis et ne ferme pas les fichiers inclus.Mais sinon, il devrait être complètement fonctionnel selon les spécifications.Quelques explications:
a
etb
sont des temps pour maintenir les chaînes de l'entrée.a
est également utilisé comme paramètre pour fonctionnerf
.v
contient les noms des macros etV
contient les valeurs «V» des macrost
etT
sont des détenteurs temporaires pour quand nous grandissonsv
etV
i
est un 'i'ncrementer pour les boucless
est la taille du tableau de macroo
est le nombre de 'o'penif
s dans un faux conditionnelg()
'g'rows les macro tableauxf()
'f' trouve une macro avec la même valeurv
que asa
d(y)
'supprime les derniersy
caractères de l'entrée actuelleD
est pour l'intérieur d'un 'D'efineF
est pour ignorer une conditionnelle «F»I
est pour 'I'gnoringelse
/elif
après qu'un vrai conditionnel a été trouvé.EDIT1: nettoyé de nombreuses fuites de mémoire et implémenté la fermeture de fichiers
EDIT2: code modifié pour gérer plus correctement les macros imbriquées
EDIT3: une quantité folle de golf
EDIT4: plus de golf
EDIT5: plus de golf; J'ai également remarqué que mon appel à fclose () provoque des problèmes sur certains ordinateurs ...
la source
#include
bourre, mais je suppose que cela est lié au bogue dans l'édition # 5. De plus, il ne remplace pas les macros, même s'il traite avec succès les blocs #if - à moins que je fasse quelque chose de mal ... mais en général, il semble très bon, et il donne une idée approximative de ce qu'un lexer peut faire, car Je peux le comprendre même sous sa forme golfée. Essayez de voir si les bugs peuvent être corrigés, sinon ce n'est pas grave, comme le code s'explique bien, probablement ce sera la réponse choisie car il n'y a pas d'autres entrées.