Ignore:
Timestamp:
Jan 21, 2018, 12:10:09 AM (6 years ago)
Author:
coas-nagasima
Message:

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

Location:
EcnlProtoTool/trunk/tcc-0.9.27
Files:
1 edited
1 moved

Legend:

Unmodified
Added
Removed
  • EcnlProtoTool/trunk/tcc-0.9.27/tccpp.c

    r321 r331  
    2525
    2626ST_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 
    3327ST_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) */
    4128
    4229ST_DATA struct BufferedFile *file;
     
    5441/* ------------------------------------------------------------------------- */
    5542
    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;
    6043static TokenSym *hash_ident[TOK_HASH_SIZE];
    6144static char token_buf[STRING_MAX_SIZE + 1];
    62 /* true if isid(c) || isnum(c) */
    63 static unsigned char isidnum_table[256-CH_EOF];
     45static CString cstr_buf;
     46static CString macro_equal_buf;
     47static TokenString tokstr_buf;
     48static unsigned char isidnum_table[256 - CH_EOF];
     49static int pp_debug_tok, pp_debug_symv;
     50static int pp_once;
     51static int pp_expr;
     52static int pp_counter;
     53static void tok_print(const char *msg, const int *str);
     54
     55static struct TinyAlloc *toksym_alloc;
     56static struct TinyAlloc *tokstr_alloc;
     57static struct TinyAlloc *cstr_alloc;
     58
     59static TokenString *macro_stack;
    6460
    6561static const char tcc_keywords[] =
     
    7167/* WARNING: the content of this string encodes token numbers */
    7268static const unsigned char tok_two_chars[] =
     69/* outdated -- gr
    7370    "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253"
    7471    "-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266";
    75 
    76 struct macro_level {
    77     struct macro_level *prev;
    78     const int *p;
     72*/{
     73    '<','=', TOK_LE,
     74    '>','=', TOK_GE,
     75    '!','=', TOK_NE,
     76    '&','&', TOK_LAND,
     77    '|','|', TOK_LOR,
     78    '+','+', TOK_INC,
     79    '-','-', TOK_DEC,
     80    '=','=', TOK_EQ,
     81    '<','<', TOK_SHL,
     82    '>','>', TOK_SAR,
     83    '+','=', TOK_A_ADD,
     84    '-','=', TOK_A_SUB,
     85    '*','=', TOK_A_MUL,
     86    '/','=', TOK_A_DIV,
     87    '%','=', TOK_A_MOD,
     88    '&','=', TOK_A_AND,
     89    '^','=', TOK_A_XOR,
     90    '|','=', TOK_A_OR,
     91    '-','>', TOK_ARROW,
     92    '.','.', TOK_TWODOTS,
     93    '#','#', TOK_TWOSHARPS,
     94    0
    7995};
    8096
    81 ST_FUNC void next_nomacro(void);
    8297static void next_nomacro_spc(void);
    83 static void macro_subst(
    84     TokenString *tok_str,
    85     Sym **nested_list,
    86     const int *macro_str,
    87     struct macro_level **can_read_stream
    88     );
    8998
    9099ST_FUNC void skip(int c)
     
    101110
    102111/* ------------------------------------------------------------------------- */
     112/* Custom allocator for tiny objects */
     113
     114//#define USE_TAL
     115
     116#ifndef USE_TAL
     117#define tal_free(al, p) tcc_free(p)
     118#define tal_realloc(al, p, size) tcc_realloc(p, size)
     119#define tal_new(a,b,c)
     120#define tal_delete(a)
     121#else
     122#if !defined(MEM_DEBUG)
     123#define tal_free(al, p) tal_free_impl(al, p)
     124#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size)
     125#define TAL_DEBUG_PARAMS
     126#else
     127#define TAL_DEBUG 1
     128//#define TAL_INFO 1 /* collect and dump allocators stats */
     129#define tal_free(al, p) tal_free_impl(al, p, __FILE__, __LINE__)
     130#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size, __FILE__, __LINE__)
     131#define TAL_DEBUG_PARAMS , const char *file, int line
     132#define TAL_DEBUG_FILE_LEN 40
     133#endif
     134
     135#define TOKSYM_TAL_SIZE     (768 * 1024) /* allocator for tiny TokenSym in table_ident */
     136#define TOKSTR_TAL_SIZE     (768 * 1024) /* allocator for tiny TokenString instances */
     137#define CSTR_TAL_SIZE       (256 * 1024) /* allocator for tiny CString instances */
     138#define TOKSYM_TAL_LIMIT    256 /* prefer unique limits to distinguish allocators debug msgs */
     139#define TOKSTR_TAL_LIMIT    128 /* 32 * sizeof(int) */
     140#define CSTR_TAL_LIMIT      1024
     141
     142typedef struct TinyAlloc {
     143    unsigned  limit;
     144    unsigned  size;
     145    uint8_t *buffer;
     146    uint8_t *p;
     147    unsigned  nb_allocs;
     148    struct TinyAlloc *next, *top;
     149#ifdef TAL_INFO
     150    unsigned  nb_peak;
     151    unsigned  nb_total;
     152    unsigned  nb_missed;
     153    uint8_t *peak_p;
     154#endif
     155} TinyAlloc;
     156
     157typedef struct tal_header_t {
     158    unsigned  size;
     159#ifdef TAL_DEBUG
     160    int     line_num; /* negative line_num used for double free check */
     161    char    file_name[TAL_DEBUG_FILE_LEN + 1];
     162#endif
     163} tal_header_t;
     164
     165/* ------------------------------------------------------------------------- */
     166
     167static TinyAlloc *tal_new(TinyAlloc **pal, unsigned limit, unsigned size)
     168{
     169    TinyAlloc *al = tcc_mallocz(sizeof(TinyAlloc));
     170    al->p = al->buffer = tcc_malloc(size);
     171    al->limit = limit;
     172    al->size = size;
     173    if (pal) *pal = al;
     174    return al;
     175}
     176
     177static void tal_delete(TinyAlloc *al)
     178{
     179    TinyAlloc *next;
     180
     181tail_call:
     182    if (!al)
     183        return;
     184#ifdef TAL_INFO
     185    fprintf(stderr, "limit=%5d, size=%5g MB, nb_peak=%6d, nb_total=%8d, nb_missed=%6d, usage=%5.1f%%\n",
     186            al->limit, al->size / 1024.0 / 1024.0, al->nb_peak, al->nb_total, al->nb_missed,
     187            (al->peak_p - al->buffer) * 100.0 / al->size);
     188#endif
     189#ifdef TAL_DEBUG
     190    if (al->nb_allocs > 0) {
     191        uint8_t *p;
     192        fprintf(stderr, "TAL_DEBUG: memory leak %d chunk(s) (limit= %d)\n",
     193                al->nb_allocs, al->limit);
     194        p = al->buffer;
     195        while (p < al->p) {
     196            tal_header_t *header = (tal_header_t *)p;
     197            if (header->line_num > 0) {
     198                fprintf(stderr, "%s:%d: chunk of %d bytes leaked\n",
     199                        header->file_name, header->line_num, header->size);
     200            }
     201            p += header->size + sizeof(tal_header_t);
     202        }
     203#if MEM_DEBUG-0 == 2
     204        exit(2);
     205#endif
     206    }
     207#endif
     208    next = al->next;
     209    tcc_free(al->buffer);
     210    tcc_free(al);
     211    al = next;
     212    goto tail_call;
     213}
     214
     215static void tal_free_impl(TinyAlloc *al, void *p TAL_DEBUG_PARAMS)
     216{
     217    if (!p)
     218        return;
     219tail_call:
     220    if (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size) {
     221#ifdef TAL_DEBUG
     222        tal_header_t *header = (((tal_header_t *)p) - 1);
     223        if (header->line_num < 0) {
     224            fprintf(stderr, "%s:%d: TAL_DEBUG: double frees chunk from\n",
     225                    file, line);
     226            fprintf(stderr, "%s:%d: %d bytes\n",
     227                    header->file_name, (int)-header->line_num, (int)header->size);
     228        } else
     229            header->line_num = -header->line_num;
     230#endif
     231        al->nb_allocs--;
     232        if (!al->nb_allocs)
     233            al->p = al->buffer;
     234    } else if (al->next) {
     235        al = al->next;
     236        goto tail_call;
     237    }
     238    else
     239        tcc_free(p);
     240}
     241
     242static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_PARAMS)
     243{
     244    tal_header_t *header;
     245    void *ret;
     246    int is_own;
     247    unsigned adj_size = (size + 3) & -4;
     248    TinyAlloc *al = *pal;
     249
     250tail_call:
     251    is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size);
     252    if ((!p || is_own) && size <= al->limit) {
     253        if (al->p + adj_size + sizeof(tal_header_t) < al->buffer + al->size) {
     254            header = (tal_header_t *)al->p;
     255            header->size = adj_size;
     256#ifdef TAL_DEBUG
     257            { int ofs = strlen(file) - TAL_DEBUG_FILE_LEN;
     258            strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), TAL_DEBUG_FILE_LEN);
     259            header->file_name[TAL_DEBUG_FILE_LEN] = 0;
     260            header->line_num = line; }
     261#endif
     262            ret = al->p + sizeof(tal_header_t);
     263            al->p += adj_size + sizeof(tal_header_t);
     264            if (is_own) {
     265                header = (((tal_header_t *)p) - 1);
     266                memcpy(ret, p, header->size);
     267#ifdef TAL_DEBUG
     268                header->line_num = -header->line_num;
     269#endif
     270            } else {
     271                al->nb_allocs++;
     272            }
     273#ifdef TAL_INFO
     274            if (al->nb_peak < al->nb_allocs)
     275                al->nb_peak = al->nb_allocs;
     276            if (al->peak_p < al->p)
     277                al->peak_p = al->p;
     278            al->nb_total++;
     279#endif
     280            return ret;
     281        } else if (is_own) {
     282            al->nb_allocs--;
     283            ret = tal_realloc(*pal, 0, size);
     284            header = (((tal_header_t *)p) - 1);
     285            memcpy(ret, p, header->size);
     286#ifdef TAL_DEBUG
     287            header->line_num = -header->line_num;
     288#endif
     289            return ret;
     290        }
     291        if (al->next) {
     292            al = al->next;
     293        } else {
     294            TinyAlloc *bottom = al, *next = al->top ? al->top : al;
     295
     296            al = tal_new(pal, next->limit, next->size * 2);
     297            al->next = next;
     298            bottom->top = al;
     299        }
     300        goto tail_call;
     301    }
     302    if (is_own) {
     303        al->nb_allocs--;
     304        ret = tcc_malloc(size);
     305        header = (((tal_header_t *)p) - 1);
     306        memcpy(ret, p, header->size);
     307#ifdef TAL_DEBUG
     308        header->line_num = -header->line_num;
     309#endif
     310    } else if (al->next) {
     311        al = al->next;
     312        goto tail_call;
     313    } else
     314        ret = tcc_realloc(p, size);
     315#ifdef TAL_INFO
     316    al->nb_missed++;
     317#endif
     318    return ret;
     319}
     320
     321#endif /* USE_TAL */
     322
     323/* ------------------------------------------------------------------------- */
    103324/* CString handling */
    104325static void cstr_realloc(CString *cstr, int new_size)
    105326{
    106327    int size;
    107     void *data;
    108328
    109329    size = cstr->size_allocated;
    110     if (size == 0)
     330    if (size < 8)
    111331        size = 8; /* no need to allocate a too small first string */
    112332    while (size < new_size)
    113333        size = size * 2;
    114     data = tcc_realloc(cstr->data_allocated, size);
    115     cstr->data_allocated = data;
     334    cstr->data = tal_realloc(cstr_alloc, cstr->data, size);
    116335    cstr->size_allocated = size;
    117     cstr->data = data;
    118336}
    119337
    120338/* add a byte */
    121 ST_FUNC void cstr_ccat(CString *cstr, int ch)
     339ST_INLN void cstr_ccat(CString *cstr, int ch)
    122340{
    123341    int size;
     
    129347}
    130348
    131 ST_FUNC void cstr_cat(CString *cstr, const char *str)
    132 {
    133     int c;
    134     for(;;) {
    135         c = *str;
    136         if (c == '\0')
    137             break;
    138         cstr_ccat(cstr, c);
    139         str++;
    140     }
     349ST_FUNC void cstr_cat(CString *cstr, const char *str, int len)
     350{
     351    int size;
     352    if (len <= 0)
     353        len = strlen(str) + 1 + len;
     354    size = cstr->size + len;
     355    if (size > cstr->size_allocated)
     356        cstr_realloc(cstr, size);
     357    memmove(((unsigned char *)cstr->data) + cstr->size, str, len);
     358    cstr->size = size;
    141359}
    142360
     
    160378ST_FUNC void cstr_free(CString *cstr)
    161379{
    162     tcc_free(cstr->data_allocated);
     380    tal_free(cstr_alloc, cstr->data);
    163381    cstr_new(cstr);
    164382}
     
    199417
    200418    if (tok_ident >= SYM_FIRST_ANOM)
    201         tcc_error("memory full");
     419        tcc_error("memory full (symbols)");
    202420
    203421    /* expand token table if needed */
     
    208426    }
    209427
    210     ts = tcc_malloc(sizeof(TokenSym) + len);
     428    ts = tal_realloc(toksym_alloc, 0, sizeof(TokenSym) + len);
    211429    table_ident[i] = ts;
    212430    ts->tok = tok_ident++;
     
    224442
    225443#define TOK_HASH_INIT 1
    226 #define TOK_HASH_FUNC(h, c) ((h) * 263 + (c))
     444#define TOK_HASH_FUNC(h, c) ((h) + ((h) << 5) + ((h) >> 27) + (c))
     445
    227446
    228447/* find a token and add it if not found */
     
    252471/* XXX: buffer overflow */
    253472/* XXX: float tokens */
    254 ST_FUNC char *get_tok_str(int v, CValue *cv)
    255 {
    256     static char buf[STRING_MAX_SIZE + 1];
    257     static CString cstr_buf;
    258     CString *cstr;
     473ST_FUNC const char *get_tok_str(int v, CValue *cv)
     474{
    259475    char *p;
    260476    int i, len;
    261477
    262     /* NOTE: to go faster, we give a fixed buffer for small strings */
    263478    cstr_reset(&cstr_buf);
    264     cstr_buf.data = buf;
    265     cstr_buf.size_allocated = sizeof(buf);
    266     p = buf;
     479    p = cstr_buf.data;
    267480
    268481    switch(v) {
    269482    case TOK_CINT:
    270483    case TOK_CUINT:
    271         /* XXX: not quite exact, but only useful for testing */
    272         sprintf(p, "%u", cv->ui);
    273         break;
     484    case TOK_CLONG:
     485    case TOK_CULONG:
    274486    case TOK_CLLONG:
    275487    case TOK_CULLONG:
    276488        /* XXX: not quite exact, but only useful for testing  */
    277489#ifdef _WIN32
    278         sprintf(p, "%u", (unsigned)cv->ull);
     490        sprintf(p, "%u", (unsigned)cv->i);
    279491#else
    280         sprintf(p, "%Lu", cv->ull);
     492        sprintf(p, "%llu", (unsigned long long)cv->i);
    281493#endif
    282494        break;
     
    290502        break;
    291503    case TOK_PPNUM:
    292         cstr = cv->cstr;
    293         len = cstr->size - 1;
    294         for(i=0;i<len;i++)
    295             add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]);
    296         cstr_ccat(&cstr_buf, '\0');
    297         break;
     504    case TOK_PPSTR:
     505        return (char*)cv->str.data;
    298506    case TOK_LSTR:
    299507        cstr_ccat(&cstr_buf, 'L');
    300508    case TOK_STR:
    301         cstr = cv->cstr;
    302509        cstr_ccat(&cstr_buf, '\"');
    303510        if (v == TOK_STR) {
    304             len = cstr->size - 1;
     511            len = cv->str.size - 1;
    305512            for(i=0;i<len;i++)
    306                 add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]);
     513                add_char(&cstr_buf, ((unsigned char *)cv->str.data)[i]);
    307514        } else {
    308             len = (cstr->size / sizeof(nwchar_t)) - 1;
     515            len = (cv->str.size / sizeof(nwchar_t)) - 1;
    309516            for(i=0;i<len;i++)
    310                 add_char(&cstr_buf, ((nwchar_t *)cstr->data)[i]);
     517                add_char(&cstr_buf, ((nwchar_t *)cv->str.data)[i]);
    311518        }
    312519        cstr_ccat(&cstr_buf, '\"');
    313520        cstr_ccat(&cstr_buf, '\0');
    314521        break;
     522
     523    case TOK_CFLOAT:
     524        cstr_cat(&cstr_buf, "<float>", 0);
     525        break;
     526    case TOK_CDOUBLE:
     527        cstr_cat(&cstr_buf, "<double>", 0);
     528        break;
     529    case TOK_CLDOUBLE:
     530        cstr_cat(&cstr_buf, "<long double>", 0);
     531        break;
     532    case TOK_LINENUM:
     533        cstr_cat(&cstr_buf, "<linenumber>", 0);
     534        break;
     535
     536    /* above tokens have value, the ones below don't */
    315537    case TOK_LT:
    316538        v = '<';
     
    325547    case TOK_A_SAR:
    326548        return strcpy(p, ">>=");
     549    case TOK_EOF:
     550        return strcpy(p, "<eof>");
    327551    default:
    328552        if (v < TOK_IDENT) {
     
    334558                    *p++ = q[1];
    335559                    *p = '\0';
    336                     return buf;
     560                    return cstr_buf.data;
    337561                }
    338562                q += 3;
    339563            }
     564        if (v >= 127) {
     565            sprintf(cstr_buf.data, "<%02x>", v);
     566            return cstr_buf.data;
     567        }
    340568        addv:
    341569            *p++ = v;
     
    355583}
    356584
    357 /* fill input buffer and peek next char */
    358 static int tcc_peekc_slow(BufferedFile *bf)
    359 {
     585/* return the current character, handling end of block if necessary
     586   (but not stray) */
     587ST_FUNC int handle_eob(void)
     588{
     589    BufferedFile *bf = file;
    360590    int len;
     591
    361592    /* only tries to read if really end of buffer */
    362593    if (bf->buf_ptr >= bf->buf_end) {
    363         if (bf->fd != -1) {
     594        if (bf->fd >= 0) {
    364595#if defined(PARSE_DEBUG)
    365             len = 8;
     596            len = 1;
    366597#else
    367598            len = IO_BUF_SIZE;
     
    384615        return CH_EOF;
    385616    }
    386 }
    387 
    388 /* return the current character, handling end of block if necessary
    389    (but not stray) */
    390 ST_FUNC int handle_eob(void)
    391 {
    392     return tcc_peekc_slow(file);
    393617}
    394618
     
    436660    int c;
    437661
     662    file->buf_ptr = p;
    438663    if (p >= file->buf_end) {
    439         file->buf_ptr = p;
    440664        c = handle_eob();
     665        if (c != '\\')
     666            return c;
    441667        p = file->buf_ptr;
    442         if (c == '\\')
    443             goto parse_stray;
    444     } else {
    445     parse_stray:
    446         file->buf_ptr = p;
    447         ch = *p;
    448         handle_stray();
    449         p = file->buf_ptr;
    450         c = *p;
    451     }
     668    }
     669    ch = *p;
     670    if (handle_stray_noerror()) {
     671        if (!(parse_flags & PARSE_FLAG_ACCEPT_STRAYS))
     672            tcc_error("stray '\\' in program");
     673        *--file->buf_ptr = '\\';
     674    }
     675    p = file->buf_ptr;
     676    c = *p;
    452677    return c;
    453678}
     
    485710        handle_stray();
    486711}
    487 
    488712
    489713/* single line C++ comments */
     
    528752{
    529753    int c;
    530    
     754
    531755    p++;
    532756    for(;;) {
     
    558782                    c = handle_eob();
    559783                    p = file->buf_ptr;
     784                    if (c == CH_EOF)
     785                        tcc_error("unexpected end of file in comment");
    560786                    if (c == '\\') {
    561787                        /* skip '\[\r]\n', otherwise just skip the stray */
     
    598824}
    599825
     826ST_FUNC int set_idnum(int c, int val)
     827{
     828    int prev = isidnum_table[c - CH_EOF];
     829    isidnum_table[c - CH_EOF] = val;
     830    return prev;
     831}
     832
    600833#define cinp minp
    601834
    602835static inline void skip_spaces(void)
    603836{
    604     while (is_space(ch))
     837    while (isidnum_table[ch - CH_EOF] & IS_SPC)
    605838        cinp();
    606839}
     
    608841static inline int check_space(int t, int *spc)
    609842{
    610     if (is_space(t)) {
     843    if (t < 256 && (isidnum_table[t - CH_EOF] & IS_SPC)) {
    611844        if (*spc)
    612845            return 1;
     
    756989                else if (tok == TOK_LINEFEED)
    757990                    goto redo_start;
    758             }
     991                else if (parse_flags & PARSE_FLAG_ASM_FILE)
     992                    p = parse_line_comment(p - 1);
     993            } else if (parse_flags & PARSE_FLAG_ASM_FILE)
     994                p = parse_line_comment(p - 1);
    759995            break;
    760996_default:
     
    7691005}
    7701006
    771 /* ParseState handling */
    772 
    773 /* XXX: currently, no include file info is stored. Thus, we cannot display
    774    accurate messages if the function or data definition spans multiple
    775    files */
    776 
    777 /* save current parse state in 's' */
    778 ST_FUNC void save_parse_state(ParseState *s)
    779 {
    780     s->line_num = file->line_num;
    781     s->macro_ptr = macro_ptr;
    782     s->tok = tok;
    783     s->tokc = tokc;
    784 }
    785 
    786 /* restore parse state from 's' */
    787 ST_FUNC void restore_parse_state(ParseState *s)
    788 {
    789     file->line_num = s->line_num;
    790     macro_ptr = s->macro_ptr;
    791     tok = s->tok;
    792     tokc = s->tokc;
    793 }
    794 
     1007#if 0
    7951008/* return the number of additional 'ints' necessary to store the
    7961009   token */
    797 static inline int tok_ext_size(int t)
    798 {
    799     switch(t) {
     1010static inline int tok_size(const int *p)
     1011{
     1012    switch(*p) {
    8001013        /* 4 bytes */
    8011014    case TOK_CINT:
     
    8051018    case TOK_CFLOAT:
    8061019    case TOK_LINENUM:
    807         return 1;
     1020        return 1 + 1;
    8081021    case TOK_STR:
    8091022    case TOK_LSTR:
    8101023    case TOK_PPNUM:
    811         tcc_error("unsupported token");
    812         return 1;
     1024    case TOK_PPSTR:
     1025        return 1 + ((sizeof(CString) + ((CString *)(p+1))->size + 3) >> 2);
     1026    case TOK_CLONG:
     1027    case TOK_CULONG:
     1028        return 1 + LONG_SIZE / 4;
    8131029    case TOK_CDOUBLE:
    8141030    case TOK_CLLONG:
    8151031    case TOK_CULLONG:
    816         return 2;
     1032        return 1 + 2;
    8171033    case TOK_CLDOUBLE:
    818         return LDOUBLE_SIZE / 4;
     1034        return 1 + LDOUBLE_SIZE / 4;
    8191035    default:
    820         return 0;
    821     }
    822 }
     1036        return 1 + 0;
     1037    }
     1038}
     1039#endif
    8231040
    8241041/* token string handling */
    825 
    8261042ST_INLN void tok_str_new(TokenString *s)
    8271043{
    8281044    s->str = NULL;
    829     s->len = 0;
     1045    s->len = s->lastlen = 0;
    8301046    s->allocated_len = 0;
    8311047    s->last_line_num = -1;
    8321048}
    8331049
    834 ST_FUNC void tok_str_free(int *str)
    835 {
    836     tcc_free(str);
    837 }
    838 
    839 static int *tok_str_realloc(TokenString *s)
    840 {
    841     int *str, len;
    842 
    843     if (s->allocated_len == 0) {
    844         len = 8;
    845     } else {
    846         len = s->allocated_len * 2;
    847     }
    848     str = tcc_realloc(s->str, len * sizeof(int));
    849     s->allocated_len = len;
    850     s->str = str;
     1050ST_FUNC TokenString *tok_str_alloc(void)
     1051{
     1052    TokenString *str = tal_realloc(tokstr_alloc, 0, sizeof *str);
     1053    tok_str_new(str);
    8511054    return str;
     1055}
     1056
     1057ST_FUNC int *tok_str_dup(TokenString *s)
     1058{
     1059    int *str;
     1060
     1061    str = tal_realloc(tokstr_alloc, 0, s->len * sizeof(int));
     1062    memcpy(str, s->str, s->len * sizeof(int));
     1063    return str;
     1064}
     1065
     1066ST_FUNC void tok_str_free_str(int *str)
     1067{
     1068    tal_free(tokstr_alloc, str);
     1069}
     1070
     1071ST_FUNC void tok_str_free(TokenString *str)
     1072{
     1073    tok_str_free_str(str->str);
     1074    tal_free(tokstr_alloc, str);
     1075}
     1076
     1077ST_FUNC int *tok_str_realloc(TokenString *s, int new_size)
     1078{
     1079    int *str, size;
     1080
     1081    size = s->allocated_len;
     1082    if (size < 16)
     1083        size = 16;
     1084    while (size < new_size)
     1085        size = size * 2;
     1086    if (size > s->allocated_len) {
     1087        str = tal_realloc(tokstr_alloc, s->str, size * sizeof(int));
     1088        s->allocated_len = size;
     1089        s->str = str;
     1090    }
     1091    return s->str;
    8521092}
    8531093
     
    8591099    str = s->str;
    8601100    if (len >= s->allocated_len)
    861         str = tok_str_realloc(s);
     1101        str = tok_str_realloc(s, len + 1);
    8621102    str[len++] = t;
    8631103    s->len = len;
    8641104}
    8651105
     1106ST_FUNC void begin_macro(TokenString *str, int alloc)
     1107{
     1108    str->alloc = alloc;
     1109    str->prev = macro_stack;
     1110    str->prev_ptr = macro_ptr;
     1111    str->save_line_num = file->line_num;
     1112    macro_ptr = str->str;
     1113    macro_stack = str;
     1114}
     1115
     1116ST_FUNC void end_macro(void)
     1117{
     1118    TokenString *str = macro_stack;
     1119    macro_stack = str->prev;
     1120    macro_ptr = str->prev_ptr;
     1121    file->line_num = str->save_line_num;
     1122    if (str->alloc == 2) {
     1123        str->alloc = 3; /* just mark as finished */
     1124    } else {
     1125        tok_str_free(str);
     1126    }
     1127}
     1128
    8661129static void tok_str_add2(TokenString *s, int t, CValue *cv)
    8671130{
    8681131    int len, *str;
    8691132
    870     len = s->len;
     1133    len = s->lastlen = s->len;
    8711134    str = s->str;
    8721135
    8731136    /* allocate space for worst case */
    874     if (len + TOK_MAX_SIZE > s->allocated_len)
    875         str = tok_str_realloc(s);
     1137    if (len + TOK_MAX_SIZE >= s->allocated_len)
     1138        str = tok_str_realloc(s, len + TOK_MAX_SIZE + 1);
    8761139    str[len++] = t;
    8771140    switch(t) {
     
    8821145    case TOK_CFLOAT:
    8831146    case TOK_LINENUM:
     1147#if LONG_SIZE == 4
     1148    case TOK_CLONG:
     1149    case TOK_CULONG:
     1150#endif
    8841151        str[len++] = cv->tab[0];
    8851152        break;
    8861153    case TOK_PPNUM:
     1154    case TOK_PPSTR:
    8871155    case TOK_STR:
    8881156    case TOK_LSTR:
    8891157        {
    890             int nb_words;
    891             CString *cstr;
    892 
    893             nb_words = (sizeof(CString) + cv->cstr->size + 3) >> 2;
    894             while ((len + nb_words) > s->allocated_len)
    895                 str = tok_str_realloc(s);
    896             cstr = (CString *)(str + len);
    897             cstr->data = NULL;
    898             cstr->size = cv->cstr->size;
    899             cstr->data_allocated = NULL;
    900             cstr->size_allocated = cstr->size;
    901             memcpy((char *)cstr + sizeof(CString),
    902                    cv->cstr->data, cstr->size);
     1158            /* Insert the string into the int array. */
     1159            size_t nb_words =
     1160                1 + (cv->str.size + sizeof(int) - 1) / sizeof(int);
     1161            if (len + nb_words >= s->allocated_len)
     1162                str = tok_str_realloc(s, len + nb_words + 1);
     1163            str[len] = cv->str.size;
     1164            memcpy(&str[len + 1], cv->str.data, cv->str.size);
    9031165            len += nb_words;
    9041166        }
     
    9071169    case TOK_CLLONG:
    9081170    case TOK_CULLONG:
     1171#if LONG_SIZE == 8
     1172    case TOK_CLONG:
     1173    case TOK_CULONG:
     1174#endif
    9091175#if LDOUBLE_SIZE == 8
    9101176    case TOK_CLDOUBLE:
     
    9571223    tab = cv->tab;
    9581224    switch(*t = *p++) {
     1225#if LONG_SIZE == 4
     1226    case TOK_CLONG:
     1227#endif
    9591228    case TOK_CINT:
    960     case TOK_CUINT:
    9611229    case TOK_CCHAR:
    9621230    case TOK_LCHAR:
     1231    case TOK_LINENUM:
     1232        cv->i = *p++;
     1233        break;
     1234#if LONG_SIZE == 4
     1235    case TOK_CULONG:
     1236#endif
     1237    case TOK_CUINT:
     1238        cv->i = (unsigned)*p++;
     1239        break;
    9631240    case TOK_CFLOAT:
    964     case TOK_LINENUM:
    965         tab[0] = *p++;
    966         break;
     1241        tab[0] = *p++;
     1242        break;
    9671243    case TOK_STR:
    9681244    case TOK_LSTR:
    9691245    case TOK_PPNUM:
    970         cv->cstr = (CString *)p;
    971         cv->cstr->data = (char *)p + sizeof(CString);
    972         p += (sizeof(CString) + cv->cstr->size + 3) >> 2;
     1246    case TOK_PPSTR:
     1247        cv->str.size = *p++;
     1248        cv->str.data = p;
     1249        p += (cv->str.size + sizeof(int) - 1) / sizeof(int);
    9731250        break;
    9741251    case TOK_CDOUBLE:
    9751252    case TOK_CLLONG:
    9761253    case TOK_CULLONG:
     1254#if LONG_SIZE == 8
     1255    case TOK_CLONG:
     1256    case TOK_CULONG:
     1257#endif
    9771258        n = 2;
    9781259        goto copy;
     
    10001281static int macro_is_equal(const int *a, const int *b)
    10011282{
    1002     char buf[STRING_MAX_SIZE + 1];
    10031283    CValue cv;
    10041284    int t;
     1285
     1286    if (!a || !b)
     1287        return 1;
     1288
    10051289    while (*a && *b) {
     1290        /* first time preallocate macro_equal_buf, next time only reset position to start */
     1291        cstr_reset(&macro_equal_buf);
    10061292        TOK_GET(&t, &a, &cv);
    1007         pstrcpy(buf, sizeof buf, get_tok_str(t, &cv));
     1293        cstr_cat(&macro_equal_buf, get_tok_str(t, &cv), 0);
    10081294        TOK_GET(&t, &b, &cv);
    1009         if (strcmp(buf, get_tok_str(t, &cv)))
     1295        if (strcmp(macro_equal_buf.data, get_tok_str(t, &cv)))
    10101296            return 0;
    10111297    }
     
    10161302ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg)
    10171303{
    1018     Sym *s;
    1019 
    1020     s = define_find(v);
    1021     if (s && !macro_is_equal(s->d, str))
    1022         tcc_warning("%s redefined", get_tok_str(v, NULL));
    1023 
     1304    Sym *s, *o;
     1305
     1306    o = define_find(v);
    10241307    s = sym_push2(&define_stack, v, macro_type, 0);
    10251308    s->d = str;
    10261309    s->next = first_arg;
    10271310    table_ident[v - TOK_IDENT]->sym_define = s;
     1311
     1312    if (o && !macro_is_equal(o->d, s->d))
     1313        tcc_warning("%s redefined", get_tok_str(v, NULL));
    10281314}
    10291315
     
    10311317ST_FUNC void define_undef(Sym *s)
    10321318{
    1033     int v;
    1034     v = s->v;
     1319    int v = s->v;
    10351320    if (v >= TOK_IDENT && v < tok_ident)
    10361321        table_ident[v - TOK_IDENT]->sym_define = NULL;
    1037     s->v = 0;
    10381322}
    10391323
     
    10491333ST_FUNC void free_defines(Sym *b)
    10501334{
    1051     Sym *top, *top1;
    1052     int v;
    1053 
    1054     top = define_stack;
    1055     while (top != b) {
    1056         top1 = top->prev;
    1057         /* do not free args or predefined defines */
    1058         if (top->d)
    1059             tok_str_free(top->d);
    1060         v = top->v;
    1061         if (v >= TOK_IDENT && v < tok_ident)
    1062             table_ident[v - TOK_IDENT]->sym_define = NULL;
     1335    while (define_stack != b) {
     1336        Sym *top = define_stack;
     1337        define_stack = top->prev;
     1338        tok_str_free_str(top->d);
     1339        define_undef(top);
    10631340        sym_free(top);
    1064         top = top1;
    1065     }
    1066     define_stack = b;
     1341    }
     1342
     1343    /* restore remaining (-D or predefined) symbols if they were
     1344       #undef'd in the file */
     1345    while (b) {
     1346        int v = b->v;
     1347        if (v >= TOK_IDENT && v < tok_ident) {
     1348            Sym **d = &table_ident[v - TOK_IDENT]->sym_define;
     1349            if (!*d)
     1350                *d = b;
     1351        }
     1352        b = b->prev;
     1353    }
    10671354}
    10681355
     
    10951382/* pop labels until element last is reached. Look if any labels are
    10961383   undefined. Define symbols if '&&label' was used. */
    1097 ST_FUNC void label_pop(Sym **ptop, Sym *slast)
     1384ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
    10981385{
    10991386    Sym *s, *s1;
     
    11141401        /* remove label */
    11151402        table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
    1116         sym_free(s);
    1117     }
    1118     *ptop = slast;
     1403        if (!keep)
     1404            sym_free(s);
     1405    }
     1406    if (!keep)
     1407        *ptop = slast;
     1408}
     1409
     1410/* fake the nth "#if defined test_..." for tcc -dt -run */
     1411static void maybe_run_test(TCCState *s)
     1412{
     1413    const char *p;
     1414    if (s->include_stack_ptr != s->include_stack)
     1415        return;
     1416    p = get_tok_str(tok, NULL);
     1417    if (0 != memcmp(p, "test_", 5))
     1418        return;
     1419    if (0 != --s->run_test)
     1420        return;
     1421    fprintf(s->ppfp, "\n[%s]\n" + !(s->dflag & 32), p), fflush(s->ppfp);
     1422    define_push(tok, MACRO_OBJ, NULL, NULL);
    11191423}
    11201424
     
    11231427{
    11241428    int c, t;
    1125     TokenString str;
     1429    TokenString *str;
    11261430   
    1127     tok_str_new(&str);
     1431    str = tok_str_alloc();
     1432    pp_expr = 1;
    11281433    while (tok != TOK_LINEFEED && tok != TOK_EOF) {
    11291434        next(); /* do macro subst */
     
    11331438            if (t == '(')
    11341439                next_nomacro();
     1440            if (tok < TOK_IDENT)
     1441                expect("identifier");
     1442            if (tcc_state->run_test)
     1443                maybe_run_test(tcc_state);
    11351444            c = define_find(tok) != 0;
    1136             if (t == '(')
     1445            if (t == '(') {
    11371446                next_nomacro();
     1447                if (tok != ')')
     1448                    expect("')'");
     1449            }
    11381450            tok = TOK_CINT;
    11391451            tokc.i = c;
     
    11431455            tokc.i = 0;
    11441456        }
    1145         tok_str_add_tok(&str);
    1146     }
    1147     tok_str_add(&str, -1); /* simulate end of file */
    1148     tok_str_add(&str, 0);
     1457        tok_str_add_tok(str);
     1458    }
     1459    pp_expr = 0;
     1460    tok_str_add(str, -1); /* simulate end of file */
     1461    tok_str_add(str, 0);
    11491462    /* now evaluate C constant expression */
    1150     macro_ptr = str.str;
     1463    begin_macro(str, 1);
    11511464    next();
    11521465    c = expr_const();
    1153     macro_ptr = NULL;
    1154     tok_str_free(str.str);
     1466    end_macro();
    11551467    return c != 0;
    11561468}
    11571469
    1158 #if defined(PARSE_DEBUG) || defined(PP_DEBUG)
    1159 static void tok_print(int *str)
    1160 {
    1161     int t;
    1162     CValue cval;
    1163 
    1164     printf("<");
    1165     while (1) {
    1166         TOK_GET(&t, &str, &cval);
    1167         if (!t)
    1168             break;
    1169         printf("%s", get_tok_str(t, &cval));
    1170     }
    1171     printf(">\n");
    1172 }
    1173 #endif
    11741470
    11751471/* parse after #define */
     
    11781474    Sym *s, *first, **ps;
    11791475    int v, t, varg, is_vaargs, spc;
    1180     TokenString str;
    1181    
     1476    int saved_parse_flags = parse_flags;
     1477
    11821478    v = tok;
    1183     if (v < TOK_IDENT)
     1479    if (v < TOK_IDENT || v == TOK_DEFINED)
    11841480        tcc_error("invalid macro name '%s'", get_tok_str(tok, &tokc));
    11851481    /* XXX: should check if same macro (ANSI) */
    11861482    first = NULL;
    11871483    t = MACRO_OBJ;
     1484    /* We have to parse the whole define as if not in asm mode, in particular
     1485       no line comment with '#' must be ignored.  Also for function
     1486       macros the argument list must be parsed without '.' being an ID
     1487       character.  */
     1488    parse_flags = ((parse_flags & ~PARSE_FLAG_ASM_FILE) | PARSE_FLAG_SPACES);
    11881489    /* '(' must be just after macro definition for MACRO_FUNC */
    11891490    next_nomacro_spc();
    11901491    if (tok == '(') {
     1492        int dotid = set_idnum('.', 0);
    11911493        next_nomacro();
    11921494        ps = &first;
    1193         while (tok != ')') {
     1495        if (tok != ')') for (;;) {
    11941496            varg = tok;
    11951497            next_nomacro();
     
    12031505            }
    12041506            if (varg < TOK_IDENT)
    1205                 tcc_error("badly punctuated parameter list");
     1507        bad_list:
     1508                tcc_error("bad macro parameter list");
    12061509            s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0);
    12071510            *ps = s;
    12081511            ps = &s->next;
    1209             if (tok != ',')
     1512            if (tok == ')')
    12101513                break;
     1514            if (tok != ',' || is_vaargs)
     1515                goto bad_list;
    12111516            next_nomacro();
    12121517        }
    1213         if (tok == ')')
    1214             next_nomacro_spc();
     1518        next_nomacro_spc();
    12151519        t = MACRO_FUNC;
    1216     }
    1217     tok_str_new(&str);
     1520        set_idnum('.', dotid);
     1521    }
     1522
     1523    tokstr_buf.len = 0;
    12181524    spc = 2;
    1219     /* EOF testing necessary for '-D' handling */
     1525    parse_flags |= PARSE_FLAG_ACCEPT_STRAYS | PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED;
     1526    /* The body of a macro definition should be parsed such that identifiers
     1527       are parsed like the file mode determines (i.e. with '.' being an
     1528       ID character in asm mode).  But '#' should be retained instead of
     1529       regarded as line comment leader, so still don't set ASM_FILE
     1530       in parse_flags. */
    12201531    while (tok != TOK_LINEFEED && tok != TOK_EOF) {
    1221         /* remove spaces around ## and after '#' */       
     1532        /* remove spaces around ## and after '#' */
    12221533        if (TOK_TWOSHARPS == tok) {
     1534            if (2 == spc)
     1535                goto bad_twosharp;
    12231536            if (1 == spc)
    1224                 --str.len;
    1225             spc = 2;
     1537                --tokstr_buf.len;
     1538            spc = 3;
     1539            tok = TOK_PPJOIN;
    12261540        } else if ('#' == tok) {
    1227             spc = 2;
     1541            spc = 4;
    12281542        } else if (check_space(tok, &spc)) {
    12291543            goto skip;
    12301544        }
    1231         tok_str_add2(&str, tok, &tokc);
     1545        tok_str_add2(&tokstr_buf, tok, &tokc);
    12321546    skip:
    12331547        next_nomacro_spc();
    12341548    }
     1549
     1550    parse_flags = saved_parse_flags;
    12351551    if (spc == 1)
    1236         --str.len; /* remove trailing space */
    1237     tok_str_add(&str, 0);
    1238 #ifdef PP_DEBUG
    1239     printf("define %s %d: ", get_tok_str(v, NULL), t);
    1240     tok_print(str.str);
    1241 #endif
    1242     define_push(v, t, str.str, first);
    1243 }
    1244 
    1245 static inline int hash_cached_include(const char *filename)
     1552        --tokstr_buf.len; /* remove trailing space */
     1553    tok_str_add(&tokstr_buf, 0);
     1554    if (3 == spc)
     1555bad_twosharp:
     1556        tcc_error("'##' cannot appear at either end of macro");
     1557    define_push(v, t, tok_str_dup(&tokstr_buf), first);
     1558}
     1559
     1560static CachedInclude *search_cached_include(TCCState *s1, const char *filename, int add)
    12461561{
    12471562    const unsigned char *s;
    12481563    unsigned int h;
     1564    CachedInclude *e;
     1565    int i;
    12491566
    12501567    h = TOK_HASH_INIT;
    1251     s = filename;
     1568    s = (unsigned char *) filename;
    12521569    while (*s) {
     1570#ifdef _WIN32
     1571        h = TOK_HASH_FUNC(h, toup(*s));
     1572#else
    12531573        h = TOK_HASH_FUNC(h, *s);
     1574#endif
    12541575        s++;
    12551576    }
    12561577    h &= (CACHED_INCLUDES_HASH_SIZE - 1);
    1257     return h;
    1258 }
    1259 
    1260 static CachedInclude *search_cached_include(TCCState *s1, const char *filename)
    1261 {
    1262     CachedInclude *e;
    1263     int i, h;
    1264     h = hash_cached_include(filename);
     1578
    12651579    i = s1->cached_includes_hash[h];
    12661580    for(;;) {
     
    12721586        i = e->hash_next;
    12731587    }
    1274     return NULL;
    1275 }
    1276 
    1277 static inline void add_cached_include(TCCState *s1, const char *filename, int ifndef_macro)
    1278 {
    1279     CachedInclude *e;
    1280     int h;
    1281 
    1282     if (search_cached_include(s1, filename))
    1283         return;
    1284 #ifdef INC_DEBUG
    1285     printf("adding cached '%s' %s\n", filename, get_tok_str(ifndef_macro, NULL));
    1286 #endif
     1588    if (!add)
     1589        return NULL;
     1590
    12871591    e = tcc_malloc(sizeof(CachedInclude) + strlen(filename));
    12881592    strcpy(e->filename, filename);
    1289     e->ifndef_macro = ifndef_macro;
    1290     dynarray_add((void ***)&s1->cached_includes, &s1->nb_cached_includes, e);
     1593    e->ifndef_macro = e->once = 0;
     1594    dynarray_add(&s1->cached_includes, &s1->nb_cached_includes, e);
    12911595    /* add in hash table */
    1292     h = hash_cached_include(filename);
    12931596    e->hash_next = s1->cached_includes_hash[h];
    12941597    s1->cached_includes_hash[h] = s1->nb_cached_includes;
     1598#ifdef INC_DEBUG
     1599    printf("adding cached '%s'\n", filename);
     1600#endif
     1601    return e;
    12951602}
    12961603
    12971604static void pragma_parse(TCCState *s1)
    12981605{
    1299     int val;
    1300 
    1301     next();
    1302     if (tok == TOK_pack) {
    1303         /*
    1304           This may be:
    1305           #pragma pack(1) // set
    1306           #pragma pack() // reset to default
    1307           #pragma pack(push,1) // push & set
    1308           #pragma pack(pop) // restore previous
    1309         */
     1606    next_nomacro();
     1607    if (tok == TOK_push_macro || tok == TOK_pop_macro) {
     1608        int t = tok, v;
     1609        Sym *s;
     1610
     1611        if (next(), tok != '(')
     1612            goto pragma_err;
     1613        if (next(), tok != TOK_STR)
     1614            goto pragma_err;
     1615        v = tok_alloc(tokc.str.data, tokc.str.size - 1)->tok;
     1616        if (next(), tok != ')')
     1617            goto pragma_err;
     1618        if (t == TOK_push_macro) {
     1619            while (NULL == (s = define_find(v)))
     1620                define_push(v, 0, NULL, NULL);
     1621            s->type.ref = s; /* set push boundary */
     1622        } else {
     1623            for (s = define_stack; s; s = s->prev)
     1624                if (s->v == v && s->type.ref == s) {
     1625                    s->type.ref = NULL;
     1626                    break;
     1627                }
     1628        }
     1629        if (s)
     1630            table_ident[v - TOK_IDENT]->sym_define = s->d ? s : NULL;
     1631        else
     1632            tcc_warning("unbalanced #pragma pop_macro");
     1633        pp_debug_tok = t, pp_debug_symv = v;
     1634
     1635    } else if (tok == TOK_once) {
     1636        search_cached_include(s1, file->filename, 1)->once = pp_once;
     1637
     1638    } else if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
     1639        /* tcc -E: keep pragmas below unchanged */
     1640        unget_tok(' ');
     1641        unget_tok(TOK_PRAGMA);
     1642        unget_tok('#');
     1643        unget_tok(TOK_LINEFEED);
     1644
     1645    } else if (tok == TOK_pack) {
     1646        /* This may be:
     1647           #pragma pack(1) // set
     1648           #pragma pack() // reset to default
     1649           #pragma pack(push,1) // push & set
     1650           #pragma pack(pop) // restore previous */
    13101651        next();
    13111652        skip('(');
     
    13181659            s1->pack_stack_ptr--;
    13191660        } else {
    1320             val = 0;
     1661            int val = 0;
    13211662            if (tok != ')') {
    13221663                if (tok == TOK_ASM_push) {
     
    13271668                    skip(',');
    13281669                }
    1329                 if (tok != TOK_CINT) {
    1330                 pack_error:
    1331                     tcc_error("invalid pack pragma");
    1332                 }
     1670                if (tok != TOK_CINT)
     1671                    goto pragma_err;
    13331672                val = tokc.i;
    13341673                if (val < 1 || val > 16 || (val & (val - 1)) != 0)
    1335                     goto pack_error;
     1674                    goto pragma_err;
    13361675                next();
    13371676            }
    13381677            *s1->pack_stack_ptr = val;
    1339             skip(')');
    1340         }
    1341     }
     1678        }
     1679        if (tok != ')')
     1680            goto pragma_err;
     1681
     1682    } else if (tok == TOK_comment) {
     1683        char *p; int t;
     1684        next();
     1685        skip('(');
     1686        t = tok;
     1687        next();
     1688        skip(',');
     1689        if (tok != TOK_STR)
     1690            goto pragma_err;
     1691        p = tcc_strdup((char *)tokc.str.data);
     1692        next();
     1693        if (tok != ')')
     1694            goto pragma_err;
     1695        if (t == TOK_lib) {
     1696            dynarray_add(&s1->pragma_libs, &s1->nb_pragma_libs, p);
     1697        } else {
     1698            if (t == TOK_option)
     1699                tcc_set_options(s1, p);
     1700            tcc_free(p);
     1701        }
     1702
     1703    } else if (s1->warn_unsupported) {
     1704        tcc_warning("#pragma %s is ignored", get_tok_str(tok, &tokc));
     1705    }
     1706    return;
     1707
     1708pragma_err:
     1709    tcc_error("malformed #pragma directive");
     1710    return;
    13421711}
    13431712
     
    13511720
    13521721    saved_parse_flags = parse_flags;
    1353     parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM |
    1354         PARSE_FLAG_LINEFEED;
     1722    parse_flags = PARSE_FLAG_PREPROCESS
     1723        | PARSE_FLAG_TOK_NUM
     1724        | PARSE_FLAG_TOK_STR
     1725        | PARSE_FLAG_LINEFEED
     1726        | (parse_flags & PARSE_FLAG_ASM_FILE)
     1727        ;
     1728
    13551729    next_nomacro();
    13561730 redo:
    13571731    switch(tok) {
    13581732    case TOK_DEFINE:
     1733        pp_debug_tok = tok;
    13591734        next_nomacro();
     1735        pp_debug_symv = tok;
    13601736        parse_define();
    13611737        break;
    13621738    case TOK_UNDEF:
     1739        pp_debug_tok = tok;
    13631740        next_nomacro();
     1741        pp_debug_symv = tok;
    13641742        s = define_find(tok);
    13651743        /* undefine symbol by putting an invalid name */
     
    13981776#endif
    13991777        } else {
    1400             /* computed #include : either we have only strings or
    1401                we have anything enclosed in '<>' */
     1778            int len;
     1779            /* computed #include : concatenate everything up to linefeed,
     1780               the result must be one of the two accepted forms.
     1781               Don't convert pp-tokens to tokens here.  */
     1782            parse_flags = (PARSE_FLAG_PREPROCESS
     1783                           | PARSE_FLAG_LINEFEED
     1784                           | (parse_flags & PARSE_FLAG_ASM_FILE));
    14021785            next();
    14031786            buf[0] = '\0';
    1404             if (tok == TOK_STR) {
    1405                 while (tok != TOK_LINEFEED) {
    1406                     if (tok != TOK_STR) {
    1407                     include_syntax:
    1408                         tcc_error("'#include' expects \"FILENAME\" or <FILENAME>");
    1409                     }
    1410                     pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data);
    1411                     next();
    1412                 }
    1413                 c = '\"';
    1414             } else {
    1415                 int len;
    1416                 while (tok != TOK_LINEFEED) {
    1417                     pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc));
    1418                     next();
    1419                 }
    1420                 len = strlen(buf);
    1421                 /* check syntax and remove '<>' */
    1422                 if (len < 2 || buf[0] != '<' || buf[len - 1] != '>')
    1423                     goto include_syntax;
    1424                 memmove(buf, buf + 1, len - 2);
    1425                 buf[len - 2] = '\0';
    1426                 c = '>';
    1427             }
     1787            while (tok != TOK_LINEFEED) {
     1788                pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc));
     1789                next();
     1790            }
     1791            len = strlen(buf);
     1792            /* check syntax and remove '<>|""' */
     1793            if ((len < 2 || ((buf[0] != '"' || buf[len-1] != '"') &&
     1794                             (buf[0] != '<' || buf[len-1] != '>'))))
     1795                tcc_error("'#include' expects \"FILENAME\" or <FILENAME>");
     1796            c = buf[len-1];
     1797            memmove(buf, buf + 1, len - 2);
     1798            buf[len - 2] = '\0';
    14281799        }
    14291800
     
    14321803        /* store current file in stack, but increment stack later below */
    14331804        *s1->include_stack_ptr = file;
    1434 
    1435         n = s1->nb_include_paths + s1->nb_sysinclude_paths;
    1436         for (i = -2; i < n; ++i) {
     1805        i = tok == TOK_INCLUDE_NEXT ? file->include_next_index : 0;
     1806        n = 2 + s1->nb_include_paths + s1->nb_sysinclude_paths;
     1807        for (; i < n; ++i) {
    14371808            char buf1[sizeof file->filename];
    14381809            CachedInclude *e;
    1439             BufferedFile **f;
    14401810            const char *path;
    14411811
    1442             if (i == -2) {
     1812            if (i == 0) {
    14431813                /* check absolute include path */
    14441814                if (!IS_ABSPATH(buf))
    14451815                    continue;
    14461816                buf1[0] = 0;
    1447                 i = n; /* force end loop */
    1448 
    1449             } else if (i == -1) {
    1450                 /* search in current dir if "header.h" */
     1817
     1818            } else if (i == 1) {
     1819                /* search in file's dir if "header.h" */
    14511820                if (c != '\"')
    14521821                    continue;
    1453                 path = file->filename;
     1822                /* https://savannah.nongnu.org/bugs/index.php?50847 */
     1823                path = file->true_filename;
    14541824                pstrncpy(buf1, path, tcc_basename(path) - path);
    14551825
    14561826            } else {
    14571827                /* search in all the include paths */
    1458                 if (i < s1->nb_include_paths)
    1459                     path = s1->include_paths[i];
    1460                 else
    1461                     path = s1->sysinclude_paths[i - s1->nb_include_paths];
     1828                int j = i - 2, k = j - s1->nb_include_paths;
     1829                path = k < 0 ? s1->include_paths[j] : s1->sysinclude_paths[k];
    14621830                pstrcpy(buf1, sizeof(buf1), path);
    14631831                pstrcat(buf1, sizeof(buf1), "/");
     
    14651833
    14661834            pstrcat(buf1, sizeof(buf1), buf);
    1467 
    1468             if (tok == TOK_INCLUDE_NEXT)
    1469                 for (f = s1->include_stack_ptr; f >= s1->include_stack; --f)
    1470                     if (0 == PATHCMP((*f)->filename, buf1)) {
    1471 #ifdef INC_DEBUG
    1472                         printf("%s: #include_next skipping %s\n", file->filename, buf1);
    1473 #endif
    1474                         goto include_trynext;
    1475                     }
    1476 
    1477             e = search_cached_include(s1, buf1);
    1478             if (e && define_find(e->ifndef_macro)) {
     1835            e = search_cached_include(s1, buf1, 0);
     1836            if (e && (define_find(e->ifndef_macro) || e->once == pp_once)) {
    14791837                /* no need to parse the include because the 'ifndef macro'
    1480                    is defined */
     1838                   is defined (or had #pragma once) */
    14811839#ifdef INC_DEBUG
    14821840                printf("%s: skipping cached %s\n", file->filename, buf1);
     
    14861844
    14871845            if (tcc_open(s1, buf1) < 0)
    1488 include_trynext:
    14891846                continue;
    14901847
     1848            file->include_next_index = i + 1;
    14911849#ifdef INC_DEBUG
    14921850            printf("%s: including %s\n", file->prev->filename, file->filename);
    14931851#endif
    14941852            /* update target deps */
    1495             dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps,
     1853            dynarray_add(&s1->target_deps, &s1->nb_target_deps,
    14961854                    tcc_strdup(buf1));
    14971855            /* push current file in stack */
     
    15301888    do_if:
    15311889        if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE)
    1532             tcc_error("memory full");
     1890            tcc_error("memory full (ifdef)");
    15331891        *s1->ifdef_stack_ptr++ = c;
    15341892        goto test_skip;
     
    15471905            tcc_error("#elif after #else");
    15481906        /* last #if/#elif expression was true: we skip */
    1549         if (c == 1)
    1550             goto skip;
    1551         c = expr_preprocess();
    1552         s1->ifdef_stack_ptr[-1] = c;
     1907        if (c == 1) {
     1908            c = 0;
     1909        } else {
     1910            c = expr_preprocess();
     1911            s1->ifdef_stack_ptr[-1] = c;
     1912        }
    15531913    test_else:
    15541914        if (s1->ifdef_stack_ptr == file->ifdef_stack_ptr + 1)
     
    15561916    test_skip:
    15571917        if (!(c & 1)) {
    1558         skip:
    15591918            preprocess_skip();
    15601919            is_bof = 0;
     
    15801939        }
    15811940        break;
     1941    case TOK_PPNUM:
     1942        n = strtoul((char*)tokc.str.data, &q, 10);
     1943        goto _line_num;
    15821944    case TOK_LINE:
    15831945        next();
    15841946        if (tok != TOK_CINT)
    1585             tcc_error("#line");
    1586         file->line_num = tokc.i - 1; /* the line number will be incremented after */
     1947    _line_err:
     1948            tcc_error("wrong #line format");
     1949        n = tokc.i;
     1950    _line_num:
    15871951        next();
    15881952        if (tok != TOK_LINEFEED) {
    1589             if (tok != TOK_STR)
    1590                 tcc_error("#line");
    1591             pstrcpy(file->filename, sizeof(file->filename),
    1592                     (char *)tokc.cstr->data);
    1593         }
     1953            if (tok == TOK_STR) {
     1954                if (file->true_filename == file->filename)
     1955                    file->true_filename = tcc_strdup(file->filename);
     1956                pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.str.data);
     1957            } else if (parse_flags & PARSE_FLAG_ASM_FILE)
     1958                break;
     1959            else
     1960                goto _line_err;
     1961            --n;
     1962        }
     1963        if (file->fd > 0)
     1964            total_lines += file->line_num - n;
     1965        file->line_num = n;
     1966        if (s1->do_debug)
     1967            put_stabs(file->filename, N_BINCL, 0, 0, 0);
    15941968        break;
    15951969    case TOK_ERROR:
     
    16171991        pragma_parse(s1);
    16181992        break;
     1993    case TOK_LINEFEED:
     1994        goto the_end;
    16191995    default:
    1620         if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_PPNUM) {
    1621             /* '!' is ignored to allow C scripts. numbers are ignored
    1622                to emulate cpp behaviour */
    1623         } else {
    1624             if (!(saved_parse_flags & PARSE_FLAG_ASM_COMMENTS))
    1625                 tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc));
    1626             else {
    1627                 /* this is a gas line comment in an 'S' file. */
    1628                 file->buf_ptr = parse_line_comment(file->buf_ptr);
    1629                 goto the_end;
    1630             }
    1631         }
    1632         break;
     1996        /* ignore gas line comment in an 'S' file. */
     1997        if (saved_parse_flags & PARSE_FLAG_ASM_FILE)
     1998            goto ignore;
     1999        if (tok == '!' && is_bof)
     2000            /* '!' is ignored at beginning to allow C scripts. */
     2001            goto ignore;
     2002        tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc));
     2003    ignore:
     2004        file->buf_ptr = parse_line_comment(file->buf_ptr - 1);
     2005        goto the_end;
    16332006    }
    16342007    /* ignore other preprocess commands or #! for C scripts */
     
    17312104                break;
    17322105            }
     2106        } else if (is_long && c >= 0x80) {
     2107            /* assume we are processing UTF-8 sequence */
     2108            /* reference: The Unicode Standard, Version 10.0, ch3.9 */
     2109
     2110            int cont; /* count of continuation bytes */
     2111            int skip; /* how many bytes should skip when error occurred */
     2112            int i;
     2113
     2114            /* decode leading byte */
     2115            if (c < 0xC2) {
     2116                    skip = 1; goto invalid_utf8_sequence;
     2117            } else if (c <= 0xDF) {
     2118                    cont = 1; n = c & 0x1f;
     2119            } else if (c <= 0xEF) {
     2120                    cont = 2; n = c & 0xf;
     2121            } else if (c <= 0xF4) {
     2122                    cont = 3; n = c & 0x7;
     2123            } else {
     2124                    skip = 1; goto invalid_utf8_sequence;
     2125            }
     2126
     2127            /* decode continuation bytes */
     2128            for (i = 1; i <= cont; i++) {
     2129                int l = 0x80, h = 0xBF;
     2130
     2131                /* adjust limit for second byte */
     2132                if (i == 1) {
     2133                    switch (c) {
     2134                    case 0xE0: l = 0xA0; break;
     2135                    case 0xED: h = 0x9F; break;
     2136                    case 0xF0: l = 0x90; break;
     2137                    case 0xF4: h = 0x8F; break;
     2138                    }
     2139                }
     2140
     2141                if (p[i] < l || p[i] > h) {
     2142                    skip = i; goto invalid_utf8_sequence;
     2143                }
     2144
     2145                n = (n << 6) | (p[i] & 0x3f);
     2146            }
     2147
     2148            /* advance pointer */
     2149            p += 1 + cont;
     2150            c = n;
     2151            goto add_char_nonext;
     2152
     2153            /* error handling */
     2154        invalid_utf8_sequence:
     2155            tcc_warning("ill-formed UTF-8 subsequence starting with: \'\\x%x\'", c);
     2156            c = 0xFFFD;
     2157            p += skip;
     2158            goto add_char_nonext;
     2159
    17332160        }
    17342161        p++;
     
    17362163        if (!is_long)
    17372164            cstr_ccat(outstr, c);
    1738         else
     2165        else {
     2166#ifdef TCC_TARGET_PE
     2167            /* store as UTF-16 */
     2168            if (c < 0x10000) {
     2169                cstr_wccat(outstr, c);
     2170            } else {
     2171                c -= 0x10000;
     2172                cstr_wccat(outstr, (c >> 10) + 0xD800);
     2173                cstr_wccat(outstr, (c & 0x3FF) + 0xDC00);
     2174            }
     2175#else
    17392176            cstr_wccat(outstr, c);
     2177#endif
     2178        }
    17402179    }
    17412180    /* add a trailing '\0' */
     
    17442183    else
    17452184        cstr_wccat(outstr, '\0');
     2185}
     2186
     2187static void parse_string(const char *s, int len)
     2188{
     2189    uint8_t buf[1000], *p = buf;
     2190    int is_long, sep;
     2191
     2192    if ((is_long = *s == 'L'))
     2193        ++s, --len;
     2194    sep = *s++;
     2195    len -= 2;
     2196    if (len >= sizeof buf)
     2197        p = tcc_malloc(len + 1);
     2198    memcpy(p, s, len);
     2199    p[len] = 0;
     2200
     2201    cstr_reset(&tokcstr);
     2202    parse_escape_string(&tokcstr, p, is_long);
     2203    if (p != buf)
     2204        tcc_free(p);
     2205
     2206    if (sep == '\'') {
     2207        int char_size, i, n, c;
     2208        /* XXX: make it portable */
     2209        if (!is_long)
     2210            tok = TOK_CCHAR, char_size = 1;
     2211        else
     2212            tok = TOK_LCHAR, char_size = sizeof(nwchar_t);
     2213        n = tokcstr.size / char_size - 1;
     2214        if (n < 1)
     2215            tcc_error("empty character constant");
     2216        if (n > 1)
     2217            tcc_warning("multi-character character constant");
     2218        for (c = i = 0; i < n; ++i) {
     2219            if (is_long)
     2220                c = ((nwchar_t *)tokcstr.data)[i];
     2221            else
     2222                c = (c << 8) | ((char *)tokcstr.data)[i];
     2223        }
     2224        tokc.i = c;
     2225    } else {
     2226        tokc.str.size = tokcstr.size;
     2227        tokc.str.data = tokcstr.data;
     2228        if (!is_long)
     2229            tok = TOK_STR;
     2230        else
     2231            tok = TOK_LSTR;
     2232    }
    17462233}
    17472234
     
    18312318                shift = 4;
    18322319            else
    1833                 shift = 2;
     2320                shift = 1;
    18342321            bn_zero(bn);
    18352322            q = token_buf;
     
    19692456    } else {
    19702457        unsigned long long n, n1;
    1971         int lcount, ucount;
     2458        int lcount, ucount, ov = 0;
     2459        const char *p1;
    19722460
    19732461        /* integer number */
     
    19822470            t = *q++;
    19832471            /* no need for checks except for base 10 / 8 errors */
    1984             if (t == '\0') {
     2472            if (t == '\0')
    19852473                break;
    1986             } else if (t >= 'a') {
     2474            else if (t >= 'a')
    19872475                t = t - 'a' + 10;
    1988             } else if (t >= 'A') {
     2476            else if (t >= 'A')
    19892477                t = t - 'A' + 10;
    1990             } else {
     2478            else
    19912479                t = t - '0';
    1992                 if (t >= b)
    1993                     tcc_error("invalid digit");
    1994             }
     2480            if (t >= b)
     2481                tcc_error("invalid digit");
    19952482            n1 = n;
    19962483            n = n * b + t;
    19972484            /* detect overflow */
    1998             /* XXX: this test is not reliable */
    1999             if (n < n1)
    2000                 tcc_error("integer constant overflow");
    2001         }
    2002        
    2003         /* XXX: not exactly ANSI compliant */
    2004         if ((n & 0xffffffff00000000LL) != 0) {
    2005             if ((n >> 63) != 0)
    2006                 tok = TOK_CULLONG;
    2007             else
    2008                 tok = TOK_CLLONG;
    2009         } else if (n > 0x7fffffff) {
    2010             tok = TOK_CUINT;
    2011         } else {
    2012             tok = TOK_CINT;
    2013         }
    2014         lcount = 0;
    2015         ucount = 0;
     2485            if (n1 >= 0x1000000000000000ULL && n / b != n1)
     2486                ov = 1;
     2487        }
     2488
     2489        /* Determine the characteristics (unsigned and/or 64bit) the type of
     2490           the constant must have according to the constant suffix(es) */
     2491        lcount = ucount = 0;
     2492        p1 = p;
    20162493        for(;;) {
    20172494            t = toup(ch);
     
    20192496                if (lcount >= 2)
    20202497                    tcc_error("three 'l's in integer constant");
     2498                if (lcount && *(p - 1) != ch)
     2499                    tcc_error("incorrect integer suffix: %s", p1);
    20212500                lcount++;
    2022 #if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
    2023                 if (lcount == 2) {
    2024 #endif
    2025                     if (tok == TOK_CINT)
    2026                         tok = TOK_CLLONG;
    2027                     else if (tok == TOK_CUINT)
    2028                         tok = TOK_CULLONG;
    2029 #if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
    2030                 }
    2031 #endif
    20322501                ch = *p++;
    20332502            } else if (t == 'U') {
     
    20352504                    tcc_error("two 'u's in integer constant");
    20362505                ucount++;
    2037                 if (tok == TOK_CINT)
    2038                     tok = TOK_CUINT;
    2039                 else if (tok == TOK_CLLONG)
    2040                     tok = TOK_CULLONG;
    20412506                ch = *p++;
    20422507            } else {
     
    20442509            }
    20452510        }
    2046         if (tok == TOK_CINT || tok == TOK_CUINT)
    2047             tokc.ui = n;
    2048         else
    2049             tokc.ull = n;
     2511
     2512        /* Determine if it needs 64 bits and/or unsigned in order to fit */
     2513        if (ucount == 0 && b == 10) {
     2514            if (lcount <= (LONG_SIZE == 4)) {
     2515                if (n >= 0x80000000U)
     2516                    lcount = (LONG_SIZE == 4) + 1;
     2517            }
     2518            if (n >= 0x8000000000000000ULL)
     2519                ov = 1, ucount = 1;
     2520        } else {
     2521            if (lcount <= (LONG_SIZE == 4)) {
     2522                if (n >= 0x100000000ULL)
     2523                    lcount = (LONG_SIZE == 4) + 1;
     2524                else if (n >= 0x80000000U)
     2525                    ucount = 1;
     2526            }
     2527            if (n >= 0x8000000000000000ULL)
     2528                ucount = 1;
     2529        }
     2530
     2531        if (ov)
     2532            tcc_warning("integer constant overflow");
     2533
     2534        tok = TOK_CINT;
     2535        if (lcount) {
     2536            tok = TOK_CLONG;
     2537            if (lcount == 2)
     2538                tok = TOK_CLLONG;
     2539        }
     2540        if (ucount)
     2541            ++tok; /* TOK_CU... */
     2542        tokc.i = n;
    20502543    }
    20512544    if (ch)
     
    20682561static inline void next_nomacro1(void)
    20692562{
    2070     int t, c, is_long;
     2563    int t, c, is_long, len;
    20712564    TokenSym *ts;
    20722565    uint8_t *p, *p1;
     
    20812574        tok = c;
    20822575        p++;
    2083         goto keep_tok_flags;
     2576        if (parse_flags & PARSE_FLAG_SPACES)
     2577            goto keep_tok_flags;
     2578        while (isidnum_table[*p - CH_EOF] & IS_SPC)
     2579            ++p;
     2580        goto redo_no_start;
    20842581    case '\f':
    20852582    case '\v':
     
    20892586    case '\\':
    20902587        /* first look if it is in fact an end of buffer */
    2091         if (p >= file->buf_end) {
    2092             file->buf_ptr = p;
    2093             handle_eob();
    2094             p = file->buf_ptr;
    2095             if (p >= file->buf_end)
    2096                 goto parse_eof;
    2097             else
    2098                 goto redo_no_start;
    2099         } else {
    2100             file->buf_ptr = p;
    2101             ch = *p;
    2102             handle_stray();
    2103             p = file->buf_ptr;
     2588        c = handle_stray1(p);
     2589        p = file->buf_ptr;
     2590        if (c == '\\')
     2591            goto parse_simple;
     2592        if (c != CH_EOF)
    21042593            goto redo_no_start;
    2105         }
    2106     parse_eof:
    21072594        {
    21082595            TCCState *s1 = tcc_state;
     
    21292616                    printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL));
    21302617#endif
    2131                     add_cached_include(s1, file->filename, file->ifndef_macro_saved);
     2618                    search_cached_include(s1, file->filename, 1)
     2619                        ->ifndef_macro = file->ifndef_macro_saved;
    21322620                    tok_flags &= ~TOK_FLAG_ENDIF;
    21332621                }
     
    21412629                s1->include_stack_ptr--;
    21422630                p = file->buf_ptr;
     2631                if (p == file->buffer)
     2632                    tok_flags = TOK_FLAG_BOF|TOK_FLAG_BOL;
    21432633                goto redo_no_start;
    21442634            }
     
    21702660                tok = TOK_TWOSHARPS;
    21712661            } else {
    2172                 if (parse_flags & PARSE_FLAG_ASM_COMMENTS) {
     2662                if (parse_flags & PARSE_FLAG_ASM_FILE) {
    21732663                    p = parse_line_comment(p - 1);
    21742664                    goto redo_no_start;
     
    21792669        }
    21802670        break;
     2671   
     2672    /* dollar is allowed to start identifiers when not parsing asm */
     2673    case '$':
     2674        if (!(isidnum_table[c - CH_EOF] & IS_ID)
     2675         || (parse_flags & PARSE_FLAG_ASM_FILE))
     2676            goto parse_simple;
    21812677
    21822678    case 'a': case 'b': case 'c': case 'd':
     
    21992695        h = TOK_HASH_INIT;
    22002696        h = TOK_HASH_FUNC(h, c);
    2201         p++;
    2202         for(;;) {
    2203             c = *p;
    2204             if (!isidnum_table[c-CH_EOF])
    2205                 break;
     2697        while (c = *++p, isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
    22062698            h = TOK_HASH_FUNC(h, c);
    2207             p++;
    2208         }
     2699        len = p - p1;
    22092700        if (c != '\\') {
    22102701            TokenSym **pts;
    2211             int len;
    22122702
    22132703            /* fast case : no stray found, so we have the full token
    22142704               and we have already hashed it */
    2215             len = p - p1;
    22162705            h &= (TOK_HASH_SIZE - 1);
    22172706            pts = &hash_ident[h];
     
    22242713                pts = &(ts->hash_next);
    22252714            }
    2226             ts = tok_alloc_new(pts, p1, len);
     2715            ts = tok_alloc_new(pts, (char *) p1, len);
    22272716        token_found: ;
    22282717        } else {
    22292718            /* slower case */
    22302719            cstr_reset(&tokcstr);
    2231 
    2232             while (p1 < p) {
    2233                 cstr_ccat(&tokcstr, *p1);
    2234                 p1++;
    2235             }
     2720            cstr_cat(&tokcstr, (char *) p1, len);
    22362721            p--;
    22372722            PEEKC(c, p);
    22382723        parse_ident_slow:
    2239             while (isidnum_table[c-CH_EOF]) {
     2724            while (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
     2725            {
    22402726                cstr_ccat(&tokcstr, c);
    22412727                PEEKC(c, p);
     
    22622748        }
    22632749        break;
     2750
    22642751    case '0': case '1': case '2': case '3':
    22652752    case '4': case '5': case '6': case '7':
    22662753    case '8': case '9':
    2267 
    2268         cstr_reset(&tokcstr);
     2754        t = c;
     2755        PEEKC(c, p);
    22692756        /* after the first digit, accept digits, alpha, '.' or sign if
    22702757           prefixed by 'eEpP' */
    22712758    parse_num:
     2759        cstr_reset(&tokcstr);
    22722760        for(;;) {
     2761            cstr_ccat(&tokcstr, t);
     2762            if (!((isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
     2763                  || c == '.'
     2764                  || ((c == '+' || c == '-')
     2765                      && (((t == 'e' || t == 'E')
     2766                            && !(parse_flags & PARSE_FLAG_ASM_FILE
     2767                                /* 0xe+1 is 3 tokens in asm */
     2768                                && ((char*)tokcstr.data)[0] == '0'
     2769                                && toup(((char*)tokcstr.data)[1]) == 'X'))
     2770                          || t == 'p' || t == 'P'))))
     2771                break;
    22732772            t = c;
    2274             cstr_ccat(&tokcstr, c);
    22752773            PEEKC(c, p);
    2276             if (!(isnum(c) || isid(c) || c == '.' ||
    2277                   ((c == '+' || c == '-') &&
    2278                    (t == 'e' || t == 'E' || t == 'p' || t == 'P'))))
    2279                 break;
    22802774        }
    22812775        /* We add a trailing '\0' to ease parsing */
    22822776        cstr_ccat(&tokcstr, '\0');
    2283         tokc.cstr = &tokcstr;
     2777        tokc.str.size = tokcstr.size;
     2778        tokc.str.data = tokcstr.data;
    22842779        tok = TOK_PPNUM;
    22852780        break;
     2781
    22862782    case '.':
    22872783        /* special dot handling because it can also start a number */
    22882784        PEEKC(c, p);
    22892785        if (isnum(c)) {
    2290             cstr_reset(&tokcstr);
    2291             cstr_ccat(&tokcstr, '.');
     2786            t = '.';
    22922787            goto parse_num;
     2788        } else if ((isidnum_table['.' - CH_EOF] & IS_ID)
     2789                   && (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))) {
     2790            *--p = c = '.';
     2791            goto parse_ident_fast;
    22932792        } else if (c == '.') {
    22942793            PEEKC(c, p);
    2295             if (c != '.')
    2296                 expect("'.'");
    2297             PEEKC(c, p);
    2298             tok = TOK_DOTS;
     2794            if (c == '.') {
     2795                p++;
     2796                tok = TOK_DOTS;
     2797            } else {
     2798                *--p = '.'; /* may underflow into file->unget[] */
     2799                tok = '.';
     2800            }
    22992801        } else {
    23002802            tok = '.';
     
    23052807        is_long = 0;
    23062808    str_const:
    2307         {
    2308             CString str;
    2309             int sep;
    2310 
    2311             sep = c;
    2312 
    2313             /* parse the string */
    2314             cstr_new(&str);
    2315             p = parse_pp_string(p, sep, &str);
    2316             cstr_ccat(&str, '\0');
    2317            
    2318             /* eval the escape (should be done as TOK_PPNUM) */
    2319             cstr_reset(&tokcstr);
    2320             parse_escape_string(&tokcstr, str.data, is_long);
    2321             cstr_free(&str);
    2322 
    2323             if (sep == '\'') {
    2324                 int char_size;
    2325                 /* XXX: make it portable */
    2326                 if (!is_long)
    2327                     char_size = 1;
    2328                 else
    2329                     char_size = sizeof(nwchar_t);
    2330                 if (tokcstr.size <= char_size)
    2331                     tcc_error("empty character constant");
    2332                 if (tokcstr.size > 2 * char_size)
    2333                     tcc_warning("multi-character character constant");
    2334                 if (!is_long) {
    2335                     tokc.i = *(int8_t *)tokcstr.data;
    2336                     tok = TOK_CCHAR;
    2337                 } else {
    2338                     tokc.i = *(nwchar_t *)tokcstr.data;
    2339                     tok = TOK_LCHAR;
    2340                 }
    2341             } else {
    2342                 tokc.cstr = &tokcstr;
    2343                 if (!is_long)
    2344                     tok = TOK_STR;
    2345                 else
    2346                     tok = TOK_LSTR;
    2347             }
    2348         }
     2809        cstr_reset(&tokcstr);
     2810        if (is_long)
     2811            cstr_ccat(&tokcstr, 'L');
     2812        cstr_ccat(&tokcstr, c);
     2813        p = parse_pp_string(p, c, &tokcstr);
     2814        cstr_ccat(&tokcstr, c);
     2815        cstr_ccat(&tokcstr, '\0');
     2816        tokc.str.size = tokcstr.size;
     2817        tokc.str.data = tokcstr.data;
     2818        tok = TOK_PPSTR;
    23492819        break;
    23502820
     
    23662836        }
    23672837        break;
    2368        
    23692838    case '>':
    23702839        PEEKC(c, p);
     
    24782947    case '?':
    24792948    case '~':
    2480     case '$': /* only used in assembler */
    2481     case '@': /* dito */
     2949    case '@': /* only used in assembler */
     2950    parse_simple:
    24822951        tok = c;
    24832952        p++;
    24842953        break;
    24852954    default:
     2955        if (c >= 0x80 && c <= 0xFF) /* utf8 identifiers */
     2956            goto parse_ident_fast;
     2957        if (parse_flags & PARSE_FLAG_ASM_FILE)
     2958            goto parse_simple;
    24862959        tcc_error("unrecognized character \\x%02x", c);
    24872960        break;
     
    24912964    file->buf_ptr = p;
    24922965#if defined(PARSE_DEBUG)
    2493     printf("token = %s\n", get_tok_str(tok, &tokc));
     2966    printf("token = %d %s\n", tok, get_tok_str(tok, &tokc));
    24942967#endif
    24952968}
     
    25122985        next_nomacro1();
    25132986    }
     2987    //printf("token = %s\n", get_tok_str(tok, &tokc));
    25142988}
    25152989
     
    25182992    do {
    25192993        next_nomacro_spc();
    2520     } while (is_space(tok));
     2994    } while (tok < 256 && (isidnum_table[tok - CH_EOF] & IS_SPC));
    25212995}
    25222996 
    2523 /* substitute args in macro_str and return allocated string */
     2997
     2998static void macro_subst(
     2999    TokenString *tok_str,
     3000    Sym **nested_list,
     3001    const int *macro_str
     3002    );
     3003
     3004/* substitute arguments in replacement lists in macro_str by the values in
     3005   args (field d) and return allocated string */
    25243006static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args)
    25253007{
    2526     int last_tok, t, spc;
     3008    int t, t0, t1, spc;
    25273009    const int *st;
    25283010    Sym *s;
     
    25323014
    25333015    tok_str_new(&str);
    2534     last_tok = 0;
     3016    t0 = t1 = 0;
    25353017    while(1) {
    25363018        TOK_GET(&t, &macro_str, &cval);
     
    25413023            TOK_GET(&t, &macro_str, &cval);
    25423024            if (!t)
    2543                 break;
     3025                goto bad_stringy;
    25443026            s = sym_find2(args, t);
    25453027            if (s) {
    25463028                cstr_new(&cstr);
     3029                cstr_ccat(&cstr, '\"');
    25473030                st = s->d;
    25483031                spc = 0;
    2549                 while (*st) {
     3032                while (*st >= 0) {
    25503033                    TOK_GET(&t, &st, &cval);
    2551                     if (!check_space(t, &spc))
    2552                         cstr_cat(&cstr, get_tok_str(t, &cval));
     3034                    if (t != TOK_PLCHLDR
     3035                     && t != TOK_NOSUBST
     3036                     && 0 == check_space(t, &spc)) {
     3037                        const char *s = get_tok_str(t, &cval);
     3038                        while (*s) {
     3039                            if (t == TOK_PPSTR && *s != '\'')
     3040                                add_char(&cstr, *s);
     3041                            else
     3042                                cstr_ccat(&cstr, *s);
     3043                            ++s;
     3044                        }
     3045                    }
    25533046                }
    25543047                cstr.size -= spc;
     3048                cstr_ccat(&cstr, '\"');
    25553049                cstr_ccat(&cstr, '\0');
    25563050#ifdef PP_DEBUG
    2557                 printf("stringize: %s\n", (char *)cstr.data);
     3051                printf("\nstringize: <%s>\n", (char *)cstr.data);
    25583052#endif
    25593053                /* add string */
    2560                 cval.cstr = &cstr;
    2561                 tok_str_add2(&str, TOK_STR, &cval);
     3054                cval.str.size = cstr.size;
     3055                cval.str.data = cstr.data;
     3056                tok_str_add2(&str, TOK_PPSTR, &cval);
    25623057                cstr_free(&cstr);
    25633058            } else {
    2564                 tok_str_add2(&str, t, &cval);
     3059        bad_stringy:
     3060                expect("macro parameter after '#'");
    25653061            }
    25663062        } else if (t >= TOK_IDENT) {
    25673063            s = sym_find2(args, t);
    25683064            if (s) {
     3065                int l0 = str.len;
    25693066                st = s->d;
    25703067                /* if '##' is present before or after, no arg substitution */
    2571                 if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
    2572                     /* special case for var arg macros : ## eats the
    2573                        ',' if empty VA_ARGS variable. */
    2574                     /* XXX: test of the ',' is not 100%
    2575                        reliable. should fix it to avoid security
    2576                        problems */
    2577                     if (gnu_ext && s->type.t &&
    2578                         last_tok == TOK_TWOSHARPS &&
    2579                         str.len >= 2 && str.str[str.len - 2] == ',') {
    2580                         if (*st == 0) {
     3068                if (*macro_str == TOK_PPJOIN || t1 == TOK_PPJOIN) {
     3069                    /* special case for var arg macros : ## eats the ','
     3070                       if empty VA_ARGS variable. */
     3071                    if (t1 == TOK_PPJOIN && t0 == ',' && gnu_ext && s->type.t) {
     3072                        if (*st <= 0) {
    25813073                            /* suppress ',' '##' */
    25823074                            str.len -= 2;
     
    25863078                            goto add_var;
    25873079                        }
    2588                     } else {
    2589                         int t1;
    2590                     add_var:
    2591                         for(;;) {
    2592                             TOK_GET(&t1, &st, &cval);
    2593                             if (!t1)
    2594                                 break;
    2595                             tok_str_add2(&str, t1, &cval);
    2596                         }
    25973080                    }
    25983081                } else {
    2599                     /* NOTE: the stream cannot be read when macro
    2600                        substituing an argument */
    2601                     macro_subst(&str, nested_list, st, NULL);
     3082            add_var:
     3083                    if (!s->next) {
     3084                        /* Expand arguments tokens and store them.  In most
     3085                           cases we could also re-expand each argument if
     3086                           used multiple times, but not if the argument
     3087                           contains the __COUNTER__ macro.  */
     3088                        TokenString str2;
     3089                        sym_push2(&s->next, s->v, s->type.t, 0);
     3090                        tok_str_new(&str2);
     3091                        macro_subst(&str2, nested_list, st);
     3092                        tok_str_add(&str2, 0);
     3093                        s->next->d = str2.str;
     3094                    }
     3095                    st = s->next->d;
    26023096                }
     3097                for(;;) {
     3098                    int t2;
     3099                    TOK_GET(&t2, &st, &cval);
     3100                    if (t2 <= 0)
     3101                        break;
     3102                    tok_str_add2(&str, t2, &cval);
     3103                }
     3104                if (str.len == l0) /* expanded to empty string */
     3105                    tok_str_add(&str, TOK_PLCHLDR);
    26033106            } else {
    26043107                tok_str_add(&str, t);
     
    26073110            tok_str_add2(&str, t, &cval);
    26083111        }
    2609         last_tok = t;
     3112        t0 = t1, t1 = t;
    26103113    }
    26113114    tok_str_add(&str, 0);
     
    26183121    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    26193122};
     3123
     3124static int paste_tokens(int t1, CValue *v1, int t2, CValue *v2)
     3125{
     3126    CString cstr;
     3127    int n, ret = 1;
     3128
     3129    cstr_new(&cstr);
     3130    if (t1 != TOK_PLCHLDR)
     3131        cstr_cat(&cstr, get_tok_str(t1, v1), -1);
     3132    n = cstr.size;
     3133    if (t2 != TOK_PLCHLDR)
     3134        cstr_cat(&cstr, get_tok_str(t2, v2), -1);
     3135    cstr_ccat(&cstr, '\0');
     3136
     3137    tcc_open_bf(tcc_state, ":paste:", cstr.size);
     3138    memcpy(file->buffer, cstr.data, cstr.size);
     3139    tok_flags = 0;
     3140    for (;;) {
     3141        next_nomacro1();
     3142        if (0 == *file->buf_ptr)
     3143            break;
     3144        if (is_space(tok))
     3145            continue;
     3146        tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid"
     3147            " preprocessing token", n, cstr.data, (char*)cstr.data + n);
     3148        ret = 0;
     3149        break;
     3150    }
     3151    tcc_close();
     3152    //printf("paste <%s>\n", (char*)cstr.data);
     3153    cstr_free(&cstr);
     3154    return ret;
     3155}
     3156
     3157/* handle the '##' operator. Return NULL if no '##' seen. Otherwise
     3158   return the resulting string (which must be freed). */
     3159static inline int *macro_twosharps(const int *ptr0)
     3160{
     3161    int t;
     3162    CValue cval;
     3163    TokenString macro_str1;
     3164    int start_of_nosubsts = -1;
     3165    const int *ptr;
     3166
     3167    /* we search the first '##' */
     3168    for (ptr = ptr0;;) {
     3169        TOK_GET(&t, &ptr, &cval);
     3170        if (t == TOK_PPJOIN)
     3171            break;
     3172        if (t == 0)
     3173            return NULL;
     3174    }
     3175
     3176    tok_str_new(&macro_str1);
     3177
     3178    //tok_print(" $$$", ptr0);
     3179    for (ptr = ptr0;;) {
     3180        TOK_GET(&t, &ptr, &cval);
     3181        if (t == 0)
     3182            break;
     3183        if (t == TOK_PPJOIN)
     3184            continue;
     3185        while (*ptr == TOK_PPJOIN) {
     3186            int t1; CValue cv1;
     3187            /* given 'a##b', remove nosubsts preceding 'a' */
     3188            if (start_of_nosubsts >= 0)
     3189                macro_str1.len = start_of_nosubsts;
     3190            /* given 'a##b', remove nosubsts preceding 'b' */
     3191            while ((t1 = *++ptr) == TOK_NOSUBST)
     3192                ;
     3193            if (t1 && t1 != TOK_PPJOIN) {
     3194                TOK_GET(&t1, &ptr, &cv1);
     3195                if (t != TOK_PLCHLDR || t1 != TOK_PLCHLDR) {
     3196                    if (paste_tokens(t, &cval, t1, &cv1)) {
     3197                        t = tok, cval = tokc;
     3198                    } else {
     3199                        tok_str_add2(&macro_str1, t, &cval);
     3200                        t = t1, cval = cv1;
     3201                    }
     3202                }
     3203            }
     3204        }
     3205        if (t == TOK_NOSUBST) {
     3206            if (start_of_nosubsts < 0)
     3207                start_of_nosubsts = macro_str1.len;
     3208        } else {
     3209            start_of_nosubsts = -1;
     3210        }
     3211        tok_str_add2(&macro_str1, t, &cval);
     3212    }
     3213    tok_str_add(&macro_str1, 0);
     3214    //tok_print(" ###", macro_str1.str);
     3215    return macro_str1.str;
     3216}
     3217
     3218/* peek or read [ws_str == NULL] next token from function macro call,
     3219   walking up macro levels up to the file if necessary */
     3220static int next_argstream(Sym **nested_list, TokenString *ws_str)
     3221{
     3222    int t;
     3223    const int *p;
     3224    Sym *sa;
     3225
     3226    for (;;) {
     3227        if (macro_ptr) {
     3228            p = macro_ptr, t = *p;
     3229            if (ws_str) {
     3230                while (is_space(t) || TOK_LINEFEED == t || TOK_PLCHLDR == t)
     3231                    tok_str_add(ws_str, t), t = *++p;
     3232            }
     3233            if (t == 0) {
     3234                end_macro();
     3235                /* also, end of scope for nested defined symbol */
     3236                sa = *nested_list;
     3237                while (sa && sa->v == 0)
     3238                    sa = sa->prev;
     3239                if (sa)
     3240                    sa->v = 0;
     3241                continue;
     3242            }
     3243        } else {
     3244            ch = handle_eob();
     3245            if (ws_str) {
     3246                while (is_space(ch) || ch == '\n' || ch == '/') {
     3247                    if (ch == '/') {
     3248                        int c;
     3249                        uint8_t *p = file->buf_ptr;
     3250                        PEEKC(c, p);
     3251                        if (c == '*') {
     3252                            p = parse_comment(p);
     3253                            file->buf_ptr = p - 1;
     3254                        } else if (c == '/') {
     3255                            p = parse_line_comment(p);
     3256                            file->buf_ptr = p - 1;
     3257                        } else
     3258                            break;
     3259                        ch = ' ';
     3260                    }
     3261                    if (ch == '\n')
     3262                        file->line_num++;
     3263                    if (!(ch == '\f' || ch == '\v' || ch == '\r'))
     3264                        tok_str_add(ws_str, ch);
     3265                    cinp();
     3266                }
     3267            }
     3268            t = ch;
     3269        }
     3270
     3271        if (ws_str)
     3272            return t;
     3273        next_nomacro_spc();
     3274        return tok;
     3275    }
     3276}
    26203277
    26213278/* do macro substitution of current token with macro 's' and add
     
    26233280   macros we got inside to avoid recursing. Return non zero if no
    26243281   substitution needs to be done */
    2625 static int macro_subst_tok(TokenString *tok_str,
    2626                            Sym **nested_list, Sym *s, struct macro_level **can_read_stream)
     3282static int macro_subst_tok(
     3283    TokenString *tok_str,
     3284    Sym **nested_list,
     3285    Sym *s)
    26273286{
    26283287    Sym *args, *sa, *sa1;
    2629     int mstr_allocated, parlevel, *mstr, t, t1, spc;
    2630     const int *p;
     3288    int parlevel, t, t1, spc;
    26313289    TokenString str;
    26323290    char *cstrval;
     
    26343292    CString cstr;
    26353293    char buf[32];
    2636    
     3294
    26373295    /* if symbol is a macro, prepare substitution */
    26383296    /* special macros */
    2639     if (tok == TOK___LINE__) {
    2640         snprintf(buf, sizeof(buf), "%d", file->line_num);
     3297    if (tok == TOK___LINE__ || tok == TOK___COUNTER__) {
     3298        t = tok == TOK___LINE__ ? file->line_num : pp_counter++;
     3299        snprintf(buf, sizeof(buf), "%d", t);
    26413300        cstrval = buf;
    26423301        t1 = TOK_PPNUM;
     
    26633322    add_cstr1:
    26643323        cstr_new(&cstr);
    2665         cstr_cat(&cstr, cstrval);
    2666         cstr_ccat(&cstr, '\0');
    2667         cval.cstr = &cstr;
     3324        cstr_cat(&cstr, cstrval, 0);
     3325        cval.str.size = cstr.size;
     3326        cval.str.data = cstr.data;
    26683327        tok_str_add2(tok_str, t1, &cval);
    26693328        cstr_free(&cstr);
    2670     } else {
    2671         mstr = s->d;
    2672         mstr_allocated = 0;
     3329    } else if (s->d) {
     3330        int saved_parse_flags = parse_flags;
     3331        int *joined_str = NULL;
     3332        int *mstr = s->d;
     3333
    26733334        if (s->type.t == MACRO_FUNC) {
    2674             /* NOTE: we do not use next_nomacro to avoid eating the
    2675                next token. XXX: find better solution */
    2676         redo:
    2677             if (macro_ptr) {
    2678                 p = macro_ptr;
    2679                 while (is_space(t = *p) || TOK_LINEFEED == t)
    2680                     ++p;
    2681                 if (t == 0 && can_read_stream) {
    2682                     /* end of macro stream: we must look at the token
    2683                        after in the file */
    2684                     struct macro_level *ml = *can_read_stream;
    2685                     macro_ptr = NULL;
    2686                     if (ml)
    2687                     {
    2688                         macro_ptr = ml->p;
    2689                         ml->p = NULL;
    2690                         *can_read_stream = ml -> prev;
    2691                     }
    2692                     /* also, end of scope for nested defined symbol */
    2693                     (*nested_list)->v = -1;
    2694                     goto redo;
     3335            /* whitespace between macro name and argument list */
     3336            TokenString ws_str;
     3337            tok_str_new(&ws_str);
     3338
     3339            spc = 0;
     3340            parse_flags |= PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED
     3341                | PARSE_FLAG_ACCEPT_STRAYS;
     3342
     3343            /* get next token from argument stream */
     3344            t = next_argstream(nested_list, &ws_str);
     3345            if (t != '(') {
     3346                /* not a macro substitution after all, restore the
     3347                 * macro token plus all whitespace we've read.
     3348                 * whitespace is intentionally not merged to preserve
     3349                 * newlines. */
     3350                parse_flags = saved_parse_flags;
     3351                tok_str_add(tok_str, tok);
     3352                if (parse_flags & PARSE_FLAG_SPACES) {
     3353                    int i;
     3354                    for (i = 0; i < ws_str.len; i++)
     3355                        tok_str_add(tok_str, ws_str.str[i]);
    26953356                }
     3357                tok_str_free_str(ws_str.str);
     3358                return 0;
    26963359            } else {
    2697                 ch = file->buf_ptr[0];
    2698                 while (is_space(ch) || ch == '\n' || ch == '/')
    2699                   {
    2700                     if (ch == '/')
    2701                       {
    2702                         int c;
    2703                         uint8_t *p = file->buf_ptr;
    2704                         PEEKC(c, p);
    2705                         if (c == '*') {
    2706                             p = parse_comment(p);
    2707                             file->buf_ptr = p - 1;
    2708                         } else if (c == '/') {
    2709                             p = parse_line_comment(p);
    2710                             file->buf_ptr = p - 1;
    2711                         } else
    2712                           break;
    2713                       }
    2714                     cinp();
    2715                   }
    2716                 t = ch;
    2717             }
    2718             if (t != '(') /* no macro subst */
    2719                 return -1;
    2720                    
     3360                tok_str_free_str(ws_str.str);
     3361            }
     3362            do {
     3363                next_nomacro(); /* eat '(' */
     3364            } while (tok == TOK_PLCHLDR);
     3365
    27213366            /* argument macro */
    2722             next_nomacro();
    2723             next_nomacro();
    27243367            args = NULL;
    27253368            sa = s->next;
    27263369            /* NOTE: empty args are allowed, except if no args */
    27273370            for(;;) {
     3371                do {
     3372                    next_argstream(nested_list, NULL);
     3373                } while (is_space(tok) || TOK_LINEFEED == tok);
     3374    empty_arg:
    27283375                /* handle '()' case */
    27293376                if (!args && !sa && tok == ')')
     
    27373384                while ((parlevel > 0 ||
    27383385                        (tok != ')' &&
    2739                          (tok != ',' || sa->type.t))) &&
    2740                        tok != -1) {
     3386                         (tok != ',' || sa->type.t)))) {
     3387                    if (tok == TOK_EOF || tok == 0)
     3388                        break;
    27413389                    if (tok == '(')
    27423390                        parlevel++;
     
    27473395                    if (!check_space(tok, &spc))
    27483396                        tok_str_add2(&str, tok, &tokc);
    2749                     next_nomacro_spc();
     3397                    next_argstream(nested_list, NULL);
    27503398                }
     3399                if (parlevel)
     3400                    expect(")");
    27513401                str.len -= spc;
     3402                tok_str_add(&str, -1);
    27523403                tok_str_add(&str, 0);
    27533404                sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0);
     
    27583409                       var arg argument if it is omitted */
    27593410                    if (sa && sa->type.t && gnu_ext)
    2760                         continue;
    2761                     else
    2762                         break;
     3411                        goto empty_arg;
     3412                    break;
    27633413                }
    27643414                if (tok != ',')
    27653415                    expect(",");
    2766                 next_nomacro();
    27673416            }
    27683417            if (sa) {
     
    27703419                      get_tok_str(s->v, 0));
    27713420            }
     3421
     3422            parse_flags = saved_parse_flags;
    27723423
    27733424            /* now subst each arg */
     
    27773428            while (sa) {
    27783429                sa1 = sa->prev;
    2779                 tok_str_free(sa->d);
     3430                tok_str_free_str(sa->d);
     3431                if (sa->next) {
     3432                    tok_str_free_str(sa->next->d);
     3433                    sym_free(sa->next);
     3434                }
    27803435                sym_free(sa);
    27813436                sa = sa1;
    27823437            }
    2783             mstr_allocated = 1;
    2784         }
     3438        }
     3439
    27853440        sym_push2(nested_list, s->v, 0, 0);
    2786         macro_subst(tok_str, nested_list, mstr, can_read_stream);
     3441        parse_flags = saved_parse_flags;
     3442        joined_str = macro_twosharps(mstr);
     3443        macro_subst(tok_str, nested_list, joined_str ? joined_str : mstr);
     3444
    27873445        /* pop nested defined symbol */
    27883446        sa1 = *nested_list;
    27893447        *nested_list = sa1->prev;
    27903448        sym_free(sa1);
    2791         if (mstr_allocated)
    2792             tok_str_free(mstr);
     3449        if (joined_str)
     3450            tok_str_free_str(joined_str);
     3451        if (mstr != s->d)
     3452            tok_str_free_str(mstr);
    27933453    }
    27943454    return 0;
    27953455}
    2796 
    2797 /* handle the '##' operator. Return NULL if no '##' seen. Otherwise
    2798    return the resulting string (which must be freed). */
    2799 static inline int *macro_twosharps(const int *macro_str)
    2800 {
    2801     const int *ptr;
    2802     int t;
    2803     TokenString macro_str1;
    2804     CString cstr;
    2805     int n, start_of_nosubsts;
    2806 
    2807     /* we search the first '##' */
    2808     for(ptr = macro_str;;) {
    2809         CValue cval;
    2810         TOK_GET(&t, &ptr, &cval);
    2811         if (t == TOK_TWOSHARPS)
    2812             break;
    2813         /* nothing more to do if end of string */
    2814         if (t == 0)
    2815             return NULL;
    2816     }
    2817 
    2818     /* we saw '##', so we need more processing to handle it */
    2819     start_of_nosubsts = -1;
    2820     tok_str_new(&macro_str1);
    2821     for(ptr = macro_str;;) {
    2822         TOK_GET(&tok, &ptr, &tokc);
    2823         if (tok == 0)
    2824             break;
    2825         if (tok == TOK_TWOSHARPS)
    2826             continue;
    2827         if (tok == TOK_NOSUBST && start_of_nosubsts < 0)
    2828             start_of_nosubsts = macro_str1.len;
    2829         while (*ptr == TOK_TWOSHARPS) {
    2830             /* given 'a##b', remove nosubsts preceding 'a' */
    2831             if (start_of_nosubsts >= 0)
    2832                 macro_str1.len = start_of_nosubsts;
    2833             /* given 'a##b', skip '##' */
    2834             t = *++ptr;
    2835             /* given 'a##b', remove nosubsts preceding 'b' */
    2836             while (t == TOK_NOSUBST)
    2837                 t = *++ptr;
    2838             if (t && t != TOK_TWOSHARPS) {
    2839                 CValue cval;
    2840                 TOK_GET(&t, &ptr, &cval);
    2841                 /* We concatenate the two tokens */
    2842                 cstr_new(&cstr);
    2843                 cstr_cat(&cstr, get_tok_str(tok, &tokc));
    2844                 n = cstr.size;
    2845                 cstr_cat(&cstr, get_tok_str(t, &cval));
    2846                 cstr_ccat(&cstr, '\0');
    2847 
    2848                 tcc_open_bf(tcc_state, ":paste:", cstr.size);
    2849                 memcpy(file->buffer, cstr.data, cstr.size);
    2850                 for (;;) {
    2851                     next_nomacro1();
    2852                     if (0 == *file->buf_ptr)
    2853                         break;
    2854                     tok_str_add2(&macro_str1, tok, &tokc);
    2855                     tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid preprocessing token",
    2856                         n, cstr.data, (char*)cstr.data + n);
    2857                 }
    2858                 tcc_close();
    2859                 cstr_free(&cstr);
    2860             }
    2861         }
    2862         if (tok != TOK_NOSUBST)
    2863             start_of_nosubsts = -1;
    2864         tok_str_add2(&macro_str1, tok, &tokc);
    2865     }
    2866     tok_str_add(&macro_str1, 0);
    2867     return macro_str1.str;
    2868 }
    2869 
    28703456
    28713457/* do macro substitution of macro_str and add result to
    28723458   (tok_str,tok_len). 'nested_list' is the list of all macros we got
    28733459   inside to avoid recursing. */
    2874 static void macro_subst(TokenString *tok_str, Sym **nested_list,
    2875                         const int *macro_str, struct macro_level ** can_read_stream)
     3460static void macro_subst(
     3461    TokenString *tok_str,
     3462    Sym **nested_list,
     3463    const int *macro_str
     3464    )
    28763465{
    28773466    Sym *s;
    2878     int *macro_str1;
    2879     const int *ptr;
    2880     int t, ret, spc;
     3467    int t, spc, nosubst;
    28813468    CValue cval;
    2882     struct macro_level ml;
    2883     int force_blank;
    28843469   
    2885     /* first scan for '##' operator handling */
    2886     ptr = macro_str;
    2887     macro_str1 = macro_twosharps(ptr);
    2888 
    2889     if (macro_str1)
    2890         ptr = macro_str1;
    2891     spc = 0;
    2892     force_blank = 0;
     3470    spc = nosubst = 0;
    28933471
    28943472    while (1) {
    2895         /* NOTE: ptr == NULL can only happen if tokens are read from
    2896            file stream due to a macro function call */
    2897         if (ptr == NULL)
     3473        TOK_GET(&t, &macro_str, &cval);
     3474        if (t <= 0)
    28983475            break;
    2899         TOK_GET(&t, &ptr, &cval);
    2900         if (t == 0)
    2901             break;
    2902         if (t == TOK_NOSUBST) {
    2903             /* following token has already been subst'd. just copy it on */
    2904             tok_str_add2(tok_str, TOK_NOSUBST, NULL);
    2905             TOK_GET(&t, &ptr, &cval);
    2906             goto no_subst;
    2907         }
    2908         s = define_find(t);
    2909         if (s != NULL) {
     3476
     3477        if (t >= TOK_IDENT && 0 == nosubst) {
     3478            s = define_find(t);
     3479            if (s == NULL)
     3480                goto no_subst;
     3481
    29103482            /* if nested substitution, do nothing */
    29113483            if (sym_find2(*nested_list, t)) {
     
    29143486                goto no_subst;
    29153487            }
    2916             ml.p = macro_ptr;
    2917             if (can_read_stream)
    2918                 ml.prev = *can_read_stream, *can_read_stream = &ml;
    2919             macro_ptr = (int *)ptr;
    2920             tok = t;
    2921             ret = macro_subst_tok(tok_str, nested_list, s, can_read_stream);
    2922             ptr = (int *)macro_ptr;
    2923             macro_ptr = ml.p;
    2924             if (can_read_stream && *can_read_stream == &ml)
    2925                 *can_read_stream = ml.prev;
    2926             if (ret != 0)
    2927                 goto no_subst;
    2928             if (parse_flags & PARSE_FLAG_SPACES)
    2929                 force_blank = 1;
     3488
     3489            {
     3490                TokenString str;
     3491                str.str = (int*)macro_str;
     3492                begin_macro(&str, 2);
     3493
     3494                tok = t;
     3495                macro_subst_tok(tok_str, nested_list, s);
     3496
     3497                if (str.alloc == 3) {
     3498                    /* already finished by reading function macro arguments */
     3499                    break;
     3500                }
     3501
     3502                macro_str = macro_ptr;
     3503                end_macro ();
     3504            }
     3505            if (tok_str->len)
     3506                spc = is_space(t = tok_str->str[tok_str->lastlen]);
    29303507        } else {
    2931         no_subst:
    2932             if (force_blank) {
    2933                 tok_str_add(tok_str, ' ');
    2934                 spc = 1;
    2935                 force_blank = 0;
    2936             }
    2937             if (!check_space(t, &spc))
     3508            if (t == '\\' && !(parse_flags & PARSE_FLAG_ACCEPT_STRAYS))
     3509                tcc_error("stray '\\' in program");
     3510no_subst:
     3511            if (!check_space(t, &spc))
    29383512                tok_str_add2(tok_str, t, &cval);
    2939         }
    2940     }
    2941     if (macro_str1)
    2942         tok_str_free(macro_str1);
     3513
     3514            if (nosubst) {
     3515                if (nosubst > 1 && (spc || (++nosubst == 3 && t == '(')))
     3516                    continue;
     3517                nosubst = 0;
     3518            }
     3519            if (t == TOK_NOSUBST)
     3520                nosubst = 1;
     3521        }
     3522        /* GCC supports 'defined' as result of a macro substitution */
     3523        if (t == TOK_DEFINED && pp_expr)
     3524            nosubst = 2;
     3525    }
    29433526}
    29443527
     
    29463529ST_FUNC void next(void)
    29473530{
    2948     Sym *nested_list, *s;
    2949     TokenString str;
    2950     struct macro_level *ml;
    2951 
    29523531 redo:
    29533532    if (parse_flags & PARSE_FLAG_SPACES)
     
    29553534    else
    29563535        next_nomacro();
    2957     if (!macro_ptr) {
    2958         /* if not reading from macro substituted string, then try
    2959            to substitute macros */
    2960         if (tok >= TOK_IDENT &&
    2961             (parse_flags & PARSE_FLAG_PREPROCESS)) {
    2962             s = define_find(tok);
    2963             if (s) {
    2964                 /* we have a macro: we try to substitute */
    2965                 tok_str_new(&str);
    2966                 nested_list = NULL;
    2967                 ml = NULL;
    2968                 if (macro_subst_tok(&str, &nested_list, s, &ml) == 0) {
    2969                     /* substitution done, NOTE: maybe empty */
    2970                     tok_str_add(&str, 0);
    2971                     macro_ptr = str.str;
    2972                     macro_ptr_allocated = str.str;
    2973                     goto redo;
    2974                 }
    2975             }
    2976         }
    2977     } else {
    2978         if (tok == 0) {
    2979             /* end of macro or end of unget buffer */
    2980             if (unget_buffer_enabled) {
    2981                 macro_ptr = unget_saved_macro_ptr;
    2982                 unget_buffer_enabled = 0;
    2983             } else {
    2984                 /* end of macro string: free it */
    2985                 tok_str_free(macro_ptr_allocated);
    2986                 macro_ptr_allocated = NULL;
    2987                 macro_ptr = NULL;
    2988             }
     3536
     3537    if (macro_ptr) {
     3538        if (tok == TOK_NOSUBST || tok == TOK_PLCHLDR) {
     3539        /* discard preprocessor markers */
    29893540            goto redo;
    2990         } else if (tok == TOK_NOSUBST) {
    2991             /* discard preprocessor's nosubst markers */
     3541        } else if (tok == 0) {
     3542            /* end of macro or unget token string */
     3543            end_macro();
    29923544            goto redo;
    29933545        }
    2994     }
    2995    
     3546    } else if (tok >= TOK_IDENT && (parse_flags & PARSE_FLAG_PREPROCESS)) {
     3547        Sym *s;
     3548        /* if reading from file, try to substitute macros */
     3549        s = define_find(tok);
     3550        if (s) {
     3551            Sym *nested_list = NULL;
     3552            tokstr_buf.len = 0;
     3553            macro_subst_tok(&tokstr_buf, &nested_list, s);
     3554            tok_str_add(&tokstr_buf, 0);
     3555            begin_macro(&tokstr_buf, 2);
     3556            goto redo;
     3557        }
     3558    }
    29963559    /* convert preprocessor tokens into C tokens */
    2997     if (tok == TOK_PPNUM &&
    2998         (parse_flags & PARSE_FLAG_TOK_NUM)) {
    2999         parse_number((char *)tokc.cstr->data);
     3560    if (tok == TOK_PPNUM) {
     3561        if  (parse_flags & PARSE_FLAG_TOK_NUM)
     3562            parse_number((char *)tokc.str.data);
     3563    } else if (tok == TOK_PPSTR) {
     3564        if (parse_flags & PARSE_FLAG_TOK_STR)
     3565            parse_string((char *)tokc.str.data, tokc.str.size - 1);
    30003566    }
    30013567}
     
    30053571ST_INLN void unget_tok(int last_tok)
    30063572{
    3007     int i, n;
    3008     int *q;
    3009     if (unget_buffer_enabled)
    3010       {
    3011         /* assert(macro_ptr == unget_saved_buffer + 1);
    3012            assert(*macro_ptr == 0);  */
    3013       }
    3014     else
    3015       {
    3016         unget_saved_macro_ptr = macro_ptr;
    3017         unget_buffer_enabled = 1;
    3018       }
    3019     q = unget_saved_buffer;
    3020     macro_ptr = q;
    3021     *q++ = tok;
    3022     n = tok_ext_size(tok) - 1;
    3023     for(i=0;i<n;i++)
    3024         *q++ = tokc.tab[i];
    3025     *q = 0; /* end of token string */
     3573
     3574    TokenString *str = tok_str_alloc();
     3575    tok_str_add2(str, tok, &tokc);
     3576    tok_str_add(str, 0);
     3577    begin_macro(str, 1);
    30263578    tok = last_tok;
    30273579}
    30283580
    3029 
    3030 /* better than nothing, but needs extension to handle '-E' option
    3031    correctly too */
    3032 ST_FUNC void preprocess_init(TCCState *s1)
    3033 {
     3581ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
     3582{
     3583    CString cstr;
     3584    int i;
     3585
    30343586    s1->include_stack_ptr = s1->include_stack;
    3035     /* XXX: move that before to avoid having to initialize
    3036        file->ifdef_stack_ptr ? */
    30373587    s1->ifdef_stack_ptr = s1->ifdef_stack;
    30383588    file->ifdef_stack_ptr = s1->ifdef_stack_ptr;
    3039 
    3040     vtop = vstack - 1;
     3589    pp_expr = 0;
     3590    pp_counter = 0;
     3591    pp_debug_tok = pp_debug_symv = 0;
     3592    pp_once++;
     3593    pvtop = vtop = vstack - 1;
    30413594    s1->pack_stack[0] = 0;
    30423595    s1->pack_stack_ptr = s1->pack_stack;
    3043 }
    3044 
    3045 ST_FUNC void preprocess_new(void)
     3596
     3597    set_idnum('$', s1->dollars_in_identifiers ? IS_ID : 0);
     3598    set_idnum('.', is_asm ? IS_ID : 0);
     3599
     3600    cstr_new(&cstr);
     3601    cstr_cat(&cstr, "\"", -1);
     3602    cstr_cat(&cstr, file->filename, -1);
     3603    cstr_cat(&cstr, "\"", 0);
     3604    tcc_define_symbol(s1, "__BASE_FILE__", cstr.data);
     3605
     3606    cstr_reset(&cstr);
     3607    for (i = 0; i < s1->nb_cmd_include_files; i++) {
     3608        cstr_cat(&cstr, "#include \"", -1);
     3609        cstr_cat(&cstr, s1->cmd_include_files[i], -1);
     3610        cstr_cat(&cstr, "\"\n", -1);
     3611    }
     3612    if (cstr.size) {
     3613        *s1->include_stack_ptr++ = file;
     3614        tcc_open_bf(s1, "<command line>", cstr.size);
     3615        memcpy(file->buffer, cstr.data, cstr.size);
     3616    }
     3617    cstr_free(&cstr);
     3618
     3619    if (is_asm)
     3620        tcc_define_symbol(s1, "__ASSEMBLER__", NULL);
     3621
     3622    parse_flags = is_asm ? PARSE_FLAG_ASM_FILE : 0;
     3623    tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
     3624}
     3625
     3626/* cleanup from error/setjmp */
     3627ST_FUNC void preprocess_end(TCCState *s1)
     3628{
     3629    while (macro_stack)
     3630        end_macro();
     3631    macro_ptr = NULL;
     3632}
     3633
     3634ST_FUNC void tccpp_new(TCCState *s)
    30463635{
    30473636    int i, c;
    30483637    const char *p, *r;
    30493638
     3639    /* might be used in error() before preprocess_start() */
     3640    s->include_stack_ptr = s->include_stack;
     3641    s->ppfp = stdout;
     3642
    30503643    /* init isid table */
    3051     for(i=CH_EOF;i<256;i++)
    3052         isidnum_table[i-CH_EOF] = isid(i) || isnum(i);
    3053 
    3054     /* add all tokens */
    3055     table_ident = NULL;
     3644    for(i = CH_EOF; i<128; i++)
     3645        set_idnum(i,
     3646            is_space(i) ? IS_SPC
     3647            : isid(i) ? IS_ID
     3648            : isnum(i) ? IS_NUM
     3649            : 0);
     3650
     3651    for(i = 128; i<256; i++)
     3652        set_idnum(i, IS_ID);
     3653
     3654    /* init allocators */
     3655    tal_new(&toksym_alloc, TOKSYM_TAL_LIMIT, TOKSYM_TAL_SIZE);
     3656    tal_new(&tokstr_alloc, TOKSTR_TAL_LIMIT, TOKSTR_TAL_SIZE);
     3657    tal_new(&cstr_alloc, CSTR_TAL_LIMIT, CSTR_TAL_SIZE);
     3658
    30563659    memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
     3660    cstr_new(&cstr_buf);
     3661    cstr_realloc(&cstr_buf, STRING_MAX_SIZE);
     3662    tok_str_new(&tokstr_buf);
     3663    tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE);
    30573664   
    30583665    tok_ident = TOK_IDENT;
     
    30703677}
    30713678
     3679ST_FUNC void tccpp_delete(TCCState *s)
     3680{
     3681    int i, n;
     3682
     3683    /* free -D and compiler defines */
     3684    free_defines(NULL);
     3685
     3686    /* free tokens */
     3687    n = tok_ident - TOK_IDENT;
     3688    for(i = 0; i < n; i++)
     3689        tal_free(toksym_alloc, table_ident[i]);
     3690    tcc_free(table_ident);
     3691    table_ident = NULL;
     3692
     3693    /* free static buffers */
     3694    cstr_free(&tokcstr);
     3695    cstr_free(&cstr_buf);
     3696    cstr_free(&macro_equal_buf);
     3697    tok_str_free_str(tokstr_buf.str);
     3698
     3699    /* free allocators */
     3700    tal_delete(toksym_alloc);
     3701    toksym_alloc = NULL;
     3702    tal_delete(tokstr_alloc);
     3703    tokstr_alloc = NULL;
     3704    tal_delete(cstr_alloc);
     3705    cstr_alloc = NULL;
     3706}
     3707
     3708/* ------------------------------------------------------------------------- */
     3709/* tcc -E [-P[1]] [-dD} support */
     3710
     3711static void tok_print(const char *msg, const int *str)
     3712{
     3713    FILE *fp;
     3714    int t, s = 0;
     3715    CValue cval;
     3716
     3717    fp = tcc_state->ppfp;
     3718    fprintf(fp, "%s", msg);
     3719    while (str) {
     3720        TOK_GET(&t, &str, &cval);
     3721        if (!t)
     3722            break;
     3723        fprintf(fp, " %s" + s, get_tok_str(t, &cval)), s = 1;
     3724    }
     3725    fprintf(fp, "\n");
     3726}
     3727
     3728static void pp_line(TCCState *s1, BufferedFile *f, int level)
     3729{
     3730    int d = f->line_num - f->line_ref;
     3731
     3732    if (s1->dflag & 4)
     3733        return;
     3734
     3735    if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_NONE) {
     3736        ;
     3737    } else if (level == 0 && f->line_ref && d < 8) {
     3738        while (d > 0)
     3739            fputs("\n", s1->ppfp), --d;
     3740    } else if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_STD) {
     3741        fprintf(s1->ppfp, "#line %d \"%s\"\n", f->line_num, f->filename);
     3742    } else {
     3743        fprintf(s1->ppfp, "# %d \"%s\"%s\n", f->line_num, f->filename,
     3744            level > 0 ? " 1" : level < 0 ? " 2" : "");
     3745    }
     3746    f->line_ref = f->line_num;
     3747}
     3748
     3749static void define_print(TCCState *s1, int v)
     3750{
     3751    FILE *fp;
     3752    Sym *s;
     3753
     3754    s = define_find(v);
     3755    if (NULL == s || NULL == s->d)
     3756        return;
     3757
     3758    fp = s1->ppfp;
     3759    fprintf(fp, "#define %s", get_tok_str(v, NULL));
     3760    if (s->type.t == MACRO_FUNC) {
     3761        Sym *a = s->next;
     3762        fprintf(fp,"(");
     3763        if (a)
     3764            for (;;) {
     3765                fprintf(fp,"%s", get_tok_str(a->v & ~SYM_FIELD, NULL));
     3766                if (!(a = a->next))
     3767                    break;
     3768                fprintf(fp,",");
     3769            }
     3770        fprintf(fp,")");
     3771    }
     3772    tok_print("", s->d);
     3773}
     3774
     3775static void pp_debug_defines(TCCState *s1)
     3776{
     3777    int v, t;
     3778    const char *vs;
     3779    FILE *fp;
     3780
     3781    t = pp_debug_tok;
     3782    if (t == 0)
     3783        return;
     3784
     3785    file->line_num--;
     3786    pp_line(s1, file, 0);
     3787    file->line_ref = ++file->line_num;
     3788
     3789    fp = s1->ppfp;
     3790    v = pp_debug_symv;
     3791    vs = get_tok_str(v, NULL);
     3792    if (t == TOK_DEFINE) {
     3793        define_print(s1, v);
     3794    } else if (t == TOK_UNDEF) {
     3795        fprintf(fp, "#undef %s\n", vs);
     3796    } else if (t == TOK_push_macro) {
     3797        fprintf(fp, "#pragma push_macro(\"%s\")\n", vs);
     3798    } else if (t == TOK_pop_macro) {
     3799        fprintf(fp, "#pragma pop_macro(\"%s\")\n", vs);
     3800    }
     3801    pp_debug_tok = 0;
     3802}
     3803
     3804static void pp_debug_builtins(TCCState *s1)
     3805{
     3806    int v;
     3807    for (v = TOK_IDENT; v < tok_ident; ++v)
     3808        define_print(s1, v);
     3809}
     3810
     3811/* Add a space between tokens a and b to avoid unwanted textual pasting */
     3812static int pp_need_space(int a, int b)
     3813{
     3814    return 'E' == a ? '+' == b || '-' == b
     3815        : '+' == a ? TOK_INC == b || '+' == b
     3816        : '-' == a ? TOK_DEC == b || '-' == b
     3817        : a >= TOK_IDENT ? b >= TOK_IDENT
     3818        : a == TOK_PPNUM ? b >= TOK_IDENT
     3819        : 0;
     3820}
     3821
     3822/* maybe hex like 0x1e */
     3823static int pp_check_he0xE(int t, const char *p)
     3824{
     3825    if (t == TOK_PPNUM && toup(strchr(p, 0)[-1]) == 'E')
     3826        return 'E';
     3827    return t;
     3828}
     3829
    30723830/* Preprocess the current file */
    30733831ST_FUNC int tcc_preprocess(TCCState *s1)
    30743832{
    3075     Sym *define_start;
    3076 
    3077     BufferedFile *file_ref, **iptr, **iptr_new;
    3078     int token_seen, line_ref, d;
    3079     const char *s;
    3080 
    3081     preprocess_init(s1);
    3082     define_start = define_stack;
    3083     ch = file->buf_ptr[0];
    3084     tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
    3085     parse_flags = PARSE_FLAG_ASM_COMMENTS | PARSE_FLAG_PREPROCESS |
    3086         PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES;
    3087     token_seen = 0;
    3088     line_ref = 0;
    3089     file_ref = NULL;
    3090     iptr = s1->include_stack_ptr;
    3091 
     3833    BufferedFile **iptr;
     3834    int token_seen, spcs, level;
     3835    const char *p;
     3836    char white[400];
     3837
     3838    parse_flags = PARSE_FLAG_PREPROCESS
     3839                | (parse_flags & PARSE_FLAG_ASM_FILE)
     3840                | PARSE_FLAG_LINEFEED
     3841                | PARSE_FLAG_SPACES
     3842                | PARSE_FLAG_ACCEPT_STRAYS
     3843                ;
     3844    /* Credits to Fabrice Bellard's initial revision to demonstrate its
     3845       capability to compile and run itself, provided all numbers are
     3846       given as decimals. tcc -E -P10 will do. */
     3847    if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_P10)
     3848        parse_flags |= PARSE_FLAG_TOK_NUM, s1->Pflag = 1;
     3849
     3850#ifdef PP_BENCH
     3851    /* for PP benchmarks */
     3852    do next(); while (tok != TOK_EOF);
     3853    return 0;
     3854#endif
     3855
     3856    if (s1->dflag & 1) {
     3857        pp_debug_builtins(s1);
     3858        s1->dflag &= ~1;
     3859    }
     3860
     3861    token_seen = TOK_LINEFEED, spcs = 0;
     3862    pp_line(s1, file, 0);
    30923863    for (;;) {
     3864        iptr = s1->include_stack_ptr;
    30933865        next();
    3094         if (tok == TOK_EOF) {
     3866        if (tok == TOK_EOF)
    30953867            break;
    3096         } else if (file != file_ref) {
    3097             goto print_line;
     3868
     3869        level = s1->include_stack_ptr - iptr;
     3870        if (level) {
     3871            if (level > 0)
     3872                pp_line(s1, *iptr, 0);
     3873            pp_line(s1, file, level);
     3874        }
     3875        if (s1->dflag & 7) {
     3876            pp_debug_defines(s1);
     3877            if (s1->dflag & 4)
     3878                continue;
     3879        }
     3880
     3881        if (is_space(tok)) {
     3882            if (spcs < sizeof white - 1)
     3883                white[spcs++] = tok;
     3884            continue;
    30983885        } else if (tok == TOK_LINEFEED) {
    3099             if (!token_seen)
     3886            spcs = 0;
     3887            if (token_seen == TOK_LINEFEED)
    31003888                continue;
    3101             ++line_ref;
    3102             token_seen = 0;
    3103         } else if (!token_seen) {
    3104             d = file->line_num - line_ref;
    3105             if (file != file_ref || d < 0 || d >= 8) {
    3106 print_line:
    3107                 iptr_new = s1->include_stack_ptr;
    3108                 s = iptr_new > iptr ? " 1"
    3109                   : iptr_new < iptr ? " 2"
    3110                   : iptr_new > s1->include_stack ? " 3"
    3111                   : ""
    3112                   ;
    3113                 iptr = iptr_new;
    3114                 fprintf(s1->ppfp, "# %d \"%s\"%s\n", file->line_num, file->filename, s);
    3115             } else {
    3116                 while (d)
    3117                     fputs("\n", s1->ppfp), --d;
    3118             }
    3119             line_ref = (file_ref = file)->line_num;
    3120             token_seen = tok != TOK_LINEFEED;
    3121             if (!token_seen)
    3122                 continue;
    3123         }
    3124         fputs(get_tok_str(tok, &tokc), s1->ppfp);
    3125     }
    3126     free_defines(define_start);
     3889            ++file->line_ref;
     3890        } else if (token_seen == TOK_LINEFEED) {
     3891            pp_line(s1, file, 0);
     3892        } else if (spcs == 0 && pp_need_space(token_seen, tok)) {
     3893            white[spcs++] = ' ';
     3894        }
     3895
     3896        white[spcs] = 0, fputs(white, s1->ppfp), spcs = 0;
     3897        fputs(p = get_tok_str(tok, &tokc), s1->ppfp);
     3898        token_seen = pp_check_he0xE(tok, p);
     3899    }
    31273900    return 0;
    31283901}
     3902
     3903/* ------------------------------------------------------------------------- */
Note: See TracChangeset for help on using the changeset viewer.