4068 lines · 114.3 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" /********************************************************//* global variables */ ST_DATA int tok_flags;ST_DATA int parse_flags; ST_DATA struct BufferedFile *file;ST_DATA int ch, 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; /* ------------------------------------------------------------------------- */ static TokenSym *hash_ident[TOK_HASH_SIZE];static char token_buf[STRING_MAX_SIZE + 1];static CString cstr_buf;static CString macro_equal_buf;static TokenString tokstr_buf;static unsigned char isidnum_table[256 - CH_EOF];static int pp_debug_tok, pp_debug_symv;static int pp_once;static int pp_expr;static int pp_counter;static void tok_print(const char *msg, const int *str); 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}; static void next_nomacro(void); ST_FUNC void skip(int c){    if (tok != c)        tcc_error("'%c' expected (got \"%s\")", c, 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#define tal_free(al, p) tcc_free(p)#define tal_realloc(al, p, size) tcc_realloc(p, size)#define tal_new(a,b,c)#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 1//#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 *file, int line#define TAL_DEBUG_FILE_LEN 40#endif #define TOKSYM_TAL_SIZE     (768 * 1024) /* allocator for tiny TokenSym in table_ident */#define TOKSTR_TAL_SIZE     (768 * 1024) /* allocator for tiny TokenString instances */#define CSTR_TAL_SIZE       (256 * 1024) /* allocator for tiny CString instances */#define TOKSYM_TAL_LIMIT    256 /* prefer unique limits to distinguish allocators debug msgs */#define TOKSTR_TAL_LIMIT    128 /* 32 * sizeof(int) */#define CSTR_TAL_LIMIT      1024 typedef struct TinyAlloc {    unsigned  limit;    unsigned  size;    uint8_t *buffer;    uint8_t *p;    unsigned  nb_allocs;    struct TinyAlloc *next, *top;#ifdef TAL_INFO    unsigned  nb_peak;    unsigned  nb_total;    unsigned  nb_missed;    uint8_t *peak_p;#endif} TinyAlloc; typedef struct tal_header_t {    unsigned  size;#ifdef TAL_DEBUG    int     line_num; /* negative line_num used for double free check */    char    file_name[TAL_DEBUG_FILE_LEN + 1];#endif} tal_header_t; /* ------------------------------------------------------------------------- */ static TinyAlloc *tal_new(TinyAlloc **pal, unsigned limit, unsigned size){    TinyAlloc *al = tcc_mallocz(sizeof(TinyAlloc));    al->p = al->buffer = tcc_malloc(size);    al->limit = limit;    al->size = size;    if (pal) *pal = al;    return al;} static void tal_delete(TinyAlloc *al){    TinyAlloc *next; tail_call:    if (!al)        return;#ifdef TAL_INFO    fprintf(stderr, "limit=%5d, size=%5g MB, nb_peak=%6d, nb_total=%8d, nb_missed=%6d, usage=%5.1f%%\n",            al->limit, al->size / 1024.0 / 1024.0, al->nb_peak, al->nb_total, al->nb_missed,            (al->peak_p - al->buffer) * 100.0 / al->size);#endif#ifdef TAL_DEBUG    if (al->nb_allocs > 0) {        uint8_t *p;        fprintf(stderr, "TAL_DEBUG: memory leak %d chunk(s) (limit= %d)\n",                al->nb_allocs, al->limit);        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, header->size);            }            p += header->size + sizeof(tal_header_t);        }#if MEM_DEBUG-0 == 2        exit(2);#endif    }#endif    next = al->next;    tcc_free(al->buffer);    tcc_free(al);    al = next;    goto tail_call;} static void tal_free_impl(TinyAlloc *al, void *p TAL_DEBUG_PARAMS){    if (!p)        return;tail_call:    if (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size) {#ifdef TAL_DEBUG        tal_header_t *header = (((tal_header_t *)p) - 1);        if (header->line_num < 0) {            fprintf(stderr, "%s:%d: TAL_DEBUG: double frees chunk from\n",                    file, line);            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->nb_allocs--;        if (!al->nb_allocs)            al->p = al->buffer;    } else if (al->next) {        al = al->next;        goto tail_call;    }    else        tcc_free(p);} static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_PARAMS){    tal_header_t *header;    void *ret;    int is_own;    unsigned adj_size = (size + 3) & -4;    TinyAlloc *al = *pal; tail_call:    is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size);    if ((!p || is_own) && size <= al->limit) {        if (al->p - al->buffer + adj_size + sizeof(tal_header_t) < al->size) {            header = (tal_header_t *)al->p;            header->size = adj_size;#ifdef TAL_DEBUG            { int ofs = strlen(file) - TAL_DEBUG_FILE_LEN;            strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), TAL_DEBUG_FILE_LEN);            header->file_name[TAL_DEBUG_FILE_LEN] = 0;            header->line_num = line; }#endif            ret = al->p + sizeof(tal_header_t);            al->p += adj_size + sizeof(tal_header_t);            if (is_own) {                header = (((tal_header_t *)p) - 1);                if (p) memcpy(ret, p, header->size);#ifdef TAL_DEBUG                header->line_num = -header->line_num;#endif            } else {                al->nb_allocs++;            }#ifdef 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            return ret;        } else if (is_own) {            al->nb_allocs--;            ret = tal_realloc(*pal, 0, size);            header = (((tal_header_t *)p) - 1);            if (p) memcpy(ret, p, header->size);#ifdef TAL_DEBUG            header->line_num = -header->line_num;#endif            return ret;        }        if (al->next) {            al = al->next;        } else {            TinyAlloc *bottom = al, *next = al->top ? al->top : al;             al = tal_new(pal, next->limit, next->size * 2);            al->next = next;            bottom->top = al;        }        goto tail_call;    }    if (is_own) {        al->nb_allocs--;        ret = tcc_malloc(size);        header = (((tal_header_t *)p) - 1);        if (p) memcpy(ret, p, header->size);#ifdef TAL_DEBUG        header->line_num = -header->line_num;#endif    } else if (al->next) {        al = al->next;        goto tail_call;    } else        ret = tcc_realloc(p, size);#ifdef TAL_INFO    al->nb_missed++;#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);    ((unsigned char *)cstr->data)[size - 1] = ch;    cstr->size = size;} 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(((unsigned char *)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 *)(((unsigned char *)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);    cstr_new(cstr);} /* reset string to empty */ST_FUNC void cstr_reset(CString *cstr){    cstr->size = 0;} ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...){    va_list v;    int len, size;     va_start(v, fmt);    len = vsnprintf(NULL, 0, fmt, v);    va_end(v);    size = cstr->size + len + 1;    if (size > cstr->size_allocated)        cstr_realloc(cstr, size);    va_start(v, fmt);    vsnprintf((char*)cstr->data + cstr->size, size, fmt, v);    va_end(v);    cstr->size += len;    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;    int i;    unsigned int h;        h = TOK_HASH_INIT;    for(i=0;i<len;i++)        h = TOK_HASH_FUNC(h, ((unsigned char *)str)[i]);    h &= (TOK_HASH_SIZE - 1);     pts = &hash_ident[h];    for(;;) {        ts = *pts;        if (!ts)            break;        if (ts->len == len && !memcmp(ts->str, str, len))            return ts;        pts = &(ts->hash_next);    }    return tok_alloc_new(pts, str, len);} /* XXX: buffer overflow *//* XXX: float tokens */ST_FUNC const char *get_tok_str(int v, CValue *cv){    char *p;    int i, len;     cstr_reset(&cstr_buf);    p = cstr_buf.data;     switch(v) {    case TOK_CINT:    case TOK_CUINT:    case TOK_CLONG:

Lines 1–500 of 4068.