3961 lines · 109.4 KB · C
RawDownload
/* *  TCC - Tiny C Compiler *  *  Copyright (c) 2001-2004 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */ #define USING_GLOBALS#include "tcc.h" /* #define to 1 to enable (see parse_pp_string()) */#define ACCEPT_LF_IN_STRINGS 0 /********************************************************//* global variables */ ST_DATA int tok_flags;ST_DATA int parse_flags; ST_DATA struct BufferedFile *file;ST_DATA int tok;ST_DATA CValue tokc;ST_DATA const int *macro_ptr;ST_DATA CString tokcstr; /* current parsed string, if any */ /* display benchmark infos */ST_DATA int tok_ident;ST_DATA TokenSym **table_ident;ST_DATA int pp_expr; /* ------------------------------------------------------------------------- */ static TokenSym *hash_ident[TOK_HASH_SIZE];static char token_buf[STRING_MAX_SIZE + 1];static CString cstr_buf;static TokenString tokstr_buf;static TokenString unget_buf;static unsigned char isidnum_table[256 - CH_EOF];static int pp_debug_tok, pp_debug_symv;static int pp_counter;static void tok_print(const int *str, const char *msg, ...);static void next_nomacro(void);static void parse_number(const char *p);static void parse_string(const char *p, int len); static struct TinyAlloc *toksym_alloc;static struct TinyAlloc *tokstr_alloc; static TokenString *macro_stack; static const char tcc_keywords[] = #define DEF(id, str) str "\0"#include "tcctok.h"#undef DEF; /* WARNING: the content of this string encodes token numbers */static const unsigned char tok_two_chars[] =/* outdated -- gr    "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253"    "-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266";*/{    '<','=', TOK_LE,    '>','=', TOK_GE,    '!','=', TOK_NE,    '&','&', TOK_LAND,    '|','|', TOK_LOR,    '+','+', TOK_INC,    '-','-', TOK_DEC,    '=','=', TOK_EQ,    '<','<', TOK_SHL,    '>','>', TOK_SAR,    '+','=', TOK_A_ADD,    '-','=', TOK_A_SUB,    '*','=', TOK_A_MUL,    '/','=', TOK_A_DIV,    '%','=', TOK_A_MOD,    '&','=', TOK_A_AND,    '^','=', TOK_A_XOR,    '|','=', TOK_A_OR,    '-','>', TOK_ARROW,    '.','.', TOK_TWODOTS,    '#','#', TOK_TWOSHARPS,    0}; ST_FUNC void skip(int c){    if (tok != c) {        char tmp[40];        pstrcpy(tmp, sizeof tmp, get_tok_str(c, &tokc));        tcc_error("'%s' expected (got '%s')", tmp, get_tok_str(tok, &tokc));	}    next();} ST_FUNC void expect(const char *msg){    tcc_error("%s expected", msg);} /* ------------------------------------------------------------------------- *//* Custom allocator for tiny objects */ #define USE_TAL #ifndef USE_TAL /* may cause memory leaks after errors */#define tal_free(al, p) tcc_free(p)#define tal_realloc(al, p, size) tcc_realloc(p, size)#define tal_new(a,b)#define tal_delete(a)#else#if !defined(MEM_DEBUG)#define tal_free(al, p) tal_free_impl(al, p)#define tal_realloc(al, p, size) tal_realloc_impl(al, p, size)#define TAL_DEBUG_PARAMS#else#define TAL_DEBUG MEM_DEBUG//#define TAL_INFO 1 /* collect and dump allocators stats */#define tal_free(al, p) tal_free_impl(al, p, __FILE__, __LINE__)#define tal_realloc(al, p, size) tal_realloc_impl(al, p, size, __FILE__, __LINE__)#define TAL_DEBUG_PARAMS , const char *sfile, int sline#endif #define TOKSYM_TAL_SIZE (256 * 1024) /* allocator for TokenSym in table_ident */#define TOKSTR_TAL_SIZE (256 * 1024) /* allocator for TokenString instances */ typedef struct TinyAlloc {    uint8_t *p;    uint8_t *bufend;    struct TinyAlloc *next;    unsigned nb_allocs;    unsigned size;#if TAL_INFO    unsigned nb_peak;    unsigned nb_total;    uint8_t *peak_p;#endif    union {        uint8_t buffer[1];        size_t _aligner_;    };} TinyAlloc; typedef struct tal_header_t {    size_t  size; /* word align */#if TAL_DEBUG    int     line_num; /* negative line_num used for double free check */    char    file_name[40];#endif} tal_header_t; #define TAL_ALIGN(size) \    (((size) + (sizeof (size_t) - 1)) & ~(sizeof (size_t) - 1)) /* ------------------------------------------------------------------------- */ static TinyAlloc *tal_new(TinyAlloc **pal, unsigned size){    TinyAlloc *al = tcc_malloc(sizeof(TinyAlloc) - sizeof (size_t) + size);    al->p = al->buffer;    al->bufend = al->buffer + size;    al->nb_allocs = 0;    al->next = *pal, *pal = al;    al->size = al->next ? al->next->size : size;#if TAL_INFO    al->nb_peak = 0;    al->nb_total = 0;    al->peak_p = al->p;#endif    return al;} static void tal_delete(TinyAlloc **pal){    TinyAlloc *al = *pal, *next; #if TAL_INFO    fprintf(stderr, "tal_delete (&tok%s_alloc):\n", pal == &toksym_alloc ? "sym" : "str");#endiftail_call:#if TAL_DEBUG && TAL_DEBUG != 3 /* do not check TAL leaks with -DMEM_DEBUG=3 */#if TAL_INFO    fprintf(stderr, "  size %7d  nb_peak %5d  nb_total %6d  usage %5.1f%%\n",            al->bufend - al->buffer, al->nb_peak, al->nb_total,            (al->peak_p - al->buffer) * 100.0 / (al->bufend - al->buffer));#endif    if (al->nb_allocs > 0) {        uint8_t *p;        fprintf(stderr, "TAL_DEBUG: memory leak %d chunk(s)\n", al->nb_allocs);        p = al->buffer;        while (p < al->p) {            tal_header_t *header = (tal_header_t *)p;            if (header->line_num > 0) {                fprintf(stderr, "%s:%d: chunk of %d bytes leaked\n",                        header->file_name, header->line_num, (int)header->size);            }            p += header->size + sizeof(tal_header_t);        }#if TAL_DEBUG == 2        exit(2);#endif    }#endif    next = al->next;    tcc_free(al);    al = next;    if (al)        goto tail_call;    *pal = al;} static void tal_free_impl(TinyAlloc **pal, void *p TAL_DEBUG_PARAMS){    TinyAlloc *al, **top = pal;    tal_header_t *header;     if (!p)        return;    header = (tal_header_t *)p - 1;#if TAL_DEBUG    if (header->line_num < 0) {        fprintf(stderr, "%s:%d: TAL_DEBUG: double frees chunk from\n",                sfile, sline);        fprintf(stderr, "%s:%d: %d bytes\n",                header->file_name, (int)-header->line_num, (int)header->size);    } else        header->line_num = -header->line_num;#endif    al = *pal;    while ((uint8_t*)p < al->buffer || (uint8_t*)p > al->bufend)        al = *(pal = &al->next);    if (0 == --al->nb_allocs) {        *pal = al->next;        if ((al->bufend - al->buffer) > al->size) {            //fprintf(stderr, "free big tal: %u\n", header->size);            tcc_free(al);        } else {            /* reset and move to front */            al->p = al->buffer;            al->next = *top, *top = al;        }    } else if ((uint8_t*)p + header->size == al->p) {        al->p = (uint8_t*)header;    }} static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_PARAMS){    tal_header_t *header;    void *ret;    unsigned adj_size = TAL_ALIGN(size) + sizeof(tal_header_t);    TinyAlloc *al = *pal;     if (p) {        /* reallpc case */        while ((uint8_t*)p < al->buffer || (uint8_t*)p > al->bufend)            al = al->next;        header = (tal_header_t *)p - 1;        if ((uint8_t*)p + header->size == al->p)            al->p = (uint8_t*)header; /* maybe reuse */        if (al->p + adj_size > al->bufend) {            ret = tal_realloc(pal, 0, size);            memcpy(ret, p, header->size);            tal_free(pal, p);            return ret;        } else if (al->p != (uint8_t*)header) {            memcpy((tal_header_t*)al->p + 1, p, header->size);#if TAL_DEBUG            header->line_num = -header->line_num;#endif        }    } else {        /* new alloc case */        while (al->p + adj_size > al->bufend) {            al = al->next;            if (!al) {                unsigned new_size = (*pal)->size;                if (adj_size > new_size) {                    new_size = adj_size;                    //fprintf(stderr, "%s:%d: alloc big tal: %u\n", file->filename, file->line_num, adj_size - sizeof(tal_header_t));                }                al = tal_new(pal, new_size);                break;            }        }        al->nb_allocs++;    }    header = (tal_header_t *)al->p;    header->size = adj_size - sizeof(tal_header_t);    al->p += adj_size;    ret = header + 1;#if  TAL_DEBUG    {        int ofs = strlen(sfile) + 1 - sizeof header->file_name;        strcpy(header->file_name, sfile + (ofs > 0 ? ofs : 0));        header->line_num = sline;#if TAL_INFO        if (al->nb_peak < al->nb_allocs)            al->nb_peak = al->nb_allocs;        if (al->peak_p < al->p)            al->peak_p = al->p;        al->nb_total++;#endif    }#endif    return ret;} #endif /* USE_TAL */ /* ------------------------------------------------------------------------- *//* CString handling */static void cstr_realloc(CString *cstr, int new_size){    int size;     size = cstr->size_allocated;    if (size < 8)        size = 8; /* no need to allocate a too small first string */    while (size < new_size)        size = size * 2;    cstr->data = tcc_realloc(cstr->data, size);    cstr->size_allocated = size;} /* add a byte */ST_INLN void cstr_ccat(CString *cstr, int ch){    int size;    size = cstr->size + 1;    if (size > cstr->size_allocated)        cstr_realloc(cstr, size);    cstr->data[size - 1] = ch;    cstr->size = size;} ST_INLN char *unicode_to_utf8 (char *b, uint32_t Uc){    if (Uc<0x80) *b++=Uc;    else if (Uc<0x800) *b++=192+Uc/64, *b++=128+Uc%64;    else if (Uc-0xd800u<0x800) goto error;    else if (Uc<0x10000) *b++=224+Uc/4096, *b++=128+Uc/64%64, *b++=128+Uc%64;    else if (Uc<0x110000) *b++=240+Uc/262144, *b++=128+Uc/4096%64, *b++=128+Uc/64%64, *b++=128+Uc%64;    else error: tcc_error("0x%x is not a valid universal character", Uc);    return b;} /* add a unicode character expanded into utf8 */ST_INLN void cstr_u8cat(CString *cstr, int ch){    char buf[4], *e;    e = unicode_to_utf8(buf, (uint32_t)ch);    cstr_cat(cstr, buf, e - buf);} /* add string of 'len', or of its len/len+1 when 'len' == -1/0 */ST_FUNC void cstr_cat(CString *cstr, const char *str, int len){    int size;    if (len <= 0)        len = strlen(str) + 1 + len;    size = cstr->size + len;    if (size > cstr->size_allocated)        cstr_realloc(cstr, size);    memmove(cstr->data + cstr->size, str, len);    cstr->size = size;} /* add a wide char */ST_FUNC void cstr_wccat(CString *cstr, int ch){    int size;    size = cstr->size + sizeof(nwchar_t);    if (size > cstr->size_allocated)        cstr_realloc(cstr, size);    *(nwchar_t *)(cstr->data + size - sizeof(nwchar_t)) = ch;    cstr->size = size;} ST_FUNC void cstr_new(CString *cstr){    memset(cstr, 0, sizeof(CString));} /* free string and reset it to NULL */ST_FUNC void cstr_free(CString *cstr){    tcc_free(cstr->data);} /* reset string to empty */ST_FUNC void cstr_reset(CString *cstr){    cstr->size = 0;} ST_FUNC int cstr_vprintf(CString *cstr, const char *fmt, va_list ap){    va_list v;    int len, size = 80;    for (;;) {        size += cstr->size;        if (size > cstr->size_allocated)            cstr_realloc(cstr, size);        size = cstr->size_allocated - cstr->size;        va_copy(v, ap);        len = vsnprintf(cstr->data + cstr->size, size, fmt, v);        va_end(v);        if (len >= 0 && len < size)            break;        size *= 2;    }    cstr->size += len;    return len;} ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...){    va_list ap; int len;    va_start(ap, fmt);    len = cstr_vprintf(cstr, fmt, ap);    va_end(ap);    return len;} /* XXX: unicode ? */static void add_char(CString *cstr, int c){    if (c == '\'' || c == '\"' || c == '\\') {        /* XXX: could be more precise if char or string */        cstr_ccat(cstr, '\\');    }    if (c >= 32 && c <= 126) {        cstr_ccat(cstr, c);    } else {        cstr_ccat(cstr, '\\');        if (c == '\n') {            cstr_ccat(cstr, 'n');        } else {            cstr_ccat(cstr, '0' + ((c >> 6) & 7));            cstr_ccat(cstr, '0' + ((c >> 3) & 7));            cstr_ccat(cstr, '0' + (c & 7));        }    }} /* ------------------------------------------------------------------------- *//* allocate a new token */static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len){    TokenSym *ts, **ptable;    int i;     if (tok_ident >= SYM_FIRST_ANOM)         tcc_error("memory full (symbols)");     /* expand token table if needed */    i = tok_ident - TOK_IDENT;    if ((i % TOK_ALLOC_INCR) == 0) {        ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *));        table_ident = ptable;    }     ts = tal_realloc(&toksym_alloc, 0, sizeof(TokenSym) + len);    table_ident[i] = ts;    ts->tok = tok_ident++;    ts->sym_define = NULL;    ts->sym_label = NULL;    ts->sym_struct = NULL;    ts->sym_identifier = NULL;    ts->len = len;    ts->hash_next = NULL;    memcpy(ts->str, str, len);    ts->str[len] = '\0';    *pts = ts;    return ts;} #define TOK_HASH_INIT 1#define TOK_HASH_FUNC(h, c) ((h) + ((h) << 5) + ((h) >> 27) + (c))  /* find a token and add it if not found */ST_FUNC TokenSym *tok_alloc(const char *str, int len){    TokenSym *ts, **pts;

Lines 1–500 of 3961.