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 " 103int this_is_an_ordinary_line_again; 104 105int d1 ; 106#define confuse_d /*"*/ "/*" 107int d2 ; 108#define resolve_d "*/" 109int d3 ; 110 111int s1 ; 112#define confuse_s /*'*/ '/*' 113int s2 ; 114#define resolve_s '*/' 115int s3 ; 116//indent end 117 118//indent run 119#define comment_in_string_literal "/* no comment " 120int this_is_an_ordinary_line_again; 121 122int d1; 123#define confuse_d /*"*/ "/*" 124int d2; 125#define resolve_d "*/" 126int d3; 127 128int s1; 129#define confuse_s /*'*/ '/*' 130int s2; 131#define resolve_s '*/' 132int 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 141int binary_plus = 3 142#define intermediate 1 143 +4; 144int unary_plus = 145#define intermediate 1 146 + 4; 147//indent end 148 149//indent run 150int binary_plus = 3 151#define intermediate 1 152+ 4; 153int 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) \ 223do { \ 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 237int 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 249int first_line; 250int 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 317int no = #; 318//indent end 319 320//indent run -di0 321int 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