1f08c3bdfSopenharmony_ci/* 2f08c3bdfSopenharmony_ci * Do C preprocessing, based on a token list gathered by 3f08c3bdfSopenharmony_ci * the tokenizer. 4f08c3bdfSopenharmony_ci * 5f08c3bdfSopenharmony_ci * This may not be the smartest preprocessor on the planet. 6f08c3bdfSopenharmony_ci * 7f08c3bdfSopenharmony_ci * Copyright (C) 2003 Transmeta Corp. 8f08c3bdfSopenharmony_ci * 2003-2004 Linus Torvalds 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 11f08c3bdfSopenharmony_ci * of this software and associated documentation files (the "Software"), to deal 12f08c3bdfSopenharmony_ci * in the Software without restriction, including without limitation the rights 13f08c3bdfSopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14f08c3bdfSopenharmony_ci * copies of the Software, and to permit persons to whom the Software is 15f08c3bdfSopenharmony_ci * furnished to do so, subject to the following conditions: 16f08c3bdfSopenharmony_ci * 17f08c3bdfSopenharmony_ci * The above copyright notice and this permission notice shall be included in 18f08c3bdfSopenharmony_ci * all copies or substantial portions of the Software. 19f08c3bdfSopenharmony_ci * 20f08c3bdfSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21f08c3bdfSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22f08c3bdfSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23f08c3bdfSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24f08c3bdfSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25f08c3bdfSopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26f08c3bdfSopenharmony_ci * THE SOFTWARE. 27f08c3bdfSopenharmony_ci */ 28f08c3bdfSopenharmony_ci#include <stdio.h> 29f08c3bdfSopenharmony_ci#include <stdlib.h> 30f08c3bdfSopenharmony_ci#include <stdarg.h> 31f08c3bdfSopenharmony_ci#include <stddef.h> 32f08c3bdfSopenharmony_ci#include <string.h> 33f08c3bdfSopenharmony_ci#include <ctype.h> 34f08c3bdfSopenharmony_ci#include <unistd.h> 35f08c3bdfSopenharmony_ci#include <fcntl.h> 36f08c3bdfSopenharmony_ci#include <limits.h> 37f08c3bdfSopenharmony_ci#include <time.h> 38f08c3bdfSopenharmony_ci 39f08c3bdfSopenharmony_ci#include "lib.h" 40f08c3bdfSopenharmony_ci#include "allocate.h" 41f08c3bdfSopenharmony_ci#include "parse.h" 42f08c3bdfSopenharmony_ci#include "token.h" 43f08c3bdfSopenharmony_ci#include "symbol.h" 44f08c3bdfSopenharmony_ci#include "expression.h" 45f08c3bdfSopenharmony_ci#include "scope.h" 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_cistatic struct ident_list *macros; // only needed for -dD 48f08c3bdfSopenharmony_cistatic int false_nesting = 0; 49f08c3bdfSopenharmony_cistatic int counter_macro = 0; // __COUNTER__ expansion 50f08c3bdfSopenharmony_cistatic int include_level = 0; 51f08c3bdfSopenharmony_cistatic int expanding = 0; 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_ci#define INCLUDEPATHS 300 54f08c3bdfSopenharmony_ciconst char *includepath[INCLUDEPATHS+1] = { 55f08c3bdfSopenharmony_ci "", 56f08c3bdfSopenharmony_ci "/usr/include", 57f08c3bdfSopenharmony_ci "/usr/local/include", 58f08c3bdfSopenharmony_ci NULL 59f08c3bdfSopenharmony_ci}; 60f08c3bdfSopenharmony_ci 61f08c3bdfSopenharmony_cistatic const char **quote_includepath = includepath; 62f08c3bdfSopenharmony_cistatic const char **angle_includepath = includepath + 1; 63f08c3bdfSopenharmony_cistatic const char **isys_includepath = includepath + 1; 64f08c3bdfSopenharmony_cistatic const char **sys_includepath = includepath + 1; 65f08c3bdfSopenharmony_cistatic const char **dirafter_includepath = includepath + 3; 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_ci#define dirty_stream(stream) \ 68f08c3bdfSopenharmony_ci do { \ 69f08c3bdfSopenharmony_ci if (!stream->dirty) { \ 70f08c3bdfSopenharmony_ci stream->dirty = 1; \ 71f08c3bdfSopenharmony_ci if (!stream->ifndef) \ 72f08c3bdfSopenharmony_ci stream->protect = NULL; \ 73f08c3bdfSopenharmony_ci } \ 74f08c3bdfSopenharmony_ci } while(0) 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci#define end_group(stream) \ 77f08c3bdfSopenharmony_ci do { \ 78f08c3bdfSopenharmony_ci if (stream->ifndef == stream->top_if) { \ 79f08c3bdfSopenharmony_ci stream->ifndef = NULL; \ 80f08c3bdfSopenharmony_ci if (!stream->dirty) \ 81f08c3bdfSopenharmony_ci stream->protect = NULL; \ 82f08c3bdfSopenharmony_ci else if (stream->protect) \ 83f08c3bdfSopenharmony_ci stream->dirty = 0; \ 84f08c3bdfSopenharmony_ci } \ 85f08c3bdfSopenharmony_ci } while(0) 86f08c3bdfSopenharmony_ci 87f08c3bdfSopenharmony_ci#define nesting_error(stream) \ 88f08c3bdfSopenharmony_ci do { \ 89f08c3bdfSopenharmony_ci stream->dirty = 1; \ 90f08c3bdfSopenharmony_ci stream->ifndef = NULL; \ 91f08c3bdfSopenharmony_ci stream->protect = NULL; \ 92f08c3bdfSopenharmony_ci } while(0) 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_cistatic struct token *alloc_token(struct position *pos) 95f08c3bdfSopenharmony_ci{ 96f08c3bdfSopenharmony_ci struct token *token = __alloc_token(0); 97f08c3bdfSopenharmony_ci 98f08c3bdfSopenharmony_ci token->pos.stream = pos->stream; 99f08c3bdfSopenharmony_ci token->pos.line = pos->line; 100f08c3bdfSopenharmony_ci token->pos.pos = pos->pos; 101f08c3bdfSopenharmony_ci token->pos.whitespace = 1; 102f08c3bdfSopenharmony_ci return token; 103f08c3bdfSopenharmony_ci} 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci/* Expand symbol 'sym' at '*list' */ 106f08c3bdfSopenharmony_cistatic int expand(struct token **, struct symbol *); 107f08c3bdfSopenharmony_ci 108f08c3bdfSopenharmony_cistatic void replace_with_string(struct token *token, const char *str) 109f08c3bdfSopenharmony_ci{ 110f08c3bdfSopenharmony_ci int size = strlen(str) + 1; 111f08c3bdfSopenharmony_ci struct string *s = __alloc_string(size); 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_ci s->length = size; 114f08c3bdfSopenharmony_ci memcpy(s->data, str, size); 115f08c3bdfSopenharmony_ci token_type(token) = TOKEN_STRING; 116f08c3bdfSopenharmony_ci token->string = s; 117f08c3bdfSopenharmony_ci} 118f08c3bdfSopenharmony_ci 119f08c3bdfSopenharmony_cistatic void replace_with_integer(struct token *token, unsigned int val) 120f08c3bdfSopenharmony_ci{ 121f08c3bdfSopenharmony_ci char *buf = __alloc_bytes(11); 122f08c3bdfSopenharmony_ci sprintf(buf, "%u", val); 123f08c3bdfSopenharmony_ci token_type(token) = TOKEN_NUMBER; 124f08c3bdfSopenharmony_ci token->number = buf; 125f08c3bdfSopenharmony_ci} 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_cistatic struct symbol *lookup_macro(struct ident *ident) 128f08c3bdfSopenharmony_ci{ 129f08c3bdfSopenharmony_ci struct symbol *sym = lookup_symbol(ident, NS_MACRO | NS_UNDEF); 130f08c3bdfSopenharmony_ci if (sym && sym->namespace != NS_MACRO) 131f08c3bdfSopenharmony_ci sym = NULL; 132f08c3bdfSopenharmony_ci return sym; 133f08c3bdfSopenharmony_ci} 134f08c3bdfSopenharmony_ci 135f08c3bdfSopenharmony_cistatic int token_defined(struct token *token) 136f08c3bdfSopenharmony_ci{ 137f08c3bdfSopenharmony_ci if (token_type(token) == TOKEN_IDENT) { 138f08c3bdfSopenharmony_ci struct symbol *sym = lookup_macro(token->ident); 139f08c3bdfSopenharmony_ci if (sym) { 140f08c3bdfSopenharmony_ci sym->used_in = file_scope; 141f08c3bdfSopenharmony_ci return 1; 142f08c3bdfSopenharmony_ci } 143f08c3bdfSopenharmony_ci return 0; 144f08c3bdfSopenharmony_ci } 145f08c3bdfSopenharmony_ci 146f08c3bdfSopenharmony_ci sparse_error(token->pos, "expected preprocessor identifier"); 147f08c3bdfSopenharmony_ci return 0; 148f08c3bdfSopenharmony_ci} 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_cistatic void replace_with_bool(struct token *token, bool val) 151f08c3bdfSopenharmony_ci{ 152f08c3bdfSopenharmony_ci static const char *string[] = { "0", "1" }; 153f08c3bdfSopenharmony_ci 154f08c3bdfSopenharmony_ci token_type(token) = TOKEN_NUMBER; 155f08c3bdfSopenharmony_ci token->number = string[val]; 156f08c3bdfSopenharmony_ci} 157f08c3bdfSopenharmony_ci 158f08c3bdfSopenharmony_cistatic void replace_with_defined(struct token *token) 159f08c3bdfSopenharmony_ci{ 160f08c3bdfSopenharmony_ci replace_with_bool(token, token_defined(token)); 161f08c3bdfSopenharmony_ci} 162f08c3bdfSopenharmony_ci 163f08c3bdfSopenharmony_cistatic void expand_line(struct token *token) 164f08c3bdfSopenharmony_ci{ 165f08c3bdfSopenharmony_ci replace_with_integer(token, token->pos.line); 166f08c3bdfSopenharmony_ci} 167f08c3bdfSopenharmony_ci 168f08c3bdfSopenharmony_cistatic void expand_file(struct token *token) 169f08c3bdfSopenharmony_ci{ 170f08c3bdfSopenharmony_ci replace_with_string(token, stream_name(token->pos.stream)); 171f08c3bdfSopenharmony_ci} 172f08c3bdfSopenharmony_ci 173f08c3bdfSopenharmony_cistatic void expand_basefile(struct token *token) 174f08c3bdfSopenharmony_ci{ 175f08c3bdfSopenharmony_ci replace_with_string(token, base_filename); 176f08c3bdfSopenharmony_ci} 177f08c3bdfSopenharmony_ci 178f08c3bdfSopenharmony_cistatic time_t t = 0; 179f08c3bdfSopenharmony_cistatic void expand_date(struct token *token) 180f08c3bdfSopenharmony_ci{ 181f08c3bdfSopenharmony_ci static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */ 182f08c3bdfSopenharmony_ci 183f08c3bdfSopenharmony_ci if (!t) 184f08c3bdfSopenharmony_ci time(&t); 185f08c3bdfSopenharmony_ci strftime(buffer, 12, "%b %e %Y", localtime(&t)); 186f08c3bdfSopenharmony_ci replace_with_string(token, buffer); 187f08c3bdfSopenharmony_ci} 188f08c3bdfSopenharmony_ci 189f08c3bdfSopenharmony_cistatic void expand_time(struct token *token) 190f08c3bdfSopenharmony_ci{ 191f08c3bdfSopenharmony_ci static char buffer[9]; /* __TIME__: 2 + ':' + 2 + ':' + 2 + '\0' */ 192f08c3bdfSopenharmony_ci 193f08c3bdfSopenharmony_ci if (!t) 194f08c3bdfSopenharmony_ci time(&t); 195f08c3bdfSopenharmony_ci strftime(buffer, 9, "%T", localtime(&t)); 196f08c3bdfSopenharmony_ci replace_with_string(token, buffer); 197f08c3bdfSopenharmony_ci} 198f08c3bdfSopenharmony_ci 199f08c3bdfSopenharmony_cistatic void expand_counter(struct token *token) 200f08c3bdfSopenharmony_ci{ 201f08c3bdfSopenharmony_ci replace_with_integer(token, counter_macro++); 202f08c3bdfSopenharmony_ci} 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_cistatic void expand_include_level(struct token *token) 205f08c3bdfSopenharmony_ci{ 206f08c3bdfSopenharmony_ci replace_with_integer(token, include_level - 1); 207f08c3bdfSopenharmony_ci} 208f08c3bdfSopenharmony_ci 209f08c3bdfSopenharmony_cistatic int expand_one_symbol(struct token **list) 210f08c3bdfSopenharmony_ci{ 211f08c3bdfSopenharmony_ci struct token *token = *list; 212f08c3bdfSopenharmony_ci struct symbol *sym; 213f08c3bdfSopenharmony_ci 214f08c3bdfSopenharmony_ci if (token->pos.noexpand) 215f08c3bdfSopenharmony_ci return 1; 216f08c3bdfSopenharmony_ci 217f08c3bdfSopenharmony_ci sym = lookup_macro(token->ident); 218f08c3bdfSopenharmony_ci if (!sym) 219f08c3bdfSopenharmony_ci return 1; 220f08c3bdfSopenharmony_ci if (sym->expand_simple) { 221f08c3bdfSopenharmony_ci sym->expand_simple(token); 222f08c3bdfSopenharmony_ci return 1; 223f08c3bdfSopenharmony_ci } else { 224f08c3bdfSopenharmony_ci int rc; 225f08c3bdfSopenharmony_ci 226f08c3bdfSopenharmony_ci sym->used_in = file_scope; 227f08c3bdfSopenharmony_ci expanding = 1; 228f08c3bdfSopenharmony_ci rc = expand(list, sym); 229f08c3bdfSopenharmony_ci expanding = 0; 230f08c3bdfSopenharmony_ci return rc; 231f08c3bdfSopenharmony_ci } 232f08c3bdfSopenharmony_ci} 233f08c3bdfSopenharmony_ci 234f08c3bdfSopenharmony_cistatic inline struct token *scan_next(struct token **where) 235f08c3bdfSopenharmony_ci{ 236f08c3bdfSopenharmony_ci struct token *token = *where; 237f08c3bdfSopenharmony_ci if (token_type(token) != TOKEN_UNTAINT) 238f08c3bdfSopenharmony_ci return token; 239f08c3bdfSopenharmony_ci do { 240f08c3bdfSopenharmony_ci token->ident->tainted = 0; 241f08c3bdfSopenharmony_ci token = token->next; 242f08c3bdfSopenharmony_ci } while (token_type(token) == TOKEN_UNTAINT); 243f08c3bdfSopenharmony_ci *where = token; 244f08c3bdfSopenharmony_ci return token; 245f08c3bdfSopenharmony_ci} 246f08c3bdfSopenharmony_ci 247f08c3bdfSopenharmony_cistatic void expand_list(struct token **list) 248f08c3bdfSopenharmony_ci{ 249f08c3bdfSopenharmony_ci struct token *next; 250f08c3bdfSopenharmony_ci while (!eof_token(next = scan_next(list))) { 251f08c3bdfSopenharmony_ci if (token_type(next) != TOKEN_IDENT || expand_one_symbol(list)) 252f08c3bdfSopenharmony_ci list = &next->next; 253f08c3bdfSopenharmony_ci } 254f08c3bdfSopenharmony_ci} 255f08c3bdfSopenharmony_ci 256f08c3bdfSopenharmony_cistatic void preprocessor_line(struct stream *stream, struct token **line); 257f08c3bdfSopenharmony_ci 258f08c3bdfSopenharmony_cistatic struct token *collect_arg(struct token *prev, int vararg, struct position *pos, int count) 259f08c3bdfSopenharmony_ci{ 260f08c3bdfSopenharmony_ci struct stream *stream = input_streams + prev->pos.stream; 261f08c3bdfSopenharmony_ci struct token **p = &prev->next; 262f08c3bdfSopenharmony_ci struct token *next; 263f08c3bdfSopenharmony_ci int nesting = 0; 264f08c3bdfSopenharmony_ci 265f08c3bdfSopenharmony_ci while (!eof_token(next = scan_next(p))) { 266f08c3bdfSopenharmony_ci if (next->pos.newline && match_op(next, '#')) { 267f08c3bdfSopenharmony_ci if (!next->pos.noexpand) { 268f08c3bdfSopenharmony_ci preprocessor_line(stream, p); 269f08c3bdfSopenharmony_ci __free_token(next); /* Free the '#' token */ 270f08c3bdfSopenharmony_ci continue; 271f08c3bdfSopenharmony_ci } 272f08c3bdfSopenharmony_ci } 273f08c3bdfSopenharmony_ci switch (token_type(next)) { 274f08c3bdfSopenharmony_ci case TOKEN_STREAMEND: 275f08c3bdfSopenharmony_ci case TOKEN_STREAMBEGIN: 276f08c3bdfSopenharmony_ci *p = &eof_token_entry; 277f08c3bdfSopenharmony_ci return next; 278f08c3bdfSopenharmony_ci case TOKEN_STRING: 279f08c3bdfSopenharmony_ci case TOKEN_WIDE_STRING: 280f08c3bdfSopenharmony_ci if (count > 1) 281f08c3bdfSopenharmony_ci next->string->immutable = 1; 282f08c3bdfSopenharmony_ci break; 283f08c3bdfSopenharmony_ci } 284f08c3bdfSopenharmony_ci if (false_nesting) { 285f08c3bdfSopenharmony_ci *p = next->next; 286f08c3bdfSopenharmony_ci __free_token(next); 287f08c3bdfSopenharmony_ci continue; 288f08c3bdfSopenharmony_ci } 289f08c3bdfSopenharmony_ci if (match_op(next, '(')) { 290f08c3bdfSopenharmony_ci nesting++; 291f08c3bdfSopenharmony_ci } else if (match_op(next, ')')) { 292f08c3bdfSopenharmony_ci if (!nesting--) 293f08c3bdfSopenharmony_ci break; 294f08c3bdfSopenharmony_ci } else if (match_op(next, ',') && !nesting && !vararg) { 295f08c3bdfSopenharmony_ci break; 296f08c3bdfSopenharmony_ci } 297f08c3bdfSopenharmony_ci next->pos.stream = pos->stream; 298f08c3bdfSopenharmony_ci next->pos.line = pos->line; 299f08c3bdfSopenharmony_ci next->pos.pos = pos->pos; 300f08c3bdfSopenharmony_ci next->pos.newline = 0; 301f08c3bdfSopenharmony_ci p = &next->next; 302f08c3bdfSopenharmony_ci } 303f08c3bdfSopenharmony_ci *p = &eof_token_entry; 304f08c3bdfSopenharmony_ci return next; 305f08c3bdfSopenharmony_ci} 306f08c3bdfSopenharmony_ci 307f08c3bdfSopenharmony_ci/* 308f08c3bdfSopenharmony_ci * We store arglist as <counter> [arg1] <number of uses for arg1> ... eof 309f08c3bdfSopenharmony_ci */ 310f08c3bdfSopenharmony_ci 311f08c3bdfSopenharmony_cistruct arg { 312f08c3bdfSopenharmony_ci struct token *arg; 313f08c3bdfSopenharmony_ci struct token *expanded; 314f08c3bdfSopenharmony_ci struct token *str; 315f08c3bdfSopenharmony_ci int n_normal; 316f08c3bdfSopenharmony_ci int n_quoted; 317f08c3bdfSopenharmony_ci int n_str; 318f08c3bdfSopenharmony_ci}; 319f08c3bdfSopenharmony_ci 320f08c3bdfSopenharmony_cistatic int collect_arguments(struct token *start, struct token *arglist, struct arg *args, struct token *what) 321f08c3bdfSopenharmony_ci{ 322f08c3bdfSopenharmony_ci int wanted = arglist->count.normal; 323f08c3bdfSopenharmony_ci struct token *next = NULL; 324f08c3bdfSopenharmony_ci int count = 0; 325f08c3bdfSopenharmony_ci 326f08c3bdfSopenharmony_ci arglist = arglist->next; /* skip counter */ 327f08c3bdfSopenharmony_ci 328f08c3bdfSopenharmony_ci if (!wanted) { 329f08c3bdfSopenharmony_ci next = collect_arg(start, 0, &what->pos, 0); 330f08c3bdfSopenharmony_ci if (eof_token(next)) 331f08c3bdfSopenharmony_ci goto Eclosing; 332f08c3bdfSopenharmony_ci if (!eof_token(start->next) || !match_op(next, ')')) { 333f08c3bdfSopenharmony_ci count++; 334f08c3bdfSopenharmony_ci goto Emany; 335f08c3bdfSopenharmony_ci } 336f08c3bdfSopenharmony_ci } else { 337f08c3bdfSopenharmony_ci for (count = 0; count < wanted; count++) { 338f08c3bdfSopenharmony_ci struct argcount *p = &arglist->next->count; 339f08c3bdfSopenharmony_ci next = collect_arg(start, p->vararg, &what->pos, p->normal); 340f08c3bdfSopenharmony_ci if (eof_token(next)) 341f08c3bdfSopenharmony_ci goto Eclosing; 342f08c3bdfSopenharmony_ci if (p->vararg && wanted == 1 && eof_token(start->next)) 343f08c3bdfSopenharmony_ci break; 344f08c3bdfSopenharmony_ci arglist = arglist->next->next; 345f08c3bdfSopenharmony_ci args[count].arg = start->next; 346f08c3bdfSopenharmony_ci args[count].n_normal = p->normal; 347f08c3bdfSopenharmony_ci args[count].n_quoted = p->quoted; 348f08c3bdfSopenharmony_ci args[count].n_str = p->str; 349f08c3bdfSopenharmony_ci if (match_op(next, ')')) { 350f08c3bdfSopenharmony_ci count++; 351f08c3bdfSopenharmony_ci break; 352f08c3bdfSopenharmony_ci } 353f08c3bdfSopenharmony_ci start = next; 354f08c3bdfSopenharmony_ci } 355f08c3bdfSopenharmony_ci if (count == wanted && !match_op(next, ')')) 356f08c3bdfSopenharmony_ci goto Emany; 357f08c3bdfSopenharmony_ci if (count == wanted - 1) { 358f08c3bdfSopenharmony_ci struct argcount *p = &arglist->next->count; 359f08c3bdfSopenharmony_ci if (!p->vararg) 360f08c3bdfSopenharmony_ci goto Efew; 361f08c3bdfSopenharmony_ci args[count].arg = NULL; 362f08c3bdfSopenharmony_ci args[count].n_normal = p->normal; 363f08c3bdfSopenharmony_ci args[count].n_quoted = p->quoted; 364f08c3bdfSopenharmony_ci args[count].n_str = p->str; 365f08c3bdfSopenharmony_ci } 366f08c3bdfSopenharmony_ci if (count < wanted - 1) 367f08c3bdfSopenharmony_ci goto Efew; 368f08c3bdfSopenharmony_ci } 369f08c3bdfSopenharmony_ci what->next = next->next; 370f08c3bdfSopenharmony_ci return 1; 371f08c3bdfSopenharmony_ci 372f08c3bdfSopenharmony_ciEfew: 373f08c3bdfSopenharmony_ci sparse_error(what->pos, "macro \"%s\" requires %d arguments, but only %d given", 374f08c3bdfSopenharmony_ci show_token(what), wanted, count); 375f08c3bdfSopenharmony_ci goto out; 376f08c3bdfSopenharmony_ciEmany: 377f08c3bdfSopenharmony_ci while (match_op(next, ',')) { 378f08c3bdfSopenharmony_ci next = collect_arg(next, 0, &what->pos, 0); 379f08c3bdfSopenharmony_ci count++; 380f08c3bdfSopenharmony_ci } 381f08c3bdfSopenharmony_ci if (eof_token(next)) 382f08c3bdfSopenharmony_ci goto Eclosing; 383f08c3bdfSopenharmony_ci sparse_error(what->pos, "macro \"%s\" passed %d arguments, but takes just %d", 384f08c3bdfSopenharmony_ci show_token(what), count, wanted); 385f08c3bdfSopenharmony_ci goto out; 386f08c3bdfSopenharmony_ciEclosing: 387f08c3bdfSopenharmony_ci sparse_error(what->pos, "unterminated argument list invoking macro \"%s\"", 388f08c3bdfSopenharmony_ci show_token(what)); 389f08c3bdfSopenharmony_ciout: 390f08c3bdfSopenharmony_ci what->next = next->next; 391f08c3bdfSopenharmony_ci return 0; 392f08c3bdfSopenharmony_ci} 393f08c3bdfSopenharmony_ci 394f08c3bdfSopenharmony_cistatic struct token *dup_list(struct token *list) 395f08c3bdfSopenharmony_ci{ 396f08c3bdfSopenharmony_ci struct token *res = NULL; 397f08c3bdfSopenharmony_ci struct token **p = &res; 398f08c3bdfSopenharmony_ci 399f08c3bdfSopenharmony_ci while (!eof_token(list)) { 400f08c3bdfSopenharmony_ci struct token *newtok = __alloc_token(0); 401f08c3bdfSopenharmony_ci *newtok = *list; 402f08c3bdfSopenharmony_ci *p = newtok; 403f08c3bdfSopenharmony_ci p = &newtok->next; 404f08c3bdfSopenharmony_ci list = list->next; 405f08c3bdfSopenharmony_ci } 406f08c3bdfSopenharmony_ci return res; 407f08c3bdfSopenharmony_ci} 408f08c3bdfSopenharmony_ci 409f08c3bdfSopenharmony_cistatic const char *show_token_sequence(struct token *token, int quote) 410f08c3bdfSopenharmony_ci{ 411f08c3bdfSopenharmony_ci static char buffer[MAX_STRING]; 412f08c3bdfSopenharmony_ci char *ptr = buffer; 413f08c3bdfSopenharmony_ci int whitespace = 0; 414f08c3bdfSopenharmony_ci 415f08c3bdfSopenharmony_ci if (!token && !quote) 416f08c3bdfSopenharmony_ci return "<none>"; 417f08c3bdfSopenharmony_ci while (!eof_token(token)) { 418f08c3bdfSopenharmony_ci const char *val = quote ? quote_token(token) : show_token(token); 419f08c3bdfSopenharmony_ci int len = strlen(val); 420f08c3bdfSopenharmony_ci 421f08c3bdfSopenharmony_ci if (ptr + whitespace + len >= buffer + sizeof(buffer)) { 422f08c3bdfSopenharmony_ci sparse_error(token->pos, "too long token expansion"); 423f08c3bdfSopenharmony_ci break; 424f08c3bdfSopenharmony_ci } 425f08c3bdfSopenharmony_ci 426f08c3bdfSopenharmony_ci if (whitespace) 427f08c3bdfSopenharmony_ci *ptr++ = ' '; 428f08c3bdfSopenharmony_ci memcpy(ptr, val, len); 429f08c3bdfSopenharmony_ci ptr += len; 430f08c3bdfSopenharmony_ci token = token->next; 431f08c3bdfSopenharmony_ci whitespace = token->pos.whitespace; 432f08c3bdfSopenharmony_ci } 433f08c3bdfSopenharmony_ci *ptr = 0; 434f08c3bdfSopenharmony_ci return buffer; 435f08c3bdfSopenharmony_ci} 436f08c3bdfSopenharmony_ci 437f08c3bdfSopenharmony_cistatic struct token *stringify(struct token *arg) 438f08c3bdfSopenharmony_ci{ 439f08c3bdfSopenharmony_ci const char *s = show_token_sequence(arg, 1); 440f08c3bdfSopenharmony_ci int size = strlen(s)+1; 441f08c3bdfSopenharmony_ci struct token *token = __alloc_token(0); 442f08c3bdfSopenharmony_ci struct string *string = __alloc_string(size); 443f08c3bdfSopenharmony_ci 444f08c3bdfSopenharmony_ci memcpy(string->data, s, size); 445f08c3bdfSopenharmony_ci string->length = size; 446f08c3bdfSopenharmony_ci token->pos = arg->pos; 447f08c3bdfSopenharmony_ci token_type(token) = TOKEN_STRING; 448f08c3bdfSopenharmony_ci token->string = string; 449f08c3bdfSopenharmony_ci token->next = &eof_token_entry; 450f08c3bdfSopenharmony_ci return token; 451f08c3bdfSopenharmony_ci} 452f08c3bdfSopenharmony_ci 453f08c3bdfSopenharmony_cistatic void expand_arguments(int count, struct arg *args) 454f08c3bdfSopenharmony_ci{ 455f08c3bdfSopenharmony_ci int i; 456f08c3bdfSopenharmony_ci for (i = 0; i < count; i++) { 457f08c3bdfSopenharmony_ci struct token *arg = args[i].arg; 458f08c3bdfSopenharmony_ci if (!arg) 459f08c3bdfSopenharmony_ci arg = &eof_token_entry; 460f08c3bdfSopenharmony_ci if (args[i].n_str) 461f08c3bdfSopenharmony_ci args[i].str = stringify(arg); 462f08c3bdfSopenharmony_ci if (args[i].n_normal) { 463f08c3bdfSopenharmony_ci if (!args[i].n_quoted) { 464f08c3bdfSopenharmony_ci args[i].expanded = arg; 465f08c3bdfSopenharmony_ci args[i].arg = NULL; 466f08c3bdfSopenharmony_ci } else if (eof_token(arg)) { 467f08c3bdfSopenharmony_ci args[i].expanded = arg; 468f08c3bdfSopenharmony_ci } else { 469f08c3bdfSopenharmony_ci args[i].expanded = dup_list(arg); 470f08c3bdfSopenharmony_ci } 471f08c3bdfSopenharmony_ci expand_list(&args[i].expanded); 472f08c3bdfSopenharmony_ci } 473f08c3bdfSopenharmony_ci } 474f08c3bdfSopenharmony_ci} 475f08c3bdfSopenharmony_ci 476f08c3bdfSopenharmony_ci/* 477f08c3bdfSopenharmony_ci * Possibly valid combinations: 478f08c3bdfSopenharmony_ci * - ident + ident -> ident 479f08c3bdfSopenharmony_ci * - ident + number -> ident unless number contains '.', '+' or '-'. 480f08c3bdfSopenharmony_ci * - 'L' + char constant -> wide char constant 481f08c3bdfSopenharmony_ci * - 'L' + string literal -> wide string literal 482f08c3bdfSopenharmony_ci * - number + number -> number 483f08c3bdfSopenharmony_ci * - number + ident -> number 484f08c3bdfSopenharmony_ci * - number + '.' -> number 485f08c3bdfSopenharmony_ci * - number + '+' or '-' -> number, if number used to end on [eEpP]. 486f08c3bdfSopenharmony_ci * - '.' + number -> number, if number used to start with a digit. 487f08c3bdfSopenharmony_ci * - special + special -> either special or an error. 488f08c3bdfSopenharmony_ci */ 489f08c3bdfSopenharmony_cistatic enum token_type combine(struct token *left, struct token *right, char *p) 490f08c3bdfSopenharmony_ci{ 491f08c3bdfSopenharmony_ci int len; 492f08c3bdfSopenharmony_ci enum token_type t1 = token_type(left), t2 = token_type(right); 493f08c3bdfSopenharmony_ci 494f08c3bdfSopenharmony_ci if (t1 != TOKEN_IDENT && t1 != TOKEN_NUMBER && t1 != TOKEN_SPECIAL) 495f08c3bdfSopenharmony_ci return TOKEN_ERROR; 496f08c3bdfSopenharmony_ci 497f08c3bdfSopenharmony_ci if (t1 == TOKEN_IDENT && left->ident == &L_ident) { 498f08c3bdfSopenharmony_ci if (t2 >= TOKEN_CHAR && t2 < TOKEN_WIDE_CHAR) 499f08c3bdfSopenharmony_ci return t2 + TOKEN_WIDE_CHAR - TOKEN_CHAR; 500f08c3bdfSopenharmony_ci if (t2 == TOKEN_STRING) 501f08c3bdfSopenharmony_ci return TOKEN_WIDE_STRING; 502f08c3bdfSopenharmony_ci } 503f08c3bdfSopenharmony_ci 504f08c3bdfSopenharmony_ci if (t2 != TOKEN_IDENT && t2 != TOKEN_NUMBER && t2 != TOKEN_SPECIAL) 505f08c3bdfSopenharmony_ci return TOKEN_ERROR; 506f08c3bdfSopenharmony_ci 507f08c3bdfSopenharmony_ci strcpy(p, show_token(left)); 508f08c3bdfSopenharmony_ci strcat(p, show_token(right)); 509f08c3bdfSopenharmony_ci len = strlen(p); 510f08c3bdfSopenharmony_ci 511f08c3bdfSopenharmony_ci if (len >= 256) 512f08c3bdfSopenharmony_ci return TOKEN_ERROR; 513f08c3bdfSopenharmony_ci 514f08c3bdfSopenharmony_ci if (t1 == TOKEN_IDENT) { 515f08c3bdfSopenharmony_ci if (t2 == TOKEN_SPECIAL) 516f08c3bdfSopenharmony_ci return TOKEN_ERROR; 517f08c3bdfSopenharmony_ci if (t2 == TOKEN_NUMBER && strpbrk(p, "+-.")) 518f08c3bdfSopenharmony_ci return TOKEN_ERROR; 519f08c3bdfSopenharmony_ci return TOKEN_IDENT; 520f08c3bdfSopenharmony_ci } 521f08c3bdfSopenharmony_ci 522f08c3bdfSopenharmony_ci if (t1 == TOKEN_NUMBER) { 523f08c3bdfSopenharmony_ci if (t2 == TOKEN_SPECIAL) { 524f08c3bdfSopenharmony_ci switch (right->special) { 525f08c3bdfSopenharmony_ci case '.': 526f08c3bdfSopenharmony_ci break; 527f08c3bdfSopenharmony_ci case '+': case '-': 528f08c3bdfSopenharmony_ci if (strchr("eEpP", p[len - 2])) 529f08c3bdfSopenharmony_ci break; 530f08c3bdfSopenharmony_ci default: 531f08c3bdfSopenharmony_ci return TOKEN_ERROR; 532f08c3bdfSopenharmony_ci } 533f08c3bdfSopenharmony_ci } 534f08c3bdfSopenharmony_ci return TOKEN_NUMBER; 535f08c3bdfSopenharmony_ci } 536f08c3bdfSopenharmony_ci 537f08c3bdfSopenharmony_ci if (p[0] == '.' && isdigit((unsigned char)p[1])) 538f08c3bdfSopenharmony_ci return TOKEN_NUMBER; 539f08c3bdfSopenharmony_ci 540f08c3bdfSopenharmony_ci return TOKEN_SPECIAL; 541f08c3bdfSopenharmony_ci} 542f08c3bdfSopenharmony_ci 543f08c3bdfSopenharmony_cistatic int merge(struct token *left, struct token *right) 544f08c3bdfSopenharmony_ci{ 545f08c3bdfSopenharmony_ci static char buffer[512]; 546f08c3bdfSopenharmony_ci enum token_type res = combine(left, right, buffer); 547f08c3bdfSopenharmony_ci int n; 548f08c3bdfSopenharmony_ci 549f08c3bdfSopenharmony_ci switch (res) { 550f08c3bdfSopenharmony_ci case TOKEN_IDENT: 551f08c3bdfSopenharmony_ci left->ident = built_in_ident(buffer); 552f08c3bdfSopenharmony_ci left->pos.noexpand = 0; 553f08c3bdfSopenharmony_ci return 1; 554f08c3bdfSopenharmony_ci 555f08c3bdfSopenharmony_ci case TOKEN_NUMBER: 556f08c3bdfSopenharmony_ci token_type(left) = TOKEN_NUMBER; /* could be . + num */ 557f08c3bdfSopenharmony_ci left->number = xstrdup(buffer); 558f08c3bdfSopenharmony_ci return 1; 559f08c3bdfSopenharmony_ci 560f08c3bdfSopenharmony_ci case TOKEN_SPECIAL: 561f08c3bdfSopenharmony_ci if (buffer[2] && buffer[3]) 562f08c3bdfSopenharmony_ci break; 563f08c3bdfSopenharmony_ci for (n = SPECIAL_BASE; n < SPECIAL_ARG_SEPARATOR; n++) { 564f08c3bdfSopenharmony_ci if (!memcmp(buffer, combinations[n-SPECIAL_BASE], 3)) { 565f08c3bdfSopenharmony_ci left->special = n; 566f08c3bdfSopenharmony_ci return 1; 567f08c3bdfSopenharmony_ci } 568f08c3bdfSopenharmony_ci } 569f08c3bdfSopenharmony_ci break; 570f08c3bdfSopenharmony_ci 571f08c3bdfSopenharmony_ci case TOKEN_WIDE_CHAR: 572f08c3bdfSopenharmony_ci case TOKEN_WIDE_STRING: 573f08c3bdfSopenharmony_ci token_type(left) = res; 574f08c3bdfSopenharmony_ci left->pos.noexpand = 0; 575f08c3bdfSopenharmony_ci left->string = right->string; 576f08c3bdfSopenharmony_ci return 1; 577f08c3bdfSopenharmony_ci 578f08c3bdfSopenharmony_ci case TOKEN_WIDE_CHAR_EMBEDDED_0 ... TOKEN_WIDE_CHAR_EMBEDDED_3: 579f08c3bdfSopenharmony_ci token_type(left) = res; 580f08c3bdfSopenharmony_ci left->pos.noexpand = 0; 581f08c3bdfSopenharmony_ci memcpy(left->embedded, right->embedded, 4); 582f08c3bdfSopenharmony_ci return 1; 583f08c3bdfSopenharmony_ci 584f08c3bdfSopenharmony_ci default: 585f08c3bdfSopenharmony_ci ; 586f08c3bdfSopenharmony_ci } 587f08c3bdfSopenharmony_ci sparse_error(left->pos, "'##' failed: concatenation is not a valid token"); 588f08c3bdfSopenharmony_ci return 0; 589f08c3bdfSopenharmony_ci} 590f08c3bdfSopenharmony_ci 591f08c3bdfSopenharmony_cistatic struct token *dup_token(struct token *token, struct position *streampos) 592f08c3bdfSopenharmony_ci{ 593f08c3bdfSopenharmony_ci struct token *alloc = alloc_token(streampos); 594f08c3bdfSopenharmony_ci token_type(alloc) = token_type(token); 595f08c3bdfSopenharmony_ci alloc->pos.newline = token->pos.newline; 596f08c3bdfSopenharmony_ci alloc->pos.whitespace = token->pos.whitespace; 597f08c3bdfSopenharmony_ci alloc->number = token->number; 598f08c3bdfSopenharmony_ci alloc->pos.noexpand = token->pos.noexpand; 599f08c3bdfSopenharmony_ci return alloc; 600f08c3bdfSopenharmony_ci} 601f08c3bdfSopenharmony_ci 602f08c3bdfSopenharmony_cistatic struct token **copy(struct token **where, struct token *list, int *count) 603f08c3bdfSopenharmony_ci{ 604f08c3bdfSopenharmony_ci int need_copy = --*count; 605f08c3bdfSopenharmony_ci while (!eof_token(list)) { 606f08c3bdfSopenharmony_ci struct token *token; 607f08c3bdfSopenharmony_ci if (need_copy) 608f08c3bdfSopenharmony_ci token = dup_token(list, &list->pos); 609f08c3bdfSopenharmony_ci else 610f08c3bdfSopenharmony_ci token = list; 611f08c3bdfSopenharmony_ci if (token_type(token) == TOKEN_IDENT && token->ident->tainted) 612f08c3bdfSopenharmony_ci token->pos.noexpand = 1; 613f08c3bdfSopenharmony_ci *where = token; 614f08c3bdfSopenharmony_ci where = &token->next; 615f08c3bdfSopenharmony_ci list = list->next; 616f08c3bdfSopenharmony_ci } 617f08c3bdfSopenharmony_ci *where = &eof_token_entry; 618f08c3bdfSopenharmony_ci return where; 619f08c3bdfSopenharmony_ci} 620f08c3bdfSopenharmony_ci 621f08c3bdfSopenharmony_cistatic int handle_kludge(struct token **p, struct arg *args) 622f08c3bdfSopenharmony_ci{ 623f08c3bdfSopenharmony_ci struct token *t = (*p)->next->next; 624f08c3bdfSopenharmony_ci while (1) { 625f08c3bdfSopenharmony_ci struct arg *v = &args[t->argnum]; 626f08c3bdfSopenharmony_ci if (token_type(t->next) != TOKEN_CONCAT) { 627f08c3bdfSopenharmony_ci if (v->arg) { 628f08c3bdfSopenharmony_ci /* ignore the first ## */ 629f08c3bdfSopenharmony_ci *p = (*p)->next; 630f08c3bdfSopenharmony_ci return 0; 631f08c3bdfSopenharmony_ci } 632f08c3bdfSopenharmony_ci /* skip the entire thing */ 633f08c3bdfSopenharmony_ci *p = t; 634f08c3bdfSopenharmony_ci return 1; 635f08c3bdfSopenharmony_ci } 636f08c3bdfSopenharmony_ci if (v->arg && !eof_token(v->arg)) 637f08c3bdfSopenharmony_ci return 0; /* no magic */ 638f08c3bdfSopenharmony_ci t = t->next->next; 639f08c3bdfSopenharmony_ci } 640f08c3bdfSopenharmony_ci} 641f08c3bdfSopenharmony_ci 642f08c3bdfSopenharmony_cistatic struct token **substitute(struct token **list, struct token *body, struct arg *args) 643f08c3bdfSopenharmony_ci{ 644f08c3bdfSopenharmony_ci struct position *base_pos = &(*list)->pos; 645f08c3bdfSopenharmony_ci int *count; 646f08c3bdfSopenharmony_ci enum {Normal, Placeholder, Concat} state = Normal; 647f08c3bdfSopenharmony_ci 648f08c3bdfSopenharmony_ci for (; !eof_token(body); body = body->next) { 649f08c3bdfSopenharmony_ci struct token *added, *arg; 650f08c3bdfSopenharmony_ci struct token **tail; 651f08c3bdfSopenharmony_ci struct token *t; 652f08c3bdfSopenharmony_ci 653f08c3bdfSopenharmony_ci switch (token_type(body)) { 654f08c3bdfSopenharmony_ci case TOKEN_GNU_KLUDGE: 655f08c3bdfSopenharmony_ci /* 656f08c3bdfSopenharmony_ci * GNU kludge: if we had <comma>##<vararg>, behaviour 657f08c3bdfSopenharmony_ci * depends on whether we had enough arguments to have 658f08c3bdfSopenharmony_ci * a vararg. If we did, ## is just ignored. Otherwise 659f08c3bdfSopenharmony_ci * both , and ## are ignored. Worse, there can be 660f08c3bdfSopenharmony_ci * an arbitrary number of ##<arg> in between; if all of 661f08c3bdfSopenharmony_ci * those are empty, we act as if they hadn't been there, 662f08c3bdfSopenharmony_ci * otherwise we act as if the kludge didn't exist. 663f08c3bdfSopenharmony_ci */ 664f08c3bdfSopenharmony_ci t = body; 665f08c3bdfSopenharmony_ci if (handle_kludge(&body, args)) { 666f08c3bdfSopenharmony_ci if (state == Concat) 667f08c3bdfSopenharmony_ci state = Normal; 668f08c3bdfSopenharmony_ci else 669f08c3bdfSopenharmony_ci state = Placeholder; 670f08c3bdfSopenharmony_ci continue; 671f08c3bdfSopenharmony_ci } 672f08c3bdfSopenharmony_ci added = dup_token(t, base_pos); 673f08c3bdfSopenharmony_ci token_type(added) = TOKEN_SPECIAL; 674f08c3bdfSopenharmony_ci tail = &added->next; 675f08c3bdfSopenharmony_ci break; 676f08c3bdfSopenharmony_ci 677f08c3bdfSopenharmony_ci case TOKEN_STR_ARGUMENT: 678f08c3bdfSopenharmony_ci arg = args[body->argnum].str; 679f08c3bdfSopenharmony_ci count = &args[body->argnum].n_str; 680f08c3bdfSopenharmony_ci goto copy_arg; 681f08c3bdfSopenharmony_ci 682f08c3bdfSopenharmony_ci case TOKEN_QUOTED_ARGUMENT: 683f08c3bdfSopenharmony_ci arg = args[body->argnum].arg; 684f08c3bdfSopenharmony_ci count = &args[body->argnum].n_quoted; 685f08c3bdfSopenharmony_ci if (!arg || eof_token(arg)) { 686f08c3bdfSopenharmony_ci if (state == Concat) 687f08c3bdfSopenharmony_ci state = Normal; 688f08c3bdfSopenharmony_ci else 689f08c3bdfSopenharmony_ci state = Placeholder; 690f08c3bdfSopenharmony_ci continue; 691f08c3bdfSopenharmony_ci } 692f08c3bdfSopenharmony_ci goto copy_arg; 693f08c3bdfSopenharmony_ci 694f08c3bdfSopenharmony_ci case TOKEN_MACRO_ARGUMENT: 695f08c3bdfSopenharmony_ci arg = args[body->argnum].expanded; 696f08c3bdfSopenharmony_ci count = &args[body->argnum].n_normal; 697f08c3bdfSopenharmony_ci if (eof_token(arg)) { 698f08c3bdfSopenharmony_ci state = Normal; 699f08c3bdfSopenharmony_ci continue; 700f08c3bdfSopenharmony_ci } 701f08c3bdfSopenharmony_ci copy_arg: 702f08c3bdfSopenharmony_ci tail = copy(&added, arg, count); 703f08c3bdfSopenharmony_ci added->pos.newline = body->pos.newline; 704f08c3bdfSopenharmony_ci added->pos.whitespace = body->pos.whitespace; 705f08c3bdfSopenharmony_ci break; 706f08c3bdfSopenharmony_ci 707f08c3bdfSopenharmony_ci case TOKEN_CONCAT: 708f08c3bdfSopenharmony_ci if (state == Placeholder) 709f08c3bdfSopenharmony_ci state = Normal; 710f08c3bdfSopenharmony_ci else 711f08c3bdfSopenharmony_ci state = Concat; 712f08c3bdfSopenharmony_ci continue; 713f08c3bdfSopenharmony_ci 714f08c3bdfSopenharmony_ci case TOKEN_IDENT: 715f08c3bdfSopenharmony_ci added = dup_token(body, base_pos); 716f08c3bdfSopenharmony_ci if (added->ident->tainted) 717f08c3bdfSopenharmony_ci added->pos.noexpand = 1; 718f08c3bdfSopenharmony_ci tail = &added->next; 719f08c3bdfSopenharmony_ci break; 720f08c3bdfSopenharmony_ci 721f08c3bdfSopenharmony_ci default: 722f08c3bdfSopenharmony_ci added = dup_token(body, base_pos); 723f08c3bdfSopenharmony_ci tail = &added->next; 724f08c3bdfSopenharmony_ci break; 725f08c3bdfSopenharmony_ci } 726f08c3bdfSopenharmony_ci 727f08c3bdfSopenharmony_ci /* 728f08c3bdfSopenharmony_ci * if we got to doing real concatenation, we already have 729f08c3bdfSopenharmony_ci * added something into the list, so containing_token() is OK. 730f08c3bdfSopenharmony_ci */ 731f08c3bdfSopenharmony_ci if (state == Concat && merge(containing_token(list), added)) { 732f08c3bdfSopenharmony_ci *list = added->next; 733f08c3bdfSopenharmony_ci if (tail != &added->next) 734f08c3bdfSopenharmony_ci list = tail; 735f08c3bdfSopenharmony_ci } else { 736f08c3bdfSopenharmony_ci *list = added; 737f08c3bdfSopenharmony_ci list = tail; 738f08c3bdfSopenharmony_ci } 739f08c3bdfSopenharmony_ci state = Normal; 740f08c3bdfSopenharmony_ci } 741f08c3bdfSopenharmony_ci *list = &eof_token_entry; 742f08c3bdfSopenharmony_ci return list; 743f08c3bdfSopenharmony_ci} 744f08c3bdfSopenharmony_ci 745f08c3bdfSopenharmony_cistatic int expand(struct token **list, struct symbol *sym) 746f08c3bdfSopenharmony_ci{ 747f08c3bdfSopenharmony_ci struct token *last; 748f08c3bdfSopenharmony_ci struct token *token = *list; 749f08c3bdfSopenharmony_ci struct ident *expanding = token->ident; 750f08c3bdfSopenharmony_ci struct token **tail; 751f08c3bdfSopenharmony_ci struct token *expansion = sym->expansion; 752f08c3bdfSopenharmony_ci int nargs = sym->arglist ? sym->arglist->count.normal : 0; 753f08c3bdfSopenharmony_ci struct arg args[nargs]; 754f08c3bdfSopenharmony_ci 755f08c3bdfSopenharmony_ci if (expanding->tainted) { 756f08c3bdfSopenharmony_ci token->pos.noexpand = 1; 757f08c3bdfSopenharmony_ci return 1; 758f08c3bdfSopenharmony_ci } 759f08c3bdfSopenharmony_ci 760f08c3bdfSopenharmony_ci if (sym->arglist) { 761f08c3bdfSopenharmony_ci if (!match_op(scan_next(&token->next), '(')) 762f08c3bdfSopenharmony_ci return 1; 763f08c3bdfSopenharmony_ci if (!collect_arguments(token->next, sym->arglist, args, token)) 764f08c3bdfSopenharmony_ci return 1; 765f08c3bdfSopenharmony_ci expand_arguments(nargs, args); 766f08c3bdfSopenharmony_ci } 767f08c3bdfSopenharmony_ci 768f08c3bdfSopenharmony_ci if (sym->expand) 769f08c3bdfSopenharmony_ci return sym->expand(token, args) ? 0 : 1; 770f08c3bdfSopenharmony_ci 771f08c3bdfSopenharmony_ci expanding->tainted = 1; 772f08c3bdfSopenharmony_ci 773f08c3bdfSopenharmony_ci last = token->next; 774f08c3bdfSopenharmony_ci tail = substitute(list, expansion, args); 775f08c3bdfSopenharmony_ci /* 776f08c3bdfSopenharmony_ci * Note that it won't be eof - at least TOKEN_UNTAINT will be there. 777f08c3bdfSopenharmony_ci * We still can lose the newline flag if the sucker expands to nothing, 778f08c3bdfSopenharmony_ci * but the price of dealing with that is probably too high (we'd need 779f08c3bdfSopenharmony_ci * to collect the flags during scan_next()) 780f08c3bdfSopenharmony_ci */ 781f08c3bdfSopenharmony_ci (*list)->pos.newline = token->pos.newline; 782f08c3bdfSopenharmony_ci (*list)->pos.whitespace = token->pos.whitespace; 783f08c3bdfSopenharmony_ci *tail = last; 784f08c3bdfSopenharmony_ci 785f08c3bdfSopenharmony_ci return 0; 786f08c3bdfSopenharmony_ci} 787f08c3bdfSopenharmony_ci 788f08c3bdfSopenharmony_cistatic const char *token_name_sequence(struct token *token, int endop, struct token *start) 789f08c3bdfSopenharmony_ci{ 790f08c3bdfSopenharmony_ci static char buffer[256]; 791f08c3bdfSopenharmony_ci char *ptr = buffer; 792f08c3bdfSopenharmony_ci 793f08c3bdfSopenharmony_ci while (!eof_token(token) && !match_op(token, endop)) { 794f08c3bdfSopenharmony_ci int len; 795f08c3bdfSopenharmony_ci const char *val = token->string->data; 796f08c3bdfSopenharmony_ci if (token_type(token) != TOKEN_STRING) 797f08c3bdfSopenharmony_ci val = show_token(token); 798f08c3bdfSopenharmony_ci len = strlen(val); 799f08c3bdfSopenharmony_ci memcpy(ptr, val, len); 800f08c3bdfSopenharmony_ci ptr += len; 801f08c3bdfSopenharmony_ci token = token->next; 802f08c3bdfSopenharmony_ci } 803f08c3bdfSopenharmony_ci *ptr = 0; 804f08c3bdfSopenharmony_ci if (endop && !match_op(token, endop)) 805f08c3bdfSopenharmony_ci sparse_error(start->pos, "expected '>' at end of filename"); 806f08c3bdfSopenharmony_ci return buffer; 807f08c3bdfSopenharmony_ci} 808f08c3bdfSopenharmony_ci 809f08c3bdfSopenharmony_cistatic int already_tokenized(const char *path) 810f08c3bdfSopenharmony_ci{ 811f08c3bdfSopenharmony_ci int stream, next; 812f08c3bdfSopenharmony_ci 813f08c3bdfSopenharmony_ci for (stream = *hash_stream(path); stream >= 0 ; stream = next) { 814f08c3bdfSopenharmony_ci struct stream *s = input_streams + stream; 815f08c3bdfSopenharmony_ci 816f08c3bdfSopenharmony_ci next = s->next_stream; 817f08c3bdfSopenharmony_ci if (s->once) { 818f08c3bdfSopenharmony_ci if (strcmp(path, s->name)) 819f08c3bdfSopenharmony_ci continue; 820f08c3bdfSopenharmony_ci return 1; 821f08c3bdfSopenharmony_ci } 822f08c3bdfSopenharmony_ci if (s->constant != CONSTANT_FILE_YES) 823f08c3bdfSopenharmony_ci continue; 824f08c3bdfSopenharmony_ci if (strcmp(path, s->name)) 825f08c3bdfSopenharmony_ci continue; 826f08c3bdfSopenharmony_ci if (s->protect && !lookup_macro(s->protect)) 827f08c3bdfSopenharmony_ci continue; 828f08c3bdfSopenharmony_ci return 1; 829f08c3bdfSopenharmony_ci } 830f08c3bdfSopenharmony_ci return 0; 831f08c3bdfSopenharmony_ci} 832f08c3bdfSopenharmony_ci 833f08c3bdfSopenharmony_ci/* Handle include of header files. 834f08c3bdfSopenharmony_ci * The relevant options are made compatible with gcc. The only options that 835f08c3bdfSopenharmony_ci * are not supported is -withprefix and friends. 836f08c3bdfSopenharmony_ci * 837f08c3bdfSopenharmony_ci * Three set of include paths are known: 838f08c3bdfSopenharmony_ci * quote_includepath: Path to search when using #include "file.h" 839f08c3bdfSopenharmony_ci * angle_includepath: Paths to search when using #include <file.h> 840f08c3bdfSopenharmony_ci * isys_includepath: Paths specified with -isystem, come before the 841f08c3bdfSopenharmony_ci * built-in system include paths. Gcc would suppress 842f08c3bdfSopenharmony_ci * warnings from system headers. Here we separate 843f08c3bdfSopenharmony_ci * them from the angle_ ones to keep search ordering. 844f08c3bdfSopenharmony_ci * 845f08c3bdfSopenharmony_ci * sys_includepath: Built-in include paths. 846f08c3bdfSopenharmony_ci * dirafter_includepath Paths added with -dirafter. 847f08c3bdfSopenharmony_ci * 848f08c3bdfSopenharmony_ci * The above is implemented as one array with pointers 849f08c3bdfSopenharmony_ci * +--------------+ 850f08c3bdfSopenharmony_ci * quote_includepath ---> | | 851f08c3bdfSopenharmony_ci * +--------------+ 852f08c3bdfSopenharmony_ci * | | 853f08c3bdfSopenharmony_ci * +--------------+ 854f08c3bdfSopenharmony_ci * angle_includepath ---> | | 855f08c3bdfSopenharmony_ci * +--------------+ 856f08c3bdfSopenharmony_ci * isys_includepath ---> | | 857f08c3bdfSopenharmony_ci * +--------------+ 858f08c3bdfSopenharmony_ci * sys_includepath ---> | | 859f08c3bdfSopenharmony_ci * +--------------+ 860f08c3bdfSopenharmony_ci * dirafter_includepath -> | | 861f08c3bdfSopenharmony_ci * +--------------+ 862f08c3bdfSopenharmony_ci * 863f08c3bdfSopenharmony_ci * -I dir insert dir just before isys_includepath and move the rest 864f08c3bdfSopenharmony_ci * -I- makes all dirs specified with -I before to quote dirs only and 865f08c3bdfSopenharmony_ci * angle_includepath is set equal to isys_includepath. 866f08c3bdfSopenharmony_ci * -nostdinc removes all sys dirs by storing NULL in entry pointed 867f08c3bdfSopenharmony_ci * to by * sys_includepath. Note that this will reset all dirs built-in 868f08c3bdfSopenharmony_ci * and added before -nostdinc by -isystem and -idirafter. 869f08c3bdfSopenharmony_ci * -isystem dir adds dir where isys_includepath points adding this dir as 870f08c3bdfSopenharmony_ci * first systemdir 871f08c3bdfSopenharmony_ci * -idirafter dir adds dir to the end of the list 872f08c3bdfSopenharmony_ci */ 873f08c3bdfSopenharmony_ci 874f08c3bdfSopenharmony_cistatic void set_stream_include_path(struct stream *stream) 875f08c3bdfSopenharmony_ci{ 876f08c3bdfSopenharmony_ci const char *path = stream->path; 877f08c3bdfSopenharmony_ci if (!path) { 878f08c3bdfSopenharmony_ci const char *p = strrchr(stream->name, '/'); 879f08c3bdfSopenharmony_ci path = ""; 880f08c3bdfSopenharmony_ci if (p) { 881f08c3bdfSopenharmony_ci int len = p - stream->name + 1; 882f08c3bdfSopenharmony_ci char *m = malloc(len+1); 883f08c3bdfSopenharmony_ci /* This includes the final "/" */ 884f08c3bdfSopenharmony_ci memcpy(m, stream->name, len); 885f08c3bdfSopenharmony_ci m[len] = 0; 886f08c3bdfSopenharmony_ci path = m; 887f08c3bdfSopenharmony_ci /* normalize this path */ 888f08c3bdfSopenharmony_ci while (path[0] == '.' && path[1] == '/') { 889f08c3bdfSopenharmony_ci path += 2; 890f08c3bdfSopenharmony_ci while (path[0] == '/') 891f08c3bdfSopenharmony_ci path++; 892f08c3bdfSopenharmony_ci } 893f08c3bdfSopenharmony_ci } 894f08c3bdfSopenharmony_ci stream->path = path; 895f08c3bdfSopenharmony_ci } 896f08c3bdfSopenharmony_ci includepath[0] = path; 897f08c3bdfSopenharmony_ci} 898f08c3bdfSopenharmony_ci 899f08c3bdfSopenharmony_cistatic int try_include(struct position pos, const char *path, const char *filename, int flen, struct token **where, const char **next_path) 900f08c3bdfSopenharmony_ci{ 901f08c3bdfSopenharmony_ci int fd; 902f08c3bdfSopenharmony_ci int plen = strlen(path); 903f08c3bdfSopenharmony_ci static char fullname[PATH_MAX]; 904f08c3bdfSopenharmony_ci 905f08c3bdfSopenharmony_ci memcpy(fullname, path, plen); 906f08c3bdfSopenharmony_ci if (plen && path[plen-1] != '/') { 907f08c3bdfSopenharmony_ci fullname[plen] = '/'; 908f08c3bdfSopenharmony_ci plen++; 909f08c3bdfSopenharmony_ci } 910f08c3bdfSopenharmony_ci memcpy(fullname+plen, filename, flen); 911f08c3bdfSopenharmony_ci if (already_tokenized(fullname)) 912f08c3bdfSopenharmony_ci return 1; 913f08c3bdfSopenharmony_ci fd = open(fullname, O_RDONLY); 914f08c3bdfSopenharmony_ci if (fd >= 0) { 915f08c3bdfSopenharmony_ci char *streamname = xmemdup(fullname, plen + flen); 916f08c3bdfSopenharmony_ci *where = tokenize(&pos, streamname, fd, *where, next_path); 917f08c3bdfSopenharmony_ci close(fd); 918f08c3bdfSopenharmony_ci return 1; 919f08c3bdfSopenharmony_ci } 920f08c3bdfSopenharmony_ci return 0; 921f08c3bdfSopenharmony_ci} 922f08c3bdfSopenharmony_ci 923f08c3bdfSopenharmony_cistatic int do_include_path(const char **pptr, struct token **list, struct token *token, const char *filename, int flen) 924f08c3bdfSopenharmony_ci{ 925f08c3bdfSopenharmony_ci const char *path; 926f08c3bdfSopenharmony_ci 927f08c3bdfSopenharmony_ci while ((path = *pptr++) != NULL) { 928f08c3bdfSopenharmony_ci if (!try_include(token->pos, path, filename, flen, list, pptr)) 929f08c3bdfSopenharmony_ci continue; 930f08c3bdfSopenharmony_ci return 1; 931f08c3bdfSopenharmony_ci } 932f08c3bdfSopenharmony_ci return 0; 933f08c3bdfSopenharmony_ci} 934f08c3bdfSopenharmony_ci 935f08c3bdfSopenharmony_cistatic int free_preprocessor_line(struct token *token) 936f08c3bdfSopenharmony_ci{ 937f08c3bdfSopenharmony_ci while (token_type(token) != TOKEN_EOF) { 938f08c3bdfSopenharmony_ci struct token *free = token; 939f08c3bdfSopenharmony_ci token = token->next; 940f08c3bdfSopenharmony_ci __free_token(free); 941f08c3bdfSopenharmony_ci }; 942f08c3bdfSopenharmony_ci return 1; 943f08c3bdfSopenharmony_ci} 944f08c3bdfSopenharmony_ci 945f08c3bdfSopenharmony_cistatic int handle_include_path(struct stream *stream, struct token **list, struct token *token, int how) 946f08c3bdfSopenharmony_ci{ 947f08c3bdfSopenharmony_ci const char *filename; 948f08c3bdfSopenharmony_ci struct token *next; 949f08c3bdfSopenharmony_ci const char **path; 950f08c3bdfSopenharmony_ci int expect; 951f08c3bdfSopenharmony_ci int flen; 952f08c3bdfSopenharmony_ci 953f08c3bdfSopenharmony_ci next = token->next; 954f08c3bdfSopenharmony_ci expect = '>'; 955f08c3bdfSopenharmony_ci if (!match_op(next, '<')) { 956f08c3bdfSopenharmony_ci expand_list(&token->next); 957f08c3bdfSopenharmony_ci expect = 0; 958f08c3bdfSopenharmony_ci next = token; 959f08c3bdfSopenharmony_ci if (match_op(token->next, '<')) { 960f08c3bdfSopenharmony_ci next = token->next; 961f08c3bdfSopenharmony_ci expect = '>'; 962f08c3bdfSopenharmony_ci } 963f08c3bdfSopenharmony_ci } 964f08c3bdfSopenharmony_ci 965f08c3bdfSopenharmony_ci token = next->next; 966f08c3bdfSopenharmony_ci filename = token_name_sequence(token, expect, token); 967f08c3bdfSopenharmony_ci flen = strlen(filename) + 1; 968f08c3bdfSopenharmony_ci 969f08c3bdfSopenharmony_ci /* Absolute path? */ 970f08c3bdfSopenharmony_ci if (filename[0] == '/') { 971f08c3bdfSopenharmony_ci if (try_include(token->pos, "", filename, flen, list, includepath)) 972f08c3bdfSopenharmony_ci return 0; 973f08c3bdfSopenharmony_ci goto out; 974f08c3bdfSopenharmony_ci } 975f08c3bdfSopenharmony_ci 976f08c3bdfSopenharmony_ci switch (how) { 977f08c3bdfSopenharmony_ci case 1: 978f08c3bdfSopenharmony_ci path = stream->next_path; 979f08c3bdfSopenharmony_ci break; 980f08c3bdfSopenharmony_ci case 2: 981f08c3bdfSopenharmony_ci includepath[0] = ""; 982f08c3bdfSopenharmony_ci path = includepath; 983f08c3bdfSopenharmony_ci break; 984f08c3bdfSopenharmony_ci default: 985f08c3bdfSopenharmony_ci /* Dir of input file is first dir to search for quoted includes */ 986f08c3bdfSopenharmony_ci set_stream_include_path(stream); 987f08c3bdfSopenharmony_ci path = expect ? angle_includepath : quote_includepath; 988f08c3bdfSopenharmony_ci break; 989f08c3bdfSopenharmony_ci } 990f08c3bdfSopenharmony_ci /* Check the standard include paths.. */ 991f08c3bdfSopenharmony_ci if (do_include_path(path, list, token, filename, flen)) 992f08c3bdfSopenharmony_ci return 0; 993f08c3bdfSopenharmony_ciout: 994f08c3bdfSopenharmony_ci error_die(token->pos, "unable to open '%s'", filename); 995f08c3bdfSopenharmony_ci} 996f08c3bdfSopenharmony_ci 997f08c3bdfSopenharmony_cistatic int handle_include(struct stream *stream, struct token **list, struct token *token) 998f08c3bdfSopenharmony_ci{ 999f08c3bdfSopenharmony_ci return handle_include_path(stream, list, token, 0); 1000f08c3bdfSopenharmony_ci} 1001f08c3bdfSopenharmony_ci 1002f08c3bdfSopenharmony_cistatic int handle_include_next(struct stream *stream, struct token **list, struct token *token) 1003f08c3bdfSopenharmony_ci{ 1004f08c3bdfSopenharmony_ci return handle_include_path(stream, list, token, 1); 1005f08c3bdfSopenharmony_ci} 1006f08c3bdfSopenharmony_ci 1007f08c3bdfSopenharmony_cistatic int handle_argv_include(struct stream *stream, struct token **list, struct token *token) 1008f08c3bdfSopenharmony_ci{ 1009f08c3bdfSopenharmony_ci return handle_include_path(stream, list, token, 2); 1010f08c3bdfSopenharmony_ci} 1011f08c3bdfSopenharmony_ci 1012f08c3bdfSopenharmony_cistatic int token_different(struct token *t1, struct token *t2) 1013f08c3bdfSopenharmony_ci{ 1014f08c3bdfSopenharmony_ci int different; 1015f08c3bdfSopenharmony_ci 1016f08c3bdfSopenharmony_ci if (token_type(t1) != token_type(t2)) 1017f08c3bdfSopenharmony_ci return 1; 1018f08c3bdfSopenharmony_ci 1019f08c3bdfSopenharmony_ci switch (token_type(t1)) { 1020f08c3bdfSopenharmony_ci case TOKEN_IDENT: 1021f08c3bdfSopenharmony_ci different = t1->ident != t2->ident; 1022f08c3bdfSopenharmony_ci break; 1023f08c3bdfSopenharmony_ci case TOKEN_ARG_COUNT: 1024f08c3bdfSopenharmony_ci case TOKEN_UNTAINT: 1025f08c3bdfSopenharmony_ci case TOKEN_CONCAT: 1026f08c3bdfSopenharmony_ci case TOKEN_GNU_KLUDGE: 1027f08c3bdfSopenharmony_ci different = 0; 1028f08c3bdfSopenharmony_ci break; 1029f08c3bdfSopenharmony_ci case TOKEN_NUMBER: 1030f08c3bdfSopenharmony_ci different = strcmp(t1->number, t2->number); 1031f08c3bdfSopenharmony_ci break; 1032f08c3bdfSopenharmony_ci case TOKEN_SPECIAL: 1033f08c3bdfSopenharmony_ci different = t1->special != t2->special; 1034f08c3bdfSopenharmony_ci break; 1035f08c3bdfSopenharmony_ci case TOKEN_MACRO_ARGUMENT: 1036f08c3bdfSopenharmony_ci case TOKEN_QUOTED_ARGUMENT: 1037f08c3bdfSopenharmony_ci case TOKEN_STR_ARGUMENT: 1038f08c3bdfSopenharmony_ci different = t1->argnum != t2->argnum; 1039f08c3bdfSopenharmony_ci break; 1040f08c3bdfSopenharmony_ci case TOKEN_CHAR_EMBEDDED_0 ... TOKEN_CHAR_EMBEDDED_3: 1041f08c3bdfSopenharmony_ci case TOKEN_WIDE_CHAR_EMBEDDED_0 ... TOKEN_WIDE_CHAR_EMBEDDED_3: 1042f08c3bdfSopenharmony_ci different = memcmp(t1->embedded, t2->embedded, 4); 1043f08c3bdfSopenharmony_ci break; 1044f08c3bdfSopenharmony_ci case TOKEN_CHAR: 1045f08c3bdfSopenharmony_ci case TOKEN_WIDE_CHAR: 1046f08c3bdfSopenharmony_ci case TOKEN_STRING: 1047f08c3bdfSopenharmony_ci case TOKEN_WIDE_STRING: { 1048f08c3bdfSopenharmony_ci struct string *s1, *s2; 1049f08c3bdfSopenharmony_ci 1050f08c3bdfSopenharmony_ci s1 = t1->string; 1051f08c3bdfSopenharmony_ci s2 = t2->string; 1052f08c3bdfSopenharmony_ci different = 1; 1053f08c3bdfSopenharmony_ci if (s1->length != s2->length) 1054f08c3bdfSopenharmony_ci break; 1055f08c3bdfSopenharmony_ci different = memcmp(s1->data, s2->data, s1->length); 1056f08c3bdfSopenharmony_ci break; 1057f08c3bdfSopenharmony_ci } 1058f08c3bdfSopenharmony_ci default: 1059f08c3bdfSopenharmony_ci different = 1; 1060f08c3bdfSopenharmony_ci break; 1061f08c3bdfSopenharmony_ci } 1062f08c3bdfSopenharmony_ci return different; 1063f08c3bdfSopenharmony_ci} 1064f08c3bdfSopenharmony_ci 1065f08c3bdfSopenharmony_cistatic int token_list_different(struct token *list1, struct token *list2) 1066f08c3bdfSopenharmony_ci{ 1067f08c3bdfSopenharmony_ci for (;;) { 1068f08c3bdfSopenharmony_ci if (list1 == list2) 1069f08c3bdfSopenharmony_ci return 0; 1070f08c3bdfSopenharmony_ci if (!list1 || !list2) 1071f08c3bdfSopenharmony_ci return 1; 1072f08c3bdfSopenharmony_ci if (token_different(list1, list2)) 1073f08c3bdfSopenharmony_ci return 1; 1074f08c3bdfSopenharmony_ci list1 = list1->next; 1075f08c3bdfSopenharmony_ci list2 = list2->next; 1076f08c3bdfSopenharmony_ci } 1077f08c3bdfSopenharmony_ci} 1078f08c3bdfSopenharmony_ci 1079f08c3bdfSopenharmony_cistatic inline void set_arg_count(struct token *token) 1080f08c3bdfSopenharmony_ci{ 1081f08c3bdfSopenharmony_ci token_type(token) = TOKEN_ARG_COUNT; 1082f08c3bdfSopenharmony_ci token->count.normal = token->count.quoted = 1083f08c3bdfSopenharmony_ci token->count.str = token->count.vararg = 0; 1084f08c3bdfSopenharmony_ci} 1085f08c3bdfSopenharmony_ci 1086f08c3bdfSopenharmony_cistatic struct token *parse_arguments(struct token *list) 1087f08c3bdfSopenharmony_ci{ 1088f08c3bdfSopenharmony_ci struct token *arg = list->next, *next = list; 1089f08c3bdfSopenharmony_ci struct argcount *count = &list->count; 1090f08c3bdfSopenharmony_ci 1091f08c3bdfSopenharmony_ci set_arg_count(list); 1092f08c3bdfSopenharmony_ci 1093f08c3bdfSopenharmony_ci if (match_op(arg, ')')) { 1094f08c3bdfSopenharmony_ci next = arg->next; 1095f08c3bdfSopenharmony_ci list->next = &eof_token_entry; 1096f08c3bdfSopenharmony_ci return next; 1097f08c3bdfSopenharmony_ci } 1098f08c3bdfSopenharmony_ci 1099f08c3bdfSopenharmony_ci while (token_type(arg) == TOKEN_IDENT) { 1100f08c3bdfSopenharmony_ci if (arg->ident == &__VA_ARGS___ident) 1101f08c3bdfSopenharmony_ci goto Eva_args; 1102f08c3bdfSopenharmony_ci if (!++count->normal) 1103f08c3bdfSopenharmony_ci goto Eargs; 1104f08c3bdfSopenharmony_ci next = arg->next; 1105f08c3bdfSopenharmony_ci 1106f08c3bdfSopenharmony_ci if (match_op(next, ',')) { 1107f08c3bdfSopenharmony_ci set_arg_count(next); 1108f08c3bdfSopenharmony_ci arg = next->next; 1109f08c3bdfSopenharmony_ci continue; 1110f08c3bdfSopenharmony_ci } 1111f08c3bdfSopenharmony_ci 1112f08c3bdfSopenharmony_ci if (match_op(next, ')')) { 1113f08c3bdfSopenharmony_ci set_arg_count(next); 1114f08c3bdfSopenharmony_ci next = next->next; 1115f08c3bdfSopenharmony_ci arg->next->next = &eof_token_entry; 1116f08c3bdfSopenharmony_ci return next; 1117f08c3bdfSopenharmony_ci } 1118f08c3bdfSopenharmony_ci 1119f08c3bdfSopenharmony_ci /* normal cases are finished here */ 1120f08c3bdfSopenharmony_ci 1121f08c3bdfSopenharmony_ci if (match_op(next, SPECIAL_ELLIPSIS)) { 1122f08c3bdfSopenharmony_ci if (match_op(next->next, ')')) { 1123f08c3bdfSopenharmony_ci set_arg_count(next); 1124f08c3bdfSopenharmony_ci next->count.vararg = 1; 1125f08c3bdfSopenharmony_ci next = next->next; 1126f08c3bdfSopenharmony_ci arg->next->next = &eof_token_entry; 1127f08c3bdfSopenharmony_ci return next->next; 1128f08c3bdfSopenharmony_ci } 1129f08c3bdfSopenharmony_ci 1130f08c3bdfSopenharmony_ci arg = next; 1131f08c3bdfSopenharmony_ci goto Enotclosed; 1132f08c3bdfSopenharmony_ci } 1133f08c3bdfSopenharmony_ci 1134f08c3bdfSopenharmony_ci if (eof_token(next)) { 1135f08c3bdfSopenharmony_ci goto Enotclosed; 1136f08c3bdfSopenharmony_ci } else { 1137f08c3bdfSopenharmony_ci arg = next; 1138f08c3bdfSopenharmony_ci goto Ebadstuff; 1139f08c3bdfSopenharmony_ci } 1140f08c3bdfSopenharmony_ci } 1141f08c3bdfSopenharmony_ci 1142f08c3bdfSopenharmony_ci if (match_op(arg, SPECIAL_ELLIPSIS)) { 1143f08c3bdfSopenharmony_ci next = arg->next; 1144f08c3bdfSopenharmony_ci token_type(arg) = TOKEN_IDENT; 1145f08c3bdfSopenharmony_ci arg->ident = &__VA_ARGS___ident; 1146f08c3bdfSopenharmony_ci if (!match_op(next, ')')) 1147f08c3bdfSopenharmony_ci goto Enotclosed; 1148f08c3bdfSopenharmony_ci if (!++count->normal) 1149f08c3bdfSopenharmony_ci goto Eargs; 1150f08c3bdfSopenharmony_ci set_arg_count(next); 1151f08c3bdfSopenharmony_ci next->count.vararg = 1; 1152f08c3bdfSopenharmony_ci next = next->next; 1153f08c3bdfSopenharmony_ci arg->next->next = &eof_token_entry; 1154f08c3bdfSopenharmony_ci return next; 1155f08c3bdfSopenharmony_ci } 1156f08c3bdfSopenharmony_ci 1157f08c3bdfSopenharmony_ci if (eof_token(arg)) { 1158f08c3bdfSopenharmony_ci arg = next; 1159f08c3bdfSopenharmony_ci goto Enotclosed; 1160f08c3bdfSopenharmony_ci } 1161f08c3bdfSopenharmony_ci if (match_op(arg, ',')) 1162f08c3bdfSopenharmony_ci goto Emissing; 1163f08c3bdfSopenharmony_ci else 1164f08c3bdfSopenharmony_ci goto Ebadstuff; 1165f08c3bdfSopenharmony_ci 1166f08c3bdfSopenharmony_ci 1167f08c3bdfSopenharmony_ciEmissing: 1168f08c3bdfSopenharmony_ci sparse_error(arg->pos, "parameter name missing"); 1169f08c3bdfSopenharmony_ci return NULL; 1170f08c3bdfSopenharmony_ciEbadstuff: 1171f08c3bdfSopenharmony_ci sparse_error(arg->pos, "\"%s\" may not appear in macro parameter list", 1172f08c3bdfSopenharmony_ci show_token(arg)); 1173f08c3bdfSopenharmony_ci return NULL; 1174f08c3bdfSopenharmony_ciEnotclosed: 1175f08c3bdfSopenharmony_ci sparse_error(arg->pos, "missing ')' in macro parameter list"); 1176f08c3bdfSopenharmony_ci return NULL; 1177f08c3bdfSopenharmony_ciEva_args: 1178f08c3bdfSopenharmony_ci sparse_error(arg->pos, "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro"); 1179f08c3bdfSopenharmony_ci return NULL; 1180f08c3bdfSopenharmony_ciEargs: 1181f08c3bdfSopenharmony_ci sparse_error(arg->pos, "too many arguments in macro definition"); 1182f08c3bdfSopenharmony_ci return NULL; 1183f08c3bdfSopenharmony_ci} 1184f08c3bdfSopenharmony_ci 1185f08c3bdfSopenharmony_cistatic int try_arg(struct token *token, enum token_type type, struct token *arglist) 1186f08c3bdfSopenharmony_ci{ 1187f08c3bdfSopenharmony_ci struct ident *ident = token->ident; 1188f08c3bdfSopenharmony_ci int nr; 1189f08c3bdfSopenharmony_ci 1190f08c3bdfSopenharmony_ci if (!arglist || token_type(token) != TOKEN_IDENT) 1191f08c3bdfSopenharmony_ci return 0; 1192f08c3bdfSopenharmony_ci 1193f08c3bdfSopenharmony_ci arglist = arglist->next; 1194f08c3bdfSopenharmony_ci 1195f08c3bdfSopenharmony_ci for (nr = 0; !eof_token(arglist); nr++, arglist = arglist->next->next) { 1196f08c3bdfSopenharmony_ci if (arglist->ident == ident) { 1197f08c3bdfSopenharmony_ci struct argcount *count = &arglist->next->count; 1198f08c3bdfSopenharmony_ci int n; 1199f08c3bdfSopenharmony_ci 1200f08c3bdfSopenharmony_ci token->argnum = nr; 1201f08c3bdfSopenharmony_ci token_type(token) = type; 1202f08c3bdfSopenharmony_ci switch (type) { 1203f08c3bdfSopenharmony_ci case TOKEN_MACRO_ARGUMENT: 1204f08c3bdfSopenharmony_ci n = ++count->normal; 1205f08c3bdfSopenharmony_ci break; 1206f08c3bdfSopenharmony_ci case TOKEN_QUOTED_ARGUMENT: 1207f08c3bdfSopenharmony_ci n = ++count->quoted; 1208f08c3bdfSopenharmony_ci break; 1209f08c3bdfSopenharmony_ci default: 1210f08c3bdfSopenharmony_ci n = ++count->str; 1211f08c3bdfSopenharmony_ci } 1212f08c3bdfSopenharmony_ci if (n) 1213f08c3bdfSopenharmony_ci return count->vararg ? 2 : 1; 1214f08c3bdfSopenharmony_ci /* 1215f08c3bdfSopenharmony_ci * XXX - need saner handling of that 1216f08c3bdfSopenharmony_ci * (>= 1024 instances of argument) 1217f08c3bdfSopenharmony_ci */ 1218f08c3bdfSopenharmony_ci token_type(token) = TOKEN_ERROR; 1219f08c3bdfSopenharmony_ci return -1; 1220f08c3bdfSopenharmony_ci } 1221f08c3bdfSopenharmony_ci } 1222f08c3bdfSopenharmony_ci return 0; 1223f08c3bdfSopenharmony_ci} 1224f08c3bdfSopenharmony_ci 1225f08c3bdfSopenharmony_cistatic struct token *handle_hash(struct token **p, struct token *arglist) 1226f08c3bdfSopenharmony_ci{ 1227f08c3bdfSopenharmony_ci struct token *token = *p; 1228f08c3bdfSopenharmony_ci if (arglist) { 1229f08c3bdfSopenharmony_ci struct token *next = token->next; 1230f08c3bdfSopenharmony_ci if (!try_arg(next, TOKEN_STR_ARGUMENT, arglist)) 1231f08c3bdfSopenharmony_ci goto Equote; 1232f08c3bdfSopenharmony_ci next->pos.whitespace = token->pos.whitespace; 1233f08c3bdfSopenharmony_ci __free_token(token); 1234f08c3bdfSopenharmony_ci token = *p = next; 1235f08c3bdfSopenharmony_ci } else { 1236f08c3bdfSopenharmony_ci token->pos.noexpand = 1; 1237f08c3bdfSopenharmony_ci } 1238f08c3bdfSopenharmony_ci return token; 1239f08c3bdfSopenharmony_ci 1240f08c3bdfSopenharmony_ciEquote: 1241f08c3bdfSopenharmony_ci sparse_error(token->pos, "'#' is not followed by a macro parameter"); 1242f08c3bdfSopenharmony_ci return NULL; 1243f08c3bdfSopenharmony_ci} 1244f08c3bdfSopenharmony_ci 1245f08c3bdfSopenharmony_ci/* token->next is ## */ 1246f08c3bdfSopenharmony_cistatic struct token *handle_hashhash(struct token *token, struct token *arglist) 1247f08c3bdfSopenharmony_ci{ 1248f08c3bdfSopenharmony_ci struct token *last = token; 1249f08c3bdfSopenharmony_ci struct token *concat; 1250f08c3bdfSopenharmony_ci int state = match_op(token, ','); 1251f08c3bdfSopenharmony_ci 1252f08c3bdfSopenharmony_ci try_arg(token, TOKEN_QUOTED_ARGUMENT, arglist); 1253f08c3bdfSopenharmony_ci 1254f08c3bdfSopenharmony_ci while (1) { 1255f08c3bdfSopenharmony_ci struct token *t; 1256f08c3bdfSopenharmony_ci int is_arg; 1257f08c3bdfSopenharmony_ci 1258f08c3bdfSopenharmony_ci /* eat duplicate ## */ 1259f08c3bdfSopenharmony_ci concat = token->next; 1260f08c3bdfSopenharmony_ci while (match_op(t = concat->next, SPECIAL_HASHHASH)) { 1261f08c3bdfSopenharmony_ci token->next = t; 1262f08c3bdfSopenharmony_ci __free_token(concat); 1263f08c3bdfSopenharmony_ci concat = t; 1264f08c3bdfSopenharmony_ci } 1265f08c3bdfSopenharmony_ci token_type(concat) = TOKEN_CONCAT; 1266f08c3bdfSopenharmony_ci 1267f08c3bdfSopenharmony_ci if (eof_token(t)) 1268f08c3bdfSopenharmony_ci goto Econcat; 1269f08c3bdfSopenharmony_ci 1270f08c3bdfSopenharmony_ci if (match_op(t, '#')) { 1271f08c3bdfSopenharmony_ci t = handle_hash(&concat->next, arglist); 1272f08c3bdfSopenharmony_ci if (!t) 1273f08c3bdfSopenharmony_ci return NULL; 1274f08c3bdfSopenharmony_ci } 1275f08c3bdfSopenharmony_ci 1276f08c3bdfSopenharmony_ci is_arg = try_arg(t, TOKEN_QUOTED_ARGUMENT, arglist); 1277f08c3bdfSopenharmony_ci 1278f08c3bdfSopenharmony_ci if (state == 1 && is_arg) { 1279f08c3bdfSopenharmony_ci state = is_arg; 1280f08c3bdfSopenharmony_ci } else { 1281f08c3bdfSopenharmony_ci last = t; 1282f08c3bdfSopenharmony_ci state = match_op(t, ','); 1283f08c3bdfSopenharmony_ci } 1284f08c3bdfSopenharmony_ci 1285f08c3bdfSopenharmony_ci token = t; 1286f08c3bdfSopenharmony_ci if (!match_op(token->next, SPECIAL_HASHHASH)) 1287f08c3bdfSopenharmony_ci break; 1288f08c3bdfSopenharmony_ci } 1289f08c3bdfSopenharmony_ci /* handle GNU ,##__VA_ARGS__ kludge, in all its weirdness */ 1290f08c3bdfSopenharmony_ci if (state == 2) 1291f08c3bdfSopenharmony_ci token_type(last) = TOKEN_GNU_KLUDGE; 1292f08c3bdfSopenharmony_ci return token; 1293f08c3bdfSopenharmony_ci 1294f08c3bdfSopenharmony_ciEconcat: 1295f08c3bdfSopenharmony_ci sparse_error(concat->pos, "'##' cannot appear at the ends of macro expansion"); 1296f08c3bdfSopenharmony_ci return NULL; 1297f08c3bdfSopenharmony_ci} 1298f08c3bdfSopenharmony_ci 1299f08c3bdfSopenharmony_cistatic struct token *parse_expansion(struct token *expansion, struct token *arglist, struct ident *name) 1300f08c3bdfSopenharmony_ci{ 1301f08c3bdfSopenharmony_ci struct token *token = expansion; 1302f08c3bdfSopenharmony_ci struct token **p; 1303f08c3bdfSopenharmony_ci 1304f08c3bdfSopenharmony_ci if (match_op(token, SPECIAL_HASHHASH)) 1305f08c3bdfSopenharmony_ci goto Econcat; 1306f08c3bdfSopenharmony_ci 1307f08c3bdfSopenharmony_ci for (p = &expansion; !eof_token(token); p = &token->next, token = *p) { 1308f08c3bdfSopenharmony_ci if (match_op(token, '#')) { 1309f08c3bdfSopenharmony_ci token = handle_hash(p, arglist); 1310f08c3bdfSopenharmony_ci if (!token) 1311f08c3bdfSopenharmony_ci return NULL; 1312f08c3bdfSopenharmony_ci } 1313f08c3bdfSopenharmony_ci if (match_op(token->next, SPECIAL_HASHHASH)) { 1314f08c3bdfSopenharmony_ci token = handle_hashhash(token, arglist); 1315f08c3bdfSopenharmony_ci if (!token) 1316f08c3bdfSopenharmony_ci return NULL; 1317f08c3bdfSopenharmony_ci } else { 1318f08c3bdfSopenharmony_ci try_arg(token, TOKEN_MACRO_ARGUMENT, arglist); 1319f08c3bdfSopenharmony_ci } 1320f08c3bdfSopenharmony_ci switch (token_type(token)) { 1321f08c3bdfSopenharmony_ci case TOKEN_ERROR: 1322f08c3bdfSopenharmony_ci goto Earg; 1323f08c3bdfSopenharmony_ci 1324f08c3bdfSopenharmony_ci case TOKEN_STRING: 1325f08c3bdfSopenharmony_ci case TOKEN_WIDE_STRING: 1326f08c3bdfSopenharmony_ci token->string->immutable = 1; 1327f08c3bdfSopenharmony_ci break; 1328f08c3bdfSopenharmony_ci } 1329f08c3bdfSopenharmony_ci } 1330f08c3bdfSopenharmony_ci token = alloc_token(&expansion->pos); 1331f08c3bdfSopenharmony_ci token_type(token) = TOKEN_UNTAINT; 1332f08c3bdfSopenharmony_ci token->ident = name; 1333f08c3bdfSopenharmony_ci token->next = *p; 1334f08c3bdfSopenharmony_ci *p = token; 1335f08c3bdfSopenharmony_ci return expansion; 1336f08c3bdfSopenharmony_ci 1337f08c3bdfSopenharmony_ciEconcat: 1338f08c3bdfSopenharmony_ci sparse_error(token->pos, "'##' cannot appear at the ends of macro expansion"); 1339f08c3bdfSopenharmony_ci return NULL; 1340f08c3bdfSopenharmony_ciEarg: 1341f08c3bdfSopenharmony_ci sparse_error(token->pos, "too many instances of argument in body"); 1342f08c3bdfSopenharmony_ci return NULL; 1343f08c3bdfSopenharmony_ci} 1344f08c3bdfSopenharmony_ci 1345f08c3bdfSopenharmony_cistatic int do_define(struct position pos, struct token *token, struct ident *name, 1346f08c3bdfSopenharmony_ci struct token *arglist, struct token *expansion, int attr) 1347f08c3bdfSopenharmony_ci{ 1348f08c3bdfSopenharmony_ci struct symbol *sym; 1349f08c3bdfSopenharmony_ci int ret = 1; 1350f08c3bdfSopenharmony_ci 1351f08c3bdfSopenharmony_ci expansion = parse_expansion(expansion, arglist, name); 1352f08c3bdfSopenharmony_ci if (!expansion) 1353f08c3bdfSopenharmony_ci return 1; 1354f08c3bdfSopenharmony_ci 1355f08c3bdfSopenharmony_ci sym = lookup_symbol(name, NS_MACRO | NS_UNDEF); 1356f08c3bdfSopenharmony_ci if (sym) { 1357f08c3bdfSopenharmony_ci int clean; 1358f08c3bdfSopenharmony_ci 1359f08c3bdfSopenharmony_ci if (attr < sym->attr) 1360f08c3bdfSopenharmony_ci goto out; 1361f08c3bdfSopenharmony_ci 1362f08c3bdfSopenharmony_ci clean = (attr == sym->attr && sym->namespace == NS_MACRO); 1363f08c3bdfSopenharmony_ci 1364f08c3bdfSopenharmony_ci if (token_list_different(sym->expansion, expansion) || 1365f08c3bdfSopenharmony_ci token_list_different(sym->arglist, arglist)) { 1366f08c3bdfSopenharmony_ci ret = 0; 1367f08c3bdfSopenharmony_ci if ((clean && attr == SYM_ATTR_NORMAL) 1368f08c3bdfSopenharmony_ci || sym->used_in == file_scope) { 1369f08c3bdfSopenharmony_ci warning(pos, "preprocessor token %.*s redefined", 1370f08c3bdfSopenharmony_ci name->len, name->name); 1371f08c3bdfSopenharmony_ci info(sym->pos, "this was the original definition"); 1372f08c3bdfSopenharmony_ci } 1373f08c3bdfSopenharmony_ci } else if (clean) 1374f08c3bdfSopenharmony_ci goto out; 1375f08c3bdfSopenharmony_ci } 1376f08c3bdfSopenharmony_ci 1377f08c3bdfSopenharmony_ci if (!sym || sym->scope != file_scope) { 1378f08c3bdfSopenharmony_ci sym = alloc_symbol(pos, SYM_NODE); 1379f08c3bdfSopenharmony_ci bind_symbol(sym, name, NS_MACRO); 1380f08c3bdfSopenharmony_ci add_ident(¯os, name); 1381f08c3bdfSopenharmony_ci ret = 0; 1382f08c3bdfSopenharmony_ci } 1383f08c3bdfSopenharmony_ci 1384f08c3bdfSopenharmony_ci if (!ret) { 1385f08c3bdfSopenharmony_ci sym->expansion = expansion; 1386f08c3bdfSopenharmony_ci sym->arglist = arglist; 1387f08c3bdfSopenharmony_ci if (token) /* Free the "define" token, but not the rest of the line */ 1388f08c3bdfSopenharmony_ci __free_token(token); 1389f08c3bdfSopenharmony_ci } 1390f08c3bdfSopenharmony_ci 1391f08c3bdfSopenharmony_ci sym->namespace = NS_MACRO; 1392f08c3bdfSopenharmony_ci sym->used_in = NULL; 1393f08c3bdfSopenharmony_ci sym->attr = attr; 1394f08c3bdfSopenharmony_ciout: 1395f08c3bdfSopenharmony_ci return ret; 1396f08c3bdfSopenharmony_ci} 1397f08c3bdfSopenharmony_ci 1398f08c3bdfSopenharmony_ci/// 1399f08c3bdfSopenharmony_ci// predefine a macro with a printf-formatted value 1400f08c3bdfSopenharmony_ci// @name: the name of the macro 1401f08c3bdfSopenharmony_ci// @weak: 0/1 for a normal or a weak define 1402f08c3bdfSopenharmony_ci// @fmt: the printf format followed by it's arguments. 1403f08c3bdfSopenharmony_ci// 1404f08c3bdfSopenharmony_ci// The type of the value is automatically infered: 1405f08c3bdfSopenharmony_ci// TOKEN_NUMBER if it starts by a digit, TOKEN_IDENT otherwise. 1406f08c3bdfSopenharmony_ci// If @fmt is null or empty, the macro is defined with an empty definition. 1407f08c3bdfSopenharmony_civoid predefine(const char *name, int weak, const char *fmt, ...) 1408f08c3bdfSopenharmony_ci{ 1409f08c3bdfSopenharmony_ci struct ident *ident = built_in_ident(name); 1410f08c3bdfSopenharmony_ci struct token *value = &eof_token_entry; 1411f08c3bdfSopenharmony_ci int attr = weak ? SYM_ATTR_WEAK : SYM_ATTR_NORMAL; 1412f08c3bdfSopenharmony_ci 1413f08c3bdfSopenharmony_ci if (fmt && fmt[0]) { 1414f08c3bdfSopenharmony_ci static char buf[256]; 1415f08c3bdfSopenharmony_ci va_list ap; 1416f08c3bdfSopenharmony_ci 1417f08c3bdfSopenharmony_ci va_start(ap, fmt); 1418f08c3bdfSopenharmony_ci vsnprintf(buf, sizeof(buf), fmt, ap); 1419f08c3bdfSopenharmony_ci va_end(ap); 1420f08c3bdfSopenharmony_ci 1421f08c3bdfSopenharmony_ci value = __alloc_token(0); 1422f08c3bdfSopenharmony_ci if (isdigit((unsigned char)buf[0])) { 1423f08c3bdfSopenharmony_ci token_type(value) = TOKEN_NUMBER; 1424f08c3bdfSopenharmony_ci value->number = xstrdup(buf); 1425f08c3bdfSopenharmony_ci } else { 1426f08c3bdfSopenharmony_ci token_type(value) = TOKEN_IDENT; 1427f08c3bdfSopenharmony_ci value->ident = built_in_ident(buf); 1428f08c3bdfSopenharmony_ci } 1429f08c3bdfSopenharmony_ci value->pos.whitespace = 1; 1430f08c3bdfSopenharmony_ci value->next = &eof_token_entry; 1431f08c3bdfSopenharmony_ci } 1432f08c3bdfSopenharmony_ci 1433f08c3bdfSopenharmony_ci do_define(value->pos, NULL, ident, NULL, value, attr); 1434f08c3bdfSopenharmony_ci} 1435f08c3bdfSopenharmony_ci 1436f08c3bdfSopenharmony_ci/// 1437f08c3bdfSopenharmony_ci// like predefine() but only if one of the non-standard dialect is chosen 1438f08c3bdfSopenharmony_civoid predefine_nostd(const char *name) 1439f08c3bdfSopenharmony_ci{ 1440f08c3bdfSopenharmony_ci if ((standard & STANDARD_GNU) || (standard == STANDARD_NONE)) 1441f08c3bdfSopenharmony_ci predefine(name, 1, "1"); 1442f08c3bdfSopenharmony_ci} 1443f08c3bdfSopenharmony_ci 1444f08c3bdfSopenharmony_cistatic void predefine_fmt(const char *fmt, int weak, va_list ap) 1445f08c3bdfSopenharmony_ci{ 1446f08c3bdfSopenharmony_ci static char buf[256]; 1447f08c3bdfSopenharmony_ci 1448f08c3bdfSopenharmony_ci vsnprintf(buf, sizeof(buf), fmt, ap); 1449f08c3bdfSopenharmony_ci predefine(buf, weak, "1"); 1450f08c3bdfSopenharmony_ci} 1451f08c3bdfSopenharmony_ci 1452f08c3bdfSopenharmony_civoid predefine_strong(const char *fmt, ...) 1453f08c3bdfSopenharmony_ci{ 1454f08c3bdfSopenharmony_ci va_list ap; 1455f08c3bdfSopenharmony_ci 1456f08c3bdfSopenharmony_ci va_start(ap, fmt); 1457f08c3bdfSopenharmony_ci predefine_fmt(fmt, 0, ap); 1458f08c3bdfSopenharmony_ci va_end(ap); 1459f08c3bdfSopenharmony_ci} 1460f08c3bdfSopenharmony_ci 1461f08c3bdfSopenharmony_civoid predefine_weak(const char *fmt, ...) 1462f08c3bdfSopenharmony_ci{ 1463f08c3bdfSopenharmony_ci va_list ap; 1464f08c3bdfSopenharmony_ci 1465f08c3bdfSopenharmony_ci va_start(ap, fmt); 1466f08c3bdfSopenharmony_ci predefine_fmt(fmt, 1, ap); 1467f08c3bdfSopenharmony_ci va_end(ap); 1468f08c3bdfSopenharmony_ci} 1469f08c3bdfSopenharmony_ci 1470f08c3bdfSopenharmony_cistatic int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr) 1471f08c3bdfSopenharmony_ci{ 1472f08c3bdfSopenharmony_ci struct token *arglist, *expansion; 1473f08c3bdfSopenharmony_ci struct token *left = token->next; 1474f08c3bdfSopenharmony_ci struct ident *name; 1475f08c3bdfSopenharmony_ci 1476f08c3bdfSopenharmony_ci if (token_type(left) != TOKEN_IDENT) { 1477f08c3bdfSopenharmony_ci sparse_error(token->pos, "expected identifier to 'define'"); 1478f08c3bdfSopenharmony_ci return 1; 1479f08c3bdfSopenharmony_ci } 1480f08c3bdfSopenharmony_ci 1481f08c3bdfSopenharmony_ci name = left->ident; 1482f08c3bdfSopenharmony_ci 1483f08c3bdfSopenharmony_ci arglist = NULL; 1484f08c3bdfSopenharmony_ci expansion = left->next; 1485f08c3bdfSopenharmony_ci if (!expansion->pos.whitespace) { 1486f08c3bdfSopenharmony_ci if (match_op(expansion, '(')) { 1487f08c3bdfSopenharmony_ci arglist = expansion; 1488f08c3bdfSopenharmony_ci expansion = parse_arguments(expansion); 1489f08c3bdfSopenharmony_ci if (!expansion) 1490f08c3bdfSopenharmony_ci return 1; 1491f08c3bdfSopenharmony_ci } else if (!eof_token(expansion)) { 1492f08c3bdfSopenharmony_ci warning(expansion->pos, 1493f08c3bdfSopenharmony_ci "no whitespace before object-like macro body"); 1494f08c3bdfSopenharmony_ci } 1495f08c3bdfSopenharmony_ci } 1496f08c3bdfSopenharmony_ci 1497f08c3bdfSopenharmony_ci return do_define(left->pos, token, name, arglist, expansion, attr); 1498f08c3bdfSopenharmony_ci} 1499f08c3bdfSopenharmony_ci 1500f08c3bdfSopenharmony_cistatic int handle_define(struct stream *stream, struct token **line, struct token *token) 1501f08c3bdfSopenharmony_ci{ 1502f08c3bdfSopenharmony_ci return do_handle_define(stream, line, token, SYM_ATTR_NORMAL); 1503f08c3bdfSopenharmony_ci} 1504f08c3bdfSopenharmony_ci 1505f08c3bdfSopenharmony_cistatic int handle_weak_define(struct stream *stream, struct token **line, struct token *token) 1506f08c3bdfSopenharmony_ci{ 1507f08c3bdfSopenharmony_ci return do_handle_define(stream, line, token, SYM_ATTR_WEAK); 1508f08c3bdfSopenharmony_ci} 1509f08c3bdfSopenharmony_ci 1510f08c3bdfSopenharmony_cistatic int handle_strong_define(struct stream *stream, struct token **line, struct token *token) 1511f08c3bdfSopenharmony_ci{ 1512f08c3bdfSopenharmony_ci return do_handle_define(stream, line, token, SYM_ATTR_STRONG); 1513f08c3bdfSopenharmony_ci} 1514f08c3bdfSopenharmony_ci 1515f08c3bdfSopenharmony_cistatic int do_handle_undef(struct stream *stream, struct token **line, struct token *token, int attr) 1516f08c3bdfSopenharmony_ci{ 1517f08c3bdfSopenharmony_ci struct token *left = token->next; 1518f08c3bdfSopenharmony_ci struct symbol *sym; 1519f08c3bdfSopenharmony_ci 1520f08c3bdfSopenharmony_ci if (token_type(left) != TOKEN_IDENT) { 1521f08c3bdfSopenharmony_ci sparse_error(token->pos, "expected identifier to 'undef'"); 1522f08c3bdfSopenharmony_ci return 1; 1523f08c3bdfSopenharmony_ci } 1524f08c3bdfSopenharmony_ci 1525f08c3bdfSopenharmony_ci sym = lookup_symbol(left->ident, NS_MACRO | NS_UNDEF); 1526f08c3bdfSopenharmony_ci if (sym) { 1527f08c3bdfSopenharmony_ci if (attr < sym->attr) 1528f08c3bdfSopenharmony_ci return 1; 1529f08c3bdfSopenharmony_ci if (attr == sym->attr && sym->namespace == NS_UNDEF) 1530f08c3bdfSopenharmony_ci return 1; 1531f08c3bdfSopenharmony_ci } else if (attr <= SYM_ATTR_NORMAL) 1532f08c3bdfSopenharmony_ci return 1; 1533f08c3bdfSopenharmony_ci 1534f08c3bdfSopenharmony_ci if (!sym || sym->scope != file_scope) { 1535f08c3bdfSopenharmony_ci sym = alloc_symbol(left->pos, SYM_NODE); 1536f08c3bdfSopenharmony_ci bind_symbol(sym, left->ident, NS_MACRO); 1537f08c3bdfSopenharmony_ci } 1538f08c3bdfSopenharmony_ci 1539f08c3bdfSopenharmony_ci sym->namespace = NS_UNDEF; 1540f08c3bdfSopenharmony_ci sym->used_in = NULL; 1541f08c3bdfSopenharmony_ci sym->attr = attr; 1542f08c3bdfSopenharmony_ci 1543f08c3bdfSopenharmony_ci return 1; 1544f08c3bdfSopenharmony_ci} 1545f08c3bdfSopenharmony_ci 1546f08c3bdfSopenharmony_cistatic int handle_undef(struct stream *stream, struct token **line, struct token *token) 1547f08c3bdfSopenharmony_ci{ 1548f08c3bdfSopenharmony_ci return do_handle_undef(stream, line, token, SYM_ATTR_NORMAL); 1549f08c3bdfSopenharmony_ci} 1550f08c3bdfSopenharmony_ci 1551f08c3bdfSopenharmony_cistatic int handle_strong_undef(struct stream *stream, struct token **line, struct token *token) 1552f08c3bdfSopenharmony_ci{ 1553f08c3bdfSopenharmony_ci return do_handle_undef(stream, line, token, SYM_ATTR_STRONG); 1554f08c3bdfSopenharmony_ci} 1555f08c3bdfSopenharmony_ci 1556f08c3bdfSopenharmony_cistatic int preprocessor_if(struct stream *stream, struct token *token, int cond) 1557f08c3bdfSopenharmony_ci{ 1558f08c3bdfSopenharmony_ci token_type(token) = false_nesting ? TOKEN_SKIP_GROUPS : TOKEN_IF; 1559f08c3bdfSopenharmony_ci free_preprocessor_line(token->next); 1560f08c3bdfSopenharmony_ci token->next = stream->top_if; 1561f08c3bdfSopenharmony_ci stream->top_if = token; 1562f08c3bdfSopenharmony_ci if (false_nesting || cond != 1) 1563f08c3bdfSopenharmony_ci false_nesting++; 1564f08c3bdfSopenharmony_ci return 0; 1565f08c3bdfSopenharmony_ci} 1566f08c3bdfSopenharmony_ci 1567f08c3bdfSopenharmony_cistatic int handle_ifdef(struct stream *stream, struct token **line, struct token *token) 1568f08c3bdfSopenharmony_ci{ 1569f08c3bdfSopenharmony_ci struct token *next = token->next; 1570f08c3bdfSopenharmony_ci int arg; 1571f08c3bdfSopenharmony_ci if (token_type(next) == TOKEN_IDENT) { 1572f08c3bdfSopenharmony_ci arg = token_defined(next); 1573f08c3bdfSopenharmony_ci } else { 1574f08c3bdfSopenharmony_ci dirty_stream(stream); 1575f08c3bdfSopenharmony_ci if (!false_nesting) 1576f08c3bdfSopenharmony_ci sparse_error(token->pos, "expected preprocessor identifier"); 1577f08c3bdfSopenharmony_ci arg = -1; 1578f08c3bdfSopenharmony_ci } 1579f08c3bdfSopenharmony_ci return preprocessor_if(stream, token, arg); 1580f08c3bdfSopenharmony_ci} 1581f08c3bdfSopenharmony_ci 1582f08c3bdfSopenharmony_cistatic int handle_ifndef(struct stream *stream, struct token **line, struct token *token) 1583f08c3bdfSopenharmony_ci{ 1584f08c3bdfSopenharmony_ci struct token *next = token->next; 1585f08c3bdfSopenharmony_ci int arg; 1586f08c3bdfSopenharmony_ci if (token_type(next) == TOKEN_IDENT) { 1587f08c3bdfSopenharmony_ci if (!stream->dirty && !stream->ifndef) { 1588f08c3bdfSopenharmony_ci if (!stream->protect) { 1589f08c3bdfSopenharmony_ci stream->ifndef = token; 1590f08c3bdfSopenharmony_ci stream->protect = next->ident; 1591f08c3bdfSopenharmony_ci } else if (stream->protect == next->ident) { 1592f08c3bdfSopenharmony_ci stream->ifndef = token; 1593f08c3bdfSopenharmony_ci stream->dirty = 1; 1594f08c3bdfSopenharmony_ci } 1595f08c3bdfSopenharmony_ci } 1596f08c3bdfSopenharmony_ci arg = !token_defined(next); 1597f08c3bdfSopenharmony_ci } else { 1598f08c3bdfSopenharmony_ci dirty_stream(stream); 1599f08c3bdfSopenharmony_ci if (!false_nesting) 1600f08c3bdfSopenharmony_ci sparse_error(token->pos, "expected preprocessor identifier"); 1601f08c3bdfSopenharmony_ci arg = -1; 1602f08c3bdfSopenharmony_ci } 1603f08c3bdfSopenharmony_ci 1604f08c3bdfSopenharmony_ci return preprocessor_if(stream, token, arg); 1605f08c3bdfSopenharmony_ci} 1606f08c3bdfSopenharmony_ci 1607f08c3bdfSopenharmony_ci/* 1608f08c3bdfSopenharmony_ci * Expression handling for #if and #elif; it differs from normal expansion 1609f08c3bdfSopenharmony_ci * due to special treatment of "defined". 1610f08c3bdfSopenharmony_ci */ 1611f08c3bdfSopenharmony_cistatic int expression_value(struct token **where) 1612f08c3bdfSopenharmony_ci{ 1613f08c3bdfSopenharmony_ci struct expression *expr; 1614f08c3bdfSopenharmony_ci struct token *p; 1615f08c3bdfSopenharmony_ci struct token **list = where, **beginning = NULL; 1616f08c3bdfSopenharmony_ci long long value; 1617f08c3bdfSopenharmony_ci int state = 0; 1618f08c3bdfSopenharmony_ci 1619f08c3bdfSopenharmony_ci while (!eof_token(p = scan_next(list))) { 1620f08c3bdfSopenharmony_ci switch (state) { 1621f08c3bdfSopenharmony_ci case 0: 1622f08c3bdfSopenharmony_ci if (token_type(p) != TOKEN_IDENT) 1623f08c3bdfSopenharmony_ci break; 1624f08c3bdfSopenharmony_ci if (p->ident == &defined_ident) { 1625f08c3bdfSopenharmony_ci state = 1; 1626f08c3bdfSopenharmony_ci beginning = list; 1627f08c3bdfSopenharmony_ci break; 1628f08c3bdfSopenharmony_ci } 1629f08c3bdfSopenharmony_ci if (!expand_one_symbol(list)) 1630f08c3bdfSopenharmony_ci continue; 1631f08c3bdfSopenharmony_ci if (token_type(p) != TOKEN_IDENT) 1632f08c3bdfSopenharmony_ci break; 1633f08c3bdfSopenharmony_ci token_type(p) = TOKEN_ZERO_IDENT; 1634f08c3bdfSopenharmony_ci break; 1635f08c3bdfSopenharmony_ci case 1: 1636f08c3bdfSopenharmony_ci if (match_op(p, '(')) { 1637f08c3bdfSopenharmony_ci state = 2; 1638f08c3bdfSopenharmony_ci } else { 1639f08c3bdfSopenharmony_ci state = 0; 1640f08c3bdfSopenharmony_ci replace_with_defined(p); 1641f08c3bdfSopenharmony_ci *beginning = p; 1642f08c3bdfSopenharmony_ci } 1643f08c3bdfSopenharmony_ci break; 1644f08c3bdfSopenharmony_ci case 2: 1645f08c3bdfSopenharmony_ci if (token_type(p) == TOKEN_IDENT) 1646f08c3bdfSopenharmony_ci state = 3; 1647f08c3bdfSopenharmony_ci else 1648f08c3bdfSopenharmony_ci state = 0; 1649f08c3bdfSopenharmony_ci replace_with_defined(p); 1650f08c3bdfSopenharmony_ci *beginning = p; 1651f08c3bdfSopenharmony_ci break; 1652f08c3bdfSopenharmony_ci case 3: 1653f08c3bdfSopenharmony_ci state = 0; 1654f08c3bdfSopenharmony_ci if (!match_op(p, ')')) 1655f08c3bdfSopenharmony_ci sparse_error(p->pos, "missing ')' after \"defined\""); 1656f08c3bdfSopenharmony_ci *list = p->next; 1657f08c3bdfSopenharmony_ci continue; 1658f08c3bdfSopenharmony_ci } 1659f08c3bdfSopenharmony_ci list = &p->next; 1660f08c3bdfSopenharmony_ci } 1661f08c3bdfSopenharmony_ci 1662f08c3bdfSopenharmony_ci p = constant_expression(*where, &expr); 1663f08c3bdfSopenharmony_ci if (!eof_token(p)) 1664f08c3bdfSopenharmony_ci sparse_error(p->pos, "garbage at end: %s", show_token_sequence(p, 0)); 1665f08c3bdfSopenharmony_ci value = get_expression_value(expr); 1666f08c3bdfSopenharmony_ci return value != 0; 1667f08c3bdfSopenharmony_ci} 1668f08c3bdfSopenharmony_ci 1669f08c3bdfSopenharmony_cistatic int handle_if(struct stream *stream, struct token **line, struct token *token) 1670f08c3bdfSopenharmony_ci{ 1671f08c3bdfSopenharmony_ci int value = 0; 1672f08c3bdfSopenharmony_ci if (!false_nesting) 1673f08c3bdfSopenharmony_ci value = expression_value(&token->next); 1674f08c3bdfSopenharmony_ci 1675f08c3bdfSopenharmony_ci dirty_stream(stream); 1676f08c3bdfSopenharmony_ci return preprocessor_if(stream, token, value); 1677f08c3bdfSopenharmony_ci} 1678f08c3bdfSopenharmony_ci 1679f08c3bdfSopenharmony_cistatic int handle_elif(struct stream * stream, struct token **line, struct token *token) 1680f08c3bdfSopenharmony_ci{ 1681f08c3bdfSopenharmony_ci struct token *top_if = stream->top_if; 1682f08c3bdfSopenharmony_ci end_group(stream); 1683f08c3bdfSopenharmony_ci 1684f08c3bdfSopenharmony_ci if (!top_if) { 1685f08c3bdfSopenharmony_ci nesting_error(stream); 1686f08c3bdfSopenharmony_ci sparse_error(token->pos, "unmatched #elif within stream"); 1687f08c3bdfSopenharmony_ci return 1; 1688f08c3bdfSopenharmony_ci } 1689f08c3bdfSopenharmony_ci 1690f08c3bdfSopenharmony_ci if (token_type(top_if) == TOKEN_ELSE) { 1691f08c3bdfSopenharmony_ci nesting_error(stream); 1692f08c3bdfSopenharmony_ci sparse_error(token->pos, "#elif after #else"); 1693f08c3bdfSopenharmony_ci if (!false_nesting) 1694f08c3bdfSopenharmony_ci false_nesting = 1; 1695f08c3bdfSopenharmony_ci return 1; 1696f08c3bdfSopenharmony_ci } 1697f08c3bdfSopenharmony_ci 1698f08c3bdfSopenharmony_ci dirty_stream(stream); 1699f08c3bdfSopenharmony_ci if (token_type(top_if) != TOKEN_IF) 1700f08c3bdfSopenharmony_ci return 1; 1701f08c3bdfSopenharmony_ci if (false_nesting) { 1702f08c3bdfSopenharmony_ci false_nesting = 0; 1703f08c3bdfSopenharmony_ci if (!expression_value(&token->next)) 1704f08c3bdfSopenharmony_ci false_nesting = 1; 1705f08c3bdfSopenharmony_ci } else { 1706f08c3bdfSopenharmony_ci false_nesting = 1; 1707f08c3bdfSopenharmony_ci token_type(top_if) = TOKEN_SKIP_GROUPS; 1708f08c3bdfSopenharmony_ci } 1709f08c3bdfSopenharmony_ci return 1; 1710f08c3bdfSopenharmony_ci} 1711f08c3bdfSopenharmony_ci 1712f08c3bdfSopenharmony_cistatic int handle_else(struct stream *stream, struct token **line, struct token *token) 1713f08c3bdfSopenharmony_ci{ 1714f08c3bdfSopenharmony_ci struct token *top_if = stream->top_if; 1715f08c3bdfSopenharmony_ci end_group(stream); 1716f08c3bdfSopenharmony_ci 1717f08c3bdfSopenharmony_ci if (!top_if) { 1718f08c3bdfSopenharmony_ci nesting_error(stream); 1719f08c3bdfSopenharmony_ci sparse_error(token->pos, "unmatched #else within stream"); 1720f08c3bdfSopenharmony_ci return 1; 1721f08c3bdfSopenharmony_ci } 1722f08c3bdfSopenharmony_ci 1723f08c3bdfSopenharmony_ci if (token_type(top_if) == TOKEN_ELSE) { 1724f08c3bdfSopenharmony_ci nesting_error(stream); 1725f08c3bdfSopenharmony_ci sparse_error(token->pos, "#else after #else"); 1726f08c3bdfSopenharmony_ci } 1727f08c3bdfSopenharmony_ci if (false_nesting) { 1728f08c3bdfSopenharmony_ci if (token_type(top_if) == TOKEN_IF) 1729f08c3bdfSopenharmony_ci false_nesting = 0; 1730f08c3bdfSopenharmony_ci } else { 1731f08c3bdfSopenharmony_ci false_nesting = 1; 1732f08c3bdfSopenharmony_ci } 1733f08c3bdfSopenharmony_ci token_type(top_if) = TOKEN_ELSE; 1734f08c3bdfSopenharmony_ci return 1; 1735f08c3bdfSopenharmony_ci} 1736f08c3bdfSopenharmony_ci 1737f08c3bdfSopenharmony_cistatic int handle_endif(struct stream *stream, struct token **line, struct token *token) 1738f08c3bdfSopenharmony_ci{ 1739f08c3bdfSopenharmony_ci struct token *top_if = stream->top_if; 1740f08c3bdfSopenharmony_ci end_group(stream); 1741f08c3bdfSopenharmony_ci if (!top_if) { 1742f08c3bdfSopenharmony_ci nesting_error(stream); 1743f08c3bdfSopenharmony_ci sparse_error(token->pos, "unmatched #endif in stream"); 1744f08c3bdfSopenharmony_ci return 1; 1745f08c3bdfSopenharmony_ci } 1746f08c3bdfSopenharmony_ci if (false_nesting) 1747f08c3bdfSopenharmony_ci false_nesting--; 1748f08c3bdfSopenharmony_ci stream->top_if = top_if->next; 1749f08c3bdfSopenharmony_ci __free_token(top_if); 1750f08c3bdfSopenharmony_ci return 1; 1751f08c3bdfSopenharmony_ci} 1752f08c3bdfSopenharmony_ci 1753f08c3bdfSopenharmony_cistatic int handle_warning(struct stream *stream, struct token **line, struct token *token) 1754f08c3bdfSopenharmony_ci{ 1755f08c3bdfSopenharmony_ci warning(token->pos, "%s", show_token_sequence(token->next, 0)); 1756f08c3bdfSopenharmony_ci return 1; 1757f08c3bdfSopenharmony_ci} 1758f08c3bdfSopenharmony_ci 1759f08c3bdfSopenharmony_cistatic int handle_error(struct stream *stream, struct token **line, struct token *token) 1760f08c3bdfSopenharmony_ci{ 1761f08c3bdfSopenharmony_ci sparse_error(token->pos, "%s", show_token_sequence(token->next, 0)); 1762f08c3bdfSopenharmony_ci return 1; 1763f08c3bdfSopenharmony_ci} 1764f08c3bdfSopenharmony_ci 1765f08c3bdfSopenharmony_cistatic int handle_nostdinc(struct stream *stream, struct token **line, struct token *token) 1766f08c3bdfSopenharmony_ci{ 1767f08c3bdfSopenharmony_ci /* 1768f08c3bdfSopenharmony_ci * Do we have any non-system includes? 1769f08c3bdfSopenharmony_ci * Clear them out if so.. 1770f08c3bdfSopenharmony_ci */ 1771f08c3bdfSopenharmony_ci *sys_includepath = NULL; 1772f08c3bdfSopenharmony_ci return 1; 1773f08c3bdfSopenharmony_ci} 1774f08c3bdfSopenharmony_ci 1775f08c3bdfSopenharmony_cistatic inline void update_inc_ptrs(const char ***where) 1776f08c3bdfSopenharmony_ci{ 1777f08c3bdfSopenharmony_ci 1778f08c3bdfSopenharmony_ci if (*where <= dirafter_includepath) { 1779f08c3bdfSopenharmony_ci dirafter_includepath++; 1780f08c3bdfSopenharmony_ci /* If this was the entry that we prepend, don't 1781f08c3bdfSopenharmony_ci * rise the lower entries, even if they are at 1782f08c3bdfSopenharmony_ci * the same level. */ 1783f08c3bdfSopenharmony_ci if (where == &dirafter_includepath) 1784f08c3bdfSopenharmony_ci return; 1785f08c3bdfSopenharmony_ci } 1786f08c3bdfSopenharmony_ci if (*where <= sys_includepath) { 1787f08c3bdfSopenharmony_ci sys_includepath++; 1788f08c3bdfSopenharmony_ci if (where == &sys_includepath) 1789f08c3bdfSopenharmony_ci return; 1790f08c3bdfSopenharmony_ci } 1791f08c3bdfSopenharmony_ci if (*where <= isys_includepath) { 1792f08c3bdfSopenharmony_ci isys_includepath++; 1793f08c3bdfSopenharmony_ci if (where == &isys_includepath) 1794f08c3bdfSopenharmony_ci return; 1795f08c3bdfSopenharmony_ci } 1796f08c3bdfSopenharmony_ci 1797f08c3bdfSopenharmony_ci /* angle_includepath is actually never updated, since we 1798f08c3bdfSopenharmony_ci * don't suppport -iquote rught now. May change some day. */ 1799f08c3bdfSopenharmony_ci if (*where <= angle_includepath) { 1800f08c3bdfSopenharmony_ci angle_includepath++; 1801f08c3bdfSopenharmony_ci if (where == &angle_includepath) 1802f08c3bdfSopenharmony_ci return; 1803f08c3bdfSopenharmony_ci } 1804f08c3bdfSopenharmony_ci} 1805f08c3bdfSopenharmony_ci 1806f08c3bdfSopenharmony_ci/* Add a path before 'where' and update the pointers associated with the 1807f08c3bdfSopenharmony_ci * includepath array */ 1808f08c3bdfSopenharmony_cistatic void add_path_entry(struct token *token, const char *path, 1809f08c3bdfSopenharmony_ci const char ***where) 1810f08c3bdfSopenharmony_ci{ 1811f08c3bdfSopenharmony_ci const char **dst; 1812f08c3bdfSopenharmony_ci const char *next; 1813f08c3bdfSopenharmony_ci 1814f08c3bdfSopenharmony_ci /* Need one free entry.. */ 1815f08c3bdfSopenharmony_ci if (includepath[INCLUDEPATHS-2]) 1816f08c3bdfSopenharmony_ci error_die(token->pos, "too many include path entries"); 1817f08c3bdfSopenharmony_ci 1818f08c3bdfSopenharmony_ci /* check that this is not a duplicate */ 1819f08c3bdfSopenharmony_ci dst = includepath; 1820f08c3bdfSopenharmony_ci while (*dst) { 1821f08c3bdfSopenharmony_ci if (strcmp(*dst, path) == 0) 1822f08c3bdfSopenharmony_ci return; 1823f08c3bdfSopenharmony_ci dst++; 1824f08c3bdfSopenharmony_ci } 1825f08c3bdfSopenharmony_ci next = path; 1826f08c3bdfSopenharmony_ci dst = *where; 1827f08c3bdfSopenharmony_ci 1828f08c3bdfSopenharmony_ci update_inc_ptrs(where); 1829f08c3bdfSopenharmony_ci 1830f08c3bdfSopenharmony_ci /* 1831f08c3bdfSopenharmony_ci * Move them all up starting at dst, 1832f08c3bdfSopenharmony_ci * insert the new entry.. 1833f08c3bdfSopenharmony_ci */ 1834f08c3bdfSopenharmony_ci do { 1835f08c3bdfSopenharmony_ci const char *tmp = *dst; 1836f08c3bdfSopenharmony_ci *dst = next; 1837f08c3bdfSopenharmony_ci next = tmp; 1838f08c3bdfSopenharmony_ci dst++; 1839f08c3bdfSopenharmony_ci } while (next); 1840f08c3bdfSopenharmony_ci} 1841f08c3bdfSopenharmony_ci 1842f08c3bdfSopenharmony_cistatic int handle_add_include(struct stream *stream, struct token **line, struct token *token) 1843f08c3bdfSopenharmony_ci{ 1844f08c3bdfSopenharmony_ci for (;;) { 1845f08c3bdfSopenharmony_ci token = token->next; 1846f08c3bdfSopenharmony_ci if (eof_token(token)) 1847f08c3bdfSopenharmony_ci return 1; 1848f08c3bdfSopenharmony_ci if (token_type(token) != TOKEN_STRING) { 1849f08c3bdfSopenharmony_ci warning(token->pos, "expected path string"); 1850f08c3bdfSopenharmony_ci return 1; 1851f08c3bdfSopenharmony_ci } 1852f08c3bdfSopenharmony_ci add_path_entry(token, token->string->data, &isys_includepath); 1853f08c3bdfSopenharmony_ci } 1854f08c3bdfSopenharmony_ci} 1855f08c3bdfSopenharmony_ci 1856f08c3bdfSopenharmony_cistatic int handle_add_isystem(struct stream *stream, struct token **line, struct token *token) 1857f08c3bdfSopenharmony_ci{ 1858f08c3bdfSopenharmony_ci for (;;) { 1859f08c3bdfSopenharmony_ci token = token->next; 1860f08c3bdfSopenharmony_ci if (eof_token(token)) 1861f08c3bdfSopenharmony_ci return 1; 1862f08c3bdfSopenharmony_ci if (token_type(token) != TOKEN_STRING) { 1863f08c3bdfSopenharmony_ci sparse_error(token->pos, "expected path string"); 1864f08c3bdfSopenharmony_ci return 1; 1865f08c3bdfSopenharmony_ci } 1866f08c3bdfSopenharmony_ci add_path_entry(token, token->string->data, &sys_includepath); 1867f08c3bdfSopenharmony_ci } 1868f08c3bdfSopenharmony_ci} 1869f08c3bdfSopenharmony_ci 1870f08c3bdfSopenharmony_cistatic int handle_add_system(struct stream *stream, struct token **line, struct token *token) 1871f08c3bdfSopenharmony_ci{ 1872f08c3bdfSopenharmony_ci for (;;) { 1873f08c3bdfSopenharmony_ci token = token->next; 1874f08c3bdfSopenharmony_ci if (eof_token(token)) 1875f08c3bdfSopenharmony_ci return 1; 1876f08c3bdfSopenharmony_ci if (token_type(token) != TOKEN_STRING) { 1877f08c3bdfSopenharmony_ci sparse_error(token->pos, "expected path string"); 1878f08c3bdfSopenharmony_ci return 1; 1879f08c3bdfSopenharmony_ci } 1880f08c3bdfSopenharmony_ci add_path_entry(token, token->string->data, &dirafter_includepath); 1881f08c3bdfSopenharmony_ci } 1882f08c3bdfSopenharmony_ci} 1883f08c3bdfSopenharmony_ci 1884f08c3bdfSopenharmony_ci/* Add to end on includepath list - no pointer updates */ 1885f08c3bdfSopenharmony_cistatic void add_dirafter_entry(struct token *token, const char *path) 1886f08c3bdfSopenharmony_ci{ 1887f08c3bdfSopenharmony_ci const char **dst = includepath; 1888f08c3bdfSopenharmony_ci 1889f08c3bdfSopenharmony_ci /* Need one free entry.. */ 1890f08c3bdfSopenharmony_ci if (includepath[INCLUDEPATHS-2]) 1891f08c3bdfSopenharmony_ci error_die(token->pos, "too many include path entries"); 1892f08c3bdfSopenharmony_ci 1893f08c3bdfSopenharmony_ci /* Add to the end */ 1894f08c3bdfSopenharmony_ci while (*dst) 1895f08c3bdfSopenharmony_ci dst++; 1896f08c3bdfSopenharmony_ci *dst = path; 1897f08c3bdfSopenharmony_ci dst++; 1898f08c3bdfSopenharmony_ci *dst = NULL; 1899f08c3bdfSopenharmony_ci} 1900f08c3bdfSopenharmony_ci 1901f08c3bdfSopenharmony_cistatic int handle_add_dirafter(struct stream *stream, struct token **line, struct token *token) 1902f08c3bdfSopenharmony_ci{ 1903f08c3bdfSopenharmony_ci for (;;) { 1904f08c3bdfSopenharmony_ci token = token->next; 1905f08c3bdfSopenharmony_ci if (eof_token(token)) 1906f08c3bdfSopenharmony_ci return 1; 1907f08c3bdfSopenharmony_ci if (token_type(token) != TOKEN_STRING) { 1908f08c3bdfSopenharmony_ci sparse_error(token->pos, "expected path string"); 1909f08c3bdfSopenharmony_ci return 1; 1910f08c3bdfSopenharmony_ci } 1911f08c3bdfSopenharmony_ci add_dirafter_entry(token, token->string->data); 1912f08c3bdfSopenharmony_ci } 1913f08c3bdfSopenharmony_ci} 1914f08c3bdfSopenharmony_ci 1915f08c3bdfSopenharmony_cistatic int handle_split_include(struct stream *stream, struct token **line, struct token *token) 1916f08c3bdfSopenharmony_ci{ 1917f08c3bdfSopenharmony_ci /* 1918f08c3bdfSopenharmony_ci * -I- 1919f08c3bdfSopenharmony_ci * From info gcc: 1920f08c3bdfSopenharmony_ci * Split the include path. Any directories specified with `-I' 1921f08c3bdfSopenharmony_ci * options before `-I-' are searched only for headers requested with 1922f08c3bdfSopenharmony_ci * `#include "FILE"'; they are not searched for `#include <FILE>'. 1923f08c3bdfSopenharmony_ci * If additional directories are specified with `-I' options after 1924f08c3bdfSopenharmony_ci * the `-I-', those directories are searched for all `#include' 1925f08c3bdfSopenharmony_ci * directives. 1926f08c3bdfSopenharmony_ci * In addition, `-I-' inhibits the use of the directory of the current 1927f08c3bdfSopenharmony_ci * file directory as the first search directory for `#include "FILE"'. 1928f08c3bdfSopenharmony_ci */ 1929f08c3bdfSopenharmony_ci quote_includepath = includepath+1; 1930f08c3bdfSopenharmony_ci angle_includepath = sys_includepath; 1931f08c3bdfSopenharmony_ci return 1; 1932f08c3bdfSopenharmony_ci} 1933f08c3bdfSopenharmony_ci 1934f08c3bdfSopenharmony_ci/* 1935f08c3bdfSopenharmony_ci * We replace "#pragma xxx" with "__pragma__" in the token 1936f08c3bdfSopenharmony_ci * stream. Just as an example. 1937f08c3bdfSopenharmony_ci * 1938f08c3bdfSopenharmony_ci * We'll just #define that away for now, but the theory here 1939f08c3bdfSopenharmony_ci * is that we can use this to insert arbitrary token sequences 1940f08c3bdfSopenharmony_ci * to turn the pragmas into internal front-end sequences for 1941f08c3bdfSopenharmony_ci * when we actually start caring about them. 1942f08c3bdfSopenharmony_ci * 1943f08c3bdfSopenharmony_ci * So eventually this will turn into some kind of extended 1944f08c3bdfSopenharmony_ci * __attribute__() like thing, except called __pragma__(xxx). 1945f08c3bdfSopenharmony_ci */ 1946f08c3bdfSopenharmony_cistatic int handle_pragma(struct stream *stream, struct token **line, struct token *token) 1947f08c3bdfSopenharmony_ci{ 1948f08c3bdfSopenharmony_ci struct token *next = *line; 1949f08c3bdfSopenharmony_ci 1950f08c3bdfSopenharmony_ci if (match_ident(token->next, &once_ident) && eof_token(token->next->next)) { 1951f08c3bdfSopenharmony_ci stream->once = 1; 1952f08c3bdfSopenharmony_ci return 1; 1953f08c3bdfSopenharmony_ci } 1954f08c3bdfSopenharmony_ci token->ident = &pragma_ident; 1955f08c3bdfSopenharmony_ci token->pos.newline = 1; 1956f08c3bdfSopenharmony_ci token->pos.whitespace = 1; 1957f08c3bdfSopenharmony_ci token->pos.pos = 1; 1958f08c3bdfSopenharmony_ci *line = token; 1959f08c3bdfSopenharmony_ci token->next = next; 1960f08c3bdfSopenharmony_ci return 0; 1961f08c3bdfSopenharmony_ci} 1962f08c3bdfSopenharmony_ci 1963f08c3bdfSopenharmony_ci/* 1964f08c3bdfSopenharmony_ci * We ignore #line for now. 1965f08c3bdfSopenharmony_ci */ 1966f08c3bdfSopenharmony_cistatic int handle_line(struct stream *stream, struct token **line, struct token *token) 1967f08c3bdfSopenharmony_ci{ 1968f08c3bdfSopenharmony_ci return 1; 1969f08c3bdfSopenharmony_ci} 1970f08c3bdfSopenharmony_ci 1971f08c3bdfSopenharmony_cistatic int handle_ident(struct stream *stream, struct token **line, struct token *token) 1972f08c3bdfSopenharmony_ci{ 1973f08c3bdfSopenharmony_ci return 1; 1974f08c3bdfSopenharmony_ci} 1975f08c3bdfSopenharmony_ci 1976f08c3bdfSopenharmony_cistatic int handle_nondirective(struct stream *stream, struct token **line, struct token *token) 1977f08c3bdfSopenharmony_ci{ 1978f08c3bdfSopenharmony_ci sparse_error(token->pos, "unrecognized preprocessor line '%s'", show_token_sequence(token, 0)); 1979f08c3bdfSopenharmony_ci return 1; 1980f08c3bdfSopenharmony_ci} 1981f08c3bdfSopenharmony_ci 1982f08c3bdfSopenharmony_cistatic bool expand_has_attribute(struct token *token, struct arg *args) 1983f08c3bdfSopenharmony_ci{ 1984f08c3bdfSopenharmony_ci struct token *arg = args[0].expanded; 1985f08c3bdfSopenharmony_ci struct symbol *sym; 1986f08c3bdfSopenharmony_ci 1987f08c3bdfSopenharmony_ci if (token_type(arg) != TOKEN_IDENT) { 1988f08c3bdfSopenharmony_ci sparse_error(arg->pos, "identifier expected"); 1989f08c3bdfSopenharmony_ci return false; 1990f08c3bdfSopenharmony_ci } 1991f08c3bdfSopenharmony_ci 1992f08c3bdfSopenharmony_ci sym = lookup_symbol(arg->ident, NS_KEYWORD); 1993f08c3bdfSopenharmony_ci replace_with_bool(token, sym && sym->op && sym->op->attribute); 1994f08c3bdfSopenharmony_ci return true; 1995f08c3bdfSopenharmony_ci} 1996f08c3bdfSopenharmony_ci 1997f08c3bdfSopenharmony_cistatic bool expand_has_builtin(struct token *token, struct arg *args) 1998f08c3bdfSopenharmony_ci{ 1999f08c3bdfSopenharmony_ci struct token *arg = args[0].expanded; 2000f08c3bdfSopenharmony_ci struct symbol *sym; 2001f08c3bdfSopenharmony_ci 2002f08c3bdfSopenharmony_ci if (token_type(arg) != TOKEN_IDENT) { 2003f08c3bdfSopenharmony_ci sparse_error(arg->pos, "identifier expected"); 2004f08c3bdfSopenharmony_ci return false; 2005f08c3bdfSopenharmony_ci } 2006f08c3bdfSopenharmony_ci 2007f08c3bdfSopenharmony_ci sym = lookup_symbol(arg->ident, NS_SYMBOL); 2008f08c3bdfSopenharmony_ci replace_with_bool(token, sym && sym->builtin); 2009f08c3bdfSopenharmony_ci return true; 2010f08c3bdfSopenharmony_ci} 2011f08c3bdfSopenharmony_ci 2012f08c3bdfSopenharmony_cistatic bool expand_has_extension(struct token *token, struct arg *args) 2013f08c3bdfSopenharmony_ci{ 2014f08c3bdfSopenharmony_ci struct token *arg = args[0].expanded; 2015f08c3bdfSopenharmony_ci struct ident *ident; 2016f08c3bdfSopenharmony_ci bool val = false; 2017f08c3bdfSopenharmony_ci 2018f08c3bdfSopenharmony_ci if (token_type(arg) != TOKEN_IDENT) { 2019f08c3bdfSopenharmony_ci sparse_error(arg->pos, "identifier expected"); 2020f08c3bdfSopenharmony_ci return false; 2021f08c3bdfSopenharmony_ci } 2022f08c3bdfSopenharmony_ci 2023f08c3bdfSopenharmony_ci ident = arg->ident; 2024f08c3bdfSopenharmony_ci if (ident == &c_alignas_ident) 2025f08c3bdfSopenharmony_ci val = true; 2026f08c3bdfSopenharmony_ci else if (ident == &c_alignof_ident) 2027f08c3bdfSopenharmony_ci val = true; 2028f08c3bdfSopenharmony_ci else if (ident == &c_generic_selections_ident) 2029f08c3bdfSopenharmony_ci val = true; 2030f08c3bdfSopenharmony_ci else if (ident == &c_static_assert_ident) 2031f08c3bdfSopenharmony_ci val = true; 2032f08c3bdfSopenharmony_ci 2033f08c3bdfSopenharmony_ci replace_with_bool(token, val); 2034f08c3bdfSopenharmony_ci return 1; 2035f08c3bdfSopenharmony_ci} 2036f08c3bdfSopenharmony_ci 2037f08c3bdfSopenharmony_cistatic bool expand_has_feature(struct token *token, struct arg *args) 2038f08c3bdfSopenharmony_ci{ 2039f08c3bdfSopenharmony_ci struct token *arg = args[0].expanded; 2040f08c3bdfSopenharmony_ci struct ident *ident; 2041f08c3bdfSopenharmony_ci bool val = false; 2042f08c3bdfSopenharmony_ci 2043f08c3bdfSopenharmony_ci if (token_type(arg) != TOKEN_IDENT) { 2044f08c3bdfSopenharmony_ci sparse_error(arg->pos, "identifier expected"); 2045f08c3bdfSopenharmony_ci return false; 2046f08c3bdfSopenharmony_ci } 2047f08c3bdfSopenharmony_ci 2048f08c3bdfSopenharmony_ci ident = arg->ident; 2049f08c3bdfSopenharmony_ci if (standard >= STANDARD_C11) { 2050f08c3bdfSopenharmony_ci if (ident == &c_alignas_ident) 2051f08c3bdfSopenharmony_ci val = true; 2052f08c3bdfSopenharmony_ci else if (ident == &c_alignof_ident) 2053f08c3bdfSopenharmony_ci val = true; 2054f08c3bdfSopenharmony_ci else if (ident == &c_generic_selections_ident) 2055f08c3bdfSopenharmony_ci val = true; 2056f08c3bdfSopenharmony_ci else if (ident == &c_static_assert_ident) 2057f08c3bdfSopenharmony_ci val = true; 2058f08c3bdfSopenharmony_ci } 2059f08c3bdfSopenharmony_ci 2060f08c3bdfSopenharmony_ci replace_with_bool(token, val); 2061f08c3bdfSopenharmony_ci return 1; 2062f08c3bdfSopenharmony_ci} 2063f08c3bdfSopenharmony_ci 2064f08c3bdfSopenharmony_cistatic void create_arglist(struct symbol *sym, int count) 2065f08c3bdfSopenharmony_ci{ 2066f08c3bdfSopenharmony_ci struct token *token; 2067f08c3bdfSopenharmony_ci struct token **next; 2068f08c3bdfSopenharmony_ci 2069f08c3bdfSopenharmony_ci if (!count) 2070f08c3bdfSopenharmony_ci return; 2071f08c3bdfSopenharmony_ci 2072f08c3bdfSopenharmony_ci token = __alloc_token(0); 2073f08c3bdfSopenharmony_ci token_type(token) = TOKEN_ARG_COUNT; 2074f08c3bdfSopenharmony_ci token->count.normal = count; 2075f08c3bdfSopenharmony_ci sym->arglist = token; 2076f08c3bdfSopenharmony_ci next = &token->next; 2077f08c3bdfSopenharmony_ci 2078f08c3bdfSopenharmony_ci while (count--) { 2079f08c3bdfSopenharmony_ci struct token *id, *uses; 2080f08c3bdfSopenharmony_ci id = __alloc_token(0); 2081f08c3bdfSopenharmony_ci token_type(id) = TOKEN_IDENT; 2082f08c3bdfSopenharmony_ci uses = __alloc_token(0); 2083f08c3bdfSopenharmony_ci token_type(uses) = TOKEN_ARG_COUNT; 2084f08c3bdfSopenharmony_ci uses->count.normal = 1; 2085f08c3bdfSopenharmony_ci 2086f08c3bdfSopenharmony_ci *next = id; 2087f08c3bdfSopenharmony_ci id->next = uses; 2088f08c3bdfSopenharmony_ci next = &uses->next; 2089f08c3bdfSopenharmony_ci } 2090f08c3bdfSopenharmony_ci *next = &eof_token_entry; 2091f08c3bdfSopenharmony_ci} 2092f08c3bdfSopenharmony_ci 2093f08c3bdfSopenharmony_cistatic void init_preprocessor(void) 2094f08c3bdfSopenharmony_ci{ 2095f08c3bdfSopenharmony_ci int i; 2096f08c3bdfSopenharmony_ci int stream = init_stream(NULL, "preprocessor", -1, includepath); 2097f08c3bdfSopenharmony_ci static struct { 2098f08c3bdfSopenharmony_ci const char *name; 2099f08c3bdfSopenharmony_ci int (*handler)(struct stream *, struct token **, struct token *); 2100f08c3bdfSopenharmony_ci } normal[] = { 2101f08c3bdfSopenharmony_ci { "define", handle_define }, 2102f08c3bdfSopenharmony_ci { "weak_define", handle_weak_define }, 2103f08c3bdfSopenharmony_ci { "strong_define", handle_strong_define }, 2104f08c3bdfSopenharmony_ci { "undef", handle_undef }, 2105f08c3bdfSopenharmony_ci { "strong_undef", handle_strong_undef }, 2106f08c3bdfSopenharmony_ci { "warning", handle_warning }, 2107f08c3bdfSopenharmony_ci { "error", handle_error }, 2108f08c3bdfSopenharmony_ci { "include", handle_include }, 2109f08c3bdfSopenharmony_ci { "include_next", handle_include_next }, 2110f08c3bdfSopenharmony_ci { "pragma", handle_pragma }, 2111f08c3bdfSopenharmony_ci { "line", handle_line }, 2112f08c3bdfSopenharmony_ci { "ident", handle_ident }, 2113f08c3bdfSopenharmony_ci 2114f08c3bdfSopenharmony_ci // our internal preprocessor tokens 2115f08c3bdfSopenharmony_ci { "nostdinc", handle_nostdinc }, 2116f08c3bdfSopenharmony_ci { "add_include", handle_add_include }, 2117f08c3bdfSopenharmony_ci { "add_isystem", handle_add_isystem }, 2118f08c3bdfSopenharmony_ci { "add_system", handle_add_system }, 2119f08c3bdfSopenharmony_ci { "add_dirafter", handle_add_dirafter }, 2120f08c3bdfSopenharmony_ci { "split_include", handle_split_include }, 2121f08c3bdfSopenharmony_ci { "argv_include", handle_argv_include }, 2122f08c3bdfSopenharmony_ci }, special[] = { 2123f08c3bdfSopenharmony_ci { "ifdef", handle_ifdef }, 2124f08c3bdfSopenharmony_ci { "ifndef", handle_ifndef }, 2125f08c3bdfSopenharmony_ci { "else", handle_else }, 2126f08c3bdfSopenharmony_ci { "endif", handle_endif }, 2127f08c3bdfSopenharmony_ci { "if", handle_if }, 2128f08c3bdfSopenharmony_ci { "elif", handle_elif }, 2129f08c3bdfSopenharmony_ci }; 2130f08c3bdfSopenharmony_ci static struct { 2131f08c3bdfSopenharmony_ci const char *name; 2132f08c3bdfSopenharmony_ci void (*expand_simple)(struct token *); 2133f08c3bdfSopenharmony_ci bool (*expand)(struct token *, struct arg *args); 2134f08c3bdfSopenharmony_ci } dynamic[] = { 2135f08c3bdfSopenharmony_ci { "__LINE__", expand_line }, 2136f08c3bdfSopenharmony_ci { "__FILE__", expand_file }, 2137f08c3bdfSopenharmony_ci { "__BASE_FILE__", expand_basefile }, 2138f08c3bdfSopenharmony_ci { "__DATE__", expand_date }, 2139f08c3bdfSopenharmony_ci { "__TIME__", expand_time }, 2140f08c3bdfSopenharmony_ci { "__COUNTER__", expand_counter }, 2141f08c3bdfSopenharmony_ci { "__INCLUDE_LEVEL__", expand_include_level }, 2142f08c3bdfSopenharmony_ci { "__has_attribute", NULL, expand_has_attribute }, 2143f08c3bdfSopenharmony_ci { "__has_builtin", NULL, expand_has_builtin }, 2144f08c3bdfSopenharmony_ci { "__has_extension", NULL, expand_has_extension }, 2145f08c3bdfSopenharmony_ci { "__has_feature", NULL, expand_has_feature }, 2146f08c3bdfSopenharmony_ci }; 2147f08c3bdfSopenharmony_ci 2148f08c3bdfSopenharmony_ci for (i = 0; i < ARRAY_SIZE(normal); i++) { 2149f08c3bdfSopenharmony_ci struct symbol *sym; 2150f08c3bdfSopenharmony_ci sym = create_symbol(stream, normal[i].name, SYM_PREPROCESSOR, NS_PREPROCESSOR); 2151f08c3bdfSopenharmony_ci sym->handler = normal[i].handler; 2152f08c3bdfSopenharmony_ci sym->normal = 1; 2153f08c3bdfSopenharmony_ci } 2154f08c3bdfSopenharmony_ci for (i = 0; i < ARRAY_SIZE(special); i++) { 2155f08c3bdfSopenharmony_ci struct symbol *sym; 2156f08c3bdfSopenharmony_ci sym = create_symbol(stream, special[i].name, SYM_PREPROCESSOR, NS_PREPROCESSOR); 2157f08c3bdfSopenharmony_ci sym->handler = special[i].handler; 2158f08c3bdfSopenharmony_ci sym->normal = 0; 2159f08c3bdfSopenharmony_ci } 2160f08c3bdfSopenharmony_ci for (i = 0; i < ARRAY_SIZE(dynamic); i++) { 2161f08c3bdfSopenharmony_ci struct symbol *sym; 2162f08c3bdfSopenharmony_ci sym = create_symbol(stream, dynamic[i].name, SYM_NODE, NS_MACRO); 2163f08c3bdfSopenharmony_ci sym->expand_simple = dynamic[i].expand_simple; 2164f08c3bdfSopenharmony_ci if ((sym->expand = dynamic[i].expand) != NULL) 2165f08c3bdfSopenharmony_ci create_arglist(sym, 1); 2166f08c3bdfSopenharmony_ci } 2167f08c3bdfSopenharmony_ci 2168f08c3bdfSopenharmony_ci counter_macro = 0; 2169f08c3bdfSopenharmony_ci} 2170f08c3bdfSopenharmony_ci 2171f08c3bdfSopenharmony_cistatic void handle_preprocessor_line(struct stream *stream, struct token **line, struct token *start) 2172f08c3bdfSopenharmony_ci{ 2173f08c3bdfSopenharmony_ci int (*handler)(struct stream *, struct token **, struct token *); 2174f08c3bdfSopenharmony_ci struct token *token = start->next; 2175f08c3bdfSopenharmony_ci int is_normal = 1; 2176f08c3bdfSopenharmony_ci int is_cond = 0; // is one of {is,ifdef,ifndef,elif,else,endif} 2177f08c3bdfSopenharmony_ci 2178f08c3bdfSopenharmony_ci if (eof_token(token)) 2179f08c3bdfSopenharmony_ci return; 2180f08c3bdfSopenharmony_ci 2181f08c3bdfSopenharmony_ci if (token_type(token) == TOKEN_IDENT) { 2182f08c3bdfSopenharmony_ci struct symbol *sym = lookup_symbol(token->ident, NS_PREPROCESSOR); 2183f08c3bdfSopenharmony_ci if (sym) { 2184f08c3bdfSopenharmony_ci handler = sym->handler; 2185f08c3bdfSopenharmony_ci is_normal = sym->normal; 2186f08c3bdfSopenharmony_ci is_cond = !sym->normal; 2187f08c3bdfSopenharmony_ci } else { 2188f08c3bdfSopenharmony_ci handler = handle_nondirective; 2189f08c3bdfSopenharmony_ci } 2190f08c3bdfSopenharmony_ci } else if (token_type(token) == TOKEN_NUMBER) { 2191f08c3bdfSopenharmony_ci handler = handle_line; 2192f08c3bdfSopenharmony_ci } else { 2193f08c3bdfSopenharmony_ci handler = handle_nondirective; 2194f08c3bdfSopenharmony_ci } 2195f08c3bdfSopenharmony_ci 2196f08c3bdfSopenharmony_ci if (is_normal) { 2197f08c3bdfSopenharmony_ci dirty_stream(stream); 2198f08c3bdfSopenharmony_ci if (false_nesting) 2199f08c3bdfSopenharmony_ci goto out; 2200f08c3bdfSopenharmony_ci } 2201f08c3bdfSopenharmony_ci 2202f08c3bdfSopenharmony_ci if (expanding) { 2203f08c3bdfSopenharmony_ci if (!is_cond || Wpedantic) 2204f08c3bdfSopenharmony_ci warning(start->pos, "directive in macro's argument list"); 2205f08c3bdfSopenharmony_ci } 2206f08c3bdfSopenharmony_ci if (!handler(stream, line, token)) /* all set */ 2207f08c3bdfSopenharmony_ci return; 2208f08c3bdfSopenharmony_ci 2209f08c3bdfSopenharmony_ciout: 2210f08c3bdfSopenharmony_ci free_preprocessor_line(token); 2211f08c3bdfSopenharmony_ci} 2212f08c3bdfSopenharmony_ci 2213f08c3bdfSopenharmony_cistatic void preprocessor_line(struct stream *stream, struct token **line) 2214f08c3bdfSopenharmony_ci{ 2215f08c3bdfSopenharmony_ci struct token *start = *line, *next; 2216f08c3bdfSopenharmony_ci struct token **tp = &start->next; 2217f08c3bdfSopenharmony_ci 2218f08c3bdfSopenharmony_ci for (;;) { 2219f08c3bdfSopenharmony_ci next = *tp; 2220f08c3bdfSopenharmony_ci if (next->pos.newline) 2221f08c3bdfSopenharmony_ci break; 2222f08c3bdfSopenharmony_ci tp = &next->next; 2223f08c3bdfSopenharmony_ci } 2224f08c3bdfSopenharmony_ci *line = next; 2225f08c3bdfSopenharmony_ci *tp = &eof_token_entry; 2226f08c3bdfSopenharmony_ci handle_preprocessor_line(stream, line, start); 2227f08c3bdfSopenharmony_ci} 2228f08c3bdfSopenharmony_ci 2229f08c3bdfSopenharmony_cistatic void do_preprocess(struct token **list) 2230f08c3bdfSopenharmony_ci{ 2231f08c3bdfSopenharmony_ci struct token *next; 2232f08c3bdfSopenharmony_ci 2233f08c3bdfSopenharmony_ci while (!eof_token(next = scan_next(list))) { 2234f08c3bdfSopenharmony_ci struct stream *stream = input_streams + next->pos.stream; 2235f08c3bdfSopenharmony_ci 2236f08c3bdfSopenharmony_ci if (next->pos.newline && match_op(next, '#')) { 2237f08c3bdfSopenharmony_ci if (!next->pos.noexpand) { 2238f08c3bdfSopenharmony_ci preprocessor_line(stream, list); 2239f08c3bdfSopenharmony_ci __free_token(next); /* Free the '#' token */ 2240f08c3bdfSopenharmony_ci continue; 2241f08c3bdfSopenharmony_ci } 2242f08c3bdfSopenharmony_ci } 2243f08c3bdfSopenharmony_ci 2244f08c3bdfSopenharmony_ci switch (token_type(next)) { 2245f08c3bdfSopenharmony_ci case TOKEN_STREAMEND: 2246f08c3bdfSopenharmony_ci if (stream->top_if) { 2247f08c3bdfSopenharmony_ci nesting_error(stream); 2248f08c3bdfSopenharmony_ci sparse_error(stream->top_if->pos, "unterminated preprocessor conditional"); 2249f08c3bdfSopenharmony_ci stream->top_if = NULL; 2250f08c3bdfSopenharmony_ci false_nesting = 0; 2251f08c3bdfSopenharmony_ci } 2252f08c3bdfSopenharmony_ci if (!stream->dirty) 2253f08c3bdfSopenharmony_ci stream->constant = CONSTANT_FILE_YES; 2254f08c3bdfSopenharmony_ci *list = next->next; 2255f08c3bdfSopenharmony_ci include_level--; 2256f08c3bdfSopenharmony_ci continue; 2257f08c3bdfSopenharmony_ci case TOKEN_STREAMBEGIN: 2258f08c3bdfSopenharmony_ci *list = next->next; 2259f08c3bdfSopenharmony_ci include_level++; 2260f08c3bdfSopenharmony_ci continue; 2261f08c3bdfSopenharmony_ci 2262f08c3bdfSopenharmony_ci default: 2263f08c3bdfSopenharmony_ci dirty_stream(stream); 2264f08c3bdfSopenharmony_ci if (false_nesting) { 2265f08c3bdfSopenharmony_ci *list = next->next; 2266f08c3bdfSopenharmony_ci __free_token(next); 2267f08c3bdfSopenharmony_ci continue; 2268f08c3bdfSopenharmony_ci } 2269f08c3bdfSopenharmony_ci 2270f08c3bdfSopenharmony_ci if (token_type(next) != TOKEN_IDENT || 2271f08c3bdfSopenharmony_ci expand_one_symbol(list)) 2272f08c3bdfSopenharmony_ci list = &next->next; 2273f08c3bdfSopenharmony_ci } 2274f08c3bdfSopenharmony_ci } 2275f08c3bdfSopenharmony_ci} 2276f08c3bdfSopenharmony_ci 2277f08c3bdfSopenharmony_cistruct token * preprocess(struct token *token) 2278f08c3bdfSopenharmony_ci{ 2279f08c3bdfSopenharmony_ci preprocessing = 1; 2280f08c3bdfSopenharmony_ci init_preprocessor(); 2281f08c3bdfSopenharmony_ci do_preprocess(&token); 2282f08c3bdfSopenharmony_ci 2283f08c3bdfSopenharmony_ci // Drop all expressions from preprocessing, they're not used any more. 2284f08c3bdfSopenharmony_ci // This is not true when we have multiple files, though ;/ 2285f08c3bdfSopenharmony_ci // clear_expression_alloc(); 2286f08c3bdfSopenharmony_ci preprocessing = 0; 2287f08c3bdfSopenharmony_ci 2288f08c3bdfSopenharmony_ci return token; 2289f08c3bdfSopenharmony_ci} 2290f08c3bdfSopenharmony_ci 2291f08c3bdfSopenharmony_cistatic int is_VA_ARGS_token(struct token *token) 2292f08c3bdfSopenharmony_ci{ 2293f08c3bdfSopenharmony_ci return (token_type(token) == TOKEN_IDENT) && 2294f08c3bdfSopenharmony_ci (token->ident == &__VA_ARGS___ident); 2295f08c3bdfSopenharmony_ci} 2296f08c3bdfSopenharmony_ci 2297f08c3bdfSopenharmony_cistatic void dump_macro(struct symbol *sym) 2298f08c3bdfSopenharmony_ci{ 2299f08c3bdfSopenharmony_ci int nargs = sym->arglist ? sym->arglist->count.normal : 0; 2300f08c3bdfSopenharmony_ci struct token *args[nargs]; 2301f08c3bdfSopenharmony_ci struct token *token; 2302f08c3bdfSopenharmony_ci 2303f08c3bdfSopenharmony_ci printf("#define %s", show_ident(sym->ident)); 2304f08c3bdfSopenharmony_ci token = sym->arglist; 2305f08c3bdfSopenharmony_ci if (token) { 2306f08c3bdfSopenharmony_ci const char *sep = ""; 2307f08c3bdfSopenharmony_ci int narg = 0; 2308f08c3bdfSopenharmony_ci putchar('('); 2309f08c3bdfSopenharmony_ci for (; !eof_token(token); token = token->next) { 2310f08c3bdfSopenharmony_ci if (token_type(token) == TOKEN_ARG_COUNT) 2311f08c3bdfSopenharmony_ci continue; 2312f08c3bdfSopenharmony_ci if (is_VA_ARGS_token(token)) 2313f08c3bdfSopenharmony_ci printf("%s...", sep); 2314f08c3bdfSopenharmony_ci else 2315f08c3bdfSopenharmony_ci printf("%s%s", sep, show_token(token)); 2316f08c3bdfSopenharmony_ci args[narg++] = token; 2317f08c3bdfSopenharmony_ci sep = ","; 2318f08c3bdfSopenharmony_ci } 2319f08c3bdfSopenharmony_ci putchar(')'); 2320f08c3bdfSopenharmony_ci } 2321f08c3bdfSopenharmony_ci 2322f08c3bdfSopenharmony_ci token = sym->expansion; 2323f08c3bdfSopenharmony_ci while (token_type(token) != TOKEN_UNTAINT) { 2324f08c3bdfSopenharmony_ci struct token *next = token->next; 2325f08c3bdfSopenharmony_ci if (token->pos.whitespace) 2326f08c3bdfSopenharmony_ci putchar(' '); 2327f08c3bdfSopenharmony_ci switch (token_type(token)) { 2328f08c3bdfSopenharmony_ci case TOKEN_CONCAT: 2329f08c3bdfSopenharmony_ci printf("##"); 2330f08c3bdfSopenharmony_ci break; 2331f08c3bdfSopenharmony_ci case TOKEN_STR_ARGUMENT: 2332f08c3bdfSopenharmony_ci printf("#"); 2333f08c3bdfSopenharmony_ci /* fall-through */ 2334f08c3bdfSopenharmony_ci case TOKEN_QUOTED_ARGUMENT: 2335f08c3bdfSopenharmony_ci case TOKEN_MACRO_ARGUMENT: 2336f08c3bdfSopenharmony_ci token = args[token->argnum]; 2337f08c3bdfSopenharmony_ci /* fall-through */ 2338f08c3bdfSopenharmony_ci default: 2339f08c3bdfSopenharmony_ci printf("%s", show_token(token)); 2340f08c3bdfSopenharmony_ci } 2341f08c3bdfSopenharmony_ci token = next; 2342f08c3bdfSopenharmony_ci } 2343f08c3bdfSopenharmony_ci putchar('\n'); 2344f08c3bdfSopenharmony_ci} 2345f08c3bdfSopenharmony_ci 2346f08c3bdfSopenharmony_civoid dump_macro_definitions(void) 2347f08c3bdfSopenharmony_ci{ 2348f08c3bdfSopenharmony_ci struct ident *name; 2349f08c3bdfSopenharmony_ci 2350f08c3bdfSopenharmony_ci FOR_EACH_PTR(macros, name) { 2351f08c3bdfSopenharmony_ci struct symbol *sym = lookup_macro(name); 2352f08c3bdfSopenharmony_ci if (sym) 2353f08c3bdfSopenharmony_ci dump_macro(sym); 2354f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(name); 2355f08c3bdfSopenharmony_ci} 2356