📄 tcc.c
字号:
break; if (ts->len == len && !memcmp(ts->str, str, len)) return ts; pts = &(ts->hash_next); } return tok_alloc_new(pts, str, len);}/* CString handling */static void cstr_realloc(CString *cstr, int new_size){ 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 = tcc_realloc(cstr->data_allocated, size); if (!data) error("memory full"); cstr->data_allocated = data; cstr->size_allocated = size; cstr->data = data;}/* add a byte */static inline 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;}static void cstr_cat(CString *cstr, const char *str){ int c; for(;;) { c = *str; if (c == '\0') break; cstr_ccat(cstr, c); str++; }}/* add a wide char */static void cstr_wccat(CString *cstr, int ch){ int size; size = cstr->size + sizeof(int); if (size > cstr->size_allocated) cstr_realloc(cstr, size); *(int *)(((unsigned char *)cstr->data) + size - sizeof(int)) = ch; cstr->size = size;}static void cstr_new(CString *cstr){ memset(cstr, 0, sizeof(CString));}/* free string and reset it to NULL */static void cstr_free(CString *cstr){ tcc_free(cstr->data_allocated); cstr_new(cstr);}#define cstr_reset(cstr) cstr_free(cstr)/* 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)); } }}/* XXX: buffer overflow *//* XXX: float tokens */char *get_tok_str(int v, CValue *cv){ static char buf[STRING_MAX_SIZE + 1]; static CString cstr_buf; CString *cstr; unsigned char *q; 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; switch(v) { case TOK_CINT: case TOK_CUINT: /* XXX: not quite exact, but only useful for testing */ sprintf(p, "%u", cv->ui); break; case TOK_CLLONG: case TOK_CULLONG: /* XXX: not quite exact, but only useful for testing */ sprintf(p, "%Lu", cv->ull); break; case TOK_CCHAR: case TOK_LCHAR: cstr_ccat(&cstr_buf, '\''); 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_STR: case TOK_LSTR: 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(int)) - 1; for(i=0;i<len;i++) add_char(&cstr_buf, ((int *)cstr->data)[i]); } cstr_ccat(&cstr_buf, '\"'); cstr_ccat(&cstr_buf, '\0'); break; case TOK_LT: v = '<'; goto addv; case TOK_GT: v = '>'; goto addv; case TOK_A_SHL: return strcpy(p, "<<="); case TOK_A_SAR: return strcpy(p, ">>="); default: if (v < TOK_IDENT) { /* search in two bytes table */ 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;}/* push, without hashing */static Sym *sym_push2(Sym **ps, int v, int t, int c){ Sym *s; s = sym_malloc(); s->v = v; s->type.t = t; 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 */static Sym *sym_find2(Sym *s, int v){ while (s) { if (s->v == v) return s; s = s->prev; } return NULL;}/* structure lookup */static inline Sym *struct_find(int v){ v -= TOK_IDENT; if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) return NULL; return table_ident[v]->sym_struct;}/* find an identifier */static inline Sym *sym_find(int v){ v -= TOK_IDENT; if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) return NULL; return table_ident[v]->sym_identifier;}/* push a given symbol on the symbol stack */static Sym *sym_push(int v, CType *type, int r, int c){ Sym *s, **ps; TokenSym *ts; if (local_stack) ps = &local_stack; else ps = &global_stack; 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 */static Sym *global_identifier_push(int v, int t, int 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;}/* pop symbols until top reaches 'b' */static void sym_pop(Sym **ptop, Sym *b){ 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;}/* I/O layer */BufferedFile *tcc_open(TCCState *s1, const char *filename){ int fd; BufferedFile *bf; fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) return NULL; bf = tcc_malloc(sizeof(BufferedFile)); if (!bf) { close(fd); return NULL; } bf->fd = fd; bf->buf_ptr = bf->buffer; bf->buf_end = bf->buffer; bf->buffer[0] = CH_EOB; /* put eob symbol */ pstrcpy(bf->filename, sizeof(bf->filename), filename); bf->line_num = 1; bf->ifndef_macro = 0; bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; // printf("opening '%s'\n", filename); return bf;}void tcc_close(BufferedFile *bf){ total_lines += bf->line_num; close(bf->fd); tcc_free(bf);}/* 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) {#if defined(PARSE_DEBUG) len = 8;#else 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; }}/* return the current character, handling end of block if necessary (but not stray) */static int handle_eob(void){ return tcc_peekc_slow(file);}/* read next char from current input file and handle end of input buffer */static inline void inp(void){ ch = *(++(file->buf_ptr)); /* end of buffer/file handling */ if (ch == CH_EOB) ch = handle_eob();}/* handle '\[\r]\n' */static void handle_stray(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: 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; 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;\ }\}/* handle the complicated stray case */#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 */static void minp(void){ inp(); if (ch == '\\') handle_stray();}/* single line C++ comments */static uint8_t *parse_line_comment(uint8_t *p){ int c; p++; for(;;) { c = *p; redo: if (c == '\n' || c == CH_EOF) { break; } else if (c == '\\') {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -