/* * 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. 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" /* #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"); #endif tail_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;