/* $NetBSD: lsym_preprocessing.c,v 1.15 2023/06/16 23:19:01 rillig Exp $ */
/*
* Tests for the token lsym_preprocessing, which represents a '#' that starts
* a preprocessing line.
*
* #define
* #ifdef
* #include
* #line
* #pragma
*
* The whole preprocessing line is processed separately from the main source
* code, without much tokenizing or parsing.
*/
// TODO: test '#' in the middle of a non-preprocessing line
// TODO: test stringify '#'
// TODO: test token paste '##'
//indent input
// TODO: add input
//indent end
//indent run-equals-input
/*
* Whitespace in the following preprocessing directives is preserved.
*/
//indent input
#define space ' ' /* the 'define' is followed by a space */
#define tab '\t' /* the 'define' is followed by a tab */
#if 0 /* 3 spaces */
#elif 0 /* 2 tabs */
#elif 0 > 1 /* tabs between the tokens */
#endif
//indent end
//indent run-equals-input
// TODO: #define unfinished_string "...
// TODO: #define unfinished_char '...
// TODO: # 123 "file.h"
// TODO: backslash-newline
// TODO: block comment
// TODO: line comment
//indent input
#include <system-header.h>
#include "local-header.h"
//indent end
//indent run-equals-input
/*
* Nested conditional compilation.
*/
//indent input
#if 0
#else
#endif
#if 0 /* if comment */
#else /* else comment */
#endif /* endif comment */
#if 0 /* outer if comment */
# if nested /* inner if comment */
# else /* inner else comment */
# endif /* inner endif comment */
#endif /* outer endif comment */
//indent end
//indent run-equals-input
//indent input
#define multi_line_definition /* first line
* middle
* final line
*/ actual_value
//indent end
//indent run-equals-input
/*
* Before indent.c 1.129 from 2021-10-08, indent mistakenly interpreted quotes
* in comments as starting a string literal. The '"' in the comment started a
* string, the next '"' finished the string, and the following '/' '*' was
* interpreted as the beginning of a comment. This comment lasted until the
* next '*' '/', which in this test is another preprocessor directive, solely
* for symmetry.
*
* The effect was that the extra space after d2 was not formatted, as that
* line was considered part of the comment.
*/
//indent input
#define comment_in_string_literal "/* no comment "
int this_is_an_ordinary_line_again;
int d1 ;
#define confuse_d /*"*/ "/*"
int d2 ;
#define resolve_d "*/"
int d3 ;
int s1 ;
#define confuse_s /*'*/ '/*'
int s2 ;
#define resolve_s '*/'
int s3 ;
//indent end
//indent run
#define comment_in_string_literal "/* no comment "
int this_is_an_ordinary_line_again;
int d1;
#define confuse_d /*"*/ "/*"
int d2;
#define resolve_d "*/"
int d3;
int s1;
#define confuse_s /*'*/ '/*'
int s2;
#define resolve_s '*/'
int s3;
//indent end
/*
* A preprocessing directive inside an expression keeps the state about
* whether the next operator is unary or binary.
*/
//indent input
int binary_plus = 3
#define intermediate 1
+4;
int unary_plus =
#define intermediate 1
+ 4;
//indent end
//indent run
int binary_plus = 3
#define intermediate 1
+ 4;
int unary_plus =
#define intermediate 1
+4;
//indent end
/*
* Before io.c 1.135 from 2021-11-26, indent fixed malformed preprocessing
* lines that had arguments even though they shouldn't. It is not the task of
* an indenter to fix code, that's what a linter is for.
*/
//indent input
#if 0
#elif 1
#else if 3
#endif 0
//indent end
//indent run-equals-input
/*
* Existing comments are indented just like code comments.
*
* This means that the above wrong preprocessing lines (#else with argument)
* need to be fed through indent twice until they become stable. Since
* compilers issue warnings about these invalid lines, not much code still has
* these, making this automatic fix an edge case.
*/
//indent input
#if 0 /* comment */
#else /* comment */
#endif /* comment */
#if 0/* comment */
#else/* comment */
#endif/* comment */
//indent end
//indent run-equals-input
/*
* Multi-line comments in preprocessing lines.
*/
//indent input
#define eol_comment // EOL
#define no_wrap_comment /* line 1
* line 2
* line 3
*/
#define fixed_comment /*- line 1
* line 2
* line 3
*/
#define two_comments /* 1 */ /* 2 */ /*3*/
#define three_comments /* first */ /* second */ /*third*/
//indent end
//indent run-equals-input
/*
* Do not touch multi-line macro definitions.
*/
//indent input
#define do_once(stmt) \
do { \
stmt; \
} while (/* constant condition */ false)
//indent end
//indent run-equals-input
/*
* The 'INDENT OFF' state is global, it does not depend on the preprocessing
* directives, otherwise the declarations for 'on' and 'after' would be moved
* to column 1.
*/
//indent input
int first_line;
int before;
#if 0
/*INDENT OFF*/
int off;
#else
int on;
#endif
int after;
//indent end
//indent run -di0
int first_line;
int before;
#if 0
/*INDENT OFF*/
int off;
#else
int on;
#endif
int after;
//indent end
/*
* Before 2023-06-14, indent was limited to 5 levels of conditional compilation
* directives.
*/
//indent input
#if 1
#if 2
#if 3
#if 4
#if 5
#if 6
#endif 6
#endif 5
#endif 4
#endif 3
#endif 2
#endif 1
//indent end
//indent run-equals-input
/*
* Unrecognized and unmatched preprocessing directives are preserved.
*/
//indent input
#else
#elif 0
#elifdef var
#endif
#unknown
# 3 "file.c"
//indent end
//indent run
#else
#elif 0
#elifdef var
#endif
#unknown
# 3 "file.c"
// exit 1
// error: Standard Input:1: Unmatched #else
// error: Standard Input:2: Unmatched #elif
// error: Standard Input:3: Unmatched #elifdef
// error: Standard Input:4: Unmatched #endif
//indent end
/*
* The '#' can only occur at the beginning of a line, therefore indent does not
* care when it occurs in the middle of a line.
*/
//indent input
int no = #;
//indent end
//indent run -di0
int no =
#;
//indent end
/*
* Preprocessing directives may be indented; indent moves them to the beginning
* of a line.
*/
//indent input
#if 0
#if 1 \
|| 2
#endif
#endif
//indent end
//indent run
#if 0
#if 1 \
|| 2
#endif
#endif
//indent end