📄 tcc.c
字号:
} 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') { 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 */void preprocess_skip(void){ int a, start_of_line, c; uint8_t *p; p = file->buf_ptr; start_of_line = 1; a = 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': start_of_line = 1; file->line_num++; p++; goto redo_no_start; case '\\': file->buf_ptr = p; c = handle_eob(); if (c == CH_EOF) { expect("#endif"); } else if (c == '\\') { /* XXX: incorrect: should not give an error */ ch = file->buf_ptr[0]; handle_stray(); } p = file->buf_ptr; goto redo_no_start; /* skip strings */ case '\"': case '\'': p = parse_pp_string(p, c, NULL); break; /* skip comments */ case '/': 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--; } break; default: p++; break; } start_of_line = 0; } the_end: ; file->buf_ptr = p;}/* ParseState handling *//* XXX: currently, no include file info is stored. Thus, we cannot display accurate messages if the function or data definition spans multiple files *//* save current parse state in 's' */void save_parse_state(ParseState *s){ s->line_num = file->line_num; s->macro_ptr = macro_ptr; s->tok = tok; s->tokc = tokc;}/* restore parse state from 's' */void restore_parse_state(ParseState *s){ 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_STR: case TOK_LSTR: case TOK_CFLOAT: case TOK_LINENUM: case TOK_PPNUM: 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 */static inline void tok_str_new(TokenString *s){ s->str = NULL; s->len = 0; s->allocated_len = 0; s->last_line_num = -1;}static void tok_str_free(int *str){ const int *p; CString *cstr; int t; p = str; for(;;) { t = *p; /* NOTE: we test zero separately so that GCC can generate a table for the following switch */ if (t == 0) break; switch(t) { case TOK_CINT: case TOK_CUINT: case TOK_CCHAR: case TOK_LCHAR: case TOK_CFLOAT: case TOK_LINENUM: p += 2; break; case TOK_PPNUM: case TOK_STR: case TOK_LSTR: /* XXX: use a macro to be portable on 64 bit ? */ cstr = (CString *)p[1]; cstr_free(cstr); tcc_free(cstr); p += 2; break; case TOK_CDOUBLE: case TOK_CLLONG: case TOK_CULLONG: p += 3; break; case TOK_CLDOUBLE: p += 1 + (LDOUBLE_SIZE / 4); break; default: p++; break; } } tcc_free(str);}static int *tok_str_realloc(TokenString *s){ int *str, len; len = s->allocated_len + TOK_STR_ALLOC_INCR; str = tcc_realloc(s->str, len * sizeof(int)); if (!str) error("memory full"); s->allocated_len = len; s->str = str; return str;}static void tok_str_add(TokenString *s, int t){ 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;}static void tok_str_add2(TokenString *s, int t, CValue *cv){ int len, *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: str[len++] = (int)cstr_dup(cv->cstr); break; case TOK_CDOUBLE: case TOK_CLLONG: case TOK_CULLONG: str[len++] = cv->tab[0]; str[len++] = cv->tab[1]; break; case TOK_CLDOUBLE:#if LDOUBLE_SIZE == 12 str[len++] = cv->tab[0]; str[len++] = cv->tab[1]; str[len++] = cv->tab[2];#else#error add long double size support#endif break; default: break; } s->len = len;}/* add the current parse token in token string 's' */static void tok_str_add_tok(TokenString *s){ 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);}#if LDOUBLE_SIZE == 12#define LDOUBLE_GET(p, cv) \ cv.tab[0] = p[0]; \ cv.tab[1] = p[1]; \ cv.tab[2] = p[2];#else#error add long double size support#endif/* get a token from an integer array and increment pointer accordingly. we code it as a macro to avoid pointer aliasing. */#define TOK_GET(t, p, cv) \{ \ t = *p++; \ switch(t) { \ case TOK_CINT: \ case TOK_CUINT: \ case TOK_CCHAR: \ case TOK_LCHAR: \ case TOK_CFLOAT: \ case TOK_LINENUM: \ case TOK_STR: \ case TOK_LSTR: \ case TOK_PPNUM: \ cv.tab[0] = *p++; \ break; \ case TOK_CDOUBLE: \ case TOK_CLLONG: \ case TOK_CULLONG: \ cv.tab[0] = p[0]; \ cv.tab[1] = p[1]; \ p += 2; \ break; \ case TOK_CLDOUBLE: \ LDOUBLE_GET(p, cv); \ p += LDOUBLE_SIZE / 4; \ break; \ default: \ break; \ } \}/* defines handling */static inline void define_push(int v, int macro_type, int *str, Sym *first_arg){ Sym *s; s = sym_push2(&define_stack, v, macro_type, (int)str); s->next = first_arg; table_ident[v - TOK_IDENT]->sym_define = s;}/* undefined a define symbol. Its name is just set to zero */static 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;}static inline Sym *define_find(int v){ 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' */static void free_defines(Sym *b){ Sym *top, *top1; int v; top = define_stack; while (top != b) { top1 = top->prev; /* do not free args or predefined defines */ if (top->c) tok_str_free((int *)top->c); v = top->v; if (v >= TOK_IDENT && v < tok_ident) table_ident[v - TOK_IDENT]->sym_define = NULL; tcc_free(top); top = top1; } define_stack = b;}/* label lookup */static Sym *label_find(int v){ v -= TOK_IDENT; if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) return NULL; return table_ident[v]->sym_label;}static 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;}/* pop labels until element last is reached. Look if any labels are undefined. Define symbols if '&&label' was used. */static 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) { warning("label '%s' declared but not used", get_tok_str(s->v, NULL)); } else if (s->r == LABEL_FORWARD) { error("label '%s' used but not defined", get_tok_str(s->v, NULL)); } else { if (s->c) { /* define corresponding symbol. A size of 1 is put. */ put_extern_sym(s, cur_text_section, (long)s->next, 1); } } /* remove label */ table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok; tcc_free(s); } *ptop = slast;}/* eval an expression for #if/#elif */static int expr_preprocess(void){ 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_C
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -