Oops. The argument symbol initializers got lost on inlining,
[smatch.git] / pre-process.c
blob1eda9688baa086c7a9544342fbaf6e6b5bce5c19
1 /*
2 * Do C preprocessing, based on a token list gathered by
3 * the tokenizer.
5 * This may not be the smartest preprocessor on the planet.
7 * Copyright (C) 2003 Transmeta Corp.
9 * Licensed under the Open Software License version 1.1
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <stdarg.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <limits.h>
21 #include "pre-process.h"
22 #include "lib.h"
23 #include "parse.h"
24 #include "token.h"
25 #include "symbol.h"
26 #include "expression.h"
28 int verbose = 0;
29 int preprocessing = 0;
31 #define MAX_NEST (256)
32 static int true_nesting = 0;
33 static int false_nesting = 0;
34 static struct token *unmatched_if = NULL;
35 static char elif_ignore[MAX_NEST];
36 #define if_nesting (true_nesting + false_nesting)
38 #define INCLUDEPATHS 32
39 const char *includepath[INCLUDEPATHS+1] = {
40 NULL
43 const char *sys_includepath[] = {
44 "/usr/include",
45 "/usr/local/include",
46 NULL,
49 const char *gcc_includepath[] = {
50 GCC_INTERNAL_INCLUDE,
51 NULL
56 * This is stupid - the tokenizer already guarantees unique
57 * identifiers, so we should just compare identifier pointers
59 int match_string_ident(struct ident *ident, const char *str)
61 return !str[ident->len] && !memcmp(str, ident->name, ident->len);
64 static struct token *alloc_token(struct position *pos)
66 struct token *token = __alloc_token(0);
68 token->pos.stream = pos->stream;
69 token->pos.line = pos->line;
70 token->pos.pos = pos->pos;
71 token->pos.whitespace = 1;
72 return token;
75 static const char *show_token_sequence(struct token *token);
77 /* Head is one-before-list, and last is one-past-list */
78 static struct token *for_each_ident(struct token *parent, struct token *head, struct token *(*action)(struct token *parent, struct token *head, struct token *))
80 for (;;) {
81 struct token *next = head->next;
83 /* Did we hit the end of the current expansion? */
84 if (eof_token(next))
85 break;
87 if (token_type(next) == TOKEN_IDENT)
88 next = action(parent, head, next);
90 head = next;
92 return head;
95 static struct token *is_defined(struct token *head, struct token *token, struct token *next)
97 char *string[] = { "0", "1" };
98 char *defined = string[lookup_symbol(token->ident, NS_PREPROCESSOR) != NULL];
99 struct token *newtoken = alloc_token(&token->pos);
101 token_type(newtoken) = TOKEN_INTEGER;
102 newtoken->integer = defined;
103 newtoken->next = next;
104 head->next = newtoken;
105 return next;
109 struct token *defined_one_symbol(struct token *head, struct token *next)
111 struct token *token = next->next;
112 struct token *past = token->next;
114 if (match_op(token, '(')) {
115 token = past;
116 past = token->next;
117 if (!match_op(past, ')'))
118 return next;
119 past = past->next;
121 if (token_type(token) == TOKEN_IDENT)
122 return is_defined(head, token, past);
123 return next;
126 /* Expand symbol 'sym' between 'head->next' and 'head->next->next' */
127 static struct token *expand(struct token *, struct token *, struct symbol *);
129 static void replace_with_string(struct token *token, const char *str)
131 int size = strlen(str) + 1;
132 struct string *s = __alloc_string(size);
134 s->length = size;
135 memcpy(s->data, str, size);
136 token_type(token) = TOKEN_STRING;
137 token->string = s;
140 static void replace_with_integer(struct token *token, unsigned int val)
142 char *buf = __alloc_bytes(10);
143 sprintf(buf, "%d", val);
144 token_type(token) = TOKEN_INTEGER;
145 token->integer = buf;
148 struct token *expand_one_symbol(struct token *parent, struct token *head, struct token *token)
150 struct symbol *sym;
151 struct token *x;
153 /* Avoid recursive expansion */
154 x = token;
155 while ((x = x->parent) != NULL) {
156 if (parent && x->ident == parent->ident)
157 return token;
158 if (x->ident == token->ident)
159 return token;
162 sym = lookup_symbol(token->ident, NS_PREPROCESSOR);
163 if (sym) {
164 if (sym->arglist && !match_op(token->next, '('))
165 return token;
166 return expand(token, head, sym);
168 if (!memcmp(token->ident->name, "__LINE__", 9)) {
169 replace_with_integer(token, token->pos.line);
170 } else if (!memcmp(token->ident->name, "__FILE__", 9)) {
171 replace_with_string(token, (input_streams + token->pos.stream)->name);
172 } else if (!memcmp(token->ident->name, "defined", 8)) {
173 return defined_one_symbol(head, token);
175 return token;
178 static struct token *expand_list(struct token *parent, struct token *head)
180 return for_each_ident(parent, head, expand_one_symbol);
183 static struct token *find_argument_end(struct token *start)
185 int nesting = 0;
187 while (!eof_token(start)) {
188 struct token *next = start->next;
189 if (match_op(next, '('))
190 nesting++;
191 else if (match_op(next, ')')) {
192 if (--nesting < 0) {
193 start->next = &eof_token_entry;
194 return next->next;
196 } else if (!nesting && match_op(next, ','))
197 next->special = SPECIAL_ARG_SEPARATOR;
198 start = next;
200 return start;
203 static struct token *dup_token(struct token *token, struct position *pos, int newline)
205 struct token *alloc = alloc_token(pos);
206 token_type(alloc) = token_type(token);
207 alloc->pos.line = pos->line;
208 alloc->pos.newline = newline;
209 alloc->integer = token->integer;
210 return alloc;
213 static void insert(struct token *token, struct token *prev)
215 token->next = prev->next;
216 prev->next = token;
219 static struct token * replace(struct token *parent, struct token *token, struct token *prev, struct token *list)
221 int newline = token->pos.newline;
223 prev->next = token->next;
224 while (!eof_token(list) && !match_op(list, SPECIAL_ARG_SEPARATOR)) {
225 struct token *newtok = dup_token(list, &token->pos, newline);
226 newtok->parent = parent;
227 newline = 0;
228 insert(newtok, prev);
229 prev = newtok;
230 list = list->next;
232 return prev;
235 static struct token *get_argument(int nr, struct token *args)
237 if (!nr)
238 return args;
239 while (!eof_token(args)) {
240 if (match_op(args, SPECIAL_ARG_SEPARATOR))
241 if (!--nr)
242 return args->next;
243 args = args->next;
246 return args;
249 static struct token *stringify(struct token *token, struct token *arg)
251 const char *s = show_token_sequence(arg);
252 int size = strlen(s)+1;
253 struct token *newtoken = alloc_token(&token->pos);
254 struct string *string = __alloc_string(size);
256 newtoken->pos.newline = token->pos.newline;
257 memcpy(string->data, s, size);
258 string->length = size;
259 token_type(newtoken) = TOKEN_STRING;
260 newtoken->string = string;
261 newtoken->next = &eof_token_entry;
262 return newtoken;
265 static int arg_number(struct token *arglist, struct ident *ident)
267 int nr = 0;
269 while (!eof_token(arglist)) {
270 if (arglist->ident == ident)
271 return nr;
272 nr++;
273 arglist = arglist->next;
275 return -1;
278 static struct token empty_arg_token = { .pos = { .type = TOKEN_EOF } };
280 static struct token *expand_one_arg(struct token *parent, struct token *head, struct token *token,
281 struct token *arglist, struct token *arguments)
283 int nr = arg_number(arglist, token->ident);
284 struct token *orig_head = head;
286 if (nr >= 0) {
287 struct token *arg = get_argument(nr, arguments);
288 struct token *last = token->next;
289 token->next = &eof_token_entry;
292 * Special case for gcc 'x ## arg' semantics: if 'arg' is empty
293 * then the 'x' goes away too.
295 if (match_op(head, SPECIAL_HASHHASH) && eof_token(arg)) {
296 arg = &empty_arg_token;
297 empty_arg_token.next = &eof_token_entry;
300 head = replace(NULL, token, head, arg);
301 if (!match_op(orig_head, SPECIAL_HASHHASH) && !match_op(last, SPECIAL_HASHHASH) && !match_op(orig_head, '#'))
302 head = expand_list(parent, orig_head);
303 head->next = last;
304 return head;
306 return token;
309 static void expand_arguments(struct token *parent,
310 struct token *token, struct token *head,
311 struct token *arguments, struct token *arglist)
313 for (;;) {
314 struct token *next = head->next;
316 /* Did we hit the end of the current expansion? */
317 if (eof_token(next))
318 break;
320 if (match_op(next, '#')) {
321 struct token *nextnext = next->next;
322 int nr = arg_number(arglist, nextnext->ident);
323 if (nextnext != head && nr >= 0 && token_type(nextnext) == TOKEN_IDENT) {
324 struct token *newtoken = stringify(nextnext, get_argument(nr, arguments));
325 replace(NULL, nextnext, head, newtoken);
326 continue;
328 warn(next->pos, "'#' operation is not followed by argument name");
331 if (token_type(next) == TOKEN_IDENT)
332 next = expand_one_arg(parent, head, next, arglist, arguments);
334 head = next;
339 * Possibly valid combinations:
340 * - anything + 'empty_arg_token' is empty.
341 * - ident + ident - combine (==ident)
342 * - ident + number - combine (==ident)
343 * - number + number - combine (==number)
344 * - number + ident - combine (==number)
345 * - string + string - leave as is, C will combine them anyway
346 * others cause an error and leave the two tokens as separate tokens.
348 static struct token *hashhash(struct token *head, struct token *first, struct token *second)
350 static char buffer[512], *p;
351 struct token *newtoken;
352 static const char *src;
353 int len;
355 first->next = second;
358 * Special case for gcc 'x ## arg' semantics: if 'arg' is empty
359 * then the 'x' goes away too.
361 * See expand_one_arg.
363 if (token_type(second) == TOKEN_EOF) {
364 head->next = second->next;
365 return head;
368 p = buffer;
369 switch (token_type(first)) {
370 case TOKEN_INTEGER:
371 len = strlen(first->integer);
372 src = first->integer;
373 break;
374 case TOKEN_IDENT:
375 len = first->ident->len;
376 src = first->ident->name;
377 break;
378 default:
379 return second;
381 memcpy(p, src, len);
382 p += len;
384 switch (token_type(second)) {
385 case TOKEN_INTEGER:
386 len = strlen(second->integer);
387 src = second->integer;
388 break;
389 case TOKEN_IDENT:
390 len = second->ident->len;
391 src = second->ident->name;
392 break;
393 default:
394 return second;
396 memcpy(p, src, len);
397 p += len;
398 *p++ = 0;
400 newtoken = alloc_token(&first->pos);
401 head->next = newtoken;
402 token_type(newtoken) = token_type(first);
403 switch (token_type(newtoken)) {
404 case TOKEN_IDENT:
405 newtoken->ident = built_in_ident(buffer);
406 break;
407 case TOKEN_INTEGER:
408 newtoken->integer = __alloc_bytes(p - buffer);
409 memcpy(newtoken->integer, buffer, p - buffer);
410 break;
412 return newtoken;
415 static void retokenize(struct token *head)
417 struct token * next = head->next;
418 struct token * nextnext = next->next;
419 struct token * nextnextnext = nextnext->next;
421 if (eof_token(next) || eof_token(nextnext))
422 return;
424 for (;;) {
425 if (eof_token(nextnextnext))
426 break;
428 if (match_op(nextnext, SPECIAL_HASHHASH)) {
429 struct token *newtoken = hashhash(head, next, nextnextnext);
431 next = newtoken;
432 nextnext = nextnextnext->next;
433 nextnextnext = nextnext->next;
435 newtoken->next = nextnext;
436 if (!eof_token(nextnext))
437 continue;
438 break;
441 head = next;
442 next = nextnext;
443 nextnext = nextnext->next;
444 nextnextnext = nextnextnext->next;
448 static struct token *expand(struct token *parent, struct token *head, struct symbol *sym)
450 struct token *arguments, *token, *last;
452 token = head->next;
453 last = token->next;
455 arguments = NULL;
456 if (sym->arglist) {
457 arguments = last->next;
458 last = find_argument_end(last);
460 token->next = &eof_token_entry;
462 /* Replace the token with the token expansion */
463 replace(parent, token, head, sym->expansion);
465 /* Then, replace all the arguments with their expansions */
466 if (arguments)
467 expand_arguments(parent, token, head, arguments, sym->arglist);
469 /* Re-tokenize the sequence if any ## token exists.. */
470 retokenize(head);
472 token = head;
473 while (!eof_token(token->next))
474 token = token->next;
475 token->next = last;
476 return head;
479 static const char *token_name_sequence(struct token *token, int endop, struct token *start)
481 struct token *last;
482 static char buffer[256];
483 char *ptr = buffer;
485 last = token;
486 while (!eof_token(token) && !match_op(token, endop)) {
487 int len;
488 const char *val = token->string->data;
489 if (token_type(token) != TOKEN_STRING)
490 val = show_token(token);
491 len = strlen(val);
492 memcpy(ptr, val, len);
493 ptr += len;
494 token = token->next;
496 *ptr = 0;
497 if (endop && !match_op(token, endop))
498 warn(start->pos, "expected '>' at end of filename");
499 return buffer;
502 static int try_include(const char *path, int plen, const char *filename, int flen, struct token *head)
504 int fd;
505 static char fullname[PATH_MAX];
507 memcpy(fullname, path, plen);
508 if (plen && path[plen-1] != '/') {
509 fullname[plen] = '/';
510 plen++;
512 memcpy(fullname+plen, filename, flen);
513 fd = open(fullname, O_RDONLY);
514 if (fd >= 0) {
515 char * streamname = __alloc_bytes(plen + flen);
516 memcpy(streamname, fullname, plen + flen);
517 head->next = tokenize(streamname, fd, head->next);
518 close(fd);
519 return 1;
521 return 0;
524 static int do_include_path(const char **pptr, struct token *head, struct token *token, const char *filename, int flen)
526 const char *path;
528 while ((path = *pptr++) != NULL) {
529 if (!try_include(path, strlen(path), filename, flen, head))
530 continue;
531 return 1;
533 return 0;
537 static void do_include(int local, struct stream *stream, struct token *head, struct token *token, const char *filename)
539 int flen = strlen(filename) + 1;
541 /* Same directory as current stream? */
542 if (local) {
543 const char *path;
544 char *slash;
545 int plen;
547 path = stream->name;
548 slash = strrchr(path, '/');
549 plen = slash ? slash - path : 0;
551 if (try_include(path, plen, filename, flen, head))
552 return;
555 /* Check the standard include paths.. */
556 if (do_include_path(includepath, head, token, filename, flen))
557 return;
558 if (do_include_path(sys_includepath, head, token, filename, flen))
559 return;
560 if (do_include_path(gcc_includepath, head, token, filename, flen))
561 return;
563 error(token->pos, "unable to open '%s'", filename);
566 static int handle_include(struct stream *stream, struct token *head, struct token *token)
568 const char *filename;
569 struct token *next;
570 int expect;
572 if (stream->constant == -1)
573 stream->constant = 0;
574 if (false_nesting)
575 return 1;
576 next = token->next;
577 expect = '>';
578 if (!match_op(next, '<')) {
579 expand_list(NULL, token);
580 expect = 0;
581 next = token;
583 token = next->next;
584 filename = token_name_sequence(token, expect, token);
585 do_include(!expect, stream, head, token, filename);
586 return 1;
589 static int token_list_different(struct token *list1, struct token *list2)
591 for (;;) {
592 if (list1 == list2)
593 return 0;
594 if (!list1 || !list2)
595 return 1;
596 if (token_type(list1) != token_type(list2))
597 return 1;
598 list1 = list1->next;
599 list2 = list2->next;
604 static int handle_define(struct stream *stream, struct token *head, struct token *token)
606 struct token *arglist, *expansion;
607 struct token *left = token->next;
608 struct symbol *sym;
609 struct ident *name;
611 if (token_type(left) != TOKEN_IDENT) {
612 warn(head->pos, "expected identifier to 'define'");
613 return 0;
615 if (false_nesting)
616 return 1;
617 name = left->ident;
619 arglist = NULL;
620 expansion = left->next;
621 if (!expansion->pos.whitespace && match_op(expansion, '(')) {
622 arglist = expansion;
623 while (!eof_token(expansion)) {
624 struct token *next = expansion->next;
625 if (match_op(next, ')')) {
626 // Terminate the arglist
627 expansion->next = &eof_token_entry;
628 expansion = next->next;
629 break;
631 if (match_op(next, ','))
632 expansion->next = next->next;
633 expansion = next;
635 arglist = arglist->next;
638 sym = lookup_symbol(name, NS_PREPROCESSOR);
639 if (sym) {
640 if (token_list_different(sym->expansion, expansion) ||
641 token_list_different(sym->arglist, arglist)) {
642 warn(left->pos, "preprocessor token redefined");
643 warn(sym->pos, "this was the original definition");
645 return 1;
647 sym = alloc_symbol(left->pos, SYM_NODE);
648 bind_symbol(sym, name, NS_PREPROCESSOR);
650 sym->expansion = expansion;
651 sym->arglist = arglist;
652 return 1;
655 static int handle_undef(struct stream *stream, struct token *head, struct token *token)
657 struct token *left = token->next;
658 struct symbol **sym;
660 if (token_type(left) != TOKEN_IDENT) {
661 warn(head->pos, "expected identifier to 'undef'");
662 return 0;
664 if (false_nesting)
665 return 1;
666 sym = &left->ident->symbols;
667 while (*sym) {
668 struct symbol *t = *sym;
669 if (t->namespace == NS_PREPROCESSOR) {
670 *sym = t->next_id;
671 return 1;
673 sym = &t->next_id;
675 return 1;
678 static int preprocessor_if(struct token *token, int true)
680 if (if_nesting == 0)
681 unmatched_if = token;
682 if (if_nesting >= MAX_NEST)
683 error(token->pos, "Maximum preprocessor conditional level exhausted");
684 elif_ignore[if_nesting] = false_nesting || true;
685 if (false_nesting || !true) {
686 false_nesting++;
687 return 1;
689 true_nesting++;
690 return 1;
693 static int token_defined(struct token *token)
695 if (token_type(token) == TOKEN_IDENT)
696 return lookup_symbol(token->ident, NS_PREPROCESSOR) != NULL;
698 warn(token->pos, "expected identifier for #if[n]def");
699 return 0;
702 static int handle_ifdef(struct stream *stream, struct token *head, struct token *token)
704 return preprocessor_if(token, token_defined(token->next));
707 static int handle_ifndef(struct stream *stream, struct token *head, struct token *token)
709 struct token *next = token->next;
710 if (stream->constant == -1) {
711 int newconstant = 0;
712 if (token_type(next) == TOKEN_IDENT) {
713 if (!stream->protect || stream->protect == next->ident) {
714 newconstant = -2;
715 stream->protect = next->ident;
716 stream->nesting = if_nesting+1;
719 stream->constant = newconstant;
721 return preprocessor_if(token, !token_defined(next));
724 static int expression_value(struct token *head)
726 struct expression *expr;
727 struct token *token;
728 long long value;
730 expand_list(NULL, head);
731 token = constant_expression(head->next, &expr);
732 if (!eof_token(token))
733 warn(token->pos, "garbage at end: %s", show_token_sequence(token));
734 value = get_expression_value(expr);
735 return value != 0;
738 static int handle_if(struct stream *stream, struct token *head, struct token *token)
740 int value = 0;
741 if (!false_nesting)
742 value = expression_value(token);
743 return preprocessor_if(token, value);
746 static int handle_elif(struct stream * stream, struct token *head, struct token *token)
748 if (stream->nesting == if_nesting)
749 stream->constant = 0;
750 if (false_nesting) {
751 /* If this whole if-thing is if'ed out, an elif cannot help */
752 if (elif_ignore[if_nesting-1])
753 return 1;
754 if (expression_value(token)) {
755 false_nesting--;
756 true_nesting++;
757 elif_ignore[if_nesting-1] = 1;
759 return 1;
761 if (true_nesting) {
762 false_nesting = 1;
763 true_nesting--;
764 return 1;
766 warn(token->pos, "unmatched '#elif'");
767 return 1;
770 static int handle_else(struct stream *stream, struct token *head, struct token *token)
772 if (stream->nesting == if_nesting)
773 stream->constant = 0;
774 if (false_nesting) {
775 /* If this whole if-thing is if'ed out, an else cannot help */
776 if (elif_ignore[if_nesting-1])
777 return 1;
778 false_nesting--;
779 true_nesting++;
780 elif_ignore[if_nesting-1] = 1;
781 return 1;
783 if (true_nesting) {
784 true_nesting--;
785 false_nesting = 1;
786 return 1;
788 warn(token->pos, "unmatched #else");
789 return 1;
792 static int handle_endif(struct stream *stream, struct token *head, struct token *token)
794 if (stream->constant == -2 && stream->nesting == if_nesting)
795 stream->constant = -1;
797 if (false_nesting) {
798 false_nesting--;
799 return 1;
801 if (true_nesting) {
802 true_nesting--;
803 return 1;
805 warn(token->pos, "unmatched #endif");
806 return 1;
809 static const char *show_token_sequence(struct token *token)
811 static char buffer[256];
812 char *ptr = buffer;
813 int whitespace = 0;
815 if (!token)
816 return "<none>";
817 while (!eof_token(token) && !match_op(token, SPECIAL_ARG_SEPARATOR)) {
818 const char *val = show_token(token);
819 int len = strlen(val);
820 if (whitespace)
821 *ptr++ = ' ';
822 memcpy(ptr, val, len);
823 ptr += len;
824 token = token->next;
825 whitespace = token->pos.whitespace;
827 *ptr = 0;
828 return buffer;
831 static int handle_warning(struct stream *stream, struct token *head, struct token *token)
833 if (false_nesting)
834 return 1;
835 warn(token->pos, "%s", show_token_sequence(token->next));
836 return 1;
839 static int handle_error(struct stream *stream, struct token *head, struct token *token)
841 if (false_nesting)
842 return 1;
843 warn(token->pos, "%s", show_token_sequence(token->next));
844 return 1;
847 static int handle_nostdinc(struct stream *stream, struct token *head, struct token *token)
849 if (false_nesting)
850 return 1;
851 includepath[0] = NULL;
852 return 1;
855 static void add_path_entry(struct token *token, const char *path)
857 int i;
859 for (i = 0; i < INCLUDEPATHS; i++) {
860 if (!includepath[i]) {
861 includepath[i] = path;
862 includepath[i+1] = NULL;
863 return;
866 warn(token->pos, "too many include path entries");
869 static int handle_add_include(struct stream *stream, struct token *head, struct token *token)
871 for (;;) {
872 token = token->next;
873 if (eof_token(token))
874 return 1;
875 if (token_type(token) != TOKEN_STRING) {
876 warn(token->pos, "expected path string");
877 return 1;
879 add_path_entry(token, token->string->data);
884 * We replace "#pragma xxx" with "__pragma__" in the token
885 * stream. Just as an example.
887 * We'll just #define that away for now, but the theory here
888 * is that we can use this to insert arbitrary token sequences
889 * to turn the pragma's into internal front-end sequences for
890 * when we actually start caring about them.
892 * So eventually this will turn into some kind of extended
893 * __attribute__() like thing, except called __pragma__(xxx).
895 static int handle_pragma(struct stream *stream, struct token *head, struct token *token)
897 struct token *next = head->next;
899 token->ident = &pragma_ident;
900 token->pos.newline = 1;
901 token->pos.whitespace = 1;
902 token->pos.pos = 1;
903 head->next = token;
904 token->next = next;
905 return 1;
908 static int handle_preprocessor_command(struct stream *stream, struct token *head, struct ident *ident, struct token *token)
910 int i;
911 static struct {
912 const char *name;
913 int (*handler)(struct stream *, struct token *, struct token *);
914 } handlers[] = {
915 { "define", handle_define },
916 { "undef", handle_undef },
917 { "ifdef", handle_ifdef },
918 { "ifndef", handle_ifndef },
919 { "else", handle_else },
920 { "endif", handle_endif },
921 { "if", handle_if },
922 { "elif", handle_elif },
923 { "warning", handle_warning },
924 { "error", handle_error },
925 { "include", handle_include },
926 { "pragma", handle_pragma },
928 // our internal preprocessor tokens
929 { "nostdinc", handle_nostdinc },
930 { "add_include", handle_add_include },
933 for (i = 0; i < (sizeof (handlers) / sizeof (handlers[0])); i++) {
934 if (match_string_ident(ident, handlers[i].name))
935 return handlers[i].handler(stream, head, token);
937 return 0;
940 static void handle_preprocessor_line(struct stream *stream, struct token * head, struct token *token)
942 if (!token)
943 return;
945 if (token_type(token) == TOKEN_IDENT)
946 if (handle_preprocessor_command(stream, head, token->ident, token))
947 return;
948 warn(token->pos, "unrecognized preprocessor line '%s'", show_token_sequence(token));
951 static void preprocessor_line(struct stream *stream, struct token * head)
953 struct token *start = head->next, *next;
954 struct token **tp = &start->next;
956 for (;;) {
957 next = *tp;
958 if (next->pos.newline)
959 break;
960 tp = &next->next;
962 head->next = next;
963 *tp = &eof_token_entry;
964 handle_preprocessor_line(stream, head, start->next);
967 static void do_preprocess(struct token *head)
969 do {
970 struct token *next = head->next;
971 struct stream *stream = input_streams + next->pos.stream;
973 if (next->pos.newline && match_op(next, '#')) {
974 preprocessor_line(stream, head);
975 continue;
978 if (false_nesting) {
979 head->next = next->next;
980 continue;
983 switch (token_type(next)) {
984 case TOKEN_STREAMEND:
985 if (stream->constant == -1 && stream->protect) {
986 stream->constant = 1;
988 /* fallthrough */
989 case TOKEN_STREAMBEGIN:
990 head->next = next->next;
991 continue;
993 case TOKEN_IDENT:
994 next = expand_one_symbol(next, head, next);
995 /* fallthrough */
996 default:
998 * Any token expansion (even if it ended up being an
999 * empty expansion) in this stream implies it can't
1000 * be constant.
1002 stream->constant = 0;
1005 head = next;
1006 } while (!eof_token(head));
1009 struct token * preprocess(struct token *token)
1011 struct token header = { };
1013 preprocessing = 1;
1014 header.next = token;
1015 do_preprocess(&header);
1016 if (if_nesting)
1017 warn(unmatched_if->pos, "unmatched preprocessor conditional");
1019 // Drop all expressions from pre-processing, they're not used any more.
1020 clear_expression_alloc();
1021 preprocessing = 0;
1023 return header.next;