/* * 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. Load more
/* * 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: