xref: /netbsd-src/tests/usr.bin/indent/lsym_preprocessing.c (revision 95820b5370230cc0c1b63cb504d714d2aa7f7b4a)
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