summaryrefslogtreecommitdiff
path: root/tests/t0039-command-line-macros.sh
blob: 94a5ec3dd51c9b38cfbc9ed2832234e490a4f994 (plain)
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/bin/sh
set -eu
base="${TMPDIR-/tmp}/mcpu-cpp-command-line-macros-$$"
mkdir -p "$base"
trap 'rm -rf "$base"' EXIT HUP INT TERM

cat > "$base/main.c" <<'EOT'
OBJECT
DEFAULT
EMPTY marker
СУММА(10, 7)
АНДРЕЙ
résumé
ПОРЯДОК
СТРОКА(АНДРЕЙ)
СКЛЕИТЬ(АНД,РЕЙ)
#ifdef __MCPU_CPP_VERSION__
BUILTIN_PRESENT
#else
BUILTIN_REMOVED
#endif
#if defined(КОМАНДА) && КОМАНДА == 31
CONDITIONAL_OK
#else
CONDITIONAL_BAD
#endif
EOT

"$MCPU_CPP" --no-config \
  -D OBJECT=17 \
  -DDEFAULT \
  -DEMPTY= \
  '-DСУММА(лево,право)=лево + право' \
  -DАНДРЕЙ=23 \
  -Drésumé=29 \
  -DПОРЯДОК=1 -U ПОРЯДОК -DПОРЯДОК=2 \
  '-DСТРОКА(x)=#x' \
  '-DСКЛЕИТЬ(a,b)=a ## b' \
  -DАНДРЕЙ=23 \
  -U__MCPU_CPP_VERSION__ \
  -DКОМАНДА=31 \
  "$base/main.c" -o "$base/out"

grep '^17$' "$base/out" >/dev/null
grep '^1$' "$base/out" >/dev/null
grep '^ marker$' "$base/out" >/dev/null
grep '^10 + 7$' "$base/out" >/dev/null
test "`grep -c '^23$' "$base/out"`" -eq 2
grep '^29$' "$base/out" >/dev/null
grep '^2$' "$base/out" >/dev/null
grep '^"АНДРЕЙ"$' "$base/out" >/dev/null
grep '^BUILTIN_REMOVED$' "$base/out" >/dev/null
if grep '^BUILTIN_PRESENT$' "$base/out" >/dev/null; then exit 1; fi
grep '^CONDITIONAL_OK$' "$base/out" >/dev/null
if grep '^CONDITIONAL_BAD$' "$base/out" >/dev/null; then exit 1; fi

# A function-like -D without '=' has the GNU meaning "replacement is 1".
printf '%s\n' 'F(99)' > "$base/default-func.c"
"$MCPU_CPP" --no-config '-DF(x)' "$base/default-func.c" -o "$base/default-func.out"
grep '^1$' "$base/default-func.out" >/dev/null

# Unicode XID continuation works on the command line as it does in source.
combining=$(printf 'e\314\201')
printf '%s\n' "$combining" > "$base/combining.c"
"$MCPU_CPP" --no-config "-D$combining=37" "$base/combining.c" -o "$base/combining.out"
grep '^37$' "$base/combining.out" >/dev/null

arabic_three=$(printf '\331\243')
name="ИМЯ$arabic_three"
printf '%s\n' "$name" > "$base/digit.c"
"$MCPU_CPP" --no-config "-D$name=43" "$base/digit.c" -o "$base/digit.out"
grep '^43$' "$base/digit.out" >/dev/null

# Command-line definitions pass through the same phase-3 comment cleanup as
# source #define directives.
printf '%s\n' 'COMMENTED' > "$base/comment.c"
"$MCPU_CPP" --no-config '-DCOMMENTED=left/* comment */right' \
  "$base/comment.c" -o "$base/comment.out"
grep '^left right$' "$base/comment.out" >/dev/null

# -dM observes the final command-line macro state.
printf '%s\n' '' > "$base/empty.c"
"$MCPU_CPP" --no-config -dM -DПОРЯДОК=1 -UПОРЯДОК -DПОРЯДОК=2 \
  "$base/empty.c" -o "$base/macros"
grep '^#define ПОРЯДОК 2$' "$base/macros" >/dev/null

# '$' is accepted after the first identifier character.  Single quotes protect
# it from shell parameter expansion; without quotes a backslash can do the same.
"$MCPU_CPP" --no-config -dD '-DАНДРЕЙ$_Y=62' -DОЛЬГА\$OLD=37 \
  "$base/empty.c" -o "$base/dollar-command-line"
grep '^#define АНДРЕЙ$_Y 62$' "$base/dollar-command-line" >/dev/null
grep '^#define ОЛЬГА$OLD 37$' "$base/dollar-command-line" >/dev/null

# '$' is not an identifier-start character.
if "$MCPU_CPP" --no-config '-D$BAD=1' "$base/empty.c" -o "$base/bad" \
     >"$base/dollar-start.stdout" 2>"$base/dollar-start.stderr"; then
  exit 1
fi
grep 'macro name expected after #define' "$base/dollar-start.stderr" >/dev/null

# For -D/-U an invalid tail after a valid identifier is discarded rather than
# becoming part of the replacement list.  The value after '=' is preserved.
"$MCPU_CPP" --no-config -dD '-DАНДРЕЙ@XYZ=62' '-DABC+TAIL=17' \
  '-UREMOVE@TAIL' -DREMOVE=99 "$base/empty.c" -o "$base/invalid-tail"
grep '^#define АНДРЕЙ 62$' "$base/invalid-tail" >/dev/null
grep '^#define ABC 17$' "$base/invalid-tail" >/dev/null
grep '^#define REMOVE 99$' "$base/invalid-tail" >/dev/null
if grep '^#define АНДРЕЙ @XYZ 62$' "$base/invalid-tail" >/dev/null; then
  exit 1
fi

# Explicit '=' in an -U tail is just another invalid suffix and is discarded.
"$MCPU_CPP" --no-config -DNAME=1 '-UNAME=bad' -dM "$base/empty.c" -o "$base/undef-tail"
if grep '^#define NAME ' "$base/undef-tail" >/dev/null; then
  exit 1
fi

# In -dD output command-line definitions have their own GNU-style origin
# marker and must not be reported as predefined/builtin macros.
"$MCPU_CPP" --no-config -dD -DАНДРЕЙ_К=62 -DОЛЬГА=37 \
  "$base/empty.c" -o "$base/dD-command-line"
awk '
  /^#define АНДРЕЙ_К 62$/ {
    if( previous != "# 0 \"<command-line>\"") exit 1
    andrey = 1
  }
  /^#define ОЛЬГА 37$/ {
    if( previous != "# 0 \"<command-line>\"") exit 1
    olga = 1
  }
  /^#define __MCPU_CPP_VERSION__ / {
    if( previous != "# 0 \"<built-in>\"") exit 1
    builtin = 1
  }
  { previous = $0 }
  END { if( !andrey || !olga || !builtin ) exit 1 }
' "$base/dD-command-line"

# An unterminated block comment in a command-line definition is diagnosed.
if "$MCPU_CPP" --no-config '-DBROKEN=left/*' "$base/empty.c" -o "$base/bad" \
     >"$base/comment-bad.stdout" 2>"$base/comment-bad.stderr"; then
  exit 1
fi
grep -- '-D: unterminated comment' "$base/comment-bad.stderr" >/dev/null

# Malformed macro names are rejected by the ordinary #define/#undef parsers.
if "$MCPU_CPP" --no-config -D1ABC=2 "$base/empty.c" -o "$base/bad" \
     >"$base/bad.stdout" 2>"$base/bad.stderr"; then
  exit 1
fi
grep 'macro name expected after #define' "$base/bad.stderr" >/dev/null


# Only -D/-U payloads are decoded.  Invalid UTF-8 and valid supplementary-plane
# UTF-8 are rejected because the internal text model is strict UCS-2.
bad_utf8=$(printf '\377')
if "$MCPU_CPP" --no-config "-D${bad_utf8}=1" "$base/empty.c" -o "$base/bad" \
     >"$base/utf8.stdout" 2>"$base/utf8.stderr"; then
  exit 1
fi
grep -- '-D: invalid UTF-8 or non-UCS-2 character' "$base/utf8.stderr" >/dev/null

non_ucs2=$(printf '\360\237\230\200')
if "$MCPU_CPP" --no-config "-D${non_ucs2}=1" "$base/empty.c" -o "$base/bad" \
     >"$base/nonucs2.stdout" 2>"$base/nonucs2.stderr"; then
  exit 1
fi
grep -- '-D: invalid UTF-8 or non-UCS-2 character' "$base/nonucs2.stderr" >/dev/null

if "$MCPU_CPP" --no-config "-U${bad_utf8}" "$base/empty.c" -o "$base/bad" \
     >"$base/utf8u.stdout" 2>"$base/utf8u.stderr"; then
  exit 1
fi
grep -- '-U: invalid UTF-8 or non-UCS-2 character' "$base/utf8u.stderr" >/dev/null