Chcę wymusić preprocesor zrobić jakieś automatyczne generowanie kodu dla mnie. Nie potrzebuję wiele: po prostu prosta pętla for, która zawiera inną pętlę for. [1]Jak napisać rekurencyjne makro pętli "repeat" w celu wygenerowania kodu C za pomocą preprocesora CPP?
Czytałem wszystko, co mogę o ekspansji makra, a nie chichot, gdy niebieska farba wyjdzie. W dobry dzień mogę nawet wyjaśnić, dlaczego potrzebujemy wielu warstw makr do wygenerowania nazwy funkcji z wklejonymi tokenami. Właściwie działa pętla for. Ale jeśli chodzi o umieszczenie pętli w pętli, jestem sprowadzany do losowego traktowania przez DEFER, EVAL i OBSTRUCT i mając nadzieję na najlepsze.
nie zostanie zahamowane połączeń do rozumu. Naprawdę chcę to zrobić ze standardowym preprocesorem C. Obiecuję, że niezależnie od wyniku, ani ja, ani mój pracodawca, ani moi spadkobiercy nie pozwiemy cię za błędy technologiczne. Obiecuję, że nie pozwolę nikomu innemu zachować kodu, a nawet go obejrzeć, bez odpowiednich okularów ochronnych. Udawaj, jeśli chcesz, po prostu pytam z teoretycznego punktu widzenia. Albo, że moją jedyną opcją jest użycie M4: jeśli makra rekursywne w CPP są perwersyjne, to na pewno M4 jest całym kurczakiem.
Najlepszy materiał referencyjny Znalazłem to 9-letni wątek Usenet: http://comp.std.c.narkive.com/5WbJfCof/double-cpp-expansion
Zaczyna niezwiązanych z tematem jest nieco małostkowy i wojowniczy w tonie i jest sposobem na głowę. Ale myślę, że odpowiedź, której szukam, jest gdzieś tam.
Następnym najlepiej jest dokumentacja dla KPP nadużywa nagłówku zwanego Cloak: https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
To zajmuje trochę inne podejście do iteracji i być może służyć zamiast moich potrzeb. Ale to także dobry przegląd.
Oto niektóre kodu cut-dół, aby pokazać, gdzie utknąłem.
repeat.h:
#define REPEAT(macro, times, start_n, next_func, next_arg, macro_args...) \
_REPEAT_ ## times(macro, start_n, next_func, next_arg, ## macro_args)
#define REPEAT_ADD_ONE(macro, times, start_n, macro_args...) \
REPEAT(macro, times, start_n, _REPEAT_ADD_ONE, 0, ## macro_args)
#define _REPEAT_ADD_ONE(n, ignore...) _REPEAT_ADD_ONE_ ## n
#define _REPEAT_0(args...) /* empty */
#define _REPEAT_1(macro, n, func, i, args...) macro(n, ## args)
#define _REPEAT_2(m, n, f, i, a...) m(n, ## a); _REPEAT_1(m, f(n, i), f, i, ## a)
#define _REPEAT_3(m, n, f, i, a...) m(n, ## a); _REPEAT_2(m, f(n, i), f, i, ## a)
#define _REPEAT_4(m, n, f, i, a...) m(n, ## a); _REPEAT_3(m, f(n, i), f, i, ## a)
#define _REPEAT_5(m, n, f, i, a...) m(n, ## a); _REPEAT_4(m, f(n, i), f, i, ## a)
#define _REPEAT_6(m, n, f, i, a...) m(n, ## a); _REPEAT_5(m, f(n, i), f, i, ## a)
#define _REPEAT_7(m, n, f, i, a...) m(n, ## a); _REPEAT_6(m, f(n, i), f, i, ## a)
#define _REPEAT_8(m, n, f, i, a...) m(n, ## a); _REPEAT_7(m, f(n, i), f, i, ## a)
#define _REPEAT_9(m, n, f, i, a...) m(n, ## a); _REPEAT_8(m, f(n, i), f, i, ## a)
#define _REPEAT_10(m, n, f, i, a...) m(n, ## a); _REPEAT_9(m, f(n, i), f, i, ## a)
#define _REPEAT_ADD_ONE_0 1
#define _REPEAT_ADD_ONE_1 2
#define _REPEAT_ADD_ONE_2 3
#define _REPEAT_ADD_ONE_3 4
#define _REPEAT_ADD_ONE_4 5
#define _REPEAT_ADD_ONE_5 6
#define _REPEAT_ADD_ONE_6 7
#define _REPEAT_ADD_ONE_7 8
#define _REPEAT_ADD_ONE_8 9
#define _REPEAT_ADD_ONE_9 10
#define _REPEAT_ADD_ONE_10 11
#define _REPEAT_ADD_0(x) x
#define _REPEAT_ADD_1(x) _REPEAT_ADD_ONE(x)
#define _REPEAT_ADD_2(x) _REPEAT_ADD_1(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_3(x) _REPEAT_ADD_2(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_4(x) _REPEAT_ADD_3(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_5(x) _REPEAT_ADD_4(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_6(x) _REPEAT_ADD_5(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_7(x) _REPEAT_ADD_6(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_8(x) _REPEAT_ADD_7(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_9(x) _REPEAT_ADD_8(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_10(x) _REPEAT_ADD_9(_REPEAT_ADD_ONE(x))
sample.c:
#include "repeat.h"
#define INNER_MACRO(inner, outer) if (inner == outer) printf("Match\n")
#define INNER_BLOCK { if (inner == outer) printf("Match\n"); }
#define OUTER_MACRO_INNER_MACRO(outer) REPEAT_ADD_ONE(INNER_MACRO, 3, 0, outer)
#define OUTER_BLOCK_INNER_MACRO { REPEAT_ADD_ONE(INNER_MACRO, 3, 0, outer); }
#define OUTER_MACRO_INNER_BLOCK(outer) REPEAT_ADD_ONE(INNER_BLOCK, 3, 0, outer)
#define OUTER_BLOCK_INNER_BLOCK { REPEAT_ADD_ONE(INNER_BLOCK, 3, 0, outer); }
void outer_macro_inner_macro() {
REPEAT_ADD_ONE(OUTER_MACRO_INNER_MACRO, 2, 1);
}
void outer_macro_inner_block() {
REPEAT_ADD_ONE(OUTER_MACRO_INNER_BLOCK, 2, 1);
}
void outer_block_inner_macro() {
REPEAT_ADD_ONE(OUTER_BLOCK_INNER_MACRO, 2, 1);
}
void outer_block_inner_block() {
REPEAT_ADD_ONE(OUTER_BLOCK_INNER_BLOCK, 2, 1);
}
W sample.c
Mam pokazano cztery odmiany, które zbliżają się do tego, co chcę. Ale nikogo tam nie ma. Oto, co otrzymuję jako wyjście z "cpp sample.c> out.c; astyle out.c;"
void outer_macro_inner_macro() {
REPEAT_ADD_ONE(INNER_MACRO, 3, 0, 1);
REPEAT_ADD_ONE(INNER_MACRO, 3, 0, 2);
}
void outer_macro_inner_block() {
REPEAT_ADD_ONE({ if (inner == outer) printf("Match\n"); }, 3, 0, 1);
REPEAT_ADD_ONE({ if (inner == outer) printf("Match\n"); }, 3, 0, 2);
}
void outer_block_inner_macro() {
{
if (0 == outer) printf("Match\n");
if (1 == outer) printf("Match\n");
if (2 == outer) printf("Match\n");
}(1);
{
if (0 == outer) printf("Match\n");
if (1 == outer) printf("Match\n");
if (2 == outer) printf("Match\n");
}(2);
}
void outer_block_inner_block() {
{ {
if (inner == outer) printf("Match\n");
}(0, outer);
{
if (inner == outer) printf("Match\n");
}(1, outer);
{
if (inner == outer) printf("Match\n");
}(2, outer);
}(1);
{ {
if (inner == outer) printf("Match\n");
}(0, outer);
{
if (inner == outer) printf("Match\n");
}(1, outer);
{
if (inner == outer) printf("Match\n");
}(2, outer);
}(2);
}
A oto wyjście chcę dostać zamiast:
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");
};
}
Zasadniczo mogę dostać rzeczy do pracy, jeśli mogę użyć bloku jako zewnętrznej ciała pętli, ale nie w przypadku korzystania z funkcji -jakie makro. Ale potrzebuję użyć makra z argumentami, aby ciała pętli mogły używać licznika pętli jako stałej zamiast zmiennej.
Problem z „makro” - „makro” sposób, że wewnętrzna rekurencyjne wywołanie REPEAT_ADD_ONE() nie jest rozszerzony. Odpowiedź wydaje się odraczać ekspansję wewnętrznej pętli, aż do momentu utworzenia zewnętrznej pętli, a następnie wymuszenie kolejnego przejścia, które rozszerza wewnętrzną pętlę. Ale z jakiegoś powodu moje podejście „random małpa” na które nie osiągnęło jeszcze rozwiązanie ...
[1] Understatement przeznaczeniem.
Cześć Jens --- Wygląda ekscytująco, a ja na pewno to sprawdzę. Dokumentacja jest świetna! Wydaje się, że stosuje podejście oparte na NARGS i wykonuje całe przetwarzanie na argumentach variadic. Czy wiesz od ręki, czy pętla w pętli działa, i czy jest możliwe, aby makro pętli wewnętrznej odebrało licznik zewnętrznej pętli jako argument? –
@NathanKurz, zagnieżdżanie dwóch pętli opartych na tym samym prymitywie nie działałoby łatwo, jak sądzę. Ale jeśli chodzi o przypadek użycia, wystarczy połączyć 'P99_FOR' z' P99_SER' (lub podobnym), które powinno być możliwe. Jedynym z tych konstruktów, które mają coś w rodzaju licznika pętli, jest 'P99_FoR', ale powinno być możliwe udostępnienie go innemu wewnętrznemu, iteratywnemu konstruktowi. –