1 /* $NetBSD: lsym_preprocessing.c,v 1.15 2023/06/16 23:19:01 rillig Exp $ */ 2 3 /* 4 * Tests for the token lsym_preprocessing, which represents a '#' that starts 5 * a preprocessing line. 6 * 7 * #define 8 * #ifdef 9 * #include 10 * #line 11 * #pragma 12 * 13 * The whole preprocessing line is processed separately from the main source 14 * code, without much tokenizing or parsing. 15 */ 16 17 // TODO: test '#' in the middle of a non-preprocessing line 18 // TODO: test stringify '#' 19 // TODO: test token paste '##' 20 21 //indent input 22 // TODO: add input 23 //indent end 24 25 //indent run-equals-input 26 27 28 /* 29 * Whitespace in the following preprocessing directives is preserved. 30 */ 31 //indent input 32 #define space ' ' /* the 'define' is followed by a space */ 33 #define tab '\t' /* the 'define' is followed by a tab */ 34 #if 0 /* 3 spaces */ 35 #elif 0 /* 2 tabs */ 36 #elif 0 > 1 /* tabs between the tokens */ 37 #endif 38 //indent end 39 40 //indent run-equals-input 41 42 // TODO: #define unfinished_string "... 43 // TODO: #define unfinished_char '... 44 // TODO: # 123 "file.h" 45 // TODO: backslash-newline 46 // TODO: block comment 47 // TODO: line comment 48 49 50 //indent input 51 #include <system-header.h> 52 #include "local-header.h" 53 //indent end 54 55 //indent run-equals-input 56 57 58 /* 59 * Nested conditional compilation. 60 */ 61 //indent input 62 #if 0 63 #else 64 #endif 65 66 #if 0 /* if comment */ 67 #else /* else comment */ 68 #endif /* endif comment */ 69 70 #if 0 /* outer if comment */ 71 # if nested /* inner if comment */ 72 # else /* inner else comment */ 73 # endif /* inner endif comment */ 74 #endif /* outer endif comment */ 75 //indent end 76 77 //indent run-equals-input 78 79 80 //indent input 81 #define multi_line_definition /* first line 82 * middle 83 * final line 84 */ actual_value 85 //indent end 86 87 //indent run-equals-input 88 89 90 /* 91 * Before indent.c 1.129 from 2021-10-08, indent mistakenly interpreted quotes 92 * in comments as starting a string literal. The '"' in the comment started a 93 * string, the next '"' finished the string, and the following '/' '*' was 94 * interpreted as the beginning of a comment. This comment lasted until the 95 * next '*' '/', which in this test is another preprocessor directive, solely 96 * for symmetry. 97 * 98 * The effect was that the extra space after d2 was not formatted, as that 99 * line was considered part of the comment. 100 */ 101 //indent input 102 #define comment_in_string_literal "/* no comment " 103 int this_is_an_ordinary_line_again; 104 105 int d1 ; 106 #define confuse_d /*"*/ "/*" 107 int d2 ; 108 #define resolve_d "*/" 109 int d3 ; 110 111 int s1 ; 112 #define confuse_s /*'*/ '/*' 113 int s2 ; 114 #define resolve_s '*/' 115 int s3 ; 116 //indent end 117 118 //indent run 119 #define comment_in_string_literal "/* no comment " 120 int this_is_an_ordinary_line_again; 121 122 int d1; 123 #define confuse_d /*"*/ "/*" 124 int d2; 125 #define resolve_d "*/" 126 int d3; 127 128 int s1; 129 #define confuse_s /*'*/ '/*' 130 int s2; 131 #define resolve_s '*/' 132 int s3; 133 //indent end 134 135 136 /* 137 * A preprocessing directive inside an expression keeps the state about 138 * whether the next operator is unary or binary. 139 */ 140 //indent input 141 int binary_plus = 3 142 #define intermediate 1 143 +4; 144 int unary_plus = 145 #define intermediate 1 146 + 4; 147 //indent end 148 149 //indent run 150 int binary_plus = 3 151 #define intermediate 1 152 + 4; 153 int unary_plus = 154 #define intermediate 1 155 +4; 156 //indent end 157 158 159 /* 160 * Before io.c 1.135 from 2021-11-26, indent fixed malformed preprocessing 161 * lines that had arguments even though they shouldn't. It is not the task of 162 * an indenter to fix code, that's what a linter is for. 163 */ 164 //indent input 165 #if 0 166 #elif 1 167 #else if 3 168 #endif 0 169 //indent end 170 171 //indent run-equals-input 172 173 174 /* 175 * Existing comments are indented just like code comments. 176 * 177 * This means that the above wrong preprocessing lines (#else with argument) 178 * need to be fed through indent twice until they become stable. Since 179 * compilers issue warnings about these invalid lines, not much code still has 180 * these, making this automatic fix an edge case. 181 */ 182 //indent input 183 #if 0 /* comment */ 184 #else /* comment */ 185 #endif /* comment */ 186 187 #if 0/* comment */ 188 #else/* comment */ 189 #endif/* comment */ 190 //indent end 191 192 //indent run-equals-input 193 194 195 /* 196 * Multi-line comments in preprocessing lines. 197 */ 198 //indent input 199 #define eol_comment // EOL 200 201 #define no_wrap_comment /* line 1 202 * line 2 203 * line 3 204 */ 205 206 #define fixed_comment /*- line 1 207 * line 2 208 * line 3 209 */ 210 211 #define two_comments /* 1 */ /* 2 */ /*3*/ 212 #define three_comments /* first */ /* second */ /*third*/ 213 //indent end 214 215 //indent run-equals-input 216 217 218 /* 219 * Do not touch multi-line macro definitions. 220 */ 221 //indent input 222 #define do_once(stmt) \ 223 do { \ 224 stmt; \ 225 } while (/* constant condition */ false) 226 //indent end 227 228 //indent run-equals-input 229 230 231 /* 232 * The 'INDENT OFF' state is global, it does not depend on the preprocessing 233 * directives, otherwise the declarations for 'on' and 'after' would be moved 234 * to column 1. 235 */ 236 //indent input 237 int first_line; 238 int before; 239 #if 0 240 /*INDENT OFF*/ 241 int off; 242 #else 243 int on; 244 #endif 245 int after; 246 //indent end 247 248 //indent run -di0 249 int first_line; 250 int before; 251 #if 0 252 /*INDENT OFF*/ 253 int off; 254 #else 255 int on; 256 #endif 257 int after; 258 //indent end 259 260 261 /* 262 * Before 2023-06-14, indent was limited to 5 levels of conditional compilation 263 * directives. 264 */ 265 //indent input 266 #if 1 267 #if 2 268 #if 3 269 #if 4 270 #if 5 271 #if 6 272 #endif 6 273 #endif 5 274 #endif 4 275 #endif 3 276 #endif 2 277 #endif 1 278 //indent end 279 280 //indent run-equals-input 281 282 283 /* 284 * Unrecognized and unmatched preprocessing directives are preserved. 285 */ 286 //indent input 287 #else 288 #elif 0 289 #elifdef var 290 #endif 291 292 #unknown 293 # 3 "file.c" 294 //indent end 295 296 //indent run 297 #else 298 #elif 0 299 #elifdef var 300 #endif 301 302 #unknown 303 # 3 "file.c" 304 // exit 1 305 // error: Standard Input:1: Unmatched #else 306 // error: Standard Input:2: Unmatched #elif 307 // error: Standard Input:3: Unmatched #elifdef 308 // error: Standard Input:4: Unmatched #endif 309 //indent end 310 311 312 /* 313 * The '#' can only occur at the beginning of a line, therefore indent does not 314 * care when it occurs in the middle of a line. 315 */ 316 //indent input 317 int no = #; 318 //indent end 319 320 //indent run -di0 321 int no = 322 #; 323 //indent end 324 325 326 /* 327 * Preprocessing directives may be indented; indent moves them to the beginning 328 * of a line. 329 */ 330 //indent input 331 #if 0 332 #if 1 \ 333 || 2 334 #endif 335 #endif 336 //indent end 337 338 //indent run 339 #if 0 340 #if 1 \ 341 || 2 342 #endif 343 #endif 344 //indent end 345