tccpp_new/delete and other cleanups
[tinycc.git] / tccpp.c
blobb75603fc5eeda5f360602abc4763f2b26f580cc3
1 /*
2 * TCC - Tiny C Compiler
3 *
4 * Copyright (c) 2001-2004 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "tcc.h"
23 /********************************************************/
24 /* global variables */
26 ST_DATA int tok_flags;
27 ST_DATA int parse_flags;
29 ST_DATA struct BufferedFile *file;
30 ST_DATA int ch, tok;
31 ST_DATA CValue tokc;
32 ST_DATA const int *macro_ptr;
33 ST_DATA CString tokcstr; /* current parsed string, if any */
35 /* display benchmark infos */
36 ST_DATA int total_lines;
37 ST_DATA int total_bytes;
38 ST_DATA int tok_ident;
39 ST_DATA TokenSym **table_ident;
41 /* ------------------------------------------------------------------------- */
43 static TokenSym *hash_ident[TOK_HASH_SIZE];
44 static char token_buf[STRING_MAX_SIZE + 1];
45 static CString cstr_buf;
46 static TokenString tokstr_buf;
47 static unsigned char isidnum_table[256 - CH_EOF];
48 static int pp_debug_tok, pp_debug_symv;
49 static int pp_once;
50 static void tok_print(const char *msg, const int *str);
52 static struct TinyAlloc *toksym_alloc;
53 static struct TinyAlloc *tokstr_alloc;
54 static struct TinyAlloc *cstr_alloc;
56 /* isidnum_table flags: */
57 #define IS_SPC 1
58 #define IS_ID 2
59 #define IS_NUM 4
61 static TokenString *macro_stack;
63 static const char tcc_keywords[] =
64 #define DEF(id, str) str "\0"
65 #include "tcctok.h"
66 #undef DEF
69 /* WARNING: the content of this string encodes token numbers */
70 static const unsigned char tok_two_chars[] =
71 /* outdated -- gr
72 "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253"
73 "-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266";
74 */{
75 '<','=', TOK_LE,
76 '>','=', TOK_GE,
77 '!','=', TOK_NE,
78 '&','&', TOK_LAND,
79 '|','|', TOK_LOR,
80 '+','+', TOK_INC,
81 '-','-', TOK_DEC,
82 '=','=', TOK_EQ,
83 '<','<', TOK_SHL,
84 '>','>', TOK_SAR,
85 '+','=', TOK_A_ADD,
86 '-','=', TOK_A_SUB,
87 '*','=', TOK_A_MUL,
88 '/','=', TOK_A_DIV,
89 '%','=', TOK_A_MOD,
90 '&','=', TOK_A_AND,
91 '^','=', TOK_A_XOR,
92 '|','=', TOK_A_OR,
93 '-','>', TOK_ARROW,
94 '.','.', 0xa8, // C++ token ?
95 '#','#', TOK_TWOSHARPS,
99 static void next_nomacro_spc(void);
101 ST_FUNC void skip(int c)
103 if (tok != c)
104 tcc_error("'%c' expected (got \"%s\")", c, get_tok_str(tok, &tokc));
105 next();
108 ST_FUNC void expect(const char *msg)
110 tcc_error("%s expected", msg);
113 /* ------------------------------------------------------------------------- */
114 /* Custom allocator for tiny objects */
116 #define USE_TAL
118 #ifndef USE_TAL
119 #define tal_free(al, p) tcc_free(p)
120 #define tal_realloc(al, p, size) tcc_realloc(p, size)
121 #define tal_new(a,b,c)
122 #define tal_delete(a)
123 #else
124 #if !defined(MEM_DEBUG)
125 #define tal_free(al, p) tal_free_impl(al, p)
126 #define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size)
127 #define TAL_DEBUG_PARAMS
128 #else
129 #define TAL_DEBUG 1
130 //#define TAL_INFO 1 /* collect and dump allocators stats */
131 #define tal_free(al, p) tal_free_impl(al, p, __FILE__, __LINE__)
132 #define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size, __FILE__, __LINE__)
133 #define TAL_DEBUG_PARAMS , const char *file, int line
134 #define TAL_DEBUG_FILE_LEN 15
135 #endif
137 #define TOKSYM_TAL_SIZE (768 * 1024) /* allocator for tiny TokenSym in table_ident */
138 #define TOKSTR_TAL_SIZE (768 * 1024) /* allocator for tiny TokenString instances */
139 #define CSTR_TAL_SIZE (256 * 1024) /* allocator for tiny CString instances */
140 #define TOKSYM_TAL_LIMIT 256 /* prefer unique limits to distinguish allocators debug msgs */
141 #define TOKSTR_TAL_LIMIT 128 /* 32 * sizeof(int) */
142 #define CSTR_TAL_LIMIT 1024
144 typedef struct TinyAlloc {
145 size_t limit;
146 size_t size;
147 uint8_t *buffer;
148 uint8_t *p;
149 size_t nb_allocs;
150 struct TinyAlloc *next, *top;
151 #ifdef TAL_INFO
152 size_t nb_peak;
153 size_t nb_total;
154 size_t nb_missed;
155 uint8_t *peak_p;
156 #endif
157 } TinyAlloc;
159 typedef struct tal_header_t {
160 size_t size;
161 #ifdef TAL_DEBUG
162 int line_num; /* negative line_num used for double free check */
163 char file_name[TAL_DEBUG_FILE_LEN + 1];
164 #endif
165 } tal_header_t;
167 /* ------------------------------------------------------------------------- */
169 ST_FUNC TinyAlloc *tal_new(TinyAlloc **pal, size_t limit, size_t size)
171 TinyAlloc *al = tcc_mallocz(sizeof(TinyAlloc));
172 al->p = al->buffer = tcc_malloc(size);
173 al->limit = limit;
174 al->size = size;
175 if (pal) *pal = al;
176 return al;
179 ST_FUNC void tal_delete(TinyAlloc *al)
181 TinyAlloc *next;
183 tail_call:
184 if (!al)
185 return;
186 #ifdef TAL_INFO
187 fprintf(stderr, "limit=%5d, size=%5g MB, nb_peak=%6d, nb_total=%8d, nb_missed=%6d, usage=%5.1f%%\n",
188 al->limit, al->size / 1024.0 / 1024.0, al->nb_peak, al->nb_total, al->nb_missed,
189 (al->peak_p - al->buffer) * 100.0 / al->size);
190 #endif
191 #ifdef TAL_DEBUG
192 if (al->nb_allocs > 0) {
193 uint8_t *p;
194 fprintf(stderr, "TAL_DEBUG: mem leak %d chunks (limit= %d)\n",
195 al->nb_allocs, al->limit);
196 p = al->buffer;
197 while (p < al->p) {
198 tal_header_t *header = (tal_header_t *)p;
199 if (header->line_num > 0) {
200 fprintf(stderr, " file %s, line %u: %u bytes\n",
201 header->file_name, header->line_num, header->size);
203 p += header->size + sizeof(tal_header_t);
206 #endif
207 next = al->next;
208 tcc_free(al->buffer);
209 tcc_free(al);
210 al = next;
211 goto tail_call;
214 ST_FUNC void tal_free_impl(TinyAlloc *al, void *p TAL_DEBUG_PARAMS)
216 if (!p)
217 return;
218 tail_call:
219 if (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size) {
220 #ifdef TAL_DEBUG
221 tal_header_t *header = (((tal_header_t *)p) - 1);
222 if (header->line_num < 0) {
223 fprintf(stderr, "TAL_DEBUG: file %s, line %u double frees chunk from\n",
224 file, line);
225 fprintf(stderr, " file %s, line %u: %u bytes\n",
226 header->file_name, -header->line_num, header->size);
227 } else
228 header->line_num = -header->line_num;
229 #endif
230 al->nb_allocs--;
231 if (!al->nb_allocs)
232 al->p = al->buffer;
233 } else if (al->next) {
234 al = al->next;
235 goto tail_call;
237 else
238 tcc_free(p);
241 ST_FUNC void *tal_realloc_impl(TinyAlloc **pal, void *p, size_t size TAL_DEBUG_PARAMS)
243 tal_header_t *header;
244 void *ret;
245 int is_own;
246 size_t adj_size = (size + 3) & -4;
247 TinyAlloc *al = *pal;
249 tail_call:
250 is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size);
251 if ((!p || is_own) && size <= al->limit) {
252 if (al->p + adj_size + sizeof(tal_header_t) < al->buffer + al->size) {
253 header = (tal_header_t *)al->p;
254 header->size = adj_size;
255 #ifdef TAL_DEBUG
256 { int ofs = strlen(file) - TAL_DEBUG_FILE_LEN;
257 strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), TAL_DEBUG_FILE_LEN);
258 header->file_name[TAL_DEBUG_FILE_LEN] = 0;
259 header->line_num = line; }
260 #endif
261 ret = al->p + sizeof(tal_header_t);
262 al->p += adj_size + sizeof(tal_header_t);
263 if (is_own) {
264 header = (((tal_header_t *)p) - 1);
265 memcpy(ret, p, header->size);
266 #ifdef TAL_DEBUG
267 header->line_num = -header->line_num;
268 #endif
269 } else {
270 al->nb_allocs++;
272 #ifdef TAL_INFO
273 if (al->nb_peak < al->nb_allocs)
274 al->nb_peak = al->nb_allocs;
275 if (al->peak_p < al->p)
276 al->peak_p = al->p;
277 al->nb_total++;
278 #endif
279 return ret;
280 } else if (is_own) {
281 al->nb_allocs--;
282 ret = tal_realloc(*pal, 0, size);
283 header = (((tal_header_t *)p) - 1);
284 memcpy(ret, p, header->size);
285 #ifdef TAL_DEBUG
286 header->line_num = -header->line_num;
287 #endif
288 return ret;
290 if (al->next) {
291 al = al->next;
292 } else {
293 TinyAlloc *bottom = al, *next = al->top ? al->top : al;
295 al = tal_new(pal, next->limit, next->size * 2);
296 al->next = next;
297 bottom->top = al;
299 goto tail_call;
301 if (is_own) {
302 al->nb_allocs--;
303 ret = tcc_malloc(size);
304 header = (((tal_header_t *)p) - 1);
305 memcpy(ret, p, header->size);
306 #ifdef TAL_DEBUG
307 header->line_num = -header->line_num;
308 #endif
309 } else if (al->next) {
310 al = al->next;
311 goto tail_call;
312 } else
313 ret = tcc_realloc(p, size);
314 #ifdef TAL_INFO
315 al->nb_missed++;
316 #endif
317 return ret;
320 #endif /* USE_TAL */
322 /* ------------------------------------------------------------------------- */
323 /* CString handling */
324 static void cstr_realloc(CString *cstr, int new_size)
326 int size;
328 size = cstr->size_allocated;
329 if (size < 8)
330 size = 8; /* no need to allocate a too small first string */
331 while (size < new_size)
332 size = size * 2;
333 cstr->data = tal_realloc(cstr_alloc, cstr->data, size);
334 cstr->size_allocated = size;
337 /* add a byte */
338 ST_INLN void cstr_ccat(CString *cstr, int ch)
340 int size;
341 size = cstr->size + 1;
342 if (size > cstr->size_allocated)
343 cstr_realloc(cstr, size);
344 ((unsigned char *)cstr->data)[size - 1] = ch;
345 cstr->size = size;
348 ST_FUNC void cstr_cat(CString *cstr, const char *str, int len)
350 int size;
351 if (len <= 0)
352 len = strlen(str) + 1 + len;
353 size = cstr->size + len;
354 if (size > cstr->size_allocated)
355 cstr_realloc(cstr, size);
356 memmove(((unsigned char *)cstr->data) + cstr->size, str, len);
357 cstr->size = size;
360 /* add a wide char */
361 ST_FUNC void cstr_wccat(CString *cstr, int ch)
363 int size;
364 size = cstr->size + sizeof(nwchar_t);
365 if (size > cstr->size_allocated)
366 cstr_realloc(cstr, size);
367 *(nwchar_t *)(((unsigned char *)cstr->data) + size - sizeof(nwchar_t)) = ch;
368 cstr->size = size;
371 ST_FUNC void cstr_new(CString *cstr)
373 memset(cstr, 0, sizeof(CString));
376 /* free string and reset it to NULL */
377 ST_FUNC void cstr_free(CString *cstr)
379 tal_free(cstr_alloc, cstr->data);
380 cstr_new(cstr);
383 /* reset string to empty */
384 ST_FUNC void cstr_reset(CString *cstr)
386 cstr->size = 0;
389 /* XXX: unicode ? */
390 static void add_char(CString *cstr, int c)
392 if (c == '\'' || c == '\"' || c == '\\') {
393 /* XXX: could be more precise if char or string */
394 cstr_ccat(cstr, '\\');
396 if (c >= 32 && c <= 126) {
397 cstr_ccat(cstr, c);
398 } else {
399 cstr_ccat(cstr, '\\');
400 if (c == '\n') {
401 cstr_ccat(cstr, 'n');
402 } else {
403 cstr_ccat(cstr, '0' + ((c >> 6) & 7));
404 cstr_ccat(cstr, '0' + ((c >> 3) & 7));
405 cstr_ccat(cstr, '0' + (c & 7));
410 /* ------------------------------------------------------------------------- */
411 /* allocate a new token */
412 static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len)
414 TokenSym *ts, **ptable;
415 int i;
417 if (tok_ident >= SYM_FIRST_ANOM)
418 tcc_error("memory full (symbols)");
420 /* expand token table if needed */
421 i = tok_ident - TOK_IDENT;
422 if ((i % TOK_ALLOC_INCR) == 0) {
423 ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *));
424 table_ident = ptable;
427 ts = tal_realloc(toksym_alloc, 0, sizeof(TokenSym) + len);
428 table_ident[i] = ts;
429 ts->tok = tok_ident++;
430 ts->sym_define = NULL;
431 ts->sym_label = NULL;
432 ts->sym_struct = NULL;
433 ts->sym_identifier = NULL;
434 ts->len = len;
435 ts->hash_next = NULL;
436 memcpy(ts->str, str, len);
437 ts->str[len] = '\0';
438 *pts = ts;
439 return ts;
442 #define TOK_HASH_INIT 1
443 #define TOK_HASH_FUNC(h, c) ((h) + ((h) << 5) + ((h) >> 27) + (c))
446 /* find a token and add it if not found */
447 ST_FUNC TokenSym *tok_alloc(const char *str, int len)
449 TokenSym *ts, **pts;
450 int i;
451 unsigned int h;
453 h = TOK_HASH_INIT;
454 for(i=0;i<len;i++)
455 h = TOK_HASH_FUNC(h, ((unsigned char *)str)[i]);
456 h &= (TOK_HASH_SIZE - 1);
458 pts = &hash_ident[h];
459 for(;;) {
460 ts = *pts;
461 if (!ts)
462 break;
463 if (ts->len == len && !memcmp(ts->str, str, len))
464 return ts;
465 pts = &(ts->hash_next);
467 return tok_alloc_new(pts, str, len);
470 /* XXX: buffer overflow */
471 /* XXX: float tokens */
472 ST_FUNC const char *get_tok_str(int v, CValue *cv)
474 char *p;
475 int i, len;
477 cstr_reset(&cstr_buf);
478 p = cstr_buf.data;
480 switch(v) {
481 case TOK_CINT:
482 case TOK_CUINT:
483 case TOK_CLLONG:
484 case TOK_CULLONG:
485 /* XXX: not quite exact, but only useful for testing */
486 #ifdef _WIN32
487 sprintf(p, "%u", (unsigned)cv->i);
488 #else
489 sprintf(p, "%llu", (unsigned long long)cv->i);
490 #endif
491 break;
492 case TOK_LCHAR:
493 cstr_ccat(&cstr_buf, 'L');
494 case TOK_CCHAR:
495 cstr_ccat(&cstr_buf, '\'');
496 add_char(&cstr_buf, cv->i);
497 cstr_ccat(&cstr_buf, '\'');
498 cstr_ccat(&cstr_buf, '\0');
499 break;
500 case TOK_PPNUM:
501 case TOK_PPSTR:
502 return (char*)cv->str.data;
503 case TOK_LSTR:
504 cstr_ccat(&cstr_buf, 'L');
505 case TOK_STR:
506 cstr_ccat(&cstr_buf, '\"');
507 if (v == TOK_STR) {
508 len = cv->str.size - 1;
509 for(i=0;i<len;i++)
510 add_char(&cstr_buf, ((unsigned char *)cv->str.data)[i]);
511 } else {
512 len = (cv->str.size / sizeof(nwchar_t)) - 1;
513 for(i=0;i<len;i++)
514 add_char(&cstr_buf, ((nwchar_t *)cv->str.data)[i]);
516 cstr_ccat(&cstr_buf, '\"');
517 cstr_ccat(&cstr_buf, '\0');
518 break;
520 case TOK_CFLOAT:
521 cstr_cat(&cstr_buf, "<float>", 0);
522 break;
523 case TOK_CDOUBLE:
524 cstr_cat(&cstr_buf, "<double>", 0);
525 break;
526 case TOK_CLDOUBLE:
527 cstr_cat(&cstr_buf, "<long double>", 0);
528 break;
529 case TOK_LINENUM:
530 cstr_cat(&cstr_buf, "<linenumber>", 0);
531 break;
533 /* above tokens have value, the ones below don't */
535 case TOK_LT:
536 v = '<';
537 goto addv;
538 case TOK_GT:
539 v = '>';
540 goto addv;
541 case TOK_DOTS:
542 return strcpy(p, "...");
543 case TOK_A_SHL:
544 return strcpy(p, "<<=");
545 case TOK_A_SAR:
546 return strcpy(p, ">>=");
547 default:
548 if (v < TOK_IDENT) {
549 /* search in two bytes table */
550 const unsigned char *q = tok_two_chars;
551 while (*q) {
552 if (q[2] == v) {
553 *p++ = q[0];
554 *p++ = q[1];
555 *p = '\0';
556 return cstr_buf.data;
558 q += 3;
560 if (v >= 127) {
561 sprintf(cstr_buf.data, "<%02x>", v);
562 return cstr_buf.data;
564 addv:
565 *p++ = v;
566 *p = '\0';
567 } else if (v < tok_ident) {
568 return table_ident[v - TOK_IDENT]->str;
569 } else if (v >= SYM_FIRST_ANOM) {
570 /* special name for anonymous symbol */
571 sprintf(p, "L.%u", v - SYM_FIRST_ANOM);
572 } else {
573 /* should never happen */
574 return NULL;
576 break;
578 return cstr_buf.data;
581 /* return the current character, handling end of block if necessary
582 (but not stray) */
583 ST_FUNC int handle_eob(void)
585 BufferedFile *bf = file;
586 int len;
588 /* only tries to read if really end of buffer */
589 if (bf->buf_ptr >= bf->buf_end) {
590 if (bf->fd != -1) {
591 #if defined(PARSE_DEBUG)
592 len = 1;
593 #else
594 len = IO_BUF_SIZE;
595 #endif
596 len = read(bf->fd, bf->buffer, len);
597 if (len < 0)
598 len = 0;
599 } else {
600 len = 0;
602 total_bytes += len;
603 bf->buf_ptr = bf->buffer;
604 bf->buf_end = bf->buffer + len;
605 *bf->buf_end = CH_EOB;
607 if (bf->buf_ptr < bf->buf_end) {
608 return bf->buf_ptr[0];
609 } else {
610 bf->buf_ptr = bf->buf_end;
611 return CH_EOF;
615 /* read next char from current input file and handle end of input buffer */
616 ST_INLN void inp(void)
618 ch = *(++(file->buf_ptr));
619 /* end of buffer/file handling */
620 if (ch == CH_EOB)
621 ch = handle_eob();
624 /* handle '\[\r]\n' */
625 static int handle_stray_noerror(void)
627 while (ch == '\\') {
628 inp();
629 if (ch == '\n') {
630 file->line_num++;
631 inp();
632 } else if (ch == '\r') {
633 inp();
634 if (ch != '\n')
635 goto fail;
636 file->line_num++;
637 inp();
638 } else {
639 fail:
640 return 1;
643 return 0;
646 static void handle_stray(void)
648 if (handle_stray_noerror())
649 tcc_error("stray '\\' in program");
652 /* skip the stray and handle the \\n case. Output an error if
653 incorrect char after the stray */
654 static int handle_stray1(uint8_t *p)
656 int c;
658 file->buf_ptr = p;
659 if (p >= file->buf_end) {
660 c = handle_eob();
661 if (c != '\\')
662 return c;
663 p = file->buf_ptr;
665 ch = *p;
666 if (handle_stray_noerror()) {
667 if (!(parse_flags & PARSE_FLAG_ACCEPT_STRAYS))
668 tcc_error("stray '\\' in program");
669 *--file->buf_ptr = '\\';
671 p = file->buf_ptr;
672 c = *p;
673 return c;
676 /* handle just the EOB case, but not stray */
677 #define PEEKC_EOB(c, p)\
679 p++;\
680 c = *p;\
681 if (c == '\\') {\
682 file->buf_ptr = p;\
683 c = handle_eob();\
684 p = file->buf_ptr;\
688 /* handle the complicated stray case */
689 #define PEEKC(c, p)\
691 p++;\
692 c = *p;\
693 if (c == '\\') {\
694 c = handle_stray1(p);\
695 p = file->buf_ptr;\
699 /* input with '\[\r]\n' handling. Note that this function cannot
700 handle other characters after '\', so you cannot call it inside
701 strings or comments */
702 ST_FUNC void minp(void)
704 inp();
705 if (ch == '\\')
706 handle_stray();
709 /* single line C++ comments */
710 static uint8_t *parse_line_comment(uint8_t *p)
712 int c;
714 p++;
715 for(;;) {
716 c = *p;
717 redo:
718 if (c == '\n' || c == CH_EOF) {
719 break;
720 } else if (c == '\\') {
721 file->buf_ptr = p;
722 c = handle_eob();
723 p = file->buf_ptr;
724 if (c == '\\') {
725 PEEKC_EOB(c, p);
726 if (c == '\n') {
727 file->line_num++;
728 PEEKC_EOB(c, p);
729 } else if (c == '\r') {
730 PEEKC_EOB(c, p);
731 if (c == '\n') {
732 file->line_num++;
733 PEEKC_EOB(c, p);
736 } else {
737 goto redo;
739 } else {
740 p++;
743 return p;
746 /* C comments */
747 ST_FUNC uint8_t *parse_comment(uint8_t *p)
749 int c;
751 p++;
752 for(;;) {
753 /* fast skip loop */
754 for(;;) {
755 c = *p;
756 if (c == '\n' || c == '*' || c == '\\')
757 break;
758 p++;
759 c = *p;
760 if (c == '\n' || c == '*' || c == '\\')
761 break;
762 p++;
764 /* now we can handle all the cases */
765 if (c == '\n') {
766 file->line_num++;
767 p++;
768 } else if (c == '*') {
769 p++;
770 for(;;) {
771 c = *p;
772 if (c == '*') {
773 p++;
774 } else if (c == '/') {
775 goto end_of_comment;
776 } else if (c == '\\') {
777 file->buf_ptr = p;
778 c = handle_eob();
779 p = file->buf_ptr;
780 if (c == CH_EOF)
781 tcc_error("unexpected end of file in comment");
782 if (c == '\\') {
783 /* skip '\[\r]\n', otherwise just skip the stray */
784 while (c == '\\') {
785 PEEKC_EOB(c, p);
786 if (c == '\n') {
787 file->line_num++;
788 PEEKC_EOB(c, p);
789 } else if (c == '\r') {
790 PEEKC_EOB(c, p);
791 if (c == '\n') {
792 file->line_num++;
793 PEEKC_EOB(c, p);
795 } else {
796 goto after_star;
800 } else {
801 break;
804 after_star: ;
805 } else {
806 /* stray, eob or eof */
807 file->buf_ptr = p;
808 c = handle_eob();
809 p = file->buf_ptr;
810 if (c == CH_EOF) {
811 tcc_error("unexpected end of file in comment");
812 } else if (c == '\\') {
813 p++;
817 end_of_comment:
818 p++;
819 return p;
822 #define cinp minp
824 static inline void skip_spaces(void)
826 while (isidnum_table[ch - CH_EOF] & IS_SPC)
827 cinp();
830 static inline int check_space(int t, int *spc)
832 if (t < 256 && (isidnum_table[t - CH_EOF] & IS_SPC)) {
833 if (*spc)
834 return 1;
835 *spc = 1;
836 } else
837 *spc = 0;
838 return 0;
841 /* parse a string without interpreting escapes */
842 static uint8_t *parse_pp_string(uint8_t *p,
843 int sep, CString *str)
845 int c;
846 p++;
847 for(;;) {
848 c = *p;
849 if (c == sep) {
850 break;
851 } else if (c == '\\') {
852 file->buf_ptr = p;
853 c = handle_eob();
854 p = file->buf_ptr;
855 if (c == CH_EOF) {
856 unterminated_string:
857 /* XXX: indicate line number of start of string */
858 tcc_error("missing terminating %c character", sep);
859 } else if (c == '\\') {
860 /* escape : just skip \[\r]\n */
861 PEEKC_EOB(c, p);
862 if (c == '\n') {
863 file->line_num++;
864 p++;
865 } else if (c == '\r') {
866 PEEKC_EOB(c, p);
867 if (c != '\n')
868 expect("'\n' after '\r'");
869 file->line_num++;
870 p++;
871 } else if (c == CH_EOF) {
872 goto unterminated_string;
873 } else {
874 if (str) {
875 cstr_ccat(str, '\\');
876 cstr_ccat(str, c);
878 p++;
881 } else if (c == '\n') {
882 file->line_num++;
883 goto add_char;
884 } else if (c == '\r') {
885 PEEKC_EOB(c, p);
886 if (c != '\n') {
887 if (str)
888 cstr_ccat(str, '\r');
889 } else {
890 file->line_num++;
891 goto add_char;
893 } else {
894 add_char:
895 if (str)
896 cstr_ccat(str, c);
897 p++;
900 p++;
901 return p;
904 /* skip block of text until #else, #elif or #endif. skip also pairs of
905 #if/#endif */
906 static void preprocess_skip(void)
908 int a, start_of_line, c, in_warn_or_error;
909 uint8_t *p;
911 p = file->buf_ptr;
912 a = 0;
913 redo_start:
914 start_of_line = 1;
915 in_warn_or_error = 0;
916 for(;;) {
917 redo_no_start:
918 c = *p;
919 switch(c) {
920 case ' ':
921 case '\t':
922 case '\f':
923 case '\v':
924 case '\r':
925 p++;
926 goto redo_no_start;
927 case '\n':
928 file->line_num++;
929 p++;
930 goto redo_start;
931 case '\\':
932 file->buf_ptr = p;
933 c = handle_eob();
934 if (c == CH_EOF) {
935 expect("#endif");
936 } else if (c == '\\') {
937 ch = file->buf_ptr[0];
938 handle_stray_noerror();
940 p = file->buf_ptr;
941 goto redo_no_start;
942 /* skip strings */
943 case '\"':
944 case '\'':
945 if (in_warn_or_error)
946 goto _default;
947 p = parse_pp_string(p, c, NULL);
948 break;
949 /* skip comments */
950 case '/':
951 if (in_warn_or_error)
952 goto _default;
953 file->buf_ptr = p;
954 ch = *p;
955 minp();
956 p = file->buf_ptr;
957 if (ch == '*') {
958 p = parse_comment(p);
959 } else if (ch == '/') {
960 p = parse_line_comment(p);
962 break;
963 case '#':
964 p++;
965 if (start_of_line) {
966 file->buf_ptr = p;
967 next_nomacro();
968 p = file->buf_ptr;
969 if (a == 0 &&
970 (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF))
971 goto the_end;
972 if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF)
973 a++;
974 else if (tok == TOK_ENDIF)
975 a--;
976 else if( tok == TOK_ERROR || tok == TOK_WARNING)
977 in_warn_or_error = 1;
978 else if (tok == TOK_LINEFEED)
979 goto redo_start;
980 else if (parse_flags & PARSE_FLAG_ASM_FILE)
981 p = parse_line_comment(p - 1);
982 } else if (parse_flags & PARSE_FLAG_ASM_FILE)
983 p = parse_line_comment(p - 1);
984 break;
985 _default:
986 default:
987 p++;
988 break;
990 start_of_line = 0;
992 the_end: ;
993 file->buf_ptr = p;
996 /* ParseState handling */
998 /* XXX: currently, no include file info is stored. Thus, we cannot display
999 accurate messages if the function or data definition spans multiple
1000 files */
1002 /* save current parse state in 's' */
1003 ST_FUNC void save_parse_state(ParseState *s)
1005 s->line_num = file->line_num;
1006 s->macro_ptr = macro_ptr;
1007 s->tok = tok;
1008 s->tokc = tokc;
1011 /* restore parse state from 's' */
1012 ST_FUNC void restore_parse_state(ParseState *s)
1014 file->line_num = s->line_num;
1015 macro_ptr = s->macro_ptr;
1016 tok = s->tok;
1017 tokc = s->tokc;
1020 /* return the number of additional 'ints' necessary to store the
1021 token */
1022 static inline int tok_size(const int *p)
1024 switch(*p) {
1025 /* 4 bytes */
1026 case TOK_CINT:
1027 case TOK_CUINT:
1028 case TOK_CCHAR:
1029 case TOK_LCHAR:
1030 case TOK_CFLOAT:
1031 case TOK_LINENUM:
1032 return 1 + 1;
1033 case TOK_STR:
1034 case TOK_LSTR:
1035 case TOK_PPNUM:
1036 case TOK_PPSTR:
1037 return 1 + ((sizeof(CString) + ((CString *)(p+1))->size + 3) >> 2);
1038 case TOK_CDOUBLE:
1039 case TOK_CLLONG:
1040 case TOK_CULLONG:
1041 return 1 + 2;
1042 case TOK_CLDOUBLE:
1043 return 1 + LDOUBLE_SIZE / 4;
1044 default:
1045 return 1 + 0;
1049 /* token string handling */
1051 ST_INLN void tok_str_new(TokenString *s)
1053 s->str = NULL;
1054 s->len = 0;
1055 s->allocated_len = 0;
1056 s->last_line_num = -1;
1059 ST_FUNC TokenString *tok_str_alloc(void)
1061 TokenString *str = tal_realloc(tokstr_alloc, 0, sizeof *str);
1062 tok_str_new(str);
1063 return str;
1066 ST_FUNC int *tok_str_dup(TokenString *s)
1068 int *str;
1070 str = tal_realloc(tokstr_alloc, 0, s->len * sizeof(int));
1071 memcpy(str, s->str, s->len * sizeof(int));
1072 return str;
1075 ST_FUNC void tok_str_free(int *str)
1077 tal_free(tokstr_alloc, str);
1080 ST_FUNC int *tok_str_realloc(TokenString *s, int new_size)
1082 int *str, size;
1084 size = s->allocated_len;
1085 if (size < 16)
1086 size = 16;
1087 while (size < new_size)
1088 size = size * 2;
1089 if (size > s->allocated_len) {
1090 str = tal_realloc(tokstr_alloc, s->str, size * sizeof(int));
1091 s->allocated_len = size;
1092 s->str = str;
1094 return s->str;
1097 ST_FUNC void tok_str_add(TokenString *s, int t)
1099 int len, *str;
1101 len = s->len;
1102 str = s->str;
1103 if (len >= s->allocated_len)
1104 str = tok_str_realloc(s, len + 1);
1105 str[len++] = t;
1106 s->len = len;
1109 ST_FUNC void begin_macro(TokenString *str, int alloc)
1111 str->alloc = alloc;
1112 str->prev = macro_stack;
1113 str->prev_ptr = macro_ptr;
1114 macro_ptr = str->str;
1115 macro_stack = str;
1118 ST_FUNC void end_macro(void)
1120 TokenString *str = macro_stack;
1121 macro_stack = str->prev;
1122 macro_ptr = str->prev_ptr;
1123 if (str->alloc == 2) {
1124 str->alloc = 3; /* just mark as finished */
1125 } else {
1126 tok_str_free(str->str);
1127 if (str->alloc == 1)
1128 tal_free(tokstr_alloc, str);
1132 static void tok_str_add2(TokenString *s, int t, CValue *cv)
1134 int len, *str;
1136 len = s->len;
1137 str = s->str;
1139 /* allocate space for worst case */
1140 if (len + TOK_MAX_SIZE >= s->allocated_len)
1141 str = tok_str_realloc(s, len + TOK_MAX_SIZE + 1);
1142 str[len++] = t;
1143 switch(t) {
1144 case TOK_CINT:
1145 case TOK_CUINT:
1146 case TOK_CCHAR:
1147 case TOK_LCHAR:
1148 case TOK_CFLOAT:
1149 case TOK_LINENUM:
1150 str[len++] = cv->tab[0];
1151 break;
1152 case TOK_PPNUM:
1153 case TOK_PPSTR:
1154 case TOK_STR:
1155 case TOK_LSTR:
1157 /* Insert the string into the int array. */
1158 size_t nb_words =
1159 1 + (cv->str.size + sizeof(int) - 1) / sizeof(int);
1160 if (len + nb_words >= s->allocated_len)
1161 str = tok_str_realloc(s, len + nb_words + 1);
1162 str[len] = cv->str.size;
1163 memcpy(&str[len + 1], cv->str.data, cv->str.size);
1164 len += nb_words;
1166 break;
1167 case TOK_CDOUBLE:
1168 case TOK_CLLONG:
1169 case TOK_CULLONG:
1170 #if LDOUBLE_SIZE == 8
1171 case TOK_CLDOUBLE:
1172 #endif
1173 str[len++] = cv->tab[0];
1174 str[len++] = cv->tab[1];
1175 break;
1176 #if LDOUBLE_SIZE == 12
1177 case TOK_CLDOUBLE:
1178 str[len++] = cv->tab[0];
1179 str[len++] = cv->tab[1];
1180 str[len++] = cv->tab[2];
1181 #elif LDOUBLE_SIZE == 16
1182 case TOK_CLDOUBLE:
1183 str[len++] = cv->tab[0];
1184 str[len++] = cv->tab[1];
1185 str[len++] = cv->tab[2];
1186 str[len++] = cv->tab[3];
1187 #elif LDOUBLE_SIZE != 8
1188 #error add long double size support
1189 #endif
1190 break;
1191 default:
1192 break;
1194 s->len = len;
1197 /* add the current parse token in token string 's' */
1198 ST_FUNC void tok_str_add_tok(TokenString *s)
1200 CValue cval;
1202 /* save line number info */
1203 if (file->line_num != s->last_line_num) {
1204 s->last_line_num = file->line_num;
1205 cval.i = s->last_line_num;
1206 tok_str_add2(s, TOK_LINENUM, &cval);
1208 tok_str_add2(s, tok, &tokc);
1211 /* get a token from an integer array and increment pointer
1212 accordingly. we code it as a macro to avoid pointer aliasing. */
1213 static inline void TOK_GET(int *t, const int **pp, CValue *cv)
1215 const int *p = *pp;
1216 int n, *tab;
1218 tab = cv->tab;
1219 switch(*t = *p++) {
1220 case TOK_CINT:
1221 case TOK_CUINT:
1222 case TOK_CCHAR:
1223 case TOK_LCHAR:
1224 case TOK_CFLOAT:
1225 case TOK_LINENUM:
1226 tab[0] = *p++;
1227 break;
1228 case TOK_STR:
1229 case TOK_LSTR:
1230 case TOK_PPNUM:
1231 case TOK_PPSTR:
1232 cv->str.size = *p++;
1233 cv->str.data = p;
1234 p += (cv->str.size + sizeof(int) - 1) / sizeof(int);
1235 break;
1236 case TOK_CDOUBLE:
1237 case TOK_CLLONG:
1238 case TOK_CULLONG:
1239 n = 2;
1240 goto copy;
1241 case TOK_CLDOUBLE:
1242 #if LDOUBLE_SIZE == 16
1243 n = 4;
1244 #elif LDOUBLE_SIZE == 12
1245 n = 3;
1246 #elif LDOUBLE_SIZE == 8
1247 n = 2;
1248 #else
1249 # error add long double size support
1250 #endif
1251 copy:
1253 *tab++ = *p++;
1254 while (--n);
1255 break;
1256 default:
1257 break;
1259 *pp = p;
1262 /* Calling this function is expensive, but it is not possible
1263 to read a token string backwards. */
1264 static int tok_last(const int *str0, const int *str1)
1266 const int *str = str0;
1267 int tok = 0;
1268 CValue cval;
1270 while (str < str1)
1271 TOK_GET(&tok, &str, &cval);
1272 return tok;
1275 static int macro_is_equal(const int *a, const int *b)
1277 CValue cv;
1278 int t;
1280 if (!a || !b)
1281 return 1;
1283 while (*a && *b) {
1284 /* first time preallocate static cstr_buf, next time only reset position to start */
1285 cstr_reset(&cstr_buf);
1286 TOK_GET(&t, &a, &cv);
1287 cstr_cat(&cstr_buf, get_tok_str(t, &cv), 0);
1288 TOK_GET(&t, &b, &cv);
1289 if (strcmp(cstr_buf.data, get_tok_str(t, &cv)))
1290 return 0;
1292 return !(*a || *b);
1295 /* defines handling */
1296 ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg)
1298 Sym *s, *o;
1300 o = define_find(v);
1301 s = sym_push2(&define_stack, v, macro_type, 0);
1302 s->d = str;
1303 s->next = first_arg;
1304 table_ident[v - TOK_IDENT]->sym_define = s;
1306 if (o && !macro_is_equal(o->d, s->d))
1307 tcc_warning("%s redefined", get_tok_str(v, NULL));
1310 /* undefined a define symbol. Its name is just set to zero */
1311 ST_FUNC void define_undef(Sym *s)
1313 int v = s->v;
1314 if (v >= TOK_IDENT && v < tok_ident)
1315 table_ident[v - TOK_IDENT]->sym_define = NULL;
1318 ST_INLN Sym *define_find(int v)
1320 v -= TOK_IDENT;
1321 if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
1322 return NULL;
1323 return table_ident[v]->sym_define;
1326 /* free define stack until top reaches 'b' */
1327 ST_FUNC void free_defines(Sym *b)
1329 while (define_stack != b) {
1330 Sym *top = define_stack;
1331 define_stack = top->prev;
1332 tok_str_free(top->d);
1333 define_undef(top);
1334 sym_free(top);
1337 /* restore remaining (-D or predefined) symbols */
1338 while (b) {
1339 int v = b->v;
1340 if (v >= TOK_IDENT && v < tok_ident) {
1341 Sym **d = &table_ident[v - TOK_IDENT]->sym_define;
1342 if (!*d)
1343 *d = b;
1345 b = b->prev;
1349 /* label lookup */
1350 ST_FUNC Sym *label_find(int v)
1352 v -= TOK_IDENT;
1353 if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
1354 return NULL;
1355 return table_ident[v]->sym_label;
1358 ST_FUNC Sym *label_push(Sym **ptop, int v, int flags)
1360 Sym *s, **ps;
1361 s = sym_push2(ptop, v, 0, 0);
1362 s->r = flags;
1363 ps = &table_ident[v - TOK_IDENT]->sym_label;
1364 if (ptop == &global_label_stack) {
1365 /* modify the top most local identifier, so that
1366 sym_identifier will point to 's' when popped */
1367 while (*ps != NULL)
1368 ps = &(*ps)->prev_tok;
1370 s->prev_tok = *ps;
1371 *ps = s;
1372 return s;
1375 /* pop labels until element last is reached. Look if any labels are
1376 undefined. Define symbols if '&&label' was used. */
1377 ST_FUNC void label_pop(Sym **ptop, Sym *slast)
1379 Sym *s, *s1;
1380 for(s = *ptop; s != slast; s = s1) {
1381 s1 = s->prev;
1382 if (s->r == LABEL_DECLARED) {
1383 tcc_warning("label '%s' declared but not used", get_tok_str(s->v, NULL));
1384 } else if (s->r == LABEL_FORWARD) {
1385 tcc_error("label '%s' used but not defined",
1386 get_tok_str(s->v, NULL));
1387 } else {
1388 if (s->c) {
1389 /* define corresponding symbol. A size of
1390 1 is put. */
1391 put_extern_sym(s, cur_text_section, s->jnext, 1);
1394 /* remove label */
1395 table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
1396 sym_free(s);
1398 *ptop = slast;
1401 /* eval an expression for #if/#elif */
1402 static int expr_preprocess(void)
1404 int c, t;
1405 TokenString *str;
1407 str = tok_str_alloc();
1408 while (tok != TOK_LINEFEED && tok != TOK_EOF) {
1409 next(); /* do macro subst */
1410 if (tok == TOK_DEFINED) {
1411 next_nomacro();
1412 t = tok;
1413 if (t == '(')
1414 next_nomacro();
1415 c = define_find(tok) != 0;
1416 if (t == '(')
1417 next_nomacro();
1418 tok = TOK_CINT;
1419 tokc.i = c;
1420 } else if (tok >= TOK_IDENT) {
1421 /* if undefined macro */
1422 tok = TOK_CINT;
1423 tokc.i = 0;
1425 tok_str_add_tok(str);
1427 tok_str_add(str, -1); /* simulate end of file */
1428 tok_str_add(str, 0);
1429 /* now evaluate C constant expression */
1430 begin_macro(str, 1);
1431 next();
1432 c = expr_const();
1433 end_macro();
1434 return c != 0;
1438 /* parse after #define */
1439 ST_FUNC void parse_define(void)
1441 Sym *s, *first, **ps;
1442 int v, t, varg, is_vaargs, spc;
1443 int saved_parse_flags = parse_flags;
1445 v = tok;
1446 if (v < TOK_IDENT)
1447 tcc_error("invalid macro name '%s'", get_tok_str(tok, &tokc));
1448 /* XXX: should check if same macro (ANSI) */
1449 first = NULL;
1450 t = MACRO_OBJ;
1451 /* '(' must be just after macro definition for MACRO_FUNC */
1452 parse_flags |= PARSE_FLAG_SPACES;
1453 next_nomacro_spc();
1454 if (tok == '(') {
1455 /* must be able to parse TOK_DOTS (in asm mode '.' can be part of identifier) */
1456 parse_flags &= ~PARSE_FLAG_ASM_FILE;
1457 isidnum_table['.' - CH_EOF] = 0;
1458 next_nomacro();
1459 ps = &first;
1460 if (tok != ')') for (;;) {
1461 varg = tok;
1462 next_nomacro();
1463 is_vaargs = 0;
1464 if (varg == TOK_DOTS) {
1465 varg = TOK___VA_ARGS__;
1466 is_vaargs = 1;
1467 } else if (tok == TOK_DOTS && gnu_ext) {
1468 is_vaargs = 1;
1469 next_nomacro();
1471 if (varg < TOK_IDENT)
1472 bad_list:
1473 tcc_error("bad macro parameter list");
1474 s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0);
1475 *ps = s;
1476 ps = &s->next;
1477 if (tok == ')')
1478 break;
1479 if (tok != ',' || is_vaargs)
1480 goto bad_list;
1481 next_nomacro();
1483 next_nomacro_spc();
1484 t = MACRO_FUNC;
1485 parse_flags |= (saved_parse_flags & PARSE_FLAG_ASM_FILE);
1486 isidnum_table['.' - CH_EOF] =
1487 (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0;
1490 tokstr_buf.len = 0;
1491 spc = 2;
1492 parse_flags |= PARSE_FLAG_ACCEPT_STRAYS | PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED;
1493 while (tok != TOK_LINEFEED && tok != TOK_EOF) {
1494 /* remove spaces around ## and after '#' */
1495 if (TOK_TWOSHARPS == tok) {
1496 if (2 == spc)
1497 goto bad_twosharp;
1498 if (1 == spc)
1499 --tokstr_buf.len;
1500 spc = 3;
1501 } else if ('#' == tok) {
1502 spc = 4;
1503 } else if (check_space(tok, &spc)) {
1504 goto skip;
1506 tok_str_add2(&tokstr_buf, tok, &tokc);
1507 skip:
1508 next_nomacro_spc();
1511 parse_flags = saved_parse_flags;
1512 if (spc == 1)
1513 --tokstr_buf.len; /* remove trailing space */
1514 tok_str_add(&tokstr_buf, 0);
1515 if (3 == spc)
1516 bad_twosharp:
1517 tcc_error("'##' cannot appear at either end of macro");
1518 define_push(v, t, tok_str_dup(&tokstr_buf), first);
1521 static CachedInclude *search_cached_include(TCCState *s1, const char *filename, int add)
1523 const unsigned char *s;
1524 unsigned int h;
1525 CachedInclude *e;
1526 int i;
1528 h = TOK_HASH_INIT;
1529 s = (unsigned char *) filename;
1530 while (*s) {
1531 #ifdef _WIN32
1532 h = TOK_HASH_FUNC(h, toup(*s));
1533 #else
1534 h = TOK_HASH_FUNC(h, *s);
1535 #endif
1536 s++;
1538 h &= (CACHED_INCLUDES_HASH_SIZE - 1);
1540 i = s1->cached_includes_hash[h];
1541 for(;;) {
1542 if (i == 0)
1543 break;
1544 e = s1->cached_includes[i - 1];
1545 if (0 == PATHCMP(e->filename, filename))
1546 return e;
1547 i = e->hash_next;
1549 if (!add)
1550 return NULL;
1552 e = tcc_malloc(sizeof(CachedInclude) + strlen(filename));
1553 strcpy(e->filename, filename);
1554 e->ifndef_macro = e->once = 0;
1555 dynarray_add((void ***)&s1->cached_includes, &s1->nb_cached_includes, e);
1556 /* add in hash table */
1557 e->hash_next = s1->cached_includes_hash[h];
1558 s1->cached_includes_hash[h] = s1->nb_cached_includes;
1559 #ifdef INC_DEBUG
1560 printf("adding cached '%s'\n", filename);
1561 #endif
1562 return e;
1565 static void pragma_parse(TCCState *s1)
1567 next_nomacro();
1568 if (tok == TOK_push_macro || tok == TOK_pop_macro) {
1569 int t = tok, v;
1570 Sym *s;
1572 if (next(), tok != '(')
1573 goto pragma_err;
1574 if (next(), tok != TOK_STR)
1575 goto pragma_err;
1576 v = tok_alloc(tokc.str.data, tokc.str.size - 1)->tok;
1577 if (next(), tok != ')')
1578 goto pragma_err;
1579 if (t == TOK_push_macro) {
1580 while (NULL == (s = define_find(v)))
1581 define_push(v, 0, NULL, NULL);
1582 s->type.ref = s; /* set push boundary */
1583 } else {
1584 for (s = define_stack; s; s = s->prev)
1585 if (s->v == v && s->type.ref == s) {
1586 s->type.ref = NULL;
1587 break;
1590 if (s)
1591 table_ident[v - TOK_IDENT]->sym_define = s->d ? s : NULL;
1592 else
1593 tcc_warning("unbalanced #pragma pop_macro");
1594 pp_debug_tok = t, pp_debug_symv = v;
1596 } else if (tok == TOK_once) {
1597 search_cached_include(s1, file->filename, 1)->once = pp_once;
1599 } else if (s1->ppfp) {
1600 /* tcc -E: keep pragmas below unchanged */
1601 unget_tok(' ');
1602 unget_tok(TOK_PRAGMA);
1603 unget_tok('#');
1604 unget_tok(TOK_LINEFEED);
1606 } else if (tok == TOK_pack) {
1607 /* This may be:
1608 #pragma pack(1) // set
1609 #pragma pack() // reset to default
1610 #pragma pack(push,1) // push & set
1611 #pragma pack(pop) // restore previous */
1612 next();
1613 skip('(');
1614 if (tok == TOK_ASM_pop) {
1615 next();
1616 if (s1->pack_stack_ptr <= s1->pack_stack) {
1617 stk_error:
1618 tcc_error("out of pack stack");
1620 s1->pack_stack_ptr--;
1621 } else {
1622 int val = 0;
1623 if (tok != ')') {
1624 if (tok == TOK_ASM_push) {
1625 next();
1626 if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1)
1627 goto stk_error;
1628 s1->pack_stack_ptr++;
1629 skip(',');
1631 if (tok != TOK_CINT)
1632 goto pragma_err;
1633 val = tokc.i;
1634 if (val < 1 || val > 16 || (val & (val - 1)) != 0)
1635 goto pragma_err;
1636 next();
1638 *s1->pack_stack_ptr = val;
1640 if (tok != ')')
1641 goto pragma_err;
1643 } else if (tok == TOK_comment) {
1644 char *file;
1645 next();
1646 skip('(');
1647 if (tok != TOK_lib)
1648 goto pragma_warn;
1649 next();
1650 skip(',');
1651 if (tok != TOK_STR)
1652 goto pragma_err;
1653 file = tcc_strdup((char *)tokc.str.data);
1654 dynarray_add((void ***)&s1->pragma_libs, &s1->nb_pragma_libs, file);
1655 next();
1656 if (tok != ')')
1657 goto pragma_err;
1658 } else {
1659 pragma_warn:
1660 if (s1->warn_unsupported)
1661 tcc_warning("#pragma %s is ignored", get_tok_str(tok, &tokc));
1663 return;
1665 pragma_err:
1666 tcc_error("malformed #pragma directive");
1667 return;
1670 /* is_bof is true if first non space token at beginning of file */
1671 ST_FUNC void preprocess(int is_bof)
1673 TCCState *s1 = tcc_state;
1674 int i, c, n, saved_parse_flags;
1675 char buf[1024], *q;
1676 Sym *s;
1678 saved_parse_flags = parse_flags;
1679 parse_flags = PARSE_FLAG_PREPROCESS
1680 | PARSE_FLAG_TOK_NUM
1681 | PARSE_FLAG_TOK_STR
1682 | PARSE_FLAG_LINEFEED
1683 | (parse_flags & PARSE_FLAG_ASM_FILE)
1686 next_nomacro();
1687 redo:
1688 switch(tok) {
1689 case TOK_DEFINE:
1690 pp_debug_tok = tok;
1691 next_nomacro();
1692 pp_debug_symv = tok;
1693 parse_define();
1694 break;
1695 case TOK_UNDEF:
1696 pp_debug_tok = tok;
1697 next_nomacro();
1698 pp_debug_symv = tok;
1699 s = define_find(tok);
1700 /* undefine symbol by putting an invalid name */
1701 if (s)
1702 define_undef(s);
1703 break;
1704 case TOK_INCLUDE:
1705 case TOK_INCLUDE_NEXT:
1706 ch = file->buf_ptr[0];
1707 /* XXX: incorrect if comments : use next_nomacro with a special mode */
1708 skip_spaces();
1709 if (ch == '<') {
1710 c = '>';
1711 goto read_name;
1712 } else if (ch == '\"') {
1713 c = ch;
1714 read_name:
1715 inp();
1716 q = buf;
1717 while (ch != c && ch != '\n' && ch != CH_EOF) {
1718 if ((q - buf) < sizeof(buf) - 1)
1719 *q++ = ch;
1720 if (ch == '\\') {
1721 if (handle_stray_noerror() == 0)
1722 --q;
1723 } else
1724 inp();
1726 *q = '\0';
1727 minp();
1728 #if 0
1729 /* eat all spaces and comments after include */
1730 /* XXX: slightly incorrect */
1731 while (ch1 != '\n' && ch1 != CH_EOF)
1732 inp();
1733 #endif
1734 } else {
1735 /* computed #include : either we have only strings or
1736 we have anything enclosed in '<>' */
1737 next();
1738 buf[0] = '\0';
1739 if (tok == TOK_STR) {
1740 while (tok != TOK_LINEFEED) {
1741 if (tok != TOK_STR) {
1742 include_syntax:
1743 tcc_error("'#include' expects \"FILENAME\" or <FILENAME>");
1745 pstrcat(buf, sizeof(buf), (char *)tokc.str.data);
1746 next();
1748 c = '\"';
1749 } else {
1750 int len;
1751 while (tok != TOK_LINEFEED) {
1752 pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc));
1753 next();
1755 len = strlen(buf);
1756 /* check syntax and remove '<>' */
1757 if (len < 2 || buf[0] != '<' || buf[len - 1] != '>')
1758 goto include_syntax;
1759 memmove(buf, buf + 1, len - 2);
1760 buf[len - 2] = '\0';
1761 c = '>';
1765 if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE)
1766 tcc_error("#include recursion too deep");
1767 /* store current file in stack, but increment stack later below */
1768 *s1->include_stack_ptr = file;
1769 i = tok == TOK_INCLUDE_NEXT ? file->include_next_index : 0;
1770 n = 2 + s1->nb_include_paths + s1->nb_sysinclude_paths;
1771 for (; i < n; ++i) {
1772 char buf1[sizeof file->filename];
1773 CachedInclude *e;
1774 const char *path;
1776 if (i == 0) {
1777 /* check absolute include path */
1778 if (!IS_ABSPATH(buf))
1779 continue;
1780 buf1[0] = 0;
1782 } else if (i == 1) {
1783 /* search in file's dir if "header.h" */
1784 if (c != '\"')
1785 continue;
1786 path = file->filename;
1787 pstrncpy(buf1, path, tcc_basename(path) - path);
1789 } else {
1790 /* search in all the include paths */
1791 int j = i - 2, k = j - s1->nb_include_paths;
1792 path = k < 0 ? s1->include_paths[j] : s1->sysinclude_paths[k];
1793 pstrcpy(buf1, sizeof(buf1), path);
1794 pstrcat(buf1, sizeof(buf1), "/");
1797 pstrcat(buf1, sizeof(buf1), buf);
1798 e = search_cached_include(s1, buf1, 0);
1799 if (e && (define_find(e->ifndef_macro) || e->once == pp_once)) {
1800 /* no need to parse the include because the 'ifndef macro'
1801 is defined (or had #pragma once) */
1802 #ifdef INC_DEBUG
1803 printf("%s: skipping cached %s\n", file->filename, buf1);
1804 #endif
1805 goto include_done;
1808 if (tcc_open(s1, buf1) < 0)
1809 continue;
1811 file->include_next_index = i + 1;
1812 #ifdef INC_DEBUG
1813 printf("%s: including %s\n", file->prev->filename, file->filename);
1814 #endif
1815 /* update target deps */
1816 dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps,
1817 tcc_strdup(buf1));
1818 /* push current file in stack */
1819 ++s1->include_stack_ptr;
1820 /* add include file debug info */
1821 if (s1->do_debug)
1822 put_stabs(file->filename, N_BINCL, 0, 0, 0);
1823 tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL;
1824 ch = file->buf_ptr[0];
1825 goto the_end;
1827 tcc_error("include file '%s' not found", buf);
1828 include_done:
1829 break;
1830 case TOK_IFNDEF:
1831 c = 1;
1832 goto do_ifdef;
1833 case TOK_IF:
1834 c = expr_preprocess();
1835 goto do_if;
1836 case TOK_IFDEF:
1837 c = 0;
1838 do_ifdef:
1839 next_nomacro();
1840 if (tok < TOK_IDENT)
1841 tcc_error("invalid argument for '#if%sdef'", c ? "n" : "");
1842 if (is_bof) {
1843 if (c) {
1844 #ifdef INC_DEBUG
1845 printf("#ifndef %s\n", get_tok_str(tok, NULL));
1846 #endif
1847 file->ifndef_macro = tok;
1850 c = (define_find(tok) != 0) ^ c;
1851 do_if:
1852 if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE)
1853 tcc_error("memory full (ifdef)");
1854 *s1->ifdef_stack_ptr++ = c;
1855 goto test_skip;
1856 case TOK_ELSE:
1857 if (s1->ifdef_stack_ptr == s1->ifdef_stack)
1858 tcc_error("#else without matching #if");
1859 if (s1->ifdef_stack_ptr[-1] & 2)
1860 tcc_error("#else after #else");
1861 c = (s1->ifdef_stack_ptr[-1] ^= 3);
1862 goto test_else;
1863 case TOK_ELIF:
1864 if (s1->ifdef_stack_ptr == s1->ifdef_stack)
1865 tcc_error("#elif without matching #if");
1866 c = s1->ifdef_stack_ptr[-1];
1867 if (c > 1)
1868 tcc_error("#elif after #else");
1869 /* last #if/#elif expression was true: we skip */
1870 if (c == 1) {
1871 c = 0;
1872 } else {
1873 c = expr_preprocess();
1874 s1->ifdef_stack_ptr[-1] = c;
1876 test_else:
1877 if (s1->ifdef_stack_ptr == file->ifdef_stack_ptr + 1)
1878 file->ifndef_macro = 0;
1879 test_skip:
1880 if (!(c & 1)) {
1881 preprocess_skip();
1882 is_bof = 0;
1883 goto redo;
1885 break;
1886 case TOK_ENDIF:
1887 if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr)
1888 tcc_error("#endif without matching #if");
1889 s1->ifdef_stack_ptr--;
1890 /* '#ifndef macro' was at the start of file. Now we check if
1891 an '#endif' is exactly at the end of file */
1892 if (file->ifndef_macro &&
1893 s1->ifdef_stack_ptr == file->ifdef_stack_ptr) {
1894 file->ifndef_macro_saved = file->ifndef_macro;
1895 /* need to set to zero to avoid false matches if another
1896 #ifndef at middle of file */
1897 file->ifndef_macro = 0;
1898 while (tok != TOK_LINEFEED)
1899 next_nomacro();
1900 tok_flags |= TOK_FLAG_ENDIF;
1901 goto the_end;
1903 break;
1904 case TOK_PPNUM:
1905 n = strtoul((char*)tokc.str.data, &q, 10);
1906 goto _line_num;
1907 case TOK_LINE:
1908 next();
1909 if (tok != TOK_CINT)
1910 _line_err:
1911 tcc_error("wrong #line format");
1912 n = tokc.i;
1913 _line_num:
1914 next();
1915 if (tok != TOK_LINEFEED) {
1916 if (tok == TOK_STR)
1917 pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.str.data);
1918 else if (parse_flags & PARSE_FLAG_ASM_FILE)
1919 break;
1920 else
1921 goto _line_err;
1922 --n;
1924 if (file->fd > 0)
1925 total_lines += file->line_num - n;
1926 file->line_num = n;
1927 if (s1->do_debug)
1928 put_stabs(file->filename, N_BINCL, 0, 0, 0);
1929 break;
1930 case TOK_ERROR:
1931 case TOK_WARNING:
1932 c = tok;
1933 ch = file->buf_ptr[0];
1934 skip_spaces();
1935 q = buf;
1936 while (ch != '\n' && ch != CH_EOF) {
1937 if ((q - buf) < sizeof(buf) - 1)
1938 *q++ = ch;
1939 if (ch == '\\') {
1940 if (handle_stray_noerror() == 0)
1941 --q;
1942 } else
1943 inp();
1945 *q = '\0';
1946 if (c == TOK_ERROR)
1947 tcc_error("#error %s", buf);
1948 else
1949 tcc_warning("#warning %s", buf);
1950 break;
1951 case TOK_PRAGMA:
1952 pragma_parse(s1);
1953 break;
1954 case TOK_LINEFEED:
1955 goto the_end;
1956 default:
1957 /* ignore gas line comment in an 'S' file. */
1958 if (saved_parse_flags & PARSE_FLAG_ASM_FILE)
1959 goto ignore;
1960 if (tok == '!' && is_bof)
1961 /* '!' is ignored at beginning to allow C scripts. */
1962 goto ignore;
1963 tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc));
1964 ignore:
1965 file->buf_ptr = parse_line_comment(file->buf_ptr - 1);
1966 goto the_end;
1968 /* ignore other preprocess commands or #! for C scripts */
1969 while (tok != TOK_LINEFEED)
1970 next_nomacro();
1971 the_end:
1972 parse_flags = saved_parse_flags;
1975 /* evaluate escape codes in a string. */
1976 static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long)
1978 int c, n;
1979 const uint8_t *p;
1981 p = buf;
1982 for(;;) {
1983 c = *p;
1984 if (c == '\0')
1985 break;
1986 if (c == '\\') {
1987 p++;
1988 /* escape */
1989 c = *p;
1990 switch(c) {
1991 case '0': case '1': case '2': case '3':
1992 case '4': case '5': case '6': case '7':
1993 /* at most three octal digits */
1994 n = c - '0';
1995 p++;
1996 c = *p;
1997 if (isoct(c)) {
1998 n = n * 8 + c - '0';
1999 p++;
2000 c = *p;
2001 if (isoct(c)) {
2002 n = n * 8 + c - '0';
2003 p++;
2006 c = n;
2007 goto add_char_nonext;
2008 case 'x':
2009 case 'u':
2010 case 'U':
2011 p++;
2012 n = 0;
2013 for(;;) {
2014 c = *p;
2015 if (c >= 'a' && c <= 'f')
2016 c = c - 'a' + 10;
2017 else if (c >= 'A' && c <= 'F')
2018 c = c - 'A' + 10;
2019 else if (isnum(c))
2020 c = c - '0';
2021 else
2022 break;
2023 n = n * 16 + c;
2024 p++;
2026 c = n;
2027 goto add_char_nonext;
2028 case 'a':
2029 c = '\a';
2030 break;
2031 case 'b':
2032 c = '\b';
2033 break;
2034 case 'f':
2035 c = '\f';
2036 break;
2037 case 'n':
2038 c = '\n';
2039 break;
2040 case 'r':
2041 c = '\r';
2042 break;
2043 case 't':
2044 c = '\t';
2045 break;
2046 case 'v':
2047 c = '\v';
2048 break;
2049 case 'e':
2050 if (!gnu_ext)
2051 goto invalid_escape;
2052 c = 27;
2053 break;
2054 case '\'':
2055 case '\"':
2056 case '\\':
2057 case '?':
2058 break;
2059 default:
2060 invalid_escape:
2061 if (c >= '!' && c <= '~')
2062 tcc_warning("unknown escape sequence: \'\\%c\'", c);
2063 else
2064 tcc_warning("unknown escape sequence: \'\\x%x\'", c);
2065 break;
2068 p++;
2069 add_char_nonext:
2070 if (!is_long)
2071 cstr_ccat(outstr, c);
2072 else
2073 cstr_wccat(outstr, c);
2075 /* add a trailing '\0' */
2076 if (!is_long)
2077 cstr_ccat(outstr, '\0');
2078 else
2079 cstr_wccat(outstr, '\0');
2082 static void parse_string(const char *s, int len)
2084 uint8_t buf[1000], *p = buf;
2085 int is_long, sep;
2087 if ((is_long = *s == 'L'))
2088 ++s, --len;
2089 sep = *s++;
2090 len -= 2;
2091 if (len >= sizeof buf)
2092 p = tcc_malloc(len + 1);
2093 memcpy(p, s, len);
2094 p[len] = 0;
2096 cstr_reset(&tokcstr);
2097 parse_escape_string(&tokcstr, p, is_long);
2098 if (p != buf)
2099 tcc_free(p);
2101 if (sep == '\'') {
2102 int char_size;
2103 /* XXX: make it portable */
2104 if (!is_long)
2105 char_size = 1;
2106 else
2107 char_size = sizeof(nwchar_t);
2108 if (tokcstr.size <= char_size)
2109 tcc_error("empty character constant");
2110 if (tokcstr.size > 2 * char_size)
2111 tcc_warning("multi-character character constant");
2112 if (!is_long) {
2113 tokc.i = *(int8_t *)tokcstr.data;
2114 tok = TOK_CCHAR;
2115 } else {
2116 tokc.i = *(nwchar_t *)tokcstr.data;
2117 tok = TOK_LCHAR;
2119 } else {
2120 tokc.str.size = tokcstr.size;
2121 tokc.str.data = tokcstr.data;
2122 if (!is_long)
2123 tok = TOK_STR;
2124 else
2125 tok = TOK_LSTR;
2129 /* we use 64 bit numbers */
2130 #define BN_SIZE 2
2132 /* bn = (bn << shift) | or_val */
2133 static void bn_lshift(unsigned int *bn, int shift, int or_val)
2135 int i;
2136 unsigned int v;
2137 for(i=0;i<BN_SIZE;i++) {
2138 v = bn[i];
2139 bn[i] = (v << shift) | or_val;
2140 or_val = v >> (32 - shift);
2144 static void bn_zero(unsigned int *bn)
2146 int i;
2147 for(i=0;i<BN_SIZE;i++) {
2148 bn[i] = 0;
2152 /* parse number in null terminated string 'p' and return it in the
2153 current token */
2154 static void parse_number(const char *p)
2156 int b, t, shift, frac_bits, s, exp_val, ch;
2157 char *q;
2158 unsigned int bn[BN_SIZE];
2159 double d;
2161 /* number */
2162 q = token_buf;
2163 ch = *p++;
2164 t = ch;
2165 ch = *p++;
2166 *q++ = t;
2167 b = 10;
2168 if (t == '.') {
2169 goto float_frac_parse;
2170 } else if (t == '0') {
2171 if (ch == 'x' || ch == 'X') {
2172 q--;
2173 ch = *p++;
2174 b = 16;
2175 } else if (tcc_ext && (ch == 'b' || ch == 'B')) {
2176 q--;
2177 ch = *p++;
2178 b = 2;
2181 /* parse all digits. cannot check octal numbers at this stage
2182 because of floating point constants */
2183 while (1) {
2184 if (ch >= 'a' && ch <= 'f')
2185 t = ch - 'a' + 10;
2186 else if (ch >= 'A' && ch <= 'F')
2187 t = ch - 'A' + 10;
2188 else if (isnum(ch))
2189 t = ch - '0';
2190 else
2191 break;
2192 if (t >= b)
2193 break;
2194 if (q >= token_buf + STRING_MAX_SIZE) {
2195 num_too_long:
2196 tcc_error("number too long");
2198 *q++ = ch;
2199 ch = *p++;
2201 if (ch == '.' ||
2202 ((ch == 'e' || ch == 'E') && b == 10) ||
2203 ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) {
2204 if (b != 10) {
2205 /* NOTE: strtox should support that for hexa numbers, but
2206 non ISOC99 libcs do not support it, so we prefer to do
2207 it by hand */
2208 /* hexadecimal or binary floats */
2209 /* XXX: handle overflows */
2210 *q = '\0';
2211 if (b == 16)
2212 shift = 4;
2213 else
2214 shift = 1;
2215 bn_zero(bn);
2216 q = token_buf;
2217 while (1) {
2218 t = *q++;
2219 if (t == '\0') {
2220 break;
2221 } else if (t >= 'a') {
2222 t = t - 'a' + 10;
2223 } else if (t >= 'A') {
2224 t = t - 'A' + 10;
2225 } else {
2226 t = t - '0';
2228 bn_lshift(bn, shift, t);
2230 frac_bits = 0;
2231 if (ch == '.') {
2232 ch = *p++;
2233 while (1) {
2234 t = ch;
2235 if (t >= 'a' && t <= 'f') {
2236 t = t - 'a' + 10;
2237 } else if (t >= 'A' && t <= 'F') {
2238 t = t - 'A' + 10;
2239 } else if (t >= '0' && t <= '9') {
2240 t = t - '0';
2241 } else {
2242 break;
2244 if (t >= b)
2245 tcc_error("invalid digit");
2246 bn_lshift(bn, shift, t);
2247 frac_bits += shift;
2248 ch = *p++;
2251 if (ch != 'p' && ch != 'P')
2252 expect("exponent");
2253 ch = *p++;
2254 s = 1;
2255 exp_val = 0;
2256 if (ch == '+') {
2257 ch = *p++;
2258 } else if (ch == '-') {
2259 s = -1;
2260 ch = *p++;
2262 if (ch < '0' || ch > '9')
2263 expect("exponent digits");
2264 while (ch >= '0' && ch <= '9') {
2265 exp_val = exp_val * 10 + ch - '0';
2266 ch = *p++;
2268 exp_val = exp_val * s;
2270 /* now we can generate the number */
2271 /* XXX: should patch directly float number */
2272 d = (double)bn[1] * 4294967296.0 + (double)bn[0];
2273 d = ldexp(d, exp_val - frac_bits);
2274 t = toup(ch);
2275 if (t == 'F') {
2276 ch = *p++;
2277 tok = TOK_CFLOAT;
2278 /* float : should handle overflow */
2279 tokc.f = (float)d;
2280 } else if (t == 'L') {
2281 ch = *p++;
2282 #ifdef TCC_TARGET_PE
2283 tok = TOK_CDOUBLE;
2284 tokc.d = d;
2285 #else
2286 tok = TOK_CLDOUBLE;
2287 /* XXX: not large enough */
2288 tokc.ld = (long double)d;
2289 #endif
2290 } else {
2291 tok = TOK_CDOUBLE;
2292 tokc.d = d;
2294 } else {
2295 /* decimal floats */
2296 if (ch == '.') {
2297 if (q >= token_buf + STRING_MAX_SIZE)
2298 goto num_too_long;
2299 *q++ = ch;
2300 ch = *p++;
2301 float_frac_parse:
2302 while (ch >= '0' && ch <= '9') {
2303 if (q >= token_buf + STRING_MAX_SIZE)
2304 goto num_too_long;
2305 *q++ = ch;
2306 ch = *p++;
2309 if (ch == 'e' || ch == 'E') {
2310 if (q >= token_buf + STRING_MAX_SIZE)
2311 goto num_too_long;
2312 *q++ = ch;
2313 ch = *p++;
2314 if (ch == '-' || ch == '+') {
2315 if (q >= token_buf + STRING_MAX_SIZE)
2316 goto num_too_long;
2317 *q++ = ch;
2318 ch = *p++;
2320 if (ch < '0' || ch > '9')
2321 expect("exponent digits");
2322 while (ch >= '0' && ch <= '9') {
2323 if (q >= token_buf + STRING_MAX_SIZE)
2324 goto num_too_long;
2325 *q++ = ch;
2326 ch = *p++;
2329 *q = '\0';
2330 t = toup(ch);
2331 errno = 0;
2332 if (t == 'F') {
2333 ch = *p++;
2334 tok = TOK_CFLOAT;
2335 tokc.f = strtof(token_buf, NULL);
2336 } else if (t == 'L') {
2337 ch = *p++;
2338 #ifdef TCC_TARGET_PE
2339 tok = TOK_CDOUBLE;
2340 tokc.d = strtod(token_buf, NULL);
2341 #else
2342 tok = TOK_CLDOUBLE;
2343 tokc.ld = strtold(token_buf, NULL);
2344 #endif
2345 } else {
2346 tok = TOK_CDOUBLE;
2347 tokc.d = strtod(token_buf, NULL);
2350 } else {
2351 unsigned long long n, n1;
2352 int lcount, ucount, must_64bit;
2353 const char *p1;
2355 /* integer number */
2356 *q = '\0';
2357 q = token_buf;
2358 if (b == 10 && *q == '0') {
2359 b = 8;
2360 q++;
2362 n = 0;
2363 while(1) {
2364 t = *q++;
2365 /* no need for checks except for base 10 / 8 errors */
2366 if (t == '\0')
2367 break;
2368 else if (t >= 'a')
2369 t = t - 'a' + 10;
2370 else if (t >= 'A')
2371 t = t - 'A' + 10;
2372 else
2373 t = t - '0';
2374 if (t >= b)
2375 tcc_error("invalid digit");
2376 n1 = n;
2377 n = n * b + t;
2378 /* detect overflow */
2379 /* XXX: this test is not reliable */
2380 if (n < n1)
2381 tcc_error("integer constant overflow");
2384 /* Determine the characteristics (unsigned and/or 64bit) the type of
2385 the constant must have according to the constant suffix(es) */
2386 lcount = ucount = must_64bit = 0;
2387 p1 = p;
2388 for(;;) {
2389 t = toup(ch);
2390 if (t == 'L') {
2391 if (lcount >= 2)
2392 tcc_error("three 'l's in integer constant");
2393 if (lcount && *(p - 1) != ch)
2394 tcc_error("incorrect integer suffix: %s", p1);
2395 lcount++;
2396 #if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
2397 if (lcount == 2)
2398 #endif
2399 must_64bit = 1;
2400 ch = *p++;
2401 } else if (t == 'U') {
2402 if (ucount >= 1)
2403 tcc_error("two 'u's in integer constant");
2404 ucount++;
2405 ch = *p++;
2406 } else {
2407 break;
2411 /* Whether 64 bits are needed to hold the constant's value */
2412 if (n & 0xffffffff00000000LL || must_64bit) {
2413 tok = TOK_CLLONG;
2414 n1 = n >> 32;
2415 } else {
2416 tok = TOK_CINT;
2417 n1 = n;
2420 /* Whether type must be unsigned to hold the constant's value */
2421 if (ucount || ((n1 >> 31) && (b != 10))) {
2422 if (tok == TOK_CLLONG)
2423 tok = TOK_CULLONG;
2424 else
2425 tok = TOK_CUINT;
2426 /* If decimal and no unsigned suffix, bump to 64 bits or throw error */
2427 } else if (n1 >> 31) {
2428 if (tok == TOK_CINT)
2429 tok = TOK_CLLONG;
2430 else
2431 tcc_error("integer constant overflow");
2434 tokc.i = n;
2436 if (ch)
2437 tcc_error("invalid number\n");
2441 #define PARSE2(c1, tok1, c2, tok2) \
2442 case c1: \
2443 PEEKC(c, p); \
2444 if (c == c2) { \
2445 p++; \
2446 tok = tok2; \
2447 } else { \
2448 tok = tok1; \
2450 break;
2452 /* return next token without macro substitution */
2453 static inline void next_nomacro1(void)
2455 int t, c, is_long, len;
2456 TokenSym *ts;
2457 uint8_t *p, *p1;
2458 unsigned int h;
2460 p = file->buf_ptr;
2461 redo_no_start:
2462 c = *p;
2463 switch(c) {
2464 case ' ':
2465 case '\t':
2466 tok = c;
2467 p++;
2468 if (parse_flags & PARSE_FLAG_SPACES)
2469 goto keep_tok_flags;
2470 while (isidnum_table[*p - CH_EOF] & IS_SPC)
2471 ++p;
2472 goto redo_no_start;
2473 case '\f':
2474 case '\v':
2475 case '\r':
2476 p++;
2477 goto redo_no_start;
2478 case '\\':
2479 /* first look if it is in fact an end of buffer */
2480 c = handle_stray1(p);
2481 p = file->buf_ptr;
2482 if (c == '\\')
2483 goto parse_simple;
2484 if (c != CH_EOF)
2485 goto redo_no_start;
2487 TCCState *s1 = tcc_state;
2488 if ((parse_flags & PARSE_FLAG_LINEFEED)
2489 && !(tok_flags & TOK_FLAG_EOF)) {
2490 tok_flags |= TOK_FLAG_EOF;
2491 tok = TOK_LINEFEED;
2492 goto keep_tok_flags;
2493 } else if (!(parse_flags & PARSE_FLAG_PREPROCESS)) {
2494 tok = TOK_EOF;
2495 } else if (s1->ifdef_stack_ptr != file->ifdef_stack_ptr) {
2496 tcc_error("missing #endif");
2497 } else if (s1->include_stack_ptr == s1->include_stack) {
2498 /* no include left : end of file. */
2499 tok = TOK_EOF;
2500 } else {
2501 tok_flags &= ~TOK_FLAG_EOF;
2502 /* pop include file */
2504 /* test if previous '#endif' was after a #ifdef at
2505 start of file */
2506 if (tok_flags & TOK_FLAG_ENDIF) {
2507 #ifdef INC_DEBUG
2508 printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL));
2509 #endif
2510 search_cached_include(s1, file->filename, 1)
2511 ->ifndef_macro = file->ifndef_macro_saved;
2512 tok_flags &= ~TOK_FLAG_ENDIF;
2515 /* add end of include file debug info */
2516 if (tcc_state->do_debug) {
2517 put_stabd(N_EINCL, 0, 0);
2519 /* pop include stack */
2520 tcc_close();
2521 s1->include_stack_ptr--;
2522 p = file->buf_ptr;
2523 goto redo_no_start;
2526 break;
2528 case '\n':
2529 file->line_num++;
2530 tok_flags |= TOK_FLAG_BOL;
2531 p++;
2532 maybe_newline:
2533 if (0 == (parse_flags & PARSE_FLAG_LINEFEED))
2534 goto redo_no_start;
2535 tok = TOK_LINEFEED;
2536 goto keep_tok_flags;
2538 case '#':
2539 /* XXX: simplify */
2540 PEEKC(c, p);
2541 if ((tok_flags & TOK_FLAG_BOL) &&
2542 (parse_flags & PARSE_FLAG_PREPROCESS)) {
2543 file->buf_ptr = p;
2544 preprocess(tok_flags & TOK_FLAG_BOF);
2545 p = file->buf_ptr;
2546 goto maybe_newline;
2547 } else {
2548 if (c == '#') {
2549 p++;
2550 tok = TOK_TWOSHARPS;
2551 } else {
2552 if (parse_flags & PARSE_FLAG_ASM_FILE) {
2553 p = parse_line_comment(p - 1);
2554 goto redo_no_start;
2555 } else {
2556 tok = '#';
2560 break;
2562 /* dollar is allowed to start identifiers when not parsing asm */
2563 case '$':
2564 if (!(isidnum_table[c - CH_EOF] & IS_ID)
2565 || (parse_flags & PARSE_FLAG_ASM_FILE))
2566 goto parse_simple;
2568 case 'a': case 'b': case 'c': case 'd':
2569 case 'e': case 'f': case 'g': case 'h':
2570 case 'i': case 'j': case 'k': case 'l':
2571 case 'm': case 'n': case 'o': case 'p':
2572 case 'q': case 'r': case 's': case 't':
2573 case 'u': case 'v': case 'w': case 'x':
2574 case 'y': case 'z':
2575 case 'A': case 'B': case 'C': case 'D':
2576 case 'E': case 'F': case 'G': case 'H':
2577 case 'I': case 'J': case 'K':
2578 case 'M': case 'N': case 'O': case 'P':
2579 case 'Q': case 'R': case 'S': case 'T':
2580 case 'U': case 'V': case 'W': case 'X':
2581 case 'Y': case 'Z':
2582 case '_':
2583 parse_ident_fast:
2584 p1 = p;
2585 h = TOK_HASH_INIT;
2586 h = TOK_HASH_FUNC(h, c);
2587 while (c = *++p, isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
2588 h = TOK_HASH_FUNC(h, c);
2589 len = p - p1;
2590 if (c != '\\') {
2591 TokenSym **pts;
2593 /* fast case : no stray found, so we have the full token
2594 and we have already hashed it */
2595 h &= (TOK_HASH_SIZE - 1);
2596 pts = &hash_ident[h];
2597 for(;;) {
2598 ts = *pts;
2599 if (!ts)
2600 break;
2601 if (ts->len == len && !memcmp(ts->str, p1, len))
2602 goto token_found;
2603 pts = &(ts->hash_next);
2605 ts = tok_alloc_new(pts, (char *) p1, len);
2606 token_found: ;
2607 } else {
2608 /* slower case */
2609 cstr_reset(&tokcstr);
2610 cstr_cat(&tokcstr, p1, len);
2611 p--;
2612 PEEKC(c, p);
2613 parse_ident_slow:
2614 while (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
2616 cstr_ccat(&tokcstr, c);
2617 PEEKC(c, p);
2619 ts = tok_alloc(tokcstr.data, tokcstr.size);
2621 tok = ts->tok;
2622 break;
2623 case 'L':
2624 t = p[1];
2625 if (t != '\\' && t != '\'' && t != '\"') {
2626 /* fast case */
2627 goto parse_ident_fast;
2628 } else {
2629 PEEKC(c, p);
2630 if (c == '\'' || c == '\"') {
2631 is_long = 1;
2632 goto str_const;
2633 } else {
2634 cstr_reset(&tokcstr);
2635 cstr_ccat(&tokcstr, 'L');
2636 goto parse_ident_slow;
2639 break;
2641 case '0': case '1': case '2': case '3':
2642 case '4': case '5': case '6': case '7':
2643 case '8': case '9':
2644 t = c;
2645 PEEKC(c, p);
2646 /* after the first digit, accept digits, alpha, '.' or sign if
2647 prefixed by 'eEpP' */
2648 parse_num:
2649 cstr_reset(&tokcstr);
2650 for(;;) {
2651 cstr_ccat(&tokcstr, t);
2652 if (!((isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
2653 || c == '.'
2654 || ((c == '+' || c == '-')
2655 && (((t == 'e' || t == 'E')
2656 && !(parse_flags & PARSE_FLAG_ASM_FILE
2657 /* 0xe+1 is 3 tokens in asm */
2658 && ((char*)tokcstr.data)[0] == '0'
2659 && toup(((char*)tokcstr.data)[1]) == 'X'))
2660 || t == 'p' || t == 'P'))))
2661 break;
2662 t = c;
2663 PEEKC(c, p);
2665 /* We add a trailing '\0' to ease parsing */
2666 cstr_ccat(&tokcstr, '\0');
2667 tokc.str.size = tokcstr.size;
2668 tokc.str.data = tokcstr.data;
2669 tok = TOK_PPNUM;
2670 break;
2672 case '.':
2673 /* special dot handling because it can also start a number */
2674 PEEKC(c, p);
2675 if (isnum(c)) {
2676 t = '.';
2677 goto parse_num;
2678 } else if ((parse_flags & PARSE_FLAG_ASM_FILE)
2679 && (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))) {
2680 *--p = c = '.';
2681 goto parse_ident_fast;
2682 } else if (c == '.') {
2683 PEEKC(c, p);
2684 if (c == '.') {
2685 p++;
2686 tok = TOK_DOTS;
2687 } else {
2688 *--p = '.'; /* may underflow into file->unget[] */
2689 tok = '.';
2691 } else {
2692 tok = '.';
2694 break;
2695 case '\'':
2696 case '\"':
2697 is_long = 0;
2698 str_const:
2699 cstr_reset(&tokcstr);
2700 if (is_long)
2701 cstr_ccat(&tokcstr, 'L');
2702 cstr_ccat(&tokcstr, c);
2703 p = parse_pp_string(p, c, &tokcstr);
2704 cstr_ccat(&tokcstr, c);
2705 cstr_ccat(&tokcstr, '\0');
2706 tokc.str.size = tokcstr.size;
2707 tokc.str.data = tokcstr.data;
2708 tok = TOK_PPSTR;
2709 break;
2711 case '<':
2712 PEEKC(c, p);
2713 if (c == '=') {
2714 p++;
2715 tok = TOK_LE;
2716 } else if (c == '<') {
2717 PEEKC(c, p);
2718 if (c == '=') {
2719 p++;
2720 tok = TOK_A_SHL;
2721 } else {
2722 tok = TOK_SHL;
2724 } else {
2725 tok = TOK_LT;
2727 break;
2728 case '>':
2729 PEEKC(c, p);
2730 if (c == '=') {
2731 p++;
2732 tok = TOK_GE;
2733 } else if (c == '>') {
2734 PEEKC(c, p);
2735 if (c == '=') {
2736 p++;
2737 tok = TOK_A_SAR;
2738 } else {
2739 tok = TOK_SAR;
2741 } else {
2742 tok = TOK_GT;
2744 break;
2746 case '&':
2747 PEEKC(c, p);
2748 if (c == '&') {
2749 p++;
2750 tok = TOK_LAND;
2751 } else if (c == '=') {
2752 p++;
2753 tok = TOK_A_AND;
2754 } else {
2755 tok = '&';
2757 break;
2759 case '|':
2760 PEEKC(c, p);
2761 if (c == '|') {
2762 p++;
2763 tok = TOK_LOR;
2764 } else if (c == '=') {
2765 p++;
2766 tok = TOK_A_OR;
2767 } else {
2768 tok = '|';
2770 break;
2772 case '+':
2773 PEEKC(c, p);
2774 if (c == '+') {
2775 p++;
2776 tok = TOK_INC;
2777 } else if (c == '=') {
2778 p++;
2779 tok = TOK_A_ADD;
2780 } else {
2781 tok = '+';
2783 break;
2785 case '-':
2786 PEEKC(c, p);
2787 if (c == '-') {
2788 p++;
2789 tok = TOK_DEC;
2790 } else if (c == '=') {
2791 p++;
2792 tok = TOK_A_SUB;
2793 } else if (c == '>') {
2794 p++;
2795 tok = TOK_ARROW;
2796 } else {
2797 tok = '-';
2799 break;
2801 PARSE2('!', '!', '=', TOK_NE)
2802 PARSE2('=', '=', '=', TOK_EQ)
2803 PARSE2('*', '*', '=', TOK_A_MUL)
2804 PARSE2('%', '%', '=', TOK_A_MOD)
2805 PARSE2('^', '^', '=', TOK_A_XOR)
2807 /* comments or operator */
2808 case '/':
2809 PEEKC(c, p);
2810 if (c == '*') {
2811 p = parse_comment(p);
2812 /* comments replaced by a blank */
2813 tok = ' ';
2814 goto keep_tok_flags;
2815 } else if (c == '/') {
2816 p = parse_line_comment(p);
2817 tok = ' ';
2818 goto keep_tok_flags;
2819 } else if (c == '=') {
2820 p++;
2821 tok = TOK_A_DIV;
2822 } else {
2823 tok = '/';
2825 break;
2827 /* simple tokens */
2828 case '(':
2829 case ')':
2830 case '[':
2831 case ']':
2832 case '{':
2833 case '}':
2834 case ',':
2835 case ';':
2836 case ':':
2837 case '?':
2838 case '~':
2839 case '@': /* only used in assembler */
2840 parse_simple:
2841 tok = c;
2842 p++;
2843 break;
2844 default:
2845 if (c >= 0x80 && c <= 0xFF) /* utf8 identifiers */
2846 goto parse_ident_fast;
2847 if (parse_flags & PARSE_FLAG_ASM_FILE)
2848 goto parse_simple;
2849 tcc_error("unrecognized character \\x%02x", c);
2850 break;
2852 tok_flags = 0;
2853 keep_tok_flags:
2854 file->buf_ptr = p;
2855 #if defined(PARSE_DEBUG)
2856 printf("token = %s\n", get_tok_str(tok, &tokc));
2857 #endif
2860 /* return next token without macro substitution. Can read input from
2861 macro_ptr buffer */
2862 static void next_nomacro_spc(void)
2864 if (macro_ptr) {
2865 redo:
2866 tok = *macro_ptr;
2867 if (tok) {
2868 TOK_GET(&tok, &macro_ptr, &tokc);
2869 if (tok == TOK_LINENUM) {
2870 file->line_num = tokc.i;
2871 goto redo;
2874 } else {
2875 next_nomacro1();
2879 ST_FUNC void next_nomacro(void)
2881 do {
2882 next_nomacro_spc();
2883 } while (tok < 256 && (isidnum_table[tok - CH_EOF] & IS_SPC));
2887 static void macro_subst(
2888 TokenString *tok_str,
2889 Sym **nested_list,
2890 const int *macro_str,
2891 int can_read_stream
2894 /* substitute arguments in replacement lists in macro_str by the values in
2895 args (field d) and return allocated string */
2896 static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args)
2898 int t, t0, t1, spc;
2899 const int *st;
2900 Sym *s;
2901 CValue cval;
2902 TokenString str;
2903 CString cstr;
2905 tok_str_new(&str);
2906 t0 = t1 = 0;
2907 while(1) {
2908 TOK_GET(&t, &macro_str, &cval);
2909 if (!t)
2910 break;
2911 if (t == '#') {
2912 /* stringize */
2913 TOK_GET(&t, &macro_str, &cval);
2914 if (!t)
2915 goto bad_stringy;
2916 s = sym_find2(args, t);
2917 if (s) {
2918 cstr_new(&cstr);
2919 cstr_ccat(&cstr, '\"');
2920 st = s->d;
2921 spc = 0;
2922 while (*st) {
2923 TOK_GET(&t, &st, &cval);
2924 if (t != TOK_PLCHLDR
2925 && t != TOK_NOSUBST
2926 && 0 == check_space(t, &spc)) {
2927 const char *s = get_tok_str(t, &cval);
2928 while (*s) {
2929 if (t == TOK_PPSTR && *s != '\'')
2930 add_char(&cstr, *s);
2931 else
2932 cstr_ccat(&cstr, *s);
2933 ++s;
2937 cstr.size -= spc;
2938 cstr_ccat(&cstr, '\"');
2939 cstr_ccat(&cstr, '\0');
2940 #ifdef PP_DEBUG
2941 printf("\nstringize: <%s>\n", (char *)cstr.data);
2942 #endif
2943 /* add string */
2944 cval.str.size = cstr.size;
2945 cval.str.data = cstr.data;
2946 tok_str_add2(&str, TOK_PPSTR, &cval);
2947 cstr_free(&cstr);
2948 } else {
2949 bad_stringy:
2950 expect("macro parameter after '#'");
2952 } else if (t >= TOK_IDENT) {
2953 s = sym_find2(args, t);
2954 if (s) {
2955 int l0 = str.len;
2956 st = s->d;
2957 /* if '##' is present before or after, no arg substitution */
2958 if (*macro_str == TOK_TWOSHARPS || t1 == TOK_TWOSHARPS) {
2959 /* special case for var arg macros : ## eats the ','
2960 if empty VA_ARGS variable. */
2961 if (t1 == TOK_TWOSHARPS && t0 == ',' && gnu_ext && s->type.t) {
2962 if (*st == 0) {
2963 /* suppress ',' '##' */
2964 str.len -= 2;
2965 } else {
2966 /* suppress '##' and add variable */
2967 str.len--;
2968 goto add_var;
2970 } else {
2971 for(;;) {
2972 int t1;
2973 TOK_GET(&t1, &st, &cval);
2974 if (!t1)
2975 break;
2976 tok_str_add2(&str, t1, &cval);
2980 } else {
2981 add_var:
2982 /* NOTE: the stream cannot be read when macro
2983 substituing an argument */
2984 macro_subst(&str, nested_list, st, 0);
2986 if (str.len == l0) /* exanded to empty string */
2987 tok_str_add(&str, TOK_PLCHLDR);
2988 } else {
2989 tok_str_add(&str, t);
2991 } else {
2992 tok_str_add2(&str, t, &cval);
2994 t0 = t1, t1 = t;
2996 tok_str_add(&str, 0);
2997 return str.str;
3000 static char const ab_month_name[12][4] =
3002 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3003 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
3006 /* peek or read [ws_str == NULL] next token from function macro call,
3007 walking up macro levels up to the file if necessary */
3008 static int next_argstream(Sym **nested_list, int can_read_stream, TokenString *ws_str)
3010 int t;
3011 const int *p;
3012 Sym *sa;
3014 for (;;) {
3015 if (macro_ptr) {
3016 p = macro_ptr, t = *p;
3017 if (ws_str) {
3018 while (is_space(t) || TOK_LINEFEED == t)
3019 tok_str_add(ws_str, t), t = *++p;
3021 if (t == 0 && can_read_stream) {
3022 end_macro();
3023 /* also, end of scope for nested defined symbol */
3024 sa = *nested_list;
3025 while (sa && sa->v == 0)
3026 sa = sa->prev;
3027 if (sa)
3028 sa->v = 0;
3029 continue;
3031 } else {
3032 ch = handle_eob();
3033 if (ws_str) {
3034 while (is_space(ch) || ch == '\n' || ch == '/') {
3035 if (ch == '/') {
3036 int c;
3037 uint8_t *p = file->buf_ptr;
3038 PEEKC(c, p);
3039 if (c == '*') {
3040 p = parse_comment(p);
3041 file->buf_ptr = p - 1;
3042 } else if (c == '/') {
3043 p = parse_line_comment(p);
3044 file->buf_ptr = p - 1;
3045 } else
3046 break;
3047 ch = ' ';
3049 if (!(ch == '\f' || ch == '\v' || ch == '\r'))
3050 tok_str_add(ws_str, ch);
3051 cinp();
3054 t = ch;
3057 if (ws_str)
3058 return t;
3059 next_nomacro_spc();
3060 return tok;
3064 /* do macro substitution of current token with macro 's' and add
3065 result to (tok_str,tok_len). 'nested_list' is the list of all
3066 macros we got inside to avoid recursing. Return non zero if no
3067 substitution needs to be done */
3068 static int macro_subst_tok(
3069 TokenString *tok_str,
3070 Sym **nested_list,
3071 Sym *s,
3072 int can_read_stream)
3074 Sym *args, *sa, *sa1;
3075 int parlevel, *mstr, t, t1, spc;
3076 TokenString str;
3077 char *cstrval;
3078 CValue cval;
3079 CString cstr;
3080 char buf[32];
3082 /* if symbol is a macro, prepare substitution */
3083 /* special macros */
3084 if (tok == TOK___LINE__) {
3085 snprintf(buf, sizeof(buf), "%d", file->line_num);
3086 cstrval = buf;
3087 t1 = TOK_PPNUM;
3088 goto add_cstr1;
3089 } else if (tok == TOK___FILE__) {
3090 cstrval = file->filename;
3091 goto add_cstr;
3092 } else if (tok == TOK___DATE__ || tok == TOK___TIME__) {
3093 time_t ti;
3094 struct tm *tm;
3096 time(&ti);
3097 tm = localtime(&ti);
3098 if (tok == TOK___DATE__) {
3099 snprintf(buf, sizeof(buf), "%s %2d %d",
3100 ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900);
3101 } else {
3102 snprintf(buf, sizeof(buf), "%02d:%02d:%02d",
3103 tm->tm_hour, tm->tm_min, tm->tm_sec);
3105 cstrval = buf;
3106 add_cstr:
3107 t1 = TOK_STR;
3108 add_cstr1:
3109 cstr_new(&cstr);
3110 cstr_cat(&cstr, cstrval, 0);
3111 cval.str.size = cstr.size;
3112 cval.str.data = cstr.data;
3113 tok_str_add2(tok_str, t1, &cval);
3114 cstr_free(&cstr);
3115 } else {
3116 int saved_parse_flags = parse_flags;
3118 mstr = s->d;
3119 if (s->type.t == MACRO_FUNC) {
3120 /* whitespace between macro name and argument list */
3121 TokenString ws_str;
3122 tok_str_new(&ws_str);
3124 spc = 0;
3125 parse_flags |= PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED
3126 | PARSE_FLAG_ACCEPT_STRAYS;
3128 /* get next token from argument stream */
3129 t = next_argstream(nested_list, can_read_stream, &ws_str);
3130 if (t != '(') {
3131 /* not a macro substitution after all, restore the
3132 * macro token plus all whitespace we've read.
3133 * whitespace is intentionally not merged to preserve
3134 * newlines. */
3135 parse_flags = saved_parse_flags;
3136 tok_str_add(tok_str, tok);
3137 if (parse_flags & PARSE_FLAG_SPACES) {
3138 int i;
3139 for (i = 0; i < ws_str.len; i++)
3140 tok_str_add(tok_str, ws_str.str[i]);
3142 tok_str_free(ws_str.str);
3143 return 0;
3144 } else {
3145 tok_str_free(ws_str.str);
3147 next_nomacro(); /* eat '(' */
3149 /* argument macro */
3150 args = NULL;
3151 sa = s->next;
3152 /* NOTE: empty args are allowed, except if no args */
3153 for(;;) {
3154 do {
3155 next_argstream(nested_list, can_read_stream, NULL);
3156 } while (is_space(tok) || TOK_LINEFEED == tok);
3157 empty_arg:
3158 /* handle '()' case */
3159 if (!args && !sa && tok == ')')
3160 break;
3161 if (!sa)
3162 tcc_error("macro '%s' used with too many args",
3163 get_tok_str(s->v, 0));
3164 tok_str_new(&str);
3165 parlevel = spc = 0;
3166 /* NOTE: non zero sa->t indicates VA_ARGS */
3167 while ((parlevel > 0 ||
3168 (tok != ')' &&
3169 (tok != ',' || sa->type.t)))) {
3170 if (tok == TOK_EOF || tok == 0)
3171 break;
3172 if (tok == '(')
3173 parlevel++;
3174 else if (tok == ')')
3175 parlevel--;
3176 if (tok == TOK_LINEFEED)
3177 tok = ' ';
3178 if (!check_space(tok, &spc))
3179 tok_str_add2(&str, tok, &tokc);
3180 next_argstream(nested_list, can_read_stream, NULL);
3182 if (parlevel)
3183 expect(")");
3184 str.len -= spc;
3185 tok_str_add(&str, 0);
3186 sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0);
3187 sa1->d = str.str;
3188 sa = sa->next;
3189 if (tok == ')') {
3190 /* special case for gcc var args: add an empty
3191 var arg argument if it is omitted */
3192 if (sa && sa->type.t && gnu_ext)
3193 goto empty_arg;
3194 break;
3196 if (tok != ',')
3197 expect(",");
3199 if (sa) {
3200 tcc_error("macro '%s' used with too few args",
3201 get_tok_str(s->v, 0));
3204 parse_flags = saved_parse_flags;
3206 /* now subst each arg */
3207 mstr = macro_arg_subst(nested_list, mstr, args);
3208 /* free memory */
3209 sa = args;
3210 while (sa) {
3211 sa1 = sa->prev;
3212 tok_str_free(sa->d);
3213 sym_free(sa);
3214 sa = sa1;
3218 sym_push2(nested_list, s->v, 0, 0);
3219 parse_flags = saved_parse_flags;
3220 macro_subst(tok_str, nested_list, mstr, can_read_stream | 2);
3222 /* pop nested defined symbol */
3223 sa1 = *nested_list;
3224 *nested_list = sa1->prev;
3225 sym_free(sa1);
3226 if (mstr != s->d)
3227 tok_str_free(mstr);
3229 return 0;
3232 static int paste_tokens(int t1, CValue *v1, int t2, CValue *v2)
3234 CString cstr;
3235 int n, ret = 1;
3237 cstr_new(&cstr);
3238 if (t1 != TOK_PLCHLDR)
3239 cstr_cat(&cstr, get_tok_str(t1, v1), -1);
3240 n = cstr.size;
3241 if (t2 != TOK_PLCHLDR)
3242 cstr_cat(&cstr, get_tok_str(t2, v2), -1);
3243 cstr_ccat(&cstr, '\0');
3245 tcc_open_bf(tcc_state, ":paste:", cstr.size);
3246 memcpy(file->buffer, cstr.data, cstr.size);
3247 for (;;) {
3248 next_nomacro1();
3249 if (0 == *file->buf_ptr)
3250 break;
3251 if (is_space(tok))
3252 continue;
3253 tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid"
3254 " preprocessing token", n, cstr.data, (char*)cstr.data + n);
3255 ret = 0;
3256 break;
3258 tcc_close();
3259 //printf("paste <%s>\n", (char*)cstr.data);
3260 cstr_free(&cstr);
3261 return ret;
3264 /* handle the '##' operator. Return NULL if no '##' seen. Otherwise
3265 return the resulting string (which must be freed). */
3266 static inline int *macro_twosharps(const int *ptr0)
3268 int t;
3269 CValue cval;
3270 TokenString macro_str1;
3271 int start_of_nosubsts = -1;
3272 const int *ptr;
3274 /* we search the first '##' */
3275 for (ptr = ptr0;;) {
3276 TOK_GET(&t, &ptr, &cval);
3277 if (t == TOK_TWOSHARPS)
3278 break;
3279 if (t == 0)
3280 return NULL;
3283 tok_str_new(&macro_str1);
3285 //tok_print(" $$$", ptr0);
3286 for (ptr = ptr0;;) {
3287 TOK_GET(&t, &ptr, &cval);
3288 if (t == 0)
3289 break;
3290 if (t == TOK_TWOSHARPS)
3291 continue;
3292 while (*ptr == TOK_TWOSHARPS) {
3293 int t1; CValue cv1;
3294 /* given 'a##b', remove nosubsts preceding 'a' */
3295 if (start_of_nosubsts >= 0)
3296 macro_str1.len = start_of_nosubsts;
3297 /* given 'a##b', remove nosubsts preceding 'b' */
3298 while ((t1 = *++ptr) == TOK_NOSUBST)
3300 if (t1 && t1 != TOK_TWOSHARPS) {
3301 TOK_GET(&t1, &ptr, &cv1);
3302 if (t != TOK_PLCHLDR || t1 != TOK_PLCHLDR) {
3303 if (paste_tokens(t, &cval, t1, &cv1)) {
3304 t = tok, cval = tokc;
3305 } else {
3306 tok_str_add2(&macro_str1, t, &cval);
3307 t = t1, cval = cv1;
3312 if (t == TOK_NOSUBST) {
3313 if (start_of_nosubsts < 0)
3314 start_of_nosubsts = macro_str1.len;
3315 } else {
3316 start_of_nosubsts = -1;
3318 tok_str_add2(&macro_str1, t, &cval);
3320 tok_str_add(&macro_str1, 0);
3321 //tok_print(" ###", macro_str1.str);
3322 return macro_str1.str;
3325 /* do macro substitution of macro_str and add result to
3326 (tok_str,tok_len). 'nested_list' is the list of all macros we got
3327 inside to avoid recursing. */
3328 static void macro_subst(
3329 TokenString *tok_str,
3330 Sym **nested_list,
3331 const int *macro_str,
3332 int can_read_stream
3335 Sym *s;
3336 const int *ptr;
3337 int t, spc, nosubst;
3338 CValue cval;
3339 int *macro_str1 = NULL;
3341 /* first scan for '##' operator handling */
3342 ptr = macro_str;
3343 spc = nosubst = 0;
3345 /* first scan for '##' operator handling */
3346 if (can_read_stream & 1) {
3347 macro_str1 = macro_twosharps(ptr);
3348 if (macro_str1)
3349 ptr = macro_str1;
3352 while (1) {
3353 TOK_GET(&t, &ptr, &cval);
3354 if (t == 0)
3355 break;
3357 if (t >= TOK_IDENT && 0 == nosubst) {
3358 s = define_find(t);
3359 if (s == NULL)
3360 goto no_subst;
3362 /* if nested substitution, do nothing */
3363 if (sym_find2(*nested_list, t)) {
3364 /* and mark it as TOK_NOSUBST, so it doesn't get subst'd again */
3365 tok_str_add2(tok_str, TOK_NOSUBST, NULL);
3366 goto no_subst;
3370 TokenString str;
3371 str.str = (int*)ptr;
3372 begin_macro(&str, 2);
3374 tok = t;
3375 macro_subst_tok(tok_str, nested_list, s, can_read_stream);
3377 if (str.alloc == 3) {
3378 /* already finished by reading function macro arguments */
3379 break;
3382 ptr = macro_ptr;
3383 end_macro ();
3386 spc = (tok_str->len &&
3387 is_space(tok_last(tok_str->str,
3388 tok_str->str + tok_str->len)));
3390 } else {
3392 if (t == '\\' && !(parse_flags & PARSE_FLAG_ACCEPT_STRAYS))
3393 tcc_error("stray '\\' in program");
3395 no_subst:
3396 if (!check_space(t, &spc))
3397 tok_str_add2(tok_str, t, &cval);
3398 nosubst = 0;
3399 if (t == TOK_NOSUBST)
3400 nosubst = 1;
3403 if (macro_str1)
3404 tok_str_free(macro_str1);
3408 /* return next token with macro substitution */
3409 ST_FUNC void next(void)
3411 redo:
3412 if (parse_flags & PARSE_FLAG_SPACES)
3413 next_nomacro_spc();
3414 else
3415 next_nomacro();
3417 if (macro_ptr) {
3418 if (tok == TOK_NOSUBST || tok == TOK_PLCHLDR) {
3419 /* discard preprocessor markers */
3420 goto redo;
3421 } else if (tok == 0) {
3422 /* end of macro or unget token string */
3423 end_macro();
3424 goto redo;
3426 } else if (tok >= TOK_IDENT && (parse_flags & PARSE_FLAG_PREPROCESS)) {
3427 Sym *s;
3428 /* if reading from file, try to substitute macros */
3429 s = define_find(tok);
3430 if (s) {
3431 Sym *nested_list = NULL;
3432 tokstr_buf.len = 0;
3433 macro_subst_tok(&tokstr_buf, &nested_list, s, 1);
3434 tok_str_add(&tokstr_buf, 0);
3435 begin_macro(&tokstr_buf, 2);
3436 goto redo;
3439 /* convert preprocessor tokens into C tokens */
3440 if (tok == TOK_PPNUM) {
3441 if (parse_flags & PARSE_FLAG_TOK_NUM)
3442 parse_number((char *)tokc.str.data);
3443 } else if (tok == TOK_PPSTR) {
3444 if (parse_flags & PARSE_FLAG_TOK_STR)
3445 parse_string((char *)tokc.str.data, tokc.str.size - 1);
3449 /* push back current token and set current token to 'last_tok'. Only
3450 identifier case handled for labels. */
3451 ST_INLN void unget_tok(int last_tok)
3454 TokenString *str = tok_str_alloc();
3455 tok_str_add2(str, tok, &tokc);
3456 tok_str_add(str, 0);
3457 begin_macro(str, 1);
3458 tok = last_tok;
3461 ST_FUNC void preprocess_start(TCCState *s1)
3463 s1->include_stack_ptr = s1->include_stack;
3464 /* XXX: move that before to avoid having to initialize
3465 file->ifdef_stack_ptr ? */
3466 s1->ifdef_stack_ptr = s1->ifdef_stack;
3467 file->ifdef_stack_ptr = s1->ifdef_stack_ptr;
3468 pp_once++;
3470 pvtop = vtop = vstack - 1;
3471 s1->pack_stack[0] = 0;
3472 s1->pack_stack_ptr = s1->pack_stack;
3474 isidnum_table['$' - CH_EOF] =
3475 s1->dollars_in_identifiers ? IS_ID : 0;
3476 isidnum_table['.' - CH_EOF] =
3477 (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0;
3480 ST_FUNC void tccpp_new(TCCState *s)
3482 int i, c;
3483 const char *p, *r;
3485 /* might be used in error() before preprocess_start() */
3486 s->include_stack_ptr = s->include_stack;
3488 /* init isid table */
3489 for(i = CH_EOF; i<128; i++)
3490 isidnum_table[i - CH_EOF]
3491 = is_space(i) ? IS_SPC
3492 : isid(i) ? IS_ID
3493 : isnum(i) ? IS_NUM
3494 : 0;
3496 for(i = 128; i<256; i++)
3497 isidnum_table[i - CH_EOF] = IS_ID;
3499 /* init allocators */
3500 tal_new(&toksym_alloc, TOKSYM_TAL_LIMIT, TOKSYM_TAL_SIZE);
3501 tal_new(&tokstr_alloc, TOKSTR_TAL_LIMIT, TOKSTR_TAL_SIZE);
3502 tal_new(&cstr_alloc, CSTR_TAL_LIMIT, CSTR_TAL_SIZE);
3504 memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
3505 cstr_new(&cstr_buf);
3506 cstr_realloc(&cstr_buf, STRING_MAX_SIZE);
3507 tok_str_new(&tokstr_buf);
3508 tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE);
3510 tok_ident = TOK_IDENT;
3511 p = tcc_keywords;
3512 while (*p) {
3513 r = p;
3514 for(;;) {
3515 c = *r++;
3516 if (c == '\0')
3517 break;
3519 tok_alloc(p, r - p - 1);
3520 p = r;
3524 ST_FUNC void tccpp_delete(TCCState *s)
3526 int i, n;
3528 /* free -D and compiler defines */
3529 free_defines(NULL);
3531 /* cleanup from error/setjmp */
3532 while (macro_stack)
3533 end_macro();
3534 macro_ptr = NULL;
3536 /* free tokens */
3537 n = tok_ident - TOK_IDENT;
3538 for(i = 0; i < n; i++)
3539 tal_free(toksym_alloc, table_ident[i]);
3540 tcc_free(table_ident);
3541 table_ident = NULL;
3543 /* free static buffers */
3544 cstr_free(&tokcstr);
3545 cstr_free(&cstr_buf);
3546 tok_str_free(tokstr_buf.str);
3548 /* free allocators */
3549 tal_delete(toksym_alloc);
3550 toksym_alloc = NULL;
3551 tal_delete(tokstr_alloc);
3552 tokstr_alloc = NULL;
3553 tal_delete(cstr_alloc);
3554 cstr_alloc = NULL;
3557 /* ------------------------------------------------------------------------- */
3558 /* tcc -E [-P[1]] [-dD} support */
3560 static void tok_print(const char *msg, const int *str)
3562 FILE *fp;
3563 int t;
3564 CValue cval;
3566 fp = tcc_state->ppfp;
3567 if (!fp || !tcc_state->dflag)
3568 fp = stdout;
3570 fprintf(fp, "%s ", msg);
3571 while (str) {
3572 TOK_GET(&t, &str, &cval);
3573 if (!t)
3574 break;
3575 fprintf(fp,"%s", get_tok_str(t, &cval));
3577 fprintf(fp, "\n");
3580 static void pp_line(TCCState *s1, BufferedFile *f, int level)
3582 int d = f->line_num - f->line_ref;
3584 if (s1->dflag & 4)
3585 return;
3587 if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_NONE) {
3589 } else if (level == 0 && f->line_ref && d < 8) {
3590 while (d > 0)
3591 fputs("\n", s1->ppfp), --d;
3592 } else if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_STD) {
3593 fprintf(s1->ppfp, "#line %d \"%s\"\n", f->line_num, f->filename);
3594 } else {
3595 fprintf(s1->ppfp, "# %d \"%s\"%s\n", f->line_num, f->filename,
3596 level > 0 ? " 1" : level < 0 ? " 2" : "");
3598 f->line_ref = f->line_num;
3601 static void define_print(TCCState *s1, int v)
3603 FILE *fp;
3604 Sym *s;
3606 s = define_find(v);
3607 if (NULL == s || NULL == s->d)
3608 return;
3610 fp = s1->ppfp;
3611 fprintf(fp, "#define %s", get_tok_str(v, NULL));
3612 if (s->type.t == MACRO_FUNC) {
3613 Sym *a = s->next;
3614 fprintf(fp,"(");
3615 if (a)
3616 for (;;) {
3617 fprintf(fp,"%s", get_tok_str(a->v & ~SYM_FIELD, NULL));
3618 if (!(a = a->next))
3619 break;
3620 fprintf(fp,",");
3622 fprintf(fp,")");
3624 tok_print("", s->d);
3627 static void pp_debug_defines(TCCState *s1)
3629 int v, t;
3630 const char *vs;
3631 FILE *fp;
3633 t = pp_debug_tok;
3634 if (t == 0)
3635 return;
3637 file->line_num--;
3638 pp_line(s1, file, 0);
3639 file->line_ref = ++file->line_num;
3641 fp = s1->ppfp;
3642 v = pp_debug_symv;
3643 vs = get_tok_str(v, NULL);
3644 if (t == TOK_DEFINE) {
3645 define_print(s1, v);
3646 } else if (t == TOK_UNDEF) {
3647 fprintf(fp, "#undef %s\n", vs);
3648 } else if (t == TOK_push_macro) {
3649 fprintf(fp, "#pragma push_macro(\"%s\")\n", vs);
3650 } else if (t == TOK_pop_macro) {
3651 fprintf(fp, "#pragma pop_macro(\"%s\")\n", vs);
3653 pp_debug_tok = 0;
3656 static void pp_debug_builtins(TCCState *s1)
3658 int v;
3659 for (v = TOK_IDENT; v < tok_ident; ++v)
3660 define_print(s1, v);
3663 /* Add a space between tokens a and b to avoid unwanted textual pasting */
3664 static int pp_need_space(int a, int b)
3666 return 'E' == a ? '+' == b || '-' == b
3667 : '+' == a ? TOK_INC == b || '+' == b
3668 : '-' == a ? TOK_DEC == b || '-' == b
3669 : a >= TOK_IDENT ? b >= TOK_IDENT
3670 : 0;
3673 /* maybe hex like 0x1e */
3674 static int pp_check_he0xE(int t, const char *p)
3676 if (t == TOK_PPNUM && toup(strchr(p, 0)[-1]) == 'E')
3677 return 'E';
3678 return t;
3681 /* Preprocess the current file */
3682 ST_FUNC int tcc_preprocess(TCCState *s1)
3684 BufferedFile **iptr;
3685 int token_seen, spcs, level;
3686 const char *p;
3687 Sym *define_start;
3689 preprocess_start(s1);
3690 ch = file->buf_ptr[0];
3691 tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
3692 parse_flags = PARSE_FLAG_PREPROCESS
3693 | (parse_flags & PARSE_FLAG_ASM_FILE)
3694 | PARSE_FLAG_LINEFEED
3695 | PARSE_FLAG_SPACES
3696 | PARSE_FLAG_ACCEPT_STRAYS
3698 define_start = define_stack;
3700 /* Credits to Fabrice Bellard's initial revision to demonstrate its
3701 capability to compile and run itself, provided all numbers are
3702 given as decimals. tcc -E -P10 will do. */
3703 if (s1->Pflag == 1 + 10)
3704 parse_flags |= PARSE_FLAG_TOK_NUM, s1->Pflag = 1;
3706 #ifdef PP_BENCH
3707 /* for PP benchmarks */
3708 do next(); while (tok != TOK_EOF); return 0;
3709 #endif
3711 if (s1->dflag & 1) {
3712 pp_debug_builtins(s1);
3713 s1->dflag &= ~1;
3716 token_seen = TOK_LINEFEED, spcs = 0;
3717 pp_line(s1, file, 0);
3719 for (;;) {
3720 iptr = s1->include_stack_ptr;
3721 next();
3722 if (tok == TOK_EOF)
3723 break;
3724 level = s1->include_stack_ptr - iptr;
3725 if (level) {
3726 if (level > 0)
3727 pp_line(s1, *iptr, 0);
3728 pp_line(s1, file, level);
3731 if (s1->dflag) {
3732 pp_debug_defines(s1);
3733 if (s1->dflag & 4)
3734 continue;
3737 if (token_seen == TOK_LINEFEED) {
3738 if (tok == ' ') {
3739 ++spcs;
3740 continue;
3742 if (tok == TOK_LINEFEED) {
3743 spcs = 0;
3744 continue;
3746 pp_line(s1, file, 0);
3747 } else if (tok == TOK_LINEFEED) {
3748 ++file->line_ref;
3749 } else {
3750 spcs = pp_need_space(token_seen, tok);
3753 while (spcs)
3754 fputs(" ", s1->ppfp), --spcs;
3755 fputs(p = get_tok_str(tok, &tokc), s1->ppfp);
3756 token_seen = pp_check_he0xE(tok, p);;
3758 /* reset define stack, but keep -D and built-ins */
3759 free_defines(define_start);
3760 return 0;
3763 /* ------------------------------------------------------------------------- */