1 #include <iostream>
2 #include <iomanip>
3 #include <string>
4 #include <boost/preprocessor/config/config.hpp>
5
6 static unsigned int indent = 4;
7 static unsigned int width = 90;
8
9 using std::cout;
10 using std::istream;
11
print_separator()12 void print_separator()
13 {
14 std::cout <<
15 "\n\n*********************************************************************\n\n";
16 }
17
remove_spaces(const std::string ss)18 std::string remove_spaces(const std::string ss)
19 {
20
21 bool inquotes(false);
22 bool escape(false);
23 char qchar;
24 int len(static_cast<int>(ss.length()));
25
26 std::string ret;
27
28 for (int i = 0; i < len; ++i)
29 {
30
31 char ch(ss[i]);
32
33 if (inquotes)
34 {
35 if (escape)
36 {
37 escape = false;
38 }
39 else if (ch == '\\')
40 {
41 escape = true;
42 }
43 else if (ch == qchar)
44 {
45 inquotes = false;
46 }
47 ret.push_back(ch);
48 }
49 else
50 {
51 if (ch == '\'' || ch == '"')
52 {
53 inquotes = true;
54 qchar = ch;
55 ret.push_back(ch);
56 }
57 else if (ch != ' ')
58 {
59 ret.push_back(ch);
60 }
61 }
62 }
63
64 return ret;
65 }
66
print_macro(const std::string name,const std::string expected,const std::string expansion)67 int print_macro(const std::string name,const std::string expected, const std::string expansion)
68 {
69 int bret(0);
70 const std::string sg("Success: ");
71 const std::string sb("Failure: ");
72 for(unsigned i = 0; i < indent; ++i) std::cout.put(' ');
73 if (name == expansion)
74 {
75 if (expected == expansion)
76 {
77 std::cout << sg;
78 std::cout << std::setw(width);
79 cout.setf(istream::left, istream::adjustfield);
80 std::cout << name;
81 std::cout << " [no value]\n";
82 }
83 else
84 {
85 std::cout << sb;
86 std::cout << std::setw(width);
87 cout.setf(istream::left, istream::adjustfield);
88 std::cout << name;
89 std::cout << " [no value]: ";
90 std::cout << " [expected]: ";
91 std::cout << expected << "\n";
92 bret = 1;
93 }
94 }
95 else
96 {
97
98 std::string sexpected(remove_spaces(expected));
99 std::string sexpansion(remove_spaces(expansion));
100
101 if (sexpected == sexpansion)
102 {
103 std::cout << sg;
104 std::cout << std::setw(width);
105 cout.setf(istream::left, istream::adjustfield);
106 std::cout << name;
107 std::cout << expansion << "\n";
108 }
109 else
110 {
111 std::cout << sb;
112 std::cout << std::setw(width);
113 cout.setf(istream::left, istream::adjustfield);
114 std::cout << name;
115 std::cout << expansion;
116 std::cout << " [expected]: ";
117 std::cout << expected << "\n";
118 bret = 1;
119 }
120 }
121 return bret;
122 }
123
124 #define STRINGIZE(...) # __VA_ARGS__
125
126 #define PRINT_MACRO_RESULTS(X,...) print_macro(std::string(# X), std::string(# __VA_ARGS__), std::string(STRINGIZE(X)))
127 #define PRINT_MACRO(...) std::string(# __VA_ARGS__)
128 #define PRINT_EXPECTED(...) std::string(# __VA_ARGS__)
129 #define PRINT_EXPANSION(...) std::string(STRINGIZE(__VA_ARGS__))
130
131 #if __cplusplus > 201703L
132
print_macros_common_c20()133 int print_macros_common_c20()
134 {
135
136 int bret = 0;
137
138 #define LPAREN() (
139 #define G(Q) 42
140 #define F(R, X, ...) __VA_OPT__(G R X) )
141
142 // int x = F(LPAREN(), 0, <:-);
143
144 // replaced by
145
146 // int x = 42;
147
148 bret += PRINT_MACRO_RESULTS(int x = F(LPAREN(), 0, <:-);,int x = 42;);
149
150 #undef LPAREN
151 #undef G
152 #undef F
153
154 #define F(...) f(0 __VA_OPT__(,) __VA_ARGS__)
155 #define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__)
156 #define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ })
157 #define EMP
158
159 // F(a, b, c)
160 // F()
161 // F(EMP)
162
163 // replaced by
164
165 // f(0, a, b, c)
166 // f(0)
167 // f(0)
168
169 // G(a, b, c)
170 // G(a, )
171 // G(a)
172
173 // replaced by
174
175 // f(0, a, b, c)
176 // f(0, a)
177 // f(0, a)
178
179 // SDEF(foo);
180 // SDEF(bar, 1, 2);
181
182 // replaced by
183
184 // S foo;
185 // S bar = { 1, 2 };
186
187 bret += PRINT_MACRO_RESULTS(F(a, b, c),f(0, a, b, c));
188 bret += PRINT_MACRO_RESULTS(F(),f(0));
189 bret += PRINT_MACRO_RESULTS(F(EMP),f(0));
190 bret += PRINT_MACRO_RESULTS(G(a, b, c),f(0, a, b, c));
191 bret += PRINT_MACRO_RESULTS(G(a, ),f(0, a));
192 bret += PRINT_MACRO_RESULTS(G(a),f(0, a));
193 bret += PRINT_MACRO_RESULTS(SDEF(foo);,S foo;);
194 bret += PRINT_MACRO_RESULTS(SDEF(bar, 1, 2);,S bar = { 1, 2 };);
195
196 #undef F
197 #undef G
198 #undef SDEF
199 #undef EMP
200
201 #define H2(X, Y, ...) __VA_OPT__(X ## Y,) __VA_ARGS__
202 #define H3(X, ...) #__VA_OPT__(X##X X##X)
203 #define H4(X, ...) __VA_OPT__(a X ## X) ## b
204 #define H5A(...) __VA_OPT__()/**/__VA_OPT__()
205 #define H5B(X) a ## X ## b
206 #define H5C(X) H5B(X)
207
208 // H2(a, b, c, d)
209
210 // replaced by
211
212 // ab, c, d
213
214 // H3(, 0)
215
216 // replaced by
217
218 // ""
219
220 // H4(, 1)
221
222 // replaced by
223
224 // a b
225
226 // H5C(H5A())
227
228 // replaced by
229
230 // ab
231
232 bret += PRINT_MACRO_RESULTS(H2(a, b, c, d),ab, c, d);
233 bret += PRINT_MACRO_RESULTS(H3(, 0),"");
234 bret += PRINT_MACRO_RESULTS(H4(, 1),a b);
235 bret += PRINT_MACRO_RESULTS(H5C(H5A()),ab);
236
237 #undef H2
238 #undef H3
239 #undef H4
240 #undef H5A
241 #undef H5B
242 #undef H5C
243
244 return bret;
245
246 }
247
248 #endif
249
250 int print_macros_common_1()
251 {
252
253 int bret = 0;
254
255 #define x 3
256 #define f(a) f(x * (a))
257 #undef x
258
259 #define x 2
260 #define g f
261 #define z z[0]
262 #define h g(~
263 #define m(a) a(w)
264 #define w 0,1
265 #define t(a) a
266
267 // f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
268 // g(x+(3,4)-w) | h 5) & m(f)^m(m);
269
270 // results in
271
272 // f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
273 // f(2 * (2+(3,4)-0,1)) | f(2 * ( ~ 5)) & f(2 * (0,1))^m(0,1);
274
275 bret += PRINT_MACRO_RESULTS(f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);,f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1););
276
277 #define PRINT_INPUT g(x+(3,4)-w) | h 5) & m(f)^m(m);
278
279 bret += print_macro
280 (
281 std::string("g(x+(3,4)-w) | h 5) & m(f)^m(m);"),
282 PRINT_EXPECTED(f(2 * (2+(3,4)-0,1)) | f(2 * ( ~ 5)) & f(2 * (0,1))^m(0,1);),
283 PRINT_EXPANSION(PRINT_INPUT)
284 );
285
286 #undef PRINT_INPUT
287
288 #undef f
289 #undef x
290 #undef g
291 #undef z
292 #undef h
293 #undef m
294 #undef w
295 #undef t
296
297 return bret;
298
299 }
300
301 int print_macros_common_4()
302 {
303
304 int bret = 0;
305
306 #define str(s) # s
307 #define xstr(s) str(s)
308 #define debug(s, t) printf("x" # s "= %d, x" # t "= %s", x ## s, x ## t)
309 #define INCFILE(n) vers ## n
310 #define glue(a, b) a ## b
311 #define xglue(a, b) glue(a, b)
312 #define HIGHLOW "hello"
313 #define LOW LOW ", world"
314
315 // debug(1, 2);
316 // fputs(str(strncmp("abc\0d", "abc", �\4�) // this goes away
317 // == 0) str(: @\n), s);
318 // #include xstr(INCFILE(2).h)
319 // glue(HIGH, LOW);
320 // xglue(HIGH, LOW)
321
322 // results in
323
324 // printf("x" "1" "= %d, x" "2" "= %s", x1, x2);
325 // fputs("strncmp(\"abc\\0d\", \"abc\", �\\4�) == 0" ": @\n", s);
326 // #include "vers2.h" (after macro replacement, before file access)
327 // "hello";
328 // "hello" ", world"
329
330 bret += PRINT_MACRO_RESULTS(debug(1, 2);,printf("x" "1" "= %d, x" "2" "= %s", x1, x2););
331 bret += print_macro
332 (
333 std::string("fputs(str(strncmp(\"abc\\0d\", \"abc\", '\\4') /* this goes away */== 0) str(: @\\n), s);"),
334 PRINT_EXPECTED(fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s);),
335 PRINT_EXPANSION(fputs(str(strncmp("abc\0d", "abc", '\4') /* this goes away */== 0) str(: @\n), s);)
336 );
337 bret += PRINT_MACRO_RESULTS(xstr(INCFILE(2).h),"vers2.h");
338 bret += PRINT_MACRO_RESULTS(glue(HIGH, LOW);,"hello";);
339
340 #if __cplusplus <= 199711L
341
342 bret += print_macro
343 (
344 PRINT_MACRO(xglue(HIGH, LOW)),
345 std::string("\"hello\" \", world\""),
346 PRINT_EXPANSION(xglue(HIGH, LOW))
347 );
348
349 #else
350
351 bret += PRINT_MACRO_RESULTS(xglue(HIGH, LOW),"hello" ", world");
352
353 #endif
354
355 #undef str
356 #undef xstr
357 #undef debug
358 #undef INCFILE
359 #undef glue
360 #undef xglue
361 #undef HIGHLOW
362 #undef LOW
363
364 return bret;
365
366 }
367
368 int print_macros_common_2()
369 {
370
371 int bret = 0;
372
373 #define hash_hash # ## #
374 #define mkstr(a) # a
375 #define in_between(a) mkstr(a)
376 #define join(c, d) in_between(c hash_hash d)
377
378 // char p[] = join(x, y);
379
380 // equivalent to
381
382 // char p[] = "x ## y";
383
384 bret += PRINT_MACRO_RESULTS(char p[] = join(x, y);,char p[] = "x ## y";);
385
386 #undef hash_hash
387 #undef mkstr
388 #undef in_between
389 #undef join
390
391 return bret;
392
393 }
394
395 #if __cplusplus > 199711L
396
397 int print_macros_common_3()
398 {
399
400 int bret = 0;
401
402 #define p() int
403 #define q(x) x
404 #define r(x,y) x ## y
405 #define str(x) # x
406
407 // p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };
408 // char c[2][6] = { str(hello), str() };
409
410 // results in
411
412 // int i[] = { 1, 23, 4, 5, };
413 // char c[2][6] = { "hello", "" };
414
415 bret += print_macro
416 (
417 PRINT_MACRO(p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };),
418 PRINT_EXPECTED(int i[] = { 1, 23, 4, 5, };),
419 PRINT_EXPANSION(p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };)
420 );
421 bret += print_macro
422 (
423 PRINT_MACRO(char c[2][6] = { str(hello), str() };),
424 PRINT_EXPECTED(char c[2][6] = { "hello", "" };),
425 PRINT_EXPANSION(char c[2][6] = { str(hello), str() };)
426 );
427
428 #undef p
429 #undef q
430 #undef r
431 #undef str
432
433 bret += print_macros_common_4();
434
435 #define t(x,y,z) x ## y ## z
436
437 // int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), t(10,,), t(,11,), t(,,12), t(,,) };
438
439 // results in
440
441 // int j[] = { 123, 45, 67, 89, 10, 11, 12, };
442
443 bret += print_macro
444 (
445 PRINT_MACRO(int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), t(10,,), t(,11,), t(,,12), t(,,) };),
446 PRINT_EXPECTED(int j[] = { 123, 45, 67, 89, 10, 11, 12, };),
447 PRINT_EXPANSION(int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), t(10,,), t(,11,), t(,,12), t(,,) };)
448 );
449
450 #undef t
451
452 #define debug(...) fprintf(stderr, __VA_ARGS__)
453 #define showlist(...) puts(#__VA_ARGS__)
454 #define report(test, ...) ((test) ? puts(#test) : printf(__VA_ARGS__))
455
456 // debug("Flag");
457 // debug("X = %d\n", x);
458 // showlist(The first, second, and third items.);
459 // report(x>y, "x is %d but y is %d", x, y);
460
461 // results in
462
463 // fprintf(stderr, "Flag");
464 // fprintf(stderr, "X = %d\n", x);
465 // puts("The first, second, and third items.");
466 // ((x>y) ? puts("x>y") : printf("x is %d but y is %d", x, y));
467
468 #define save_stderr stderr
469 #undef stderr
470
471 bret += PRINT_MACRO_RESULTS(debug("Flag");,fprintf(stderr, "Flag"););
472 bret += PRINT_MACRO_RESULTS(debug("X = %d\n", x);,fprintf(stderr, "X = %d\n", x););
473
474 #define stderr save_stderr
475
476 bret += PRINT_MACRO_RESULTS(showlist(The first, second, and third items.);,puts("The first, second, and third items."););
477 bret += PRINT_MACRO_RESULTS(report(x>y, "x is %d but y is %d", x, y);,((x>y) ? puts("x>y") : printf("x is %d but y is %d", x, y)););
478
479 #undef debug
480 #undef showlist
481 #undef report
482
483 return bret;
484
485 }
486
487 #endif
488
489 int print_macros()
490 {
491 int bret = 0;
492
493 print_separator();
494
495 std::cout << "__cplusplus = " << __cplusplus;
496
497 print_separator();
498
499 #define OBJ_LIKE (1-1)
500 #define OBJ_LIKE /* white space */ (1-1) /* other */
501 #define FTN_LIKE(a) ( a )
502 #define FTN_LIKE( a )( /* note the white space */ a /* other stuff on this line */ )
503
504 #if __cplusplus <= 199711L
505
506 bret += print_macros_common_2();
507 bret += print_macros_common_1();
508 bret += print_macros_common_4();
509
510 #elif __cplusplus <= 201703L
511
512 bret += print_macros_common_2();
513 bret += print_macros_common_1();
514 bret += print_macros_common_3();
515
516 #else
517
518 bret += print_macros_common_c20();
519 bret += print_macros_common_2();
520 bret += print_macros_common_1();
521 bret += print_macros_common_3();
522
523 #endif
524
525 print_separator();
526
527 return bret;
528 }
529
530 int main()
531 {
532 return (print_macros());
533 }
534