#!/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