diff --git a/shlr/tcc/libtcc.c b/shlr/tcc/libtcc.c index c38adee630..fb472ba552 100644 --- a/shlr/tcc/libtcc.c +++ b/shlr/tcc/libtcc.c @@ -38,17 +38,21 @@ ST_DATA struct TCCState *tcc_state; // GCC appears to use '/' for relative paths and '\\' for absolute paths on Windows static char *normalize_slashes(char *path) { - char *p; - if (path[1] == ':') { - for (p = path+2; *p; ++p) - if (*p == '/') - *p = '\\'; - } else { - for (p = path; *p; ++p) - if (*p == '\\') - *p = '/'; - } - return path; + char *p; + if (path[1] == ':') { + for (p = path + 2; *p; ++p) { + if (*p == '/') { + *p = '\\'; + } + } + } else { + for (p = path; *p; ++p) { + if (*p == '\\') { + *p = '/'; + } + } + } + return path; } #endif @@ -56,58 +60,60 @@ static char *normalize_slashes(char *path) /* copy a string and truncate it. */ PUB_FUNC char *pstrcpy(char *buf, int buf_size, const char *s) { - char *q, *q_end; - int c; + char *q, *q_end; + int c; - if (buf_size > 0) { - q = buf; - q_end = buf + buf_size - 1; - while (q < q_end) { - c = *s++; - if (c == '\0') - break; - *q++ = c; - } - *q = '\0'; - } - return buf; + if (buf_size > 0) { + q = buf; + q_end = buf + buf_size - 1; + while (q < q_end) { + c = *s++; + if (c == '\0') { + break; + } + *q++ = c; + } + *q = '\0'; + } + return buf; } /* strcat and truncate. */ PUB_FUNC char *pstrcat(char *buf, int buf_size, const char *s) { - int len; - len = strlen(buf); - if (len < buf_size) - pstrcpy(buf + len, buf_size - len, s); - return buf; + int len; + len = strlen (buf); + if (len < buf_size) { + pstrcpy (buf + len, buf_size - len, s); + } + return buf; } PUB_FUNC char *pstrncpy(char *out, const char *in, size_t num) { - memcpy(out, in, num); - out[num] = '\0'; - return out; + memcpy (out, in, num); + out[num] = '\0'; + return out; } /* extract the basename of a file */ PUB_FUNC char *tcc_basename(const char *name) { - char *p = strchr(name, 0); - while (p && p > name && !IS_DIRSEP(p[-1])) - --p; - return p; + char *p = strchr (name, 0); + while (p && p > name && !IS_DIRSEP (p[-1])) + --p; + return p; } /* extract extension part of a file * * (if no extension, return pointer to end-of-string) */ -PUB_FUNC char *tcc_fileextension (const char *name) +PUB_FUNC char *tcc_fileextension(const char *name) { - char *b = tcc_basename(name); - char *e = strrchr(b, '.'); - return e ? e : strchr(b, 0); + char *b = tcc_basename (name); + char *e = strrchr (b, '.'); + return e? e: strchr (b, 0); } /********************************************************/ @@ -116,17 +122,17 @@ PUB_FUNC char *tcc_fileextension (const char *name) PUB_FUNC void *tcc_mallocz(unsigned long size) { - void *ptr; - ptr = malloc(size); - memset(ptr, 0, size); - return ptr; + void *ptr; + ptr = malloc (size); + memset (ptr, 0, size); + return ptr; } PUB_FUNC void tcc_memstats(void) { #ifdef MEM_DEBUG - printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size); + printf ("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size); #endif } @@ -135,142 +141,151 @@ PUB_FUNC void tcc_memstats(void) ST_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data) { - int nb, nb_alloc; - void **pp; + int nb, nb_alloc; + void **pp; - nb = *nb_ptr; - pp = *ptab; - /* every power of two we double array size */ - if ((nb & (nb - 1)) == 0) { - if (!nb) - nb_alloc = 1; - else - nb_alloc = nb * 2; - pp = realloc(pp, nb_alloc * sizeof(void *)); - *ptab = pp; - } - pp[nb++] = data; - *nb_ptr = nb; + nb = *nb_ptr; + pp = *ptab; + /* every power of two we double array size */ + if ((nb & (nb - 1)) == 0) { + if (!nb) { + nb_alloc = 1; + } else { + nb_alloc = nb * 2; + } + pp = realloc (pp, nb_alloc * sizeof(void *)); + *ptab = pp; + } + pp[nb++] = data; + *nb_ptr = nb; } ST_FUNC void dynarray_reset(void *pp, int *n) { - void **p; - for (p = *(void***)pp; *n; ++p, --*n) - if (*p) - free(*p); - free(*(void**)pp); - *(void**)pp = NULL; + void **p; + for (p = *(void ***) pp; *n; ++p, --*n) { + if (*p) { + free (*p); + } + } + free (*(void **) pp); + *(void **) pp = NULL; } static void tcc_split_path(TCCState *s, void ***p_ary, int *p_nb_ary, const char *in) { - const char *p; - do { - int c; - CString str; + const char *p; + do { + int c; + CString str; - cstr_new(&str); - for (p = in; c = *p, c != '\0' && c != PATHSEP; ++p) { - if (c == '{' && p[1] && p[2] == '}') { - c = p[1], p += 2; - if (c == 'B') - cstr_cat(&str, s->tcc_lib_path); - } else { - cstr_ccat(&str, c); - } - } - cstr_ccat(&str, '\0'); - dynarray_add(p_ary, p_nb_ary, str.data); - in = p+1; - } while (*p); + cstr_new (&str); + for (p = in; c = *p, c != '\0' && c != PATHSEP; ++p) { + if (c == '{' && p[1] && p[2] == '}') { + c = p[1], p += 2; + if (c == 'B') { + cstr_cat (&str, s->tcc_lib_path); + } + } else { + cstr_ccat (&str, c); + } + } + cstr_ccat (&str, '\0'); + dynarray_add (p_ary, p_nb_ary, str.data); + in = p + 1; + } while (*p); } /********************************************************/ static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap) { - int len; - len = strlen(buf); - vsnprintf(buf + len, buf_size - len, fmt, ap); + int len; + len = strlen (buf); + vsnprintf (buf + len, buf_size - len, fmt, ap); } static void strcat_printf(char *buf, int buf_size, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - strcat_vprintf(buf, buf_size, fmt, ap); - va_end(ap); + va_list ap; + va_start (ap, fmt); + strcat_vprintf (buf, buf_size, fmt, ap); + va_end (ap); } static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap) { - char buf[2048]; - BufferedFile **pf, *f; + char buf[2048]; + BufferedFile **pf, *f; - buf[0] = '\0'; - /* use upper file if inline ":asm:" or token ":paste:" */ - for (f = file; f && f->filename[0] == ':'; f = f->prev) - ; - if (f) { - for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++) - strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", - (*pf)->filename, (*pf)->line_num); - if (f->line_num > 0) { - strcat_printf(buf, sizeof(buf), "%s:%d: ", - f->filename, f->line_num); - } else { - strcat_printf(buf, sizeof(buf), "%s: ", - f->filename); - } - } else { - strcat_printf(buf, sizeof(buf), "tcc: "); - } - if (is_warning) - strcat_printf(buf, sizeof(buf), "warning: "); - else - strcat_printf(buf, sizeof(buf), "error: "); - strcat_vprintf(buf, sizeof(buf), fmt, ap); + buf[0] = '\0'; + /* use upper file if inline ":asm:" or token ":paste:" */ + for (f = file; f && f->filename[0] == ':'; f = f->prev) { + ; + } + if (f) { + for (pf = s1->include_stack; pf < s1->include_stack_ptr; pf++) { + strcat_printf (buf, sizeof(buf), "In file included from %s:%d:\n", + (*pf)->filename, (*pf)->line_num); + } + if (f->line_num > 0) { + strcat_printf (buf, sizeof(buf), "%s:%d: ", + f->filename, f->line_num); + } else { + strcat_printf (buf, sizeof(buf), "%s: ", + f->filename); + } + } else { + strcat_printf (buf, sizeof(buf), "tcc: "); + } + if (is_warning) { + strcat_printf (buf, sizeof(buf), "warning: "); + } else { + strcat_printf (buf, sizeof(buf), "error: "); + } + strcat_vprintf (buf, sizeof(buf), fmt, ap); - if (!s1->error_func) { - /* default case: stderr */ - fprintf(stderr, "%s\n", buf); - } else { - s1->error_func(s1->error_opaque, buf); - } - if (!is_warning || s1->warn_error) - s1->nb_errors++; + if (!s1->error_func) { + /* default case: stderr */ + fprintf (stderr, "%s\n", buf); + } else { + s1->error_func (s1->error_opaque, buf); + } + if (!is_warning || s1->warn_error) { + s1->nb_errors++; + } } LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, - void (*error_func)(void *opaque, const char *msg)) + void (*error_func)(void *opaque, const char *msg)) { - s->error_opaque = error_opaque; - s->error_func = error_func; + s->error_opaque = error_opaque; + s->error_func = error_func; } /* error without aborting current compilation */ PUB_FUNC void tcc_error(const char *fmt, ...) { - TCCState *s1 = tcc_state; - va_list ap; + TCCState *s1 = tcc_state; + va_list ap; - va_start(ap, fmt); - error1(s1, 0, fmt, ap); - va_end(ap); + va_start (ap, fmt); + error1 (s1, 0, fmt, ap); + va_end (ap); } PUB_FUNC void tcc_warning(const char *fmt, ...) { - TCCState *s1 = tcc_state; - va_list ap; + TCCState *s1 = tcc_state; + va_list ap; - if (s1->warn_none) - return; + if (s1->warn_none) { + return; + } - va_start(ap, fmt); - error1(s1, 1, fmt, ap); - va_end(ap); + va_start (ap, fmt); + error1 (s1, 1, fmt, ap); + va_end (ap); } /********************************************************/ @@ -278,75 +293,78 @@ PUB_FUNC void tcc_warning(const char *fmt, ...) ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen) { - BufferedFile *bf; - int buflen = initlen ? initlen : IO_BUF_SIZE; + BufferedFile *bf; + int buflen = initlen? initlen: IO_BUF_SIZE; - bf = malloc(sizeof(BufferedFile) + buflen); - bf->buf_ptr = bf->buffer; - bf->buf_end = bf->buffer + initlen; - bf->buf_end[0] = CH_EOB; /* put eob symbol */ - pstrcpy(bf->filename, sizeof(bf->filename), filename); + bf = malloc (sizeof(BufferedFile) + buflen); + bf->buf_ptr = bf->buffer; + bf->buf_end = bf->buffer + initlen; + bf->buf_end[0] = CH_EOB;/* put eob symbol */ + pstrcpy (bf->filename, sizeof(bf->filename), filename); #ifdef __WINDOWS__ - normalize_slashes(bf->filename); + normalize_slashes (bf->filename); #endif - bf->line_num = 1; - bf->ifndef_macro = 0; - bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; - bf->fd = -1; - bf->prev = file; - file = bf; + bf->line_num = 1; + bf->ifndef_macro = 0; + bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; + bf->fd = -1; + bf->prev = file; + file = bf; } ST_FUNC void tcc_close(void) { - BufferedFile *bf = file; - if (bf->fd > 0) { - close(bf->fd); - total_lines += bf->line_num; - } - file = bf->prev; - free(bf); + BufferedFile *bf = file; + if (bf->fd > 0) { + close (bf->fd); + total_lines += bf->line_num; + } + file = bf->prev; + free (bf); } ST_FUNC int tcc_open(TCCState *s1, const char *filename) { - int fd; - if (strcmp(filename, "-") == 0) - fd = 0, filename = "stdin"; - else - fd = open(filename, O_RDONLY | O_BINARY); - if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3) - printf("%s %*s%s\n", fd < 0 ? "nf":"->", - (int)(s1->include_stack_ptr - s1->include_stack), "", filename); - if (fd < 0) - return -1; + int fd; + if (strcmp (filename, "-") == 0) { + fd = 0, filename = "stdin"; + } else { + fd = open (filename, O_RDONLY | O_BINARY); + } + if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3) { + printf ("%s %*s%s\n", fd < 0? "nf": "->", + (int) (s1->include_stack_ptr - s1->include_stack), "", filename); + } + if (fd < 0) { + return -1; + } - tcc_open_bf(s1, filename, 0); - file->fd = fd; - return fd; + tcc_open_bf (s1, filename, 0); + file->fd = fd; + return fd; } /* compile the C file opened in 'file'. Return non zero if errors. */ static int tcc_compile(TCCState *s1) { - Sym *define_start; + Sym *define_start; #ifdef INC_DEBUG - printf("%s: **** new file\n", file->filename); + printf ("%s: **** new file\n", file->filename); #endif - preprocess_init(s1); + preprocess_init (s1); - funcname = ""; - anon_sym = SYM_FIRST_ANOM; + funcname = ""; + anon_sym = SYM_FIRST_ANOM; /* define some often used types */ int8_type.t = VT_INT8; int16_type.t = VT_INT16; - int32_type.t = VT_INT32; + int32_type.t = VT_INT32; int64_type.t = VT_INT64; - char_pointer_type.t = VT_INT8; - mk_pointer(&char_pointer_type); + char_pointer_type.t = VT_INT8; + mk_pointer (&char_pointer_type); if (tcc_state->bits != 64) { size_type.t = VT_INT32; @@ -354,394 +372,408 @@ static int tcc_compile(TCCState *s1) size_type.t = VT_INT64; } - func_old_type.t = VT_FUNC; - func_old_type.ref = sym_push(SYM_FIELD, &int32_type, FUNC_CDECL, FUNC_OLD); + func_old_type.t = VT_FUNC; + func_old_type.ref = sym_push (SYM_FIELD, &int32_type, FUNC_CDECL, FUNC_OLD); // FIXME: Should depend on the target options too #ifdef TCC_TARGET_ARM - arm_init_types(); + arm_init_types (); #endif #if 0 - /* define 'void *alloca(unsigned int)' builtin function */ - { - Sym *s1; + /* define 'void *alloca(unsigned int)' builtin function */ + { + Sym *s1; - p = anon_sym++; - sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW); - s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0); - s1->next = NULL; - sym->next = s1; - sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0); - } + p = anon_sym++; + sym = sym_push (p, mk_pointer (VT_VOID), FUNC_CDECL, FUNC_NEW); + s1 = sym_push (SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0); + s1->next = NULL; + sym->next = s1; + sym_push (TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0); + } #endif - define_start = define_stack; - nocode_wanted = 1; + define_start = define_stack; + nocode_wanted = 1; - if (setjmp(s1->error_jmp_buf) == 0) { - s1->nb_errors = 0; - s1->error_set_jmp_enabled = 1; + if (setjmp (s1->error_jmp_buf) == 0) { + s1->nb_errors = 0; + s1->error_set_jmp_enabled = 1; - ch = file->buf_ptr[0]; - tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; - parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM; - //pvtop = vtop; - next(); - decl(VT_CONST); - if (tok != TOK_EOF) - expect("declaration"); + ch = file->buf_ptr[0]; + tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; + parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM; + // pvtop = vtop; + next (); + decl (VT_CONST); + if (tok != TOK_EOF) { + expect ("declaration"); + } #if 0 - if (pvtop != vtop) - fprintf (stderr, "internal compiler error:" - " vstack leak? (%d)", vtop - pvtop); + if (pvtop != vtop) { + fprintf (stderr, "internal compiler error:" + " vstack leak? (%d)", vtop - pvtop); + } #endif - } + } - s1->error_set_jmp_enabled = 0; + s1->error_set_jmp_enabled = 0; - /* reset define stack, but leave -Dsymbols (may be incorrect if - they are undefined) */ - free_defines(define_start); + /* reset define stack, but leave -Dsymbols (may be incorrect if + they are undefined) */ + free_defines (define_start); - sym_pop(&global_stack, NULL); - sym_pop(&local_stack, NULL); + sym_pop (&global_stack, NULL); + sym_pop (&local_stack, NULL); - return s1->nb_errors != 0 ? -1 : 0; + return s1->nb_errors != 0? -1: 0; } LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str) { - int len, ret; - len = strlen(str); + int len, ret; + len = strlen (str); - tcc_open_bf(s, "", len); - memcpy(file->buffer, str, len); - ret = tcc_compile(s); - tcc_close(); - return ret; + tcc_open_bf (s, "", len); + memcpy (file->buffer, str, len); + ret = tcc_compile (s); + tcc_close (); + return ret; } /* define a preprocessor symbol. A value can also be provided with the '=' operator */ LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *value) { - int len1, len2; - /* default value */ - if (!value) - value = "1"; - len1 = strlen(sym); - len2 = strlen(value); + int len1, len2; + /* default value */ + if (!value) { + value = "1"; + } + len1 = strlen (sym); + len2 = strlen (value); - /* init file structure */ - tcc_open_bf(s1, "", len1 + len2 + 1); - memcpy(file->buffer, sym, len1); - file->buffer[len1] = ' '; - memcpy(file->buffer + len1 + 1, value, len2); + /* init file structure */ + tcc_open_bf (s1, "", len1 + len2 + 1); + memcpy (file->buffer, sym, len1); + file->buffer[len1] = ' '; + memcpy (file->buffer + len1 + 1, value, len2); - /* parse with define parser */ - ch = file->buf_ptr[0]; - next_nomacro(); - parse_define(); + /* parse with define parser */ + ch = file->buf_ptr[0]; + next_nomacro (); + parse_define (); - tcc_close(); + tcc_close (); } /* undefine a preprocessor symbol */ LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym) { - TokenSym *ts; - Sym *s; - ts = tok_alloc(sym, strlen(sym)); - s = define_find(ts->tok); - /* undefine symbol by putting an invalid name */ - if (s) - define_undef(s); + TokenSym *ts; + Sym *s; + ts = tok_alloc (sym, strlen (sym)); + s = define_find (ts->tok); + /* undefine symbol by putting an invalid name */ + if (s) { + define_undef (s); + } } /* cleanup all static data used during compilation */ static void tcc_cleanup(void) { - int i, n; - if (NULL == tcc_state) - return; - tcc_state = NULL; + int i, n; + if (NULL == tcc_state) { + return; + } + tcc_state = NULL; - /* free -D defines */ - free_defines(NULL); + /* free -D defines */ + free_defines (NULL); - /* free tokens */ - n = tok_ident - TOK_IDENT; - for(i = 0; i < n; i++) - free(table_ident[i]); - free(table_ident); + /* free tokens */ + n = tok_ident - TOK_IDENT; + for (i = 0; i < n; i++) { + free (table_ident[i]); + } + free (table_ident); - /* free sym_pools */ - dynarray_reset(&sym_pools, &nb_sym_pools); - /* string buffer */ - cstr_free(&tokcstr); - /* reset symbol stack */ - sym_free_first = NULL; - /* cleanup from error/setjmp */ - macro_ptr = NULL; + /* free sym_pools */ + dynarray_reset (&sym_pools, &nb_sym_pools); + /* string buffer */ + cstr_free (&tokcstr); + /* reset symbol stack */ + sym_free_first = NULL; + /* cleanup from error/setjmp */ + macro_ptr = NULL; } -LIBTCCAPI TCCState *tcc_new(const char* arch, int bits, const char *os) +LIBTCCAPI TCCState *tcc_new(const char *arch, int bits, const char *os) { - TCCState *s; - char buffer[100]; - int a,b,c; + TCCState *s; + char buffer[100]; + int a, b, c; - if (!arch || !os) return NULL; - tcc_cleanup(); - s = tcc_mallocz(sizeof(TCCState)); - if (!s) { + if (!arch || !os) { return NULL; } - tcc_state = s; - s->arch = strdup(arch); + tcc_cleanup (); + s = tcc_mallocz (sizeof(TCCState)); + if (!s) { + return NULL; + } + tcc_state = s; + s->arch = strdup (arch); s->bits = bits; - s->os = strdup(os); - s->output_type = TCC_OUTPUT_MEMORY; - preprocess_new(); - s->include_stack_ptr = s->include_stack; + s->os = strdup (os); + s->output_type = TCC_OUTPUT_MEMORY; + preprocess_new (); + s->include_stack_ptr = s->include_stack; - /* we add dummy defines for some special macros to speed up tests - and to have working defined() */ - define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL); - define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL); - define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL); - define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL); + /* we add dummy defines for some special macros to speed up tests + and to have working defined() */ + define_push (TOK___LINE__, MACRO_OBJ, NULL, NULL); + define_push (TOK___FILE__, MACRO_OBJ, NULL, NULL); + define_push (TOK___DATE__, MACRO_OBJ, NULL, NULL); + define_push (TOK___TIME__, MACRO_OBJ, NULL, NULL); - /* define __TINYC__ 92X */ - sscanf(TCC_VERSION, "%d.%d.%d", &a, &b, &c); - sprintf(buffer, "%d", a*10000 + b*100 + c); - tcc_define_symbol(s, "__TINYC__", buffer); + /* define __TINYC__ 92X */ + sscanf (TCC_VERSION, "%d.%d.%d", &a, &b, &c); + sprintf (buffer, "%d", a * 10000 + b * 100 + c); + tcc_define_symbol (s, "__TINYC__", buffer); - /* standard defines */ - tcc_define_symbol(s, "__STDC__", NULL); - tcc_define_symbol(s, "__STDC_VERSION__", "199901L"); - tcc_define_symbol(s, "__STDC_HOSTED__", NULL); + /* standard defines */ + tcc_define_symbol (s, "__STDC__", NULL); + tcc_define_symbol (s, "__STDC_VERSION__", "199901L"); + tcc_define_symbol (s, "__STDC_HOSTED__", NULL); - /* target defines */ - if (!strncmp(arch, "x86", 3)) { + /* target defines */ + if (!strncmp (arch, "x86", 3)) { if (bits == 32 || bits == 16) { - tcc_define_symbol(s, "__i386__", NULL); - tcc_define_symbol(s, "__i386", NULL); - tcc_define_symbol(s, "i386", NULL); + tcc_define_symbol (s, "__i386__", NULL); + tcc_define_symbol (s, "__i386", NULL); + tcc_define_symbol (s, "i386", NULL); } else { - tcc_define_symbol(s, "__x86_64__", NULL); + tcc_define_symbol (s, "__x86_64__", NULL); } - } else if (!strncmp(arch, "arm", 3)) { - tcc_define_symbol(s, "__ARM_ARCH_4__", NULL); - tcc_define_symbol(s, "__arm_elf__", NULL); - tcc_define_symbol(s, "__arm_elf", NULL); - tcc_define_symbol(s, "arm_elf", NULL); - tcc_define_symbol(s, "__arm__", NULL); - tcc_define_symbol(s, "__arm", NULL); - tcc_define_symbol(s, "arm", NULL); - tcc_define_symbol(s, "__APCS_32__", NULL); + } else if (!strncmp (arch, "arm", 3)) { + tcc_define_symbol (s, "__ARM_ARCH_4__", NULL); + tcc_define_symbol (s, "__arm_elf__", NULL); + tcc_define_symbol (s, "__arm_elf", NULL); + tcc_define_symbol (s, "arm_elf", NULL); + tcc_define_symbol (s, "__arm__", NULL); + tcc_define_symbol (s, "__arm", NULL); + tcc_define_symbol (s, "arm", NULL); + tcc_define_symbol (s, "__APCS_32__", NULL); } // TODO: Add other architectures // TODO: Move that in SDB - if (!strncmp(os, "windows", 7)) { - tcc_define_symbol(s, "__WINDOWS__", NULL); + if (!strncmp (os, "windows", 7)) { + tcc_define_symbol (s, "__WINDOWS__", NULL); if (bits == 64) { - tcc_define_symbol(s, "_WIN64", NULL); + tcc_define_symbol (s, "_WIN64", NULL); } } else { - tcc_define_symbol(s, "__unix__", NULL); - tcc_define_symbol(s, "__unix", NULL); - tcc_define_symbol(s, "unix", NULL); + tcc_define_symbol (s, "__unix__", NULL); + tcc_define_symbol (s, "__unix", NULL); + tcc_define_symbol (s, "unix", NULL); - if (!strncmp(os, "linux", 5)) { - tcc_define_symbol(s, "__linux__", NULL); - tcc_define_symbol(s, "__linux", NULL); + if (!strncmp (os, "linux", 5)) { + tcc_define_symbol (s, "__linux__", NULL); + tcc_define_symbol (s, "__linux", NULL); } #define str(s) #s - if (!strncmp(os, "freebsd", 7)) { - tcc_define_symbol(s, "__FreeBSD__", str( __FreeBSD__)); + if (!strncmp (os, "freebsd", 7)) { + tcc_define_symbol (s, "__FreeBSD__", str ( __FreeBSD__)); } #undef str } - /* TinyCC & gcc defines */ - if (!strncmp(os, "windows", 7) && (bits == 64)) { - tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long"); - tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long"); + /* TinyCC & gcc defines */ + if (!strncmp (os, "windows", 7) && (bits == 64)) { + tcc_define_symbol (s, "__SIZE_TYPE__", "unsigned long long"); + tcc_define_symbol (s, "__PTRDIFF_TYPE__", "long long"); } else { - tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long"); - tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long"); + tcc_define_symbol (s, "__SIZE_TYPE__", "unsigned long"); + tcc_define_symbol (s, "__PTRDIFF_TYPE__", "long"); } - if (!strncmp(os, "windows", 7)) { - tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short"); + if (!strncmp (os, "windows", 7)) { + tcc_define_symbol (s, "__WCHAR_TYPE__", "unsigned short"); } else { - tcc_define_symbol(s, "__WCHAR_TYPE__", "int"); + tcc_define_symbol (s, "__WCHAR_TYPE__", "int"); /* glibc defines */ - tcc_define_symbol(s, "__REDIRECT(name, proto, alias)", "name proto __asm__ (#alias)"); - tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)", "name proto __asm__ (#alias) __THROW"); + tcc_define_symbol (s, "__REDIRECT(name, proto, alias)", "name proto __asm__(#alias)"); + tcc_define_symbol (s, "__REDIRECT_NTH(name, proto, alias)", "name proto __asm__(#alias) __THROW"); } - s->alacarte_link = 1; - s->nocommon = 1; + s->alacarte_link = 1; + s->nocommon = 1; #ifdef CHAR_IS_UNSIGNED - s->char_is_unsigned = 1; + s->char_is_unsigned = 1; #endif - /* enable this if you want symbols with leading underscore on windows: */ -#if 0 /* def TCC_TARGET_PE */ - s->leading_underscore = 1; + /* enable this if you want symbols with leading underscore on windows: */ +#if 0 /* def TCC_TARGET_PE */ + s->leading_underscore = 1; #endif - if (!strncmp(arch, "x86", 3)) { + if (!strncmp (arch, "x86", 3)) { // TODO: Set it to 16 for 16bit x86 if (bits == 32 || bits == 16) { s->seg_size = 32; } } - return s; + return s; } LIBTCCAPI void tcc_delete(TCCState *s1) { - tcc_cleanup(); + tcc_cleanup (); - /* free library paths */ - dynarray_reset(&s1->library_paths, &s1->nb_library_paths); - dynarray_reset(&s1->crt_paths, &s1->nb_crt_paths); + /* free library paths */ + dynarray_reset (&s1->library_paths, &s1->nb_library_paths); + dynarray_reset (&s1->crt_paths, &s1->nb_crt_paths); - /* free include paths */ - dynarray_reset(&s1->cached_includes, &s1->nb_cached_includes); - dynarray_reset(&s1->include_paths, &s1->nb_include_paths); - dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths); + /* free include paths */ + dynarray_reset (&s1->cached_includes, &s1->nb_cached_includes); + dynarray_reset (&s1->include_paths, &s1->nb_include_paths); + dynarray_reset (&s1->sysinclude_paths, &s1->nb_sysinclude_paths); - free(s1->tcc_lib_path); - free(s1->soname); - free(s1->rpath); - free(s1->init_symbol); - free(s1->fini_symbol); - free(s1->outfile); - free(s1->deps_outfile); - dynarray_reset(&s1->files, &s1->nb_files); - dynarray_reset(&s1->target_deps, &s1->nb_target_deps); + free (s1->tcc_lib_path); + free (s1->soname); + free (s1->rpath); + free (s1->init_symbol); + free (s1->fini_symbol); + free (s1->outfile); + free (s1->deps_outfile); + dynarray_reset (&s1->files, &s1->nb_files); + dynarray_reset (&s1->target_deps, &s1->nb_target_deps); /* target config */ - free(s1->arch); - free(s1->os); + free (s1->arch); + free (s1->os); #ifdef TCC_IS_NATIVE -# ifdef HAVE_SELINUX - munmap (s1->write_mem, s1->mem_size); - munmap (s1->runtime_mem, s1->mem_size); -# else - free(s1->runtime_mem); -# endif +#ifdef HAVE_SELINUX + munmap (s1->write_mem, s1->mem_size); + munmap (s1->runtime_mem, s1->mem_size); +#else + free (s1->runtime_mem); +#endif #endif - free(s1); + free (s1); } LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname) { - tcc_split_path(s, (void ***)&s->include_paths, &s->nb_include_paths, pathname); - return 0; + tcc_split_path (s, (void ***) &s->include_paths, &s->nb_include_paths, pathname); + return 0; } LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname) { - tcc_split_path(s, (void ***)&s->sysinclude_paths, &s->nb_sysinclude_paths, pathname); - return 0; + tcc_split_path (s, (void ***) &s->sysinclude_paths, &s->nb_sysinclude_paths, pathname); + return 0; } ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) { - const char *ext; - int ret; + const char *ext; + int ret; - /* find source file type with extension */ - ext = tcc_fileextension(filename); - if (ext[0]) - ext++; + /* find source file type with extension */ + ext = tcc_fileextension (filename); + if (ext[0]) { + ext++; + } - /* open the file */ - ret = tcc_open(s1, filename); - if (ret < 0) { - if (flags & AFF_PRINT_ERROR) - tcc_error("file '%s' not found", filename); - return ret; - } + /* open the file */ + ret = tcc_open (s1, filename); + if (ret < 0) { + if (flags & AFF_PRINT_ERROR) { + tcc_error ("file '%s' not found", filename); + } + return ret; + } - /* update target deps */ - dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps, - strdup(filename)); + /* update target deps */ + dynarray_add ((void ***) &s1->target_deps, &s1->nb_target_deps, + strdup (filename)); - if (flags & AFF_PREPROCESS) { - ret = tcc_preprocess(s1); - goto the_end; - } + if (flags & AFF_PREPROCESS) { + ret = tcc_preprocess (s1); + goto the_end; + } - if (!ext[0] || !PATHCMP(ext, "c") || !PATHCMP(ext, "h") || !PATHCMP(ext, "cparse")) { - /* C file assumed */ - ret = tcc_compile(s1); - goto the_end; - } - if (ret < 0) - tcc_error("unrecognized file type"); + if (!ext[0] || !PATHCMP (ext, "c") || !PATHCMP (ext, "h") || !PATHCMP (ext, "cparse")) { + /* C file assumed */ + ret = tcc_compile (s1); + goto the_end; + } + if (ret < 0) { + tcc_error ("unrecognized file type"); + } the_end: - tcc_close(); - return ret; + tcc_close (); + return ret; } LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename) { - if (s->output_type == TCC_OUTPUT_PREPROCESS) - return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS); - else - return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR); + if (s->output_type == TCC_OUTPUT_PREPROCESS) { + return tcc_add_file_internal (s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS); + } else { + return tcc_add_file_internal (s, filename, AFF_PRINT_ERROR); + } } -#define WD_ALL 0x0001 /* warning is activated when using -Wall */ -#define FD_INVERT 0x0002 /* invert value before storing */ +#define WD_ALL 0x0001/* warning is activated when using -Wall */ +#define FD_INVERT 0x0002/* invert value before storing */ typedef struct FlagDef { - uint16_t offset; - uint16_t flags; - const char *name; + uint16_t offset; + uint16_t flags; + const char *name; } FlagDef; ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, int nb_flags, - const char *name, int value) + const char *name, int value) { - int i; - const FlagDef *p; - const char *r; + int i; + const FlagDef *p; + const char *r; - r = name; - if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') { - r += 3; - value = !value; - } - for(i = 0, p = flags; i < nb_flags; i++, p++) { - if (!strcmp(r, p->name)) - goto found; - } - return -1; - found: - if (p->flags & FD_INVERT) - value = !value; - *(int *)((uint8_t *)s + p->offset) = value; - return 0; + r = name; + if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') { + r += 3; + value = !value; + } + for (i = 0, p = flags; i < nb_flags; i++, p++) { + if (!strcmp (r, p->name)) { + goto found; + } + } + return -1; +found: + if (p->flags & FD_INVERT) { + value = !value; + } + *(int *) ((uint8_t *) s + p->offset) = value; + return 0; } void (*tcc_cb)(const char *, char **); -PUB_FUNC void tcc_set_callback (TCCState *s, void (*cb)(const char *,char**), char **p) { +PUB_FUNC void tcc_set_callback(TCCState *s, void (*cb)(const char *, char **), char **p) { tcc_cb = cb; tcc_cb_ptr = p; } -PUB_FUNC void tcc_appendf (const char *fmt, ...) { +PUB_FUNC void tcc_appendf(const char *fmt, ...) { char b[1024]; va_list ap; va_start (ap, fmt); diff --git a/shlr/tcc/tccgen.c b/shlr/tcc/tccgen.c index a0569548cc..acc7f0af33 100644 --- a/shlr/tcc/tccgen.c +++ b/shlr/tcc/tccgen.c @@ -47,19 +47,19 @@ ST_DATA Sym *define_stack; ST_DATA Sym *global_label_stack; ST_DATA Sym *local_label_stack; -ST_DATA int vla_sp_loc_tmp; /* vla_sp_loc is set to this when the value won't be needed later */ -ST_DATA int vla_sp_root_loc; /* vla_sp_loc for SP before any VLAs were pushed */ -ST_DATA int *vla_sp_loc; /* Pointer to variable holding location to store stack pointer on the stack when modifying stack pointer */ -ST_DATA int vla_flags; /* VLA_* flags */ +ST_DATA int vla_sp_loc_tmp; /* vla_sp_loc is set to this when the value won't be needed later */ +ST_DATA int vla_sp_root_loc; /* vla_sp_loc for SP before any VLAs were pushed */ +ST_DATA int *vla_sp_loc;/* Pointer to variable holding location to store stack pointer on the stack when modifying stack pointer */ +ST_DATA int vla_flags; /* VLA_* flags */ -ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop; +ST_DATA SValue __vstack[1 + VSTACK_SIZE], *vtop; -ST_DATA int const_wanted; /* true if constant wanted */ -ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */ -ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ -ST_DATA CType func_vt; /* current function return type (used by return instruction) */ +ST_DATA int const_wanted; /* true if constant wanted */ +ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */ +ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ +ST_DATA CType func_vt; /* current function return type (used by return instruction) */ ST_DATA int func_vc; -ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ +ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ ST_DATA char *funcname; ST_DATA CType char_pointer_type, func_old_type; @@ -81,9 +81,9 @@ static void expr_type(CType *type); ST_INLN int is_float(int t) { - int bt; - bt = t & VT_BTYPE; - return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT || bt == VT_QFLOAT; + int bt; + bt = t & VT_BTYPE; + return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT || bt == VT_QFLOAT; } /* we use our own 'finite' function to avoid potential problems with @@ -91,294 +91,310 @@ ST_INLN int is_float(int t) /* XXX: endianness dependent */ ST_FUNC int ieee_finite(double d) { - int *p = (int *)&d; - return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; + int *p = (int *) &d; + return ((unsigned) ((p[1] | 0x800fffff) + 1)) >> 31; } ST_FUNC void test_lvalue(void) { - if (!(vtop->r & VT_LVAL)) - expect("lvalue"); + if (!(vtop->r & VT_LVAL)) { + expect ("lvalue"); + } } /* ------------------------------------------------------------------------- */ /* symbol allocator */ static Sym *__sym_malloc(void) { - Sym *sym_pool, *sym, *last_sym; - int i; + Sym *sym_pool, *sym, *last_sym; + int i; int sym_pool_size = SYM_POOL_NB * sizeof(Sym); - sym_pool = malloc(sym_pool_size); - memset(sym_pool, 0, sym_pool_size); - dynarray_add(&sym_pools, &nb_sym_pools, sym_pool); + sym_pool = malloc (sym_pool_size); + memset (sym_pool, 0, sym_pool_size); + dynarray_add (&sym_pools, &nb_sym_pools, sym_pool); - last_sym = sym_free_first; - sym = sym_pool; - for(i = 0; i < SYM_POOL_NB; i++) { - sym->next = last_sym; - last_sym = sym; - sym++; - } - sym_free_first = last_sym; - return last_sym; + last_sym = sym_free_first; + sym = sym_pool; + for (i = 0; i < SYM_POOL_NB; i++) { + sym->next = last_sym; + last_sym = sym; + sym++; + } + sym_free_first = last_sym; + return last_sym; } static inline Sym *sym_malloc(void) { - Sym *sym; - sym = sym_free_first; - if (!sym) - sym = __sym_malloc(); - sym_free_first = sym->next; - return sym; + Sym *sym; + sym = sym_free_first; + if (!sym) { + sym = __sym_malloc (); + } + sym_free_first = sym->next; + return sym; } ST_INLN void sym_free(Sym *sym) { - sym->next = sym_free_first; - free(sym->asm_label); - sym_free_first = sym; + sym->next = sym_free_first; + free (sym->asm_label); + sym_free_first = sym; } /* push, without hashing */ ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long long c) { - Sym *s; - if (ps == &local_stack) { - for (s = *ps; s && s != scope_stack_bottom; s = s->prev) - if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM && s->v == v) - tcc_error("incompatible types for redefinition of '%s'", - get_tok_str(v, NULL)); - } + Sym *s; + if (ps == &local_stack) { + for (s = *ps; s && s != scope_stack_bottom; s = s->prev) { + if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM && s->v == v) { + tcc_error ("incompatible types for redefinition of '%s'", + get_tok_str (v, NULL)); + } + } + } // printf (" %d %ld set symbol '%s'\n", t, c, get_tok_str(v, NULL)); - // s = *ps; - s = sym_malloc (); - s->asm_label = NULL; - s->v = v; - s->type.t = t; - s->type.ref = NULL; + // s = *ps; + s = sym_malloc (); + s->asm_label = NULL; + s->v = v; + s->type.t = t; + s->type.ref = NULL; #ifdef _WIN64 - s->d = NULL; + s->d = NULL; #endif - s->c = c; - s->next = NULL; - /* add in stack */ - s->prev = *ps; - *ps = s; - return s; + s->c = c; + s->next = NULL; + /* add in stack */ + s->prev = *ps; + *ps = s; + return s; } /* find a symbol and return its associated structure. 's' is the top of the symbol stack */ ST_FUNC Sym *sym_find2(Sym *s, int v) { - while (s) { - if (s->v == v) - return s; - s = s->prev; - } - return NULL; + while (s) { + if (s->v == v) { + return s; + } + s = s->prev; + } + return NULL; } /* structure lookup */ ST_INLN Sym *struct_find(int v) { - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_struct; + v -= TOK_IDENT; + if ((unsigned) v >= (unsigned) (tok_ident - TOK_IDENT)) { + return NULL; + } + return table_ident[v]->sym_struct; } /* find an identifier */ ST_INLN Sym *sym_find(int v) { - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_identifier; + v -= TOK_IDENT; + if ((unsigned) v >= (unsigned) (tok_ident - TOK_IDENT)) { + return NULL; + } + return table_ident[v]->sym_identifier; } // TODO: Add better way to store the meta information // about the pushed type -int tcc_sym_push(char* typename, int typesize, int meta) +int tcc_sym_push(char *typename, int typesize, int meta) { - CType *new_type = (CType*)malloc (sizeof(CType)); + CType *new_type = (CType *) malloc (sizeof(CType)); if (!new_type) { return 0; } - new_type->ref = sym_malloc(); + new_type->ref = sym_malloc (); new_type->t = meta; - sym_push(0, new_type, 0, 0); + sym_push (0, new_type, 0, 0); free (new_type); return 1; } void dump_type(CType *type, int depth) { - if (depth <= 0) return; - eprintf("------------------------\n"); + if (depth <= 0) { + return; + } + eprintf ("------------------------\n"); int bt = type->t & VT_BTYPE; - eprintf("BTYPE = %d ", bt); + eprintf ("BTYPE = %d ", bt); switch (bt) { - case VT_STRUCT: eprintf("[STRUCT]\n"); - break; - case VT_PTR: eprintf("[PTR]\n"); - break; - case VT_ENUM: eprintf("[ENUM]\n"); - break; - case VT_INT64: eprintf("[INT64_T]\n"); - break; - case VT_INT32: eprintf("[INT32_T]\n"); - break; - case VT_INT16: eprintf("[INT16_T]\n"); - break; - case VT_INT8: eprintf("[INT8_T]\n"); - break; - default: - eprintf("\n"); - break; + case VT_STRUCT: eprintf ("[STRUCT]\n"); + break; + case VT_PTR: eprintf ("[PTR]\n"); + break; + case VT_ENUM: eprintf ("[ENUM]\n"); + break; + case VT_INT64: eprintf ("[INT64_T]\n"); + break; + case VT_INT32: eprintf ("[INT32_T]\n"); + break; + case VT_INT16: eprintf ("[INT16_T]\n"); + break; + case VT_INT8: eprintf ("[INT8_T]\n"); + break; + default: + eprintf ("\n"); + break; } if (type->ref) { - eprintf("v = %d\n", type->ref->v); + eprintf ("v = %d\n", type->ref->v); char *varstr = NULL; - varstr = get_tok_str(type->ref->v, NULL); + varstr = get_tok_str (type->ref->v, NULL); if (varstr) { - eprintf("var = %s\n", varstr); + eprintf ("var = %s\n", varstr); } if (type->ref->asm_label) { - eprintf("asm_label = %s\n", type->ref->asm_label); + eprintf ("asm_label = %s\n", type->ref->asm_label); } - eprintf("r = %d\n", type->ref->r); - eprintf("associated type:\n"); - //dump_type(&(type->ref->type), --depth); + eprintf ("r = %d\n", type->ref->r); + eprintf ("associated type:\n"); + // dump_type(&(type->ref->type), --depth); } } /* push a given symbol on the symbol stack */ ST_FUNC Sym *sym_push(int v, CType *type, int r, long long c) { - Sym *s, **ps; - TokenSym *ts; + Sym *s, **ps; + TokenSym *ts; - if (local_stack) - ps = &local_stack; - else - ps = &global_stack; - //dump_type(type, 5); - s = sym_push2(ps, v, type->t, c); - s->type.ref = type->ref; - s->r = r; - /* don't record fields or anonymous symbols */ - /* XXX: simplify */ - if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { - /* record symbol in token array */ - ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; - if (v & SYM_STRUCT) - ps = &ts->sym_struct; - else - ps = &ts->sym_identifier; - s->prev_tok = *ps; - *ps = s; - } - return s; + if (local_stack) { + ps = &local_stack; + } else { + ps = &global_stack; + } + // dump_type(type, 5); + s = sym_push2 (ps, v, type->t, c); + s->type.ref = type->ref; + s->r = r; + /* don't record fields or anonymous symbols */ + /* XXX: simplify */ + if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { + /* record symbol in token array */ + ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; + if (v & SYM_STRUCT) { + ps = &ts->sym_struct; + } else { + ps = &ts->sym_identifier; + } + s->prev_tok = *ps; + *ps = s; + } + return s; } /* push a global identifier */ ST_FUNC Sym *global_identifier_push(int v, int t, long long c) { - Sym *s, **ps; - s = sym_push2(&global_stack, v, t, c); - /* don't record anonymous symbol */ - if (v < SYM_FIRST_ANOM) { - ps = &table_ident[v - TOK_IDENT]->sym_identifier; - /* modify the top most local identifier, so that - sym_identifier will point to 's' when popped */ - while (*ps != NULL) - ps = &(*ps)->prev_tok; - s->prev_tok = NULL; - *ps = s; - } - return s; + Sym *s, **ps; + s = sym_push2 (&global_stack, v, t, c); + /* don't record anonymous symbol */ + if (v < SYM_FIRST_ANOM) { + ps = &table_ident[v - TOK_IDENT]->sym_identifier; + /* modify the top most local identifier, so that + sym_identifier will point to 's' when popped */ + while (*ps != NULL) + ps = &(*ps)->prev_tok; + s->prev_tok = NULL; + *ps = s; + } + return s; } /* pop symbols until top reaches 'b' */ ST_FUNC void sym_pop(Sym **ptop, Sym *b) { - Sym *s, *ss, **ps; - TokenSym *ts; - int v; + Sym *s, *ss, **ps; + TokenSym *ts; + int v; - s = *ptop; - while(s != b) { - ss = s->prev; - v = s->v; - /* remove symbol in token array */ - /* XXX: simplify */ - if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { - ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; - if (v & SYM_STRUCT) - ps = &ts->sym_struct; - else - ps = &ts->sym_identifier; - *ps = s->prev_tok; - } - sym_free(s); - s = ss; - } - *ptop = b; + s = *ptop; + while (s != b) { + ss = s->prev; + v = s->v; + /* remove symbol in token array */ + /* XXX: simplify */ + if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { + ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; + if (v & SYM_STRUCT) { + ps = &ts->sym_struct; + } else { + ps = &ts->sym_identifier; + } + *ps = s->prev_tok; + } + sym_free (s); + s = ss; + } + *ptop = b; } static void weaken_symbol(Sym *sym) { - sym->type.t |= VT_WEAK; + sym->type.t |= VT_WEAK; } /* ------------------------------------------------------------------------- */ ST_FUNC void swap(int *p, int *q) { - int t; - t = *p; - *p = *q; - *q = t; + int t; + t = *p; + *p = *q; + *q = t; } static void vsetc(CType *type, int r, CValue *vc) { - if (vtop >= vstack + (VSTACK_SIZE - 1)) - tcc_error("memory full"); - vtop++; - vtop->type = *type; - vtop->r = r; - vtop->r2 = VT_CONST; - vtop->c = *vc; + if (vtop >= vstack + (VSTACK_SIZE - 1)) { + tcc_error ("memory full"); + } + vtop++; + vtop->type = *type; + vtop->r = r; + vtop->r2 = VT_CONST; + vtop->c = *vc; } /* push constant of type "type" with useless value */ void vpush(CType *type) { - CValue cval; - vsetc(type, VT_CONST, &cval); + CValue cval; + vsetc (type, VT_CONST, &cval); } /* push integer constant */ ST_FUNC void vpushi(int v) { - CValue cval = {0}; - cval.i = v; - vsetc(&int32_type, VT_CONST, &cval); + CValue cval = { + 0 + }; + cval.i = v; + vsetc (&int32_type, VT_CONST, &cval); } /* push a pointer sized constant */ static void vpushs(long long v) { CValue cval; - if (PTR_SIZE == 4) - cval.i = (int)v; - else + if (PTR_SIZE == 4) { + cval.i = (int) v; + } else { cval.ull = v; - vsetc(&size_type, VT_CONST, &cval); + } + vsetc (&size_type, VT_CONST, &cval); } /* push arbitrary 64 bit constant */ @@ -389,7 +405,7 @@ void vpush64(int ty, unsigned long long v) ctype.t = ty; ctype.ref = NULL; cval.ull = v; - vsetc(&ctype, VT_CONST, &cval); + vsetc (&ctype, VT_CONST, &cval); } /* push long long constant */ @@ -397,34 +413,34 @@ ST_FUNC void vpushll(long long v) { CValue cval; cval.ll = v; - vsetc(&int64_type, VT_CONST, &cval); + vsetc (&int64_type, VT_CONST, &cval); } ST_FUNC void vset(CType *type, int r, int v) { - CValue cval; + CValue cval; - cval.i = v; - vsetc(type, r, &cval); + cval.i = v; + vsetc (type, r, &cval); } static void vseti(int r, int v) { - CType type; - type.t = VT_INT32; - type.ref = NULL; - vset(&type, r, v); + CType type; + type.t = VT_INT32; + type.ref = NULL; + vset (&type, r, v); } ST_FUNC void vswap(void) { - SValue tmp; - /* cannot let cpu flags if other instruction are generated. Also - avoid leaving VT_JMP anywhere except on the top of the stack - because it would complicate the code generator. */ - tmp = vtop[0]; - vtop[0] = vtop[-1]; - vtop[-1] = tmp; + SValue tmp; + /* cannot let cpu flags if other instruction are generated. Also + avoid leaving VT_JMP anywhere except on the top of the stack + because it would complicate the code generator. */ + tmp = vtop[0]; + vtop[0] = vtop[-1]; + vtop[-1] = tmp; /* XXX: +2% overall speed possible with optimized memswap * @@ -434,153 +450,163 @@ ST_FUNC void vswap(void) ST_FUNC void vpushv(SValue *v) { - if (vtop >= vstack + (VSTACK_SIZE - 1)) - tcc_error("memory full"); - vtop++; - *vtop = *v; + if (vtop >= vstack + (VSTACK_SIZE - 1)) { + tcc_error ("memory full"); + } + vtop++; + *vtop = *v; } static void vdup(void) { - vpushv(vtop); + vpushv (vtop); } /* get address of vtop (vtop MUST BE an lvalue) */ static void gaddrof(void) { - vtop->r &= ~VT_LVAL; - /* tricky: if saved lvalue, then we can go back to lvalue */ - if ((vtop->r & VT_VALMASK) == VT_LLOCAL) - vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; + vtop->r &= ~VT_LVAL; + /* tricky: if saved lvalue, then we can go back to lvalue */ + if ((vtop->r & VT_VALMASK) == VT_LLOCAL) { + vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; + } } static int pointed_size(CType *type) { - int align; - return type_size(pointed_type(type), &align); + int align; + return type_size (pointed_type (type), &align); } static inline int is_integer_btype(int bt) { - return (bt == VT_INT8 || bt == VT_INT16 || - bt == VT_INT32 || bt == VT_INT64); + return bt == VT_INT8 || bt == VT_INT16 || + bt == VT_INT32 || bt == VT_INT64; } /* return type size as known at compile time. Put alignment at 'a' */ ST_FUNC int type_size(CType *type, int *a) { - Sym *s; - int bt; + Sym *s; + int bt; - bt = type->t & VT_BTYPE; - if (bt == VT_STRUCT) { - /* struct/union */ - s = type->ref; - *a = s->r; - return s->c; - } else if (bt == VT_PTR) { - if (type->t & VT_ARRAY) { - int ts; + bt = type->t & VT_BTYPE; + if (bt == VT_STRUCT) { + /* struct/union */ + s = type->ref; + *a = s->r; + return s->c; + } else if (bt == VT_PTR) { + if (type->t & VT_ARRAY) { + int ts; - s = type->ref; - ts = type_size(&s->type, a); + s = type->ref; + ts = type_size (&s->type, a); - if (ts < 0 && s->c < 0) - ts = -ts; + if (ts < 0 && s->c < 0) { + ts = -ts; + } - return ts * s->c; - } else { - *a = PTR_SIZE; - return PTR_SIZE; - } - } else if (bt == VT_LDOUBLE) { - *a = LDOUBLE_ALIGN; - return LDOUBLE_SIZE; - } else if (bt == VT_DOUBLE || bt == VT_INT64) { - if (!strncmp(tcc_state->arch, "x86", 3) && tcc_state->bits == 32) { - if (!strncmp(tcc_state->os, "windows", 7)) { + return ts * s->c; + } else { + *a = PTR_SIZE; + return PTR_SIZE; + } + } else if (bt == VT_LDOUBLE) { + *a = LDOUBLE_ALIGN; + return LDOUBLE_SIZE; + } else if (bt == VT_DOUBLE || bt == VT_INT64) { + if (!strncmp (tcc_state->arch, "x86", 3) && tcc_state->bits == 32) { + if (!strncmp (tcc_state->os, "windows", 7)) { *a = 8; } else { *a = 4; } - } else if (!strncmp(tcc_state->arch, "arm", 3)) { - /* It was like originally: - #ifdef TCC_ARM_EABI - *a = 8; - #else - *a = 4; - #endif - FIXME: Determine EABI then too - */ + } else if (!strncmp (tcc_state->arch, "arm", 3)) { + /* It was like originally: + #ifdef TCC_ARM_EABI + *a = 8; + #else + *a = 4; + #endif + FIXME: Determine EABI then too + */ *a = 8; } else { *a = 8; } - return 8; + return 8; } else if (bt == VT_ENUM) { /* Non standard, but still widely used * and implemented in GCC, MSVC */ *a = 8; return 8; - } else if (bt == VT_INT32 || bt == VT_FLOAT) { - *a = 4; - return 4; - } else if (bt == VT_INT16) { - *a = 2; - return 2; - } else if (bt == VT_QLONG || bt == VT_QFLOAT) { - *a = 8; - return 16; - } else { - /* char, void, function, _Bool */ - *a = 1; - return 1; - } + } else if (bt == VT_INT32 || bt == VT_FLOAT) { + *a = 4; + return 4; + } else if (bt == VT_INT16) { + *a = 2; + return 2; + } else if (bt == VT_QLONG || bt == VT_QFLOAT) { + *a = 8; + return 16; + } else { + /* char, void, function, _Bool */ + *a = 1; + return 1; + } } /* return the pointed type of t */ static inline CType *pointed_type(CType *type) { - return &type->ref->type; + return &type->ref->type; } /* modify type so that its it is a pointer to type. */ ST_FUNC void mk_pointer(CType *type) { - Sym *s; - s = sym_push(SYM_FIELD, type, 0, -1); - type->t = VT_PTR | (type->t & ~VT_TYPE); - type->ref = s; + Sym *s; + s = sym_push (SYM_FIELD, type, 0, -1); + type->t = VT_PTR | (type->t & ~VT_TYPE); + type->ref = s; } /* compare function types. OLD functions match any new functions */ static int is_compatible_func(CType *type1, CType *type2) { - Sym *s1, *s2; + Sym *s1, *s2; - s1 = type1->ref; - s2 = type2->ref; - if (!is_compatible_types(&s1->type, &s2->type)) - return 0; - /* check func_call */ - if (FUNC_CALL(s1->r) != FUNC_CALL(s2->r)) - return 0; - /* XXX: not complete */ - if (s1->c == FUNC_OLD || s2->c == FUNC_OLD) - return 1; - if (s1->c != s2->c) - return 0; - while (s1 != NULL) { - if (s2 == NULL) - return 0; - if (!is_compatible_parameter_types(&s1->type, &s2->type)) - return 0; - s1 = s1->next; - s2 = s2->next; - } - if (s2) - return 0; - return 1; + s1 = type1->ref; + s2 = type2->ref; + if (!is_compatible_types (&s1->type, &s2->type)) { + return 0; + } + /* check func_call */ + if (FUNC_CALL (s1->r) != FUNC_CALL (s2->r)) { + return 0; + } + /* XXX: not complete */ + if (s1->c == FUNC_OLD || s2->c == FUNC_OLD) { + return 1; + } + if (s1->c != s2->c) { + return 0; + } + while (s1 != NULL) { + if (s2 == NULL) { + return 0; + } + if (!is_compatible_parameter_types (&s1->type, &s2->type)) { + return 0; + } + s1 = s1->next; + s2 = s2->next; + } + if (s2) { + return 0; + } + return 1; } /* return true if type1 and type2 are the same. If unqualified is @@ -590,31 +616,32 @@ static int is_compatible_func(CType *type1, CType *type2) */ static int compare_types(CType *type1, CType *type2, int unqualified) { - int bt1, t1, t2; + int bt1, t1, t2; - t1 = type1->t & VT_TYPE; - t2 = type2->t & VT_TYPE; - if (unqualified) { - /* strip qualifiers before comparing */ - t1 &= ~(VT_CONSTANT | VT_VOLATILE); - t2 &= ~(VT_CONSTANT | VT_VOLATILE); - } - /* XXX: bitfields ? */ - if (t1 != t2) - return 0; - /* test more complicated cases */ - bt1 = t1 & VT_BTYPE; - if (bt1 == VT_PTR) { - type1 = pointed_type(type1); - type2 = pointed_type(type2); - return is_compatible_types(type1, type2); - } else if (bt1 == VT_STRUCT) { - return (type1->ref == type2->ref); - } else if (bt1 == VT_FUNC) { - return is_compatible_func(type1, type2); - } else { - return 1; - } + t1 = type1->t & VT_TYPE; + t2 = type2->t & VT_TYPE; + if (unqualified) { + /* strip qualifiers before comparing */ + t1 &= ~(VT_CONSTANT | VT_VOLATILE); + t2 &= ~(VT_CONSTANT | VT_VOLATILE); + } + /* XXX: bitfields ? */ + if (t1 != t2) { + return 0; + } + /* test more complicated cases */ + bt1 = t1 & VT_BTYPE; + if (bt1 == VT_PTR) { + type1 = pointed_type (type1); + type2 = pointed_type (type2); + return is_compatible_types (type1, type2); + } else if (bt1 == VT_STRUCT) { + return type1->ref == type2->ref; + } else if (bt1 == VT_FUNC) { + return is_compatible_func (type1, type2); + } else { + return 1; + } } /* return true if type1 and type2 are exactly the same (including @@ -622,14 +649,14 @@ static int compare_types(CType *type1, CType *type2, int unqualified) */ static int is_compatible_types(CType *type1, CType *type2) { - return compare_types(type1,type2,0); + return compare_types (type1, type2, 0); } /* return true if type1 and type2 are the same (ignoring qualifiers). */ static int is_compatible_parameter_types(CType *type1, CType *type2) { - return compare_types(type1,type2,1); + return compare_types (type1, type2, 1); } /* print a type. If 'varstr' is not NULL, then the variable is also @@ -637,29 +664,29 @@ static int is_compatible_parameter_types(CType *type1, CType *type2) /* XXX: union */ /* XXX: add array and function pointers */ static void type_to_str(char *buf, int buf_size, - CType *type, const char *varstr) + CType *type, const char *varstr) { - int bt, v, t; - Sym *s, *sa; - char buf1[256]; - const char *tstr; - t = type->t & VT_TYPE; - bt = t & VT_BTYPE; - buf[0] = '\0'; - if (t & VT_CONSTANT) { - pstrcat(buf, buf_size, "const "); + int bt, v, t; + Sym *s, *sa; + char buf1[256]; + const char *tstr; + t = type->t & VT_TYPE; + bt = t & VT_BTYPE; + buf[0] = '\0'; + if (t & VT_CONSTANT) { + pstrcat (buf, buf_size, "const "); } - if (t & VT_VOLATILE) { - pstrcat(buf, buf_size, "volatile "); + if (t & VT_VOLATILE) { + pstrcat (buf, buf_size, "volatile "); } - switch(bt) { - case VT_VOID: - tstr = "void"; - goto add_tstr; - case VT_BOOL: - tstr = "bool"; - goto add_tstr; - case VT_INT8: + switch (bt) { + case VT_VOID: + tstr = "void"; + goto add_tstr; + case VT_BOOL: + tstr = "bool"; + goto add_tstr; + case VT_INT8: if (t & VT_UNSIGNED) { tstr = "uint8_t"; } else { @@ -669,91 +696,96 @@ static void type_to_str(char *buf, int buf_size, tstr = "int8_t"; } } - goto add_tstr; - case VT_INT16: + goto add_tstr; + case VT_INT16: if (t & VT_UNSIGNED) { tstr = "uint16_t"; } else { tstr = "int16_t"; } - goto add_tstr; - case VT_INT32: + goto add_tstr; + case VT_INT32: if (t & VT_UNSIGNED) { tstr = "uint32_t"; } else { tstr = "int32_t"; } - goto add_tstr; - case VT_LONG: - tstr = "long"; - goto add_tstr; - case VT_INT64: + goto add_tstr; + case VT_LONG: + tstr = "long"; + goto add_tstr; + case VT_INT64: if (t & VT_UNSIGNED) { tstr = "uint64_t"; } else { tstr = "int64_t"; } - goto add_tstr; - case VT_FLOAT: - tstr = "float"; - goto add_tstr; - case VT_DOUBLE: - tstr = "double"; - goto add_tstr; - case VT_LDOUBLE: - tstr = "long double"; - add_tstr: - pstrcat(buf, buf_size, tstr); + goto add_tstr; + case VT_FLOAT: + tstr = "float"; + goto add_tstr; + case VT_DOUBLE: + tstr = "double"; + goto add_tstr; + case VT_LDOUBLE: + tstr = "long double"; +add_tstr: + pstrcat (buf, buf_size, tstr); if ((t & VT_UNSIGNED) && (bt != VT_INT8) && - (bt != VT_INT16) && (bt != VT_INT32) && - (bt != VT_INT64)) { - pstrcat(buf, buf_size, "unsigned "); + (bt != VT_INT16) && (bt != VT_INT32) && + (bt != VT_INT64)) { + pstrcat (buf, buf_size, "unsigned "); } - break; - case VT_ENUM: - case VT_STRUCT: - if (bt == VT_STRUCT) - tstr = "struct "; - else - tstr = "enum "; - pstrcat(buf, buf_size, tstr); - v = type->ref->v & ~SYM_STRUCT; - if (v >= SYM_FIRST_ANOM) - pstrcat(buf, buf_size, ""); - else - pstrcat(buf, buf_size, get_tok_str(v, NULL)); - break; - case VT_FUNC: - s = type->ref; - type_to_str(buf, buf_size, &s->type, varstr); - pstrcat(buf, buf_size, "("); - sa = s->next; - while (sa != NULL) { - type_to_str(buf1, sizeof(buf1), &sa->type, NULL); - pstrcat(buf, buf_size, buf1); - sa = sa->next; - if (sa) - pstrcat(buf, buf_size, ", "); - } - pstrcat(buf, buf_size, ")"); - goto no_var; - case VT_PTR: - s = type->ref; - if (t & VT_ARRAY) { - type_to_str(buf, buf_size, &s->type, NULL); - } else { - pstrcpy(buf1, sizeof(buf1), "*"); - if (varstr) - pstrcat(buf1, sizeof(buf1), varstr); - type_to_str(buf, buf_size, &s->type, buf1); - } - goto no_var; - } - if (varstr) { - pstrcat(buf, buf_size, " "); - pstrcat(buf, buf_size, varstr); - } - no_var: ; + break; + case VT_ENUM: + case VT_STRUCT: + if (bt == VT_STRUCT) { + tstr = "struct "; + } else { + tstr = "enum "; + } + pstrcat (buf, buf_size, tstr); + v = type->ref->v & ~SYM_STRUCT; + if (v >= SYM_FIRST_ANOM) { + pstrcat (buf, buf_size, ""); + } else { + pstrcat (buf, buf_size, get_tok_str (v, NULL)); + } + break; + case VT_FUNC: + s = type->ref; + type_to_str (buf, buf_size, &s->type, varstr); + pstrcat (buf, buf_size, "("); + sa = s->next; + while (sa != NULL) { + type_to_str (buf1, sizeof(buf1), &sa->type, NULL); + pstrcat (buf, buf_size, buf1); + sa = sa->next; + if (sa) { + pstrcat (buf, buf_size, ", "); + } + } + pstrcat (buf, buf_size, ")"); + goto no_var; + case VT_PTR: + s = type->ref; + if (t & VT_ARRAY) { + type_to_str (buf, buf_size, &s->type, NULL); + } else { + pstrcpy (buf1, sizeof(buf1), "*"); + if (varstr) { + pstrcat (buf1, sizeof(buf1), varstr); + } + type_to_str (buf, buf_size, &s->type, buf1); + } + goto no_var; + } + if (varstr) { + pstrcat (buf, buf_size, " "); + pstrcat (buf, buf_size, varstr); + } +no_var: + ; } /* Parse GNUC __attribute__ extension. Currently, the following @@ -765,379 +797,405 @@ static void type_to_str(char *buf, int buf_size, */ static void parse_attribute(AttributeDef *ad) { - int t; + int t; long long n; - while (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) { - next(); - skip('('); - skip('('); - while (tok != ')') { - if (tok < TOK_IDENT) - expect("attribute name"); - t = tok; - next(); - switch(t) { - case TOK_ALIAS1: - case TOK_ALIAS2: - skip('('); - if (tok != TOK_STR) - expect("alias(\"target\")"); - ad->alias_target = /* save string as token, for later */ - tok_alloc((char*)tokc.cstr->data, tokc.cstr->size-1)->tok; - next(); - skip(')'); - break; - case TOK_ALIGNED1: - case TOK_ALIGNED2: - if (tok == '(') { - next(); - n = expr_const(); - if (n <= 0 || (n & (n - 1)) != 0) - tcc_error("alignment must be a positive power of two"); - skip(')'); - } else { - n = MAX_ALIGN; - } - ad->aligned = n; - break; - case TOK_PACKED1: - case TOK_PACKED2: - ad->packed = 1; - break; - case TOK_WEAK1: - case TOK_WEAK2: - ad->weak = 1; - break; - case TOK_UNUSED1: - case TOK_UNUSED2: - /* currently, no need to handle it because tcc does not - track unused objects */ - break; - case TOK_NORETURN1: - case TOK_NORETURN2: - /* currently, no need to handle it because tcc does not - track unused objects */ - break; - case TOK_CDECL1: - case TOK_CDECL2: - case TOK_CDECL3: - ad->func_call = FUNC_CDECL; - break; - case TOK_STDCALL1: - case TOK_STDCALL2: - case TOK_STDCALL3: - ad->func_call = FUNC_STDCALL; - break; + while (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) { + next (); + skip ('('); + skip ('('); + while (tok != ')') { + if (tok < TOK_IDENT) { + expect ("attribute name"); + } + t = tok; + next (); + switch (t) { + case TOK_ALIAS1: + case TOK_ALIAS2: + skip ('('); + if (tok != TOK_STR) { + expect ("alias(\"target\")"); + } + ad->alias_target = /* save string as token, for later */ + tok_alloc ((char *) tokc.cstr->data, tokc.cstr->size - 1)->tok; + next (); + skip (')'); + break; + case TOK_ALIGNED1: + case TOK_ALIGNED2: + if (tok == '(') { + next (); + n = expr_const (); + if (n <= 0 || (n & (n - 1)) != 0) { + tcc_error ("alignment must be a positive power of two"); + } + skip (')'); + } else { + n = MAX_ALIGN; + } + ad->aligned = n; + break; + case TOK_PACKED1: + case TOK_PACKED2: + ad->packed = 1; + break; + case TOK_WEAK1: + case TOK_WEAK2: + ad->weak = 1; + break; + case TOK_UNUSED1: + case TOK_UNUSED2: + /* currently, no need to handle it because tcc does not + track unused objects */ + break; + case TOK_NORETURN1: + case TOK_NORETURN2: + /* currently, no need to handle it because tcc does not + track unused objects */ + break; + case TOK_CDECL1: + case TOK_CDECL2: + case TOK_CDECL3: + ad->func_call = FUNC_CDECL; + break; + case TOK_STDCALL1: + case TOK_STDCALL2: + case TOK_STDCALL3: + ad->func_call = FUNC_STDCALL; + break; #ifdef TCC_TARGET_I386 - case TOK_REGPARM1: - case TOK_REGPARM2: - skip('('); - n = expr_const(); - if (n > 3) - n = 3; - else if (n < 0) - n = 0; - if (n > 0) - ad->func_call = FUNC_FASTCALL1 + n - 1; - skip(')'); - break; - case TOK_FASTCALL1: - case TOK_FASTCALL2: - case TOK_FASTCALL3: - ad->func_call = FUNC_FASTCALLW; - break; + case TOK_REGPARM1: + case TOK_REGPARM2: + skip ('('); + n = expr_const (); + if (n > 3) { + n = 3; + } else if (n < 0) { + n = 0; + } + if (n > 0) { + ad->func_call = FUNC_FASTCALL1 + n - 1; + } + skip (')'); + break; + case TOK_FASTCALL1: + case TOK_FASTCALL2: + case TOK_FASTCALL3: + ad->func_call = FUNC_FASTCALLW; + break; #endif - case TOK_MODE: - skip('('); - switch(tok) { - case TOK_MODE_DI: - ad->mode = VT_INT64 + 1; - break; - case TOK_MODE_HI: - ad->mode = VT_INT16 + 1; - break; - case TOK_MODE_SI: - ad->mode = VT_INT32 + 1; - break; - default: - tcc_warning("__mode__(%s) not supported\n", get_tok_str(tok, NULL)); - break; - } - next(); - skip(')'); - break; - case TOK_DLLEXPORT: - ad->func_export = 1; - break; - case TOK_DLLIMPORT: - ad->func_import = 1; - break; - default: - if (tcc_state->warn_unsupported) - tcc_warning("'%s' attribute ignored", get_tok_str(t, NULL)); - /* skip parameters */ - if (tok == '(') { - int parenthesis = 0; - do { - if (tok == '(') - parenthesis++; - else if (tok == ')') - parenthesis--; - next(); - } while (parenthesis && tok != -1); - } - break; - } - if (tok != ',') - break; - next(); - } - skip(')'); - skip(')'); - } + case TOK_MODE: + skip ('('); + switch (tok) { + case TOK_MODE_DI: + ad->mode = VT_INT64 + 1; + break; + case TOK_MODE_HI: + ad->mode = VT_INT16 + 1; + break; + case TOK_MODE_SI: + ad->mode = VT_INT32 + 1; + break; + default: + tcc_warning ("__mode__(%s) not supported\n", get_tok_str (tok, NULL)); + break; + } + next (); + skip (')'); + break; + case TOK_DLLEXPORT: + ad->func_export = 1; + break; + case TOK_DLLIMPORT: + ad->func_import = 1; + break; + default: + if (tcc_state->warn_unsupported) { + tcc_warning ("'%s' attribute ignored", get_tok_str (t, NULL)); + } + /* skip parameters */ + if (tok == '(') { + int parenthesis = 0; + do { + if (tok == '(') { + parenthesis++; + } else if (tok == ')') { + parenthesis--; + } + next (); + } while (parenthesis && tok != -1); + } + break; + } + if (tok != ',') { + break; + } + next (); + } + skip (')'); + skip (')'); + } } /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ static void struct_decl(CType *type, int u) { - int a, v, size, align, maxalign, offset; + int a, v, size, align, maxalign, offset; long long c = 0; - int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt; - Sym *s, *ss, *ass, **ps; - AttributeDef ad; + int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt; + Sym *s, *ss, *ass, **ps; + AttributeDef ad; const char *name = NULL; - STACK_NEW0(CType, type1); - STACK_NEW0(CType, btype); + STACK_NEW0 (CType, type1); + STACK_NEW0 (CType, btype); - a = tok; /* save decl type */ - next(); + a = tok;/* save decl type */ + next (); name = get_tok_str (tok, NULL); - if (tok != '{') { - v = tok; - next(); - /* struct already defined ? return it */ - if (v < TOK_IDENT) - expect("struct/union/enum name"); - s = struct_find(v); - if (s) { - if (s->type.t != a) - tcc_error("invalid type"); - goto do_decl; - } - } else { - v = anon_sym++; - } - type1.t = a; - /* we put an undefined size for struct/union */ - s = sym_push(v | SYM_STRUCT, &type1, 0, -1); - s->r = 0; /* default alignment is zero as gcc */ - /* put struct/union/enum name in type */ - do_decl: - type->t = u; - type->ref = s; - - if (tok == '{') { - next(); - if (s->c != -1) - tcc_error("struct/union/enum already defined"); - /* cannot be empty */ - c = 0LL; - /* non empty enums are not allowed */ - if (a == TOK_ENUM) { - if (!strcmp (name, "{")) { - // UNNAMED - fprintf (stderr, "anonymous enums are ignored\n"); - } else { - tcc_appendf ("%s=enum\n", name); + if (tok != '{') { + v = tok; + next (); + /* struct already defined ? return it */ + if (v < TOK_IDENT) { + expect ("struct/union/enum name"); } - for(;;) { - v = tok; - if (v < TOK_UIDENT) - expect("identifier"); - next(); - if (tok == '=') { - next(); - c = expr_const(); - } + s = struct_find (v); + if (s) { + if (s->type.t != a) { + tcc_error ("invalid type"); + } + goto do_decl; + } + } else { + v = anon_sym++; + } + type1.t = a; + /* we put an undefined size for struct/union */ + s = sym_push (v | SYM_STRUCT, &type1, 0, -1); + s->r = 0; /* default alignment is zero as gcc */ + /* put struct/union/enum name in type */ +do_decl: + type->t = u; + type->ref = s; + + if (tok == '{') { + next (); + if (s->c != -1) { + tcc_error ("struct/union/enum already defined"); + } + /* cannot be empty */ + c = 0LL; + /* non empty enums are not allowed */ + if (a == TOK_ENUM) { + if (!strcmp (name, "{")) { + // UNNAMED + fprintf (stderr, "anonymous enums are ignored\n"); + } else { + tcc_appendf ("%s=enum\n", name); + } + for (;;) { + v = tok; + if (v < TOK_UIDENT) { + expect ("identifier"); + } + next (); + if (tok == '=') { + next (); + c = expr_const (); + } if (strcmp (name, "{")) { char *varstr = get_tok_str (v, NULL); - //eprintf("%s.%s @ 0x%"PFMT64x"\n", name, varstr, c); - tcc_appendf ("%s.%s=0x%"PFMT64x"\n", name, varstr, c); - tcc_appendf ("%s.0x%"PFMT64x"=%s\n", name, c, varstr); + // eprintf("%s.%s @ 0x%"PFMT64x"\n", name, varstr, c); + tcc_appendf ("%s.%s=0x%"PFMT64x "\n", name, varstr, c); + tcc_appendf ("%s.0x%"PFMT64x "=%s\n", name, c, varstr); // TODO: if token already defined throw an error - // if (varstr isInside (arrayOfvars)) { erprintf ("ERROR: DUP VAR IN ENUM\n"); } + // if (varstr isInside (arrayOfvars)) { erprintf ("ERROR: DUP VAR IN ENUM\n"); } + } + /* enum symbols have static storage */ + ss = sym_push (v, &int64_type, VT_CONST, c); + ss->type.t |= VT_STATIC; + if (tok != ',') { + break; + } + next (); + c++; + /* NOTE: we accept a trailing comma */ + if (tok == '}') { + break; } - /* enum symbols have static storage */ - ss = sym_push(v, &int64_type, VT_CONST, c); - ss->type.t |= VT_STATIC; - if (tok != ',') - break; - next(); - c++; - /* NOTE: we accept a trailing comma */ - if (tok == '}') - break; - } - skip('}'); - } else { - maxalign = 1; - ps = &s->next; - prevbt = VT_INT32; - bit_pos = 0; - offset = 0; - while (tok != '}') { - if (!parse_btype(&btype, &ad)) { - expect("bracket"); - break; - } - while (1) { - bit_size = -1; - v = 0; - memcpy(&type1, &btype, sizeof(type1)); - if (tok != ':') { - type_decl(&type1, &ad, &v, TYPE_DIRECT | TYPE_ABSTRACT); - if (v == 0 && (type1.t & VT_BTYPE) != VT_STRUCT) - expect("identifier"); - if ((type1.t & VT_BTYPE) == VT_FUNC || - (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE))) - tcc_error("invalid type for '%s'", - get_tok_str(v, NULL)); - } - if (tok == ':') { - next(); - bit_size = (int)expr_const(); - /* XXX: handle v = 0 case for messages */ - if (bit_size < 0) - tcc_error("negative width in bit-field '%s'", - get_tok_str(v, NULL)); - if (v && bit_size == 0) - tcc_error("zero width for bit-field '%s'", - get_tok_str(v, NULL)); - } - size = type_size(&type1, &align); - if (ad.aligned) { - if (align < ad.aligned) - align = ad.aligned; - } else if (ad.packed) { - align = 1; - } else if (*tcc_state->pack_stack_ptr) { - if (align > *tcc_state->pack_stack_ptr) - align = *tcc_state->pack_stack_ptr; - } - lbit_pos = 0; - if (bit_size >= 0) { - bt = type1.t & VT_BTYPE; - if (bt != VT_INT8 && - bt != VT_INT16 && - bt != VT_INT32 && - bt != VT_INT64 && - bt != VT_ENUM && - bt != VT_BOOL) - tcc_error("bitfields must have scalar type"); - bsize = size * 8; - if (bit_size > bsize) { - tcc_error("width of '%s' exceeds its type", - get_tok_str(v, NULL)); - } else if (bit_size == bsize) { - /* no need for bit fields */ - bit_pos = 0; - } else if (bit_size == 0) { - /* XXX: what to do if only padding in a - structure ? */ - /* zero size: means to pad */ - bit_pos = 0; - } else { - /* we do not have enough room ? - did the type change? - is it a union? */ - if ((bit_pos + bit_size) > bsize || - bt != prevbt || a == TOK_UNION) - bit_pos = 0; - lbit_pos = bit_pos; - /* XXX: handle LSB first */ - type1.t |= VT_BITFIELD | - (bit_pos << VT_STRUCT_SHIFT) | - (bit_size << (VT_STRUCT_SHIFT + 6)); - bit_pos += bit_size; - } - prevbt = bt; - } else { - bit_pos = 0; - } - if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) { - /* add new memory data only if starting - bit field */ - if (lbit_pos == 0) { - if (a == TOK_STRUCT) { - c = (c + align - 1) & -align; - offset = c; - if (size > 0) - c += size; - } else { - offset = 0; - if (size > c) - c = size; - } - if (align > maxalign) - maxalign = align; } + skip ('}'); + } else { + maxalign = 1; + ps = &s->next; + prevbt = VT_INT32; + bit_pos = 0; + offset = 0; + while (tok != '}') { + if (!parse_btype (&btype, &ad)) { + expect ("bracket"); + break; + } + while (1) { + bit_size = -1; + v = 0; + memcpy (&type1, &btype, sizeof(type1)); + if (tok != ':') { + type_decl (&type1, &ad, &v, TYPE_DIRECT | TYPE_ABSTRACT); + if (v == 0 && (type1.t & VT_BTYPE) != VT_STRUCT) { + expect ("identifier"); + } + if ((type1.t & VT_BTYPE) == VT_FUNC || + (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE))) { + tcc_error ("invalid type for '%s'", + get_tok_str (v, NULL)); + } + } + if (tok == ':') { + next (); + bit_size = (int) expr_const (); + /* XXX: handle v = 0 case for messages */ + if (bit_size < 0) { + tcc_error ("negative width in bit-field '%s'", + get_tok_str (v, NULL)); + } + if (v && bit_size == 0) { + tcc_error ("zero width for bit-field '%s'", + get_tok_str (v, NULL)); + } + } + size = type_size (&type1, &align); + if (ad.aligned) { + if (align < ad.aligned) { + align = ad.aligned; + } + } else if (ad.packed) { + align = 1; + } else if (*tcc_state->pack_stack_ptr) { + if (align > *tcc_state->pack_stack_ptr) { + align = *tcc_state->pack_stack_ptr; + } + } + lbit_pos = 0; + if (bit_size >= 0) { + bt = type1.t & VT_BTYPE; + if (bt != VT_INT8 && + bt != VT_INT16 && + bt != VT_INT32 && + bt != VT_INT64 && + bt != VT_ENUM && + bt != VT_BOOL) { + tcc_error ("bitfields must have scalar type"); + } + bsize = size * 8; + if (bit_size > bsize) { + tcc_error ("width of '%s' exceeds its type", + get_tok_str (v, NULL)); + } else if (bit_size == bsize) { + /* no need for bit fields */ + bit_pos = 0; + } else if (bit_size == 0) { + /* XXX: what to do if only padding in a + structure ? */ + /* zero size: means to pad */ + bit_pos = 0; + } else { + /* we do not have enough room ? + did the type change? + is it a union? */ + if ((bit_pos + bit_size) > bsize || + bt != prevbt || a == TOK_UNION) { + bit_pos = 0; + } + lbit_pos = bit_pos; + /* XXX: handle LSB first */ + type1.t |= VT_BITFIELD | + (bit_pos << VT_STRUCT_SHIFT) | + (bit_size << (VT_STRUCT_SHIFT + 6)); + bit_pos += bit_size; + } + prevbt = bt; + } else { + bit_pos = 0; + } + if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) { + /* add new memory data only if starting + bit field */ + if (lbit_pos == 0) { + if (a == TOK_STRUCT) { + c = (c + align - 1) & - align; + offset = c; + if (size > 0) { + c += size; + } + } else { + offset = 0; + if (size > c) { + c = size; + } + } + if (align > maxalign) { + maxalign = align; + } + } #if 1 - char b[1024]; - char *varstr = get_tok_str (v, NULL); - type_to_str (b, sizeof(b), &type1, NULL); - { - const char *ctype = (a == TOK_UNION)? "union": "struct"; - int type_bt = type1.t & VT_BTYPE; - //eprintf("2: %s.%s = %s\n", ctype, name, varstr); - tcc_appendf ("%s=%s\n", name, ctype); - tcc_appendf ("[+]%s.%s=%s\n", - ctype, name, varstr); - tcc_appendf ("%s.%s.%s.meta=%d\n", - ctype, name, varstr, type_bt); - /* compact form */ - tcc_appendf ("%s.%s.%s=%s,%d,%d\n", - ctype, name,varstr,b,offset,arraysize); - } + char b[1024]; + char *varstr = get_tok_str (v, NULL); + type_to_str (b, sizeof(b), &type1, NULL); + { + const char *ctype = (a == TOK_UNION)? "union": "struct"; + int type_bt = type1.t & VT_BTYPE; + // eprintf("2: %s.%s = %s\n", ctype, name, varstr); + tcc_appendf ("%s=%s\n", name, ctype); + tcc_appendf ("[+]%s.%s=%s\n", + ctype, name, varstr); + tcc_appendf ("%s.%s.%s.meta=%d\n", + ctype, name, varstr, type_bt); + /* compact form */ + tcc_appendf ("%s.%s.%s=%s,%d,%d\n", + ctype, name, varstr, b, offset, arraysize); + } #if 0 - printf ("struct.%s.%s.type=%s\n", name, varstr, b); - printf ("struct.%s.%s.offset=%d\n", name, varstr, offset); - printf ("struct.%s.%s.array=%d\n", name, varstr, arraysize); + printf ("struct.%s.%s.type=%s\n", name, varstr, b); + printf ("struct.%s.%s.offset=%d\n", name, varstr, offset); + printf ("struct.%s.%s.array=%d\n", name, varstr, arraysize); #endif - //(%s) field (%s) offset=%d array=%d", name, b, get_tok_str(v, NULL), offset, arraysize); - arraysize = 0; - if (type1.t & VT_BITFIELD) { - tcc_appendf (" pos=%d size=%d", - (type1.t >> VT_STRUCT_SHIFT) & 0x3f, - (type1.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f); + // (%s) field (%s) offset=%d array=%d", name, b, get_tok_str(v, NULL), offset, arraysize); + arraysize = 0; + if (type1.t & VT_BITFIELD) { + tcc_appendf (" pos=%d size=%d", + (type1.t >> VT_STRUCT_SHIFT) & 0x3f, + (type1.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f); + } + // printf("\n"); +#endif + } + if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) { + ass = type1.ref; + while ((ass = ass->next) != NULL) { + ss = sym_push (ass->v, &ass->type, 0, offset + ass->c); + *ps = ss; + ps = &ss->next; + } + } else if (v) { + ss = sym_push (v | SYM_FIELD, &type1, 0, offset); + *ps = ss; + ps = &ss->next; + } + if (tok == ';' || tok == TOK_EOF) { + break; + } + skip (','); + } + skip (';'); } - //printf("\n"); -#endif - } - if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) { - ass = type1.ref; - while ((ass = ass->next) != NULL) { - ss = sym_push(ass->v, &ass->type, 0, offset + ass->c); - *ps = ss; - ps = &ss->next; - } - } else if (v) { - ss = sym_push(v | SYM_FIELD, &type1, 0, offset); - *ps = ss; - ps = &ss->next; - } - if (tok == ';' || tok == TOK_EOF) - break; - skip(','); - } - skip(';'); - } - skip('}'); - /* store size and alignment */ - s->c = (c + maxalign - 1) & -maxalign; - s->r = maxalign; - } - } + skip ('}'); + /* store size and alignment */ + s->c = (c + maxalign - 1) & - maxalign; + s->r = maxalign; + } + } } /* return 0 if no type declaration. otherwise, return the basic type @@ -1145,26 +1203,26 @@ static void struct_decl(CType *type, int u) */ static int parse_btype(CType *type, AttributeDef *ad) { - int t, u, type_found, typespec_found, typedef_found; - Sym *s; - STACK_NEW0(CType, type1); + int t, u, type_found, typespec_found, typedef_found; + Sym *s; + STACK_NEW0 (CType, type1); - memset(ad, 0, sizeof(AttributeDef)); - type_found = 0; - typespec_found = 0; - typedef_found = 0; + memset (ad, 0, sizeof(AttributeDef)); + type_found = 0; + typespec_found = 0; + typedef_found = 0; /* FIXME: Make this dependent on the target */ - t = 0; /* default for 'int' */ - while(1) { - switch(tok) { - case TOK_EXTENSION: - /* currently, we really ignore extension */ - next(); - continue; + t = 0; /* default for 'int' */ + while (1) { + switch (tok) { + case TOK_EXTENSION: + /* currently, we really ignore extension */ + next (); + continue; - /* ------------------------------------------------------------------ */ + /* ------------------------------------------------------------------ */ /* basic types */ - /* ------------------------------------------------------------------ */ + /* ------------------------------------------------------------------ */ /* int8_t, uint8_t, char */ case TOK_UINT8: @@ -1172,31 +1230,31 @@ static int parse_btype(CType *type, AttributeDef *ad) case TOK_INT8: u = VT_INT8; goto basic_type; - case TOK_CHAR: - u = VT_INT8; + case TOK_CHAR: + u = VT_INT8; /* Mark as character type, for strings */ t |= VT_CHAR; - basic_type: - next(); - basic_type1: - if ((t & VT_BTYPE) != 0) { - tcc_error("too many basic types"); +basic_type: + next (); +basic_type1: + if ((t & VT_BTYPE) != 0) { + tcc_error ("too many basic types"); } - t |= u; - typespec_found = 1; - break; + t |= u; + typespec_found = 1; + break; /* void* */ - case TOK_VOID: - u = VT_VOID; - goto basic_type; + case TOK_VOID: + u = VT_VOID; + goto basic_type; /* int16_t, uint16_t, short */ case TOK_UINT16: - t |= VT_UNSIGNED; + t |= VT_UNSIGNED; case TOK_INT16: - case TOK_SHORT: - u = VT_INT16; + case TOK_SHORT: + u = VT_INT16; goto basic_type; /* int32_t, uint32_t, int */ @@ -1205,10 +1263,10 @@ static int parse_btype(CType *type, AttributeDef *ad) case TOK_INT32: u = VT_INT32; goto basic_type; - case TOK_INT: - next(); - typespec_found = 1; - break; + case TOK_INT: + next (); + typespec_found = 1; + break; /* int64_t, uint64_t, long, long long */ case TOK_UINT64: @@ -1216,317 +1274,332 @@ static int parse_btype(CType *type, AttributeDef *ad) case TOK_INT64: u = VT_INT64; goto basic_type; - case TOK_LONG: - next(); + case TOK_LONG: + next (); // FIXME: Better handling long and long long types - if ((t & VT_BTYPE) == VT_DOUBLE) { - if (strncmp(tcc_state->os, "windows", 7)) { + if ((t & VT_BTYPE) == VT_DOUBLE) { + if (strncmp (tcc_state->os, "windows", 7)) { t = (t & ~VT_BTYPE) | VT_LDOUBLE; } - } else if ((t & VT_BTYPE) == VT_LONG) { - t = (t & ~VT_BTYPE) | VT_INT64; - } else { - u = VT_LONG; - goto basic_type1; - } - break; - case TOK_BOOL: + } else if ((t & VT_BTYPE) == VT_LONG) { + t = (t & ~VT_BTYPE) | VT_INT64; + } else { + u = VT_LONG; + goto basic_type1; + } + break; + case TOK_BOOL: case TOK_STDBOOL: - u = VT_BOOL; - goto basic_type; - case TOK_FLOAT: - u = VT_FLOAT; - goto basic_type; - case TOK_DOUBLE: - next(); - if ((t & VT_BTYPE) == VT_LONG) { - if (!strncmp(tcc_state->os, "windows", 7)) { + u = VT_BOOL; + goto basic_type; + case TOK_FLOAT: + u = VT_FLOAT; + goto basic_type; + case TOK_DOUBLE: + next (); + if ((t & VT_BTYPE) == VT_LONG) { + if (!strncmp (tcc_state->os, "windows", 7)) { t = (t & ~VT_BTYPE) | VT_DOUBLE; } else { t = (t & ~VT_BTYPE) | VT_LDOUBLE; } - } else { - u = VT_DOUBLE; - goto basic_type1; - } - break; - case TOK_ENUM: - struct_decl(&type1, VT_ENUM); - basic_type2: - u = type1.t; - type->ref = type1.ref; - goto basic_type1; - case TOK_STRUCT: - case TOK_UNION: - struct_decl(&type1, VT_STRUCT); - goto basic_type2; + } else { + u = VT_DOUBLE; + goto basic_type1; + } + break; + case TOK_ENUM: + struct_decl (&type1, VT_ENUM); +basic_type2: + u = type1.t; + type->ref = type1.ref; + goto basic_type1; + case TOK_STRUCT: + case TOK_UNION: + struct_decl (&type1, VT_STRUCT); + goto basic_type2; - /* type modifiers */ - case TOK_CONST1: - case TOK_CONST2: - case TOK_CONST3: - t |= VT_CONSTANT; - next(); - break; - case TOK_VOLATILE1: - case TOK_VOLATILE2: - case TOK_VOLATILE3: - t |= VT_VOLATILE; - next(); - break; - case TOK_SIGNED1: - case TOK_SIGNED2: - case TOK_SIGNED3: - typespec_found = 1; - t |= VT_SIGNED; - next(); - break; - case TOK_REGISTER: - case TOK_AUTO: - case TOK_RESTRICT1: - case TOK_RESTRICT2: - case TOK_RESTRICT3: - next(); - break; - case TOK_UNSIGNED: - t |= VT_UNSIGNED; - next(); - typespec_found = 1; - break; + /* type modifiers */ + case TOK_CONST1: + case TOK_CONST2: + case TOK_CONST3: + t |= VT_CONSTANT; + next (); + break; + case TOK_VOLATILE1: + case TOK_VOLATILE2: + case TOK_VOLATILE3: + t |= VT_VOLATILE; + next (); + break; + case TOK_SIGNED1: + case TOK_SIGNED2: + case TOK_SIGNED3: + typespec_found = 1; + t |= VT_SIGNED; + next (); + break; + case TOK_REGISTER: + case TOK_AUTO: + case TOK_RESTRICT1: + case TOK_RESTRICT2: + case TOK_RESTRICT3: + next (); + break; + case TOK_UNSIGNED: + t |= VT_UNSIGNED; + next (); + typespec_found = 1; + break; - /* storage */ - case TOK_EXTERN: - t |= VT_EXTERN; - next(); - break; - case TOK_STATIC: - t |= VT_STATIC; - next(); - break; - case TOK_TYPEDEF: - t |= VT_TYPEDEF; - next(); - break; - case TOK_INLINE1: - case TOK_INLINE2: - case TOK_INLINE3: - t |= VT_INLINE; - next(); - break; + /* storage */ + case TOK_EXTERN: + t |= VT_EXTERN; + next (); + break; + case TOK_STATIC: + t |= VT_STATIC; + next (); + break; + case TOK_TYPEDEF: + t |= VT_TYPEDEF; + next (); + break; + case TOK_INLINE1: + case TOK_INLINE2: + case TOK_INLINE3: + t |= VT_INLINE; + next (); + break; - /* GNUC attribute */ - case TOK_ATTRIBUTE1: - case TOK_ATTRIBUTE2: - parse_attribute(ad); - if (ad->mode) { - u = ad->mode -1; - t = (t & ~VT_BTYPE) | u; - } - break; - /* GNUC typeof */ - case TOK_TYPEOF1: - case TOK_TYPEOF2: - case TOK_TYPEOF3: - next(); - parse_expr_type(&type1); - /* remove all storage modifiers except typedef */ - type1.t &= ~(VT_STORAGE&~VT_TYPEDEF); - goto basic_type2; - default: - if (typespec_found || typedef_found) - goto the_end; - s = sym_find(tok); - if (!s || !(s->type.t & VT_TYPEDEF)) - goto the_end; - typedef_found = 1; - t |= (s->type.t & ~VT_TYPEDEF); - type->ref = s->type.ref; - if (s->r) { - /* get attributes from typedef */ - if (0 == ad->aligned) - ad->aligned = FUNC_ALIGN(s->r); - if (0 == ad->func_call) - ad->func_call = FUNC_CALL(s->r); - ad->packed |= FUNC_PACKED(s->r); - } - next(); - typespec_found = 1; - break; - } - type_found = 1; - } -the_end: - if ((t & (VT_SIGNED|VT_UNSIGNED)) == (VT_SIGNED|VT_UNSIGNED)) { - tcc_error("signed and unsigned modifier"); + /* GNUC attribute */ + case TOK_ATTRIBUTE1: + case TOK_ATTRIBUTE2: + parse_attribute (ad); + if (ad->mode) { + u = ad->mode - 1; + t = (t & ~VT_BTYPE) | u; + } + break; + /* GNUC typeof */ + case TOK_TYPEOF1: + case TOK_TYPEOF2: + case TOK_TYPEOF3: + next (); + parse_expr_type (&type1); + /* remove all storage modifiers except typedef */ + type1.t &= ~(VT_STORAGE & ~VT_TYPEDEF); + goto basic_type2; + default: + if (typespec_found || typedef_found) { + goto the_end; + } + s = sym_find (tok); + if (!s || !(s->type.t & VT_TYPEDEF)) { + goto the_end; + } + typedef_found = 1; + t |= (s->type.t & ~VT_TYPEDEF); + type->ref = s->type.ref; + if (s->r) { + /* get attributes from typedef */ + if (0 == ad->aligned) { + ad->aligned = FUNC_ALIGN (s->r); + } + if (0 == ad->func_call) { + ad->func_call = FUNC_CALL (s->r); + } + ad->packed |= FUNC_PACKED (s->r); + } + next (); + typespec_found = 1; + break; + } + type_found = 1; } - if (tcc_state->char_is_unsigned) { - if ((t & (VT_SIGNED|VT_UNSIGNED|VT_BTYPE)) == VT_INT8) - t |= VT_UNSIGNED; - } - t &= ~VT_SIGNED; +the_end: + if ((t & (VT_SIGNED | VT_UNSIGNED)) == (VT_SIGNED | VT_UNSIGNED)) { + tcc_error ("signed and unsigned modifier"); + } + if (tcc_state->char_is_unsigned) { + if ((t & (VT_SIGNED | VT_UNSIGNED | VT_BTYPE)) == VT_INT8) { + t |= VT_UNSIGNED; + } + } + t &= ~VT_SIGNED; - /* long is never used as type */ - if ((t & VT_BTYPE) == VT_LONG) { - if (!strncmp(tcc_state->os, "windows", 7) || - (!strncmp(tcc_state->arch, "x86", 3) && tcc_state->bits == 32)) { + /* long is never used as type */ + if ((t & VT_BTYPE) == VT_LONG) { + if (!strncmp (tcc_state->os, "windows", 7) || + (!strncmp (tcc_state->arch, "x86", 3) && tcc_state->bits == 32)) { t = (t & ~VT_BTYPE) | VT_INT32; } else { t = (t & ~VT_BTYPE) | VT_INT64; } } - type->t = t; - return type_found; + type->t = t; + return type_found; } /* convert a function parameter type (array to pointer and function to function pointer) */ static inline void convert_parameter_type(CType *pt) { - /* remove const and volatile qualifiers (XXX: const could be used - to indicate a const function parameter */ - pt->t &= ~(VT_CONSTANT | VT_VOLATILE); - /* array must be transformed to pointer according to ANSI C */ - pt->t &= ~VT_ARRAY; - if ((pt->t & VT_BTYPE) == VT_FUNC) { - mk_pointer(pt); - } + /* remove const and volatile qualifiers (XXX: const could be used + to indicate a const function parameter */ + pt->t &= ~(VT_CONSTANT | VT_VOLATILE); + /* array must be transformed to pointer according to ANSI C */ + pt->t &= ~VT_ARRAY; + if ((pt->t & VT_BTYPE) == VT_FUNC) { + mk_pointer (pt); + } } static void post_type(CType *type, AttributeDef *ad) { - int n, l, t1, arg_size, align; - Sym **plast, *s, *first; - AttributeDef ad1; - CType pt; -char *symname = NULL; -int narg =0; + int n, l, t1, arg_size, align; + Sym **plast, *s, *first; + AttributeDef ad1; + CType pt; + char *symname = NULL; + int narg = 0; - if (tok == '(') { - /* function declaration */ - next(); - l = 0; - first = NULL; - plast = &first; + if (tok == '(') { + /* function declaration */ + next (); + l = 0; + first = NULL; + plast = &first; { const char *ret_type = global_type; free (symname); symname = strdup (global_symname); tcc_appendf ("func.%s.ret=%s\n", symname, ret_type); - tcc_appendf ("func.%s.cc=%s\n", symname, "cdecl"); // TODO + tcc_appendf ("func.%s.cc=%s\n", symname, "cdecl"); // TODO tcc_appendf ("%s=func\n", symname); } - arg_size = 0; - if (tok != ')') { - for(;;) { - /* read param name and compute offset */ - if (l != FUNC_OLD) { - if (!parse_btype(&pt, &ad1)) { - if (l) { - tcc_error("invalid type"); - } else { - l = FUNC_OLD; - goto old_proto; - } - } - l = FUNC_NEW; - if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') - break; - type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); - if ((pt.t & VT_BTYPE) == VT_VOID) - tcc_error("parameter declared as void"); - arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE; - } else { - old_proto: - n = tok; - if (n < TOK_UIDENT) - expect("identifier"); - pt.t = VT_INT32; - next(); - } - convert_parameter_type(&pt); - s = sym_push(n | SYM_FIELD, &pt, 0, 0); - { - char kind[1024]; - type_to_str (kind, sizeof (kind), &pt, NULL); - tcc_appendf ("func.%s.arg.%d=%s,%s\n", - symname, narg, kind, global_symname); - narg++; + arg_size = 0; + if (tok != ')') { + for (;;) { + /* read param name and compute offset */ + if (l != FUNC_OLD) { + if (!parse_btype (&pt, &ad1)) { + if (l) { + tcc_error ("invalid type"); + } else { + l = FUNC_OLD; + goto old_proto; + } + } + l = FUNC_NEW; + if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') { + break; + } + type_decl (&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); + if ((pt.t & VT_BTYPE) == VT_VOID) { + tcc_error ("parameter declared as void"); + } + arg_size += (type_size (&pt, &align) + PTR_SIZE - 1) / PTR_SIZE; + } else { +old_proto: + n = tok; + if (n < TOK_UIDENT) { + expect ("identifier"); + } + pt.t = VT_INT32; + next (); } - *plast = s; - plast = &s->next; - if (tok == ')') - break; - skip(','); - if (l == FUNC_NEW && tok == TOK_DOTS) { - l = FUNC_ELLIPSIS; - next(); - break; - } - } - } + convert_parameter_type (&pt); + s = sym_push (n | SYM_FIELD, &pt, 0, 0); + { + char kind[1024]; + type_to_str (kind, sizeof (kind), &pt, NULL); + tcc_appendf ("func.%s.arg.%d=%s,%s\n", + symname, narg, kind, global_symname); + narg++; + } + *plast = s; + plast = &s->next; + if (tok == ')') { + break; + } + skip (','); + if (l == FUNC_NEW && tok == TOK_DOTS) { + l = FUNC_ELLIPSIS; + next (); + break; + } + } + } tcc_appendf ("func.%s.args=%d\n", symname, narg); - /* if no parameters, then old type prototype */ - if (l == 0) - l = FUNC_OLD; - skip(')'); - /* NOTE: const is ignored in returned type as it has a special - meaning in gcc / C++ */ - type->t &= ~VT_CONSTANT; - /* some ancient pre-K&R C allows a function to return an array - and the array brackets to be put after the arguments, such - that "int c()[]" means something like "int[] c()" */ - if (tok == '[') { - next(); - skip(']'); /* only handle simple "[]" */ - type->t |= VT_PTR; - } - /* we push a anonymous symbol which will contain the function prototype */ - ad->func_args = arg_size; - s = sym_push(SYM_FIELD, type, INT_ATTR(ad), l); - s->next = first; - type->t = VT_FUNC; - type->ref = s; -free(symname); -symname = NULL; - } else if (tok == '[') { - /* array definition */ - next(); - if (tok == TOK_RESTRICT1) - next(); - n = -1; - t1 = 0; - if (tok != ']') { - if (!local_stack || nocode_wanted) - vpushll(expr_const()); - else gexpr(); - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - n = vtop->c.i; - if (n < 0) - tcc_error("invalid array size"); - } else { - if (!is_integer_btype(vtop->type.t & VT_BTYPE)) - tcc_error("size of variable length array should be an integer"); - t1 = VT_VLA; - } - } - skip(']'); - /* parse next post type */ - post_type(type, ad); + /* if no parameters, then old type prototype */ + if (l == 0) { + l = FUNC_OLD; + } + skip (')'); + /* NOTE: const is ignored in returned type as it has a special + meaning in gcc / C++ */ + type->t &= ~VT_CONSTANT; + /* some ancient pre-K&R C allows a function to return an array + and the array brackets to be put after the arguments, such + that "int c()[]" means something like "int[] c()" */ + if (tok == '[') { + next (); + skip (']'); /* only handle simple "[]" */ + type->t |= VT_PTR; + } + /* we push a anonymous symbol which will contain the function prototype */ + ad->func_args = arg_size; + s = sym_push (SYM_FIELD, type, INT_ATTR (ad), l); + s->next = first; + type->t = VT_FUNC; + type->ref = s; + free (symname); + symname = NULL; + } else if (tok == '[') { + /* array definition */ + next (); + if (tok == TOK_RESTRICT1) { + next (); + } + n = -1; + t1 = 0; + if (tok != ']') { + if (!local_stack || nocode_wanted) { + vpushll (expr_const ()); + } else { + gexpr (); + } + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + n = vtop->c.i; + if (n < 0) { + tcc_error ("invalid array size"); + } + } else { + if (!is_integer_btype (vtop->type.t & VT_BTYPE)) { + tcc_error ("size of variable length array should be an integer"); + } + t1 = VT_VLA; + } + } + skip (']'); + /* parse next post type */ + post_type (type, ad); - /* we push an anonymous symbol which will contain the array - element type */ -arraysize = n; + /* we push an anonymous symbol which will contain the array + element type */ + arraysize = n; #if 0 -if (n<0) { - printf ("array with no size []\n"); -} else { - printf ("PUSH SIZE %d\n", n); -} + if (n < 0) { + printf ("array with no size []\n"); + } else { + printf ("PUSH SIZE %d\n", n); + } #endif - s = sym_push(SYM_FIELD, type, 0, n); - type->t = (t1 ? VT_VLA : VT_ARRAY) | VT_PTR; - type->ref = s; - } + s = sym_push (SYM_FIELD, type, 0, n); + type->t = (t1? VT_VLA: VT_ARRAY) | VT_PTR; + type->ref = s; + } } /* Parse a type declaration (except basic type), and return the type @@ -1537,749 +1610,773 @@ if (n<0) { */ static void type_decl(CType *type, AttributeDef *ad, int *v, int td) { - Sym *s; - int qualifiers, storage; - CType *type1 = R_NEW0(CType); - CType *type2 = R_NEW0(CType); + Sym *s; + int qualifiers, storage; + CType *type1 = R_NEW0 (CType); + CType *type2 = R_NEW0 (CType); if (!type1 || !type2) { -free (type1); -free (type2); -return; -} + free (type1); + free (type2); + return; + } - while (tok == '*') { - qualifiers = 0; - redo: - next(); - switch(tok) { - case TOK_CONST1: - case TOK_CONST2: - case TOK_CONST3: - qualifiers |= VT_CONSTANT; - goto redo; - case TOK_VOLATILE1: - case TOK_VOLATILE2: - case TOK_VOLATILE3: - qualifiers |= VT_VOLATILE; - goto redo; - case TOK_RESTRICT1: - case TOK_RESTRICT2: - case TOK_RESTRICT3: - goto redo; - } - mk_pointer(type); - type->t |= qualifiers; - } + while (tok == '*') { + qualifiers = 0; +redo: + next (); + switch (tok) { + case TOK_CONST1: + case TOK_CONST2: + case TOK_CONST3: + qualifiers |= VT_CONSTANT; + goto redo; + case TOK_VOLATILE1: + case TOK_VOLATILE2: + case TOK_VOLATILE3: + qualifiers |= VT_VOLATILE; + goto redo; + case TOK_RESTRICT1: + case TOK_RESTRICT2: + case TOK_RESTRICT3: + goto redo; + } + mk_pointer (type); + type->t |= qualifiers; + } - /* XXX: clarify attribute handling */ - if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) - parse_attribute(ad); + /* XXX: clarify attribute handling */ + if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) { + parse_attribute (ad); + } - /* recursive type */ - /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ - type1->t = 0; /* XXX: same as int */ - if (tok == '(') { - next(); - /* XXX: this is not correct to modify 'ad' at this point, but - the syntax is not clear */ - if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) - parse_attribute(ad); - type_decl(type1, ad, v, td); - skip(')'); - } else { - /* type identifier */ - if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { - *v = tok; - next(); - } else { - if (!(td & TYPE_ABSTRACT)) - expect("identifier"); - *v = 0; - } - } - storage = type->t & VT_STORAGE; - type->t &= ~VT_STORAGE; - if (storage & VT_STATIC) { - int saved_nocode_wanted = nocode_wanted; - nocode_wanted = 1; -//eprintf ("STATIC %s\n", get_tok_str(*v, NULL)); - post_type(type, ad); - nocode_wanted = saved_nocode_wanted; - } else { - static char kind[1024]; - char *name = get_tok_str (*v, NULL); - type_to_str (kind, sizeof(kind), type, NULL); - //eprintf ("---%d %s STATIC %s\n", td, kind, name); - global_symname = name; - global_type = kind; - post_type(type, ad); - } - type->t |= storage; - if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) - parse_attribute(ad); + /* recursive type */ + /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ + type1->t = 0; /* XXX: same as int */ + if (tok == '(') { + next (); + /* XXX: this is not correct to modify 'ad' at this point, but + the syntax is not clear */ + if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) { + parse_attribute (ad); + } + type_decl (type1, ad, v, td); + skip (')'); + } else { + /* type identifier */ + if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { + *v = tok; + next (); + } else { + if (!(td & TYPE_ABSTRACT)) { + expect ("identifier"); + } + *v = 0; + } + } + storage = type->t & VT_STORAGE; + type->t &= ~VT_STORAGE; + if (storage & VT_STATIC) { + int saved_nocode_wanted = nocode_wanted; + nocode_wanted = 1; +// eprintf ("STATIC %s\n", get_tok_str(*v, NULL)); + post_type (type, ad); + nocode_wanted = saved_nocode_wanted; + } else { + static char kind[1024]; + char *name = get_tok_str (*v, NULL); + type_to_str (kind, sizeof(kind), type, NULL); + // eprintf ("---%d %s STATIC %s\n", td, kind, name); + global_symname = name; + global_type = kind; + post_type (type, ad); + } + type->t |= storage; + if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) { + parse_attribute (ad); + } - if (!type1->t) { -free (type1); -free (type2); - return; - } - /* append type at the end of type1 */ - type2 = type1; - for(;;) { - s = type2->ref; - type2 = &s->type; - if (!type2->t) { - *type2 = *type; - break; - } - } - memcpy(type, type1, sizeof(*type)); + if (!type1->t) { + free (type1); + free (type2); + return; + } + /* append type at the end of type1 */ + type2 = type1; + for (;;) { + s = type2->ref; + type2 = &s->type; + if (!type2->t) { + *type2 = *type; + break; + } + } + memcpy (type, type1, sizeof(*type)); } /* compute the lvalue VT_LVAL_xxx needed to match type t. */ ST_FUNC int lvalue_type(int t) { - int bt, r; - r = VT_LVAL; - bt = t & VT_BTYPE; - if (bt == VT_INT8 || bt == VT_BOOL) - r |= VT_LVAL_BYTE; - else if (bt == VT_INT16) - r |= VT_LVAL_SHORT; - else - return r; - if (t & VT_UNSIGNED) - r |= VT_LVAL_UNSIGNED; - return r; + int bt, r; + r = VT_LVAL; + bt = t & VT_BTYPE; + if (bt == VT_INT8 || bt == VT_BOOL) { + r |= VT_LVAL_BYTE; + } else if (bt == VT_INT16) { + r |= VT_LVAL_SHORT; + } else { + return r; + } + if (t & VT_UNSIGNED) { + r |= VT_LVAL_UNSIGNED; + } + return r; } /* indirection with full error checking and bound check */ ST_FUNC void indir(void) { - if ((vtop->type.t & VT_BTYPE) != VT_PTR) { - if ((vtop->type.t & VT_BTYPE) == VT_FUNC) - return; - expect("pointer"); - } - vtop->type = *pointed_type(&vtop->type); - /* Arrays and functions are never lvalues */ - if (!(vtop->type.t & VT_ARRAY) && !(vtop->type.t & VT_VLA) - && (vtop->type.t & VT_BTYPE) != VT_FUNC) { - vtop->r |= lvalue_type(vtop->type.t); - /* if bound checking, the referenced pointer must be checked */ + if ((vtop->type.t & VT_BTYPE) != VT_PTR) { + if ((vtop->type.t & VT_BTYPE) == VT_FUNC) { + return; + } + expect ("pointer"); + } + vtop->type = *pointed_type (&vtop->type); + /* Arrays and functions are never lvalues */ + if (!(vtop->type.t & VT_ARRAY) && !(vtop->type.t & VT_VLA) + && (vtop->type.t & VT_BTYPE) != VT_FUNC) { + vtop->r |= lvalue_type (vtop->type.t); + /* if bound checking, the referenced pointer must be checked */ #ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - vtop->r |= VT_MUSTBOUND; + if (tcc_state->do_bounds_check) { + vtop->r |= VT_MUSTBOUND; + } #endif - } + } } /* parse an expression of the form '(type)' or '(expr)' and return its type */ static void parse_expr_type(CType *type) { - int n; - AttributeDef ad; + int n; + AttributeDef ad; - skip('('); - if (parse_btype(type, &ad)) { - type_decl(type, &ad, &n, TYPE_ABSTRACT); - } else { - expr_type(type); - } - skip(')'); + skip ('('); + if (parse_btype (type, &ad)) { + type_decl (type, &ad, &n, TYPE_ABSTRACT); + } else { + expr_type (type); + } + skip (')'); } static void parse_type(CType *type) { - AttributeDef ad; - int n; + AttributeDef ad; + int n; - if (!parse_btype(type, &ad)) { - expect("type"); - } - type_decl(type, &ad, &n, TYPE_ABSTRACT); + if (!parse_btype (type, &ad)) { + expect ("type"); + } + type_decl (type, &ad, &n, TYPE_ABSTRACT); } static void vpush_tokc(int t) { - CType type; - type.t = t; - type.ref = NULL; - vsetc(&type, VT_CONST, &tokc); + CType type; + type.t = t; + type.ref = NULL; + vsetc (&type, VT_CONST, &tokc); } ST_FUNC void unary(void) { - int n, t, align, size, r, sizeof_caller; - CType type; - Sym *s; - AttributeDef ad; - static int in_sizeof = 0; + int n, t, align, size, r, sizeof_caller; + CType type; + Sym *s; + AttributeDef ad; + static int in_sizeof = 0; - sizeof_caller = in_sizeof; - in_sizeof = 0; - /* XXX: GCC 2.95.3 does not generate a table although it should be - better here */ - tok_next: - switch(tok) { - case TOK_EXTENSION: - next(); - goto tok_next; - case TOK_CINT: - case TOK_CCHAR: - case TOK_LCHAR: - vpushi(tokc.i); - next(); - break; - case TOK_CUINT: - vpush_tokc(VT_INT32 | VT_UNSIGNED); - next(); - break; - case TOK_CLLONG: - vpush_tokc(VT_INT64); - next(); - break; - case TOK_CULLONG: - vpush_tokc(VT_INT64 | VT_UNSIGNED); - next(); - break; - case TOK_CFLOAT: - vpush_tokc(VT_FLOAT); - next(); - break; - case TOK_CDOUBLE: - vpush_tokc(VT_DOUBLE); - next(); - break; - case TOK_CLDOUBLE: - vpush_tokc(VT_LDOUBLE); - next(); - break; - case TOK___FUNCTION__: - if (!gnu_ext) - goto tok_identifier; - /* fall thru */ - case TOK___FUNC__: - { - // void *ptr = NULL; - int len; - /* special function name identifier */ - len = strlen(funcname) + 1; - /* generate char[len] type */ - type.t = VT_INT8; - mk_pointer(&type); - type.t |= VT_ARRAY; - type.ref->c = len; - // XXX ptr is NULL HERE WTF - // memcpy(ptr, funcname, len); - next(); - } - break; - case TOK_LSTR: - if (!strncmp(tcc_state->os, "windows", 7)) { + sizeof_caller = in_sizeof; + in_sizeof = 0; + /* XXX: GCC 2.95.3 does not generate a table although it should be + better here */ +tok_next: + switch (tok) { + case TOK_EXTENSION: + next (); + goto tok_next; + case TOK_CINT: + case TOK_CCHAR: + case TOK_LCHAR: + vpushi (tokc.i); + next (); + break; + case TOK_CUINT: + vpush_tokc (VT_INT32 | VT_UNSIGNED); + next (); + break; + case TOK_CLLONG: + vpush_tokc (VT_INT64); + next (); + break; + case TOK_CULLONG: + vpush_tokc (VT_INT64 | VT_UNSIGNED); + next (); + break; + case TOK_CFLOAT: + vpush_tokc (VT_FLOAT); + next (); + break; + case TOK_CDOUBLE: + vpush_tokc (VT_DOUBLE); + next (); + break; + case TOK_CLDOUBLE: + vpush_tokc (VT_LDOUBLE); + next (); + break; + case TOK___FUNCTION__: + if (!gnu_ext) { + goto tok_identifier; + } + /* fall thru */ + case TOK___FUNC__: + { + // void *ptr = NULL; + int len; + /* special function name identifier */ + len = strlen (funcname) + 1; + /* generate char[len] type */ + type.t = VT_INT8; + mk_pointer (&type); + type.t |= VT_ARRAY; + type.ref->c = len; + // XXX ptr is NULL HERE WTF + // memcpy(ptr, funcname, len); + next (); + } + break; + case TOK_LSTR: + if (!strncmp (tcc_state->os, "windows", 7)) { t = VT_INT16 | VT_UNSIGNED; } else { t = VT_INT32; } - goto str_init; - case TOK_STR: - /* string parsing */ - t = VT_INT8; - str_init: - if (tcc_state->warn_write_strings) - t |= VT_CONSTANT; - type.t = t; - mk_pointer(&type); - type.t |= VT_ARRAY; - memset(&ad, 0, sizeof(AttributeDef)); - decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, NULL, 0); - break; - case '(': - next(); - /* cast ? */ - if (parse_btype(&type, &ad)) { - type_decl(&type, &ad, &n, TYPE_ABSTRACT); - skip(')'); - /* check ISOC99 compound literal */ - if (tok == '{') { - /* data is allocated locally by default */ - if (global_expr) - r = VT_CONST; - else - r = VT_LOCAL; - /* all except arrays are lvalues */ - if (!(type.t & VT_ARRAY)) - r |= lvalue_type(type.t); - memset(&ad, 0, sizeof(AttributeDef)); - decl_initializer_alloc(&type, &ad, r, 1, 0, NULL, 0); - } else { - if (sizeof_caller) { - vpush(&type); - return; - } - unary(); - } - } else if (tok == '{') { - /* statement expression : we do not accept break/continue - inside as GCC does */ - skip(')'); - } else { - gexpr(); - skip(')'); - } - break; - case '*': - next(); - unary(); - indir(); - break; - case '!': - next(); - unary(); - if ((vtop->r & VT_VALMASK) == VT_CMP) - vtop->c.i = vtop->c.i ^ 1; - break; - case TOK_SIZEOF: - case TOK_ALIGNOF1: - case TOK_ALIGNOF2: - t = tok; - next(); - in_sizeof++; - unary_type(&type); // Perform a in_sizeof = 0; - size = type_size(&type, &align); - if (t == TOK_SIZEOF) { - if (!(type.t & VT_VLA)) { - if (size < 0) - tcc_error("sizeof applied to an incomplete type"); - vpushs(size); + goto str_init; + case TOK_STR: + /* string parsing */ + t = VT_INT8; +str_init: + if (tcc_state->warn_write_strings) { + t |= VT_CONSTANT; + } + type.t = t; + mk_pointer (&type); + type.t |= VT_ARRAY; + memset (&ad, 0, sizeof(AttributeDef)); + decl_initializer_alloc (&type, &ad, VT_CONST, 2, 0, NULL, 0); + break; + case '(': + next (); + /* cast ? */ + if (parse_btype (&type, &ad)) { + type_decl (&type, &ad, &n, TYPE_ABSTRACT); + skip (')'); + /* check ISOC99 compound literal */ + if (tok == '{') { + /* data is allocated locally by default */ + if (global_expr) { + r = VT_CONST; + } else { + r = VT_LOCAL; + } + /* all except arrays are lvalues */ + if (!(type.t & VT_ARRAY)) { + r |= lvalue_type (type.t); + } + memset (&ad, 0, sizeof(AttributeDef)); + decl_initializer_alloc (&type, &ad, r, 1, 0, NULL, 0); + } else { + if (sizeof_caller) { + vpush (&type); + return; + } + unary (); } - } else { - vpushs(align); - } - vtop->type.t |= VT_UNSIGNED; - break; + } else if (tok == '{') { + /* statement expression : we do not accept break/continue + inside as GCC does */ + skip (')'); + } else { + gexpr (); + skip (')'); + } + break; + case '*': + next (); + unary (); + indir (); + break; + case '!': + next (); + unary (); + if ((vtop->r & VT_VALMASK) == VT_CMP) { + vtop->c.i = vtop->c.i ^ 1; + } + break; + case TOK_SIZEOF: + case TOK_ALIGNOF1: + case TOK_ALIGNOF2: + t = tok; + next (); + in_sizeof++; + unary_type (&type); // Perform a in_sizeof = 0; + size = type_size (&type, &align); + if (t == TOK_SIZEOF) { + if (!(type.t & VT_VLA)) { + if (size < 0) { + tcc_error ("sizeof applied to an incomplete type"); + } + vpushs (size); + } + } else { + vpushs (align); + } + vtop->type.t |= VT_UNSIGNED; + break; - case TOK_builtin_types_compatible_p: - { - STACK_NEW0(CType, type1); - STACK_NEW0(CType, type2); - next(); - skip('('); - parse_type(&type1); - skip(','); - parse_type(&type2); - skip(')'); - type1.t &= ~(VT_CONSTANT | VT_VOLATILE); - type2.t &= ~(VT_CONSTANT | VT_VOLATILE); - vpushi(is_compatible_types(&type1, &type2)); - } - break; - case TOK_builtin_constant_p: - { - int saved_nocode_wanted; - long long res; - next(); - skip('('); - saved_nocode_wanted = nocode_wanted; - nocode_wanted = 1; - gexpr(); - res = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - nocode_wanted = saved_nocode_wanted; - skip(')'); - vpushll(res); - } - break; - case TOK_builtin_frame_address: - { - int level; - CType type; - next(); - skip('('); - if (tok != TOK_CINT || tokc.i < 0) { - tcc_error("__builtin_frame_address only takes positive integers"); - } - level = tokc.i; - next(); - skip(')'); - type.t = VT_VOID; - mk_pointer(&type); - vset(&type, VT_LOCAL, 0); /* local frame */ - while (level--) { - mk_pointer(&vtop->type); - indir(); /* -> parent frame */ - } - } - break; - case TOK_builtin_va_start: - if (!strncmp(tcc_state->arch, "x86", 3) && tcc_state->bits == 64 && - !strncmp(tcc_state->os, "windows", 7)) { - next(); - skip('('); - expr_eq(); - skip(','); - expr_eq(); - skip(')'); - if ((vtop->r & VT_VALMASK) != VT_LOCAL) - tcc_error("__builtin_va_start expects a local variable"); - vtop->r &= ~(VT_LVAL | VT_REF); - vtop->type = char_pointer_type; - } - break; - case TOK_builtin_va_arg_types: - if (!(!strncmp(tcc_state->arch, "x86", 3) && tcc_state->bits == 64 && - !strncmp(tcc_state->os, "windows", 7))) { - CType type; - next(); - skip('('); - parse_type(&type); - skip(')'); + case TOK_builtin_types_compatible_p: + { + STACK_NEW0 (CType, type1); + STACK_NEW0 (CType, type2); + next (); + skip ('('); + parse_type (&type1); + skip (','); + parse_type (&type2); + skip (')'); + type1.t &= ~(VT_CONSTANT | VT_VOLATILE); + type2.t &= ~(VT_CONSTANT | VT_VOLATILE); + vpushi (is_compatible_types (&type1, &type2)); + } + break; + case TOK_builtin_constant_p: + { + int saved_nocode_wanted; + long long res; + next (); + skip ('('); + saved_nocode_wanted = nocode_wanted; + nocode_wanted = 1; + gexpr (); + res = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + nocode_wanted = saved_nocode_wanted; + skip (')'); + vpushll (res); + } + break; + case TOK_builtin_frame_address: + { + int level; + CType type; + next (); + skip ('('); + if (tok != TOK_CINT || tokc.i < 0) { + tcc_error ("__builtin_frame_address only takes positive integers"); + } + level = tokc.i; + next (); + skip (')'); + type.t = VT_VOID; + mk_pointer (&type); + vset (&type, VT_LOCAL, 0); /* local frame */ + while (level--) { + mk_pointer (&vtop->type); + indir (); /* -> parent frame */ + } + } + break; + case TOK_builtin_va_start: + if (!strncmp (tcc_state->arch, "x86", 3) && tcc_state->bits == 64 && + !strncmp (tcc_state->os, "windows", 7)) { + next (); + skip ('('); + expr_eq (); + skip (','); + expr_eq (); + skip (')'); + if ((vtop->r & VT_VALMASK) != VT_LOCAL) { + tcc_error ("__builtin_va_start expects a local variable"); + } + vtop->r &= ~(VT_LVAL | VT_REF); + vtop->type = char_pointer_type; + } + break; + case TOK_builtin_va_arg_types: + if (!(!strncmp (tcc_state->arch, "x86", 3) && tcc_state->bits == 64 && + !strncmp (tcc_state->os, "windows", 7))) { + CType type; + next (); + skip ('('); + parse_type (&type); + skip (')'); // FIXME: Handle this too - //vpushll(classify_x86_64_va_arg(&type)); - } - break; + // vpushll(classify_x86_64_va_arg(&type)); + } + break; - // special qnan , snan and infinity values - case TOK___NAN__: - vpush64(VT_DOUBLE, 0x7ff8000000000000ULL); - next(); - break; - case TOK___SNAN__: - vpush64(VT_DOUBLE, 0x7ff0000000000001ULL); - next(); - break; - case TOK___INF__: - vpush64(VT_DOUBLE, 0x7ff0000000000000ULL); - next(); - break; + // special qnan , snan and infinity values + case TOK___NAN__: + vpush64 (VT_DOUBLE, 0x7ff8000000000000ULL); + next (); + break; + case TOK___SNAN__: + vpush64 (VT_DOUBLE, 0x7ff0000000000001ULL); + next (); + break; + case TOK___INF__: + vpush64 (VT_DOUBLE, 0x7ff0000000000000ULL); + next (); + break; - default: - tok_identifier: - t = tok; - next(); - if (t < TOK_UIDENT) - expect("identifier"); - s = sym_find(t); - if (!s) { - if (tok != '(') - tcc_error("'%s' undeclared", get_tok_str(t, NULL)); - } - if (!s) { - tcc_error("invalid declaration '%s'", get_tok_str(t, NULL)); - } - if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) == - (VT_STATIC | VT_INLINE | VT_FUNC)) { - /* if referencing an inline function, then we generate a - symbol to it if not already done. It will have the - effect to generate code for it at the end of the - compilation unit. */ - r = VT_SYM | VT_CONST; - } else { - r = s->r; - } - vset(&s->type, r, s->c); - /* if forward reference, we must point to s */ - if (vtop->r & VT_SYM) { - vtop->sym = s; - vtop->c.ul = 0; - } - break; - } + default: +tok_identifier: + t = tok; + next (); + if (t < TOK_UIDENT) { + expect ("identifier"); + } + s = sym_find (t); + if (!s) { + if (tok != '(') { + tcc_error ("'%s' undeclared", get_tok_str (t, NULL)); + } + } + if (!s) { + tcc_error ("invalid declaration '%s'", get_tok_str (t, NULL)); + } + if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) == + (VT_STATIC | VT_INLINE | VT_FUNC)) { + /* if referencing an inline function, then we generate a + symbol to it if not already done. It will have the + effect to generate code for it at the end of the + compilation unit. */ + r = VT_SYM | VT_CONST; + } else { + r = s->r; + } + vset (&s->type, r, s->c); + /* if forward reference, we must point to s */ + if (vtop->r & VT_SYM) { + vtop->sym = s; + vtop->c.ul = 0; + } + break; + } - /* post operations */ - while (1) { - if (tok == '.' || tok == TOK_ARROW) { - int qualifiers; - /* field */ - if (tok == TOK_ARROW) - indir(); - qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); - test_lvalue(); - gaddrof(); - next(); - /* expect pointer on structure */ - if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) - expect("struct or union"); - s = vtop->type.ref; - /* find field */ - tok |= SYM_FIELD; - while ((s = s->next) != NULL) { - if (s->v == tok) - break; - } - if (!s) { - tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, NULL)); - } - /* add field offset to pointer */ - vtop->type = char_pointer_type; /* change type to 'char *' */ - vpushi(s->c); - /* change type to field type, and set to lvalue */ - vtop->type = s->type; - vtop->type.t |= qualifiers; - /* an array is never an lvalue */ - if (!(vtop->type.t & VT_ARRAY)) { - vtop->r |= lvalue_type(vtop->type.t); + /* post operations */ + while (1) { + if (tok == '.' || tok == TOK_ARROW) { + int qualifiers; + /* field */ + if (tok == TOK_ARROW) { + indir (); + } + qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); + test_lvalue (); + gaddrof (); + next (); + /* expect pointer on structure */ + if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) { + expect ("struct or union"); + } + s = vtop->type.ref; + /* find field */ + tok |= SYM_FIELD; + while ((s = s->next) != NULL) { + if (s->v == tok) { + break; + } + } + if (!s) { + tcc_error ("field not found: %s", get_tok_str (tok & ~SYM_FIELD, NULL)); + } + /* add field offset to pointer */ + vtop->type = char_pointer_type; /* change type to 'char *' */ + vpushi (s->c); + /* change type to field type, and set to lvalue */ + vtop->type = s->type; + vtop->type.t |= qualifiers; + /* an array is never an lvalue */ + if (!(vtop->type.t & VT_ARRAY)) { + vtop->r |= lvalue_type (vtop->type.t); #ifdef CONFIG_TCC_BCHECK - /* if bound checking, the referenced pointer must be checked */ - if (tcc_state->do_bounds_check) - vtop->r |= VT_MUSTBOUND; + /* if bound checking, the referenced pointer must be checked */ + if (tcc_state->do_bounds_check) { + vtop->r |= VT_MUSTBOUND; + } #endif - } - next(); - } else if (tok == '[') { - next(); - gexpr(); - indir(); - skip(']'); - /* - } else if (tok == '(') { - SValue ret; - Sym *sa; - int nb_args, sret; - */ - } else { - break; - } - } + } + next (); + } else if (tok == '[') { + next (); + gexpr (); + indir (); + skip (']'); + /* + } else if (tok == '(') { + SValue ret; + Sym *sa; + int nb_args, sret; + */ + } else { + break; + } + } } ST_FUNC void expr_prod(void) { - unary(); - while (tok == '*' || tok == '/' || tok == '%') { - next(); - unary(); - } + unary (); + while (tok == '*' || tok == '/' || tok == '%') { + next (); + unary (); + } } ST_FUNC void expr_sum(void) { - expr_prod(); - while (tok == '+' || tok == '-') { - next(); - expr_prod(); - } + expr_prod (); + while (tok == '+' || tok == '-') { + next (); + expr_prod (); + } } static void expr_shift(void) { - expr_sum(); - while (tok == TOK_SHL || tok == TOK_SAR) { - next(); - expr_sum(); - } + expr_sum (); + while (tok == TOK_SHL || tok == TOK_SAR) { + next (); + expr_sum (); + } } static void expr_cmp(void) { - expr_shift(); - while ((tok >= TOK_ULE && tok <= TOK_GT) || - tok == TOK_ULT || tok == TOK_UGE) { - next(); - expr_shift(); - } + expr_shift (); + while ((tok >= TOK_ULE && tok <= TOK_GT) || + tok == TOK_ULT || tok == TOK_UGE) { + next (); + expr_shift (); + } } static void expr_cmpeq(void) { - expr_cmp(); - while (tok == TOK_EQ || tok == TOK_NE) { - next(); - expr_cmp(); - } + expr_cmp (); + while (tok == TOK_EQ || tok == TOK_NE) { + next (); + expr_cmp (); + } } static void expr_and(void) { - expr_cmpeq(); - while (tok == '&') { - next(); - expr_cmpeq(); - } + expr_cmpeq (); + while (tok == '&') { + next (); + expr_cmpeq (); + } } static void expr_xor(void) { - expr_and(); - while (tok == '^') { - next(); - expr_and(); - } + expr_and (); + while (tok == '^') { + next (); + expr_and (); + } } static void expr_or(void) { - expr_xor(); - while (tok == '|') { - next(); - expr_xor(); - } + expr_xor (); + while (tok == '|') { + next (); + expr_xor (); + } } /* XXX: fix this mess */ static void expr_land_const(void) { - expr_or(); - while (tok == TOK_LAND) { - next(); - expr_or(); - } + expr_or (); + while (tok == TOK_LAND) { + next (); + expr_or (); + } } /* XXX: fix this mess */ static void expr_lor_const(void) { - expr_land_const(); - while (tok == TOK_LOR) { - next(); - expr_land_const(); - } + expr_land_const (); + while (tok == TOK_LOR) { + next (); + expr_land_const (); + } } /* only used if non constant */ static void expr_land(void) { - expr_or(); - if (tok == TOK_LAND) { - for(;;) { - if (tok != TOK_LAND) { - break; - } - next(); - expr_or(); - } - } + expr_or (); + if (tok == TOK_LAND) { + for (;;) { + if (tok != TOK_LAND) { + break; + } + next (); + expr_or (); + } + } } static void expr_lor(void) { - expr_land(); - if (tok == TOK_LOR) { - for(;;) { - if (tok != TOK_LOR) { - break; - } - next(); - expr_land(); - } - } + expr_land (); + if (tok == TOK_LOR) { + for (;;) { + if (tok != TOK_LOR) { + break; + } + next (); + expr_land (); + } + } } /* XXX: better constant handling */ static void expr_cond(void) { - if (const_wanted) { - expr_lor_const(); - if (tok == '?') { - vdup(); - next(); - if (tok != ':' || !gnu_ext) { - gexpr(); - } - skip(':'); - expr_cond(); - } - } else { - expr_lor(); - } + if (const_wanted) { + expr_lor_const (); + if (tok == '?') { + vdup (); + next (); + if (tok != ':' || !gnu_ext) { + gexpr (); + } + skip (':'); + expr_cond (); + } + } else { + expr_lor (); + } } static void expr_eq(void) { - int t; + int t; - expr_cond(); - if (tok == '=' || - (tok >= TOK_A_MOD && tok <= TOK_A_DIV) || - tok == TOK_A_XOR || tok == TOK_A_OR || - tok == TOK_A_SHL || tok == TOK_A_SAR) { - test_lvalue(); - t = tok; - next(); - if (t == '=') { - expr_eq(); - } else { - vdup(); - expr_eq(); - } - } + expr_cond (); + if (tok == '=' || + (tok >= TOK_A_MOD && tok <= TOK_A_DIV) || + tok == TOK_A_XOR || tok == TOK_A_OR || + tok == TOK_A_SHL || tok == TOK_A_SAR) { + test_lvalue (); + t = tok; + next (); + if (t == '=') { + expr_eq (); + } else { + vdup (); + expr_eq (); + } + } } ST_FUNC void gexpr(void) { - while (1) { - expr_eq(); - if (tok != ',') - break; - next(); - } + while (1) { + expr_eq (); + if (tok != ',') { + break; + } + next (); + } } /* parse an expression and return its type without any side effect. */ static void expr_type(CType *type) { - int saved_nocode_wanted; + int saved_nocode_wanted; - saved_nocode_wanted = nocode_wanted; - nocode_wanted = 1; - gexpr(); - *type = vtop->type; - nocode_wanted = saved_nocode_wanted; + saved_nocode_wanted = nocode_wanted; + nocode_wanted = 1; + gexpr (); + *type = vtop->type; + nocode_wanted = saved_nocode_wanted; } /* parse a unary expression and return its type without any side effect. */ static void unary_type(CType *type) { - int a; + int a; - a = nocode_wanted; - nocode_wanted = 1; - unary(); - *type = vtop->type; - nocode_wanted = a; + a = nocode_wanted; + nocode_wanted = 1; + unary (); + *type = vtop->type; + nocode_wanted = a; } /* parse a constant expression and return value in vtop. */ static void expr_const1(void) { - int a; - a = const_wanted; - const_wanted = 1; - expr_cond(); - const_wanted = a; + int a; + a = const_wanted; + const_wanted = 1; + expr_cond (); + const_wanted = a; } /* parse an integer constant and return its value. */ ST_FUNC long long expr_const(void) { - long long c = 0LL; - expr_const1(); - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) - expect("constant expression"); - c = vtop->c.ll; - return c; + long long c = 0LL; + expr_const1 (); + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) { + expect ("constant expression"); + } + c = vtop->c.ll; + return c; } /* return the label token if current token is a label, otherwise return zero */ static int is_label(void) { - int last_tok; + int last_tok; - /* fast test first */ - if (tok < TOK_UIDENT) - return 0; - /* no need to save tokc because tok is an identifier */ - last_tok = tok; - next(); - if (tok == ':') { - next(); - return last_tok; - } else { - unget_tok(last_tok); - return 0; - } + /* fast test first */ + if (tok < TOK_UIDENT) { + return 0; + } + /* no need to save tokc because tok is an identifier */ + last_tok = tok; + next (); + if (tok == ':') { + next (); + return last_tok; + } else { + unget_tok (last_tok); + return 0; + } } /* t is the array or struct type. c is the array or struct @@ -2287,103 +2384,114 @@ static int is_label(void) value. 'size_only' is true if only size info is needed (only used in arrays) */ static void decl_designator(CType *type, unsigned long c, - long long *cur_index, Sym **cur_field, - int size_only) + long long *cur_index, Sym **cur_field, + int size_only) { - Sym *s, *f = NULL; - long long index, index_last; - int notfirst, align, l, nb_elems, elem_size; - STACK_NEW0(CType, type1); + Sym *s, *f = NULL; + long long index, index_last; + int notfirst, align, l, nb_elems, elem_size; + STACK_NEW0 (CType, type1); - notfirst = 0; - if (gnu_ext && (l = is_label()) != 0) - goto struct_field; - while (tok == '[' || tok == '.') { - if (tok == '[') { - if (!(type->t & VT_ARRAY)) - expect("array type"); - s = type->ref; - next(); - index = expr_const(); - if (index < 0 || (s->c >= 0 && index >= s->c)) - expect("invalid index"); - if (tok == TOK_DOTS && gnu_ext) { - next(); - index_last = expr_const(); - if (index_last < 0 || - (s->c >= 0 && index_last >= s->c) || - index_last < index) - expect("invalid index"); - } else { - index_last = index; - } - skip(']'); - if (!notfirst) - *cur_index = index_last; - type = pointed_type(type); - elem_size = type_size(type, &align); - c += index * elem_size; - /* NOTE: we only support ranges for last designator */ - nb_elems = index_last - index + 1; - if (nb_elems != 1) { - notfirst = 1; - break; - } - } else { - next(); - l = tok; - next(); - struct_field: - if ((type->t & VT_BTYPE) != VT_STRUCT) - expect("struct/union type"); - s = type->ref; - l |= SYM_FIELD; - f = s->next; - while (f) { - if (f->v == l) - break; - f = f->next; - } - if (!f) - expect("field"); - if (!notfirst) - *cur_field = f; - /* XXX: fix this mess by using explicit storage field */ -if (f) { - type1 = f->type; - type1.t |= (type->t & ~VT_TYPE); - type = &type1; - c += f->c; -} - } - notfirst = 1; - } - if (notfirst) { - if (tok == '=') { - next(); - } else { - if (!gnu_ext) - expect("="); - } - } else { - if (type->t & VT_ARRAY) { - index = *cur_index; - type = pointed_type(type); - c += index * type_size(type, &align); - } else { - f = *cur_field; - if (!f) - tcc_error("too many field init"); - /* XXX: fix this mess by using explicit storage field */ -if (f) { - type1 = f->type; - type1.t |= (type->t & ~VT_TYPE); - type = &type1; - c += f->c; -} - } - } - decl_initializer(type, c, 0, size_only); + notfirst = 0; + if (gnu_ext && (l = is_label ()) != 0) { + goto struct_field; + } + while (tok == '[' || tok == '.') { + if (tok == '[') { + if (!(type->t & VT_ARRAY)) { + expect ("array type"); + } + s = type->ref; + next (); + index = expr_const (); + if (index < 0 || (s->c >= 0 && index >= s->c)) { + expect ("invalid index"); + } + if (tok == TOK_DOTS && gnu_ext) { + next (); + index_last = expr_const (); + if (index_last < 0 || + (s->c >= 0 && index_last >= s->c) || + index_last < index) { + expect ("invalid index"); + } + } else { + index_last = index; + } + skip (']'); + if (!notfirst) { + *cur_index = index_last; + } + type = pointed_type (type); + elem_size = type_size (type, &align); + c += index * elem_size; + /* NOTE: we only support ranges for last designator */ + nb_elems = index_last - index + 1; + if (nb_elems != 1) { + notfirst = 1; + break; + } + } else { + next (); + l = tok; + next (); +struct_field: + if ((type->t & VT_BTYPE) != VT_STRUCT) { + expect ("struct/union type"); + } + s = type->ref; + l |= SYM_FIELD; + f = s->next; + while (f) { + if (f->v == l) { + break; + } + f = f->next; + } + if (!f) { + expect ("field"); + } + if (!notfirst) { + *cur_field = f; + } + /* XXX: fix this mess by using explicit storage field */ + if (f) { + type1 = f->type; + type1.t |= (type->t & ~VT_TYPE); + type = &type1; + c += f->c; + } + } + notfirst = 1; + } + if (notfirst) { + if (tok == '=') { + next (); + } else { + if (!gnu_ext) { + expect ("="); + } + } + } else { + if (type->t & VT_ARRAY) { + index = *cur_index; + type = pointed_type (type); + c += index * type_size (type, &align); + } else { + f = *cur_field; + if (!f) { + tcc_error ("too many field init"); + } + /* XXX: fix this mess by using explicit storage field */ + if (f) { + type1 = f->type; + type1.t |= (type->t & ~VT_TYPE); + type = &type1; + c += f->c; + } + } + } + decl_initializer (type, c, 0, size_only); } #define EXPR_VAL 0 @@ -2392,43 +2500,44 @@ if (f) { /* store a value or an expression directly in global data or in local array */ static void init_putv(CType *type, unsigned long c, - long long v, int expr_type) + long long v, int expr_type) { - int saved_global_expr; - CType dtype; + int saved_global_expr; + CType dtype; - switch(expr_type) { - case EXPR_VAL: - vpushll(v); - break; - case EXPR_CONST: - /* compound literals must be allocated globally in this case */ - saved_global_expr = global_expr; - global_expr = 1; - expr_const1(); - global_expr = saved_global_expr; - /* NOTE: symbols are accepted */ - if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST) - tcc_error("initializer element is not constant"); - break; - case EXPR_ANY: - expr_eq(); - break; - } + switch (expr_type) { + case EXPR_VAL: + vpushll (v); + break; + case EXPR_CONST: + /* compound literals must be allocated globally in this case */ + saved_global_expr = global_expr; + global_expr = 1; + expr_const1 (); + global_expr = saved_global_expr; + /* NOTE: symbols are accepted */ + if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST) { + tcc_error ("initializer element is not constant"); + } + break; + case EXPR_ANY: + expr_eq (); + break; + } - dtype = *type; - dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ + dtype = *type; + dtype.t &= ~VT_CONSTANT;/* need to do that to avoid false warning */ - vset(&dtype, VT_LOCAL|VT_LVAL, c); - vswap(); + vset (&dtype, VT_LOCAL | VT_LVAL, c); + vswap (); } /* put zeros for variable based init */ static void init_putz(CType *t, unsigned long c, int size) { - vseti(VT_LOCAL, c); - vpushi(0); - vpushs(size); + vseti (VT_LOCAL, c); + vpushi (0); + vpushs (size); } /* 't' contains the type and storage info. 'c' is the offset of the @@ -2437,227 +2546,247 @@ static void init_putz(CType *t, unsigned long c, int size) dimension implicit array init handling). 'size_only' is true if size only evaluation is wanted (only for arrays). */ static void decl_initializer(CType *type, unsigned long c, - int first, int size_only) + int first, int size_only) { - long long index; - int array_length, n, no_oblock, nb, parlevel, parlevel1, i; - int size1, align1, expr_type; - Sym *s, *f; - CType *t1; + long long index; + int array_length, n, no_oblock, nb, parlevel, parlevel1, i; + int size1, align1, expr_type; + Sym *s, *f; + CType *t1; - if (type->t & VT_ARRAY) { - s = type->ref; - n = s->c; - array_length = 0; - t1 = pointed_type(type); - size1 = type_size(t1, &align1); + if (type->t & VT_ARRAY) { + s = type->ref; + n = s->c; + array_length = 0; + t1 = pointed_type (type); + size1 = type_size (t1, &align1); - no_oblock = 1; - if ((first && tok != TOK_LSTR && tok != TOK_STR) || - tok == '{') { - if (tok != '{') - tcc_error("character array initializer must be a literal," - " optionally enclosed in braces"); - skip('{'); - no_oblock = 0; - } + no_oblock = 1; + if ((first && tok != TOK_LSTR && tok != TOK_STR) || + tok == '{') { + if (tok != '{') { + tcc_error ("character array initializer must be a literal," + " optionally enclosed in braces"); + } + skip ('{'); + no_oblock = 0; + } - /* only parse strings here if correct type (otherwise: handle - them as ((w)char *) expressions */ - if ((tok == TOK_LSTR && + /* only parse strings here if correct type (otherwise: handle + them as ((w)char *) expressions */ + if ((tok == TOK_LSTR && /* FIXME: Handle platform here ! */ #ifdef TCC_TARGET_PE - (t1->t & VT_BTYPE) == VT_INT16 && (t1->t & VT_UNSIGNED) + (t1->t & VT_BTYPE) == VT_INT16 && (t1->t & VT_UNSIGNED) #else - (t1->t & VT_BTYPE) == VT_INT32 + (t1->t & VT_BTYPE) == VT_INT32 #endif - ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_INT8)) { - while (tok == TOK_STR || tok == TOK_LSTR) { - int cstr_len, ch; - CString *cstr; + ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_INT8)) { + while (tok == TOK_STR || tok == TOK_LSTR) { + int cstr_len, ch; + CString *cstr; - cstr = tokc.cstr; - /* compute maximum number of chars wanted */ - if (tok == TOK_STR) - cstr_len = cstr->size; - else - cstr_len = cstr->size / sizeof(nwchar_t); - cstr_len--; - nb = cstr_len; - if (n >= 0 && nb > (n - array_length)) - nb = n - array_length; - if (!size_only) { - if (cstr_len > nb) - tcc_warning("initializer-string for array is too long"); - /* in order to go faster for common case (char - string in global variable, we handle it - specifically */ - for(i=0;idata)[i]; - else - ch = ((nwchar_t *)cstr->data)[i]; - init_putv(t1, c + (array_length + i) * size1, - ch, EXPR_VAL); - } - } - array_length += nb; - next(); - } - /* only add trailing zero if enough storage (no - warning in this case since it is standard) */ - if (n < 0 || array_length < n) { - if (!size_only) { - init_putv(t1, c + (array_length * size1), 0, EXPR_VAL); - } - array_length++; - } - } else { - index = 0; - while (tok != '}') { - decl_designator(type, c, &index, NULL, size_only); - if (n >= 0 && index >= n) - tcc_error("index too large"); - /* must put zero in holes (note that doing it that way - ensures that it even works with designators) */ - if (!size_only && array_length < index) { - init_putz(t1, c + array_length * size1, - (index - array_length) * size1); - } - index++; - if (index > array_length) - array_length = index; - /* special test for multi dimensional arrays (may not - be strictly correct if designators are used at the - same time) */ - if (index >= n && no_oblock) - break; - if (tok == '}') - break; - skip(','); - } - } - if (!no_oblock) - skip('}'); - /* put zeros at the end */ - if (!size_only && n >= 0 && array_length < n) { - init_putz(t1, c + array_length * size1, - (n - array_length) * size1); - } - /* patch type size if needed */ - if (n < 0) - s->c = array_length; - } else if ((type->t & VT_BTYPE) == VT_STRUCT && - (!first || tok == '{')) { - int par_count; + cstr = tokc.cstr; + /* compute maximum number of chars wanted */ + if (tok == TOK_STR) { + cstr_len = cstr->size; + } else { + cstr_len = cstr->size / sizeof(nwchar_t); + } + cstr_len--; + nb = cstr_len; + if (n >= 0 && nb > (n - array_length)) { + nb = n - array_length; + } + if (!size_only) { + if (cstr_len > nb) { + tcc_warning ("initializer-string for array is too long"); + } + /* in order to go faster for common case (char + string in global variable, we handle it + specifically */ + for (i = 0; i < nb; i++) { + if (tok == TOK_STR) { + ch = ((unsigned char *) cstr->data)[i]; + } else { + ch = ((nwchar_t *) cstr->data)[i]; + } + init_putv (t1, c + (array_length + i) * size1, + ch, EXPR_VAL); + } + } + array_length += nb; + next (); + } + /* only add trailing zero if enough storage (no + warning in this case since it is standard) */ + if (n < 0 || array_length < n) { + if (!size_only) { + init_putv (t1, c + (array_length * size1), 0, EXPR_VAL); + } + array_length++; + } + } else { + index = 0; + while (tok != '}') { + decl_designator (type, c, &index, NULL, size_only); + if (n >= 0 && index >= n) { + tcc_error ("index too large"); + } + /* must put zero in holes (note that doing it that way + ensures that it even works with designators) */ + if (!size_only && array_length < index) { + init_putz (t1, c + array_length * size1, + (index - array_length) * size1); + } + index++; + if (index > array_length) { + array_length = index; + } + /* special test for multi dimensional arrays (may not + be strictly correct if designators are used at the + same time) */ + if (index >= n && no_oblock) { + break; + } + if (tok == '}') { + break; + } + skip (','); + } + } + if (!no_oblock) { + skip ('}'); + } + /* put zeros at the end */ + if (!size_only && n >= 0 && array_length < n) { + init_putz (t1, c + array_length * size1, + (n - array_length) * size1); + } + /* patch type size if needed */ + if (n < 0) { + s->c = array_length; + } + } else if ((type->t & VT_BTYPE) == VT_STRUCT && + (!first || tok == '{')) { + int par_count; - /* NOTE: the previous test is a specific case for automatic - struct/union init */ - /* XXX: union needs only one init */ + /* NOTE: the previous test is a specific case for automatic + struct/union init */ + /* XXX: union needs only one init */ - /* XXX: this test is incorrect for local initializers - beginning with ( without {. It would be much more difficult - to do it correctly (ideally, the expression parser should - be used in all cases) */ - par_count = 0; - if (tok == '(') { - AttributeDef ad1; - STACK_NEW0(CType, type1); - next(); - while (tok == '(') { - par_count++; - next(); - } - if (!parse_btype(&type1, &ad1)) - expect("cast"); - type_decl(&type1, &ad1, &n, TYPE_ABSTRACT); + /* XXX: this test is incorrect for local initializers + beginning with ( without {. It would be much more difficult + to do it correctly (ideally, the expression parser should + be used in all cases) */ + par_count = 0; + if (tok == '(') { + AttributeDef ad1; + STACK_NEW0 (CType, type1); + next (); + while (tok == '(') { + par_count++; + next (); + } + if (!parse_btype (&type1, &ad1)) { + expect ("cast"); + } + type_decl (&type1, &ad1, &n, TYPE_ABSTRACT); #if 0 - if (!is_assignable_types(type, &type1)) - tcc_error("invalid type for cast"); + if (!is_assignable_types (type, &type1)) { + tcc_error ("invalid type for cast"); + } #endif - skip(')'); - } - no_oblock = 1; - if (first || tok == '{') { - skip('{'); - no_oblock = 0; - } - s = type->ref; - f = s->next; - array_length = 0; - index = 0; - n = s->c; - while (tok != '}') { - decl_designator(type, c, NULL, &f, size_only); - index = f->c; - if (!size_only && array_length < index) { - init_putz(type, c + array_length, - index - array_length); - } - index = index + type_size(&f->type, &align1); - if (index > array_length) - array_length = index; + skip (')'); + } + no_oblock = 1; + if (first || tok == '{') { + skip ('{'); + no_oblock = 0; + } + s = type->ref; + f = s->next; + array_length = 0; + index = 0; + n = s->c; + while (tok != '}') { + decl_designator (type, c, NULL, &f, size_only); + index = f->c; + if (!size_only && array_length < index) { + init_putz (type, c + array_length, + index - array_length); + } + index = index + type_size (&f->type, &align1); + if (index > array_length) { + array_length = index; + } - /* gr: skip fields from same union - ugly. */ - while (f->next) { - ///printf("index: %2d %08x -- %2d %08x\n", f->c, f->type.t, f->next->c, f->next->type.t); - /* test for same offset */ - if (f->next->c != f->c) - break; - /* if yes, test for bitfield shift */ - if ((f->type.t & VT_BITFIELD) && (f->next->type.t & VT_BITFIELD)) { - int bit_pos_1 = (f->type.t >> VT_STRUCT_SHIFT) & 0x3f; - int bit_pos_2 = (f->next->type.t >> VT_STRUCT_SHIFT) & 0x3f; - //printf("bitfield %d %d\n", bit_pos_1, bit_pos_2); - if (bit_pos_1 != bit_pos_2) - break; - } - f = f->next; - } + /* gr: skip fields from same union - ugly. */ + while (f->next) { + ///printf("index: %2d %08x -- %2d %08x\n", f->c, f->type.t, f->next->c, f->next->type.t); + /* test for same offset */ + if (f->next->c != f->c) { + break; + } + /* if yes, test for bitfield shift */ + if ((f->type.t & VT_BITFIELD) && (f->next->type.t & VT_BITFIELD)) { + int bit_pos_1 = (f->type.t >> VT_STRUCT_SHIFT) & 0x3f; + int bit_pos_2 = (f->next->type.t >> VT_STRUCT_SHIFT) & 0x3f; + // printf("bitfield %d %d\n", bit_pos_1, bit_pos_2); + if (bit_pos_1 != bit_pos_2) { + break; + } + } + f = f->next; + } - f = f->next; - if (no_oblock && f == NULL) - break; - if (tok == '}') - break; - skip(','); - } - /* put zeros at the end */ - if (!size_only && array_length < n) { - init_putz(type, c + array_length, - n - array_length); - } - if (!no_oblock) - skip('}'); - while (par_count) { - skip(')'); - par_count--; - } - } else if (tok == '{') { - next(); - decl_initializer(type, c, first, size_only); - skip('}'); - } else if (size_only) { - /* just skip expression */ - parlevel = parlevel1 = 0; - while ((parlevel > 0 || parlevel1 > 0 || - (tok != '}' && tok != ',')) && tok != -1) { - if (tok == '(') - parlevel++; - else if (tok == ')') - parlevel--; - else if (tok == '{') - parlevel1++; - else if (tok == '}') - parlevel1--; - next(); - } - } else { - /* currently, we always use constant expression for globals - (may change for scripting case) */ - expr_type = EXPR_CONST; - init_putv(type, c, 0, expr_type); - } + f = f->next; + if (no_oblock && f == NULL) { + break; + } + if (tok == '}') { + break; + } + skip (','); + } + /* put zeros at the end */ + if (!size_only && array_length < n) { + init_putz (type, c + array_length, + n - array_length); + } + if (!no_oblock) { + skip ('}'); + } + while (par_count) { + skip (')'); + par_count--; + } + } else if (tok == '{') { + next (); + decl_initializer (type, c, first, size_only); + skip ('}'); + } else if (size_only) { + /* just skip expression */ + parlevel = parlevel1 = 0; + while ((parlevel > 0 || parlevel1 > 0 || + (tok != '}' && tok != ',')) && tok != -1) { + if (tok == '(') { + parlevel++; + } else if (tok == ')') { + parlevel--; + } else if (tok == '{') { + parlevel1++; + } else if (tok == '}') { + parlevel1--; + } + next (); + } + } else { + /* currently, we always use constant expression for globals + (may change for scripting case) */ + expr_type = EXPR_CONST; + init_putv (type, c, 0, expr_type); + } } /* parse an initializer for type 't' if 'has_init' is non zero, and @@ -2669,355 +2798,388 @@ static void decl_initializer(CType *type, unsigned long c, If 'has_init' is 2, a special parsing is done to handle string constants. */ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, - int has_init, int v, char *asm_label, - int scope) + int has_init, int v, char *asm_label, + int scope) { - int size, align, addr; - int level; - ParseState saved_parse_state = {0}; - TokenString init_str; - Sym *flexible_array; + int size, align, addr; + int level; + ParseState saved_parse_state = { + 0 + }; + TokenString init_str; + Sym *flexible_array; - flexible_array = NULL; - if ((type->t & VT_BTYPE) == VT_STRUCT) { - Sym *field; - field = type->ref; - while (field && field->next) - field = field->next; - if (field->type.t & VT_ARRAY && field->type.ref->c < 0) - flexible_array = field; - } + flexible_array = NULL; + if ((type->t & VT_BTYPE) == VT_STRUCT) { + Sym *field; + field = type->ref; + while (field && field->next) + field = field->next; + if (field->type.t & VT_ARRAY && field->type.ref->c < 0) { + flexible_array = field; + } + } - size = type_size(type, &align); - /* If unknown size, we must evaluate it before - evaluating initializers because - initializers can generate global data too - (e.g. string pointers or ISOC99 compound - literals). It also simplifies local - initializers handling */ - tok_str_new(&init_str); - if (size < 0 || (flexible_array && has_init)) { - if (!has_init) - tcc_error("unknown type size"); - /* get all init string */ - if (has_init == 2) { - /* only get strings */ - while (tok == TOK_STR || tok == TOK_LSTR) { - tok_str_add_tok(&init_str); - next(); - } - } else { - level = 0; - while (level > 0 || (tok != ',' && tok != ';')) { - if (tok < 0) - tcc_error("unexpected end of file in initializer"); - tok_str_add_tok(&init_str); - if (tok == '{') - level++; - else if (tok == '}') { - level--; - if (level <= 0) { - next(); - break; - } - } - next(); - } - } - tok_str_add(&init_str, -1); - tok_str_add(&init_str, 0); + size = type_size (type, &align); + /* If unknown size, we must evaluate it before + evaluating initializers because + initializers can generate global data too + (e.g. string pointers or ISOC99 compound + literals). It also simplifies local + initializers handling */ + tok_str_new (&init_str); + if (size < 0 || (flexible_array && has_init)) { + if (!has_init) { + tcc_error ("unknown type size"); + } + /* get all init string */ + if (has_init == 2) { + /* only get strings */ + while (tok == TOK_STR || tok == TOK_LSTR) { + tok_str_add_tok (&init_str); + next (); + } + } else { + level = 0; + while (level > 0 || (tok != ',' && tok != ';')) { + if (tok < 0) { + tcc_error ("unexpected end of file in initializer"); + } + tok_str_add_tok (&init_str); + if (tok == '{') { + level++; + } else if (tok == '}') { + level--; + if (level <= 0) { + next (); + break; + } + } + next (); + } + } + tok_str_add (&init_str, -1); + tok_str_add (&init_str, 0); - /* compute size */ - save_parse_state(&saved_parse_state); + /* compute size */ + save_parse_state (&saved_parse_state); - macro_ptr = init_str.str; - next(); - decl_initializer(type, 0, 1, 1); - /* prepare second initializer parsing */ - macro_ptr = init_str.str; - next(); + macro_ptr = init_str.str; + next (); + decl_initializer (type, 0, 1, 1); + /* prepare second initializer parsing */ + macro_ptr = init_str.str; + next (); - /* if still unknown size, error */ - size = type_size(type, &align); - if (size < 0) - tcc_error("unknown type size"); - } - if (flexible_array) - size += flexible_array->type.ref->c * pointed_size(&flexible_array->type); - /* take into account specified alignment if bigger */ - if (ad->aligned) { - if (ad->aligned > align) - align = ad->aligned; - } else if (ad->packed) { - align = 1; - } - if ((r & VT_VALMASK) == VT_LOCAL) { - loc = (loc - size) & -align; - addr = loc; - if (v) { - /* local variable */ - sym_push(v, type, r, addr); - } else { - /* push local reference */ - vset(type, r, addr); - } - } else { - Sym *sym; + /* if still unknown size, error */ + size = type_size (type, &align); + if (size < 0) { + tcc_error ("unknown type size"); + } + } + if (flexible_array) { + size += flexible_array->type.ref->c * pointed_size (&flexible_array->type); + } + /* take into account specified alignment if bigger */ + if (ad->aligned) { + if (ad->aligned > align) { + align = ad->aligned; + } + } else if (ad->packed) { + align = 1; + } + if ((r & VT_VALMASK) == VT_LOCAL) { + loc = (loc - size) & - align; + addr = loc; + if (v) { + /* local variable */ + sym_push (v, type, r, addr); + } else { + /* push local reference */ + vset (type, r, addr); + } + } else { + Sym *sym; - sym = NULL; - if (v && scope == VT_CONST) { - /* see if the symbol was already defined */ - sym = sym_find(v); - if (sym) { - if (!is_compatible_types(&sym->type, type)) - tcc_error("incompatible types for redefinition of '%s'", - get_tok_str(v, NULL)); - if (sym->type.t & VT_EXTERN) { - /* if the variable is extern, it was not allocated */ - sym->type.t &= ~VT_EXTERN; - /* set array size if it was ommited in extern - declaration */ - if ((sym->type.t & VT_ARRAY) && - sym->type.ref->c < 0 && - type->ref->c >= 0) - sym->type.ref->c = type->ref->c; - } else { - /* we accept several definitions of the same - global variable. this is tricky, because we - must play with the SHN_COMMON type of the symbol */ - /* XXX: should check if the variable was already - initialized. It is incorrect to initialized it - twice */ - /* no init data, we won't add more to the symbol */ - if (!has_init) - goto no_alloc; - } - } - } + sym = NULL; + if (v && scope == VT_CONST) { + /* see if the symbol was already defined */ + sym = sym_find (v); + if (sym) { + if (!is_compatible_types (&sym->type, type)) { + tcc_error ("incompatible types for redefinition of '%s'", + get_tok_str (v, NULL)); + } + if (sym->type.t & VT_EXTERN) { + /* if the variable is extern, it was not allocated */ + sym->type.t &= ~VT_EXTERN; + /* set array size if it was ommited in extern + declaration */ + if ((sym->type.t & VT_ARRAY) && + sym->type.ref->c < 0 && + type->ref->c >= 0) { + sym->type.ref->c = type->ref->c; + } + } else { + /* we accept several definitions of the same + global variable. this is tricky, because we + must play with the SHN_COMMON type of the symbol */ + /* XXX: should check if the variable was already + initialized. It is incorrect to initialized it + twice */ + /* no init data, we won't add more to the symbol */ + if (!has_init) { + goto no_alloc; + } + } + } + } - if (v) { - if (scope != VT_CONST || !sym) { - sym = sym_push(v, type, r | VT_SYM, 0); - sym->asm_label = asm_label; - } - } else { - CValue cval; + if (v) { + if (scope != VT_CONST || !sym) { + sym = sym_push (v, type, r | VT_SYM, 0); + sym->asm_label = asm_label; + } + } else { + CValue cval; - cval.ul = 0; - vsetc(type, VT_CONST | VT_SYM, &cval); - vtop->sym = sym; - } - /* patch symbol weakness */ - if ((type->t & VT_WEAK) && sym) - weaken_symbol(sym); - } - no_alloc: ; + cval.ul = 0; + vsetc (type, VT_CONST | VT_SYM, &cval); + vtop->sym = sym; + } + /* patch symbol weakness */ + if ((type->t & VT_WEAK) && sym) { + weaken_symbol (sym); + } + } +no_alloc: + ; } /* parse an old style function declaration list */ /* XXX: check multiple parameter */ static void func_decl_list(Sym *func_sym) { - AttributeDef ad; - int v; - Sym *s = NULL; - CType btype, type; + AttributeDef ad; + int v; + Sym *s = NULL; + CType btype, type; - /* parse each declaration */ - while (tok != '{' && tok != ';' && tok != ',' && tok != TOK_EOF && - tok != TOK_ASM1 && tok != TOK_ASM2 && tok != TOK_ASM3) { - if (!parse_btype(&btype, &ad)) - expect("declaration list"); - if (((btype.t & VT_BTYPE) == VT_ENUM || - (btype.t & VT_BTYPE) == VT_STRUCT) && - tok == ';') { - /* we accept no variable after */ - } else { - for(;;) { - type = btype; - type_decl(&type, &ad, &v, TYPE_DIRECT); - /* find parameter in function parameter list */ - s = func_sym->next; - while (s != NULL) { - if ((s->v & ~SYM_FIELD) == v) - goto found; - s = s->next; - } - tcc_error("declaration for parameter '%s' but no such parameter", - get_tok_str(v, NULL)); - found: - /* check that no storage specifier except 'register' was given */ - if (type.t & VT_STORAGE) - tcc_error("storage class specified for '%s'", get_tok_str(v, NULL)); - convert_parameter_type(&type); - /* we can add the type (NOTE: it could be local to the function) */ -if (s) { - s->type = type; -} - /* accept other parameters */ - if (tok == ',') - next(); - else - break; - } - } - skip(';'); - } + /* parse each declaration */ + while (tok != '{' && tok != ';' && tok != ',' && tok != TOK_EOF && + tok != TOK_ASM1 && tok != TOK_ASM2 && tok != TOK_ASM3) { + if (!parse_btype (&btype, &ad)) { + expect ("declaration list"); + } + if (((btype.t & VT_BTYPE) == VT_ENUM || + (btype.t & VT_BTYPE) == VT_STRUCT) && + tok == ';') { + /* we accept no variable after */ + } else { + for (;;) { + type = btype; + type_decl (&type, &ad, &v, TYPE_DIRECT); + /* find parameter in function parameter list */ + s = func_sym->next; + while (s != NULL) { + if ((s->v & ~SYM_FIELD) == v) { + goto found; + } + s = s->next; + } + tcc_error ("declaration for parameter '%s' but no such parameter", + get_tok_str (v, NULL)); +found: + /* check that no storage specifier except 'register' was given */ + if (type.t & VT_STORAGE) { + tcc_error ("storage class specified for '%s'", get_tok_str (v, NULL)); + } + convert_parameter_type (&type); + /* we can add the type (NOTE: it could be local to the function) */ + if (s) { + s->type = type; + } + /* accept other parameters */ + if (tok == ',') { + next (); + } else { + break; + } + } + } + skip (';'); + } } /* 'l' is VT_LOCAL or VT_CONST to define default storage type */ static int decl0(int l, int is_for_loop_init) { - int v, has_init, r; - CType type, btype; - Sym *sym; - AttributeDef ad; + int v, has_init, r; + CType type, btype; + Sym *sym; + AttributeDef ad; - for (;;) { - if (!parse_btype(&btype, &ad)) { - if (is_for_loop_init) - return 0; - /* skip redundant ';' */ - /* XXX: find more elegant solution */ - if (tok == ';') { - next(); - continue; - } - if (l == VT_CONST && - (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { - /* global asm block */ + for (;;) { + if (!parse_btype (&btype, &ad)) { + if (is_for_loop_init) { + return 0; + } + /* skip redundant ';' */ + /* XXX: find more elegant solution */ + if (tok == ';') { + next (); + continue; + } + if (l == VT_CONST && + (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { + /* global asm block */ #if 1 -eprintf ("global asm not supported\n"); -return 1; + eprintf ("global asm not supported\n"); + return 1; #endif - //asm_global_instr(); - continue; - } - /* special test for old K&R protos without explicit int - type. Only accepted when defining global data */ - if (l == VT_LOCAL || tok < TOK_DEFINE) - break; - btype.t = VT_INT32; - } - if (((btype.t & VT_BTYPE) == VT_ENUM || - (btype.t & VT_BTYPE) == VT_STRUCT) && - tok == ';') { - /* we accept no variable after */ - next(); - continue; - } - while (1) { /* iterate thru each declaration */ - type = btype; - type_decl(&type, &ad, &v, TYPE_DIRECT); -#if 0 - { - char buf[500]; - type_to_str(buf, sizeof(buf), t, get_tok_str(v, NULL)); - printf("type = '%s'\n", buf); - } -#endif - if ((type.t & VT_BTYPE) == VT_FUNC) { - if ((type.t & VT_STATIC) && (l == VT_LOCAL)) { - tcc_error("function without file scope cannot be static"); - } - /* if old style function prototype, we accept a - declaration list */ - sym = type.ref; - if (sym->c == FUNC_OLD) - func_decl_list(sym); - } - - if (ad.weak) - type.t |= VT_WEAK; -#ifdef TCC_TARGET_PE - if (ad.func_import) - type.t |= VT_IMPORT; - if (ad.func_export) - type.t |= VT_EXPORT; -#endif - if (tok == '{') { - if (l == VT_LOCAL) - tcc_error("cannot use local functions"); - if ((type.t & VT_BTYPE) != VT_FUNC) - expect("function definition"); - - /* reject abstract declarators in function definition */ - sym = type.ref; - while ((sym = sym->next) != NULL) - if (!(sym->v & ~SYM_FIELD)) - expect("identifier"); - - /* XXX: cannot do better now: convert extern line to static inline */ - if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE)) - type.t = (type.t & ~VT_EXTERN) | VT_STATIC; - - sym = sym_find(v); - if (sym) { - if ((sym->type.t & VT_BTYPE) != VT_FUNC) - goto func_error1; - - r = sym->type.ref->r; - /* use func_call from prototype if not defined */ - if (FUNC_CALL(r) != FUNC_CDECL - && FUNC_CALL(type.ref->r) == FUNC_CDECL) - FUNC_CALL(type.ref->r) = FUNC_CALL(r); - - /* use export from prototype */ - if (FUNC_EXPORT(r)) - FUNC_EXPORT(type.ref->r) = 1; - - /* use static from prototype */ - if (sym->type.t & VT_STATIC) - type.t = (type.t & ~VT_EXTERN) | VT_STATIC; - - if (!is_compatible_types(&sym->type, &type)) { - func_error1: - tcc_error("incompatible types for redefinition of '%s'", - get_tok_str(v, NULL)); - } - /* if symbol is already defined, then put complete type */ - sym->type = type; - } else { - /* put function symbol */ - sym = global_identifier_push(v, type.t, 0); - sym->type.ref = type.ref; - } + // asm_global_instr(); + continue; + } + /* special test for old K&R protos without explicit int + type. Only accepted when defining global data */ + if (l == VT_LOCAL || tok < TOK_DEFINE) { break; - } else { - if (btype.t & VT_TYPEDEF) { - /* save typedefed type */ - /* XXX: test storage specifiers ? */ - sym = sym_push(v, &type, INT_ATTR(&ad), 0); - sym->type.t |= VT_TYPEDEF; - } else { - r = 0; - if ((type.t & VT_BTYPE) == VT_FUNC) { - /* external function definition */ - /* specific case for func_call attribute */ - type.ref->r = INT_ATTR(&ad); - } else if (!(type.t & VT_ARRAY)) { - /* not lvalue if array */ - r |= lvalue_type(type.t); - } - has_init = (tok == '='); - if (has_init && (type.t & VT_VLA)) - tcc_error("Variable length array cannot be initialized"); - } - if (tok != ',') { - if (is_for_loop_init) - return 1; - skip(';'); - break; - } - next(); - } - ad.aligned = 0; - } - } - return 0; + } + btype.t = VT_INT32; + } + if (((btype.t & VT_BTYPE) == VT_ENUM || + (btype.t & VT_BTYPE) == VT_STRUCT) && + tok == ';') { + /* we accept no variable after */ + next (); + continue; + } + while (1) { /* iterate thru each declaration */ + type = btype; + type_decl (&type, &ad, &v, TYPE_DIRECT); +#if 0 + { + char buf[500]; + type_to_str (buf, sizeof(buf), t, get_tok_str (v, NULL)); + printf ("type = '%s'\n", buf); + } +#endif + if ((type.t & VT_BTYPE) == VT_FUNC) { + if ((type.t & VT_STATIC) && (l == VT_LOCAL)) { + tcc_error ("function without file scope cannot be static"); + } + /* if old style function prototype, we accept a + declaration list */ + sym = type.ref; + if (sym->c == FUNC_OLD) { + func_decl_list (sym); + } + } + + if (ad.weak) { + type.t |= VT_WEAK; + } +#ifdef TCC_TARGET_PE + if (ad.func_import) { + type.t |= VT_IMPORT; + } + if (ad.func_export) { + type.t |= VT_EXPORT; + } +#endif + if (tok == '{') { + if (l == VT_LOCAL) { + tcc_error ("cannot use local functions"); + } + if ((type.t & VT_BTYPE) != VT_FUNC) { + expect ("function definition"); + } + + /* reject abstract declarators in function definition */ + sym = type.ref; + while ((sym = sym->next) != NULL) + if (!(sym->v & ~SYM_FIELD)) { + expect ("identifier"); + } + + /* XXX: cannot do better now: convert extern line to static inline */ + if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE)) { + type.t = (type.t & ~VT_EXTERN) | VT_STATIC; + } + + sym = sym_find (v); + if (sym) { + if ((sym->type.t & VT_BTYPE) != VT_FUNC) { + goto func_error1; + } + + r = sym->type.ref->r; + /* use func_call from prototype if not defined */ + if (FUNC_CALL (r) != FUNC_CDECL + && FUNC_CALL (type.ref->r) == FUNC_CDECL) { + FUNC_CALL (type.ref->r) = FUNC_CALL (r); + } + + /* use export from prototype */ + if (FUNC_EXPORT (r)) { + FUNC_EXPORT (type.ref->r) = 1; + } + + /* use static from prototype */ + if (sym->type.t & VT_STATIC) { + type.t = (type.t & ~VT_EXTERN) | VT_STATIC; + } + + if (!is_compatible_types (&sym->type, &type)) { +func_error1: + tcc_error ("incompatible types for redefinition of '%s'", + get_tok_str (v, NULL)); + } + /* if symbol is already defined, then put complete type */ + sym->type = type; + } else { + /* put function symbol */ + sym = global_identifier_push (v, type.t, 0); + sym->type.ref = type.ref; + } + break; + } else { + if (btype.t & VT_TYPEDEF) { + /* save typedefed type */ + /* XXX: test storage specifiers ? */ + sym = sym_push (v, &type, INT_ATTR (&ad), 0); + sym->type.t |= VT_TYPEDEF; + } else { + r = 0; + if ((type.t & VT_BTYPE) == VT_FUNC) { + /* external function definition */ + /* specific case for func_call attribute */ + type.ref->r = INT_ATTR (&ad); + } else if (!(type.t & VT_ARRAY)) { + /* not lvalue if array */ + r |= lvalue_type (type.t); + } + has_init = (tok == '='); + if (has_init && (type.t & VT_VLA)) { + tcc_error ("Variable length array cannot be initialized"); + } + } + if (tok != ',') { + if (is_for_loop_init) { + return 1; + } + skip (';'); + break; + } + next (); + } + ad.aligned = 0; + } + } + return 0; } ST_FUNC void decl(int l) { - decl0(l, 0); + decl0 (l, 0); } diff --git a/shlr/tcc/tccpp.c b/shlr/tcc/tccpp.c index 72a5299c64..02bbc07708 100644 --- a/shlr/tcc/tccpp.c +++ b/shlr/tcc/tccpp.c @@ -25,25 +25,25 @@ ST_DATA int tok_flags; /* additional informations about token */ -#define TOK_FLAG_BOL 0x0001 /* beginning of line before */ -#define TOK_FLAG_BOF 0x0002 /* beginning of file before */ -#define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */ -#define TOK_FLAG_EOF 0x0008 /* end of file */ +#define TOK_FLAG_BOL 0x0001 /* beginning of line before */ +#define TOK_FLAG_BOF 0x0002 /* beginning of file before */ +#define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */ +#define TOK_FLAG_EOF 0x0008 /* end of file */ ST_DATA int parse_flags; -#define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */ -#define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */ -#define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a - token. line feed is also - returned at eof */ -#define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */ -#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ +#define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */ +#define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */ +#define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a + token. line feed is also + returned at eof */ +#define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */ +#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ 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 */ +ST_DATA CString tokcstr;/* current parsed string, if any */ /* display benchmark infos */ ST_DATA int total_lines; @@ -60,7 +60,7 @@ static int unget_buffer_enabled; static TokenSym *hash_ident[TOK_HASH_SIZE]; static char token_buf[STRING_MAX_SIZE + 1]; /* true if isid(c) || isnum(c) */ -static unsigned char isidnum_table[256-CH_EOF]; +static unsigned char isidnum_table[256 - CH_EOF]; static const char tcc_keywords[] = #define DEF(id, str) str "\0" @@ -70,155 +70,161 @@ static const char tcc_keywords[] = /* WARNING: the content of this string encodes token numbers */ static const unsigned char tok_two_chars[] = - "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253" - "-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266"; + "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253" + "-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266"; struct macro_level { - struct macro_level *prev; - const int *p; + struct macro_level *prev; + const int *p; }; static void next_nomacro_spc(void); static void macro_subst( - TokenString *tok_str, - Sym **nested_list, - const int *macro_str, - struct macro_level **can_read_stream - ); + TokenString *tok_str, + Sym **nested_list, + const int *macro_str, + struct macro_level **can_read_stream +); ST_FUNC void skip(int c) { - if (tok != c) - tcc_error("'%c' expected (got \"%s\")", c, get_tok_str(tok, &tokc)); - next(); + 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); + tcc_error ("%s expected", msg); } /* ------------------------------------------------------------------------- */ /* CString handling */ static void cstr_realloc(CString *cstr, int new_size) { - int size; - void *data; + int size; + void *data; - size = cstr->size_allocated; - if (size == 0) - size = 8; /* no need to allocate a too small first string */ - while (size < new_size) - size = size * 2; - data = realloc(cstr->data_allocated, size); - cstr->data_allocated = data; - cstr->size_allocated = size; - cstr->data = data; + size = cstr->size_allocated; + if (size == 0) { + size = 8; /* no need to allocate a too small first string */ + } + while (size < new_size) + size = size * 2; + data = realloc (cstr->data_allocated, size); + cstr->data_allocated = data; + cstr->size_allocated = size; + cstr->data = data; } /* add a byte */ ST_FUNC 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; + 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 c; - for(;;) { - c = *str; - if (c == '\0') - break; - cstr_ccat(cstr, c); - str++; - } + int c; + for (;;) { + c = *str; + if (c == '\0') { + break; + } + cstr_ccat (cstr, c); + str++; + } } /* 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; + 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)); + memset (cstr, 0, sizeof(CString)); } /* free string and reset it to NULL */ ST_FUNC void cstr_free(CString *cstr) { - free(cstr->data_allocated); - cstr_new(cstr); + free (cstr->data_allocated); + cstr_new (cstr); } /* reset string to empty */ ST_FUNC void cstr_reset(CString *cstr) { - cstr->size = 0; + cstr->size = 0; } /* 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)); - } - } + 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; + TokenSym *ts, **ptable; + int i; - if (tok_ident >= SYM_FIRST_ANOM) - tcc_error("memory full"); + if (tok_ident >= SYM_FIRST_ANOM) { + tcc_error ("memory full"); + } - /* expand token table if needed */ - i = tok_ident - TOK_IDENT; - if ((i % TOK_ALLOC_INCR) == 0) { - ptable = realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *)); - table_ident = ptable; - } + /* expand token table if needed */ + i = tok_ident - TOK_IDENT; + if ((i % TOK_ALLOC_INCR) == 0) { + ptable = realloc (table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *)); + table_ident = ptable; + } - ts = malloc(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; + ts = malloc (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 @@ -227,545 +233,575 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) /* 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; + TokenSym *ts, **pts; + int i; + unsigned int h; - h = TOK_HASH_INIT; - for(i=0;ilen == len && !memcmp(ts->str, str, len)) - return ts; - pts = &(ts->hash_next); - } - return tok_alloc_new(pts, str, len); + 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 char *get_tok_str(int v, CValue *cv) { - static char buf[STRING_MAX_SIZE + 1]; - static CString cstr_buf; - CString *cstr; - char *p; - int i, len; + static char buf[STRING_MAX_SIZE + 1]; + static CString cstr_buf; + CString *cstr; + char *p; + int i, len; - /* NOTE: to go faster, we give a fixed buffer for small strings */ - cstr_reset(&cstr_buf); - cstr_buf.data = buf; - cstr_buf.size_allocated = sizeof(buf); - p = buf; + /* NOTE: to go faster, we give a fixed buffer for small strings */ + cstr_reset (&cstr_buf); + cstr_buf.data = buf; + cstr_buf.size_allocated = sizeof(buf); + p = buf; - switch(v) { - case TOK_CINT: - case TOK_CUINT: - /* XXX: not quite exact, but only useful for testing */ - if (cv) - sprintf(p, "%u", cv->ui); - break; - case TOK_CLLONG: - case TOK_CULLONG: - /* XXX: not quite exact, but only useful for testing */ - if (cv) - sprintf(p, "%"PFMT64u, cv->ull); - break; - case TOK_LCHAR: - cstr_ccat(&cstr_buf, 'L'); - case TOK_CCHAR: - cstr_ccat(&cstr_buf, '\''); - if (cv) - add_char(&cstr_buf, cv->i); - cstr_ccat(&cstr_buf, '\''); - cstr_ccat(&cstr_buf, '\0'); - break; - case TOK_PPNUM: - cstr = cv->cstr; - len = cstr->size - 1; - for(i=0;idata)[i]); - cstr_ccat(&cstr_buf, '\0'); - break; - case TOK_LSTR: - cstr_ccat(&cstr_buf, 'L'); - case TOK_STR: - if (cv) { - cstr = cv->cstr; - cstr_ccat(&cstr_buf, '\"'); - if (v == TOK_STR) { - len = cstr->size - 1; - for(i=0;idata)[i]); - } else { - len = (cstr->size / sizeof(nwchar_t)) - 1; - for(i=0;idata)[i]); - } - cstr_ccat(&cstr_buf, '\"'); - cstr_ccat(&cstr_buf, '\0'); - } else eprintf ("cv = nil\n"); - break; - case TOK_LT: - v = '<'; - goto addv; - case TOK_GT: - v = '>'; - goto addv; - case TOK_DOTS: - return strcpy(p, "..."); - case TOK_A_SHL: - return strcpy(p, "<<="); - case TOK_A_SAR: - return strcpy(p, ">>="); - default: - if (v < TOK_IDENT) { - /* search in two bytes table */ - const unsigned char *q = tok_two_chars; - while (*q) { - if (q[2] == v) { - *p++ = q[0]; - *p++ = q[1]; - *p = '\0'; - return buf; - } - q += 3; - } - addv: - *p++ = v; - *p = '\0'; - } else if (v < tok_ident) { - return table_ident[v - TOK_IDENT]->str; - } else if (v >= SYM_FIRST_ANOM) { - /* special name for anonymous symbol */ - sprintf(p, "L.%u", v - SYM_FIRST_ANOM); - } else { - /* should never happen */ - return NULL; - } - break; - } - return cstr_buf.data; + switch (v) { + case TOK_CINT: + case TOK_CUINT: + /* XXX: not quite exact, but only useful for testing */ + if (cv) { + sprintf (p, "%u", cv->ui); + } + break; + case TOK_CLLONG: + case TOK_CULLONG: + /* XXX: not quite exact, but only useful for testing */ + if (cv) { + sprintf (p, "%"PFMT64u, cv->ull); + } + break; + case TOK_LCHAR: + cstr_ccat (&cstr_buf, 'L'); + case TOK_CCHAR: + cstr_ccat (&cstr_buf, '\''); + if (cv) { + add_char (&cstr_buf, cv->i); + } + cstr_ccat (&cstr_buf, '\''); + cstr_ccat (&cstr_buf, '\0'); + break; + case TOK_PPNUM: + cstr = cv->cstr; + len = cstr->size - 1; + for (i = 0; i < len; i++) { + add_char (&cstr_buf, ((unsigned char *) cstr->data)[i]); + } + cstr_ccat (&cstr_buf, '\0'); + break; + case TOK_LSTR: + cstr_ccat (&cstr_buf, 'L'); + case TOK_STR: + if (cv) { + cstr = cv->cstr; + cstr_ccat (&cstr_buf, '\"'); + if (v == TOK_STR) { + len = cstr->size - 1; + for (i = 0; i < len; i++) { + add_char (&cstr_buf, ((unsigned char *) cstr->data)[i]); + } + } else { + len = (cstr->size / sizeof(nwchar_t)) - 1; + for (i = 0; i < len; i++) { + add_char (&cstr_buf, ((nwchar_t *) cstr->data)[i]); + } + } + cstr_ccat (&cstr_buf, '\"'); + cstr_ccat (&cstr_buf, '\0'); + } else { + eprintf ("cv = nil\n"); + } + break; + case TOK_LT: + v = '<'; + goto addv; + case TOK_GT: + v = '>'; + goto addv; + case TOK_DOTS: + return strcpy (p, "..."); + case TOK_A_SHL: + return strcpy (p, "<<="); + case TOK_A_SAR: + return strcpy (p, ">>="); + default: + if (v < TOK_IDENT) { + /* search in two bytes table */ + const unsigned char *q = tok_two_chars; + while (*q) { + if (q[2] == v) { + *p++ = q[0]; + *p++ = q[1]; + *p = '\0'; + return buf; + } + q += 3; + } +addv: + *p++ = v; + *p = '\0'; + } else if (v < tok_ident) { + return table_ident[v - TOK_IDENT]->str; + } else if (v >= SYM_FIRST_ANOM) { + /* special name for anonymous symbol */ + sprintf (p, "L.%u", v - SYM_FIRST_ANOM); + } else { + /* should never happen */ + return NULL; + } + break; + } + return cstr_buf.data; } /* fill input buffer and peek next char */ static int tcc_peekc_slow(BufferedFile *bf) { - int len; - /* only tries to read if really end of buffer */ - if (bf->buf_ptr >= bf->buf_end) { - if (bf->fd != -1) { + int len; + /* only tries to read if really end of buffer */ + if (bf->buf_ptr >= bf->buf_end) { + if (bf->fd != -1) { #if defined(PARSE_DEBUG) - len = 8; + len = 8; #else - len = IO_BUF_SIZE; + len = IO_BUF_SIZE; #endif - len = read(bf->fd, bf->buffer, len); - if (len < 0) - len = 0; - } else { - len = 0; - } - total_bytes += len; - bf->buf_ptr = bf->buffer; - bf->buf_end = bf->buffer + len; - *bf->buf_end = CH_EOB; - } - if (bf->buf_ptr < bf->buf_end) { - return bf->buf_ptr[0]; - } else { - bf->buf_ptr = bf->buf_end; - return CH_EOF; - } + len = read (bf->fd, bf->buffer, len); + if (len < 0) { + len = 0; + } + } else { + len = 0; + } + total_bytes += len; + bf->buf_ptr = bf->buffer; + bf->buf_end = bf->buffer + len; + *bf->buf_end = CH_EOB; + } + if (bf->buf_ptr < bf->buf_end) { + return bf->buf_ptr[0]; + } else { + bf->buf_ptr = bf->buf_end; + return CH_EOF; + } } /* return the current character, handling end of block if necessary (but not stray) */ ST_FUNC int handle_eob(void) { - return tcc_peekc_slow(file); + return tcc_peekc_slow (file); } /* read next char from current input file and handle end of input buffer */ ST_INLN void inp(void) { - ch = *(++(file->buf_ptr)); - /* end of buffer/file handling */ - if (ch == CH_EOB) - ch = handle_eob(); + ch = *(++(file->buf_ptr)); + /* end of buffer/file handling */ + if (ch == CH_EOB) { + ch = handle_eob (); + } } /* handle '\[\r]\n' */ static int handle_stray_noerror(void) { - while (ch == '\\') { - inp(); - if (ch == '\n') { - file->line_num++; - inp(); - } else if (ch == '\r') { - inp(); - if (ch != '\n') - goto fail; - file->line_num++; - inp(); - } else { - fail: - return 1; - } - } - return 0; + while (ch == '\\') { + inp (); + if (ch == '\n') { + file->line_num++; + inp (); + } else if (ch == '\r') { + inp (); + if (ch != '\n') { + goto fail; + } + file->line_num++; + inp (); + } else { +fail: + return 1; + } + } + return 0; } static void handle_stray(void) { - if (handle_stray_noerror()) - tcc_error("stray '\\' in program"); + if (handle_stray_noerror ()) { + tcc_error ("stray '\\' in program"); + } } /* skip the stray and handle the \\n case. Output an error if incorrect char after the stray */ static int handle_stray1(uint8_t *p) { - int c; + int c; - if (p >= file->buf_end) { - file->buf_ptr = p; - c = handle_eob(); - p = file->buf_ptr; - if (c == '\\') - goto parse_stray; - } else { - parse_stray: - file->buf_ptr = p; - ch = *p; - handle_stray(); - p = file->buf_ptr; - c = *p; - } - return c; + if (p >= file->buf_end) { + file->buf_ptr = p; + c = handle_eob (); + p = file->buf_ptr; + if (c == '\\') { + goto parse_stray; + } + } else { +parse_stray: + file->buf_ptr = p; + ch = *p; + handle_stray (); + p = file->buf_ptr; + c = *p; + } + return c; } /* handle just the EOB case, but not stray */ -#define PEEKC_EOB(c, p)\ -{\ - p++;\ - c = *p;\ - if (c == '\\') {\ - file->buf_ptr = p;\ - c = handle_eob();\ - p = file->buf_ptr;\ - }\ -} +#define PEEKC_EOB(c, p) \ + { \ + p++; \ + c = *p; \ + if (c == '\\') { \ + file->buf_ptr = p;\ + c = handle_eob ();\ + p = file->buf_ptr;\ + } \ + } /* handle the complicated stray case */ -#define PEEKC(c, p)\ -{\ - p++;\ - c = *p;\ - if (c == '\\') {\ - c = handle_stray1(p);\ - p = file->buf_ptr;\ - }\ -} +#define PEEKC(c, p) \ + { \ + p++; \ + c = *p; \ + if (c == '\\') { \ + c = handle_stray1 (p);\ + p = file->buf_ptr;\ + } \ + } /* input with '\[\r]\n' handling. Note that this function cannot handle other characters after '\', so you cannot call it inside strings or comments */ ST_FUNC void minp(void) { - inp(); - if (ch == '\\') - handle_stray(); + inp (); + if (ch == '\\') { + handle_stray (); + } } /* single line C++ comments */ static uint8_t *parse_line_comment(uint8_t *p) { - int c; + int c; - p++; - for(;;) { - c = *p; - redo: - if (c == '\n' || c == CH_EOF) { - break; - } else if (c == '\\') { - file->buf_ptr = p; - c = handle_eob(); - p = file->buf_ptr; - if (c == '\\') { - PEEKC_EOB(c, p); - if (c == '\n') { - file->line_num++; - PEEKC_EOB(c, p); - } else if (c == '\r') { - PEEKC_EOB(c, p); - if (c == '\n') { - file->line_num++; - PEEKC_EOB(c, p); - } - } - } else { - goto redo; - } - } else { - p++; - } - } - return p; + p++; + for (;;) { + c = *p; +redo: + if (c == '\n' || c == CH_EOF) { + break; + } else if (c == '\\') { + file->buf_ptr = p; + c = handle_eob (); + p = file->buf_ptr; + if (c == '\\') { + PEEKC_EOB (c, p); + if (c == '\n') { + file->line_num++; + PEEKC_EOB (c, p); + } else if (c == '\r') { + PEEKC_EOB (c, p); + if (c == '\n') { + file->line_num++; + PEEKC_EOB (c, p); + } + } + } else { + goto redo; + } + } else { + p++; + } + } + return p; } /* C comments */ ST_FUNC uint8_t *parse_comment(uint8_t *p) { - int c; + int c; - p++; - for(;;) { - /* fast skip loop */ - for(;;) { - c = *p; - if (c == '\n' || c == '*' || c == '\\') - break; - p++; - c = *p; - if (c == '\n' || c == '*' || c == '\\') - break; - p++; - } - /* now we can handle all the cases */ - if (c == '\n') { - file->line_num++; - p++; - } else if (c == '*') { - p++; - for(;;) { - c = *p; - if (c == '*') { - p++; - } else if (c == '/') { - goto end_of_comment; - } else if (c == '\\') { - file->buf_ptr = p; - c = handle_eob(); - p = file->buf_ptr; - if (c == '\\') { - /* skip '\[\r]\n', otherwise just skip the stray */ - while (c == '\\') { - PEEKC_EOB(c, p); - if (c == '\n') { - file->line_num++; - PEEKC_EOB(c, p); - } else if (c == '\r') { - PEEKC_EOB(c, p); - if (c == '\n') { - file->line_num++; - PEEKC_EOB(c, p); - } - } else { - goto after_star; - } - } - } - } else { - break; - } - } - after_star: ; - } else { - /* stray, eob or eof */ - file->buf_ptr = p; - c = handle_eob(); - p = file->buf_ptr; - if (c == CH_EOF) { - tcc_error("unexpected end of file in comment"); - } else if (c == '\\') { - p++; - } - } - } - end_of_comment: - p++; - return p; + p++; + for (;;) { + /* fast skip loop */ + for (;;) { + c = *p; + if (c == '\n' || c == '*' || c == '\\') { + break; + } + p++; + c = *p; + if (c == '\n' || c == '*' || c == '\\') { + break; + } + p++; + } + /* now we can handle all the cases */ + if (c == '\n') { + file->line_num++; + p++; + } else if (c == '*') { + p++; + for (;;) { + c = *p; + if (c == '*') { + p++; + } else if (c == '/') { + goto end_of_comment; + } else if (c == '\\') { + file->buf_ptr = p; + c = handle_eob (); + p = file->buf_ptr; + if (c == '\\') { + /* skip '\[\r]\n', otherwise just skip the stray */ + while (c == '\\') { + PEEKC_EOB (c, p); + if (c == '\n') { + file->line_num++; + PEEKC_EOB (c, p); + } else if (c == '\r') { + PEEKC_EOB (c, p); + if (c == '\n') { + file->line_num++; + PEEKC_EOB (c, p); + } + } else { + goto after_star; + } + } + } + } else { + break; + } + } +after_star: + ; + } else { + /* stray, eob or eof */ + file->buf_ptr = p; + c = handle_eob (); + p = file->buf_ptr; + if (c == CH_EOF) { + tcc_error ("unexpected end of file in comment"); + } else if (c == '\\') { + p++; + } + } + } +end_of_comment: + p++; + return p; } #define cinp minp static inline void skip_spaces(void) { - while (is_space(ch)) - cinp(); + while (is_space (ch)) + cinp (); } static inline int check_space(int t, int *spc) { - if (is_space(t)) { - if (*spc) - return 1; - *spc = 1; - } else - *spc = 0; - return 0; + if (is_space (t)) { + if (*spc) { + return 1; + } + *spc = 1; + } else { + *spc = 0; + } + return 0; } /* parse a string without interpreting escapes */ static uint8_t *parse_pp_string(uint8_t *p, - int sep, CString *str) + int sep, CString *str) { - int c; - p++; - for(;;) { - c = *p; - if (c == sep) { - break; - } else if (c == '\\') { - file->buf_ptr = p; - c = handle_eob(); - p = file->buf_ptr; - if (c == CH_EOF) { - unterminated_string: - /* XXX: indicate line number of start of string */ - tcc_error("missing terminating %c character", sep); - } else if (c == '\\') { - /* escape : just skip \[\r]\n */ - PEEKC_EOB(c, p); - if (c == '\n') { - file->line_num++; - p++; - } else if (c == '\r') { - PEEKC_EOB(c, p); - if (c != '\n') - expect("'\n' after '\r'"); - file->line_num++; - p++; - } else if (c == CH_EOF) { - goto unterminated_string; - } else { - if (str) { - cstr_ccat(str, '\\'); - cstr_ccat(str, c); - } - p++; - } - } - } else if (c == '\n') { - file->line_num++; - goto add_char; - } else if (c == '\r') { - PEEKC_EOB(c, p); - if (c != '\n') { - if (str) - cstr_ccat(str, '\r'); - } else { - file->line_num++; - goto add_char; - } - } else { - add_char: - if (str) - cstr_ccat(str, c); - p++; - } - } - p++; - return p; + int c; + p++; + for (;;) { + c = *p; + if (c == sep) { + break; + } else if (c == '\\') { + file->buf_ptr = p; + c = handle_eob (); + p = file->buf_ptr; + if (c == CH_EOF) { +unterminated_string: + /* XXX: indicate line number of start of string */ + tcc_error ("missing terminating %c character", sep); + } else if (c == '\\') { + /* escape : just skip \[\r]\n */ + PEEKC_EOB (c, p); + if (c == '\n') { + file->line_num++; + p++; + } else if (c == '\r') { + PEEKC_EOB (c, p); + if (c != '\n') { + expect ("'\n' after '\r'"); + } + file->line_num++; + p++; + } else if (c == CH_EOF) { + goto unterminated_string; + } else { + if (str) { + cstr_ccat (str, '\\'); + cstr_ccat (str, c); + } + p++; + } + } + } else if (c == '\n') { + file->line_num++; + goto add_char; + } else if (c == '\r') { + PEEKC_EOB (c, p); + if (c != '\n') { + if (str) { + cstr_ccat (str, '\r'); + } + } else { + file->line_num++; + goto add_char; + } + } else { +add_char: + if (str) { + cstr_ccat (str, c); + } + p++; + } + } + p++; + return p; } /* skip block of text until #else, #elif or #endif. skip also pairs of #if/#endif */ static void preprocess_skip(void) { - int a, start_of_line, c, in_warn_or_error; - uint8_t *p; + int a, start_of_line, c, in_warn_or_error; + uint8_t *p; - p = file->buf_ptr; - a = 0; + p = file->buf_ptr; + a = 0; redo_start: - start_of_line = 1; - in_warn_or_error = 0; - for(;;) { - redo_no_start: - c = *p; - switch(c) { - case ' ': - case '\t': - case '\f': - case '\v': - case '\r': - p++; - goto redo_no_start; - case '\n': - file->line_num++; - p++; - goto redo_start; - case '\\': - file->buf_ptr = p; - c = handle_eob(); - if (c == CH_EOF) { - expect("#endif"); - } else if (c == '\\') { - ch = file->buf_ptr[0]; - handle_stray_noerror(); - } - p = file->buf_ptr; - goto redo_no_start; - /* skip strings */ - case '\"': - case '\'': - if (in_warn_or_error) - goto _default; - p = parse_pp_string(p, c, NULL); - break; - /* skip comments */ - case '/': - if (in_warn_or_error) - goto _default; - file->buf_ptr = p; - ch = *p; - minp(); - p = file->buf_ptr; - if (ch == '*') { - p = parse_comment(p); - } else if (ch == '/') { - p = parse_line_comment(p); - } - break; - case '#': - p++; - if (start_of_line) { - file->buf_ptr = p; - next_nomacro(); - p = file->buf_ptr; - if (a == 0 && - (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF)) - goto the_end; - if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF) - a++; - else if (tok == TOK_ENDIF) - a--; - else if( tok == TOK_ERROR || tok == TOK_WARNING) - in_warn_or_error = 1; - else if (tok == TOK_LINEFEED) - goto redo_start; - } - break; + start_of_line = 1; + in_warn_or_error = 0; + for (;;) { +redo_no_start: + c = *p; + switch (c) { + case ' ': + case '\t': + case '\f': + case '\v': + case '\r': + p++; + goto redo_no_start; + case '\n': + file->line_num++; + p++; + goto redo_start; + case '\\': + file->buf_ptr = p; + c = handle_eob (); + if (c == CH_EOF) { + expect ("#endif"); + } else if (c == '\\') { + ch = file->buf_ptr[0]; + handle_stray_noerror (); + } + p = file->buf_ptr; + goto redo_no_start; + /* skip strings */ + case '\"': + case '\'': + if (in_warn_or_error) { + goto _default; + } + p = parse_pp_string (p, c, NULL); + break; + /* skip comments */ + case '/': + if (in_warn_or_error) { + goto _default; + } + file->buf_ptr = p; + ch = *p; + minp (); + p = file->buf_ptr; + if (ch == '*') { + p = parse_comment (p); + } else if (ch == '/') { + p = parse_line_comment (p); + } + break; + case '#': + p++; + if (start_of_line) { + file->buf_ptr = p; + next_nomacro (); + p = file->buf_ptr; + if (a == 0 && + (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF)) { + goto the_end; + } + if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF) { + a++; + } else if (tok == TOK_ENDIF) { + a--; + } else if (tok == TOK_ERROR || tok == TOK_WARNING) { + in_warn_or_error = 1; + } else if (tok == TOK_LINEFEED) { + goto redo_start; + } + } + break; _default: - default: - p++; - break; - } - start_of_line = 0; - } - the_end: ; - file->buf_ptr = p; + default: + p++; + break; + } + start_of_line = 0; + } +the_end: + ; + file->buf_ptr = p; } /* ParseState handling */ @@ -777,743 +813,785 @@ _default: /* save current parse state in 's' */ ST_FUNC void save_parse_state(ParseState *s) { - s->line_num = file->line_num; - s->macro_ptr = macro_ptr; - s->tok = tok; - s->tokc = tokc; + s->line_num = file->line_num; + s->macro_ptr = macro_ptr; + s->tok = tok; + s->tokc = tokc; } /* restore parse state from 's' */ ST_FUNC void restore_parse_state(ParseState *s) { - file->line_num = s->line_num; - macro_ptr = s->macro_ptr; - tok = s->tok; - tokc = s->tokc; + file->line_num = s->line_num; + macro_ptr = s->macro_ptr; + tok = s->tok; + tokc = s->tokc; } /* return the number of additional 'ints' necessary to store the token */ static inline int tok_ext_size(int t) { - switch(t) { - /* 4 bytes */ - case TOK_CINT: - case TOK_CUINT: - case TOK_CCHAR: - case TOK_LCHAR: - case TOK_CFLOAT: - case TOK_LINENUM: - return 1; - case TOK_STR: - case TOK_LSTR: - case TOK_PPNUM: - tcc_error("unsupported token"); - return 1; - case TOK_CDOUBLE: - case TOK_CLLONG: - case TOK_CULLONG: - return 2; - case TOK_CLDOUBLE: - return LDOUBLE_SIZE / 4; - default: - return 0; - } + switch (t) { + /* 4 bytes */ + case TOK_CINT: + case TOK_CUINT: + case TOK_CCHAR: + case TOK_LCHAR: + case TOK_CFLOAT: + case TOK_LINENUM: + return 1; + case TOK_STR: + case TOK_LSTR: + case TOK_PPNUM: + tcc_error ("unsupported token"); + return 1; + case TOK_CDOUBLE: + case TOK_CLLONG: + case TOK_CULLONG: + return 2; + case TOK_CLDOUBLE: + return LDOUBLE_SIZE / 4; + default: + return 0; + } } /* token string handling */ ST_INLN void tok_str_new(TokenString *s) { - s->str = NULL; - s->len = 0; - s->allocated_len = 0; - s->last_line_num = -1; + s->str = NULL; + s->len = 0; + s->allocated_len = 0; + s->last_line_num = -1; } ST_FUNC void tok_str_free(int *str) { - free(str); + free (str); } static int *tok_str_realloc(TokenString *s) { - int *str, len; + int *str, len; - if (s->allocated_len == 0) { - len = 8; - } else { - len = s->allocated_len * 2; - } - str = realloc(s->str, len * sizeof(int)); - s->allocated_len = len; - s->str = str; - return str; + if (s->allocated_len == 0) { + len = 8; + } else { + len = s->allocated_len * 2; + } + str = realloc (s->str, len * sizeof(int)); + s->allocated_len = len; + s->str = str; + return str; } ST_FUNC void tok_str_add(TokenString *s, int t) { - int len, *str; + int len, *str; - len = s->len; - str = s->str; - if (len >= s->allocated_len) - str = tok_str_realloc(s); - str[len++] = t; - s->len = len; + len = s->len; + str = s->str; + if (len >= s->allocated_len) { + str = tok_str_realloc (s); + } + str[len++] = t; + s->len = len; } static void tok_str_add2(TokenString *s, int t, CValue *cv) { - int len, *str; + int len, *str; - len = s->len; - str = s->str; + len = s->len; + str = s->str; - /* allocate space for worst case */ - if (len + TOK_MAX_SIZE > s->allocated_len) - str = tok_str_realloc(s); - str[len++] = t; - switch(t) { - case TOK_CINT: - case TOK_CUINT: - case TOK_CCHAR: - case TOK_LCHAR: - case TOK_CFLOAT: - case TOK_LINENUM: - str[len++] = cv->tab[0]; - break; - case TOK_PPNUM: - case TOK_STR: - case TOK_LSTR: - { - int nb_words; - CString *cstr; + /* allocate space for worst case */ + if (len + TOK_MAX_SIZE > s->allocated_len) { + str = tok_str_realloc (s); + } + str[len++] = t; + switch (t) { + case TOK_CINT: + case TOK_CUINT: + case TOK_CCHAR: + case TOK_LCHAR: + case TOK_CFLOAT: + case TOK_LINENUM: + str[len++] = cv->tab[0]; + break; + case TOK_PPNUM: + case TOK_STR: + case TOK_LSTR: + { + int nb_words; + CString *cstr; - nb_words = (sizeof(CString) + cv->cstr->size + 3) >> 2; - while ((len + nb_words) > s->allocated_len) - str = tok_str_realloc(s); - cstr = (CString *)(str + len); - cstr->data = NULL; - cstr->size = cv->cstr->size; - cstr->data_allocated = NULL; - cstr->size_allocated = cstr->size; - memcpy((char *)cstr + sizeof(CString), - cv->cstr->data, cstr->size); - len += nb_words; - } - break; - case TOK_CDOUBLE: - case TOK_CLLONG: - case TOK_CULLONG: + nb_words = (sizeof(CString) + cv->cstr->size + 3) >> 2; + while ((len + nb_words) > s->allocated_len) + str = tok_str_realloc (s); + cstr = (CString *) (str + len); + cstr->data = NULL; + cstr->size = cv->cstr->size; + cstr->data_allocated = NULL; + cstr->size_allocated = cstr->size; + memcpy ((char *) cstr + sizeof(CString), + cv->cstr->data, cstr->size); + len += nb_words; + } + break; + case TOK_CDOUBLE: + case TOK_CLLONG: + case TOK_CULLONG: #if LDOUBLE_SIZE == 8 - case TOK_CLDOUBLE: + case TOK_CLDOUBLE: #endif - str[len++] = cv->tab[0]; - str[len++] = cv->tab[1]; - break; + str[len++] = cv->tab[0]; + str[len++] = cv->tab[1]; + break; #if LDOUBLE_SIZE == 12 - case TOK_CLDOUBLE: - str[len++] = cv->tab[0]; - str[len++] = cv->tab[1]; - str[len++] = cv->tab[2]; + case TOK_CLDOUBLE: + str[len++] = cv->tab[0]; + str[len++] = cv->tab[1]; + str[len++] = cv->tab[2]; #elif LDOUBLE_SIZE == 16 - case TOK_CLDOUBLE: - str[len++] = cv->tab[0]; - str[len++] = cv->tab[1]; - str[len++] = cv->tab[2]; - str[len++] = cv->tab[3]; + case TOK_CLDOUBLE: + str[len++] = cv->tab[0]; + str[len++] = cv->tab[1]; + str[len++] = cv->tab[2]; + str[len++] = cv->tab[3]; #elif LDOUBLE_SIZE != 8 #error add long double size support #endif - break; - default: - break; - } - s->len = len; + break; + default: + break; + } + s->len = len; } /* add the current parse token in token string 's' */ ST_FUNC void tok_str_add_tok(TokenString *s) { - CValue cval; + CValue cval; - /* save line number info */ - if (file->line_num != s->last_line_num) { - s->last_line_num = file->line_num; - cval.i = s->last_line_num; - tok_str_add2(s, TOK_LINENUM, &cval); - } - tok_str_add2(s, tok, &tokc); + /* save line number info */ + if (file->line_num != s->last_line_num) { + s->last_line_num = file->line_num; + cval.i = s->last_line_num; + tok_str_add2 (s, TOK_LINENUM, &cval); + } + tok_str_add2 (s, tok, &tokc); } /* get a token from an integer array and increment pointer accordingly. we code it as a macro to avoid pointer aliasing. */ static inline void TOK_GET(int *t, const int **pp, CValue *cv) { - const int *p = *pp; - int n, *tab; + const int *p = *pp; + int n, *tab; - tab = cv->tab; - switch(*t = *p++) { - case TOK_CINT: - case TOK_CUINT: - case TOK_CCHAR: - case TOK_LCHAR: - case TOK_CFLOAT: - case TOK_LINENUM: - tab[0] = *p++; - break; - case TOK_STR: - case TOK_LSTR: - case TOK_PPNUM: - cv->cstr = (CString *)p; - cv->cstr->data = (char *)p + sizeof(CString); - p += (sizeof(CString) + cv->cstr->size + 3) >> 2; - break; - case TOK_CDOUBLE: - case TOK_CLLONG: - case TOK_CULLONG: - n = 2; - goto copy; - case TOK_CLDOUBLE: + tab = cv->tab; + switch (*t = *p++) { + case TOK_CINT: + case TOK_CUINT: + case TOK_CCHAR: + case TOK_LCHAR: + case TOK_CFLOAT: + case TOK_LINENUM: + tab[0] = *p++; + break; + case TOK_STR: + case TOK_LSTR: + case TOK_PPNUM: + cv->cstr = (CString *) p; + cv->cstr->data = (char *) p + sizeof(CString); + p += (sizeof(CString) + cv->cstr->size + 3) >> 2; + break; + case TOK_CDOUBLE: + case TOK_CLLONG: + case TOK_CULLONG: + n = 2; + goto copy; + case TOK_CLDOUBLE: #if LDOUBLE_SIZE == 16 - n = 4; + n = 4; #elif LDOUBLE_SIZE == 12 - n = 3; + n = 3; #elif LDOUBLE_SIZE == 8 - n = 2; + n = 2; #else -# error add long double size support +#error add long double size support #endif - copy: - do - *tab++ = *p++; - while (--n); - break; - default: - break; - } - *pp = p; +copy: + do { + *tab++ = *p++; + } while (--n); + break; + default: + break; + } + *pp = p; } static int macro_is_equal(const int *a, const int *b) { - char buf[STRING_MAX_SIZE + 1]; - CValue cv; - int t; - while (*a && *b) { - TOK_GET(&t, &a, &cv); - pstrcpy(buf, sizeof buf, get_tok_str(t, &cv)); - TOK_GET(&t, &b, &cv); - if (strcmp(buf, get_tok_str(t, &cv))) - return 0; - } - return !(*a || *b); + char buf[STRING_MAX_SIZE + 1]; + CValue cv; + int t; + while (*a && *b) { + TOK_GET (&t, &a, &cv); + pstrcpy (buf, sizeof buf, get_tok_str (t, &cv)); + TOK_GET (&t, &b, &cv); + if (strcmp (buf, get_tok_str (t, &cv))) { + return 0; + } + } + return !(*a || *b); } /* defines handling */ ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg) { - Sym *s; + Sym *s; - s = define_find(v); - if (s && !macro_is_equal(s->d, str)) - tcc_warning("%s redefined", get_tok_str(v, NULL)); + s = define_find (v); + if (s && !macro_is_equal (s->d, str)) { + tcc_warning ("%s redefined", get_tok_str (v, NULL)); + } - s = sym_push2(&define_stack, v, macro_type, 0); - s->d = str; - s->next = first_arg; - table_ident[v - TOK_IDENT]->sym_define = s; + s = sym_push2 (&define_stack, v, macro_type, 0); + s->d = str; + s->next = first_arg; + table_ident[v - TOK_IDENT]->sym_define = s; } /* undefined a define symbol. Its name is just set to zero */ ST_FUNC void define_undef(Sym *s) { - int v; - v = s->v; - if (v >= TOK_IDENT && v < tok_ident) - table_ident[v - TOK_IDENT]->sym_define = NULL; - s->v = 0; + int v; + v = s->v; + if (v >= TOK_IDENT && v < tok_ident) { + table_ident[v - TOK_IDENT]->sym_define = NULL; + } + s->v = 0; } ST_INLN Sym *define_find(int v) { - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_define; + v -= TOK_IDENT; + if ((unsigned) v >= (unsigned) (tok_ident - TOK_IDENT)) { + return NULL; + } + return table_ident[v]->sym_define; } /* free define stack until top reaches 'b' */ ST_FUNC void free_defines(Sym *b) { - Sym *top, *top1; - int v; + Sym *top, *top1; + int v; - top = define_stack; - while (top != b) { - top1 = top->prev; - /* do not free args or predefined defines */ - if (top->d) - tok_str_free(top->d); - v = top->v; - if (v >= TOK_IDENT && v < tok_ident) - table_ident[v - TOK_IDENT]->sym_define = NULL; - sym_free(top); - top = top1; - } - define_stack = b; + top = define_stack; + while (top != b) { + top1 = top->prev; + /* do not free args or predefined defines */ + if (top->d) { + tok_str_free (top->d); + } + v = top->v; + if (v >= TOK_IDENT && v < tok_ident) { + table_ident[v - TOK_IDENT]->sym_define = NULL; + } + sym_free (top); + top = top1; + } + define_stack = b; } /* label lookup */ ST_FUNC Sym *label_find(int v) { - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_label; + v -= TOK_IDENT; + if ((unsigned) v >= (unsigned) (tok_ident - TOK_IDENT)) { + return NULL; + } + return table_ident[v]->sym_label; } ST_FUNC Sym *label_push(Sym **ptop, int v, int flags) { - Sym *s, **ps; - s = sym_push2(ptop, v, 0, 0); - s->r = flags; - ps = &table_ident[v - TOK_IDENT]->sym_label; - if (ptop == &global_label_stack) { - /* modify the top most local identifier, so that - sym_identifier will point to 's' when popped */ - while (*ps != NULL) - ps = &(*ps)->prev_tok; - } - s->prev_tok = *ps; - *ps = s; - return s; + Sym *s, **ps; + s = sym_push2 (ptop, v, 0, 0); + s->r = flags; + ps = &table_ident[v - TOK_IDENT]->sym_label; + if (ptop == &global_label_stack) { + /* modify the top most local identifier, so that + sym_identifier will point to 's' when popped */ + while (*ps != NULL) + ps = &(*ps)->prev_tok; + } + s->prev_tok = *ps; + *ps = s; + return s; } /* pop labels until element last is reached. Look if any labels are undefined. Define symbols if '&&label' was used. */ ST_FUNC void label_pop(Sym **ptop, Sym *slast) { - Sym *s, *s1; - for(s = *ptop; s != slast; s = s1) { - s1 = s->prev; - if (s->r == LABEL_DECLARED) { - tcc_warning("label '%s' declared but not used", get_tok_str(s->v, NULL)); - } else if (s->r == LABEL_FORWARD) { - tcc_error("label '%s' used but not defined", - get_tok_str(s->v, NULL)); - } - /* remove label */ - table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok; - sym_free(s); - } - *ptop = slast; + Sym *s, *s1; + for (s = *ptop; s != slast; s = s1) { + s1 = s->prev; + if (s->r == LABEL_DECLARED) { + tcc_warning ("label '%s' declared but not used", get_tok_str (s->v, NULL)); + } else if (s->r == LABEL_FORWARD) { + tcc_error ("label '%s' used but not defined", + get_tok_str (s->v, NULL)); + } + /* remove label */ + table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok; + sym_free (s); + } + *ptop = slast; } /* eval an expression for #if/#elif */ static int expr_preprocess(void) { - int c, t; - TokenString str; + int c, t; + TokenString str; - tok_str_new(&str); - while (tok != TOK_LINEFEED && tok != TOK_EOF) { - next(); /* do macro subst */ - if (tok == TOK_DEFINED) { - next_nomacro(); - t = tok; - if (t == '(') - next_nomacro(); - c = define_find(tok) != 0; - if (t == '(') - next_nomacro(); - tok = TOK_CINT; - tokc.i = c; - } else if (tok >= TOK_IDENT) { - /* if undefined macro */ - tok = TOK_CINT; - tokc.i = 0; - } - tok_str_add_tok(&str); - } - tok_str_add(&str, -1); /* simulate end of file */ - tok_str_add(&str, 0); - /* now evaluate C constant expression */ - macro_ptr = str.str; - next(); - c = expr_const(); - macro_ptr = NULL; - tok_str_free(str.str); - return c != 0; + tok_str_new (&str); + while (tok != TOK_LINEFEED && tok != TOK_EOF) { + next ();/* do macro subst */ + if (tok == TOK_DEFINED) { + next_nomacro (); + t = tok; + if (t == '(') { + next_nomacro (); + } + c = define_find (tok) != 0; + if (t == '(') { + next_nomacro (); + } + tok = TOK_CINT; + tokc.i = c; + } else if (tok >= TOK_IDENT) { + /* if undefined macro */ + tok = TOK_CINT; + tokc.i = 0; + } + tok_str_add_tok (&str); + } + tok_str_add (&str, -1); /* simulate end of file */ + tok_str_add (&str, 0); + /* now evaluate C constant expression */ + macro_ptr = str.str; + next (); + c = expr_const (); + macro_ptr = NULL; + tok_str_free (str.str); + return c != 0; } #if defined(PARSE_DEBUG) || defined(PP_DEBUG) static void tok_print(int *str) { - int t; - CValue cval; + int t; + CValue cval; - printf("<"); - while (1) { - TOK_GET(&t, &str, &cval); - if (!t) - break; - printf("%s", get_tok_str(t, &cval)); - } - printf(">\n"); + printf ("<"); + while (1) { + TOK_GET (&t, &str, &cval); + if (!t) { + break; + } + printf ("%s", get_tok_str (t, &cval)); + } + printf (">\n"); } #endif /* parse after #define */ ST_FUNC void parse_define(void) { - Sym *s, *first, **ps; - int v, t, varg, is_vaargs, spc; - TokenString str; + Sym *s, *first, **ps; + int v, t, varg, is_vaargs, spc; + TokenString str; - v = tok; - if (v < TOK_IDENT) - tcc_error("invalid macro name '%s'", get_tok_str(tok, &tokc)); - /* XXX: should check if same macro (ANSI) */ - first = NULL; - t = MACRO_OBJ; - /* '(' must be just after macro definition for MACRO_FUNC */ - next_nomacro_spc(); - if (tok == '(') { - next_nomacro(); - ps = &first; - while (tok != ')') { - varg = tok; - next_nomacro(); - is_vaargs = 0; - if (varg == TOK_DOTS) { - varg = TOK___VA_ARGS__; - is_vaargs = 1; - } else if (tok == TOK_DOTS && gnu_ext) { - is_vaargs = 1; - next_nomacro(); - } - if (varg < TOK_IDENT) - tcc_error("badly punctuated parameter list"); - s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0); - *ps = s; - ps = &s->next; - if (tok != ',') - break; - next_nomacro(); - } - if (tok == ')') - next_nomacro_spc(); - t = MACRO_FUNC; - } - tok_str_new(&str); - spc = 2; - /* EOF testing necessary for '-D' handling */ - while (tok != TOK_LINEFEED && tok != TOK_EOF) { - /* remove spaces around ## and after '#' */ - if (TOK_TWOSHARPS == tok) { - if (1 == spc) - --str.len; - spc = 2; - } else if ('#' == tok) { - spc = 2; - } else if (check_space(tok, &spc)) { - goto skip; - } - tok_str_add2(&str, tok, &tokc); - skip: - next_nomacro_spc(); - } - if (spc == 1) - --str.len; /* remove trailing space */ - tok_str_add(&str, 0); + v = tok; + if (v < TOK_IDENT) { + tcc_error ("invalid macro name '%s'", get_tok_str (tok, &tokc)); + } + /* XXX: should check if same macro (ANSI) */ + first = NULL; + t = MACRO_OBJ; + /* '(' must be just after macro definition for MACRO_FUNC */ + next_nomacro_spc (); + if (tok == '(') { + next_nomacro (); + ps = &first; + while (tok != ')') { + varg = tok; + next_nomacro (); + is_vaargs = 0; + if (varg == TOK_DOTS) { + varg = TOK___VA_ARGS__; + is_vaargs = 1; + } else if (tok == TOK_DOTS && gnu_ext) { + is_vaargs = 1; + next_nomacro (); + } + if (varg < TOK_IDENT) { + tcc_error ("badly punctuated parameter list"); + } + s = sym_push2 (&define_stack, varg | SYM_FIELD, is_vaargs, 0); + *ps = s; + ps = &s->next; + if (tok != ',') { + break; + } + next_nomacro (); + } + if (tok == ')') { + next_nomacro_spc (); + } + t = MACRO_FUNC; + } + tok_str_new (&str); + spc = 2; + /* EOF testing necessary for '-D' handling */ + while (tok != TOK_LINEFEED && tok != TOK_EOF) { + /* remove spaces around ## and after '#' */ + if (TOK_TWOSHARPS == tok) { + if (1 == spc) { + --str.len; + } + spc = 2; + } else if ('#' == tok) { + spc = 2; + } else if (check_space (tok, &spc)) { + goto skip; + } + tok_str_add2 (&str, tok, &tokc); +skip: + next_nomacro_spc (); + } + if (spc == 1) { + --str.len; /* remove trailing space */ + } + tok_str_add (&str, 0); #ifdef PP_DEBUG - printf("define %s %d: ", get_tok_str(v, NULL), t); - tok_print(str.str); + printf ("define %s %d: ", get_tok_str (v, NULL), t); + tok_print (str.str); #endif - define_push(v, t, str.str, first); + define_push (v, t, str.str, first); } static inline int hash_cached_include(const char *filename) { - const unsigned char *s; - unsigned int h; + const unsigned char *s; + unsigned int h; - h = TOK_HASH_INIT; - s = (const unsigned char *)filename; - while (*s) { - h = TOK_HASH_FUNC(h, *s); - s++; - } - h &= (CACHED_INCLUDES_HASH_SIZE - 1); - return h; + h = TOK_HASH_INIT; + s = (const unsigned char *) filename; + while (*s) { + h = TOK_HASH_FUNC (h, *s); + s++; + } + h &= (CACHED_INCLUDES_HASH_SIZE - 1); + return h; } static CachedInclude *search_cached_include(TCCState *s1, const char *filename) { - CachedInclude *e; - int i, h; - h = hash_cached_include(filename); - i = s1->cached_includes_hash[h]; - for(;;) { - if (i == 0) - break; - e = s1->cached_includes[i - 1]; - if (0 == PATHCMP(e->filename, filename)) - return e; - i = e->hash_next; - } - return NULL; + CachedInclude *e; + int i, h; + h = hash_cached_include (filename); + i = s1->cached_includes_hash[h]; + for (;;) { + if (i == 0) { + break; + } + e = s1->cached_includes[i - 1]; + if (0 == PATHCMP (e->filename, filename)) { + return e; + } + i = e->hash_next; + } + return NULL; } static inline void add_cached_include(TCCState *s1, const char *filename, int ifndef_macro) { - CachedInclude *e; - int h; + CachedInclude *e; + int h; - if (search_cached_include(s1, filename)) - return; + if (search_cached_include (s1, filename)) { + return; + } #ifdef INC_DEBUG - printf("adding cached '%s' %s\n", filename, get_tok_str(ifndef_macro, NULL)); + printf ("adding cached '%s' %s\n", filename, get_tok_str (ifndef_macro, NULL)); #endif - e = malloc(sizeof(CachedInclude) + strlen(filename)); - strcpy(e->filename, filename); - e->ifndef_macro = ifndef_macro; - dynarray_add((void ***)&s1->cached_includes, &s1->nb_cached_includes, e); - /* add in hash table */ - h = hash_cached_include(filename); - e->hash_next = s1->cached_includes_hash[h]; - s1->cached_includes_hash[h] = s1->nb_cached_includes; + e = malloc (sizeof(CachedInclude) + strlen (filename)); + strcpy (e->filename, filename); + e->ifndef_macro = ifndef_macro; + dynarray_add ((void ***) &s1->cached_includes, &s1->nb_cached_includes, e); + /* add in hash table */ + h = hash_cached_include (filename); + e->hash_next = s1->cached_includes_hash[h]; + s1->cached_includes_hash[h] = s1->nb_cached_includes; } static void pragma_parse(TCCState *s1) { - int val; + int val; - next(); - if (tok == TOK_pack) { - /* - This may be: - #pragma pack(1) // set - #pragma pack() // reset to default - #pragma pack(push,1) // push & set - #pragma pack(pop) // restore previous - */ - next(); - skip('('); - if (tok == TOK_ASM_pop) { - next(); - if (s1->pack_stack_ptr <= s1->pack_stack) { - stk_error: - tcc_error("out of pack stack"); - } - s1->pack_stack_ptr--; - } else { - val = 0; - if (tok != ')') { - if (tok == TOK_ASM_push) { - next(); - if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) - goto stk_error; - s1->pack_stack_ptr++; - skip(','); - } - if (tok != TOK_CINT) { - pack_error: - tcc_error("invalid pack pragma"); - } - val = tokc.i; - if (val < 1 || val > 16 || (val & (val - 1)) != 0) - goto pack_error; - next(); - } - *s1->pack_stack_ptr = val; - skip(')'); - } - } + next (); + if (tok == TOK_pack) { + /* + This may be: + #pragma pack(1) // set + #pragma pack() // reset to default + #pragma pack(push,1) // push & set + #pragma pack(pop) // restore previous + */ + next (); + skip ('('); + if (tok == TOK_ASM_pop) { + next (); + if (s1->pack_stack_ptr <= s1->pack_stack) { +stk_error: + tcc_error ("out of pack stack"); + } + s1->pack_stack_ptr--; + } else { + val = 0; + if (tok != ')') { + if (tok == TOK_ASM_push) { + next (); + if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) { + goto stk_error; + } + s1->pack_stack_ptr++; + skip (','); + } + if (tok != TOK_CINT) { +pack_error: + tcc_error ("invalid pack pragma"); + } + val = tokc.i; + if (val < 1 || val > 16 || (val & (val - 1)) != 0) { + goto pack_error; + } + next (); + } + *s1->pack_stack_ptr = val; + skip (')'); + } + } } /* is_bof is true if first non space token at beginning of file */ ST_FUNC void preprocess(int is_bof) { - TCCState *s1 = tcc_state; - int i, c, n, saved_parse_flags; - char buf[1024], *q; - Sym *s; + TCCState *s1 = tcc_state; + int i, c, n, saved_parse_flags; + char buf[1024], *q; + Sym *s; - saved_parse_flags = parse_flags; - parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | - PARSE_FLAG_LINEFEED; - next_nomacro(); - redo: - switch(tok) { - case TOK_DEFINE: - next_nomacro(); - parse_define(); - break; - case TOK_UNDEF: - next_nomacro(); - s = define_find(tok); - /* undefine symbol by putting an invalid name */ - if (s) - define_undef(s); - break; - case TOK_INCLUDE: - case TOK_INCLUDE_NEXT: - ch = file->buf_ptr[0]; - /* XXX: incorrect if comments : use next_nomacro with a special mode */ - skip_spaces(); - if (ch == '<') { - c = '>'; - goto read_name; - } else if (ch == '\"') { - c = ch; - read_name: - inp(); - q = buf; - while (ch != c && ch != '\n' && ch != CH_EOF) { - if ((q - buf) < sizeof(buf) - 1) - *q++ = ch; - if (ch == '\\') { - if (handle_stray_noerror() == 0) - --q; - } else - inp(); - } - *q = '\0'; - minp(); -#if 0 - /* eat all spaces and comments after include */ - /* XXX: slightly incorrect */ - while (ch1 != '\n' && ch1 != CH_EOF) - inp(); -#endif - } else { - /* computed #include : either we have only strings or - we have anything enclosed in '<>' */ - next(); - buf[0] = '\0'; - if (tok == TOK_STR) { - while (tok != TOK_LINEFEED) { - if (tok != TOK_STR) { - include_syntax: - tcc_error("'#include' expects \"FILENAME\" or "); - } - pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data); - next(); - } - c = '\"'; - } else { - int len; - while (tok != TOK_LINEFEED) { - pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc)); - next(); - } - len = strlen(buf); - /* check syntax and remove '<>' */ - if (len < 2 || buf[0] != '<' || buf[len - 1] != '>') - goto include_syntax; - memmove(buf, buf + 1, len - 2); - buf[len - 2] = '\0'; - c = '>'; - } - } - - if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) - tcc_error("#include recursion too deep"); - /* store current file in stack, but increment stack later below */ - *s1->include_stack_ptr = file; - - n = s1->nb_include_paths + s1->nb_sysinclude_paths; - for (i = -2; i < n; ++i) { - char buf1[sizeof file->filename]; - CachedInclude *e; - BufferedFile **f; - const char *path; - - if (i == -2) { - /* check absolute include path */ - if (!IS_ABSPATH(buf)) - continue; - buf1[0] = 0; - i = n; /* force end loop */ - - } else if (i == -1) { - /* search in current dir if "header.h" */ - if (c != '\"') - continue; - path = file->filename; - pstrncpy(buf1, path, tcc_basename(path) - path); - - } else { - /* search in all the include paths */ - if (i < s1->nb_include_paths) - path = s1->include_paths[i]; - else - path = s1->sysinclude_paths[i - s1->nb_include_paths]; - pstrcpy(buf1, sizeof(buf1), path); - pstrcat(buf1, sizeof(buf1), "/"); - } - - pstrcat(buf1, sizeof(buf1), buf); - - if (tok == TOK_INCLUDE_NEXT) - for (f = s1->include_stack_ptr; f >= s1->include_stack; --f) - if (0 == PATHCMP((*f)->filename, buf1)) { -#ifdef INC_DEBUG - printf("%s: #include_next skipping %s\n", file->filename, buf1); -#endif - goto include_trynext; - } - - e = search_cached_include(s1, buf1); - if (e && define_find(e->ifndef_macro)) { - /* no need to parse the include because the 'ifndef macro' - is defined */ -#ifdef INC_DEBUG - printf("%s: skipping cached %s\n", file->filename, buf1); -#endif - goto include_done; - } - - if (tcc_open(s1, buf1) < 0) -include_trynext: - continue; - fprintf (stderr, "#include \"%s\"\n", buf1); - -#ifdef INC_DEBUG - fprintf(stderr, "%s: including %s\n", file->prev->filename, file->filename); -#endif - /* update target deps */ - dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps, - strdup(buf1)); - /* push current file in stack */ - ++s1->include_stack_ptr; - tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL; - ch = file->buf_ptr[0]; - goto the_end; - } - /* load include file from the same directory as the parent */ - { - char filepath[1024]; - int filepath_len; - char *e = file->filename + strlen (file->filename); - while (e>file->filename) { - if (*e=='/') { - break; - } - e--; + saved_parse_flags = parse_flags; + parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | + PARSE_FLAG_LINEFEED; + next_nomacro (); +redo: + switch (tok) { + case TOK_DEFINE: + next_nomacro (); + parse_define (); + break; + case TOK_UNDEF: + next_nomacro (); + s = define_find (tok); + /* undefine symbol by putting an invalid name */ + if (s) { + define_undef (s); } - filepath_len = R_MIN ((size_t)(e - file->filename)+1, sizeof (filepath) - 1); - memcpy (filepath, file->filename, filepath_len); - strcpy (filepath+filepath_len, buf); - if (tcc_open (s1, filepath) < 0) { - snprintf (filepath, sizeof (filepath), - "/usr/include/%s", buf); + break; + case TOK_INCLUDE: + case TOK_INCLUDE_NEXT: + ch = file->buf_ptr[0]; + /* XXX: incorrect if comments : use next_nomacro with a special mode */ + skip_spaces (); + if (ch == '<') { + c = '>'; + goto read_name; + } else if (ch == '\"') { + c = ch; +read_name: + inp (); + q = buf; + while (ch != c && ch != '\n' && ch != CH_EOF) { + if ((q - buf) < sizeof(buf) - 1) { + *q++ = ch; + } + if (ch == '\\') { + if (handle_stray_noerror () == 0) { + --q; + } + } else { + inp (); + } + } + *q = '\0'; + minp (); +#if 0 + /* eat all spaces and comments after include */ + /* XXX: slightly incorrect */ + while (ch1 != '\n' && ch1 != CH_EOF) + inp (); +#endif + } else { + /* computed #include : either we have only strings or + we have anything enclosed in '<>' */ + next (); + buf[0] = '\0'; + if (tok == TOK_STR) { + while (tok != TOK_LINEFEED) { + if (tok != TOK_STR) { +include_syntax: + tcc_error ("'#include' expects \"FILENAME\" or "); + } + pstrcat (buf, sizeof(buf), (char *) tokc.cstr->data); + next (); + } + c = '\"'; + } else { + int len; + while (tok != TOK_LINEFEED) { + pstrcat (buf, sizeof(buf), get_tok_str (tok, &tokc)); + next (); + } + len = strlen (buf); + /* check syntax and remove '<>' */ + if (len < 2 || buf[0] != '<' || buf[len - 1] != '>') { + goto include_syntax; + } + memmove (buf, buf + 1, len - 2); + buf[len - 2] = '\0'; + c = '>'; + } + } + + if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) { + tcc_error ("#include recursion too deep"); + } + /* store current file in stack, but increment stack later below */ + *s1->include_stack_ptr = file; + + n = s1->nb_include_paths + s1->nb_sysinclude_paths; + for (i = -2; i < n; ++i) { + char buf1[sizeof file->filename]; + CachedInclude *e; + BufferedFile **f; + const char *path; + + if (i == -2) { + /* check absolute include path */ + if (!IS_ABSPATH (buf)) { + continue; + } + buf1[0] = 0; + i = n; /* force end loop */ + + } else if (i == -1) { + /* search in current dir if "header.h" */ + if (c != '\"') { + continue; + } + path = file->filename; + pstrncpy (buf1, path, tcc_basename (path) - path); + + } else { + /* search in all the include paths */ + if (i < s1->nb_include_paths) { + path = s1->include_paths[i]; + } else { + path = s1->sysinclude_paths[i - s1->nb_include_paths]; + } + pstrcpy (buf1, sizeof(buf1), path); + pstrcat (buf1, sizeof(buf1), "/"); + } + + pstrcat (buf1, sizeof(buf1), buf); + + if (tok == TOK_INCLUDE_NEXT) { + for (f = s1->include_stack_ptr; f >= s1->include_stack; --f) { + if (0 == PATHCMP ((*f)->filename, buf1)) { +#ifdef INC_DEBUG + printf ("%s: #include_next skipping %s\n", file->filename, buf1); +#endif + goto include_trynext; + } + } + } + + e = search_cached_include (s1, buf1); + if (e && define_find (e->ifndef_macro)) { + /* no need to parse the include because the 'ifndef macro' + is defined */ +#ifdef INC_DEBUG + printf ("%s: skipping cached %s\n", file->filename, buf1); +#endif + goto include_done; + } + + if (tcc_open (s1, buf1) < 0) { +include_trynext: + continue; + } + fprintf (stderr, "#include \"%s\"\n", buf1); + +#ifdef INC_DEBUG + fprintf (stderr, "%s: including %s\n", file->prev->filename, file->filename); +#endif + /* update target deps */ + dynarray_add ((void ***) &s1->target_deps, &s1->nb_target_deps, + strdup (buf1)); + /* push current file in stack */ + ++s1->include_stack_ptr; + tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL; + ch = file->buf_ptr[0]; + goto the_end; + } + /* load include file from the same directory as the parent */ + { + char filepath[1024]; + int filepath_len; + char *e = file->filename + strlen (file->filename); + while (e > file->filename) { + if (*e == '/') { + break; + } + e--; + } + filepath_len = R_MIN ((size_t) (e - file->filename) + 1, sizeof (filepath) - 1); + memcpy (filepath, file->filename, filepath_len); + strcpy (filepath + filepath_len, buf); if (tcc_open (s1, filepath) < 0) { - tcc_error ("include file '%s' not found", filepath); + snprintf (filepath, sizeof (filepath), + "/usr/include/%s", buf); + if (tcc_open (s1, filepath) < 0) { + tcc_error ("include file '%s' not found", filepath); + } else { + fprintf (stderr, "#include \"%s\"\n", filepath); + ++s1->include_stack_ptr; + tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL; + ch = file->buf_ptr[0]; + goto the_end; + } } else { fprintf (stderr, "#include \"%s\"\n", filepath); ++s1->include_stack_ptr; @@ -1521,250 +1599,263 @@ include_trynext: ch = file->buf_ptr[0]; goto the_end; } - } else { - fprintf (stderr, "#include \"%s\"\n", filepath); - ++s1->include_stack_ptr; - tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL; - ch = file->buf_ptr[0]; + } +include_done: + break; + case TOK_IFNDEF: + c = 1; + goto do_ifdef; + case TOK_IF: + c = expr_preprocess (); + goto do_if; + case TOK_IFDEF: + c = 0; +do_ifdef: + next_nomacro (); + if (tok < TOK_IDENT) { + tcc_error ("invalid argument for '#if%sdef'", c? "n": ""); + } + if (is_bof) { + if (c) { +#ifdef INC_DEBUG + printf ("#ifndef %s\n", get_tok_str (tok, NULL)); +#endif + file->ifndef_macro = tok; + } + } + c = (define_find (tok) != 0) ^ c; +do_if: + if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) { + tcc_error ("memory full"); + } + *s1->ifdef_stack_ptr++ = c; + goto test_skip; + case TOK_ELSE: + if (s1->ifdef_stack_ptr == s1->ifdef_stack) { + tcc_error ("#else without matching #if"); + } + if (s1->ifdef_stack_ptr[-1] & 2) { + tcc_error ("#else after #else"); + } + c = (s1->ifdef_stack_ptr[-1] ^= 3); + goto test_else; + case TOK_ELIF: + if (s1->ifdef_stack_ptr == s1->ifdef_stack) { + tcc_error ("#elif without matching #if"); + } + c = s1->ifdef_stack_ptr[-1]; + if (c > 1) { + tcc_error ("#elif after #else"); + } + /* last #if/#elif expression was true: we skip */ + if (c == 1) { + goto skip; + } + c = expr_preprocess (); + s1->ifdef_stack_ptr[-1] = c; +test_else: + if (s1->ifdef_stack_ptr == file->ifdef_stack_ptr + 1) { + file->ifndef_macro = 0; + } +test_skip: + if (!(c & 1)) { +skip: + preprocess_skip (); + is_bof = 0; + goto redo; + } + break; + case TOK_ENDIF: + if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr) { + tcc_error ("#endif without matching #if"); + } + s1->ifdef_stack_ptr--; + /* '#ifndef macro' was at the start of file. Now we check if + an '#endif' is exactly at the end of file */ + if (file->ifndef_macro && + s1->ifdef_stack_ptr == file->ifdef_stack_ptr) { + file->ifndef_macro_saved = file->ifndef_macro; + /* need to set to zero to avoid false matches if another + #ifndef at middle of file */ + file->ifndef_macro = 0; + while (tok != TOK_LINEFEED) + next_nomacro (); + tok_flags |= TOK_FLAG_ENDIF; goto the_end; } + break; + case TOK_LINE: + next (); + if (tok != TOK_CINT) { + tcc_error ("#line"); + } + file->line_num = tokc.i - 1; /* the line number will be incremented after */ + next (); + if (tok != TOK_LINEFEED) { + if (tok != TOK_STR) { + tcc_error ("#line"); + } + pstrcpy (file->filename, sizeof(file->filename), + (char *) tokc.cstr->data); + } + break; + case TOK_ERROR: + case TOK_WARNING: + c = tok; + ch = file->buf_ptr[0]; + skip_spaces (); + q = buf; + while (ch != '\n' && ch != CH_EOF) { + if ((q - buf) < sizeof(buf) - 1) { + *q++ = ch; + } + if (ch == '\\') { + if (handle_stray_noerror () == 0) { + --q; + } + } else { + inp (); + } + } + *q = '\0'; + tcc_warning ("#%s %s", c == TOK_ERROR? "error": "warning", buf); + break; + case TOK_PRAGMA: + pragma_parse (s1); + break; + default: + if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_PPNUM) { + /* '!' is ignored to allow C scripts. numbers are ignored + to emulate cpp behaviour */ + } else { + if (!(saved_parse_flags & PARSE_FLAG_ASM_COMMENTS)) { + tcc_warning ("Ignoring unknown preprocessing directive #%s", get_tok_str (tok, &tokc)); + } else { + /* this is a gas line comment in an 'S' file. */ + file->buf_ptr = parse_line_comment (file->buf_ptr); + goto the_end; + } + } + break; } -include_done: - break; - case TOK_IFNDEF: - c = 1; - goto do_ifdef; - case TOK_IF: - c = expr_preprocess(); - goto do_if; - case TOK_IFDEF: - c = 0; - do_ifdef: - next_nomacro(); - if (tok < TOK_IDENT) - tcc_error("invalid argument for '#if%sdef'", c ? "n" : ""); - if (is_bof) { - if (c) { -#ifdef INC_DEBUG - printf("#ifndef %s\n", get_tok_str(tok, NULL)); -#endif - file->ifndef_macro = tok; - } - } - c = (define_find(tok) != 0) ^ c; - do_if: - if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) - tcc_error("memory full"); - *s1->ifdef_stack_ptr++ = c; - goto test_skip; - case TOK_ELSE: - if (s1->ifdef_stack_ptr == s1->ifdef_stack) - tcc_error("#else without matching #if"); - if (s1->ifdef_stack_ptr[-1] & 2) - tcc_error("#else after #else"); - c = (s1->ifdef_stack_ptr[-1] ^= 3); - goto test_else; - case TOK_ELIF: - if (s1->ifdef_stack_ptr == s1->ifdef_stack) - tcc_error("#elif without matching #if"); - c = s1->ifdef_stack_ptr[-1]; - if (c > 1) - tcc_error("#elif after #else"); - /* last #if/#elif expression was true: we skip */ - if (c == 1) - goto skip; - c = expr_preprocess(); - s1->ifdef_stack_ptr[-1] = c; - test_else: - if (s1->ifdef_stack_ptr == file->ifdef_stack_ptr + 1) - file->ifndef_macro = 0; - test_skip: - if (!(c & 1)) { - skip: - preprocess_skip(); - is_bof = 0; - goto redo; - } - break; - case TOK_ENDIF: - if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr) - tcc_error("#endif without matching #if"); - s1->ifdef_stack_ptr--; - /* '#ifndef macro' was at the start of file. Now we check if - an '#endif' is exactly at the end of file */ - if (file->ifndef_macro && - s1->ifdef_stack_ptr == file->ifdef_stack_ptr) { - file->ifndef_macro_saved = file->ifndef_macro; - /* need to set to zero to avoid false matches if another - #ifndef at middle of file */ - file->ifndef_macro = 0; - while (tok != TOK_LINEFEED) - next_nomacro(); - tok_flags |= TOK_FLAG_ENDIF; - goto the_end; - } - break; - case TOK_LINE: - next(); - if (tok != TOK_CINT) - tcc_error("#line"); - file->line_num = tokc.i - 1; /* the line number will be incremented after */ - next(); - if (tok != TOK_LINEFEED) { - if (tok != TOK_STR) - tcc_error("#line"); - pstrcpy(file->filename, sizeof(file->filename), - (char *)tokc.cstr->data); - } - break; - case TOK_ERROR: - case TOK_WARNING: - c = tok; - ch = file->buf_ptr[0]; - skip_spaces(); - q = buf; - while (ch != '\n' && ch != CH_EOF) { - if ((q - buf) < sizeof(buf) - 1) - *q++ = ch; - if (ch == '\\') { - if (handle_stray_noerror() == 0) - --q; - } else - inp(); - } - *q = '\0'; - tcc_warning("#%s %s",c==TOK_ERROR?"error":"warning",buf); - break; - case TOK_PRAGMA: - pragma_parse(s1); - break; - default: - if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_PPNUM) { - /* '!' is ignored to allow C scripts. numbers are ignored - to emulate cpp behaviour */ - } else { - if (!(saved_parse_flags & PARSE_FLAG_ASM_COMMENTS)) - tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc)); - else { - /* this is a gas line comment in an 'S' file. */ - file->buf_ptr = parse_line_comment(file->buf_ptr); - goto the_end; - } - } - break; - } - /* ignore other preprocess commands or #! for C scripts */ - while (tok != TOK_LINEFEED) - next_nomacro(); - the_end: - parse_flags = saved_parse_flags; + /* ignore other preprocess commands or #! for C scripts */ + while (tok != TOK_LINEFEED) + next_nomacro (); +the_end: + parse_flags = saved_parse_flags; } /* evaluate escape codes in a string. */ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long) { - int c, n; - const uint8_t *p; + int c, n; + const uint8_t *p; - p = buf; - for(;;) { - c = *p; - if (c == '\0') - break; - if (c == '\\') { - p++; - /* escape */ - c = *p; - switch(c) { - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - /* at most three octal digits */ - n = c - '0'; - p++; - c = *p; - if (isoct(c)) { - n = n * 8 + c - '0'; - p++; - c = *p; - if (isoct(c)) { - n = n * 8 + c - '0'; - p++; - } - } - c = n; - goto add_char_nonext; - case 'x': - case 'u': - case 'U': - p++; - n = 0; - for(;;) { - c = *p; - if (c >= 'a' && c <= 'f') - c = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - c = c - 'A' + 10; - else if (isnum(c)) - c = c - '0'; - else - break; - n = n * 16 + c; - p++; - } - c = n; - goto add_char_nonext; - case 'a': - c = '\a'; - break; - case 'b': - c = '\b'; - break; - case 'f': - c = '\f'; - break; - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case 'v': - c = '\v'; - break; - case 'e': - if (!gnu_ext) - goto invalid_escape; - c = 27; - break; - case '\'': - case '\"': - case '\\': - case '?': - break; - default: - invalid_escape: - if (c >= '!' && c <= '~') - tcc_warning("unknown escape sequence: \'\\%c\'", c); - else - tcc_warning("unknown escape sequence: \'\\x%x\'", c); - break; - } - } - p++; - add_char_nonext: - if (!is_long) - cstr_ccat(outstr, c); - else - cstr_wccat(outstr, c); - } - /* add a trailing '\0' */ - if (!is_long) - cstr_ccat(outstr, '\0'); - else - cstr_wccat(outstr, '\0'); + p = buf; + for (;;) { + c = *p; + if (c == '\0') { + break; + } + if (c == '\\') { + p++; + /* escape */ + c = *p; + switch (c) { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + /* at most three octal digits */ + n = c - '0'; + p++; + c = *p; + if (isoct (c)) { + n = n * 8 + c - '0'; + p++; + c = *p; + if (isoct (c)) { + n = n * 8 + c - '0'; + p++; + } + } + c = n; + goto add_char_nonext; + case 'x': + case 'u': + case 'U': + p++; + n = 0; + for (;;) { + c = *p; + if (c >= 'a' && c <= 'f') { + c = c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + c = c - 'A' + 10; + } else if (isnum (c)) { + c = c - '0'; + } else { + break; + } + n = n * 16 + c; + p++; + } + c = n; + goto add_char_nonext; + case 'a': + c = '\a'; + break; + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = '\v'; + break; + case 'e': + if (!gnu_ext) { + goto invalid_escape; + } + c = 27; + break; + case '\'': + case '\"': + case '\\': + case '?': + break; + default: +invalid_escape: + if (c >= '!' && c <= '~') { + tcc_warning ("unknown escape sequence: \'\\%c\'", c); + } else { + tcc_warning ("unknown escape sequence: \'\\x%x\'", c); + } + break; + } + } + p++; +add_char_nonext: + if (!is_long) { + cstr_ccat (outstr, c); + } else { + cstr_wccat (outstr, c); + } + } + /* add a trailing '\0' */ + if (!is_long) { + cstr_ccat (outstr, '\0'); + } else { + cstr_wccat (outstr, '\0'); + } } /* we use 64 bit numbers */ @@ -1773,746 +1864,779 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long /* bn = (bn << shift) | or_val */ static void bn_lshift(unsigned int *bn, int shift, int or_val) { - int i; - unsigned int v; - for(i=0;i> (32 - shift); - } + int i; + unsigned int v; + for (i = 0; i < BN_SIZE; i++) { + v = bn[i]; + bn[i] = (v << shift) | or_val; + or_val = v >> (32 - shift); + } } static void bn_zero(unsigned int *bn) { - int i; - for(i=0;i= 'a' && ch <= 'f') - t = ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'F') - t = ch - 'A' + 10; - else if (isnum(ch)) - t = ch - '0'; - else - break; - if (t >= b) - break; - if (q >= token_buf + STRING_MAX_SIZE) { - num_too_long: - tcc_error("number too long"); - } - *q++ = ch; - ch = *p++; - } - if (ch == '.' || - ((ch == 'e' || ch == 'E') && b == 10) || - ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { - if (b != 10) { - /* NOTE: strtox should support that for hexa numbers, but - non ISOC99 libcs do not support it, so we prefer to do - it by hand */ - /* hexadecimal or binary floats */ - /* XXX: handle overflows */ - *q = '\0'; - if (b == 16) - shift = 4; - else - shift = 2; - bn_zero(bn); - q = token_buf; - while (1) { - t = *q++; - if (t == '\0') { - break; - } else if (t >= 'a') { - t = t - 'a' + 10; - } else if (t >= 'A') { - t = t - 'A' + 10; - } else { - t = t - '0'; - } - bn_lshift(bn, shift, t); - } - frac_bits = 0; - if (ch == '.') { - ch = *p++; - while (1) { - t = ch; - if (t >= 'a' && t <= 'f') { - t = t - 'a' + 10; - } else if (t >= 'A' && t <= 'F') { - t = t - 'A' + 10; - } else if (t >= '0' && t <= '9') { - t = t - '0'; - } else { - break; - } - if (t >= b) - tcc_error("invalid digit"); - bn_lshift(bn, shift, t); - frac_bits += shift; - ch = *p++; - } - } - if (ch != 'p' && ch != 'P') - expect("exponent"); - ch = *p++; - s = 1; - exp_val = 0; - if (ch == '+') { - ch = *p++; - } else if (ch == '-') { - s = -1; - ch = *p++; - } - if (ch < '0' || ch > '9') - expect("exponent digits"); - while (ch >= '0' && ch <= '9') { - exp_val = exp_val * 10 + ch - '0'; - ch = *p++; - } - exp_val = exp_val * s; + /* number */ + q = token_buf; + ch = *p++; + t = ch; + ch = *p++; + *q++ = t; + b = 10; + if (t == '.') { + goto float_frac_parse; + } else if (t == '0') { + if (ch == 'x' || ch == 'X') { + q--; + ch = *p++; + b = 16; + } else if (tcc_ext && (ch == 'b' || ch == 'B')) { + q--; + ch = *p++; + b = 2; + } + } + /* parse all digits. cannot check octal numbers at this stage + because of floating point constants */ + while (1) { + if (ch >= 'a' && ch <= 'f') { + t = ch - 'a' + 10; + } else if (ch >= 'A' && ch <= 'F') { + t = ch - 'A' + 10; + } else if (isnum (ch)) { + t = ch - '0'; + } else { + break; + } + if (t >= b) { + break; + } + if (q >= token_buf + STRING_MAX_SIZE) { +num_too_long: + tcc_error ("number too long"); + } + *q++ = ch; + ch = *p++; + } + if (ch == '.' || + ((ch == 'e' || ch == 'E') && b == 10) || + ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { + if (b != 10) { + /* NOTE: strtox should support that for hexa numbers, but + non ISOC99 libcs do not support it, so we prefer to do + it by hand */ + /* hexadecimal or binary floats */ + /* XXX: handle overflows */ + *q = '\0'; + if (b == 16) { + shift = 4; + } else { + shift = 2; + } + bn_zero (bn); + q = token_buf; + while (1) { + t = *q++; + if (t == '\0') { + break; + } else if (t >= 'a') { + t = t - 'a' + 10; + } else if (t >= 'A') { + t = t - 'A' + 10; + } else { + t = t - '0'; + } + bn_lshift (bn, shift, t); + } + frac_bits = 0; + if (ch == '.') { + ch = *p++; + while (1) { + t = ch; + if (t >= 'a' && t <= 'f') { + t = t - 'a' + 10; + } else if (t >= 'A' && t <= 'F') { + t = t - 'A' + 10; + } else if (t >= '0' && t <= '9') { + t = t - '0'; + } else { + break; + } + if (t >= b) { + tcc_error ("invalid digit"); + } + bn_lshift (bn, shift, t); + frac_bits += shift; + ch = *p++; + } + } + if (ch != 'p' && ch != 'P') { + expect ("exponent"); + } + ch = *p++; + s = 1; + exp_val = 0; + if (ch == '+') { + ch = *p++; + } else if (ch == '-') { + s = -1; + ch = *p++; + } + if (ch < '0' || ch > '9') { + expect ("exponent digits"); + } + while (ch >= '0' && ch <= '9') { + exp_val = exp_val * 10 + ch - '0'; + ch = *p++; + } + exp_val = exp_val * s; - /* now we can generate the number */ - /* XXX: should patch directly float number */ - d = (double)bn[1] * 4294967296.0 + (double)bn[0]; - d = ldexp(d, exp_val - frac_bits); - t = toup(ch); - if (t == 'F') { - ch = *p++; - tok = TOK_CFLOAT; - /* float : should handle overflow */ - tokc.f = (float)d; - } else if (t == 'L') { - ch = *p++; + /* now we can generate the number */ + /* XXX: should patch directly float number */ + d = (double) bn[1] * 4294967296.0 + (double) bn[0]; + d = ldexp (d, exp_val - frac_bits); + t = toup (ch); + if (t == 'F') { + ch = *p++; + tok = TOK_CFLOAT; + /* float : should handle overflow */ + tokc.f = (float) d; + } else if (t == 'L') { + ch = *p++; #ifdef TCC_TARGET_PE - tok = TOK_CDOUBLE; - tokc.d = d; + tok = TOK_CDOUBLE; + tokc.d = d; #else - tok = TOK_CLDOUBLE; - /* XXX: not large enough */ - tokc.ld = (long double)d; + tok = TOK_CLDOUBLE; + /* XXX: not large enough */ + tokc.ld = (long double) d; #endif - } else { - tok = TOK_CDOUBLE; - tokc.d = d; - } - } else { - /* decimal floats */ - if (ch == '.') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - float_frac_parse: - while (ch >= '0' && ch <= '9') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - } - } - if (ch == 'e' || ch == 'E') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - if (ch == '-' || ch == '+') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - } - if (ch < '0' || ch > '9') - expect("exponent digits"); - while (ch >= '0' && ch <= '9') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - } - } - *q = '\0'; - t = toup(ch); - errno = 0; - if (t == 'F') { - ch = *p++; - tok = TOK_CFLOAT; - tokc.f = strtof(token_buf, NULL); - } else if (t == 'L') { - ch = *p++; - tok = TOK_CDOUBLE; - tokc.d = strtod(token_buf, NULL); + } else { + tok = TOK_CDOUBLE; + tokc.d = d; + } + } else { + /* decimal floats */ + if (ch == '.') { + if (q >= token_buf + STRING_MAX_SIZE) { + goto num_too_long; + } + *q++ = ch; + ch = *p++; +float_frac_parse: + while (ch >= '0' && ch <= '9') { + if (q >= token_buf + STRING_MAX_SIZE) { + goto num_too_long; + } + *q++ = ch; + ch = *p++; + } + } + if (ch == 'e' || ch == 'E') { + if (q >= token_buf + STRING_MAX_SIZE) { + goto num_too_long; + } + *q++ = ch; + ch = *p++; + if (ch == '-' || ch == '+') { + if (q >= token_buf + STRING_MAX_SIZE) { + goto num_too_long; + } + *q++ = ch; + ch = *p++; + } + if (ch < '0' || ch > '9') { + expect ("exponent digits"); + } + while (ch >= '0' && ch <= '9') { + if (q >= token_buf + STRING_MAX_SIZE) { + goto num_too_long; + } + *q++ = ch; + ch = *p++; + } + } + *q = '\0'; + t = toup (ch); + errno = 0; + if (t == 'F') { + ch = *p++; + tok = TOK_CFLOAT; + tokc.f = strtof (token_buf, NULL); + } else if (t == 'L') { + ch = *p++; + tok = TOK_CDOUBLE; + tokc.d = strtod (token_buf, NULL); #if 0 #ifdef TCC_TARGET_PE - tok = TOK_CDOUBLE; - tokc.d = strtod(token_buf, NULL); + tok = TOK_CDOUBLE; + tokc.d = strtod (token_buf, NULL); #else - tok = TOK_CLDOUBLE; - tokc.ld = strtold(token_buf, NULL); + tok = TOK_CLDOUBLE; + tokc.ld = strtold (token_buf, NULL); #endif #endif - } else { - tok = TOK_CDOUBLE; - tokc.d = strtod(token_buf, NULL); - } - } - } else { - unsigned long long n, n1; - int lcount, ucount; + } else { + tok = TOK_CDOUBLE; + tokc.d = strtod (token_buf, NULL); + } + } + } else { + unsigned long long n, n1; + int lcount, ucount; - /* integer number */ - *q = '\0'; - q = token_buf; - if (b == 10 && *q == '0') { - b = 8; - q++; - } - n = 0; - while(1) { - t = *q++; - /* no need for checks except for base 10 / 8 errors */ - if (t == '\0') { - break; - } else if (t >= 'a') { - t = t - 'a' + 10; - } else if (t >= 'A') { - t = t - 'A' + 10; - } else { - t = t - '0'; - if (t >= b) - tcc_error("invalid digit"); - } - n1 = n; - n = n * b + t; - /* detect overflow */ - /* XXX: this test is not reliable */ - if (n < n1) - tcc_error("integer constant overflow"); - } + /* integer number */ + *q = '\0'; + q = token_buf; + if (b == 10 && *q == '0') { + b = 8; + q++; + } + n = 0; + while (1) { + t = *q++; + /* no need for checks except for base 10 / 8 errors */ + if (t == '\0') { + break; + } else if (t >= 'a') { + t = t - 'a' + 10; + } else if (t >= 'A') { + t = t - 'A' + 10; + } else { + t = t - '0'; + if (t >= b) { + tcc_error ("invalid digit"); + } + } + n1 = n; + n = n * b + t; + /* detect overflow */ + /* XXX: this test is not reliable */ + if (n < n1) { + tcc_error ("integer constant overflow"); + } + } - /* XXX: not exactly ANSI compliant */ - if ((n & 0xffffffff00000000LL) != 0) { - if ((n >> 63) != 0) - tok = TOK_CULLONG; - else - tok = TOK_CLLONG; - } else if (n > 0x7fffffff) { - tok = TOK_CUINT; - } else { - tok = TOK_CINT; - } - lcount = 0; - ucount = 0; - for(;;) { - t = toup(ch); - if (t == 'L') { - if (lcount >= 2) - tcc_error("three 'l's in integer constant"); - lcount++; + /* XXX: not exactly ANSI compliant */ + if ((n & 0xffffffff00000000LL) != 0) { + if ((n >> 63) != 0) { + tok = TOK_CULLONG; + } else { + tok = TOK_CLLONG; + } + } else if (n > 0x7fffffff) { + tok = TOK_CUINT; + } else { + tok = TOK_CINT; + } + lcount = 0; + ucount = 0; + for (;;) { + t = toup (ch); + if (t == 'L') { + if (lcount >= 2) { + tcc_error ("three 'l's in integer constant"); + } + lcount++; #if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE - if (lcount == 2) { + if (lcount == 2) { #endif - if (tok == TOK_CINT) - tok = TOK_CLLONG; - else if (tok == TOK_CUINT) - tok = TOK_CULLONG; + if (tok == TOK_CINT) { + tok = TOK_CLLONG; + } else if (tok == TOK_CUINT) { + tok = TOK_CULLONG; + } #if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE - } + } #endif - ch = *p++; - } else if (t == 'U') { - if (ucount >= 1) - tcc_error("two 'u's in integer constant"); - ucount++; - if (tok == TOK_CINT) - tok = TOK_CUINT; - else if (tok == TOK_CLLONG) - tok = TOK_CULLONG; - ch = *p++; - } else { - break; - } - } - if (tok == TOK_CINT || tok == TOK_CUINT) - tokc.ui = n; - else - tokc.ull = n; - } - if (ch) - tcc_error("invalid number\n"); + ch = *p++; + } else if (t == 'U') { + if (ucount >= 1) { + tcc_error ("two 'u's in integer constant"); + } + ucount++; + if (tok == TOK_CINT) { + tok = TOK_CUINT; + } else if (tok == TOK_CLLONG) { + tok = TOK_CULLONG; + } + ch = *p++; + } else { + break; + } + } + if (tok == TOK_CINT || tok == TOK_CUINT) { + tokc.ui = n; + } else { + tokc.ull = n; + } + } + if (ch) { + tcc_error ("invalid number\n"); + } } -#define PARSE2(c1, tok1, c2, tok2) \ - case c1: \ - PEEKC(c, p); \ - if (c == c2) { \ - p++; \ - tok = tok2; \ - } else { \ - tok = tok1; \ - } \ - break; +#define PARSE2(c1, tok1, c2, tok2)\ +case c1: \ + PEEKC (c, p); \ + if (c == c2) { \ + p++; \ + tok = tok2; \ + } else { \ + tok = tok1; \ + } \ + break; /* return next token without macro substitution */ static inline void next_nomacro1(void) { - int t, c, is_long; - TokenSym *ts; - uint8_t *p, *p1; - unsigned int h; + int t, c, is_long; + TokenSym *ts; + uint8_t *p, *p1; + unsigned int h; - p = file->buf_ptr; - redo_no_start: - c = *p; - switch(c) { - case ' ': - case '\t': - tok = c; - p++; - goto keep_tok_flags; - case '\f': - case '\v': - case '\r': - p++; - goto redo_no_start; - case '\\': - /* first look if it is in fact an end of buffer */ - if (p >= file->buf_end) { - file->buf_ptr = p; - handle_eob(); - p = file->buf_ptr; - if (p >= file->buf_end) - goto parse_eof; - else - goto redo_no_start; - } else { - file->buf_ptr = p; - ch = *p; - handle_stray(); - p = file->buf_ptr; - goto redo_no_start; - } - parse_eof: - { - TCCState *s1 = tcc_state; - if ((parse_flags & PARSE_FLAG_LINEFEED) - && !(tok_flags & TOK_FLAG_EOF)) { - tok_flags |= TOK_FLAG_EOF; - tok = TOK_LINEFEED; - goto keep_tok_flags; - } else if (!(parse_flags & PARSE_FLAG_PREPROCESS)) { - tok = TOK_EOF; - } else if (s1->ifdef_stack_ptr != file->ifdef_stack_ptr) { - tcc_error("missing #endif"); - } else if (s1->include_stack_ptr == s1->include_stack) { - /* no include left : end of file. */ - tok = TOK_EOF; - } else { - tok_flags &= ~TOK_FLAG_EOF; - /* pop include file */ + p = file->buf_ptr; +redo_no_start: + c = *p; + switch (c) { + case ' ': + case '\t': + tok = c; + p++; + goto keep_tok_flags; + case '\f': + case '\v': + case '\r': + p++; + goto redo_no_start; + case '\\': + /* first look if it is in fact an end of buffer */ + if (p >= file->buf_end) { + file->buf_ptr = p; + handle_eob (); + p = file->buf_ptr; + if (p >= file->buf_end) { + goto parse_eof; + } else { + goto redo_no_start; + } + } else { + file->buf_ptr = p; + ch = *p; + handle_stray (); + p = file->buf_ptr; + goto redo_no_start; + } +parse_eof: + { + TCCState *s1 = tcc_state; + if ((parse_flags & PARSE_FLAG_LINEFEED) + && !(tok_flags & TOK_FLAG_EOF)) { + tok_flags |= TOK_FLAG_EOF; + tok = TOK_LINEFEED; + goto keep_tok_flags; + } else if (!(parse_flags & PARSE_FLAG_PREPROCESS)) { + tok = TOK_EOF; + } else if (s1->ifdef_stack_ptr != file->ifdef_stack_ptr) { + tcc_error ("missing #endif"); + } else if (s1->include_stack_ptr == s1->include_stack) { + /* no include left : end of file. */ + tok = TOK_EOF; + } else { + tok_flags &= ~TOK_FLAG_EOF; + /* pop include file */ - /* test if previous '#endif' was after a #ifdef at - start of file */ - if (tok_flags & TOK_FLAG_ENDIF) { + /* test if previous '#endif' was after a #ifdef at + start of file */ + if (tok_flags & TOK_FLAG_ENDIF) { #ifdef INC_DEBUG - printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL)); + printf ("#endif %s\n", get_tok_str (file->ifndef_macro_saved, NULL)); #endif - add_cached_include(s1, file->filename, file->ifndef_macro_saved); - tok_flags &= ~TOK_FLAG_ENDIF; - } + add_cached_include (s1, file->filename, file->ifndef_macro_saved); + tok_flags &= ~TOK_FLAG_ENDIF; + } - /* pop include stack */ - tcc_close(); - s1->include_stack_ptr--; - p = file->buf_ptr; - goto redo_no_start; - } - } - break; + /* pop include stack */ + tcc_close (); + s1->include_stack_ptr--; + p = file->buf_ptr; + goto redo_no_start; + } + } + break; - case '\n': - file->line_num++; - tok_flags |= TOK_FLAG_BOL; - p++; + case '\n': + file->line_num++; + tok_flags |= TOK_FLAG_BOL; + p++; maybe_newline: - if (0 == (parse_flags & PARSE_FLAG_LINEFEED)) - goto redo_no_start; - tok = TOK_LINEFEED; - goto keep_tok_flags; + if (0 == (parse_flags & PARSE_FLAG_LINEFEED)) { + goto redo_no_start; + } + tok = TOK_LINEFEED; + goto keep_tok_flags; - case '#': - /* XXX: simplify */ - PEEKC(c, p); - if ((tok_flags & TOK_FLAG_BOL) && - (parse_flags & PARSE_FLAG_PREPROCESS)) { - file->buf_ptr = p; - preprocess(tok_flags & TOK_FLAG_BOF); - p = file->buf_ptr; - goto maybe_newline; - } else { - if (c == '#') { - p++; - tok = TOK_TWOSHARPS; - } else { - if (parse_flags & PARSE_FLAG_ASM_COMMENTS) { - p = parse_line_comment(p - 1); - goto redo_no_start; - } else { - tok = '#'; - } - } - } - break; + case '#': + /* XXX: simplify */ + PEEKC (c, p); + if ((tok_flags & TOK_FLAG_BOL) && + (parse_flags & PARSE_FLAG_PREPROCESS)) { + file->buf_ptr = p; + preprocess (tok_flags & TOK_FLAG_BOF); + p = file->buf_ptr; + goto maybe_newline; + } else { + if (c == '#') { + p++; + tok = TOK_TWOSHARPS; + } else { + if (parse_flags & PARSE_FLAG_ASM_COMMENTS) { + p = parse_line_comment (p - 1); + goto redo_no_start; + } else { + tok = '#'; + } + } + } + break; - case 'a': case 'b': case 'c': case 'd': - case 'e': case 'f': case 'g': case 'h': - case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': - case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': - case 'E': case 'F': case 'G': case 'H': - case 'I': case 'J': case 'K': - case 'M': case 'N': case 'O': case 'P': - case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case '_': - parse_ident_fast: - p1 = p; - h = TOK_HASH_INIT; - h = TOK_HASH_FUNC(h, c); - p++; - for(;;) { - c = *p; - if (!isidnum_table[c-CH_EOF]) - break; - h = TOK_HASH_FUNC(h, c); - p++; - } - if (c != '\\') { - TokenSym **pts; - int len; + case 'a': case 'b': case 'c': case 'd': + case 'e': case 'f': case 'g': case 'h': + case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': + case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': + case 'E': case 'F': case 'G': case 'H': + case 'I': case 'J': case 'K': + case 'M': case 'N': case 'O': case 'P': + case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + case '_': +parse_ident_fast: + p1 = p; + h = TOK_HASH_INIT; + h = TOK_HASH_FUNC (h, c); + p++; + for (;;) { + c = *p; + if (!isidnum_table[c - CH_EOF]) { + break; + } + h = TOK_HASH_FUNC (h, c); + p++; + } + if (c != '\\') { + TokenSym **pts; + int len; - /* fast case : no stray found, so we have the full token - and we have already hashed it */ - len = p - p1; - h &= (TOK_HASH_SIZE - 1); - pts = &hash_ident[h]; - for(;;) { - ts = *pts; - if (!ts) - break; - if (ts->len == len && !memcmp(ts->str, p1, len)) - goto token_found; - pts = &(ts->hash_next); - } - ts = tok_alloc_new(pts, (const char*)p1, len); - token_found: ; - } else { - /* slower case */ - cstr_reset(&tokcstr); + /* fast case : no stray found, so we have the full token + and we have already hashed it */ + len = p - p1; + h &= (TOK_HASH_SIZE - 1); + pts = &hash_ident[h]; + for (;;) { + ts = *pts; + if (!ts) { + break; + } + if (ts->len == len && !memcmp (ts->str, p1, len)) { + goto token_found; + } + pts = &(ts->hash_next); + } + ts = tok_alloc_new (pts, (const char *) p1, len); +token_found: + ; + } else { + /* slower case */ + cstr_reset (&tokcstr); - while (p1 < p) { - cstr_ccat(&tokcstr, *p1); - p1++; - } - p--; - PEEKC(c, p); - parse_ident_slow: - while (isidnum_table[((c>255)?255:c)-CH_EOF]) { - cstr_ccat(&tokcstr, c); - PEEKC(c, p); - } - ts = tok_alloc(tokcstr.data, tokcstr.size); - } - tok = ts->tok; - break; - case 'L': - t = p[1]; - if (t != '\\' && t != '\'' && t != '\"') { - /* fast case */ - goto parse_ident_fast; - } else { - PEEKC(c, p); - if (c == '\'' || c == '\"') { - is_long = 1; - goto str_const; - } else { - cstr_reset(&tokcstr); - cstr_ccat(&tokcstr, 'L'); - goto parse_ident_slow; - } - } - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - case '8': case '9': + while (p1 < p) { + cstr_ccat (&tokcstr, *p1); + p1++; + } + p--; + PEEKC (c, p); +parse_ident_slow: + while (isidnum_table[((c > 255)? 255: c) - CH_EOF]) { + cstr_ccat (&tokcstr, c); + PEEKC (c, p); + } + ts = tok_alloc (tokcstr.data, tokcstr.size); + } + tok = ts->tok; + break; + case 'L': + t = p[1]; + if (t != '\\' && t != '\'' && t != '\"') { + /* fast case */ + goto parse_ident_fast; + } else { + PEEKC (c, p); + if (c == '\'' || c == '\"') { + is_long = 1; + goto str_const; + } else { + cstr_reset (&tokcstr); + cstr_ccat (&tokcstr, 'L'); + goto parse_ident_slow; + } + } + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': - cstr_reset(&tokcstr); - /* after the first digit, accept digits, alpha, '.' or sign if - prefixed by 'eEpP' */ - parse_num: - for(;;) { - t = c; - cstr_ccat(&tokcstr, c); - PEEKC(c, p); - if (!(isnum(c) || isid(c) || c == '.' || - ((c == '+' || c == '-') && - (t == 'e' || t == 'E' || t == 'p' || t == 'P')))) - break; - } - /* We add a trailing '\0' to ease parsing */ - cstr_ccat(&tokcstr, '\0'); - tokc.cstr = &tokcstr; - tok = TOK_PPNUM; - break; - case '.': - /* special dot handling because it can also start a number */ - PEEKC(c, p); - if (isnum(c)) { - cstr_reset(&tokcstr); - cstr_ccat(&tokcstr, '.'); - goto parse_num; - } else if (c == '.') { - PEEKC(c, p); - if (c != '.') - expect("'.'"); - PEEKC(c, p); - tok = TOK_DOTS; - } else { - tok = '.'; - } - break; - case '\'': - case '\"': - is_long = 0; - str_const: - { - CString str; - int sep; + cstr_reset (&tokcstr); + /* after the first digit, accept digits, alpha, '.' or sign if + prefixed by 'eEpP' */ +parse_num: + for (;;) { + t = c; + cstr_ccat (&tokcstr, c); + PEEKC (c, p); + if (!(isnum (c) || isid (c) || c == '.' || + ((c == '+' || c == '-') && + (t == 'e' || t == 'E' || t == 'p' || t == 'P')))) { + break; + } + } + /* We add a trailing '\0' to ease parsing */ + cstr_ccat (&tokcstr, '\0'); + tokc.cstr = &tokcstr; + tok = TOK_PPNUM; + break; + case '.': + /* special dot handling because it can also start a number */ + PEEKC (c, p); + if (isnum (c)) { + cstr_reset (&tokcstr); + cstr_ccat (&tokcstr, '.'); + goto parse_num; + } else if (c == '.') { + PEEKC (c, p); + if (c != '.') { + expect ("'.'"); + } + PEEKC (c, p); + tok = TOK_DOTS; + } else { + tok = '.'; + } + break; + case '\'': + case '\"': + is_long = 0; +str_const: + { + CString str; + int sep; - sep = c; + sep = c; - /* parse the string */ - cstr_new(&str); - p = parse_pp_string(p, sep, &str); - cstr_ccat(&str, '\0'); + /* parse the string */ + cstr_new (&str); + p = parse_pp_string (p, sep, &str); + cstr_ccat (&str, '\0'); - /* eval the escape (should be done as TOK_PPNUM) */ - cstr_reset(&tokcstr); - parse_escape_string(&tokcstr, str.data, is_long); - cstr_free(&str); + /* eval the escape (should be done as TOK_PPNUM) */ + cstr_reset (&tokcstr); + parse_escape_string (&tokcstr, str.data, is_long); + cstr_free (&str); - if (sep == '\'') { - int char_size; - /* XXX: make it portable */ - if (!is_long) - char_size = 1; - else - char_size = sizeof(nwchar_t); - if (tokcstr.size <= char_size) - tcc_error("empty character constant"); - if (tokcstr.size > 2 * char_size) - tcc_warning("multi-character character constant"); - if (!is_long) { - tokc.i = *(int8_t *)tokcstr.data; - tok = TOK_CCHAR; - } else { - tokc.i = *(nwchar_t *)tokcstr.data; - tok = TOK_LCHAR; - } - } else { - tokc.cstr = &tokcstr; - if (!is_long) - tok = TOK_STR; - else - tok = TOK_LSTR; - } - } - break; + if (sep == '\'') { + int char_size; + /* XXX: make it portable */ + if (!is_long) { + char_size = 1; + } else { + char_size = sizeof(nwchar_t); + } + if (tokcstr.size <= char_size) { + tcc_error ("empty character constant"); + } + if (tokcstr.size > 2 * char_size) { + tcc_warning ("multi-character character constant"); + } + if (!is_long) { + tokc.i = *(int8_t *) tokcstr.data; + tok = TOK_CCHAR; + } else { + tokc.i = *(nwchar_t *) tokcstr.data; + tok = TOK_LCHAR; + } + } else { + tokc.cstr = &tokcstr; + if (!is_long) { + tok = TOK_STR; + } else { + tok = TOK_LSTR; + } + } + } + break; - case '<': - PEEKC(c, p); - if (c == '=') { - p++; - tok = TOK_LE; - } else if (c == '<') { - PEEKC(c, p); - if (c == '=') { - p++; - tok = TOK_A_SHL; - } else { - tok = TOK_SHL; - } - } else { - tok = TOK_LT; - } - break; + case '<': + PEEKC (c, p); + if (c == '=') { + p++; + tok = TOK_LE; + } else if (c == '<') { + PEEKC (c, p); + if (c == '=') { + p++; + tok = TOK_A_SHL; + } else { + tok = TOK_SHL; + } + } else { + tok = TOK_LT; + } + break; - case '>': - PEEKC(c, p); - if (c == '=') { - p++; - tok = TOK_GE; - } else if (c == '>') { - PEEKC(c, p); - if (c == '=') { - p++; - tok = TOK_A_SAR; - } else { - tok = TOK_SAR; - } - } else { - tok = TOK_GT; - } - break; + case '>': + PEEKC (c, p); + if (c == '=') { + p++; + tok = TOK_GE; + } else if (c == '>') { + PEEKC (c, p); + if (c == '=') { + p++; + tok = TOK_A_SAR; + } else { + tok = TOK_SAR; + } + } else { + tok = TOK_GT; + } + break; - case '&': - PEEKC(c, p); - if (c == '&') { - p++; - tok = TOK_LAND; - } else if (c == '=') { - p++; - tok = TOK_A_AND; - } else { - tok = '&'; - } - break; + case '&': + PEEKC (c, p); + if (c == '&') { + p++; + tok = TOK_LAND; + } else if (c == '=') { + p++; + tok = TOK_A_AND; + } else { + tok = '&'; + } + break; - case '|': - PEEKC(c, p); - if (c == '|') { - p++; - tok = TOK_LOR; - } else if (c == '=') { - p++; - tok = TOK_A_OR; - } else { - tok = '|'; - } - break; + case '|': + PEEKC (c, p); + if (c == '|') { + p++; + tok = TOK_LOR; + } else if (c == '=') { + p++; + tok = TOK_A_OR; + } else { + tok = '|'; + } + break; - case '+': - PEEKC(c, p); - if (c == '+') { - p++; - tok = TOK_INC; - } else if (c == '=') { - p++; - tok = TOK_A_ADD; - } else { - tok = '+'; - } - break; + case '+': + PEEKC (c, p); + if (c == '+') { + p++; + tok = TOK_INC; + } else if (c == '=') { + p++; + tok = TOK_A_ADD; + } else { + tok = '+'; + } + break; - case '-': - PEEKC(c, p); - if (c == '-') { - p++; - tok = TOK_DEC; - } else if (c == '=') { - p++; - tok = TOK_A_SUB; - } else if (c == '>') { - p++; - tok = TOK_ARROW; - } else { - tok = '-'; - } - break; + case '-': + PEEKC (c, p); + if (c == '-') { + p++; + tok = TOK_DEC; + } else if (c == '=') { + p++; + tok = TOK_A_SUB; + } else if (c == '>') { + p++; + tok = TOK_ARROW; + } else { + tok = '-'; + } + break; - PARSE2('!', '!', '=', TOK_NE) - PARSE2('=', '=', '=', TOK_EQ) - PARSE2('*', '*', '=', TOK_A_MUL) - PARSE2('%', '%', '=', TOK_A_MOD) - PARSE2('^', '^', '=', TOK_A_XOR) + PARSE2 ('!', '!', '=', TOK_NE) + PARSE2 ('=', '=', '=', TOK_EQ) + PARSE2 ('*', '*', '=', TOK_A_MUL) + PARSE2 ('%', '%', '=', TOK_A_MOD) + PARSE2 ('^', '^', '=', TOK_A_XOR) - /* comments or operator */ - case '/': - PEEKC(c, p); - if (c == '*') { - p = parse_comment(p); - /* comments replaced by a blank */ - tok = ' '; - goto keep_tok_flags; - } else if (c == '/') { - p = parse_line_comment(p); - tok = ' '; - goto keep_tok_flags; - } else if (c == '=') { - p++; - tok = TOK_A_DIV; - } else { - tok = '/'; - } - break; + /* comments or operator */ + case '/': + PEEKC (c, p); + if (c == '*') { + p = parse_comment (p); + /* comments replaced by a blank */ + tok = ' '; + goto keep_tok_flags; + } else if (c == '/') { + p = parse_line_comment (p); + tok = ' '; + goto keep_tok_flags; + } else if (c == '=') { + p++; + tok = TOK_A_DIV; + } else { + tok = '/'; + } + break; - /* simple tokens */ - case '(': - case ')': - case '[': - case ']': - case '{': - case '}': - case ',': - case ';': - case ':': - case '?': - case '~': - case '$': /* only used in assembler */ - case '@': /* dito */ - tok = c; - p++; - break; - default: - tcc_error("unrecognized character \\x%02x", c); - break; - } - tok_flags = 0; + /* simple tokens */ + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case ',': + case ';': + case ':': + case '?': + case '~': + case '$': /* only used in assembler */ + case '@': /* dito */ + tok = c; + p++; + break; + default: + tcc_error ("unrecognized character \\x%02x", c); + break; + } + tok_flags = 0; keep_tok_flags: - file->buf_ptr = p; + file->buf_ptr = p; #if defined(PARSE_DEBUG) - printf("token = %s\n", get_tok_str(tok, &tokc)); + printf ("token = %s\n", get_tok_str (tok, &tokc)); #endif } @@ -2520,124 +2644,128 @@ keep_tok_flags: macro_ptr buffer */ static void next_nomacro_spc(void) { - if (macro_ptr) { - redo: - tok = *macro_ptr; - if (tok) { - TOK_GET(&tok, ¯o_ptr, &tokc); - if (tok == TOK_LINENUM) { - file->line_num = tokc.i; - goto redo; - } - } - } else { - next_nomacro1(); - } + if (macro_ptr) { +redo: + tok = *macro_ptr; + if (tok) { + TOK_GET (&tok, ¯o_ptr, &tokc); + if (tok == TOK_LINENUM) { + file->line_num = tokc.i; + goto redo; + } + } + } else { + next_nomacro1 (); + } } ST_FUNC void next_nomacro(void) { - do { - next_nomacro_spc(); - } while (is_space(tok)); + do { + next_nomacro_spc (); + } while (is_space (tok)); } /* substitute args in macro_str and return allocated string */ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) { - int last_tok, t, spc; - const int *st; - Sym *s; - CValue cval; - TokenString str; - CString cstr; + int last_tok, t, spc; + const int *st; + Sym *s; + CValue cval; + TokenString str; + CString cstr; - tok_str_new(&str); - last_tok = 0; - while(1) { - TOK_GET(&t, ¯o_str, &cval); - if (!t) - break; - if (t == '#') { - /* stringize */ - TOK_GET(&t, ¯o_str, &cval); - if (!t) - break; - s = sym_find2(args, t); - if (s) { - cstr_new(&cstr); - st = s->d; - spc = 0; - while (*st) { - TOK_GET(&t, &st, &cval); - if (!check_space(t, &spc)) - cstr_cat(&cstr, get_tok_str(t, &cval)); - } - cstr.size -= spc; - cstr_ccat(&cstr, '\0'); + tok_str_new (&str); + last_tok = 0; + while (1) { + TOK_GET (&t, ¯o_str, &cval); + if (!t) { + break; + } + if (t == '#') { + /* stringize */ + TOK_GET (&t, ¯o_str, &cval); + if (!t) { + break; + } + s = sym_find2 (args, t); + if (s) { + cstr_new (&cstr); + st = s->d; + spc = 0; + while (*st) { + TOK_GET (&t, &st, &cval); + if (!check_space (t, &spc)) { + cstr_cat (&cstr, get_tok_str (t, &cval)); + } + } + cstr.size -= spc; + cstr_ccat (&cstr, '\0'); #ifdef PP_DEBUG - printf("stringize: %s\n", (char *)cstr.data); + printf ("stringize: %s\n", (char *) cstr.data); #endif - /* add string */ - cval.cstr = &cstr; - tok_str_add2(&str, TOK_STR, &cval); - cstr_free(&cstr); - } else { - tok_str_add2(&str, t, &cval); - } - } else if (t >= TOK_IDENT) { - s = sym_find2(args, t); - if (s) { - st = s->d; - /* if '##' is present before or after, no arg substitution */ - if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) { - /* special case for var arg macros : ## eats the - ',' if empty VA_ARGS variable. */ - /* XXX: test of the ',' is not 100% - reliable. should fix it to avoid security - problems */ - if (gnu_ext && s->type.t && - last_tok == TOK_TWOSHARPS && - str.len >= 2 && str.str[str.len - 2] == ',') { - if (*st == 0) { - /* suppress ',' '##' */ - str.len -= 2; - } else { - /* suppress '##' and add variable */ - str.len--; - goto add_var; - } - } else { - int t1; - add_var: - for(;;) { - TOK_GET(&t1, &st, &cval); - if (!t1) - break; - tok_str_add2(&str, t1, &cval); - } - } - } else { - /* NOTE: the stream cannot be read when macro - substituing an argument */ - macro_subst(&str, nested_list, st, NULL); - } - } else { - tok_str_add(&str, t); - } - } else { - tok_str_add2(&str, t, &cval); - } - last_tok = t; - } - tok_str_add(&str, 0); - return str.str; + /* add string */ + cval.cstr = &cstr; + tok_str_add2 (&str, TOK_STR, &cval); + cstr_free (&cstr); + } else { + tok_str_add2 (&str, t, &cval); + } + } else if (t >= TOK_IDENT) { + s = sym_find2 (args, t); + if (s) { + st = s->d; + /* if '##' is present before or after, no arg substitution */ + if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) { + /* special case for var arg macros : ## eats the + ',' if empty VA_ARGS variable. */ + /* XXX: test of the ',' is not 100% + reliable. should fix it to avoid security + problems */ + if (gnu_ext && s->type.t && + last_tok == TOK_TWOSHARPS && + str.len >= 2 && str.str[str.len - 2] == ',') { + if (*st == 0) { + /* suppress ',' '##' */ + str.len -= 2; + } else { + /* suppress '##' and add variable */ + str.len--; + goto add_var; + } + } else { + int t1; +add_var: + for (;;) { + TOK_GET (&t1, &st, &cval); + if (!t1) { + break; + } + tok_str_add2 (&str, t1, &cval); + } + } + } else { + /* NOTE: the stream cannot be read when macro + substituing an argument */ + macro_subst (&str, nested_list, st, NULL); + } + } else { + tok_str_add (&str, t); + } + } else { + tok_str_add2 (&str, t, &cval); + } + last_tok = t; + } + tok_str_add (&str, 0); + return str.str; } static char const ab_month_name[12][4] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /* do macro substitution of current token with macro 's' and add @@ -2645,248 +2773,263 @@ static char const ab_month_name[12][4] = macros we got inside to avoid recursing. Return non zero if no substitution needs to be done */ static int macro_subst_tok(TokenString *tok_str, - Sym **nested_list, Sym *s, struct macro_level **can_read_stream) + Sym **nested_list, Sym *s, struct macro_level **can_read_stream) { - Sym *args, *sa, *sa1; - int mstr_allocated, parlevel, *mstr, t, t1, spc; - const int *p; - TokenString str; - char *cstrval; - CValue cval; - CString cstr; - char buf[32]; + Sym *args, *sa, *sa1; + int mstr_allocated, parlevel, *mstr, t, t1, spc; + const int *p; + TokenString str; + char *cstrval; + CValue cval; + CString cstr; + char buf[32]; - /* if symbol is a macro, prepare substitution */ - /* special macros */ - if (tok == TOK___LINE__) { - snprintf(buf, sizeof(buf), "%d", file->line_num); - cstrval = buf; - t1 = TOK_PPNUM; - goto add_cstr1; - } else if (tok == TOK___FILE__) { - cstrval = file->filename; - goto add_cstr; - } else if (tok == TOK___DATE__ || tok == TOK___TIME__) { - time_t ti; - struct tm *tm; + /* if symbol is a macro, prepare substitution */ + /* special macros */ + if (tok == TOK___LINE__) { + snprintf (buf, sizeof(buf), "%d", file->line_num); + cstrval = buf; + t1 = TOK_PPNUM; + goto add_cstr1; + } else if (tok == TOK___FILE__) { + cstrval = file->filename; + goto add_cstr; + } else if (tok == TOK___DATE__ || tok == TOK___TIME__) { + time_t ti; + struct tm *tm; - time(&ti); - tm = localtime(&ti); - if (tok == TOK___DATE__) { - snprintf(buf, sizeof(buf), "%s %2d %d", - ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900); - } else { - snprintf(buf, sizeof(buf), "%02d:%02d:%02d", - tm->tm_hour, tm->tm_min, tm->tm_sec); - } - cstrval = buf; - add_cstr: - t1 = TOK_STR; - add_cstr1: - cstr_new(&cstr); - cstr_cat(&cstr, cstrval); - cstr_ccat(&cstr, '\0'); - cval.cstr = &cstr; - tok_str_add2(tok_str, t1, &cval); - cstr_free(&cstr); - } else { - mstr = s->d; - mstr_allocated = 0; - if (s->type.t == MACRO_FUNC) { - /* NOTE: we do not use next_nomacro to avoid eating the - next token. XXX: find better solution */ - redo: - if (macro_ptr) { - p = macro_ptr; - while (is_space(t = *p) || TOK_LINEFEED == t) - ++p; - if (t == 0 && can_read_stream) { - /* end of macro stream: we must look at the token - after in the file */ - struct macro_level *ml = *can_read_stream; - macro_ptr = NULL; - if (ml) - { - macro_ptr = ml->p; - ml->p = NULL; - *can_read_stream = ml -> prev; - } - /* also, end of scope for nested defined symbol */ - (*nested_list)->v = -1; - goto redo; - } - } else { - ch = file->buf_ptr[0]; - while (is_space(ch) || ch == '\n' || ch == '/') - { - if (ch == '/') - { - int c; - uint8_t *p = file->buf_ptr; - PEEKC(c, p); - if (c == '*') { - p = parse_comment(p); - file->buf_ptr = p - 1; - } else if (c == '/') { - p = parse_line_comment(p); - file->buf_ptr = p - 1; - } else - break; - } - cinp(); - } - t = ch; - } - if (t != '(') /* no macro subst */ - return -1; + time (&ti); + tm = localtime (&ti); + if (tok == TOK___DATE__) { + snprintf (buf, sizeof(buf), "%s %2d %d", + ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900); + } else { + snprintf (buf, sizeof(buf), "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + } + cstrval = buf; +add_cstr: + t1 = TOK_STR; +add_cstr1: + cstr_new (&cstr); + cstr_cat (&cstr, cstrval); + cstr_ccat (&cstr, '\0'); + cval.cstr = &cstr; + tok_str_add2 (tok_str, t1, &cval); + cstr_free (&cstr); + } else { + mstr = s->d; + mstr_allocated = 0; + if (s->type.t == MACRO_FUNC) { + /* NOTE: we do not use next_nomacro to avoid eating the + next token. XXX: find better solution */ +redo: + if (macro_ptr) { + p = macro_ptr; + while (is_space (t = *p) || TOK_LINEFEED == t) + ++p; + if (t == 0 && can_read_stream) { + /* end of macro stream: we must look at the token + after in the file */ + struct macro_level *ml = *can_read_stream; + macro_ptr = NULL; + if (ml) { + macro_ptr = ml->p; + ml->p = NULL; + *can_read_stream = ml->prev; + } + /* also, end of scope for nested defined symbol */ + (*nested_list)->v = -1; + goto redo; + } + } else { + ch = file->buf_ptr[0]; + while (is_space (ch) || ch == '\n' || ch == '/') { + if (ch == '/') { + int c; + uint8_t *p = file->buf_ptr; + PEEKC (c, p); + if (c == '*') { + p = parse_comment (p); + file->buf_ptr = p - 1; + } else if (c == '/') { + p = parse_line_comment (p); + file->buf_ptr = p - 1; + } else { + break; + } + } + cinp (); + } + t = ch; + } + if (t != '(') { /* no macro subst */ + return -1; + } - /* argument macro */ - next_nomacro(); - next_nomacro(); - args = NULL; - sa = s->next; - /* NOTE: empty args are allowed, except if no args */ - for(;;) { - /* handle '()' case */ - if (!args && !sa && tok == ')') - break; - if (!sa) - tcc_error("macro '%s' used with too many args", - get_tok_str(s->v, 0)); - tok_str_new(&str); - parlevel = spc = 0; - /* NOTE: non zero sa->t indicates VA_ARGS */ - while ((parlevel > 0 || - (tok != ')' && - (tok != ',' || sa->type.t))) && - tok != -1) { - if (tok == '(') - parlevel++; - else if (tok == ')') - parlevel--; - if (tok == TOK_LINEFEED) - tok = ' '; - if (!check_space(tok, &spc)) - tok_str_add2(&str, tok, &tokc); - next_nomacro_spc(); - } - str.len -= spc; - tok_str_add(&str, 0); - sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0); - sa1->d = str.str; - sa = sa->next; - if (tok == ')') { - /* special case for gcc var args: add an empty - var arg argument if it is omitted */ - if (sa && sa->type.t && gnu_ext) - continue; - else - break; - } - if (tok != ',') - expect(","); - next_nomacro(); - } - if (sa) { - tcc_error("macro '%s' used with too few args", - get_tok_str(s->v, 0)); - } + /* argument macro */ + next_nomacro (); + next_nomacro (); + args = NULL; + sa = s->next; + /* NOTE: empty args are allowed, except if no args */ + for (;;) { + /* handle '()' case */ + if (!args && !sa && tok == ')') { + break; + } + if (!sa) { + tcc_error ("macro '%s' used with too many args", + get_tok_str (s->v, 0)); + } + tok_str_new (&str); + parlevel = spc = 0; + /* NOTE: non zero sa->t indicates VA_ARGS */ + while ((parlevel > 0 || + (tok != ')' && + (tok != ',' || sa->type.t))) && + tok != -1) { + if (tok == '(') { + parlevel++; + } else if (tok == ')') { + parlevel--; + } + if (tok == TOK_LINEFEED) { + tok = ' '; + } + if (!check_space (tok, &spc)) { + tok_str_add2 (&str, tok, &tokc); + } + next_nomacro_spc (); + } + str.len -= spc; + tok_str_add (&str, 0); + sa1 = sym_push2 (&args, sa->v & ~SYM_FIELD, sa->type.t, 0); + sa1->d = str.str; + sa = sa->next; + if (tok == ')') { + /* special case for gcc var args: add an empty + var arg argument if it is omitted */ + if (sa && sa->type.t && gnu_ext) { + continue; + } else { + break; + } + } + if (tok != ',') { + expect (","); + } + next_nomacro (); + } + if (sa) { + tcc_error ("macro '%s' used with too few args", + get_tok_str (s->v, 0)); + } - /* now subst each arg */ - mstr = macro_arg_subst(nested_list, mstr, args); - /* free memory */ - sa = args; - while (sa) { - sa1 = sa->prev; - tok_str_free(sa->d); - sym_free(sa); - sa = sa1; - } - mstr_allocated = 1; - } - sym_push2(nested_list, s->v, 0, 0); - macro_subst(tok_str, nested_list, mstr, can_read_stream); - /* pop nested defined symbol */ - sa1 = *nested_list; - *nested_list = sa1->prev; - sym_free(sa1); - if (mstr_allocated) - tok_str_free(mstr); - } - return 0; + /* now subst each arg */ + mstr = macro_arg_subst (nested_list, mstr, args); + /* free memory */ + sa = args; + while (sa) { + sa1 = sa->prev; + tok_str_free (sa->d); + sym_free (sa); + sa = sa1; + } + mstr_allocated = 1; + } + sym_push2 (nested_list, s->v, 0, 0); + macro_subst (tok_str, nested_list, mstr, can_read_stream); + /* pop nested defined symbol */ + sa1 = *nested_list; + *nested_list = sa1->prev; + sym_free (sa1); + if (mstr_allocated) { + tok_str_free (mstr); + } + } + return 0; } /* handle the '##' operator. Return NULL if no '##' seen. Otherwise return the resulting string (which must be freed). */ static inline int *macro_twosharps(const int *macro_str) { - const int *ptr; - int t; - TokenString macro_str1; - CString cstr; - int n, start_of_nosubsts; + const int *ptr; + int t; + TokenString macro_str1; + CString cstr; + int n, start_of_nosubsts; - /* we search the first '##' */ - for(ptr = macro_str;;) { - CValue cval; - TOK_GET(&t, &ptr, &cval); - if (t == TOK_TWOSHARPS) - break; - /* nothing more to do if end of string */ - if (t == 0) - return NULL; - } + /* we search the first '##' */ + for (ptr = macro_str;;) { + CValue cval; + TOK_GET (&t, &ptr, &cval); + if (t == TOK_TWOSHARPS) { + break; + } + /* nothing more to do if end of string */ + if (t == 0) { + return NULL; + } + } - /* we saw '##', so we need more processing to handle it */ - start_of_nosubsts = -1; - tok_str_new(¯o_str1); - for(ptr = macro_str;;) { - TOK_GET(&tok, &ptr, &tokc); - if (tok == 0) - break; - if (tok == TOK_TWOSHARPS) - continue; - if (tok == TOK_NOSUBST && start_of_nosubsts < 0) - start_of_nosubsts = macro_str1.len; - while (*ptr == TOK_TWOSHARPS) { - /* given 'a##b', remove nosubsts preceding 'a' */ - if (start_of_nosubsts >= 0) - macro_str1.len = start_of_nosubsts; - /* given 'a##b', skip '##' */ - t = *++ptr; - /* given 'a##b', remove nosubsts preceding 'b' */ - while (t == TOK_NOSUBST) - t = *++ptr; - if (t && t != TOK_TWOSHARPS) { - CValue cval; - TOK_GET(&t, &ptr, &cval); - /* We concatenate the two tokens */ - cstr_new(&cstr); - cstr_cat(&cstr, get_tok_str(tok, &tokc)); - n = cstr.size; - cstr_cat(&cstr, get_tok_str(t, &cval)); - cstr_ccat(&cstr, '\0'); + /* we saw '##', so we need more processing to handle it */ + start_of_nosubsts = -1; + tok_str_new (¯o_str1); + for (ptr = macro_str;;) { + TOK_GET (&tok, &ptr, &tokc); + if (tok == 0) { + break; + } + if (tok == TOK_TWOSHARPS) { + continue; + } + if (tok == TOK_NOSUBST && start_of_nosubsts < 0) { + start_of_nosubsts = macro_str1.len; + } + while (*ptr == TOK_TWOSHARPS) { + /* given 'a##b', remove nosubsts preceding 'a' */ + if (start_of_nosubsts >= 0) { + macro_str1.len = start_of_nosubsts; + } + /* given 'a##b', skip '##' */ + t = *++ptr; + /* given 'a##b', remove nosubsts preceding 'b' */ + while (t == TOK_NOSUBST) + t = *++ptr; + if (t && t != TOK_TWOSHARPS) { + CValue cval; + TOK_GET (&t, &ptr, &cval); + /* We concatenate the two tokens */ + cstr_new (&cstr); + cstr_cat (&cstr, get_tok_str (tok, &tokc)); + n = cstr.size; + cstr_cat (&cstr, get_tok_str (t, &cval)); + cstr_ccat (&cstr, '\0'); - tcc_open_bf(tcc_state, ":paste:", cstr.size); - memcpy(file->buffer, cstr.data, cstr.size); - for (;;) { - next_nomacro1(); - if (0 == *file->buf_ptr) - break; - tok_str_add2(¯o_str1, tok, &tokc); - tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid preprocessing token", - n, cstr.data, (char*)cstr.data + n); - } - tcc_close(); - cstr_free(&cstr); - } - } - if (tok != TOK_NOSUBST) - start_of_nosubsts = -1; - tok_str_add2(¯o_str1, tok, &tokc); - } - tok_str_add(¯o_str1, 0); - return macro_str1.str; + tcc_open_bf (tcc_state, ":paste:", cstr.size); + memcpy (file->buffer, cstr.data, cstr.size); + for (;;) { + next_nomacro1 (); + if (0 == *file->buf_ptr) { + break; + } + tok_str_add2 (¯o_str1, tok, &tokc); + tcc_warning ("pasting \"%.*s\" and \"%s\" does not give a valid preprocessing token", + n, cstr.data, (char *) cstr.data + n); + } + tcc_close (); + cstr_free (&cstr); + } + } + if (tok != TOK_NOSUBST) { + start_of_nosubsts = -1; + } + tok_str_add2 (¯o_str1, tok, &tokc); + } + tok_str_add (¯o_str1, 0); + return macro_str1.str; } @@ -2894,158 +3037,166 @@ static inline int *macro_twosharps(const int *macro_str) (tok_str,tok_len). 'nested_list' is the list of all macros we got inside to avoid recursing. */ static void macro_subst(TokenString *tok_str, Sym **nested_list, - const int *macro_str, struct macro_level ** can_read_stream) + const int *macro_str, struct macro_level **can_read_stream) { - Sym *s; - int *macro_str1; - const int *ptr; - int t, ret, spc; - CValue cval; - struct macro_level ml; - int force_blank; + Sym *s; + int *macro_str1; + const int *ptr; + int t, ret, spc; + CValue cval; + struct macro_level ml; + int force_blank; - /* first scan for '##' operator handling */ - ptr = macro_str; - macro_str1 = macro_twosharps(ptr); + /* first scan for '##' operator handling */ + ptr = macro_str; + macro_str1 = macro_twosharps (ptr); - if (macro_str1) - ptr = macro_str1; - spc = 0; - force_blank = 0; + if (macro_str1) { + ptr = macro_str1; + } + spc = 0; + force_blank = 0; - while (1) { - /* NOTE: ptr == NULL can only happen if tokens are read from - file stream due to a macro function call */ - if (ptr == NULL) - break; - TOK_GET(&t, &ptr, &cval); - if (t == 0) - break; - if (t == TOK_NOSUBST) { - /* following token has already been subst'd. just copy it on */ - tok_str_add2(tok_str, TOK_NOSUBST, NULL); - TOK_GET(&t, &ptr, &cval); - goto no_subst; - } - s = define_find(t); - if (s != NULL) { - /* if nested substitution, do nothing */ - if (sym_find2(*nested_list, t)) { - /* and mark it as TOK_NOSUBST, so it doesn't get subst'd again */ - tok_str_add2(tok_str, TOK_NOSUBST, NULL); - goto no_subst; - } - ml.p = macro_ptr; - if (can_read_stream) - ml.prev = *can_read_stream, *can_read_stream = &ml; - macro_ptr = (int *)ptr; - tok = t; - ret = macro_subst_tok(tok_str, nested_list, s, can_read_stream); - ptr = (int *)macro_ptr; - macro_ptr = ml.p; - if (can_read_stream && *can_read_stream == &ml) - *can_read_stream = ml.prev; - if (ret != 0) - goto no_subst; - if (parse_flags & PARSE_FLAG_SPACES) - force_blank = 1; - } else { - no_subst: - if (force_blank) { - tok_str_add(tok_str, ' '); - spc = 1; - force_blank = 0; - } - if (!check_space(t, &spc)) - tok_str_add2(tok_str, t, &cval); - } - } - if (macro_str1) - tok_str_free(macro_str1); + while (1) { + /* NOTE: ptr == NULL can only happen if tokens are read from + file stream due to a macro function call */ + if (ptr == NULL) { + break; + } + TOK_GET (&t, &ptr, &cval); + if (t == 0) { + break; + } + if (t == TOK_NOSUBST) { + /* following token has already been subst'd. just copy it on */ + tok_str_add2 (tok_str, TOK_NOSUBST, NULL); + TOK_GET (&t, &ptr, &cval); + goto no_subst; + } + s = define_find (t); + if (s != NULL) { + /* if nested substitution, do nothing */ + if (sym_find2 (*nested_list, t)) { + /* and mark it as TOK_NOSUBST, so it doesn't get subst'd again */ + tok_str_add2 (tok_str, TOK_NOSUBST, NULL); + goto no_subst; + } + ml.p = macro_ptr; + if (can_read_stream) { + ml.prev = *can_read_stream, *can_read_stream = &ml; + } + macro_ptr = (int *) ptr; + tok = t; + ret = macro_subst_tok (tok_str, nested_list, s, can_read_stream); + ptr = (int *) macro_ptr; + macro_ptr = ml.p; + if (can_read_stream && *can_read_stream == &ml) { + *can_read_stream = ml.prev; + } + if (ret != 0) { + goto no_subst; + } + if (parse_flags & PARSE_FLAG_SPACES) { + force_blank = 1; + } + } else { +no_subst: + if (force_blank) { + tok_str_add (tok_str, ' '); + spc = 1; + force_blank = 0; + } + if (!check_space (t, &spc)) { + tok_str_add2 (tok_str, t, &cval); + } + } + } + if (macro_str1) { + tok_str_free (macro_str1); + } } /* return next token with macro substitution */ ST_FUNC void next(void) { - Sym *nested_list, *s; - TokenString str; - struct macro_level *ml; + Sym *nested_list, *s; + TokenString str; + struct macro_level *ml; - redo: - if (parse_flags & PARSE_FLAG_SPACES) - next_nomacro_spc(); - else - next_nomacro(); - if (!macro_ptr) { - /* if not reading from macro substituted string, then try - to substitute macros */ - if (tok >= TOK_IDENT && - (parse_flags & PARSE_FLAG_PREPROCESS)) { - s = define_find(tok); - if (s) { - /* we have a macro: we try to substitute */ - tok_str_new(&str); - nested_list = NULL; - ml = NULL; - if (macro_subst_tok(&str, &nested_list, s, &ml) == 0) { - /* substitution done, NOTE: maybe empty */ - tok_str_add(&str, 0); - macro_ptr = str.str; - macro_ptr_allocated = str.str; - goto redo; - } - } - } - } else { - if (tok == 0) { - /* end of macro or end of unget buffer */ - if (unget_buffer_enabled) { - macro_ptr = unget_saved_macro_ptr; - unget_buffer_enabled = 0; - } else { - /* end of macro string: free it */ - tok_str_free(macro_ptr_allocated); - macro_ptr_allocated = NULL; - macro_ptr = NULL; - } - goto redo; - } else if (tok == TOK_NOSUBST) { - /* discard preprocessor's nosubst markers */ - goto redo; - } - } +redo: + if (parse_flags & PARSE_FLAG_SPACES) { + next_nomacro_spc (); + } else { + next_nomacro (); + } + if (!macro_ptr) { + /* if not reading from macro substituted string, then try + to substitute macros */ + if (tok >= TOK_IDENT && + (parse_flags & PARSE_FLAG_PREPROCESS)) { + s = define_find (tok); + if (s) { + /* we have a macro: we try to substitute */ + tok_str_new (&str); + nested_list = NULL; + ml = NULL; + if (macro_subst_tok (&str, &nested_list, s, &ml) == 0) { + /* substitution done, NOTE: maybe empty */ + tok_str_add (&str, 0); + macro_ptr = str.str; + macro_ptr_allocated = str.str; + goto redo; + } + } + } + } else { + if (tok == 0) { + /* end of macro or end of unget buffer */ + if (unget_buffer_enabled) { + macro_ptr = unget_saved_macro_ptr; + unget_buffer_enabled = 0; + } else { + /* end of macro string: free it */ + tok_str_free (macro_ptr_allocated); + macro_ptr_allocated = NULL; + macro_ptr = NULL; + } + goto redo; + } else if (tok == TOK_NOSUBST) { + /* discard preprocessor's nosubst markers */ + goto redo; + } + } - /* convert preprocessor tokens into C tokens */ - if (tok == TOK_PPNUM && - (parse_flags & PARSE_FLAG_TOK_NUM)) { - parse_number((char *)tokc.cstr->data); - } + /* convert preprocessor tokens into C tokens */ + if (tok == TOK_PPNUM && + (parse_flags & PARSE_FLAG_TOK_NUM)) { + parse_number ((char *) tokc.cstr->data); + } } /* push back current token and set current token to 'last_tok'. Only identifier case handled for labels. */ ST_INLN void unget_tok(int last_tok) { - int i, n; - int *q; - if (unget_buffer_enabled) - { - /* assert(macro_ptr == unget_saved_buffer + 1); - assert(*macro_ptr == 0); */ - } - else - { - unget_saved_macro_ptr = macro_ptr; - unget_buffer_enabled = 1; - } - q = unget_saved_buffer; - macro_ptr = q; - *q++ = tok; - n = tok_ext_size(tok) - 1; - for(i=0;iinclude_stack_ptr = s1->include_stack; - /* XXX: move that before to avoid having to initialize - file->ifdef_stack_ptr ? */ - s1->ifdef_stack_ptr = s1->ifdef_stack; - file->ifdef_stack_ptr = s1->ifdef_stack_ptr; + s1->include_stack_ptr = s1->include_stack; + /* XXX: move that before to avoid having to initialize + file->ifdef_stack_ptr ? */ + s1->ifdef_stack_ptr = s1->ifdef_stack; + file->ifdef_stack_ptr = s1->ifdef_stack_ptr; - vtop = vstack - 1; - s1->pack_stack[0] = 0; - s1->pack_stack_ptr = s1->pack_stack; + vtop = vstack - 1; + s1->pack_stack[0] = 0; + s1->pack_stack_ptr = s1->pack_stack; } ST_FUNC void preprocess_new(void) { - int i, c; - const char *p, *r; + int i, c; + const char *p, *r; - /* init isid table */ - for(i=CH_EOF;i<256;i++) - isidnum_table[i-CH_EOF] = isid(i) || isnum(i); + /* init isid table */ + for (i = CH_EOF; i < 256; i++) { + isidnum_table[i - CH_EOF] = isid (i) || isnum (i); + } - /* add all tokens */ - table_ident = NULL; - memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *)); + /* add all tokens */ + table_ident = NULL; + memset (hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *)); - tok_ident = TOK_IDENT; - p = tcc_keywords; - while (*p) { - r = p; - for(;;) { - c = *r++; - if (c == '\0') - break; - } - tok_alloc(p, r - p - 1); - p = r; - } + tok_ident = TOK_IDENT; + p = tcc_keywords; + while (*p) { + r = p; + for (;;) { + c = *r++; + if (c == '\0') { + break; + } + } + tok_alloc (p, r - p - 1); + p = r; + } } /* Preprocess the current file */ ST_FUNC int tcc_preprocess(TCCState *s1) { - Sym *define_start; + Sym *define_start; - BufferedFile *file_ref, **iptr, **iptr_new; - int token_seen, line_ref, d; - const char *s; + BufferedFile *file_ref, **iptr, **iptr_new; + int token_seen, line_ref, d; + const char *s; - preprocess_init(s1); - define_start = define_stack; - ch = file->buf_ptr[0]; - tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; - parse_flags = PARSE_FLAG_ASM_COMMENTS | PARSE_FLAG_PREPROCESS | - PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES; - token_seen = 0; - line_ref = 0; - file_ref = NULL; - iptr = s1->include_stack_ptr; + preprocess_init (s1); + define_start = define_stack; + ch = file->buf_ptr[0]; + tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; + parse_flags = PARSE_FLAG_ASM_COMMENTS | PARSE_FLAG_PREPROCESS | + PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES; + token_seen = 0; + line_ref = 0; + file_ref = NULL; + iptr = s1->include_stack_ptr; - for (;;) { - next(); - if (tok == TOK_EOF) { - break; - } else if (file != file_ref) { - goto print_line; - } else if (tok == TOK_LINEFEED) { - if (!token_seen) - continue; - ++line_ref; - token_seen = 0; - } else if (!token_seen) { - d = file->line_num - line_ref; - if (file != file_ref || d < 0 || d >= 8) { + for (;;) { + next (); + if (tok == TOK_EOF) { + break; + } else if (file != file_ref) { + goto print_line; + } else if (tok == TOK_LINEFEED) { + if (!token_seen) { + continue; + } + ++line_ref; + token_seen = 0; + } else if (!token_seen) { + d = file->line_num - line_ref; + if (file != file_ref || d < 0 || d >= 8) { print_line: - iptr_new = s1->include_stack_ptr; - s = iptr_new > iptr ? " 1" - : iptr_new < iptr ? " 2" - : iptr_new > s1->include_stack ? " 3" - : "" - ; - iptr = iptr_new; - fprintf(s1->ppfp, "# %d \"%s\"%s\n", file->line_num, file->filename, s); - } else { - while (d) - fputs("\n", s1->ppfp), --d; - } - line_ref = (file_ref = file)->line_num; - token_seen = tok != TOK_LINEFEED; - if (!token_seen) - continue; - } - fputs(get_tok_str(tok, &tokc), s1->ppfp); - } - free_defines(define_start); - return 0; + iptr_new = s1->include_stack_ptr; + s = iptr_new > iptr? " 1" + : iptr_new < iptr? " 2" + : iptr_new > s1->include_stack? " 3" + : "" + ; + iptr = iptr_new; + fprintf (s1->ppfp, "# %d \"%s\"%s\n", file->line_num, file->filename, s); + } else { + while (d) + fputs ("\n", s1->ppfp), --d; + } + line_ref = (file_ref = file)->line_num; + token_seen = tok != TOK_LINEFEED; + if (!token_seen) { + continue; + } + } + fputs (get_tok_str (tok, &tokc), s1->ppfp); + } + free_defines (define_start); + return 0; } diff --git a/sys/indent-whitelist.sh b/sys/indent-whitelist.sh index 4b9a168fb8..f1b6fc19e9 100755 --- a/sys/indent-whitelist.sh +++ b/sys/indent-whitelist.sh @@ -66,6 +66,10 @@ libr/core/yank.c libr/core/blaze.c libr/core/cmd_egg.c +shlr/tcc/tccgen.c +shlr/tcc/libtcc.c +shlr/tcc/tccpp.c + binr/radare2/radare2.c binr/rabin2/rabin2.c binr/radiff2/radiff2.c