Je veux forcer le préprocesseur à faire de la génération automatique de code pour moi. Je n'ai pas besoin de beaucoup: juste une simple boucle qui contient une autre boucle. [1]
J'ai lu tout ce que je peux sur la macro expansion et que je ne range plus lorsque la peinture bleue arrive. Une bonne journée, je peux même expliquer pourquoi on a besoin de multiples couches de macros pour générer un nom de fonction avec colle de jeton. J'ai vraiment eu la boucle de travail. Mais quand il s'agit de mettre une boucle au sein d'une boucle, je suis réduit de saupoudronner au hasard avec de reporter, d'évaluer et d'obstruer et d'espérer les meilleurs. P>
Je ne serai pas dissuadé par des appels à la raison. Je veux vraiment faire cela avec le préprocesseur Standard C. Je promets que peu importe le résultat, ni moi, mon employeur, ni mes héritiers ne vous poursuivront pour une faute professionnelle technologique. Je promets que je ne laisserai personne d'autre à maintenir le code, ni même à la voir, sans lunettes de sécurité appropriées. Faites semblant que vous voudriez que je pose juste des intérêts théoriques. Ou que ma seule autre option utilise M4: car si des macros récursives dans le CPP sont crépus, le M4 est certainement le poulet entier. P>
Le meilleur matériau de référence que j'ai trouvé est un fil useNet de 9 ans: http://comp.std.c.narkive.com/5wbjfcof/double -cpp-expansion p>
Il commence hors sujets, est quelque peu petite et combative sur ton, et c'est bien sur ma tête. Mais je pense que la réponse que je cherche est là quelque part. P>
Le meilleur est la documentation pour un en-tête abusant du CPP appelé Cape: https://github.com/pfultz2/cloak / wiki / c-préprocesseur-astuces, -Tips,-et idioms p>
Il faut une approche quelque peu différente de l'itération, et peut-être servirait mes besoins. Mais c'est aussi un bon aperçu. P>
Voici un code coupé pour montrer où je suis coincé. p>
répéter.h: p> échantillon.c : p> dans et voici la sortie que je veux obtenir à la place: P> Sample.c code> J'ai montré quatre variantes qui se rapprochent de ce que je veux. Mais aucun n'est tout à fait là. Voici ce que je reçois en tant que sortie avec "CPP échantillon.c> out.c; asttyle out.c;" p>
void desired_results() {
{
if (0 == 1) printf("Match\n");
if (1 == 1) printf("Match\n");
if (2 == 1) printf("Match\n");
};
{
if (0 == 2) printf("Match\n");
if (1 == 2) printf("Match\n");
if (2 == 2) printf("Match\n");
};
}
4 Réponses :
P99 pourrait vous fournir ce que vous recherchez. Il a plusieurs types d'itérateurs macro, des simples comme p99_unroll code>,
p99_ser code> etc. et un
p99_for code>. P>.
Salut Jens --- a l'air passionnant et je vais certainement vérifier. La documentation est géniale! Semble que cela prend l'approche basée sur les Nargs et fait tout son traitement sur les arguments variadiques. Connaissez-vous hors tension si la boucle de boucle-a-boucle fonctionne et s'il est possible que la macro de la boucle interne reçoive le comptoir de la boucle externe comme un argument?
@Nathankurz, nidification de deux boucles basées sur la même primitive ne fonctionnerait pas facilement, je pense. Mais si pour l'utilisation, il suffirait de combiner p99_for code> avec
p99_ser code> (ou similaire) qui devrait être possible. Le seul de ces constructions qui a quelque chose comme un compteur de boucle est
p99_for code>, mais il devrait être possible de rendre cela accessible à une autre construction intérieure itérative.
J'ai examiné P99, mais je ne veux pas de dépendance externe, et il est difficile de commencer à comprendre ce qui est nécessaire pour P99_FOR et que nécessaire pour cela. Tout est nommé très confortablement et au hasard.
@Marcusj, désolé si vous avez cette impression et que ces noms vous dérangent. P99_FOR CODE> est hautement non trivial, si cela n'étirait pas, je n'aurais probablement pas été fourni comme un projet open source en premier lieu, je pense, mais je viens de poster du code sur mon blog. Je pense que mettre en œuvre une telle chose à vous-même n'est généralement pas une bonne idée, c'est très chronométrant et erronprone.
Je ne suis pas sûr de suivre toutes vos macros là-bas. Cette réponse ici (aussi ici MAINTENANT également) Comment créer un usage général Ceci prend un compte, une macro et des données utilisateur. Étant donné que la macro passe est différée, la macro code> répéter code> peut être appelée directement et récursive. Voici donc votre Ceci sera sortie ceci: p> répéter code> macro, comme Ceci:
externe code> et
interne code> Répéter les macros: p>
{
if (0 == 1) printf("Match\n");
if (1 == 1) printf("Match\n");
if (2 == 1) printf("Match\n");
}
{
if (0 == 2) printf("Match\n");
if (1 == 2) printf("Match\n");
if (2 == 2) printf("Match\n");
}
Bonjour Paul --- Merci beaucoup d'avoir répondu et merci pour l'exemple de travail. J'ai lu votre page et vos autres réponses ici plusieurs fois. Bien que je comprenne la ligne par ligne, je suis toujours confondu par la manière dont l'expansion fonctionne et comment l'indirecte interagit avec le (double) différent. Mais entre vos exemples et le code P99 de Jen, j'espère tout comprendre. Y a-t-il d'autres ressources que vous avez trouvées utiles?
@Nathankurz L'indirection est nécessaire pour éviter d'obtenir un jeton peint en bleu. Même si la macro différée n'est pas évaluée, elle est numérisée par le préprocesseur et lorsqu'il voit un jeton dans son contexte désactivé (disons répéter code>) il le peint bleue et le jeton ne peut plus se développer. Donc, nous mettons un
répéter_indirect code> macro là-bas afin que le préprocesseur ne voie pas le jeton code> code>, jusqu'à ce qu'une autre analyse soit appliquée, ce qui aura un contexte invalidant différent, espérons-le, sans
répéter code> dedans.
De plus, le obstruer code> (ou double différensif) signifie simplement deux analyses sont nécessaires pour développer complètement la macro. Donc,
Développement (obstrutif (macro)) () code> équivaut à
de reportage (macro) () code>. C'est nécessaire pour
répéter code> en raison du conditionnel. Le
quand code> macro appliquera une analyse. Fondamentalement, causer
obstructeur (répéter_indirect) () code> pour devenir
de reporter (répéter_indirect) () code>. Maintenant si nous venons d'avoir
de reporter (répéter_indirect) () code> à la place, il deviendrait
répéter code> après l'application de la numérisation, provoquant une répétition
code> pour devenir peint bleu . Cela a-t-il du sens?
@Nathankurz également la seule ressource, je connais la bibliothèque de préprocesseur du chaos de Paul Mensonides. Il a inventé la plupart de ces techniques, sauf qu'ils sont plus sophistiqués. Par exemple, les macros récursives utilisent un état de récursivité de sorte que seul le nombre de scans requis est appliqué, ce qui est plus efficace que la macro eval code> qui applique toujours beaucoup de scans, même si elles ne sont pas nécessaires.
"Commande" Bibliothèque / Langue peut définitivement cela pour vous. Il implémente une récursion et une boucle sans restriction dans le prétraiteur C, et comme un bonus vraiment cool lui habillait avec la belle syntaxe concise d'un langage de programmation "approprié" (clarifier: ce n'est pas un préprocesseur alternatif, il fait simplement un Lot em> de jeton-coller pour garder ses mots-clés courts. C'est toujours pur CPP). P>
Il utilise une technique assez différente, convertissant vos métaprogrammes en CPS, puis les transmettant à une construction de boucle em> qui contient des milliards de marches et exécute le métaprogramme de manière strictement linéaire. Les boucles et les fonctions récursives peuvent donc être imbriquées aussi profondément que vous le souhaitez, car ils n'ont pas de pilotes distincts qui doivent interagir et se peindre mutuellement. P>
Oui, une personne implémençait une machine virtuelle complète et un interprète utilisant des macros CPP. Il est intimidant. P>
(edit: essayez La version archivée < / a> Si le code Rosetta a cessé de travailler pour vous aussi.) p>
Merci pour le pointeur. La source semble également être disponible aux côtés de la bibliothèque de chaos Mensonides: Chaos-pp. cvs.sourceforge.net/viewvc/chaos-pp
Aide avec l'aide des réponses ici (et étudier p99 , < Un href = "http://chaos-pp.cvs.sourceforge.net/vievc/chaos-pp/chaos-pp/" rel = "nofollow"> chaos , Commander et Cloak ) Je pense avoir une épreuve de concept raisonnablement simple et compacte (1). Comme je ne voulais que "répéter" fonctionnalité plutôt qu'un interprète époustouflé complet, je suis allé avec une approche quelque peu différente que ces autres solutions. Au lieu de créer générique "si", "tandis que" ou "quand" macros, je suis directement utilisé directement une série de macros "décrément" qui développent la macro souhaitée à la macro pour N-1. J'ai toujours du mal à comprendre beaucoup de subtilités, mais comme d'autres soulignaient que la règle générale est qu'aucune macro ne peut se développer. Le moyen de créer une macro qui se développe juste au point où elle s'appellerait elle-même, puis mettrait une enveloppe autour de ce résultat pour compléter l'expansion. P> Le truc (commun) que j'ai fini par utiliser est de tirer parti du fait qu'une macro de type fonction ne se développe que s'il est immédiatement suivi par des parenthèses. On peut utiliser une macro "de différend" qui place un jeton "vide" entre le nom de macro appelé et ses parenthèses, puis "étendre" cela comme argument à une autre macro. P> Étant donné que l'expansion des arguments a lieu dans un contexte différent de celle de l'expansion initiale, la macro initiale se développera à nouveau. Dans ma solution, un niveau d'expansion est nécessaire pour chaque niveau de récursivité potentielle. Si vous jouez avec le code pour le comprendre, il peut être utile de diminuer le nombre d'extensions pour vérifier les résultats intermédiaires. P> Merci pour toute l'aide! p> (1) True, la norme pour "raisonnablement simple" est assez lâche lorsqu'il est appliqué à des macros de préprocesseur récursif. C'est assez compact, cependant. P> p>