Relicensing TinyCC
[tinycc.git] / tccpp.c
1 /*
2  *  TCC - Tiny C Compiler
3  * 
4  *  Copyright (c) 2001-2004 Fabrice Bellard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "tcc.h"
22
23 /********************************************************/
24 /* global variables */
25
26 ST_DATA int tok_flags;
27 /* additional informations about token */
28 #define TOK_FLAG_BOL   0x0001 /* beginning of line before */
29 #define TOK_FLAG_BOF   0x0002 /* beginning of file before */
30 #define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */
31 #define TOK_FLAG_EOF   0x0008 /* end of file */
32
33 ST_DATA int parse_flags;
34 #define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */
35 #define PARSE_FLAG_TOK_NUM    0x0002 /* return numbers instead of TOK_PPNUM */
36 #define PARSE_FLAG_LINEFEED   0x0004 /* line feed is returned as a
37                                         token. line feed is also
38                                         returned at eof */
39 #define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */
40 #define PARSE_FLAG_SPACES     0x0010 /* next() returns space tokens (for -E) */
41
42 ST_DATA struct BufferedFile *file;
43 ST_DATA int ch, tok;
44 ST_DATA CValue tokc;
45 ST_DATA const int *macro_ptr;
46 ST_DATA CString tokcstr; /* current parsed string, if any */
47
48 /* display benchmark infos */
49 ST_DATA int total_lines;
50 ST_DATA int total_bytes;
51 ST_DATA int tok_ident;
52 ST_DATA TokenSym **table_ident;
53
54 /* ------------------------------------------------------------------------- */
55
56 static int *macro_ptr_allocated;
57 static const int *unget_saved_macro_ptr;
58 static int unget_saved_buffer[TOK_MAX_SIZE + 1];
59 static int unget_buffer_enabled;
60 static TokenSym *hash_ident[TOK_HASH_SIZE];
61 static char token_buf[STRING_MAX_SIZE + 1];
62 /* true if isid(c) || isnum(c) */
63 static unsigned char isidnum_table[256-CH_EOF];
64
65 static const char tcc_keywords[] = 
66 #define DEF(id, str) str "\0"
67 #include "tcctok.h"
68 #undef DEF
69 ;
70
71 /* WARNING: the content of this string encodes token numbers */
72 static const unsigned char tok_two_chars[] =
73     "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253"
74     "-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266";
75
76 struct macro_level {
77     struct macro_level *prev;
78     const int *p;
79 };
80
81 static void next_nomacro_spc(void);
82 static void macro_subst(
83     TokenString *tok_str,
84     Sym **nested_list,
85     const int *macro_str,
86     struct macro_level **can_read_stream
87     );
88
89 ST_FUNC void skip(int c)
90 {
91     if (tok != c)
92         tcc_error("'%c' expected (got \"%s\")", c, get_tok_str(tok, &tokc));
93     next();
94 }
95
96 ST_FUNC void expect(const char *msg)
97 {
98     tcc_error("%s expected", msg);
99 }
100
101 /* ------------------------------------------------------------------------- */
102 /* CString handling */
103 static void cstr_realloc(CString *cstr, int new_size)
104 {
105     int size;
106     void *data;
107
108     size = cstr->size_allocated;
109     if (size == 0)
110         size = 8; /* no need to allocate a too small first string */
111     while (size < new_size)
112         size = size * 2;
113     data = tcc_realloc(cstr->data_allocated, size);
114     cstr->data_allocated = data;
115     cstr->size_allocated = size;
116     cstr->data = data;
117 }
118
119 /* add a byte */
120 ST_FUNC void cstr_ccat(CString *cstr, int ch)
121 {
122     int size;
123     size = cstr->size + 1;
124     if (size > cstr->size_allocated)
125         cstr_realloc(cstr, size);
126     ((unsigned char *)cstr->data)[size - 1] = ch;
127     cstr->size = size;
128 }
129
130 ST_FUNC void cstr_cat(CString *cstr, const char *str)
131 {
132     int c;
133     for(;;) {
134         c = *str;
135         if (c == '\0')
136             break;
137         cstr_ccat(cstr, c);
138         str++;
139     }
140 }
141
142 /* add a wide char */
143 ST_FUNC void cstr_wccat(CString *cstr, int ch)
144 {
145     int size;
146     size = cstr->size + sizeof(nwchar_t);
147     if (size > cstr->size_allocated)
148         cstr_realloc(cstr, size);
149     *(nwchar_t *)(((unsigned char *)cstr->data) + size - sizeof(nwchar_t)) = ch;
150     cstr->size = size;
151 }
152
153 ST_FUNC void cstr_new(CString *cstr)
154 {
155     memset(cstr, 0, sizeof(CString));
156 }
157
158 /* free string and reset it to NULL */
159 ST_FUNC void cstr_free(CString *cstr)
160 {
161     tcc_free(cstr->data_allocated);
162     cstr_new(cstr);
163 }
164
165 /* reset string to empty */
166 ST_FUNC void cstr_reset(CString *cstr)
167 {
168     cstr->size = 0;
169 }
170
171 /* XXX: unicode ? */
172 static void add_char(CString *cstr, int c)
173 {
174     if (c == '\'' || c == '\"' || c == '\\') {
175         /* XXX: could be more precise if char or string */
176         cstr_ccat(cstr, '\\');
177     }
178     if (c >= 32 && c <= 126) {
179         cstr_ccat(cstr, c);
180     } else {
181         cstr_ccat(cstr, '\\');
182         if (c == '\n') {
183             cstr_ccat(cstr, 'n');
184         } else {
185             cstr_ccat(cstr, '0' + ((c >> 6) & 7));
186             cstr_ccat(cstr, '0' + ((c >> 3) & 7));
187             cstr_ccat(cstr, '0' + (c & 7));
188         }
189     }
190 }
191
192 /* ------------------------------------------------------------------------- */
193 /* allocate a new token */
194 static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len)
195 {
196     TokenSym *ts, **ptable;
197     int i;
198
199     if (tok_ident >= SYM_FIRST_ANOM) 
200         tcc_error("memory full");
201
202     /* expand token table if needed */
203     i = tok_ident - TOK_IDENT;
204     if ((i % TOK_ALLOC_INCR) == 0) {
205         ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *));
206         table_ident = ptable;
207     }
208
209     ts = tcc_malloc(sizeof(TokenSym) + len);
210     table_ident[i] = ts;
211     ts->tok = tok_ident++;
212     ts->sym_define = NULL;
213     ts->sym_label = NULL;
214     ts->sym_struct = NULL;
215     ts->sym_identifier = NULL;
216     ts->len = len;
217     ts->hash_next = NULL;
218     memcpy(ts->str, str, len);
219     ts->str[len] = '\0';
220     *pts = ts;
221     return ts;
222 }
223
224 #define TOK_HASH_INIT 1
225 #define TOK_HASH_FUNC(h, c) ((h) * 263 + (c))
226
227 /* find a token and add it if not found */
228 ST_FUNC TokenSym *tok_alloc(const char *str, int len)
229 {
230     TokenSym *ts, **pts;
231     int i;
232     unsigned int h;
233     
234     h = TOK_HASH_INIT;
235     for(i=0;i<len;i++)
236         h = TOK_HASH_FUNC(h, ((unsigned char *)str)[i]);
237     h &= (TOK_HASH_SIZE - 1);
238
239     pts = &hash_ident[h];
240     for(;;) {
241         ts = *pts;
242         if (!ts)
243             break;
244         if (ts->len == len && !memcmp(ts->str, str, len))
245             return ts;
246         pts = &(ts->hash_next);
247     }
248     return tok_alloc_new(pts, str, len);
249 }
250
251 /* XXX: buffer overflow */
252 /* XXX: float tokens */
253 ST_FUNC char *get_tok_str(int v, CValue *cv)
254 {
255     static char buf[STRING_MAX_SIZE + 1];
256     static CString cstr_buf;
257     CString *cstr;
258     char *p;
259     int i, len;
260
261     /* NOTE: to go faster, we give a fixed buffer for small strings */
262     cstr_reset(&cstr_buf);
263     cstr_buf.data = buf;
264     cstr_buf.size_allocated = sizeof(buf);
265     p = buf;
266
267     switch(v) {
268     case TOK_CINT:
269     case TOK_CUINT:
270         /* XXX: not quite exact, but only useful for testing */
271         sprintf(p, "%u", cv->ui);
272         break;
273     case TOK_CLLONG:
274     case TOK_CULLONG:
275         /* XXX: not quite exact, but only useful for testing  */
276 #ifdef _WIN32
277         sprintf(p, "%u", (unsigned)cv->ull);
278 #else
279         sprintf(p, "%Lu", cv->ull);
280 #endif
281         break;
282     case TOK_LCHAR:
283         cstr_ccat(&cstr_buf, 'L');
284     case TOK_CCHAR:
285         cstr_ccat(&cstr_buf, '\'');
286         add_char(&cstr_buf, cv->i);
287         cstr_ccat(&cstr_buf, '\'');
288         cstr_ccat(&cstr_buf, '\0');
289         break;
290     case TOK_PPNUM:
291         cstr = cv->cstr;
292         len = cstr->size - 1;
293         for(i=0;i<len;i++)
294             add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]);
295         cstr_ccat(&cstr_buf, '\0');
296         break;
297     case TOK_LSTR:
298         cstr_ccat(&cstr_buf, 'L');
299     case TOK_STR:
300         cstr = cv->cstr;
301         cstr_ccat(&cstr_buf, '\"');
302         if (v == TOK_STR) {
303             len = cstr->size - 1;
304             for(i=0;i<len;i++)
305                 add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]);
306         } else {
307             len = (cstr->size / sizeof(nwchar_t)) - 1;
308             for(i=0;i<len;i++)
309                 add_char(&cstr_buf, ((nwchar_t *)cstr->data)[i]);
310         }
311         cstr_ccat(&cstr_buf, '\"');
312         cstr_ccat(&cstr_buf, '\0');
313         break;
314     case TOK_LT:
315         v = '<';
316         goto addv;
317     case TOK_GT:
318         v = '>';
319         goto addv;
320     case TOK_DOTS:
321         return strcpy(p, "...");
322     case TOK_A_SHL:
323         return strcpy(p, "<<=");
324     case TOK_A_SAR:
325         return strcpy(p, ">>=");
326     default:
327         if (v < TOK_IDENT) {
328             /* search in two bytes table */
329             const unsigned char *q = tok_two_chars;
330             while (*q) {
331                 if (q[2] == v) {
332                     *p++ = q[0];
333                     *p++ = q[1];
334                     *p = '\0';
335                     return buf;
336                 }
337                 q += 3;
338             }
339         addv:
340             *p++ = v;
341             *p = '\0';
342         } else if (v < tok_ident) {
343             return table_ident[v - TOK_IDENT]->str;
344         } else if (v >= SYM_FIRST_ANOM) {
345             /* special name for anonymous symbol */
346             sprintf(p, "L.%u", v - SYM_FIRST_ANOM);
347         } else {
348             /* should never happen */
349             return NULL;
350         }
351         break;
352     }
353     return cstr_buf.data;
354 }
355
356 /* fill input buffer and peek next char */
357 static int tcc_peekc_slow(BufferedFile *bf)
358 {
359     int len;
360     /* only tries to read if really end of buffer */
361     if (bf->buf_ptr >= bf->buf_end) {
362         if (bf->fd != -1) {
363 #if defined(PARSE_DEBUG)
364             len = 8;
365 #else
366             len = IO_BUF_SIZE;
367 #endif
368             len = read(bf->fd, bf->buffer, len);
369             if (len < 0)
370                 len = 0;
371         } else {
372             len = 0;
373         }
374         total_bytes += len;
375         bf->buf_ptr = bf->buffer;
376         bf->buf_end = bf->buffer + len;
377         *bf->buf_end = CH_EOB;
378     }
379     if (bf->buf_ptr < bf->buf_end) {
380         return bf->buf_ptr[0];
381     } else {
382         bf->buf_ptr = bf->buf_end;
383         return CH_EOF;
384     }
385 }
386
387 /* return the current character, handling end of block if necessary
388    (but not stray) */
389 ST_FUNC int handle_eob(void)
390 {
391     return tcc_peekc_slow(file);
392 }
393
394 /* read next char from current input file and handle end of input buffer */
395 ST_INLN void inp(void)
396 {
397     ch = *(++(file->buf_ptr));
398     /* end of buffer/file handling */
399     if (ch == CH_EOB)
400         ch = handle_eob();
401 }
402
403 /* handle '\[\r]\n' */
404 static int handle_stray_noerror(void)
405 {
406     while (ch == '\\') {
407         inp();
408         if (ch == '\n') {
409             file->line_num++;
410             inp();
411         } else if (ch == '\r') {
412             inp();
413             if (ch != '\n')
414                 goto fail;
415             file->line_num++;
416             inp();
417         } else {
418         fail:
419             return 1;
420         }
421     }
422     return 0;
423 }
424
425 static void handle_stray(void)
426 {
427     if (handle_stray_noerror())
428         tcc_error("stray '\\' in program");
429 }
430
431 /* skip the stray and handle the \\n case. Output an error if
432    incorrect char after the stray */
433 static int handle_stray1(uint8_t *p)
434 {
435     int c;
436
437     if (p >= file->buf_end) {
438         file->buf_ptr = p;
439         c = handle_eob();
440         p = file->buf_ptr;
441         if (c == '\\')
442             goto parse_stray;
443     } else {
444     parse_stray:
445         file->buf_ptr = p;
446         ch = *p;
447         handle_stray();
448         p = file->buf_ptr;
449         c = *p;
450     }
451     return c;
452 }
453
454 /* handle just the EOB case, but not stray */
455 #define PEEKC_EOB(c, p)\
456 {\
457     p++;\
458     c = *p;\
459     if (c == '\\') {\
460         file->buf_ptr = p;\
461         c = handle_eob();\
462         p = file->buf_ptr;\
463     }\
464 }
465
466 /* handle the complicated stray case */
467 #define PEEKC(c, p)\
468 {\
469     p++;\
470     c = *p;\
471     if (c == '\\') {\
472         c = handle_stray1(p);\
473         p = file->buf_ptr;\
474     }\
475 }
476
477 /* input with '\[\r]\n' handling. Note that this function cannot
478    handle other characters after '\', so you cannot call it inside
479    strings or comments */
480 ST_FUNC void minp(void)
481 {
482     inp();
483     if (ch == '\\') 
484         handle_stray();
485 }
486
487
488 /* single line C++ comments */
489 static uint8_t *parse_line_comment(uint8_t *p)
490 {
491     int c;
492
493     p++;
494     for(;;) {
495         c = *p;
496     redo:
497         if (c == '\n' || c == CH_EOF) {
498             break;
499         } else if (c == '\\') {
500             file->buf_ptr = p;
501             c = handle_eob();
502             p = file->buf_ptr;
503             if (c == '\\') {
504                 PEEKC_EOB(c, p);
505                 if (c == '\n') {
506                     file->line_num++;
507                     PEEKC_EOB(c, p);
508                 } else if (c == '\r') {
509                     PEEKC_EOB(c, p);
510                     if (c == '\n') {
511                         file->line_num++;
512                         PEEKC_EOB(c, p);
513                     }
514                 }
515             } else {
516                 goto redo;
517             }
518         } else {
519             p++;
520         }
521     }
522     return p;
523 }
524
525 /* C comments */
526 ST_FUNC uint8_t *parse_comment(uint8_t *p)
527 {
528     int c;
529     
530     p++;
531     for(;;) {
532         /* fast skip loop */
533         for(;;) {
534             c = *p;
535             if (c == '\n' || c == '*' || c == '\\')
536                 break;
537             p++;
538             c = *p;
539             if (c == '\n' || c == '*' || c == '\\')
540                 break;
541             p++;
542         }
543         /* now we can handle all the cases */
544         if (c == '\n') {
545             file->line_num++;
546             p++;
547         } else if (c == '*') {
548             p++;
549             for(;;) {
550                 c = *p;
551                 if (c == '*') {
552                     p++;
553                 } else if (c == '/') {
554                     goto end_of_comment;
555                 } else if (c == '\\') {
556                     file->buf_ptr = p;
557                     c = handle_eob();
558                     p = file->buf_ptr;
559                     if (c == '\\') {
560                         /* skip '\[\r]\n', otherwise just skip the stray */
561                         while (c == '\\') {
562                             PEEKC_EOB(c, p);
563                             if (c == '\n') {
564                                 file->line_num++;
565                                 PEEKC_EOB(c, p);
566                             } else if (c == '\r') {
567                                 PEEKC_EOB(c, p);
568                                 if (c == '\n') {
569                                     file->line_num++;
570                                     PEEKC_EOB(c, p);
571                                 }
572                             } else {
573                                 goto after_star;
574                             }
575                         }
576                     }
577                 } else {
578                     break;
579                 }
580             }
581         after_star: ;
582         } else {
583             /* stray, eob or eof */
584             file->buf_ptr = p;
585             c = handle_eob();
586             p = file->buf_ptr;
587             if (c == CH_EOF) {
588                 tcc_error("unexpected end of file in comment");
589             } else if (c == '\\') {
590                 p++;
591             }
592         }
593     }
594  end_of_comment:
595     p++;
596     return p;
597 }
598
599 #define cinp minp
600
601 static inline void skip_spaces(void)
602 {
603     while (is_space(ch))
604         cinp();
605 }
606
607 static inline int check_space(int t, int *spc) 
608 {
609     if (is_space(t)) {
610         if (*spc) 
611             return 1;
612         *spc = 1;
613     } else 
614         *spc = 0;
615     return 0;
616 }
617
618 /* parse a string without interpreting escapes */
619 static uint8_t *parse_pp_string(uint8_t *p,
620                                 int sep, CString *str)
621 {
622     int c;
623     p++;
624     for(;;) {
625         c = *p;
626         if (c == sep) {
627             break;
628         } else if (c == '\\') {
629             file->buf_ptr = p;
630             c = handle_eob();
631             p = file->buf_ptr;
632             if (c == CH_EOF) {
633             unterminated_string:
634                 /* XXX: indicate line number of start of string */
635                 tcc_error("missing terminating %c character", sep);
636             } else if (c == '\\') {
637                 /* escape : just skip \[\r]\n */
638                 PEEKC_EOB(c, p);
639                 if (c == '\n') {
640                     file->line_num++;
641                     p++;
642                 } else if (c == '\r') {
643                     PEEKC_EOB(c, p);
644                     if (c != '\n')
645                         expect("'\n' after '\r'");
646                     file->line_num++;
647                     p++;
648                 } else if (c == CH_EOF) {
649                     goto unterminated_string;
650                 } else {
651                     if (str) {
652                         cstr_ccat(str, '\\');
653                         cstr_ccat(str, c);
654                     }
655                     p++;
656                 }
657             }
658         } else if (c == '\n') {
659             file->line_num++;
660             goto add_char;
661         } else if (c == '\r') {
662             PEEKC_EOB(c, p);
663             if (c != '\n') {
664                 if (str)
665                     cstr_ccat(str, '\r');
666             } else {
667                 file->line_num++;
668                 goto add_char;
669             }
670         } else {
671         add_char:
672             if (str)
673                 cstr_ccat(str, c);
674             p++;
675         }
676     }
677     p++;
678     return p;
679 }
680
681 /* skip block of text until #else, #elif or #endif. skip also pairs of
682    #if/#endif */
683 static void preprocess_skip(void)
684 {
685     int a, start_of_line, c, in_warn_or_error;
686     uint8_t *p;
687
688     p = file->buf_ptr;
689     a = 0;
690 redo_start:
691     start_of_line = 1;
692     in_warn_or_error = 0;
693     for(;;) {
694     redo_no_start:
695         c = *p;
696         switch(c) {
697         case ' ':
698         case '\t':
699         case '\f':
700         case '\v':
701         case '\r':
702             p++;
703             goto redo_no_start;
704         case '\n':
705             file->line_num++;
706             p++;
707             goto redo_start;
708         case '\\':
709             file->buf_ptr = p;
710             c = handle_eob();
711             if (c == CH_EOF) {
712                 expect("#endif");
713             } else if (c == '\\') {
714                 ch = file->buf_ptr[0];
715                 handle_stray_noerror();
716             }
717             p = file->buf_ptr;
718             goto redo_no_start;
719         /* skip strings */
720         case '\"':
721         case '\'':
722             if (in_warn_or_error)
723                 goto _default;
724             p = parse_pp_string(p, c, NULL);
725             break;
726         /* skip comments */
727         case '/':
728             if (in_warn_or_error)
729                 goto _default;
730             file->buf_ptr = p;
731             ch = *p;
732             minp();
733             p = file->buf_ptr;
734             if (ch == '*') {
735                 p = parse_comment(p);
736             } else if (ch == '/') {
737                 p = parse_line_comment(p);
738             }
739             break;
740         case '#':
741             p++;
742             if (start_of_line) {
743                 file->buf_ptr = p;
744                 next_nomacro();
745                 p = file->buf_ptr;
746                 if (a == 0 && 
747                     (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF))
748                     goto the_end;
749                 if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF)
750                     a++;
751                 else if (tok == TOK_ENDIF)
752                     a--;
753                 else if( tok == TOK_ERROR || tok == TOK_WARNING)
754                     in_warn_or_error = 1;
755                 else if (tok == TOK_LINEFEED)
756                     goto redo_start;
757             }
758             break;
759 _default:
760         default:
761             p++;
762             break;
763         }
764         start_of_line = 0;
765     }
766  the_end: ;
767     file->buf_ptr = p;
768 }
769
770 /* ParseState handling */
771
772 /* XXX: currently, no include file info is stored. Thus, we cannot display
773    accurate messages if the function or data definition spans multiple
774    files */
775
776 /* save current parse state in 's' */
777 ST_FUNC void save_parse_state(ParseState *s)
778 {
779     s->line_num = file->line_num;
780     s->macro_ptr = macro_ptr;
781     s->tok = tok;
782     s->tokc = tokc;
783 }
784
785 /* restore parse state from 's' */
786 ST_FUNC void restore_parse_state(ParseState *s)
787 {
788     file->line_num = s->line_num;
789     macro_ptr = s->macro_ptr;
790     tok = s->tok;
791     tokc = s->tokc;
792 }
793
794 /* return the number of additional 'ints' necessary to store the
795    token */
796 static inline int tok_ext_size(int t)
797 {
798     switch(t) {
799         /* 4 bytes */
800     case TOK_CINT:
801     case TOK_CUINT:
802     case TOK_CCHAR:
803     case TOK_LCHAR:
804     case TOK_CFLOAT:
805     case TOK_LINENUM:
806         return 1;
807     case TOK_STR:
808     case TOK_LSTR:
809     case TOK_PPNUM:
810         tcc_error("unsupported token");
811         return 1;
812     case TOK_CDOUBLE:
813     case TOK_CLLONG:
814     case TOK_CULLONG:
815         return 2;
816     case TOK_CLDOUBLE:
817         return LDOUBLE_SIZE / 4;
818     default:
819         return 0;
820     }
821 }
822
823 /* token string handling */
824
825 ST_INLN void tok_str_new(TokenString *s)
826 {
827     s->str = NULL;
828     s->len = 0;
829     s->allocated_len = 0;
830     s->last_line_num = -1;
831 }
832
833 ST_FUNC void tok_str_free(int *str)
834 {
835     tcc_free(str);
836 }
837
838 static int *tok_str_realloc(TokenString *s)
839 {
840     int *str, len;
841
842     if (s->allocated_len == 0) {
843         len = 8;
844     } else {
845         len = s->allocated_len * 2;
846     }
847     str = tcc_realloc(s->str, len * sizeof(int));
848     s->allocated_len = len;
849     s->str = str;
850     return str;
851 }
852
853 ST_FUNC void tok_str_add(TokenString *s, int t)
854 {
855     int len, *str;
856
857     len = s->len;
858     str = s->str;
859     if (len >= s->allocated_len)
860         str = tok_str_realloc(s);
861     str[len++] = t;
862     s->len = len;
863 }
864
865 static void tok_str_add2(TokenString *s, int t, CValue *cv)
866 {
867     int len, *str;
868
869     len = s->len;
870     str = s->str;
871
872     /* allocate space for worst case */
873     if (len + TOK_MAX_SIZE > s->allocated_len)
874         str = tok_str_realloc(s);
875     str[len++] = t;
876     switch(t) {
877     case TOK_CINT:
878     case TOK_CUINT:
879     case TOK_CCHAR:
880     case TOK_LCHAR:
881     case TOK_CFLOAT:
882     case TOK_LINENUM:
883         str[len++] = cv->tab[0];
884         break;
885     case TOK_PPNUM:
886     case TOK_STR:
887     case TOK_LSTR:
888         {
889             int nb_words;
890             CString *cstr;
891
892             nb_words = (sizeof(CString) + cv->cstr->size + 3) >> 2;
893             while ((len + nb_words) > s->allocated_len)
894                 str = tok_str_realloc(s);
895             cstr = (CString *)(str + len);
896             cstr->data = NULL;
897             cstr->size = cv->cstr->size;
898             cstr->data_allocated = NULL;
899             cstr->size_allocated = cstr->size;
900             memcpy((char *)cstr + sizeof(CString), 
901                    cv->cstr->data, cstr->size);
902             len += nb_words;
903         }
904         break;
905     case TOK_CDOUBLE:
906     case TOK_CLLONG:
907     case TOK_CULLONG:
908 #if LDOUBLE_SIZE == 8
909     case TOK_CLDOUBLE:
910 #endif
911         str[len++] = cv->tab[0];
912         str[len++] = cv->tab[1];
913         break;
914 #if LDOUBLE_SIZE == 12
915     case TOK_CLDOUBLE:
916         str[len++] = cv->tab[0];
917         str[len++] = cv->tab[1];
918         str[len++] = cv->tab[2];
919 #elif LDOUBLE_SIZE == 16
920     case TOK_CLDOUBLE:
921         str[len++] = cv->tab[0];
922         str[len++] = cv->tab[1];
923         str[len++] = cv->tab[2];
924         str[len++] = cv->tab[3];
925 #elif LDOUBLE_SIZE != 8
926 #error add long double size support
927 #endif
928         break;
929     default:
930         break;
931     }
932     s->len = len;
933 }
934
935 /* add the current parse token in token string 's' */
936 ST_FUNC void tok_str_add_tok(TokenString *s)
937 {
938     CValue cval;
939
940     /* save line number info */
941     if (file->line_num != s->last_line_num) {
942         s->last_line_num = file->line_num;
943         cval.i = s->last_line_num;
944         tok_str_add2(s, TOK_LINENUM, &cval);
945     }
946     tok_str_add2(s, tok, &tokc);
947 }
948
949 /* get a token from an integer array and increment pointer
950    accordingly. we code it as a macro to avoid pointer aliasing. */
951 static inline void TOK_GET(int *t, const int **pp, CValue *cv)
952 {
953     const int *p = *pp;
954     int n, *tab;
955
956     tab = cv->tab;
957     switch(*t = *p++) {
958     case TOK_CINT:
959     case TOK_CUINT:
960     case TOK_CCHAR:
961     case TOK_LCHAR:
962     case TOK_CFLOAT:
963     case TOK_LINENUM:
964         tab[0] = *p++;
965         break;
966     case TOK_STR:
967     case TOK_LSTR:
968     case TOK_PPNUM:
969         cv->cstr = (CString *)p;
970         cv->cstr->data = (char *)p + sizeof(CString);
971         p += (sizeof(CString) + cv->cstr->size + 3) >> 2;
972         break;
973     case TOK_CDOUBLE:
974     case TOK_CLLONG:
975     case TOK_CULLONG:
976         n = 2;
977         goto copy;
978     case TOK_CLDOUBLE:
979 #if LDOUBLE_SIZE == 16
980         n = 4;
981 #elif LDOUBLE_SIZE == 12
982         n = 3;
983 #elif LDOUBLE_SIZE == 8
984         n = 2;
985 #else
986 # error add long double size support
987 #endif
988     copy:
989         do
990             *tab++ = *p++;
991         while (--n);
992         break;
993     default:
994         break;
995     }
996     *pp = p;
997 }
998
999 static int macro_is_equal(const int *a, const int *b)
1000 {
1001     char buf[STRING_MAX_SIZE + 1];
1002     CValue cv;
1003     int t;
1004     while (*a && *b) {
1005         TOK_GET(&t, &a, &cv);
1006         pstrcpy(buf, sizeof buf, get_tok_str(t, &cv));
1007         TOK_GET(&t, &b, &cv);
1008         if (strcmp(buf, get_tok_str(t, &cv)))
1009             return 0;
1010     }
1011     return !(*a || *b);
1012 }
1013
1014 /* defines handling */
1015 ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg)
1016 {
1017     Sym *s;
1018
1019     s = define_find(v);
1020     if (s && !macro_is_equal(s->d, str))
1021         tcc_warning("%s redefined", get_tok_str(v, NULL));
1022
1023     s = sym_push2(&define_stack, v, macro_type, 0);
1024     s->d = str;
1025     s->next = first_arg;
1026     table_ident[v - TOK_IDENT]->sym_define = s;
1027 }
1028
1029 /* undefined a define symbol. Its name is just set to zero */
1030 ST_FUNC void define_undef(Sym *s)
1031 {
1032     int v;
1033     v = s->v;
1034     if (v >= TOK_IDENT && v < tok_ident)
1035         table_ident[v - TOK_IDENT]->sym_define = NULL;
1036     s->v = 0;
1037 }
1038
1039 ST_INLN Sym *define_find(int v)
1040 {
1041     v -= TOK_IDENT;
1042     if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
1043         return NULL;
1044     return table_ident[v]->sym_define;
1045 }
1046
1047 /* free define stack until top reaches 'b' */
1048 ST_FUNC void free_defines(Sym *b)
1049 {
1050     Sym *top, *top1;
1051     int v;
1052
1053     top = define_stack;
1054     while (top != b) {
1055         top1 = top->prev;
1056         /* do not free args or predefined defines */
1057         if (top->d)
1058             tok_str_free(top->d);
1059         v = top->v;
1060         if (v >= TOK_IDENT && v < tok_ident)
1061             table_ident[v - TOK_IDENT]->sym_define = NULL;
1062         sym_free(top);
1063         top = top1;
1064     }
1065     define_stack = b;
1066 }
1067
1068 /* label lookup */
1069 ST_FUNC Sym *label_find(int v)
1070 {
1071     v -= TOK_IDENT;
1072     if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
1073         return NULL;
1074     return table_ident[v]->sym_label;
1075 }
1076
1077 ST_FUNC Sym *label_push(Sym **ptop, int v, int flags)
1078 {
1079     Sym *s, **ps;
1080     s = sym_push2(ptop, v, 0, 0);
1081     s->r = flags;
1082     ps = &table_ident[v - TOK_IDENT]->sym_label;
1083     if (ptop == &global_label_stack) {
1084         /* modify the top most local identifier, so that
1085            sym_identifier will point to 's' when popped */
1086         while (*ps != NULL)
1087             ps = &(*ps)->prev_tok;
1088     }
1089     s->prev_tok = *ps;
1090     *ps = s;
1091     return s;
1092 }
1093
1094 /* pop labels until element last is reached. Look if any labels are
1095    undefined. Define symbols if '&&label' was used. */
1096 ST_FUNC void label_pop(Sym **ptop, Sym *slast)
1097 {
1098     Sym *s, *s1;
1099     for(s = *ptop; s != slast; s = s1) {
1100         s1 = s->prev;
1101         if (s->r == LABEL_DECLARED) {
1102             tcc_warning("label '%s' declared but not used", get_tok_str(s->v, NULL));
1103         } else if (s->r == LABEL_FORWARD) {
1104                 tcc_error("label '%s' used but not defined",
1105                       get_tok_str(s->v, NULL));
1106         } else {
1107             if (s->c) {
1108                 /* define corresponding symbol. A size of
1109                    1 is put. */
1110                 put_extern_sym(s, cur_text_section, s->jnext, 1);
1111             }
1112         }
1113         /* remove label */
1114         table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
1115         sym_free(s);
1116     }
1117     *ptop = slast;
1118 }
1119
1120 /* eval an expression for #if/#elif */
1121 static int expr_preprocess(void)
1122 {
1123     int c, t;
1124     TokenString str;
1125     
1126     tok_str_new(&str);
1127     while (tok != TOK_LINEFEED && tok != TOK_EOF) {
1128         next(); /* do macro subst */
1129         if (tok == TOK_DEFINED) {
1130             next_nomacro();
1131             t = tok;
1132             if (t == '(') 
1133                 next_nomacro();
1134             c = define_find(tok) != 0;
1135             if (t == '(')
1136                 next_nomacro();
1137             tok = TOK_CINT;
1138             tokc.i = c;
1139         } else if (tok >= TOK_IDENT) {
1140             /* if undefined macro */
1141             tok = TOK_CINT;
1142             tokc.i = 0;
1143         }
1144         tok_str_add_tok(&str);
1145     }
1146     tok_str_add(&str, -1); /* simulate end of file */
1147     tok_str_add(&str, 0);
1148     /* now evaluate C constant expression */
1149     macro_ptr = str.str;
1150     next();
1151     c = expr_const();
1152     macro_ptr = NULL;
1153     tok_str_free(str.str);
1154     return c != 0;
1155 }
1156
1157 #if defined(PARSE_DEBUG) || defined(PP_DEBUG)
1158 static void tok_print(int *str)
1159 {
1160     int t;
1161     CValue cval;
1162
1163     printf("<");
1164     while (1) {
1165         TOK_GET(&t, &str, &cval);
1166         if (!t)
1167             break;
1168         printf("%s", get_tok_str(t, &cval));
1169     }
1170     printf(">\n");
1171 }
1172 #endif
1173
1174 /* parse after #define */
1175 ST_FUNC void parse_define(void)
1176 {
1177     Sym *s, *first, **ps;
1178     int v, t, varg, is_vaargs, spc;
1179     TokenString str;
1180     
1181     v = tok;
1182     if (v < TOK_IDENT)
1183         tcc_error("invalid macro name '%s'", get_tok_str(tok, &tokc));
1184     /* XXX: should check if same macro (ANSI) */
1185     first = NULL;
1186     t = MACRO_OBJ;
1187     /* '(' must be just after macro definition for MACRO_FUNC */
1188     next_nomacro_spc();
1189     if (tok == '(') {
1190         next_nomacro();
1191         ps = &first;
1192         while (tok != ')') {
1193             varg = tok;
1194             next_nomacro();
1195             is_vaargs = 0;
1196             if (varg == TOK_DOTS) {
1197                 varg = TOK___VA_ARGS__;
1198                 is_vaargs = 1;
1199             } else if (tok == TOK_DOTS && gnu_ext) {
1200                 is_vaargs = 1;
1201                 next_nomacro();
1202             }
1203             if (varg < TOK_IDENT)
1204                 tcc_error("badly punctuated parameter list");
1205             s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0);
1206             *ps = s;
1207             ps = &s->next;
1208             if (tok != ',')
1209                 break;
1210             next_nomacro();
1211         }
1212         if (tok == ')')
1213             next_nomacro_spc();
1214         t = MACRO_FUNC;
1215     }
1216     tok_str_new(&str);
1217     spc = 2;
1218     /* EOF testing necessary for '-D' handling */
1219     while (tok != TOK_LINEFEED && tok != TOK_EOF) {
1220         /* remove spaces around ## and after '#' */        
1221         if (TOK_TWOSHARPS == tok) {
1222             if (1 == spc)
1223                 --str.len;
1224             spc = 2;
1225         } else if ('#' == tok) {
1226             spc = 2;
1227         } else if (check_space(tok, &spc)) {
1228             goto skip;
1229         }
1230         tok_str_add2(&str, tok, &tokc);
1231     skip:
1232         next_nomacro_spc();
1233     }
1234     if (spc == 1)
1235         --str.len; /* remove trailing space */
1236     tok_str_add(&str, 0);
1237 #ifdef PP_DEBUG
1238     printf("define %s %d: ", get_tok_str(v, NULL), t);
1239     tok_print(str.str);
1240 #endif
1241     define_push(v, t, str.str, first);
1242 }
1243
1244 static inline int hash_cached_include(const char *filename)
1245 {
1246     const unsigned char *s;
1247     unsigned int h;
1248
1249     h = TOK_HASH_INIT;
1250     s = filename;
1251     while (*s) {
1252         h = TOK_HASH_FUNC(h, *s);
1253         s++;
1254     }
1255     h &= (CACHED_INCLUDES_HASH_SIZE - 1);
1256     return h;
1257 }
1258
1259 static CachedInclude *search_cached_include(TCCState *s1, const char *filename)
1260 {
1261     CachedInclude *e;
1262     int i, h;
1263     h = hash_cached_include(filename);
1264     i = s1->cached_includes_hash[h];
1265     for(;;) {
1266         if (i == 0)
1267             break;
1268         e = s1->cached_includes[i - 1];
1269         if (0 == PATHCMP(e->filename, filename))
1270             return e;
1271         i = e->hash_next;
1272     }
1273     return NULL;
1274 }
1275
1276 static inline void add_cached_include(TCCState *s1, const char *filename, int ifndef_macro)
1277 {
1278     CachedInclude *e;
1279     int h;
1280
1281     if (search_cached_include(s1, filename))
1282         return;
1283 #ifdef INC_DEBUG
1284     printf("adding cached '%s' %s\n", filename, get_tok_str(ifndef_macro, NULL));
1285 #endif
1286     e = tcc_malloc(sizeof(CachedInclude) + strlen(filename));
1287     strcpy(e->filename, filename);
1288     e->ifndef_macro = ifndef_macro;
1289     dynarray_add((void ***)&s1->cached_includes, &s1->nb_cached_includes, e);
1290     /* add in hash table */
1291     h = hash_cached_include(filename);
1292     e->hash_next = s1->cached_includes_hash[h];
1293     s1->cached_includes_hash[h] = s1->nb_cached_includes;
1294 }
1295
1296 static void pragma_parse(TCCState *s1)
1297 {
1298     int val;
1299
1300     next();
1301     if (tok == TOK_pack) {
1302         /*
1303           This may be:
1304           #pragma pack(1) // set
1305           #pragma pack() // reset to default
1306           #pragma pack(push,1) // push & set
1307           #pragma pack(pop) // restore previous
1308         */
1309         next();
1310         skip('(');
1311         if (tok == TOK_ASM_pop) {
1312             next();
1313             if (s1->pack_stack_ptr <= s1->pack_stack) {
1314             stk_error:
1315                 tcc_error("out of pack stack");
1316             }
1317             s1->pack_stack_ptr--;
1318         } else {
1319             val = 0;
1320             if (tok != ')') {
1321                 if (tok == TOK_ASM_push) {
1322                     next();
1323                     if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1)
1324                         goto stk_error;
1325                     s1->pack_stack_ptr++;
1326                     skip(',');
1327                 }
1328                 if (tok != TOK_CINT) {
1329                 pack_error:
1330                     tcc_error("invalid pack pragma");
1331                 }
1332                 val = tokc.i;
1333                 if (val < 1 || val > 16 || (val & (val - 1)) != 0)
1334                     goto pack_error;
1335                 next();
1336             }
1337             *s1->pack_stack_ptr = val;
1338             skip(')');
1339         }
1340     }
1341 }
1342
1343 /* is_bof is true if first non space token at beginning of file */
1344 ST_FUNC void preprocess(int is_bof)
1345 {
1346     TCCState *s1 = tcc_state;
1347     int i, c, n, saved_parse_flags;
1348     char buf[1024], *q;
1349     Sym *s;
1350
1351     saved_parse_flags = parse_flags;
1352     parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | 
1353         PARSE_FLAG_LINEFEED;
1354     next_nomacro();
1355  redo:
1356     switch(tok) {
1357     case TOK_DEFINE:
1358         next_nomacro();
1359         parse_define();
1360         break;
1361     case TOK_UNDEF:
1362         next_nomacro();
1363         s = define_find(tok);
1364         /* undefine symbol by putting an invalid name */
1365         if (s)
1366             define_undef(s);
1367         break;
1368     case TOK_INCLUDE:
1369     case TOK_INCLUDE_NEXT:
1370         ch = file->buf_ptr[0];
1371         /* XXX: incorrect if comments : use next_nomacro with a special mode */
1372         skip_spaces();
1373         if (ch == '<') {
1374             c = '>';
1375             goto read_name;
1376         } else if (ch == '\"') {
1377             c = ch;
1378         read_name:
1379             inp();
1380             q = buf;
1381             while (ch != c && ch != '\n' && ch != CH_EOF) {
1382                 if ((q - buf) < sizeof(buf) - 1)
1383                     *q++ = ch;
1384                 if (ch == '\\') {
1385                     if (handle_stray_noerror() == 0)
1386                         --q;
1387                 } else
1388                     inp();
1389             }
1390             *q = '\0';
1391             minp();
1392 #if 0
1393             /* eat all spaces and comments after include */
1394             /* XXX: slightly incorrect */
1395             while (ch1 != '\n' && ch1 != CH_EOF)
1396                 inp();
1397 #endif
1398         } else {
1399             /* computed #include : either we have only strings or
1400                we have anything enclosed in '<>' */
1401             next();
1402             buf[0] = '\0';
1403             if (tok == TOK_STR) {
1404                 while (tok != TOK_LINEFEED) {
1405                     if (tok != TOK_STR) {
1406                     include_syntax:
1407                         tcc_error("'#include' expects \"FILENAME\" or <FILENAME>");
1408                     }
1409                     pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data);
1410                     next();
1411                 }
1412                 c = '\"';
1413             } else {
1414                 int len;
1415                 while (tok != TOK_LINEFEED) {
1416                     pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc));
1417                     next();
1418                 }
1419                 len = strlen(buf);
1420                 /* check syntax and remove '<>' */
1421                 if (len < 2 || buf[0] != '<' || buf[len - 1] != '>')
1422                     goto include_syntax;
1423                 memmove(buf, buf + 1, len - 2);
1424                 buf[len - 2] = '\0';
1425                 c = '>';
1426             }
1427         }
1428
1429         if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE)
1430             tcc_error("#include recursion too deep");
1431         /* store current file in stack, but increment stack later below */
1432         *s1->include_stack_ptr = file;
1433
1434         n = s1->nb_include_paths + s1->nb_sysinclude_paths;
1435         for (i = -2; i < n; ++i) {
1436             char buf1[sizeof file->filename];
1437             CachedInclude *e;
1438             BufferedFile **f;
1439             const char *path;
1440
1441             if (i == -2) {
1442                 /* check absolute include path */
1443                 if (!IS_ABSPATH(buf))
1444                     continue;
1445                 buf1[0] = 0;
1446                 i = n; /* force end loop */
1447
1448             } else if (i == -1) {
1449                 /* search in current dir if "header.h" */
1450                 if (c != '\"')
1451                     continue;
1452                 path = file->filename;
1453                 pstrncpy(buf1, path, tcc_basename(path) - path);
1454
1455             } else {
1456                 /* search in all the include paths */
1457                 if (i < s1->nb_include_paths)
1458                     path = s1->include_paths[i];
1459                 else
1460                     path = s1->sysinclude_paths[i - s1->nb_include_paths];
1461                 pstrcpy(buf1, sizeof(buf1), path);
1462                 pstrcat(buf1, sizeof(buf1), "/");
1463             }
1464
1465             pstrcat(buf1, sizeof(buf1), buf);
1466
1467             if (tok == TOK_INCLUDE_NEXT)
1468                 for (f = s1->include_stack_ptr; f >= s1->include_stack; --f)
1469                     if (0 == PATHCMP((*f)->filename, buf1)) {
1470 #ifdef INC_DEBUG
1471                         printf("%s: #include_next skipping %s\n", file->filename, buf1);
1472 #endif
1473                         goto include_trynext;
1474                     }
1475
1476             e = search_cached_include(s1, buf1);
1477             if (e && define_find(e->ifndef_macro)) {
1478                 /* no need to parse the include because the 'ifndef macro'
1479                    is defined */
1480 #ifdef INC_DEBUG
1481                 printf("%s: skipping cached %s\n", file->filename, buf1);
1482 #endif
1483                 goto include_done;
1484             }
1485
1486             if (tcc_open(s1, buf1) < 0)
1487 include_trynext:
1488                 continue;
1489
1490 #ifdef INC_DEBUG
1491             printf("%s: including %s\n", file->prev->filename, file->filename);
1492 #endif
1493             /* update target deps */
1494             dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps,
1495                     tcc_strdup(buf1));
1496             /* push current file in stack */
1497             ++s1->include_stack_ptr;
1498             /* add include file debug info */
1499             if (s1->do_debug)
1500                 put_stabs(file->filename, N_BINCL, 0, 0, 0);
1501             tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL;
1502             ch = file->buf_ptr[0];
1503             goto the_end;
1504         }
1505         tcc_error("include file '%s' not found", buf);
1506 include_done:
1507         break;
1508     case TOK_IFNDEF:
1509         c = 1;
1510         goto do_ifdef;
1511     case TOK_IF:
1512         c = expr_preprocess();
1513         goto do_if;
1514     case TOK_IFDEF:
1515         c = 0;
1516     do_ifdef:
1517         next_nomacro();
1518         if (tok < TOK_IDENT)
1519             tcc_error("invalid argument for '#if%sdef'", c ? "n" : "");
1520         if (is_bof) {
1521             if (c) {
1522 #ifdef INC_DEBUG
1523                 printf("#ifndef %s\n", get_tok_str(tok, NULL));
1524 #endif
1525                 file->ifndef_macro = tok;
1526             }
1527         }
1528         c = (define_find(tok) != 0) ^ c;
1529     do_if:
1530         if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE)
1531             tcc_error("memory full");
1532         *s1->ifdef_stack_ptr++ = c;
1533         goto test_skip;
1534     case TOK_ELSE:
1535         if (s1->ifdef_stack_ptr == s1->ifdef_stack)
1536             tcc_error("#else without matching #if");
1537         if (s1->ifdef_stack_ptr[-1] & 2)
1538             tcc_error("#else after #else");
1539         c = (s1->ifdef_stack_ptr[-1] ^= 3);
1540         goto test_else;
1541     case TOK_ELIF:
1542         if (s1->ifdef_stack_ptr == s1->ifdef_stack)
1543             tcc_error("#elif without matching #if");
1544         c = s1->ifdef_stack_ptr[-1];
1545         if (c > 1)
1546             tcc_error("#elif after #else");
1547         /* last #if/#elif expression was true: we skip */
1548         if (c == 1)
1549             goto skip;
1550         c = expr_preprocess();
1551         s1->ifdef_stack_ptr[-1] = c;
1552     test_else:
1553         if (s1->ifdef_stack_ptr == file->ifdef_stack_ptr + 1)
1554             file->ifndef_macro = 0;
1555     test_skip:
1556         if (!(c & 1)) {
1557         skip:
1558             preprocess_skip();
1559             is_bof = 0;
1560             goto redo;
1561         }
1562         break;
1563     case TOK_ENDIF:
1564         if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr)
1565             tcc_error("#endif without matching #if");
1566         s1->ifdef_stack_ptr--;
1567         /* '#ifndef macro' was at the start of file. Now we check if
1568            an '#endif' is exactly at the end of file */
1569         if (file->ifndef_macro &&
1570             s1->ifdef_stack_ptr == file->ifdef_stack_ptr) {
1571             file->ifndef_macro_saved = file->ifndef_macro;
1572             /* need to set to zero to avoid false matches if another
1573                #ifndef at middle of file */
1574             file->ifndef_macro = 0;
1575             while (tok != TOK_LINEFEED)
1576                 next_nomacro();
1577             tok_flags |= TOK_FLAG_ENDIF;
1578             goto the_end;
1579         }
1580         break;
1581     case TOK_LINE:
1582         next();
1583         if (tok != TOK_CINT)
1584             tcc_error("#line");
1585         file->line_num = tokc.i - 1; /* the line number will be incremented after */
1586         next();
1587         if (tok != TOK_LINEFEED) {
1588             if (tok != TOK_STR)
1589                 tcc_error("#line");
1590             pstrcpy(file->filename, sizeof(file->filename), 
1591                     (char *)tokc.cstr->data);
1592         }
1593         break;
1594     case TOK_ERROR:
1595     case TOK_WARNING:
1596         c = tok;
1597         ch = file->buf_ptr[0];
1598         skip_spaces();
1599         q = buf;
1600         while (ch != '\n' && ch != CH_EOF) {
1601             if ((q - buf) < sizeof(buf) - 1)
1602                 *q++ = ch;
1603             if (ch == '\\') {
1604                 if (handle_stray_noerror() == 0)
1605                     --q;
1606             } else
1607                 inp();
1608         }
1609         *q = '\0';
1610         if (c == TOK_ERROR)
1611             tcc_error("#error %s", buf);
1612         else
1613             tcc_warning("#warning %s", buf);
1614         break;
1615     case TOK_PRAGMA:
1616         pragma_parse(s1);
1617         break;
1618     default:
1619         if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_PPNUM) {
1620             /* '!' is ignored to allow C scripts. numbers are ignored
1621                to emulate cpp behaviour */
1622         } else {
1623             if (!(saved_parse_flags & PARSE_FLAG_ASM_COMMENTS))
1624                 tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc));
1625             else {
1626                 /* this is a gas line comment in an 'S' file. */
1627                 file->buf_ptr = parse_line_comment(file->buf_ptr);
1628                 goto the_end;
1629             }
1630         }
1631         break;
1632     }
1633     /* ignore other preprocess commands or #! for C scripts */
1634     while (tok != TOK_LINEFEED)
1635         next_nomacro();
1636  the_end:
1637     parse_flags = saved_parse_flags;
1638 }
1639
1640 /* evaluate escape codes in a string. */
1641 static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long)
1642 {
1643     int c, n;
1644     const uint8_t *p;
1645
1646     p = buf;
1647     for(;;) {
1648         c = *p;
1649         if (c == '\0')
1650             break;
1651         if (c == '\\') {
1652             p++;
1653             /* escape */
1654             c = *p;
1655             switch(c) {
1656             case '0': case '1': case '2': case '3':
1657             case '4': case '5': case '6': case '7':
1658                 /* at most three octal digits */
1659                 n = c - '0';
1660                 p++;
1661                 c = *p;
1662                 if (isoct(c)) {
1663                     n = n * 8 + c - '0';
1664                     p++;
1665                     c = *p;
1666                     if (isoct(c)) {
1667                         n = n * 8 + c - '0';
1668                         p++;
1669                     }
1670                 }
1671                 c = n;
1672                 goto add_char_nonext;
1673             case 'x':
1674             case 'u':
1675             case 'U':
1676                 p++;
1677                 n = 0;
1678                 for(;;) {
1679                     c = *p;
1680                     if (c >= 'a' && c <= 'f')
1681                         c = c - 'a' + 10;
1682                     else if (c >= 'A' && c <= 'F')
1683                         c = c - 'A' + 10;
1684                     else if (isnum(c))
1685                         c = c - '0';
1686                     else
1687                         break;
1688                     n = n * 16 + c;
1689                     p++;
1690                 }
1691                 c = n;
1692                 goto add_char_nonext;
1693             case 'a':
1694                 c = '\a';
1695                 break;
1696             case 'b':
1697                 c = '\b';
1698                 break;
1699             case 'f':
1700                 c = '\f';
1701                 break;
1702             case 'n':
1703                 c = '\n';
1704                 break;
1705             case 'r':
1706                 c = '\r';
1707                 break;
1708             case 't':
1709                 c = '\t';
1710                 break;
1711             case 'v':
1712                 c = '\v';
1713                 break;
1714             case 'e':
1715                 if (!gnu_ext)
1716                     goto invalid_escape;
1717                 c = 27;
1718                 break;
1719             case '\'':
1720             case '\"':
1721             case '\\': 
1722             case '?':
1723                 break;
1724             default:
1725             invalid_escape:
1726                 if (c >= '!' && c <= '~')
1727                     tcc_warning("unknown escape sequence: \'\\%c\'", c);
1728                 else
1729                     tcc_warning("unknown escape sequence: \'\\x%x\'", c);
1730                 break;
1731             }
1732         }
1733         p++;
1734     add_char_nonext:
1735         if (!is_long)
1736             cstr_ccat(outstr, c);
1737         else
1738             cstr_wccat(outstr, c);
1739     }
1740     /* add a trailing '\0' */
1741     if (!is_long)
1742         cstr_ccat(outstr, '\0');
1743     else
1744         cstr_wccat(outstr, '\0');
1745 }
1746
1747 /* we use 64 bit numbers */
1748 #define BN_SIZE 2
1749
1750 /* bn = (bn << shift) | or_val */
1751 static void bn_lshift(unsigned int *bn, int shift, int or_val)
1752 {
1753     int i;
1754     unsigned int v;
1755     for(i=0;i<BN_SIZE;i++) {
1756         v = bn[i];
1757         bn[i] = (v << shift) | or_val;
1758         or_val = v >> (32 - shift);
1759     }
1760 }
1761
1762 static void bn_zero(unsigned int *bn)
1763 {
1764     int i;
1765     for(i=0;i<BN_SIZE;i++) {
1766         bn[i] = 0;
1767     }
1768 }
1769
1770 /* parse number in null terminated string 'p' and return it in the
1771    current token */
1772 static void parse_number(const char *p)
1773 {
1774     int b, t, shift, frac_bits, s, exp_val, ch;
1775     char *q;
1776     unsigned int bn[BN_SIZE];
1777     double d;
1778
1779     /* number */
1780     q = token_buf;
1781     ch = *p++;
1782     t = ch;
1783     ch = *p++;
1784     *q++ = t;
1785     b = 10;
1786     if (t == '.') {
1787         goto float_frac_parse;
1788     } else if (t == '0') {
1789         if (ch == 'x' || ch == 'X') {
1790             q--;
1791             ch = *p++;
1792             b = 16;
1793         } else if (tcc_ext && (ch == 'b' || ch == 'B')) {
1794             q--;
1795             ch = *p++;
1796             b = 2;
1797         }
1798     }
1799     /* parse all digits. cannot check octal numbers at this stage
1800        because of floating point constants */
1801     while (1) {
1802         if (ch >= 'a' && ch <= 'f')
1803             t = ch - 'a' + 10;
1804         else if (ch >= 'A' && ch <= 'F')
1805             t = ch - 'A' + 10;
1806         else if (isnum(ch))
1807             t = ch - '0';
1808         else
1809             break;
1810         if (t >= b)
1811             break;
1812         if (q >= token_buf + STRING_MAX_SIZE) {
1813         num_too_long:
1814             tcc_error("number too long");
1815         }
1816         *q++ = ch;
1817         ch = *p++;
1818     }
1819     if (ch == '.' ||
1820         ((ch == 'e' || ch == 'E') && b == 10) ||
1821         ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) {
1822         if (b != 10) {
1823             /* NOTE: strtox should support that for hexa numbers, but
1824                non ISOC99 libcs do not support it, so we prefer to do
1825                it by hand */
1826             /* hexadecimal or binary floats */
1827             /* XXX: handle overflows */
1828             *q = '\0';
1829             if (b == 16)
1830                 shift = 4;
1831             else 
1832                 shift = 2;
1833             bn_zero(bn);
1834             q = token_buf;
1835             while (1) {
1836                 t = *q++;
1837                 if (t == '\0') {
1838                     break;
1839                 } else if (t >= 'a') {
1840                     t = t - 'a' + 10;
1841                 } else if (t >= 'A') {
1842                     t = t - 'A' + 10;
1843                 } else {
1844                     t = t - '0';
1845                 }
1846                 bn_lshift(bn, shift, t);
1847             }
1848             frac_bits = 0;
1849             if (ch == '.') {
1850                 ch = *p++;
1851                 while (1) {
1852                     t = ch;
1853                     if (t >= 'a' && t <= 'f') {
1854                         t = t - 'a' + 10;
1855                     } else if (t >= 'A' && t <= 'F') {
1856                         t = t - 'A' + 10;
1857                     } else if (t >= '0' && t <= '9') {
1858                         t = t - '0';
1859                     } else {
1860                         break;
1861                     }
1862                     if (t >= b)
1863                         tcc_error("invalid digit");
1864                     bn_lshift(bn, shift, t);
1865                     frac_bits += shift;
1866                     ch = *p++;
1867                 }
1868             }
1869             if (ch != 'p' && ch != 'P')
1870                 expect("exponent");
1871             ch = *p++;
1872             s = 1;
1873             exp_val = 0;
1874             if (ch == '+') {
1875                 ch = *p++;
1876             } else if (ch == '-') {
1877                 s = -1;
1878                 ch = *p++;
1879             }
1880             if (ch < '0' || ch > '9')
1881                 expect("exponent digits");
1882             while (ch >= '0' && ch <= '9') {
1883                 exp_val = exp_val * 10 + ch - '0';
1884                 ch = *p++;
1885             }
1886             exp_val = exp_val * s;
1887             
1888             /* now we can generate the number */
1889             /* XXX: should patch directly float number */
1890             d = (double)bn[1] * 4294967296.0 + (double)bn[0];
1891             d = ldexp(d, exp_val - frac_bits);
1892             t = toup(ch);
1893             if (t == 'F') {
1894                 ch = *p++;
1895                 tok = TOK_CFLOAT;
1896                 /* float : should handle overflow */
1897                 tokc.f = (float)d;
1898             } else if (t == 'L') {
1899                 ch = *p++;
1900 #ifdef TCC_TARGET_PE
1901                 tok = TOK_CDOUBLE;
1902                 tokc.d = d;
1903 #else
1904                 tok = TOK_CLDOUBLE;
1905                 /* XXX: not large enough */
1906                 tokc.ld = (long double)d;
1907 #endif
1908             } else {
1909                 tok = TOK_CDOUBLE;
1910                 tokc.d = d;
1911             }
1912         } else {
1913             /* decimal floats */
1914             if (ch == '.') {
1915                 if (q >= token_buf + STRING_MAX_SIZE)
1916                     goto num_too_long;
1917                 *q++ = ch;
1918                 ch = *p++;
1919             float_frac_parse:
1920                 while (ch >= '0' && ch <= '9') {
1921                     if (q >= token_buf + STRING_MAX_SIZE)
1922                         goto num_too_long;
1923                     *q++ = ch;
1924                     ch = *p++;
1925                 }
1926             }
1927             if (ch == 'e' || ch == 'E') {
1928                 if (q >= token_buf + STRING_MAX_SIZE)
1929                     goto num_too_long;
1930                 *q++ = ch;
1931                 ch = *p++;
1932                 if (ch == '-' || ch == '+') {
1933                     if (q >= token_buf + STRING_MAX_SIZE)
1934                         goto num_too_long;
1935                     *q++ = ch;
1936                     ch = *p++;
1937                 }
1938                 if (ch < '0' || ch > '9')
1939                     expect("exponent digits");
1940                 while (ch >= '0' && ch <= '9') {
1941                     if (q >= token_buf + STRING_MAX_SIZE)
1942                         goto num_too_long;
1943                     *q++ = ch;
1944                     ch = *p++;
1945                 }
1946             }
1947             *q = '\0';
1948             t = toup(ch);
1949             errno = 0;
1950             if (t == 'F') {
1951                 ch = *p++;
1952                 tok = TOK_CFLOAT;
1953                 tokc.f = strtof(token_buf, NULL);
1954             } else if (t == 'L') {
1955                 ch = *p++;
1956 #ifdef TCC_TARGET_PE
1957                 tok = TOK_CDOUBLE;
1958                 tokc.d = strtod(token_buf, NULL);
1959 #else
1960                 tok = TOK_CLDOUBLE;
1961                 tokc.ld = strtold(token_buf, NULL);
1962 #endif
1963             } else {
1964                 tok = TOK_CDOUBLE;
1965                 tokc.d = strtod(token_buf, NULL);
1966             }
1967         }
1968     } else {
1969         unsigned long long n, n1;
1970         int lcount, ucount;
1971
1972         /* integer number */
1973         *q = '\0';
1974         q = token_buf;
1975         if (b == 10 && *q == '0') {
1976             b = 8;
1977             q++;
1978         }
1979         n = 0;
1980         while(1) {
1981             t = *q++;
1982             /* no need for checks except for base 10 / 8 errors */
1983             if (t == '\0') {
1984                 break;
1985             } else if (t >= 'a') {
1986                 t = t - 'a' + 10;
1987             } else if (t >= 'A') {
1988                 t = t - 'A' + 10;
1989             } else {
1990                 t = t - '0';
1991                 if (t >= b)
1992                     tcc_error("invalid digit");
1993             }
1994             n1 = n;
1995             n = n * b + t;
1996             /* detect overflow */
1997             /* XXX: this test is not reliable */
1998             if (n < n1)
1999                 tcc_error("integer constant overflow");
2000         }
2001         
2002         /* XXX: not exactly ANSI compliant */
2003         if ((n & 0xffffffff00000000LL) != 0) {
2004             if ((n >> 63) != 0)
2005                 tok = TOK_CULLONG;
2006             else
2007                 tok = TOK_CLLONG;
2008         } else if (n > 0x7fffffff) {
2009             tok = TOK_CUINT;
2010         } else {
2011             tok = TOK_CINT;
2012         }
2013         lcount = 0;
2014         ucount = 0;
2015         for(;;) {
2016             t = toup(ch);
2017             if (t == 'L') {
2018                 if (lcount >= 2)
2019                     tcc_error("three 'l's in integer constant");
2020                 lcount++;
2021 #if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
2022                 if (lcount == 2) {
2023 #endif
2024                     if (tok == TOK_CINT)
2025                         tok = TOK_CLLONG;
2026                     else if (tok == TOK_CUINT)
2027                         tok = TOK_CULLONG;
2028 #if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
2029                 }
2030 #endif
2031                 ch = *p++;
2032             } else if (t == 'U') {
2033                 if (ucount >= 1)
2034                     tcc_error("two 'u's in integer constant");
2035                 ucount++;
2036                 if (tok == TOK_CINT)
2037                     tok = TOK_CUINT;
2038                 else if (tok == TOK_CLLONG)
2039                     tok = TOK_CULLONG;
2040                 ch = *p++;
2041             } else {
2042                 break;
2043             }
2044         }
2045         if (tok == TOK_CINT || tok == TOK_CUINT)
2046             tokc.ui = n;
2047         else
2048             tokc.ull = n;
2049     }
2050     if (ch)
2051         tcc_error("invalid number\n");
2052 }
2053
2054
2055 #define PARSE2(c1, tok1, c2, tok2)              \
2056     case c1:                                    \
2057         PEEKC(c, p);                            \
2058         if (c == c2) {                          \
2059             p++;                                \
2060             tok = tok2;                         \
2061         } else {                                \
2062             tok = tok1;                         \
2063         }                                       \
2064         break;
2065
2066 /* return next token without macro substitution */
2067 static inline void next_nomacro1(void)
2068 {
2069     int t, c, is_long;
2070     TokenSym *ts;
2071     uint8_t *p, *p1;
2072     unsigned int h;
2073
2074     p = file->buf_ptr;
2075  redo_no_start:
2076     c = *p;
2077     switch(c) {
2078     case ' ':
2079     case '\t':
2080         tok = c;
2081         p++;
2082         goto keep_tok_flags;
2083     case '\f':
2084     case '\v':
2085     case '\r':
2086         p++;
2087         goto redo_no_start;
2088     case '\\':
2089         /* first look if it is in fact an end of buffer */
2090         if (p >= file->buf_end) {
2091             file->buf_ptr = p;
2092             handle_eob();
2093             p = file->buf_ptr;
2094             if (p >= file->buf_end)
2095                 goto parse_eof;
2096             else
2097                 goto redo_no_start;
2098         } else {
2099             file->buf_ptr = p;
2100             ch = *p;
2101             handle_stray();
2102             p = file->buf_ptr;
2103             goto redo_no_start;
2104         }
2105     parse_eof:
2106         {
2107             TCCState *s1 = tcc_state;
2108             if ((parse_flags & PARSE_FLAG_LINEFEED)
2109                 && !(tok_flags & TOK_FLAG_EOF)) {
2110                 tok_flags |= TOK_FLAG_EOF;
2111                 tok = TOK_LINEFEED;
2112                 goto keep_tok_flags;
2113             } else if (!(parse_flags & PARSE_FLAG_PREPROCESS)) {
2114                 tok = TOK_EOF;
2115             } else if (s1->ifdef_stack_ptr != file->ifdef_stack_ptr) {
2116                 tcc_error("missing #endif");
2117             } else if (s1->include_stack_ptr == s1->include_stack) {
2118                 /* no include left : end of file. */
2119                 tok = TOK_EOF;
2120             } else {
2121                 tok_flags &= ~TOK_FLAG_EOF;
2122                 /* pop include file */
2123                 
2124                 /* test if previous '#endif' was after a #ifdef at
2125                    start of file */
2126                 if (tok_flags & TOK_FLAG_ENDIF) {
2127 #ifdef INC_DEBUG
2128                     printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL));
2129 #endif
2130                     add_cached_include(s1, file->filename, file->ifndef_macro_saved);
2131                     tok_flags &= ~TOK_FLAG_ENDIF;
2132                 }
2133
2134                 /* add end of include file debug info */
2135                 if (tcc_state->do_debug) {
2136                     put_stabd(N_EINCL, 0, 0);
2137                 }
2138                 /* pop include stack */
2139                 tcc_close();
2140                 s1->include_stack_ptr--;
2141                 p = file->buf_ptr;
2142                 goto redo_no_start;
2143             }
2144         }
2145         break;
2146
2147     case '\n':
2148         file->line_num++;
2149         tok_flags |= TOK_FLAG_BOL;
2150         p++;
2151 maybe_newline:
2152         if (0 == (parse_flags & PARSE_FLAG_LINEFEED))
2153             goto redo_no_start;
2154         tok = TOK_LINEFEED;
2155         goto keep_tok_flags;
2156
2157     case '#':
2158         /* XXX: simplify */
2159         PEEKC(c, p);
2160         if ((tok_flags & TOK_FLAG_BOL) && 
2161             (parse_flags & PARSE_FLAG_PREPROCESS)) {
2162             file->buf_ptr = p;
2163             preprocess(tok_flags & TOK_FLAG_BOF);
2164             p = file->buf_ptr;
2165             goto maybe_newline;
2166         } else {
2167             if (c == '#') {
2168                 p++;
2169                 tok = TOK_TWOSHARPS;
2170             } else {
2171                 if (parse_flags & PARSE_FLAG_ASM_COMMENTS) {
2172                     p = parse_line_comment(p - 1);
2173                     goto redo_no_start;
2174                 } else {
2175                     tok = '#';
2176                 }
2177             }
2178         }
2179         break;
2180
2181     case 'a': case 'b': case 'c': case 'd':
2182     case 'e': case 'f': case 'g': case 'h':
2183     case 'i': case 'j': case 'k': case 'l':
2184     case 'm': case 'n': case 'o': case 'p':
2185     case 'q': case 'r': case 's': case 't':
2186     case 'u': case 'v': case 'w': case 'x':
2187     case 'y': case 'z': 
2188     case 'A': case 'B': case 'C': case 'D':
2189     case 'E': case 'F': case 'G': case 'H':
2190     case 'I': case 'J': case 'K': 
2191     case 'M': case 'N': case 'O': case 'P':
2192     case 'Q': case 'R': case 'S': case 'T':
2193     case 'U': case 'V': case 'W': case 'X':
2194     case 'Y': case 'Z': 
2195     case '_':
2196     parse_ident_fast:
2197         p1 = p;
2198         h = TOK_HASH_INIT;
2199         h = TOK_HASH_FUNC(h, c);
2200         p++;
2201         for(;;) {
2202             c = *p;
2203             if (!isidnum_table[c-CH_EOF])
2204                 break;
2205             h = TOK_HASH_FUNC(h, c);
2206             p++;
2207         }
2208         if (c != '\\') {
2209             TokenSym **pts;
2210             int len;
2211
2212             /* fast case : no stray found, so we have the full token
2213                and we have already hashed it */
2214             len = p - p1;
2215             h &= (TOK_HASH_SIZE - 1);
2216             pts = &hash_ident[h];
2217             for(;;) {
2218                 ts = *pts;
2219                 if (!ts)
2220                     break;
2221                 if (ts->len == len && !memcmp(ts->str, p1, len))
2222                     goto token_found;
2223                 pts = &(ts->hash_next);
2224             }
2225             ts = tok_alloc_new(pts, p1, len);
2226         token_found: ;
2227         } else {
2228             /* slower case */
2229             cstr_reset(&tokcstr);
2230
2231             while (p1 < p) {
2232                 cstr_ccat(&tokcstr, *p1);
2233                 p1++;
2234             }
2235             p--;
2236             PEEKC(c, p);
2237         parse_ident_slow:
2238             while (isidnum_table[c-CH_EOF]) {
2239                 cstr_ccat(&tokcstr, c);
2240                 PEEKC(c, p);
2241             }
2242             ts = tok_alloc(tokcstr.data, tokcstr.size);
2243         }
2244         tok = ts->tok;
2245         break;
2246     case 'L':
2247         t = p[1];
2248         if (t != '\\' && t != '\'' && t != '\"') {
2249             /* fast case */
2250             goto parse_ident_fast;
2251         } else {
2252             PEEKC(c, p);
2253             if (c == '\'' || c == '\"') {
2254                 is_long = 1;
2255                 goto str_const;
2256             } else {
2257                 cstr_reset(&tokcstr);
2258                 cstr_ccat(&tokcstr, 'L');
2259                 goto parse_ident_slow;
2260             }
2261         }
2262         break;
2263     case '0': case '1': case '2': case '3':
2264     case '4': case '5': case '6': case '7':
2265     case '8': case '9':
2266
2267         cstr_reset(&tokcstr);
2268         /* after the first digit, accept digits, alpha, '.' or sign if
2269            prefixed by 'eEpP' */
2270     parse_num:
2271         for(;;) {
2272             t = c;
2273             cstr_ccat(&tokcstr, c);
2274             PEEKC(c, p);
2275             if (!(isnum(c) || isid(c) || c == '.' ||
2276                   ((c == '+' || c == '-') && 
2277                    (t == 'e' || t == 'E' || t == 'p' || t == 'P'))))
2278                 break;
2279         }
2280         /* We add a trailing '\0' to ease parsing */
2281         cstr_ccat(&tokcstr, '\0');
2282         tokc.cstr = &tokcstr;
2283         tok = TOK_PPNUM;
2284         break;
2285     case '.':
2286         /* special dot handling because it can also start a number */
2287         PEEKC(c, p);
2288         if (isnum(c)) {
2289             cstr_reset(&tokcstr);
2290             cstr_ccat(&tokcstr, '.');
2291             goto parse_num;
2292         } else if (c == '.') {
2293             PEEKC(c, p);
2294             if (c != '.')
2295                 expect("'.'");
2296             PEEKC(c, p);
2297             tok = TOK_DOTS;
2298         } else {
2299             tok = '.';
2300         }
2301         break;
2302     case '\'':
2303     case '\"':
2304         is_long = 0;
2305     str_const:
2306         {
2307             CString str;
2308             int sep;
2309
2310             sep = c;
2311
2312             /* parse the string */
2313             cstr_new(&str);
2314             p = parse_pp_string(p, sep, &str);
2315             cstr_ccat(&str, '\0');
2316             
2317             /* eval the escape (should be done as TOK_PPNUM) */
2318             cstr_reset(&tokcstr);
2319             parse_escape_string(&tokcstr, str.data, is_long);
2320             cstr_free(&str);
2321
2322             if (sep == '\'') {
2323                 int char_size;
2324                 /* XXX: make it portable */
2325                 if (!is_long)
2326                     char_size = 1;
2327                 else
2328                     char_size = sizeof(nwchar_t);
2329                 if (tokcstr.size <= char_size)
2330                     tcc_error("empty character constant");
2331                 if (tokcstr.size > 2 * char_size)
2332                     tcc_warning("multi-character character constant");
2333                 if (!is_long) {
2334                     tokc.i = *(int8_t *)tokcstr.data;
2335                     tok = TOK_CCHAR;
2336                 } else {
2337                     tokc.i = *(nwchar_t *)tokcstr.data;
2338                     tok = TOK_LCHAR;
2339                 }
2340             } else {
2341                 tokc.cstr = &tokcstr;
2342                 if (!is_long)
2343                     tok = TOK_STR;
2344                 else
2345                     tok = TOK_LSTR;
2346             }
2347         }
2348         break;
2349
2350     case '<':
2351         PEEKC(c, p);
2352         if (c == '=') {
2353             p++;
2354             tok = TOK_LE;
2355         } else if (c == '<') {
2356             PEEKC(c, p);
2357             if (c == '=') {
2358                 p++;
2359                 tok = TOK_A_SHL;
2360             } else {
2361                 tok = TOK_SHL;
2362             }
2363         } else {
2364             tok = TOK_LT;
2365         }
2366         break;
2367         
2368     case '>':
2369         PEEKC(c, p);
2370         if (c == '=') {
2371             p++;
2372             tok = TOK_GE;
2373         } else if (c == '>') {
2374             PEEKC(c, p);
2375             if (c == '=') {
2376                 p++;
2377                 tok = TOK_A_SAR;
2378             } else {
2379                 tok = TOK_SAR;
2380             }
2381         } else {
2382             tok = TOK_GT;
2383         }
2384         break;
2385         
2386     case '&':
2387         PEEKC(c, p);
2388         if (c == '&') {
2389             p++;
2390             tok = TOK_LAND;
2391         } else if (c == '=') {
2392             p++;
2393             tok = TOK_A_AND;
2394         } else {
2395             tok = '&';
2396         }
2397         break;
2398         
2399     case '|':
2400         PEEKC(c, p);
2401         if (c == '|') {
2402             p++;
2403             tok = TOK_LOR;
2404         } else if (c == '=') {
2405             p++;
2406             tok = TOK_A_OR;
2407         } else {
2408             tok = '|';
2409         }
2410         break;
2411
2412     case '+':
2413         PEEKC(c, p);
2414         if (c == '+') {
2415             p++;
2416             tok = TOK_INC;
2417         } else if (c == '=') {
2418             p++;
2419             tok = TOK_A_ADD;
2420         } else {
2421             tok = '+';
2422         }
2423         break;
2424         
2425     case '-':
2426         PEEKC(c, p);
2427         if (c == '-') {
2428             p++;
2429             tok = TOK_DEC;
2430         } else if (c == '=') {
2431             p++;
2432             tok = TOK_A_SUB;
2433         } else if (c == '>') {
2434             p++;
2435             tok = TOK_ARROW;
2436         } else {
2437             tok = '-';
2438         }
2439         break;
2440
2441     PARSE2('!', '!', '=', TOK_NE)
2442     PARSE2('=', '=', '=', TOK_EQ)
2443     PARSE2('*', '*', '=', TOK_A_MUL)
2444     PARSE2('%', '%', '=', TOK_A_MOD)
2445     PARSE2('^', '^', '=', TOK_A_XOR)
2446         
2447         /* comments or operator */
2448     case '/':
2449         PEEKC(c, p);
2450         if (c == '*') {
2451             p = parse_comment(p);
2452             /* comments replaced by a blank */
2453             tok = ' ';
2454             goto keep_tok_flags;
2455         } else if (c == '/') {
2456             p = parse_line_comment(p);
2457             tok = ' ';
2458             goto keep_tok_flags;
2459         } else if (c == '=') {
2460             p++;
2461             tok = TOK_A_DIV;
2462         } else {
2463             tok = '/';
2464         }
2465         break;
2466         
2467         /* simple tokens */
2468     case '(':
2469     case ')':
2470     case '[':
2471     case ']':
2472     case '{':
2473     case '}':
2474     case ',':
2475     case ';':
2476     case ':':
2477     case '?':
2478     case '~':
2479     case '$': /* only used in assembler */
2480     case '@': /* dito */
2481         tok = c;
2482         p++;
2483         break;
2484     default:
2485         tcc_error("unrecognized character \\x%02x", c);
2486         break;
2487     }
2488     tok_flags = 0;
2489 keep_tok_flags:
2490     file->buf_ptr = p;
2491 #if defined(PARSE_DEBUG)
2492     printf("token = %s\n", get_tok_str(tok, &tokc));
2493 #endif
2494 }
2495
2496 /* return next token without macro substitution. Can read input from
2497    macro_ptr buffer */
2498 static void next_nomacro_spc(void)
2499 {
2500     if (macro_ptr) {
2501     redo:
2502         tok = *macro_ptr;
2503         if (tok) {
2504             TOK_GET(&tok, &macro_ptr, &tokc);
2505             if (tok == TOK_LINENUM) {
2506                 file->line_num = tokc.i;
2507                 goto redo;
2508             }
2509         }
2510     } else {
2511         next_nomacro1();
2512     }
2513 }
2514
2515 ST_FUNC void next_nomacro(void)
2516 {
2517     do {
2518         next_nomacro_spc();
2519     } while (is_space(tok));
2520 }
2521  
2522 /* substitute args in macro_str and return allocated string */
2523 static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args)
2524 {
2525     int last_tok, t, spc;
2526     const int *st;
2527     Sym *s;
2528     CValue cval;
2529     TokenString str;
2530     CString cstr;
2531
2532     tok_str_new(&str);
2533     last_tok = 0;
2534     while(1) {
2535         TOK_GET(&t, &macro_str, &cval);
2536         if (!t)
2537             break;
2538         if (t == '#') {
2539             /* stringize */
2540             TOK_GET(&t, &macro_str, &cval);
2541             if (!t)
2542                 break;
2543             s = sym_find2(args, t);
2544             if (s) {
2545                 cstr_new(&cstr);
2546                 st = s->d;
2547                 spc = 0;
2548                 while (*st) {
2549                     TOK_GET(&t, &st, &cval);
2550                     if (!check_space(t, &spc))
2551                         cstr_cat(&cstr, get_tok_str(t, &cval));
2552                 }
2553                 cstr.size -= spc;
2554                 cstr_ccat(&cstr, '\0');
2555 #ifdef PP_DEBUG
2556                 printf("stringize: %s\n", (char *)cstr.data);
2557 #endif
2558                 /* add string */
2559                 cval.cstr = &cstr;
2560                 tok_str_add2(&str, TOK_STR, &cval);
2561                 cstr_free(&cstr);
2562             } else {
2563                 tok_str_add2(&str, t, &cval);
2564             }
2565         } else if (t >= TOK_IDENT) {
2566             s = sym_find2(args, t);
2567             if (s) {
2568                 st = s->d;
2569                 /* if '##' is present before or after, no arg substitution */
2570                 if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
2571                     /* special case for var arg macros : ## eats the
2572                        ',' if empty VA_ARGS variable. */
2573                     /* XXX: test of the ',' is not 100%
2574                        reliable. should fix it to avoid security
2575                        problems */
2576                     if (gnu_ext && s->type.t &&
2577                         last_tok == TOK_TWOSHARPS && 
2578                         str.len >= 2 && str.str[str.len - 2] == ',') {
2579                         if (*st == 0) {
2580                             /* suppress ',' '##' */
2581                             str.len -= 2;
2582                         } else {
2583                             /* suppress '##' and add variable */
2584                             str.len--;
2585                             goto add_var;
2586                         }
2587                     } else {
2588                         int t1;
2589                     add_var:
2590                         for(;;) {
2591                             TOK_GET(&t1, &st, &cval);
2592                             if (!t1)
2593                                 break;
2594                             tok_str_add2(&str, t1, &cval);
2595                         }
2596                     }
2597                 } else {
2598                     /* NOTE: the stream cannot be read when macro
2599                        substituing an argument */
2600                     macro_subst(&str, nested_list, st, NULL);
2601                 }
2602             } else {
2603                 tok_str_add(&str, t);
2604             }
2605         } else {
2606             tok_str_add2(&str, t, &cval);
2607         }
2608         last_tok = t;
2609     }
2610     tok_str_add(&str, 0);
2611     return str.str;
2612 }
2613
2614 static char const ab_month_name[12][4] =
2615 {
2616     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2617     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
2618 };
2619
2620 /* do macro substitution of current token with macro 's' and add
2621    result to (tok_str,tok_len). 'nested_list' is the list of all
2622    macros we got inside to avoid recursing. Return non zero if no
2623    substitution needs to be done */
2624 static int macro_subst_tok(TokenString *tok_str,
2625                            Sym **nested_list, Sym *s, struct macro_level **can_read_stream)
2626 {
2627     Sym *args, *sa, *sa1;
2628     int mstr_allocated, parlevel, *mstr, t, t1, spc;
2629     const int *p;
2630     TokenString str;
2631     char *cstrval;
2632     CValue cval;
2633     CString cstr;
2634     char buf[32];
2635     
2636     /* if symbol is a macro, prepare substitution */
2637     /* special macros */
2638     if (tok == TOK___LINE__) {
2639         snprintf(buf, sizeof(buf), "%d", file->line_num);
2640         cstrval = buf;
2641         t1 = TOK_PPNUM;
2642         goto add_cstr1;
2643     } else if (tok == TOK___FILE__) {
2644         cstrval = file->filename;
2645         goto add_cstr;
2646     } else if (tok == TOK___DATE__ || tok == TOK___TIME__) {
2647         time_t ti;
2648         struct tm *tm;
2649
2650         time(&ti);
2651         tm = localtime(&ti);
2652         if (tok == TOK___DATE__) {
2653             snprintf(buf, sizeof(buf), "%s %2d %d", 
2654                      ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900);
2655         } else {
2656             snprintf(buf, sizeof(buf), "%02d:%02d:%02d", 
2657                      tm->tm_hour, tm->tm_min, tm->tm_sec);
2658         }
2659         cstrval = buf;
2660     add_cstr:
2661         t1 = TOK_STR;
2662     add_cstr1:
2663         cstr_new(&cstr);
2664         cstr_cat(&cstr, cstrval);
2665         cstr_ccat(&cstr, '\0');
2666         cval.cstr = &cstr;
2667         tok_str_add2(tok_str, t1, &cval);
2668         cstr_free(&cstr);
2669     } else {
2670         mstr = s->d;
2671         mstr_allocated = 0;
2672         if (s->type.t == MACRO_FUNC) {
2673             /* NOTE: we do not use next_nomacro to avoid eating the
2674                next token. XXX: find better solution */
2675         redo:
2676             if (macro_ptr) {
2677                 p = macro_ptr;
2678                 while (is_space(t = *p) || TOK_LINEFEED == t) 
2679                     ++p;
2680                 if (t == 0 && can_read_stream) {
2681                     /* end of macro stream: we must look at the token
2682                        after in the file */
2683                     struct macro_level *ml = *can_read_stream;
2684                     macro_ptr = NULL;
2685                     if (ml)
2686                     {
2687                         macro_ptr = ml->p;
2688                         ml->p = NULL;
2689                         *can_read_stream = ml -> prev;
2690                     }
2691                     /* also, end of scope for nested defined symbol */
2692                     (*nested_list)->v = -1;
2693                     goto redo;
2694                 }
2695             } else {
2696                 ch = file->buf_ptr[0];
2697                 while (is_space(ch) || ch == '\n' || ch == '/')
2698                   {
2699                     if (ch == '/')
2700                       {
2701                         int c;
2702                         uint8_t *p = file->buf_ptr;
2703                         PEEKC(c, p);
2704                         if (c == '*') {
2705                             p = parse_comment(p);
2706                             file->buf_ptr = p - 1;
2707                         } else if (c == '/') {
2708                             p = parse_line_comment(p);
2709                             file->buf_ptr = p - 1;
2710                         } else
2711                           break;
2712                       }
2713                     cinp();
2714                   }
2715                 t = ch;
2716             }
2717             if (t != '(') /* no macro subst */
2718                 return -1;
2719                     
2720             /* argument macro */
2721             next_nomacro();
2722             next_nomacro();
2723             args = NULL;
2724             sa = s->next;
2725             /* NOTE: empty args are allowed, except if no args */
2726             for(;;) {
2727                 /* handle '()' case */
2728                 if (!args && !sa && tok == ')')
2729                     break;
2730                 if (!sa)
2731                     tcc_error("macro '%s' used with too many args",
2732                           get_tok_str(s->v, 0));
2733                 tok_str_new(&str);
2734                 parlevel = spc = 0;
2735                 /* NOTE: non zero sa->t indicates VA_ARGS */
2736                 while ((parlevel > 0 || 
2737                         (tok != ')' && 
2738                          (tok != ',' || sa->type.t))) && 
2739                        tok != -1) {
2740                     if (tok == '(')
2741                         parlevel++;
2742                     else if (tok == ')')
2743                         parlevel--;
2744                     if (tok == TOK_LINEFEED)
2745                         tok = ' ';
2746                     if (!check_space(tok, &spc))
2747                         tok_str_add2(&str, tok, &tokc);
2748                     next_nomacro_spc();
2749                 }
2750                 str.len -= spc;
2751                 tok_str_add(&str, 0);
2752                 sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0);
2753                 sa1->d = str.str;
2754                 sa = sa->next;
2755                 if (tok == ')') {
2756                     /* special case for gcc var args: add an empty
2757                        var arg argument if it is omitted */
2758                     if (sa && sa->type.t && gnu_ext)
2759                         continue;
2760                     else
2761                         break;
2762                 }
2763                 if (tok != ',')
2764                     expect(",");
2765                 next_nomacro();
2766             }
2767             if (sa) {
2768                 tcc_error("macro '%s' used with too few args",
2769                       get_tok_str(s->v, 0));
2770             }
2771
2772             /* now subst each arg */
2773             mstr = macro_arg_subst(nested_list, mstr, args);
2774             /* free memory */
2775             sa = args;
2776             while (sa) {
2777                 sa1 = sa->prev;
2778                 tok_str_free(sa->d);
2779                 sym_free(sa);
2780                 sa = sa1;
2781             }
2782             mstr_allocated = 1;
2783         }
2784         sym_push2(nested_list, s->v, 0, 0);
2785         macro_subst(tok_str, nested_list, mstr, can_read_stream);
2786         /* pop nested defined symbol */
2787         sa1 = *nested_list;
2788         *nested_list = sa1->prev;
2789         sym_free(sa1);
2790         if (mstr_allocated)
2791             tok_str_free(mstr);
2792     }
2793     return 0;
2794 }
2795
2796 /* handle the '##' operator. Return NULL if no '##' seen. Otherwise
2797    return the resulting string (which must be freed). */
2798 static inline int *macro_twosharps(const int *macro_str)
2799 {
2800     const int *ptr;
2801     int t;
2802     TokenString macro_str1;
2803     CString cstr;
2804     int n, start_of_nosubsts;
2805
2806     /* we search the first '##' */
2807     for(ptr = macro_str;;) {
2808         CValue cval;
2809         TOK_GET(&t, &ptr, &cval);
2810         if (t == TOK_TWOSHARPS)
2811             break;
2812         /* nothing more to do if end of string */
2813         if (t == 0)
2814             return NULL;
2815     }
2816
2817     /* we saw '##', so we need more processing to handle it */
2818     start_of_nosubsts = -1;
2819     tok_str_new(&macro_str1);
2820     for(ptr = macro_str;;) {
2821         TOK_GET(&tok, &ptr, &tokc);
2822         if (tok == 0)
2823             break;
2824         if (tok == TOK_TWOSHARPS)
2825             continue;
2826         if (tok == TOK_NOSUBST && start_of_nosubsts < 0)
2827             start_of_nosubsts = macro_str1.len;
2828         while (*ptr == TOK_TWOSHARPS) {
2829             /* given 'a##b', remove nosubsts preceding 'a' */
2830             if (start_of_nosubsts >= 0)
2831                 macro_str1.len = start_of_nosubsts;
2832             /* given 'a##b', skip '##' */
2833             t = *++ptr;
2834             /* given 'a##b', remove nosubsts preceding 'b' */
2835             while (t == TOK_NOSUBST)
2836                 t = *++ptr;
2837             if (t && t != TOK_TWOSHARPS) {
2838                 CValue cval;
2839                 TOK_GET(&t, &ptr, &cval);
2840                 /* We concatenate the two tokens */
2841                 cstr_new(&cstr);
2842                 cstr_cat(&cstr, get_tok_str(tok, &tokc));
2843                 n = cstr.size;
2844                 cstr_cat(&cstr, get_tok_str(t, &cval));
2845                 cstr_ccat(&cstr, '\0');
2846
2847                 tcc_open_bf(tcc_state, ":paste:", cstr.size);
2848                 memcpy(file->buffer, cstr.data, cstr.size);
2849                 for (;;) {
2850                     next_nomacro1();
2851                     if (0 == *file->buf_ptr)
2852                         break;
2853                     tok_str_add2(&macro_str1, tok, &tokc);
2854                     tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid preprocessing token",
2855                         n, cstr.data, (char*)cstr.data + n);
2856                 }
2857                 tcc_close();
2858                 cstr_free(&cstr);
2859             }
2860         }
2861         if (tok != TOK_NOSUBST) 
2862             start_of_nosubsts = -1;
2863         tok_str_add2(&macro_str1, tok, &tokc);
2864     }
2865     tok_str_add(&macro_str1, 0);
2866     return macro_str1.str;
2867 }
2868
2869
2870 /* do macro substitution of macro_str and add result to
2871    (tok_str,tok_len). 'nested_list' is the list of all macros we got
2872    inside to avoid recursing. */
2873 static void macro_subst(TokenString *tok_str, Sym **nested_list, 
2874                         const int *macro_str, struct macro_level ** can_read_stream)
2875 {
2876     Sym *s;
2877     int *macro_str1;
2878     const int *ptr;
2879     int t, ret, spc;
2880     CValue cval;
2881     struct macro_level ml;
2882     int force_blank;
2883     
2884     /* first scan for '##' operator handling */
2885     ptr = macro_str;
2886     macro_str1 = macro_twosharps(ptr);
2887
2888     if (macro_str1) 
2889         ptr = macro_str1;
2890     spc = 0;
2891     force_blank = 0;
2892
2893     while (1) {
2894         /* NOTE: ptr == NULL can only happen if tokens are read from
2895            file stream due to a macro function call */
2896         if (ptr == NULL)
2897             break;
2898         TOK_GET(&t, &ptr, &cval);
2899         if (t == 0)
2900             break;
2901         if (t == TOK_NOSUBST) {
2902             /* following token has already been subst'd. just copy it on */
2903             tok_str_add2(tok_str, TOK_NOSUBST, NULL);
2904             TOK_GET(&t, &ptr, &cval);
2905             goto no_subst;
2906         }
2907         s = define_find(t);
2908         if (s != NULL) {
2909             /* if nested substitution, do nothing */
2910             if (sym_find2(*nested_list, t)) {
2911                 /* and mark it as TOK_NOSUBST, so it doesn't get subst'd again */
2912                 tok_str_add2(tok_str, TOK_NOSUBST, NULL);
2913                 goto no_subst;
2914             }
2915             ml.p = macro_ptr;
2916             if (can_read_stream)
2917                 ml.prev = *can_read_stream, *can_read_stream = &ml;
2918             macro_ptr = (int *)ptr;
2919             tok = t;
2920             ret = macro_subst_tok(tok_str, nested_list, s, can_read_stream);
2921             ptr = (int *)macro_ptr;
2922             macro_ptr = ml.p;
2923             if (can_read_stream && *can_read_stream == &ml)
2924                 *can_read_stream = ml.prev;
2925             if (ret != 0)
2926                 goto no_subst;
2927             if (parse_flags & PARSE_FLAG_SPACES)
2928                 force_blank = 1;
2929         } else {
2930         no_subst:
2931             if (force_blank) {
2932                 tok_str_add(tok_str, ' ');
2933                 spc = 1;
2934                 force_blank = 0;
2935             }
2936             if (!check_space(t, &spc)) 
2937                 tok_str_add2(tok_str, t, &cval);
2938         }
2939     }
2940     if (macro_str1)
2941         tok_str_free(macro_str1);
2942 }
2943
2944 /* return next token with macro substitution */
2945 ST_FUNC void next(void)
2946 {
2947     Sym *nested_list, *s;
2948     TokenString str;
2949     struct macro_level *ml;
2950
2951  redo:
2952     if (parse_flags & PARSE_FLAG_SPACES)
2953         next_nomacro_spc();
2954     else
2955         next_nomacro();
2956     if (!macro_ptr) {
2957         /* if not reading from macro substituted string, then try
2958            to substitute macros */
2959         if (tok >= TOK_IDENT &&
2960             (parse_flags & PARSE_FLAG_PREPROCESS)) {
2961             s = define_find(tok);
2962             if (s) {
2963                 /* we have a macro: we try to substitute */
2964                 tok_str_new(&str);
2965                 nested_list = NULL;
2966                 ml = NULL;
2967                 if (macro_subst_tok(&str, &nested_list, s, &ml) == 0) {
2968                     /* substitution done, NOTE: maybe empty */
2969                     tok_str_add(&str, 0);
2970                     macro_ptr = str.str;
2971                     macro_ptr_allocated = str.str;
2972                     goto redo;
2973                 }
2974             }
2975         }
2976     } else {
2977         if (tok == 0) {
2978             /* end of macro or end of unget buffer */
2979             if (unget_buffer_enabled) {
2980                 macro_ptr = unget_saved_macro_ptr;
2981                 unget_buffer_enabled = 0;
2982             } else {
2983                 /* end of macro string: free it */
2984                 tok_str_free(macro_ptr_allocated);
2985                 macro_ptr_allocated = NULL;
2986                 macro_ptr = NULL;
2987             }
2988             goto redo;
2989         } else if (tok == TOK_NOSUBST) {
2990             /* discard preprocessor's nosubst markers */
2991             goto redo;
2992         }
2993     }
2994     
2995     /* convert preprocessor tokens into C tokens */
2996     if (tok == TOK_PPNUM &&
2997         (parse_flags & PARSE_FLAG_TOK_NUM)) {
2998         parse_number((char *)tokc.cstr->data);
2999     }
3000 }
3001
3002 /* push back current token and set current token to 'last_tok'. Only
3003    identifier case handled for labels. */
3004 ST_INLN void unget_tok(int last_tok)
3005 {
3006     int i, n;
3007     int *q;
3008     if (unget_buffer_enabled)
3009       {
3010         /* assert(macro_ptr == unget_saved_buffer + 1);
3011            assert(*macro_ptr == 0);  */
3012       }
3013     else
3014       {
3015         unget_saved_macro_ptr = macro_ptr;
3016         unget_buffer_enabled = 1;
3017       }
3018     q = unget_saved_buffer;
3019     macro_ptr = q;
3020     *q++ = tok;
3021     n = tok_ext_size(tok) - 1;
3022     for(i=0;i<n;i++)
3023         *q++ = tokc.tab[i];
3024     *q = 0; /* end of token string */
3025     tok = last_tok;
3026 }
3027
3028
3029 /* better than nothing, but needs extension to handle '-E' option
3030    correctly too */
3031 ST_FUNC void preprocess_init(TCCState *s1)
3032 {
3033     s1->include_stack_ptr = s1->include_stack;
3034     /* XXX: move that before to avoid having to initialize
3035        file->ifdef_stack_ptr ? */
3036     s1->ifdef_stack_ptr = s1->ifdef_stack;
3037     file->ifdef_stack_ptr = s1->ifdef_stack_ptr;
3038
3039     vtop = vstack - 1;
3040     s1->pack_stack[0] = 0;
3041     s1->pack_stack_ptr = s1->pack_stack;
3042 }
3043
3044 ST_FUNC void preprocess_new(void)
3045 {
3046     int i, c;
3047     const char *p, *r;
3048
3049     /* init isid table */
3050     for(i=CH_EOF;i<256;i++)
3051         isidnum_table[i-CH_EOF] = isid(i) || isnum(i);
3052
3053     /* add all tokens */
3054     table_ident = NULL;
3055     memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
3056     
3057     tok_ident = TOK_IDENT;
3058     p = tcc_keywords;
3059     while (*p) {
3060         r = p;
3061         for(;;) {
3062             c = *r++;
3063             if (c == '\0')
3064                 break;
3065         }
3066         tok_alloc(p, r - p - 1);
3067         p = r;
3068     }
3069 }
3070
3071 /* Preprocess the current file */
3072 ST_FUNC int tcc_preprocess(TCCState *s1)
3073 {
3074     Sym *define_start;
3075
3076     BufferedFile *file_ref, **iptr, **iptr_new;
3077     int token_seen, line_ref, d;
3078     const char *s;
3079
3080     preprocess_init(s1);
3081     define_start = define_stack;
3082     ch = file->buf_ptr[0];
3083     tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
3084     parse_flags = PARSE_FLAG_ASM_COMMENTS | PARSE_FLAG_PREPROCESS |
3085         PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES;
3086     token_seen = 0;
3087     line_ref = 0;
3088     file_ref = NULL;
3089     iptr = s1->include_stack_ptr;
3090
3091     for (;;) {
3092         next();
3093         if (tok == TOK_EOF) {
3094             break;
3095         } else if (file != file_ref) {
3096             goto print_line;
3097         } else if (tok == TOK_LINEFEED) {
3098             if (!token_seen)
3099                 continue;
3100             ++line_ref;
3101             token_seen = 0;
3102         } else if (!token_seen) {
3103             d = file->line_num - line_ref;
3104             if (file != file_ref || d < 0 || d >= 8) {
3105 print_line:
3106                 iptr_new = s1->include_stack_ptr;
3107                 s = iptr_new > iptr ? " 1"
3108                   : iptr_new < iptr ? " 2"
3109                   : iptr_new > s1->include_stack ? " 3"
3110                   : ""
3111                   ;
3112                 iptr = iptr_new;
3113                 fprintf(s1->ppfp, "# %d \"%s\"%s\n", file->line_num, file->filename, s);
3114             } else {
3115                 while (d)
3116                     fputs("\n", s1->ppfp), --d;
3117             }
3118             line_ref = (file_ref = file)->line_num;
3119             token_seen = tok != TOK_LINEFEED;
3120             if (!token_seen)
3121                 continue;
3122         }
3123         fputs(get_tok_str(tok, &tokc), s1->ppfp);
3124     }
3125     free_defines(define_start);
3126     return 0;
3127 }