diff --git a/libtcc.c b/libtcc.c index 7caa7c1e..4bb7f1b8 100644 --- a/libtcc.c +++ b/libtcc.c @@ -868,6 +868,7 @@ LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym) static void tcc_cleanup(void) { int i, n; + CSym *def; if (NULL == tcc_state) return; tcc_state = NULL; @@ -877,8 +878,11 @@ static void tcc_cleanup(void) /* free tokens */ n = tok_ident - TOK_IDENT; - for(i = 0; i < n; i++) + for(i = 0; i < n; i++){ + def = &table_ident[i]->sym_define; + tcc_free(def->data); tcc_free(table_ident[i]); + } tcc_free(table_ident); /* free sym_pools */ diff --git a/tcc.h b/tcc.h index c93cedfe..c49eac42 100644 --- a/tcc.h +++ b/tcc.h @@ -303,15 +303,22 @@ #define VSTACK_SIZE 256 #define STRING_MAX_SIZE 1024 #define PACK_STACK_SIZE 8 +#define MACRO_STACK_SIZE 4 #define TOK_HASH_SIZE 8192 /* must be a power of two */ #define TOK_ALLOC_INCR 512 /* must be a power of two */ #define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */ +typedef struct CSym { + int off; + int size;/* size in *sym */ + struct Sym **data; /* if non NULL, data has been malloced */ +} CSym; + /* token symbol management */ typedef struct TokenSym { struct TokenSym *hash_next; - struct Sym *sym_define; /* direct pointer to define */ + struct CSym sym_define; /* direct pointer to define */ struct Sym *sym_label; /* direct pointer to label */ struct Sym *sym_struct; /* direct pointer to structure */ struct Sym *sym_identifier; /* direct pointer to identifier */ @@ -1124,7 +1131,8 @@ ST_DATA TokenSym **table_ident; 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_SPACES 0x0010 /* next() returns space tokens (for -E) */ +#define PARSE_FLAG_PACK 0x0020 /* #pragma pack */ ST_FUNC TokenSym *tok_alloc(const char *str, int len); ST_FUNC char *get_tok_str(int v, CValue *cv); diff --git a/tccgen.c b/tccgen.c index 0937883a..db821e17 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5234,13 +5234,13 @@ static void init_putz(CType *t, Section *sec, unsigned long c, int size) } else { vpush_global_sym(&func_old_type, TOK_memset); vseti(VT_LOCAL, c); -#ifdef TCC_TARGET_ARM +# ifdef TCC_TARGET_ARM vpushs(size); vpushi(0); -#else +# else vpushi(0); vpushs(size); -#endif +# endif gfunc_call(3); } } diff --git a/tccpp.c b/tccpp.c index 2da65cd2..99471716 100644 --- a/tccpp.c +++ b/tccpp.c @@ -234,7 +234,10 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) ts = tcc_malloc(sizeof(TokenSym) + len); table_ident[i] = ts; ts->tok = tok_ident++; - ts->sym_define = NULL; + ts->sym_define.data = tcc_malloc(sizeof(Sym**)); + ts->sym_define.off = 0; + ts->sym_define.data[0] = NULL; + ts->sym_define.size = 1; ts->sym_label = NULL; ts->sym_struct = NULL; ts->sym_identifier = NULL; @@ -1053,52 +1056,62 @@ static int macro_is_equal(const int *a, const int *b) ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg) { Sym *s; - + CSym *def; 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; + def = &table_ident[v - TOK_IDENT]->sym_define; + def->data[def->off] = 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; + CSym *def; + v = s->v - TOK_IDENT; + if ((unsigned)v < (unsigned)(tok_ident - TOK_IDENT)){ + def = &table_ident[v]->sym_define; + def->data[def->off] = NULL; + } } ST_INLN Sym *define_find(int v) { + CSym *def; v -= TOK_IDENT; if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) return NULL; - return table_ident[v]->sym_define; + def = &table_ident[v]->sym_define; + return def->data[def->off]; } /* free define stack until top reaches 'b' */ ST_FUNC void free_defines(Sym *b) { - Sym *top, *top1; + Sym *top, *tmp; int v; + CSym *def; top = define_stack; while (top != b) { - top1 = top->prev; + tmp = 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; + v = top->v - TOK_IDENT; + if ((unsigned)v < (unsigned)(tok_ident - TOK_IDENT)){ + def = &table_ident[v]->sym_define; + if(def->off) + def->off = 0; + if(def->data[0]) + def->data[0] = NULL; + } sym_free(top); - top = top1; + top = tmp; } define_stack = b; } @@ -1339,66 +1352,18 @@ static inline void add_cached_include(TCCState *s1, const char *filename, int if s1->cached_includes_hash[h] = s1->nb_cached_includes; } -static void pragma_parse(TCCState *s1) -{ - 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(')'); - } - } -} - /* 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; + uint8_t buf[1024], *p; Sym *s; saved_parse_flags = parse_flags; - parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | - PARSE_FLAG_LINEFEED; + parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_LINEFEED; next_nomacro(); - redo: +redo: switch(tok) { case TOK_DEFINE: next_nomacro(); @@ -1421,19 +1386,21 @@ ST_FUNC void preprocess(int is_bof) goto read_name; } else if (ch == '\"') { c = ch; - read_name: +read_name: inp(); - q = buf; + p = buf; while (ch != c && ch != '\n' && ch != CH_EOF) { - if ((q - buf) < sizeof(buf) - 1) - *q++ = ch; + if ((p - buf) < sizeof(buf) - 1) + *p++ = ch; if (ch == '\\') { if (handle_stray_noerror() == 0) - --q; + --p; } else inp(); } - *q = '\0'; + if (ch != c) + goto include_syntax; + *p = '\0'; minp(); #if 0 /* eat all spaces and comments after include */ @@ -1471,6 +1438,8 @@ ST_FUNC void preprocess(int is_bof) c = '>'; } } + if(!buf[0]) + tcc_error(" empty filename in #include"); if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) tcc_error("#include recursion too deep"); @@ -1537,8 +1506,7 @@ include_trynext: printf("%s: including %s\n", file->prev->filename, file->filename); #endif /* update target deps */ - dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps, - tcc_strdup(buf1)); + dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps, tcc_strdup(buf1)); /* push current file in stack */ ++s1->include_stack_ptr; /* add include file debug info */ @@ -1571,7 +1539,7 @@ include_done: file->ifndef_macro = tok; } } - c = (define_find(tok) != 0) ^ c; + c = !!define_find(tok) ^ c; do_if: if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) tcc_error("memory full (ifdef)"); @@ -1595,12 +1563,12 @@ include_done: goto skip; c = expr_preprocess(); s1->ifdef_stack_ptr[-1] = c; - test_else: +test_else: if (s1->ifdef_stack_ptr == file->ifdef_stack_ptr + 1) file->ifndef_macro = 0; - test_skip: +test_skip: if (!(c & 1)) { - skip: +skip: preprocess_skip(); is_bof = 0; goto redo; @@ -1618,11 +1586,11 @@ include_done: /* 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; } + next_nomacro(); + if (tok != TOK_LINEFEED) + tcc_warning("Ignoring: %s", get_tok_str(tok, &tokc)); break; case TOK_LINE: next(); @@ -1633,8 +1601,7 @@ include_done: if (tok != TOK_LINEFEED) { if (tok != TOK_STR) tcc_error("#line"); - pstrcpy(file->filename, sizeof(file->filename), - (char *)tokc.cstr->data); + pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.cstr->data); } break; case TOK_ERROR: @@ -1642,24 +1609,161 @@ include_done: c = tok; ch = file->buf_ptr[0]; skip_spaces(); - q = buf; + p = buf; while (ch != '\n' && ch != CH_EOF) { - if ((q - buf) < sizeof(buf) - 1) - *q++ = ch; + if ((p - buf) < sizeof(buf) - 1) + *p++ = ch; if (ch == '\\') { if (handle_stray_noerror() == 0) - --q; + --p; } else inp(); } - *q = '\0'; + *p = '\0'; if (c == TOK_ERROR) tcc_error("#error %s", buf); else tcc_warning("#warning %s", buf); break; case TOK_PRAGMA: - pragma_parse(s1); + next(); + if (tok == TOK_pack && parse_flags & PARSE_FLAG_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 { + int val = 0; + if (tok != ')') { + if (tok == TOK_ASM_push) { + next(); + s1->pack_stack_ptr++; + if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE) + goto stk_error; + skip(','); + } + if (tok != TOK_CINT) { +pack_error: + tcc_error("invalid pack pragma"); + } + val = tokc.i; + if (val < 1 || val > 16) + goto pack_error; + if (val < 1 || val > 16) + tcc_error("Value must be greater than 1 is less than or equal to 16"); + if ((val & (val - 1)) != 0) + tcc_error("Value must be a power of 2 curtain"); + next(); + } + *s1->pack_stack_ptr = val; + skip(')'); + } + }else if (tok == TOK_PUSH_MACRO || tok == TOK_POP_MACRO) { + TokenSym *ts; + CSym *def; + uint8_t *p1; + int len, t; + t = tok; + ch = file->buf_ptr[0]; + skip_spaces(); + if (ch != '(') + goto macro_xxx_syntax; + /* XXX: incorrect if comments : use next_nomacro with a special mode */ + inp(); + skip_spaces(); + if (ch == '\"'){ + inp(); + p = buf; + while (ch != '\"' && ch != '\n' && ch != CH_EOF) { + if ((p - buf) < sizeof(buf) - 1) + *p++ = ch; + if (ch == CH_EOB) { + --p; + handle_stray(); + }else + inp(); + } + if(ch != '\"') + goto macro_xxx_syntax; + *p = '\0'; + minp(); + next(); + }else{ + /* computed #pragma macro_xxx for #define xxx */ + next(); + buf[0] = '\0'; + while (tok != ')') { + if (tok != TOK_STR) { + macro_xxx_syntax: + tcc_error("'macro_xxx' expects (\"NAME\")"); + } + pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data); + next(); + } + } + skip (')'); + if(!buf[0]) + tcc_error(" empty string in #pragma"); + /* find TokenSym */ + p = buf; + while (is_space(*p)) + p++; + p1 = p; + for(;;){ + if (!isidnum_table[p[0] - CH_EOF]) + break; + ++p; + } + len = p - p1; + while (is_space(*p)) + p++; + if(!p) //'\0' + tcc_error("unrecognized string: %s", buf); + ts = tok_alloc(p1, len); + if(ts){ + def = &ts->sym_define; + if(t == TOK_PUSH_MACRO){ + void *tmp = def->data[def->off]; + if(tmp){ + def->off++; + if(def->off >= def->size){ + int size = def->size; + size *= 2; + if (size >= MACRO_STACK_SIZE) + tcc_error("stack full"); + def->data = tcc_realloc(def->data, size*sizeof(Sym**)); + def->size = size; + } + def->data[def->off] = tmp; + } + }else{ + if(def->off){ + --def->off; + }else{ + tcc_warning("stack empty"); + } + } + } + }else{ + fputs("#pragma ", s1->ppfp); + while (tok != TOK_LINEFEED){ + fputs(get_tok_str(tok, &tokc), s1->ppfp); + next(); + } + goto the_end; + } break; default: if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_PPNUM) { @@ -1679,7 +1783,7 @@ include_done: /* ignore other preprocess commands or #! for C scripts */ while (tok != TOK_LINEFEED) next_nomacro(); - the_end: +the_end: parse_flags = saved_parse_flags; } @@ -3136,12 +3240,13 @@ ST_FUNC int tcc_preprocess(TCCState *s1) 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; + PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES; token_seen = 0; line_ref = 0; file_ref = NULL; iptr = s1->include_stack_ptr; - + tok = TOK_LINEFEED; /* print line */ + goto print_line; for (;;) { next(); if (tok == TOK_EOF) { @@ -3149,11 +3254,11 @@ ST_FUNC int tcc_preprocess(TCCState *s1) } else if (file != file_ref) { goto print_line; } else if (tok == TOK_LINEFEED) { - if (!token_seen) + if (token_seen) continue; ++line_ref; - token_seen = 0; - } else if (!token_seen) { + token_seen = 1; + } else if (token_seen) { d = file->line_num - line_ref; if (file != file_ref || d < 0 || d >= 8) { print_line: @@ -3161,8 +3266,7 @@ print_line: 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 { @@ -3170,8 +3274,8 @@ print_line: fputs("\n", s1->ppfp), --d; } line_ref = (file_ref = file)->line_num; - token_seen = tok != TOK_LINEFEED; - if (!token_seen) + token_seen = tok == TOK_LINEFEED; + if (token_seen) continue; } fputs(get_tok_str(tok, &tokc), s1->ppfp); diff --git a/tcctok.h b/tcctok.h index 735ccdd1..41a8840e 100644 --- a/tcctok.h +++ b/tcctok.h @@ -138,6 +138,8 @@ /* pragma */ DEF(TOK_pack, "pack") + DEF(TOK_PUSH_MACRO, "push_macro") + DEF(TOK_POP_MACRO, "pop_macro") #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) /* already defined for assembler */ DEF(TOK_ASM_push, "push") diff --git a/tests/tcctest.c b/tests/tcctest.c index cc8ffd81..ee4a0e65 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -235,7 +235,7 @@ void intdiv_test(void) void macro_test(void) { - printf("macro:\n"); + printf("macro:\n"); pf("N=%d\n", N); printf("aaa=%d\n", AAA); @@ -379,6 +379,23 @@ comment /* And again when the name and parenthes are separated by a comment. */ TEST2 /* the comment */ (); + /* macro_push and macro_pop test */ + #define MACRO_TEST "macro_test1\n" + #pragma push_macro("MACRO_TEST") + #undef MACRO_TEST + #define MACRO_TEST "macro_test2\n" + printf(MACRO_TEST); + #pragma pop_macro("MACRO_TEST") + printf(MACRO_TEST); +/* gcc does not support + #define MACRO_TEST_MACRO "MACRO_TEST" + #pragma push_macro(MACRO_TEST_MACRO) + #undef MACRO_TEST + #define MACRO_TEST "macro_test3\n" + printf(MACRO_TEST); + #pragma pop_macro(MACRO_TEST_MACRO) + printf(MACRO_TEST); +*/ } @@ -2155,14 +2172,15 @@ void whitespace_test(void) { char *str; - #if 1 + +#if 1 pri\ -ntf("whitspace:\n"); +ntf("whitspace:\n"); #endif pf("N=%d\n", 2); #ifdef CORRECT_CR_HANDLING - pri\ + pri\ ntf("aaa=%d\n", 3); #endif @@ -2174,11 +2192,12 @@ ntf("min=%d\n", 4); printf("len1=%d\n", strlen(" ")); #ifdef CORRECT_CR_HANDLING - str = " + str = " "; printf("len1=%d str[0]=%d\n", strlen(str), str[0]); #endif - printf("len1=%d\n", strlen(" a + printf("len1=%d\n", strlen(" +a ")); #endif /* ACCEPT_CR_IN_STRINGS */ }