1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
#!/bin/sh
set -eu
base="${TMPDIR-/tmp}/mcpu-cpp-concat-$$"
mkdir -p "$base"
trap 'rm -rf "$base"' EXIT HUP INT TERM
cat > "$base/main.c" <<'EOT'
#define A left
#define B right
#define AB raw_result
#define leftright expanded_result
#define CAT(X, Y) X ## Y
#define XCAT(X, Y) CAT(X, Y)
#define AFTERX(X) X_ ## X
#define XAFTERX(X) AFTERX(X)
#define TABLESIZE 1024
#define BUFSIZE TABLESIZE
#define MADE 91
#define MK(A, B) A ## B
#define L(X) X ## tail
#define R(X) head ## X
#define CHAIN(A, B, C) A ## B ## C
#define OBJECT obj ## ect
#define object object_result
#define COMMAND(NAME) #NAME | NAME ## _command
#define quit_command command_result
#define CALL(NAME) NAME ## _fn(1)
#define run_fn(X) called_result
#define ONE1 1
#define PCAT(A, B) A ## B
#define RUN(A, B) A ## ## B
#define ab adjacent_result
#define TEXT "a ## b"
#define COMMENT_CAT(A, B) A /* left */ ## /* right */ B
#define DIRECT_EMPTY
#define xDIRECT_EMPTY direct_empty_raw
#define EXPAND_EMPTY(A, B) CAT(A, B)
CAT(A, B)
XCAT(A, B)
AFTERX(BUFSIZE)
XAFTERX(BUFSIZE)
MK(MA, DE)
CAT(x y, z)
CAT(x, y z)
L()
R()
CHAIN(x, , z)
OBJECT
CAT(1.5, e3)
CAT(+, =)
CAT(L, "wide")
CAT(u8, "utf8")
COMMAND(quit)
CALL(run)
RUN(a, b)
CAT(x, DIRECT_EMPTY)
EXPAND_EMPTY(x, DIRECT_EMPTY)
TEXT
COMMENT_CAT(c, d)
CAT(e /* argument comment */, f)
#if PCAT(ONE, 1)
conditional_result
#endif
EOT
"$MCPU_CPP" --no-config "$base/main.c" -o "$base/out"
grep -Fx 'raw_result' "$base/out" >/dev/null
grep -Fx 'expanded_result' "$base/out" >/dev/null
grep -Fx 'X_BUFSIZE' "$base/out" >/dev/null
grep -Fx 'X_1024' "$base/out" >/dev/null
grep -Fx '91' "$base/out" >/dev/null
grep -Fx 'x yz' "$base/out" >/dev/null
grep -Fx 'xy z' "$base/out" >/dev/null
grep -Fx 'tail' "$base/out" >/dev/null
grep -Fx 'head' "$base/out" >/dev/null
grep -Fx 'xz' "$base/out" >/dev/null
grep -Fx 'object_result' "$base/out" >/dev/null
grep -Fx '1.5e3' "$base/out" >/dev/null
grep -Fx '+=' "$base/out" >/dev/null
grep -Fx 'L"wide"' "$base/out" >/dev/null
grep -Fx 'u8"utf8"' "$base/out" >/dev/null
grep -Fx '"quit" | command_result' "$base/out" >/dev/null
grep -Fx 'called_result' "$base/out" >/dev/null
grep -Fx 'adjacent_result' "$base/out" >/dev/null
grep -Fx 'direct_empty_raw' "$base/out" >/dev/null
grep -Fx 'x' "$base/out" >/dev/null
grep -Fx '"a ## b"' "$base/out" >/dev/null
grep -Fx 'cd' "$base/out" >/dev/null
grep -Fx 'ef' "$base/out" >/dev/null
grep -Fx 'conditional_result' "$base/out" >/dev/null
"$MCPU_CPP" --no-config -dM "$base/main.c" > "$base/dump"
grep -Fx '#define CAT(X,Y) X ## Y' "$base/dump" >/dev/null
grep -Fx '#define COMMAND(NAME) #NAME | NAME ## _command' "$base/dump" >/dev/null
cat > "$base/invalid.c" <<'EOT'
#define BAD(X) X ## +
BAD(foo)
EOT
"$MCPU_CPP" --no-config "$base/invalid.c" -o "$base/invalid.out" 2>"$base/invalid.err"
grep 'pasting "foo" and "+" does not give a valid preprocessing token' "$base/invalid.err" >/dev/null
grep 'foo' "$base/invalid.out" | tr -d '[:space:]' | grep -Fx 'foo+' >/dev/null
cat > "$base/first.c" <<'EOT'
#define FIRST(X) ## X
EOT
if "$MCPU_CPP" --no-config "$base/first.c" -o "$base/first.out" 2>"$base/first.err"; then
echo "leading ## accepted" >&2
exit 1
fi
grep "'##' cannot appear at the beginning of a macro replacement list" "$base/first.err" >/dev/null
cat > "$base/last.c" <<'EOT'
#define LAST(X) X ##
EOT
if "$MCPU_CPP" --no-config "$base/last.c" -o "$base/last.out" 2>"$base/last.err"; then
echo "trailing ## accepted" >&2
exit 1
fi
grep "'##' cannot appear at the end of a macro replacement list" "$base/last.err" >/dev/null
|