diff --git a/tcc.c b/tcc.c index 6e03422..5769af2 100644 --- a/tcc.c +++ b/tcc.c @@ -57,10 +57,14 @@ typedef struct Sym { #define FUNC_OLD 2 /* old function prototype */ #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */ -/* field t for macros */ +/* field 'Sym.t' for macros */ #define MACRO_OBJ 0 /* object like macro */ #define MACRO_FUNC 1 /* function like macro */ +/* type_decl() types */ +#define TYPE_ABSTRACT 1 /* type without variable */ +#define TYPE_DIRECT 2 /* type with variable */ + typedef struct { FILE *file; char *filename; @@ -244,7 +248,25 @@ int type_size(int t, int *a); int pointed_type(int t); int pointed_size(int t); int ist(void); -int typ(int *v, int t); +int type_decl(int *v, int t, int td); + +#ifdef PROFILE +/* dummy function for profiling */ +void *dlopen(const char *filename, int flag) +{ + return (void *)1; +} +const char *dlerror(void) +{ + return "error"; +} + +void *dlsym(void *handle, char *symbol) +{ + return (void *)1; +} + +#endif int isid(c) { @@ -262,38 +284,37 @@ void printline() { IncludeFile *f; for(f = include_stack; f < include_stack_ptr; f++) - printf("In file included from %s:%d:\n", f->filename, f->line_num); - printf("%s:%d: ", filename, line_num); + fprintf(stderr, "In file included from %s:%d:\n", + f->filename, f->line_num); + fprintf(stderr, "%s:%d: ", filename, line_num); } -/* XXX: use stderr ? */ -void error(char *msg) +void error(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); printline(); - printf("%s\n", msg); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); exit(1); + va_end(ap); } -void expect(char *msg) +void expect(const char *msg) { - printline(); - printf("%s expected\n", msg); - exit(1); + error("%s expected", msg); } -void warning(char *msg) +void warning(const char *msg) { printline(); - printf("warning: %s\n", msg); + fprintf(stderr, "warning: %s\n", msg); } void skip(c) { - if (tok != c) { - printline(); - printf("'%c' expected\n", c); - exit(1); - } + if (tok != c) + error("'%c' expected", c); next(); } @@ -563,33 +584,6 @@ void preprocess_skip() } } -/* parse until eol and add given char */ -char *get_str(c) -{ - char *str; - int size, n; - - str = NULL; - size = 0; - n = 0; - while (1) { - if ((n + 1) >= size) { - size += 128; - str = realloc(str, size); - if (!str) - error("memory full"); - } - if (ch == -1 || ch == '\n') { - str[n++] = c; - str[n++] = '\0'; - break; - } - str[n++] = ch; - cinp(); - } - return str; -} - void tok_add(int **tok_str, int *tok_len, int t) { int len, *str; @@ -616,7 +610,6 @@ void tok_add2(int **tok_str, int *tok_len, int t, int c) int expr_preprocess() { int *str, len, c, t; - int *saved_macro_ptr; str = NULL; len = 0; @@ -645,11 +638,10 @@ int expr_preprocess() tok_add(&str, &len, -1); /* simulate end of file */ tok_add(&str, &len, 0); /* now evaluate C constant expression */ - saved_macro_ptr = macro_ptr; macro_ptr = str; next(); c = expr_const(); - macro_ptr = saved_macro_ptr; + macro_ptr = NULL; free(str); return c != 0; } @@ -672,6 +664,20 @@ void tok_print(int *str) } #endif +/* XXX: should be more factorized */ +void define_symbol(char *sym) +{ + TokenSym *ts; + int *str, len; + + ts = tok_alloc(sym, strlen(sym)); + str = NULL; + len = 0; + tok_add2(&str, &len, TOK_NUM, 1); + tok_add(&str, &len, 0); + sym_push1(&define_stack, ts->tok, MACRO_OBJ, (int)str); +} + void preprocess() { int size, i, c, v, t, *str, len; @@ -687,8 +693,6 @@ void preprocess() next_nomacro(); v = tok; /* XXX: should check if same macro (ANSI) */ - if (sym_find1(define_stack, v)) - warning("macro redefinition"); first = NULL; t = MACRO_OBJ; /* '(' must be just after macro definition for MACRO_FUNC */ @@ -1874,18 +1878,20 @@ int struct_decl(u) if (s = sym_find(v | SYM_STRUCT)) { if (s->t != a) error("invalid type"); - u = u | (v << VT_STRUCT_SHIFT); - return u; + goto do_decl; } } else { v = anon_sym++; } s = sym_push(v | SYM_STRUCT, a, 0); /* put struct/union/enum name in type */ + do_decl: u = u | (v << VT_STRUCT_SHIFT); if (tok == '{') { next(); + if (s->c) + error("struct/union/enum already defined"); /* cannot be empty */ c = 0; maxalign = 0; @@ -1905,7 +1911,7 @@ int struct_decl(u) } else { b = ist(); while (1) { - t = typ(&v, b); + t = type_decl(&v, b, TYPE_DIRECT); if (t & (VT_FUNC | VT_TYPEDEF)) error("invalid type"); /* XXX: align & correct type size */ @@ -1965,7 +1971,8 @@ int ist(void) (tok >= TOK_CONST & tok <= TOK_INLINE)) { /* ignored types */ } else if (tok == TOK_FLOAT || tok == TOK_DOUBLE) { - warning("floats not supported"); + /* We allow that to compile standard headers */ + // warning("floats not supported"); } else if (tok == TOK_EXTERN) { t |= VT_EXTERN; } else if (tok == TOK_STATIC) { @@ -1978,7 +1985,7 @@ int ist(void) s = sym_find(tok); if (!s || !(s->t & VT_TYPEDEF)) break; - t = s->t & ~VT_TYPEDEF; + t |= (s->t & ~VT_TYPEDEF); } next(); } @@ -2012,8 +2019,7 @@ int post_type(t) if (pt & VT_VOID && tok == ')') break; l = FUNC_NEW; - pt = typ(&n, pt); /* XXX: should accept - both arg/non arg if v == 0 */ + pt = type_decl(&n, pt, TYPE_DIRECT | TYPE_ABSTRACT); } else { old_proto: n = tok; @@ -2067,7 +2073,7 @@ int post_type(t) /* Read a type declaration (except basic type), and return the type. If v is true, then also put variable name in 'vc' */ -int typ(int *v, int t) +int type_decl(int *v, int t, int td) { int u, p; Sym *s; @@ -2075,6 +2081,8 @@ int typ(int *v, int t) t = t & -3; /* suppress the ored '2' */ while (tok == '*') { next(); + while (tok == TOK_CONST || tok == TOK_VOLATILE) + next(); t = mk_pointer(t); } @@ -2082,14 +2090,18 @@ int typ(int *v, int t) /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ if (tok == '(') { next(); - u = typ(v, 0); + u = type_decl(v, 0, td); skip(')'); } else { u = 0; /* type identifier */ - if (v) { + if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { *v = tok; next(); + } else { + if (!(td & TYPE_ABSTRACT)) + expect("identifier"); + *v = 0; } } /* append t at the end of u */ @@ -2165,7 +2177,7 @@ void unary() if (t == '(') { /* cast ? */ if (t = ist()) { - ft = typ(0, t); + ft = type_decl(&n, t, TYPE_ABSTRACT); skip(')'); unary(); vt = (vt & VT_TYPEN) | ft; @@ -2204,7 +2216,7 @@ void unary() if (tok == '(') { next(); if (t = ist()) - vt = typ(0, t); + vt = type_decl(&n, t, TYPE_ABSTRACT); else expr(); skip(')'); @@ -2699,7 +2711,7 @@ void decl(l) continue; } while (1) { /* iterate thru each declaration */ - t = typ(&v, b); + t = type_decl(&v, b, TYPE_DIRECT); if (tok == '{') { if (!(t & VT_FUNC)) expect("function defintion"); @@ -2743,7 +2755,7 @@ void decl(l) /* not lvalue if array */ if (!(t & VT_ARRAY)) t |= VT_LVAL; - if (t & VT_EXTERN) { + if (b & VT_EXTERN) { /* external variable */ /* XXX: factorize with external function def */ n = (int)dlsym(NULL, get_tok_str(v, 0)); @@ -2780,6 +2792,19 @@ void decl(l) } } +/* open a dynamic library so that its symbol are available for + compiled programs */ +void open_dll(char *libname) +{ + char buf[1024]; + void *h; + + snprintf(buf, sizeof(buf), "lib%s.so", libname); + h = dlopen(buf, RTLD_GLOBAL | RTLD_LAZY); + if (!h) + error((char *)dlerror()); +} + int main(int argc, char **argv) { Sym *s; @@ -2801,10 +2826,16 @@ int main(int argc, char **argv) p = r; } + /* standard defines */ + define_symbol("__STDC__"); +#ifdef __i386__ + define_symbol("__i386__"); +#endif + optind = 1; while (1) { if (optind >= argc) { - printf("usage: tcc [-Idir] infile [infile_arg...]\n"); + printf("usage: tcc [-Idir] [-Dsym] [-llib] infile [infile_arg...]\n"); return 1; } r = argv[optind]; @@ -2814,8 +2845,13 @@ int main(int argc, char **argv) if (nb_include_paths >= INCLUDE_PATHS_MAX) error("too many include paths"); include_paths[nb_include_paths++] = r + 2; + } else if (r[1] == 'D') { + define_symbol(r + 2); + } else if (r[1] == 'l') { + open_dll(r + 2); } else { - error("invalid option"); + fprintf(stderr, "invalid option -- '%s'\n", r); + exit(1); } optind++; } @@ -2845,7 +2881,7 @@ int main(int argc, char **argv) #ifdef TEST { FILE *f; - f = fopen(v[1], "w"); + f = fopen(argv[optind + 1], "w"); fwrite((void *)prog, 1, ind - prog, f); fclose(f); return 0; @@ -2855,6 +2891,10 @@ int main(int argc, char **argv) if (!s) error("main() not defined"); t = s->c; +#ifdef PROFILE + return 1; +#else return (*t)(argc - optind, argv + optind); #endif +#endif }