📄 tcc.c
字号:
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 = tcc_malloc(sizeof(Sym)); 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; } tcc_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); 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; if (c == '\n' || c == CH_EOF) { break; } else 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 { p++; } } return p;}/* C comments */static uint8_t *parse_comment(uint8_t *p){ 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) { error("unexpected end of file in comment"); } else if (c == '\\') { p++; } } } end_of_comment: p++; return p;}#define cinp minp/* space exlcuding newline */static inline int is_space(int ch){ return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r';}static inline void skip_spaces(void){ while (is_space(ch)) cinp();}/* parse a string without interpreting escapes */static uint8_t *parse_pp_string(uint8_t *p, 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 */ error("missing terminating %c character", sep);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -