From 3eeb6f219e4d32160fa10895b57a8ddfefff5ff7 Mon Sep 17 00:00:00 2001 From: lemon Date: Tue, 17 Mar 2026 13:43:05 +0100 Subject: REFACTOR: finish renaming --- .gitignore | 5 +- README.md | 42 +- bootstrap.sh | 2 +- src/a_common.h | 465 ------------------ src/a_embedfilesdir.c | 106 +++++ src/a_main.c | 4 +- src/a_targ.c | 4 +- src/antcc.h | 465 ++++++++++++++++++ src/c.c | 8 +- src/c.h | 4 +- src/c_builtin.c | 2 +- src/c_embedfilesdir.c | 106 ----- src/c_eval.c | 2 +- src/c_lex.c | 6 +- src/c_lex.h | 6 +- src/c_type.c | 2 +- src/c_type.h | 2 +- src/io.c | 1255 ------------------------------------------------- src/ir.c | 6 +- src/ir.h | 8 +- src/ir_dump.c | 6 +- src/ir_fold.c | 2 +- src/o_elf.c | 6 +- src/o_elf.h | 131 +++--- src/obj.c | 2 +- src/obj.h | 2 +- src/t_aarch64.h | 2 +- src/t_aarch64_aapcs.c | 2 +- src/t_aarch64_emit.c | 6 +- src/t_aarch64_isel.c | 2 +- src/t_x86-64.h | 2 +- src/t_x86-64_emit.c | 6 +- src/t_x86-64_isel.c | 4 +- src/t_x86-64_sysv.c | 2 +- src/u_endian.h | 2 +- src/u_io.c | 1255 +++++++++++++++++++++++++++++++++++++++++++++++++ src/u_mem.c | 2 +- tool/depgen.c | 10 +- 38 files changed, 1978 insertions(+), 1966 deletions(-) delete mode 100644 src/a_common.h create mode 100644 src/a_embedfilesdir.c create mode 100644 src/antcc.h delete mode 100644 src/c_embedfilesdir.c delete mode 100644 src/io.c create mode 100644 src/u_io.c diff --git a/.gitignore b/.gitignore index 22ef4d1..abee9df 100644 --- a/.gitignore +++ b/.gitignore @@ -16,10 +16,11 @@ !Makefile !bootstrap.sh -src/hostconfig.h !/src/ !/src/* -!/tool/ +!/tool/*.c +!/tool/*.h +src/hostconfig.h !/test/ !/test/external/** diff --git a/README.md b/README.md index 279a69b..30b7619 100644 --- a/README.md +++ b/README.md @@ -78,45 +78,46 @@ Contributions are welcome as long as they aren't low-effort AI slop, send as pul ## Internals & Design -C type representation (`type.h` & `type.c`) is shared by the frontend and +C type representation (`c_type.h` & `c_type.c`) is shared by the frontend and backend because the backend is responsible for ABI-specific lowering of calling conventions. The C frontend is structured like so: - - Compiler driver (`main.c`), which parses command line options, inputs and + + - Compiler driver (`a_main.c`), which parses command line options, inputs and outputs and calls out to the core compiler to build individual object files and possibly invoke an external command to link them together. - - Tokenizer & preprocessor (`c/lex.c`): The input file is scanned on-demand, + - Tokenizer & preprocessor (`c_lex.c`): The input file is scanned on-demand, initially reading characters into an internal buffer after performing backslash-newline delition (and possibly trigraph substitution), then producing one token at a time when the parser requests the next one. Preprocessing (directives & macro expansion) is also done on the fly. - - Parser & IR generation (`c/c.c`): The handwritten parser reads declarations + - Parser & IR generation (`c.c`): The handwritten parser reads declarations and keeps them in a symbol table/environment. Static data is written to buffers that correspond to the .rodata/.data sections of the final object file, emitting relocations to the object file interface too. Function bodies are parsed and transformed into the IR in one pass. Expressions are parsed into expression trees before being emitted or compile-time evaluated - (`c/eval.c`), but there is no whole-program AST. When the end of a + (`c_eval.c`), but there is no whole-program AST. When the end of a function definition is reached, the backend is called to perform all of the passes that will finally transform it into machine code written to the .text section. -The backend (`ir/*`) uses an IR in Static Single Assignment (SSA) form. +The backend (`ir_*`) uses an IR in Static Single Assignment (SSA) form. Instructions have a return type and up to two operands. Because of SSA form, temporaries are simply referenced by the instruction that provides their definition, so an explicit output operand is not required. The list of -instructions is defined in `ir/op.def`. Each basic block in the control flow +instructions is defined in `ir_op.def`. Each basic block in the control flow graph consists of 0 or more phi functions, followed by 0 or more instructions, terminated by a jump (unconditional/conditional branch, return, or trap). -The builder API (`ir/builder.c`) used by the frontend performs peephole +The builder API (`ir_builder.c`) used by the frontend performs peephole optimizations on the fly, mainly constant folding. -Object file interface routines are in `obj/obj.[c/h]` ELF implementation in -`obj/elf.[c/h]`. Support for other object formats like PE and Mach-O is planned. +Object file interface routines are in `obj.[c/h]` ELF implementation in +`o_elf.[c/h]`. Support for other object formats like PE and Mach-O is planned. Debug information in the form of DWARF is also planned, but it is a sizeable undertaking. @@ -124,32 +125,33 @@ The `-d...` compiler flag can be used to print the output of different stages of the backend for debugging. The backend performs the following main passes: - - ABI lowering (`ir/abi0.c`, `x86_64/sysv.c`): implements target calling + + - ABI lowering (`ir_abi0.c`, `t_x86-64_sysv.c`): implements target calling convention details, such as lowering structures being passed/returned by value in registers or the stack. - - Intrinsics lowering (`ir/intrin.c`): lowers some intrinsics emitted by the + - Intrinsics lowering (`ir_intrin.c`): lowers some intrinsics emitted by the frontend (currently just structcopy) - - mem2reg (`ir/mem2reg.c`): lower stack slots into SSA temporaries. This is + - mem2reg (`ir_mem2reg.c`): lower stack slots into SSA temporaries. This is an important pass because the frontend puts every C variable into a stack slot, and this pass transforms those into temporaries and phi instructions in SSA form instructions when possible (most of the time, unless they are aggregates or their address is taken), which is also how clang/LLVM does it. Can be disabled with -O0. - With -O1+ optimizations enabled - + inlining (`ir/inliner.c`) - + common-subexpression elimination (`ir/cse.c`), + + inlining (`ir_inliner.c`) + + common-subexpression elimination (`ir_cse.c`), + general arithmetic simplifications, branch simplification - (`ir/simpl.c`) + (`ir_simpl.c`) - - Stack lowering (`ir/stack.c`): `alloca` instructions are deleted and + - Stack lowering (`ir_stack.c`): `alloca` instructions are deleted and corresponding stack slots replaced with calculated stack offsets. - - Instruction selection (`ir/isel.c`, `x86_64/isel.c`): architecture-specific + - Instruction selection (`x86_64/isel.c`): architecture-specific instruction selection, addressing mode utilization, introduction of register constraints. - - Register allocation (`ir/regalloc.c`): performs linear scan register + - Register allocation (`ir_regalloc.c`): performs linear scan register allocation. A scratch register is reserved for operations with spilled temporaries. - - Code emission (`x86_64/emit.c`): binary code for the target architecture is + - Code emission (`t_x86-64_emit.c`): binary code for the target architecture is emitted directly (not textual assembly). Relocations are deferred to the object file interface too. diff --git a/bootstrap.sh b/bootstrap.sh index 8a2cd64..b193bbd 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -12,7 +12,7 @@ test -n "$cflags" || : ${cflags:="-std=c11"} if test -n "$V"; then opt="$opt -v" fi -src=$(head -n 15 Makefile | grep -o '\([_A-Za-z0-9/]\)\+\.c') +src=$(find src/ -name '*.c') X() { echo "> $@" | (test -n "$V" && cat || sed -s 's/\([^ ]\+\.c \?\)\{10\}$/.../') $@ diff --git a/src/a_common.h b/src/a_common.h deleted file mode 100644 index a24aa3d..0000000 --- a/src/a_common.h +++ /dev/null @@ -1,465 +0,0 @@ -#ifndef COMMON_H_ -#define COMMON_H_ - -#include -#include -#include - -#ifdef __clang__ /* stop linter from complaining about "unused" inline functions */ -#pragma GCC diagnostic ignored "-Wunused-function" -#endif - -#define bool _Bool -typedef unsigned char uchar; -typedef signed char schar; -typedef unsigned short ushort; -typedef unsigned long long uvlong; -typedef signed long long vlong; -typedef unsigned uint; - -#if __STDC_VERSION__ >= 202311L -#define NORETURN [[noreturn]] -#elif __STDC_VERSION__ >= 201112L -#define NORETURN _Noreturn -#else -#define NORETURN -#endif - -#ifdef __has_builtin -#define HAS_BUILTIN(b) __has_builtin(__builtin_##b) -#else -#define HAS_BUILTIN(_) 0 -#endif - -#define static_assert(x) _Static_assert(x, #x) -#define in_range(x, Lo, Hi) ((uint) (x) - (Lo) <= (Hi) - (Lo)) /* lo <= x <= hi; lo > 0, hi > 0 */ -#define alignup(x, A) (((x) + ((A) - 1)) & -(A)) -#define countof(a) (sizeof(a) / sizeof 0[a]) - -enum { SPANFILEBITS = 10 }; -struct span { - struct span0 { - uint off; - uint len : 32-SPANFILEBITS, - file : SPANFILEBITS; - } sl, /* original source location */ - ex; /* the location after #include/macro expansion */ -}; - -void _assertfmt(const char *file, int line, const char *func, const char *expr); -#if HAS_BUILTIN(trap) -#define assert(x) (!(x) ? _assertfmt(__FILE__,__LINE__,__func__,#x), __builtin_trap() : (void)0) -#else -#define assert(x) (void)(!(x) ? _assertfmt(__FILE__,__LINE__,__func__,#x), *(volatile int *)0 : 0) -#endif - -static inline size_t -hashs(size_t h, const char *s) -{ - while (*s) h = (uchar)*s++ + h*65599; - return h; -} -static inline size_t -hashb(size_t h, const void *d, size_t n) -{ - const uchar *b = d; - while (n--) h = *b++ + h*65599; - return h; -} -static inline size_t -ptrhash(const void *p) { - return (size_t)p * 2654435761u; -} -static inline uint -popcnt(uvlong x) { -#if HAS_BUILTIN(popcountll) - return x ? __builtin_popcountll(x) : 0; -#else - uint n = 0; - while (x) n += x&1, x >>= 1; - return n; -#endif -} -static inline bool -ispo2(uvlong x) { - return (x != 0) & ((x & (x - 1)) == 0); -} -static inline uint -ilog2(uvlong x) { /* assumes x is a power of 2 */ -#if HAS_BUILTIN(ctzll) - return __builtin_ctzll(x); -#else - uint n = 0; - while (x >>= 1) ++n; - return n; -#endif -} -static inline uint -lowestsetbit(uvlong x) -{ -#if HAS_BUILTIN(ctzll) - return __builtin_ctzll(x); -#else - int i = 0; - for (uvlong mask = 1;; ++i, mask <<= 1) - if (x & mask) - break; - return i; -#endif -} - -#define aisprint(c) in_range(c, ' ', '~') -#define aisdigit(c) in_range(c, '0', '9') -#define aisodigit(c) in_range(c, '0', '7') -#define aisalpha(c) in_range((c)|0x20, 'a', 'z') -static inline bool aisspace(int c) { return c == ' ' || in_range(c, '\t', '\r'); } -static inline bool aisxdigit(int c) { return aisdigit(c) || in_range(c|0x20, 'a', 'f'); } - -/******************/ -/* COMPILER STATE */ -/******************/ - -enum cstd { - STDC89, - STDC99, - STDC11, - STDC23, -}; -struct option { - enum cstd cstd; - bool pedant; - bool trigraph; - bool nocolor; - bool pie, pic; - bool werror; - bool wnone; - enum optz { - OPT0 = -1, - OPT1 = 1, - OPT2 = 2, - } o; - union { - struct { - bool p : 1, /* after parsing */ - a : 1, /* after abi0 */ - m : 1, /* after mem */ - y : 1, /* after inline */ - o : 1, /* after optimizations */ - s : 1, /* after stack */ - i : 1, /* after isel */ - l : 1, /* after liveness fixup */ - r : 1; /* after regalloc */ - }; - uint any; - } dbg; - struct wbuf *dbgout; -}; -extern struct option ccopt; -extern struct cinclpaths { - struct inclpath { - struct inclpath *next; - const char *path; - } *list, **tail; -} cinclpaths[5]; -enum { /* GCC include directory search order: https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html#Options-for-Directory-Search */ - CINCL_iquote, - CINCL_I, - CINCL_isystem, - CINCLsys, - CINCL_idirafter, -}; - -/**********/ -/* Target */ -/**********/ - -struct targtriple { - enum mcarch { ISxxx, ISx86_64, ISaarch64 } arch; - enum mcos { OSunknown, OSlinux } os; - enum mcabi { ABInone, ABIgnu, ABImusl } abi; -}; -extern const struct mctarg *mctarg; -extern struct targtriple target; -void targ_init(const char *); - -/*********/ -/** MEM **/ -/*********/ - -/* libc *alloc wrappers */ -void *xmalloc(size_t n, const char *); -void *xcalloc(size_t n, const char *); -void *xrealloc(void *, size_t n, const char *); -void free(void *); -#define xmalloc(n) xmalloc(n, __func__) -#define xcalloc(n) xcalloc(n, __func__) -#define xrealloc(p,n) xrealloc(p, n, __func__) - -/* string interning */ -typedef const struct internstr {char c;} *internstr; -internstr intern_(const char *, uint len); -#define intern(s) intern_(s, 0) - -/* growable buffer that stores its capacity in the allocated memory */ -#define xbnew_(n) (void *)(1 + (size_t *)xcalloc(sizeof(size_t) + (n))) -#define xbcap_(p) ((size_t *)(p))[-1] -static inline void -xbgrow_(void **p, size_t n) -{ - if (!n) return; - if (!*p) { *p = xbnew_(n); xbcap_(*p) = n; assert(n>0); } - else if (xbcap_(*p) < n) { - size_t k = xbcap_(*p); - assert(k > 0); - do k *= 2; while (k < n); - *p = 1 + (size_t *)xrealloc(&xbcap_(*(p)), sizeof(size_t) + k); - xbcap_(*p) = k; - }; -} -#define xbgrow(p, n) xbgrow_((void **)(p), (n) * sizeof**(p)) -#define xbpush(p, n, x) (xbgrow(p, (*(n) + 1)), (*(p))[(*(n))++] = (x)) -#define xbfree(p) ((p) ? free(&xbcap_(p)) : (void)0) -#define xbcap(p) ((p) ? xbcap_(p) / sizeof*(p) : 0) -#define xbgrowz(p, n) do { \ - size_t tmp = *(p) ? xbcap_(*(p)) : 0; \ - xbgrow(p, n); \ - memset((char*)*(p)+tmp, 0, xbcap_(*(p))-tmp); \ -} while (0) - - -/** arenas **/ -struct arena { - uint cap : 31, - dyn : 1; - uint n; - struct arena *prev; - uchar mem[]; -}; - -extern struct arena *globarena; - -struct arena *newarena(uint chunksiz); -void *alloc(struct arena **, uint siz, uint align); -void *allocz(struct arena **, uint siz, uint align); -static inline void * -alloccopy(struct arena **arena, const void *src, uint siz, uint align) -{ - if (!siz) return NULL; - return memcpy(alloc(arena, siz, align), src, siz); -} -void freearena(struct arena **); - -/** vec **/ -struct vecbase { void *p; uint n; uint cap : 31, dyn : 1; }; -#define vec_of(T) union { \ - struct { T *p; uint n; }; \ - struct vecbase _vb; \ -} -void vinit_(struct vecbase *, void *inlbuf, uint cap, uint siz); -void vpush_(struct vecbase *, uint siz); -void *vpushn_(struct vecbase *, uint siz, const void *dat, uint ndat); -void vresize_(struct vecbase *, uint siz, uint N); -#define VINIT(inlbuf, Cap) { ._vb.p = (inlbuf), ._vb.cap = (Cap) } -#define vfree(v) ((v)->_vb.dyn ? free((v)->p) : (void)0, memset((v), 0, sizeof*(v))) -#define vinit(v, inlbuf, Cap) (vfree(v), vinit_(&(v)->_vb, inlbuf, (Cap), sizeof *(v)->p)) -#define vpush(v, x) (vpush_(&(v)->_vb, sizeof *(v)->p), (v)->p[(v)->n++] = (x)) -#define vpushn(v, xs, N) vpushn_(&(v)->_vb, sizeof *(v)->p, xs, N) -#define vresize(v, N) vresize_(&(v)->_vb, sizeof *(v)->p, N) - -/** map of short -> T **/ -#define imap_of(T) struct { T *v; int tmp; struct imapbase mb; } -struct imapbase { short *k; struct bitset *bs; uint n, N; }; - -void imap_init_(struct imapbase *, void **v, uint vsiz, uint N); -int imap_get_(struct imapbase *, short k); -int imap_set_(struct imapbase *, void **v, uint vsiz, short k); -#define imap_free(m) (free((m)->mb.k), memset((m), 0, sizeof *(m))) -#define imap_init(m, N) (imap_free(m), imap_init_(&(m)->mb, (void **)&(m)->v, sizeof*(m)->v, (N))) -#define imap_clear(m) ((m)->mb.bs ? bszero((m)->mb.bs, BSSIZE((m)->mb.N)) : (void)0, \ - (m)->mb.n = 0) -#define imap_get(m, k) ((m)->tmp = imap_get_(&(m)->mb, k), (m)->tmp < 0 ? NULL : &(m)->v[(m)->tmp]) -#define imap_set(m, k, ...) ((m)->tmp = imap_set_(&(m)->mb, (void **)&(m)->v, sizeof*(m)->v, k), \ - (m)->v[(m)->tmp] = (__VA_ARGS__), &(m)->v[(m)->tmp]) -#define imap_each(m,kx,pvx) \ - for (int _i = 0; _i < (m)->mb.N && ((kx) = (m)->mb.k[_i], (pvx) = &(m)->v[_i], 1); ++_i) \ - if (bstest((m)->mb.bs, _i)) -#define imap_copy(dst,src) do { \ - size_t N = (src)->mb.N; \ - if (!N) break; \ - (dst)->mb.n = (src)->mb.n; \ - imap_init((dst), N); \ - memcpy((dst)->mb.k, (src)->mb.k, \ - N*(sizeof*(src)->mb.k + sizeof*(src)->v) + BSSIZE(N)*sizeof(struct bitset)); \ -} while (0) - - -/** map of non-null ptr -> T **/ -#define pmap_of(T) struct { T *v; int tmp; struct pmapbase mb; } -struct pmapbase { void **k; uint n, N; }; - -void pmap_init_(struct pmapbase *, void **v, uint vsiz, uint N); -int pmap_get_(struct pmapbase *, const void *k); -int pmap_set_(struct pmapbase *, void **v, uint vsiz, const void *k); -void pmap_del_(struct pmapbase *, const void *k); -extern char pmap_tombstone_[]; -#define pmap_free(m) (free((m)->mb.k), memset((m), 0, sizeof *(m))) -#define pmap_init(m, N) (pmap_free(m), pmap_init_(&(m)->mb, (void **)&(m)->v, sizeof*(m)->v, (N))) -#define pmap_get(m, k) (((m)->tmp = pmap_get_(&(m)->mb, k)) < 0 ? NULL : &(m)->v[(m)->tmp]) -#define pmap_set(m, k, x) ((m)->tmp = pmap_set_(&(m)->mb, (void **)&(m)->v, sizeof*(m)->v, k), \ - (m)->v[(m)->tmp] = (x)) -#define pmap_del(m, k) pmap_del_(&(m)->mb, k) -#define pmap_each(m,kx,pvx) \ - for (size_t _i = 0; _i < (m)->mb.N && ((kx) = (m)->mb.k[_i], (pvx) = &(m)->v[_i], 1); ++_i) \ - if (kx && kx != pmap_tombstone_) - -/** bitset **/ -struct bitset { size_t u; }; -enum { BSNBIT = 8 * sizeof(struct bitset) }; -#define BSSIZE(nbit) ((nbit)/BSNBIT + ((nbit)%BSNBIT != 0)) - -static inline bool -bstest(const struct bitset *bs, uint i) -{ - return bs[i/BSNBIT].u >> i%BSNBIT & 1; -} - -static inline void -bsset(struct bitset *bs, uint i) -{ - bs[i/BSNBIT].u |= 1ull << i%BSNBIT; -} - -static inline void -bsclr(struct bitset *bs, uint i) -{ - bs[i/BSNBIT].u &= ~(1ull << i%BSNBIT); -} - -static inline void -bszero(struct bitset bs[/*siz*/], uint siz) -{ - memset(bs, 0, siz * sizeof *bs); -} - -static inline void -bscopy(struct bitset dst[/*siz*/], const struct bitset src[/*siz*/], uint siz) -{ - while (siz--) dst++->u = src++->u; -} - -static inline void -bsunion(struct bitset dst[/*siz*/], const struct bitset src[/*siz*/], uint siz) -{ - while (siz--) dst++->u |= src++->u; -} - -static inline uint -bscount(struct bitset bs[/*siz*/], uint siz) -{ - uint n = 0; - while (siz--) n += popcnt(bs++->u); - return n; -} - -static inline bool -bsiter(uint *i, struct bitset bs[/*siz*/], uint siz) -{ - uint k = *i/BSNBIT, j = *i%BSNBIT; - if (k >= siz) return 0; - size_t t = bs[k].u & ~(((size_t)1 << j) - 1); - while (!t) { - if (++k >= siz) return 0; - t = bs[k].u; - } - *i = k*BSNBIT + lowestsetbit(t); - return 1; -} -#define bs_each(T, var, bs, siz) for (T (var) = 0; bsiter(&(var), (bs), (siz)); ++(var)) - -static inline bool -bsiterzr(uint *i, struct bitset bs[/*siz*/], uint siz) -{ - uint k = *i/BSNBIT, j = *i%BSNBIT; - if (k >= siz) return 0; - size_t t = ~bs[k].u & ~(((size_t)1 << j) - 1); - while (!t) { - if (++k >= siz) return 0; - t = ~bs[k].u; - } - *i = k*BSNBIT + lowestsetbit(t); - return 1; -} - -/********/ -/** IO **/ -/********/ - -struct wbuf { - union { - struct { - char *buf; - uint cap; - uint len; - int fd; - }; - void *fp; - }; - bool err; - bool isfp; -}; - -/* read-only file mapping that is at least 1 page larger than the real file - * so it's legal to read a few bytes beyond it to avoid some bounds checks */ -struct memfile { - const uchar *p; - uint n; - bool statik; -}; - -struct embedfile { - const char *name; - const char *s; - size_t len; -}; - -#define MEMBUF(buf_, cap_) { .buf = (buf_), .cap = (cap_), .fd = -1 } -#define FDBUF(buf_, cap_, fd_) { .buf = (buf_), .cap = (cap_), .fd = (fd_) } -extern struct wbuf bstdout, bstderr; -void ioinit(void); -void iowrite(struct wbuf *, const void *src, int n); -void ioputc(struct wbuf *, uchar); -void ioflush(struct wbuf *); -int vbfmt(struct wbuf *, const char *, va_list ap); -int bfmt(struct wbuf *, const char *, ...); -#define pfmt(...) bfmt(&bstdout, __VA_ARGS__) -#define efmt(...) bfmt(&bstderr, __VA_ARGS__) -struct memfile mapopen(const char **err, const char *path); -void mapclose(struct memfile *); -void *mapzeros(uint); -int munmap(void *, size_t); -int getpredeffile(struct memfile **, const char *name); -int openfile(const char **err, struct memfile **, const char *path); -const char *getfilename(int id, uint atoff); -struct memfile *getfile(int id); -void addfileline(int id, uint off); -void setfileline(int id, uint off, int line, const char *file); -const char *getfilepos(int *line, int *col, int id, uint off); -bool isoncefile(int id, internstr *guard); -void markfileonce(int id, internstr guard); -void markfileseen(int id); -bool isfileseen(int id); -void closefile(int id); - -enum diagkind { DGERROR, DGWARN, DGNOTE, }; -void vdiag(const struct span *, enum diagkind, const char *, va_list); -NORETURN void fatal(const struct span *, const char *, ...); -void error(const struct span *, const char *, ...); -void warn(const struct span *, const char *, ...); -void note(const struct span *, const char *, ...); -ushort *utf8to16(uint *ulen, struct arena **, const uchar *s, size_t len); -uint *utf8to32(uint *ulen, struct arena **, const uchar *s, size_t len); -int utf8enc(char out[4], uint cp); - -#endif /* COMMON_H_ */ - -/* vim:set ts=3 sw=3 expandtab: */ diff --git a/src/a_embedfilesdir.c b/src/a_embedfilesdir.c new file mode 100644 index 0000000..d1c8dd4 --- /dev/null +++ b/src/a_embedfilesdir.c @@ -0,0 +1,106 @@ +#include + +struct embedfile { + const char *name; + const char *s; + size_t len; +}; + +#define S(s) s"\0\0\0\0\0", (sizeof s) - 1 + +struct embedfile embedfilesdir[] = { +{"stddef.h", S("\ +#pragma once\n\ +typedef __typeof__((char*)0 - (char*)0) ptrdiff_t;\n\ +typedef __typeof__(sizeof 0) size_t;\n\ +typedef __typeof__(L'a') wchar_t;\n\ +#undef NULL\n\ +#define NULL ((void *)0)\n\ +#undef offsetof\n\ +#define offsetof(type, memb) ((size_t)((char *)&((type *)0)->memb - (char *)0))\n\ +")}, + +{"stdarg.h", S("\ +#pragma once\n\ +typedef __builtin_va_list va_list;\n\ +#ifndef __GNUC_VA_LIST\n\ +#define __GNUC_VA_LIST\n\ +typedef __builtin_va_list __gnuc_va_list;\n\ +#endif\n\ +#define va_start(ap,n) __builtin_va_start(ap)\n\ +#define va_arg(ap,type) __builtin_va_arg(ap, type)\n\ +#define va_copy(dst,src) __builtin_va_copy(dst, src)\n\ +#define va_end(ap) __builtin_va_end(ap)\n\ +")}, + +{"stdbool.h", S("\ +#pragma once\n\ +#if __STDC_VERSION__ < 202311L /* in C23 they are keywords */\n\ +#define bool _Bool \n\ +#define true 1\n\ +#define false 0\n\ +#endif\n\ +#define __bool_true_false_are_defined 1\n\ +")}, + +{"float.h", S("\ +#pragma once\n\ +#define FLT_ROUNDS (-1)\n\ +#define FLT_EVAL_METHOD (-1)\n\ +#define FLT_HAS_SUBNORM (-1)\n\ +#define DBL_HAS_SUBNORM (-1)\n\ +#define LDBL_HAS_SUBNORM (-1)\n\ +#define FLT_RADIX 2\n\ +#define FLT_MANT_DIG 24\n\ +#define DBL_MANT_DIG 53\n\ +#define LDBL_MANT_DIG 53\n\ +#define FLT_DECIMAL_DIG 9\n\ +#define DBL_DECIMAL_DIG 17\n\ +#define LDBL_DECIMAL_DIG 17\n\ +#define DECIMAL_DIG 17\n\ +#define FLT_DIG 6\n\ +#define DBL_DIG 15\n\ +#define LDBL_DIG 15\n\ +#define FLT_MIN_EXP (-125)\n\ +#define DBL_MIN_EXP (-1021)\n\ +#define LDBL_MIN_EXP (-1021)\n\ +#define FLT_MIN_10_EXP (-37)\n\ +#define DBL_MIN_10_EXP (-307)\n\ +#define LDBL_MIN_10_EXP (-307)\n\ +#define FLT_MAX_EXP 128\n\ +#define DBL_MAX_EXP 1024\n\ +#define LDBL_MAX_EXP 1024\n\ +#define FLT_MAX_10_EXP 38\n\ +#define DBL_MAX_10_EXP 308\n\ +#define LDBL_MAX_10_EXP 308\n\ +#define FLT_MAX 3.40282e+38\n\ +#define DBL_MAX 1.79769e+308\n\ +#define LDBL_MAX 1.79769e+308\n\ +#define FLT_EPSILON 1.19209e-07\n\ +#define DBL_EPSILON 2.22045e-16\n\ +#define LDBL_EPSILON 2.22045e-16\n\ +#define FLT_MIN 1.17549e-38\n\ +#define DBL_MIN 2.22507e-308\n\ +#define LDBL_MIN 2.22507e-308\n\ +#define FLT_TRUE_MIN 1.4013e-45\n\ +#define DBL_TRUE_MIN 4.94066e-324\n\ +#define LDBL_TRUE_MIN 4.94066e-324\n\ +")}, + +{"stdnoreturn.h", S("\ +#define noreturn _Noreturn\n\ +")}, + +{"stdalign.h", S("\ +#if __STDC_VERSION__ < 202311L\n\ +#define alignas _Alignas\n\ +#define alignof _Alignof\n\ +#define __alignas_is_defined 1\n\ +#define __alignof_is_defined 1\n\ +#endif\n\ +")}, + + {NULL} +}; + +/* vim:set ts=3 sw=3 expandtab: */ diff --git a/src/a_main.c b/src/a_main.c index 9710814..303d513 100644 --- a/src/a_main.c +++ b/src/a_main.c @@ -1,7 +1,7 @@ -#include "common.h" +#include "antcc.h" #include "version.h" #include "hostconfig.h" /* run ./configure */ -#include "obj/obj.h" +#include "obj.h" #include #include #include diff --git a/src/a_targ.c b/src/a_targ.c index fdc11f8..0a14554 100644 --- a/src/a_targ.c +++ b/src/a_targ.c @@ -1,5 +1,5 @@ -#include "common.h" -#include "type.h" +#include "antcc.h" +#include "c_type.h" extern const struct mctarg t_x86_64_sysv, t_aarch64_aapcs; static const struct targ { diff --git a/src/antcc.h b/src/antcc.h new file mode 100644 index 0000000..a24aa3d --- /dev/null +++ b/src/antcc.h @@ -0,0 +1,465 @@ +#ifndef COMMON_H_ +#define COMMON_H_ + +#include +#include +#include + +#ifdef __clang__ /* stop linter from complaining about "unused" inline functions */ +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#define bool _Bool +typedef unsigned char uchar; +typedef signed char schar; +typedef unsigned short ushort; +typedef unsigned long long uvlong; +typedef signed long long vlong; +typedef unsigned uint; + +#if __STDC_VERSION__ >= 202311L +#define NORETURN [[noreturn]] +#elif __STDC_VERSION__ >= 201112L +#define NORETURN _Noreturn +#else +#define NORETURN +#endif + +#ifdef __has_builtin +#define HAS_BUILTIN(b) __has_builtin(__builtin_##b) +#else +#define HAS_BUILTIN(_) 0 +#endif + +#define static_assert(x) _Static_assert(x, #x) +#define in_range(x, Lo, Hi) ((uint) (x) - (Lo) <= (Hi) - (Lo)) /* lo <= x <= hi; lo > 0, hi > 0 */ +#define alignup(x, A) (((x) + ((A) - 1)) & -(A)) +#define countof(a) (sizeof(a) / sizeof 0[a]) + +enum { SPANFILEBITS = 10 }; +struct span { + struct span0 { + uint off; + uint len : 32-SPANFILEBITS, + file : SPANFILEBITS; + } sl, /* original source location */ + ex; /* the location after #include/macro expansion */ +}; + +void _assertfmt(const char *file, int line, const char *func, const char *expr); +#if HAS_BUILTIN(trap) +#define assert(x) (!(x) ? _assertfmt(__FILE__,__LINE__,__func__,#x), __builtin_trap() : (void)0) +#else +#define assert(x) (void)(!(x) ? _assertfmt(__FILE__,__LINE__,__func__,#x), *(volatile int *)0 : 0) +#endif + +static inline size_t +hashs(size_t h, const char *s) +{ + while (*s) h = (uchar)*s++ + h*65599; + return h; +} +static inline size_t +hashb(size_t h, const void *d, size_t n) +{ + const uchar *b = d; + while (n--) h = *b++ + h*65599; + return h; +} +static inline size_t +ptrhash(const void *p) { + return (size_t)p * 2654435761u; +} +static inline uint +popcnt(uvlong x) { +#if HAS_BUILTIN(popcountll) + return x ? __builtin_popcountll(x) : 0; +#else + uint n = 0; + while (x) n += x&1, x >>= 1; + return n; +#endif +} +static inline bool +ispo2(uvlong x) { + return (x != 0) & ((x & (x - 1)) == 0); +} +static inline uint +ilog2(uvlong x) { /* assumes x is a power of 2 */ +#if HAS_BUILTIN(ctzll) + return __builtin_ctzll(x); +#else + uint n = 0; + while (x >>= 1) ++n; + return n; +#endif +} +static inline uint +lowestsetbit(uvlong x) +{ +#if HAS_BUILTIN(ctzll) + return __builtin_ctzll(x); +#else + int i = 0; + for (uvlong mask = 1;; ++i, mask <<= 1) + if (x & mask) + break; + return i; +#endif +} + +#define aisprint(c) in_range(c, ' ', '~') +#define aisdigit(c) in_range(c, '0', '9') +#define aisodigit(c) in_range(c, '0', '7') +#define aisalpha(c) in_range((c)|0x20, 'a', 'z') +static inline bool aisspace(int c) { return c == ' ' || in_range(c, '\t', '\r'); } +static inline bool aisxdigit(int c) { return aisdigit(c) || in_range(c|0x20, 'a', 'f'); } + +/******************/ +/* COMPILER STATE */ +/******************/ + +enum cstd { + STDC89, + STDC99, + STDC11, + STDC23, +}; +struct option { + enum cstd cstd; + bool pedant; + bool trigraph; + bool nocolor; + bool pie, pic; + bool werror; + bool wnone; + enum optz { + OPT0 = -1, + OPT1 = 1, + OPT2 = 2, + } o; + union { + struct { + bool p : 1, /* after parsing */ + a : 1, /* after abi0 */ + m : 1, /* after mem */ + y : 1, /* after inline */ + o : 1, /* after optimizations */ + s : 1, /* after stack */ + i : 1, /* after isel */ + l : 1, /* after liveness fixup */ + r : 1; /* after regalloc */ + }; + uint any; + } dbg; + struct wbuf *dbgout; +}; +extern struct option ccopt; +extern struct cinclpaths { + struct inclpath { + struct inclpath *next; + const char *path; + } *list, **tail; +} cinclpaths[5]; +enum { /* GCC include directory search order: https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html#Options-for-Directory-Search */ + CINCL_iquote, + CINCL_I, + CINCL_isystem, + CINCLsys, + CINCL_idirafter, +}; + +/**********/ +/* Target */ +/**********/ + +struct targtriple { + enum mcarch { ISxxx, ISx86_64, ISaarch64 } arch; + enum mcos { OSunknown, OSlinux } os; + enum mcabi { ABInone, ABIgnu, ABImusl } abi; +}; +extern const struct mctarg *mctarg; +extern struct targtriple target; +void targ_init(const char *); + +/*********/ +/** MEM **/ +/*********/ + +/* libc *alloc wrappers */ +void *xmalloc(size_t n, const char *); +void *xcalloc(size_t n, const char *); +void *xrealloc(void *, size_t n, const char *); +void free(void *); +#define xmalloc(n) xmalloc(n, __func__) +#define xcalloc(n) xcalloc(n, __func__) +#define xrealloc(p,n) xrealloc(p, n, __func__) + +/* string interning */ +typedef const struct internstr {char c;} *internstr; +internstr intern_(const char *, uint len); +#define intern(s) intern_(s, 0) + +/* growable buffer that stores its capacity in the allocated memory */ +#define xbnew_(n) (void *)(1 + (size_t *)xcalloc(sizeof(size_t) + (n))) +#define xbcap_(p) ((size_t *)(p))[-1] +static inline void +xbgrow_(void **p, size_t n) +{ + if (!n) return; + if (!*p) { *p = xbnew_(n); xbcap_(*p) = n; assert(n>0); } + else if (xbcap_(*p) < n) { + size_t k = xbcap_(*p); + assert(k > 0); + do k *= 2; while (k < n); + *p = 1 + (size_t *)xrealloc(&xbcap_(*(p)), sizeof(size_t) + k); + xbcap_(*p) = k; + }; +} +#define xbgrow(p, n) xbgrow_((void **)(p), (n) * sizeof**(p)) +#define xbpush(p, n, x) (xbgrow(p, (*(n) + 1)), (*(p))[(*(n))++] = (x)) +#define xbfree(p) ((p) ? free(&xbcap_(p)) : (void)0) +#define xbcap(p) ((p) ? xbcap_(p) / sizeof*(p) : 0) +#define xbgrowz(p, n) do { \ + size_t tmp = *(p) ? xbcap_(*(p)) : 0; \ + xbgrow(p, n); \ + memset((char*)*(p)+tmp, 0, xbcap_(*(p))-tmp); \ +} while (0) + + +/** arenas **/ +struct arena { + uint cap : 31, + dyn : 1; + uint n; + struct arena *prev; + uchar mem[]; +}; + +extern struct arena *globarena; + +struct arena *newarena(uint chunksiz); +void *alloc(struct arena **, uint siz, uint align); +void *allocz(struct arena **, uint siz, uint align); +static inline void * +alloccopy(struct arena **arena, const void *src, uint siz, uint align) +{ + if (!siz) return NULL; + return memcpy(alloc(arena, siz, align), src, siz); +} +void freearena(struct arena **); + +/** vec **/ +struct vecbase { void *p; uint n; uint cap : 31, dyn : 1; }; +#define vec_of(T) union { \ + struct { T *p; uint n; }; \ + struct vecbase _vb; \ +} +void vinit_(struct vecbase *, void *inlbuf, uint cap, uint siz); +void vpush_(struct vecbase *, uint siz); +void *vpushn_(struct vecbase *, uint siz, const void *dat, uint ndat); +void vresize_(struct vecbase *, uint siz, uint N); +#define VINIT(inlbuf, Cap) { ._vb.p = (inlbuf), ._vb.cap = (Cap) } +#define vfree(v) ((v)->_vb.dyn ? free((v)->p) : (void)0, memset((v), 0, sizeof*(v))) +#define vinit(v, inlbuf, Cap) (vfree(v), vinit_(&(v)->_vb, inlbuf, (Cap), sizeof *(v)->p)) +#define vpush(v, x) (vpush_(&(v)->_vb, sizeof *(v)->p), (v)->p[(v)->n++] = (x)) +#define vpushn(v, xs, N) vpushn_(&(v)->_vb, sizeof *(v)->p, xs, N) +#define vresize(v, N) vresize_(&(v)->_vb, sizeof *(v)->p, N) + +/** map of short -> T **/ +#define imap_of(T) struct { T *v; int tmp; struct imapbase mb; } +struct imapbase { short *k; struct bitset *bs; uint n, N; }; + +void imap_init_(struct imapbase *, void **v, uint vsiz, uint N); +int imap_get_(struct imapbase *, short k); +int imap_set_(struct imapbase *, void **v, uint vsiz, short k); +#define imap_free(m) (free((m)->mb.k), memset((m), 0, sizeof *(m))) +#define imap_init(m, N) (imap_free(m), imap_init_(&(m)->mb, (void **)&(m)->v, sizeof*(m)->v, (N))) +#define imap_clear(m) ((m)->mb.bs ? bszero((m)->mb.bs, BSSIZE((m)->mb.N)) : (void)0, \ + (m)->mb.n = 0) +#define imap_get(m, k) ((m)->tmp = imap_get_(&(m)->mb, k), (m)->tmp < 0 ? NULL : &(m)->v[(m)->tmp]) +#define imap_set(m, k, ...) ((m)->tmp = imap_set_(&(m)->mb, (void **)&(m)->v, sizeof*(m)->v, k), \ + (m)->v[(m)->tmp] = (__VA_ARGS__), &(m)->v[(m)->tmp]) +#define imap_each(m,kx,pvx) \ + for (int _i = 0; _i < (m)->mb.N && ((kx) = (m)->mb.k[_i], (pvx) = &(m)->v[_i], 1); ++_i) \ + if (bstest((m)->mb.bs, _i)) +#define imap_copy(dst,src) do { \ + size_t N = (src)->mb.N; \ + if (!N) break; \ + (dst)->mb.n = (src)->mb.n; \ + imap_init((dst), N); \ + memcpy((dst)->mb.k, (src)->mb.k, \ + N*(sizeof*(src)->mb.k + sizeof*(src)->v) + BSSIZE(N)*sizeof(struct bitset)); \ +} while (0) + + +/** map of non-null ptr -> T **/ +#define pmap_of(T) struct { T *v; int tmp; struct pmapbase mb; } +struct pmapbase { void **k; uint n, N; }; + +void pmap_init_(struct pmapbase *, void **v, uint vsiz, uint N); +int pmap_get_(struct pmapbase *, const void *k); +int pmap_set_(struct pmapbase *, void **v, uint vsiz, const void *k); +void pmap_del_(struct pmapbase *, const void *k); +extern char pmap_tombstone_[]; +#define pmap_free(m) (free((m)->mb.k), memset((m), 0, sizeof *(m))) +#define pmap_init(m, N) (pmap_free(m), pmap_init_(&(m)->mb, (void **)&(m)->v, sizeof*(m)->v, (N))) +#define pmap_get(m, k) (((m)->tmp = pmap_get_(&(m)->mb, k)) < 0 ? NULL : &(m)->v[(m)->tmp]) +#define pmap_set(m, k, x) ((m)->tmp = pmap_set_(&(m)->mb, (void **)&(m)->v, sizeof*(m)->v, k), \ + (m)->v[(m)->tmp] = (x)) +#define pmap_del(m, k) pmap_del_(&(m)->mb, k) +#define pmap_each(m,kx,pvx) \ + for (size_t _i = 0; _i < (m)->mb.N && ((kx) = (m)->mb.k[_i], (pvx) = &(m)->v[_i], 1); ++_i) \ + if (kx && kx != pmap_tombstone_) + +/** bitset **/ +struct bitset { size_t u; }; +enum { BSNBIT = 8 * sizeof(struct bitset) }; +#define BSSIZE(nbit) ((nbit)/BSNBIT + ((nbit)%BSNBIT != 0)) + +static inline bool +bstest(const struct bitset *bs, uint i) +{ + return bs[i/BSNBIT].u >> i%BSNBIT & 1; +} + +static inline void +bsset(struct bitset *bs, uint i) +{ + bs[i/BSNBIT].u |= 1ull << i%BSNBIT; +} + +static inline void +bsclr(struct bitset *bs, uint i) +{ + bs[i/BSNBIT].u &= ~(1ull << i%BSNBIT); +} + +static inline void +bszero(struct bitset bs[/*siz*/], uint siz) +{ + memset(bs, 0, siz * sizeof *bs); +} + +static inline void +bscopy(struct bitset dst[/*siz*/], const struct bitset src[/*siz*/], uint siz) +{ + while (siz--) dst++->u = src++->u; +} + +static inline void +bsunion(struct bitset dst[/*siz*/], const struct bitset src[/*siz*/], uint siz) +{ + while (siz--) dst++->u |= src++->u; +} + +static inline uint +bscount(struct bitset bs[/*siz*/], uint siz) +{ + uint n = 0; + while (siz--) n += popcnt(bs++->u); + return n; +} + +static inline bool +bsiter(uint *i, struct bitset bs[/*siz*/], uint siz) +{ + uint k = *i/BSNBIT, j = *i%BSNBIT; + if (k >= siz) return 0; + size_t t = bs[k].u & ~(((size_t)1 << j) - 1); + while (!t) { + if (++k >= siz) return 0; + t = bs[k].u; + } + *i = k*BSNBIT + lowestsetbit(t); + return 1; +} +#define bs_each(T, var, bs, siz) for (T (var) = 0; bsiter(&(var), (bs), (siz)); ++(var)) + +static inline bool +bsiterzr(uint *i, struct bitset bs[/*siz*/], uint siz) +{ + uint k = *i/BSNBIT, j = *i%BSNBIT; + if (k >= siz) return 0; + size_t t = ~bs[k].u & ~(((size_t)1 << j) - 1); + while (!t) { + if (++k >= siz) return 0; + t = ~bs[k].u; + } + *i = k*BSNBIT + lowestsetbit(t); + return 1; +} + +/********/ +/** IO **/ +/********/ + +struct wbuf { + union { + struct { + char *buf; + uint cap; + uint len; + int fd; + }; + void *fp; + }; + bool err; + bool isfp; +}; + +/* read-only file mapping that is at least 1 page larger than the real file + * so it's legal to read a few bytes beyond it to avoid some bounds checks */ +struct memfile { + const uchar *p; + uint n; + bool statik; +}; + +struct embedfile { + const char *name; + const char *s; + size_t len; +}; + +#define MEMBUF(buf_, cap_) { .buf = (buf_), .cap = (cap_), .fd = -1 } +#define FDBUF(buf_, cap_, fd_) { .buf = (buf_), .cap = (cap_), .fd = (fd_) } +extern struct wbuf bstdout, bstderr; +void ioinit(void); +void iowrite(struct wbuf *, const void *src, int n); +void ioputc(struct wbuf *, uchar); +void ioflush(struct wbuf *); +int vbfmt(struct wbuf *, const char *, va_list ap); +int bfmt(struct wbuf *, const char *, ...); +#define pfmt(...) bfmt(&bstdout, __VA_ARGS__) +#define efmt(...) bfmt(&bstderr, __VA_ARGS__) +struct memfile mapopen(const char **err, const char *path); +void mapclose(struct memfile *); +void *mapzeros(uint); +int munmap(void *, size_t); +int getpredeffile(struct memfile **, const char *name); +int openfile(const char **err, struct memfile **, const char *path); +const char *getfilename(int id, uint atoff); +struct memfile *getfile(int id); +void addfileline(int id, uint off); +void setfileline(int id, uint off, int line, const char *file); +const char *getfilepos(int *line, int *col, int id, uint off); +bool isoncefile(int id, internstr *guard); +void markfileonce(int id, internstr guard); +void markfileseen(int id); +bool isfileseen(int id); +void closefile(int id); + +enum diagkind { DGERROR, DGWARN, DGNOTE, }; +void vdiag(const struct span *, enum diagkind, const char *, va_list); +NORETURN void fatal(const struct span *, const char *, ...); +void error(const struct span *, const char *, ...); +void warn(const struct span *, const char *, ...); +void note(const struct span *, const char *, ...); +ushort *utf8to16(uint *ulen, struct arena **, const uchar *s, size_t len); +uint *utf8to32(uint *ulen, struct arena **, const uchar *s, size_t len); +int utf8enc(char out[4], uint cp); + +#endif /* COMMON_H_ */ + +/* vim:set ts=3 sw=3 expandtab: */ diff --git a/src/c.c b/src/c.c index 63c3f7f..80ddc74 100644 --- a/src/c.c +++ b/src/c.c @@ -1,8 +1,8 @@ #include "c.h" -#include "lex.h" -#include "../endian.h" -#include "../ir/ir.h" -#include "../obj/obj.h" +#include "c_lex.h" +#include "u_endian.h" +#include "ir.h" +#include "obj.h" /** Parsing helper functions **/ #define peek(Cm,Tk) lexpeek((Cm)->lx,Tk) diff --git a/src/c.h b/src/c.h index 0214db5..50d09ed 100644 --- a/src/c.h +++ b/src/c.h @@ -1,5 +1,5 @@ -#include "../common.h" -#include "../type.h" +#include "antcc.h" +#include "c_type.h" /*************/ /* EXPR TREE */ diff --git a/src/c_builtin.c b/src/c_builtin.c index 5c59857..ddcfa82 100644 --- a/src/c_builtin.c +++ b/src/c_builtin.c @@ -1,5 +1,5 @@ #include "c.h" -#include "../ir/ir.h" +#include "ir.h" static bool callcheck(const struct span *span, int nparam, const union type *param, int narg, struct expr *args) diff --git a/src/c_embedfilesdir.c b/src/c_embedfilesdir.c deleted file mode 100644 index d1c8dd4..0000000 --- a/src/c_embedfilesdir.c +++ /dev/null @@ -1,106 +0,0 @@ -#include - -struct embedfile { - const char *name; - const char *s; - size_t len; -}; - -#define S(s) s"\0\0\0\0\0", (sizeof s) - 1 - -struct embedfile embedfilesdir[] = { -{"stddef.h", S("\ -#pragma once\n\ -typedef __typeof__((char*)0 - (char*)0) ptrdiff_t;\n\ -typedef __typeof__(sizeof 0) size_t;\n\ -typedef __typeof__(L'a') wchar_t;\n\ -#undef NULL\n\ -#define NULL ((void *)0)\n\ -#undef offsetof\n\ -#define offsetof(type, memb) ((size_t)((char *)&((type *)0)->memb - (char *)0))\n\ -")}, - -{"stdarg.h", S("\ -#pragma once\n\ -typedef __builtin_va_list va_list;\n\ -#ifndef __GNUC_VA_LIST\n\ -#define __GNUC_VA_LIST\n\ -typedef __builtin_va_list __gnuc_va_list;\n\ -#endif\n\ -#define va_start(ap,n) __builtin_va_start(ap)\n\ -#define va_arg(ap,type) __builtin_va_arg(ap, type)\n\ -#define va_copy(dst,src) __builtin_va_copy(dst, src)\n\ -#define va_end(ap) __builtin_va_end(ap)\n\ -")}, - -{"stdbool.h", S("\ -#pragma once\n\ -#if __STDC_VERSION__ < 202311L /* in C23 they are keywords */\n\ -#define bool _Bool \n\ -#define true 1\n\ -#define false 0\n\ -#endif\n\ -#define __bool_true_false_are_defined 1\n\ -")}, - -{"float.h", S("\ -#pragma once\n\ -#define FLT_ROUNDS (-1)\n\ -#define FLT_EVAL_METHOD (-1)\n\ -#define FLT_HAS_SUBNORM (-1)\n\ -#define DBL_HAS_SUBNORM (-1)\n\ -#define LDBL_HAS_SUBNORM (-1)\n\ -#define FLT_RADIX 2\n\ -#define FLT_MANT_DIG 24\n\ -#define DBL_MANT_DIG 53\n\ -#define LDBL_MANT_DIG 53\n\ -#define FLT_DECIMAL_DIG 9\n\ -#define DBL_DECIMAL_DIG 17\n\ -#define LDBL_DECIMAL_DIG 17\n\ -#define DECIMAL_DIG 17\n\ -#define FLT_DIG 6\n\ -#define DBL_DIG 15\n\ -#define LDBL_DIG 15\n\ -#define FLT_MIN_EXP (-125)\n\ -#define DBL_MIN_EXP (-1021)\n\ -#define LDBL_MIN_EXP (-1021)\n\ -#define FLT_MIN_10_EXP (-37)\n\ -#define DBL_MIN_10_EXP (-307)\n\ -#define LDBL_MIN_10_EXP (-307)\n\ -#define FLT_MAX_EXP 128\n\ -#define DBL_MAX_EXP 1024\n\ -#define LDBL_MAX_EXP 1024\n\ -#define FLT_MAX_10_EXP 38\n\ -#define DBL_MAX_10_EXP 308\n\ -#define LDBL_MAX_10_EXP 308\n\ -#define FLT_MAX 3.40282e+38\n\ -#define DBL_MAX 1.79769e+308\n\ -#define LDBL_MAX 1.79769e+308\n\ -#define FLT_EPSILON 1.19209e-07\n\ -#define DBL_EPSILON 2.22045e-16\n\ -#define LDBL_EPSILON 2.22045e-16\n\ -#define FLT_MIN 1.17549e-38\n\ -#define DBL_MIN 2.22507e-308\n\ -#define LDBL_MIN 2.22507e-308\n\ -#define FLT_TRUE_MIN 1.4013e-45\n\ -#define DBL_TRUE_MIN 4.94066e-324\n\ -#define LDBL_TRUE_MIN 4.94066e-324\n\ -")}, - -{"stdnoreturn.h", S("\ -#define noreturn _Noreturn\n\ -")}, - -{"stdalign.h", S("\ -#if __STDC_VERSION__ < 202311L\n\ -#define alignas _Alignas\n\ -#define alignof _Alignof\n\ -#define __alignas_is_defined 1\n\ -#define __alignof_is_defined 1\n\ -#endif\n\ -")}, - - {NULL} -}; - -/* vim:set ts=3 sw=3 expandtab: */ diff --git a/src/c_eval.c b/src/c_eval.c index 3dfbbfb..ad5cf40 100644 --- a/src/c_eval.c +++ b/src/c_eval.c @@ -1,5 +1,5 @@ #include "c.h" -#include "../ir/ir.h" +#include "ir.h" #include static int diff --git a/src/c_lex.c b/src/c_lex.c index c196a21..d3529c0 100644 --- a/src/c_lex.c +++ b/src/c_lex.c @@ -1,5 +1,5 @@ -#include "lex.h" -#include "../version.h" +#include "c_lex.h" +#include "version.h" #include #include @@ -2040,7 +2040,7 @@ identkeyword(struct token *tk) const char *alias[2]; } kwtab[] = { #define _(kw, cstd, ...) { #kw, {TKW##kw, cstd}, __VA_ARGS__ }, -#include "keywords.def" +#include "c_keywords.def" #undef _ }; #ifdef __GNUC__ diff --git a/src/c_lex.h b/src/c_lex.h index e70bc78..8797ded 100644 --- a/src/c_lex.h +++ b/src/c_lex.h @@ -1,5 +1,5 @@ -#include "../common.h" -#include "../type.h" +#include "antcc.h" +#include "c_type.h" static inline bool joinspan(struct span0 *dst, struct span0 snd) @@ -45,7 +45,7 @@ enum toktag { /* single-character tokens' tag value is the character itself */ TKSETSHR, /* >>= */ TKIDENT = 0x80, #define _(kw, stdc, ...) TKW##kw, -#include "keywords.def" +#include "c_keywords.def" #undef _ NTOKTAG, }; diff --git a/src/c_type.c b/src/c_type.c index e8a5b1e..59d890b 100644 --- a/src/c_type.c +++ b/src/c_type.c @@ -1,4 +1,4 @@ -#include "type.h" +#include "c_type.h" struct typedata typedata[1<<13]; internstr ttypenames[1<<10]; diff --git a/src/c_type.h b/src/c_type.h index ad8e1b1..12f24b2 100644 --- a/src/c_type.h +++ b/src/c_type.h @@ -1,6 +1,6 @@ #ifndef TYPE_H_ #define TYPE_H_ -#include "common.h" +#include "antcc.h" enum qualifier { QCONST = 1<<0, diff --git a/src/io.c b/src/io.c deleted file mode 100644 index d33afb1..0000000 --- a/src/io.c +++ /dev/null @@ -1,1255 +0,0 @@ -#include "c/lex.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct wbuf bstdout, bstderr; - -void -ioinit(void) -{ - bstdout.fp = stdout; - bstdout.isfp = 1; - bstderr.fp = stderr; - bstderr.isfp = 1; -} - -void -iowrite(struct wbuf *buf, const void *Src, int n) -{ - const uchar *src = Src; - - if (buf->isfp) { - fwrite(Src, 1, n, buf->fp); - buf->err = ferror(buf->fp) != 0; - return; - } - while (n > 0) { - int avail = buf->cap - buf->len; - int amt = avail < n ? avail : n; - - memcpy(buf->buf + buf->len, src, amt); - n -= amt; - src += amt; - buf->len += amt; - if (n > 0 && buf->len == buf->cap) { - if (buf->fd < 0) { - buf->err = 1; - return; - } - ioflush(buf); - } - } -} - -void -ioflush(struct wbuf *buf) -{ - int i, ret; - - if (buf->isfp) { - fflush(buf->fp); - buf->err = ferror(buf->fp) != 0; - return; - } - buf->err = 0; - if (buf->fd < 0) { - buf->len = 0; - return; - } - for (i = 0; buf->len > 0;) { - ret = write(buf->fd, buf->buf + i, buf->len); - if (ret > 0) { - assert(ret <= buf->len); - buf->len -= ret; - i += ret; - } else if (errno == EAGAIN || errno == EWOULDBLOCK) { - continue; - } else { - buf->err = 1; - break; - } - } -} - -void -ioputc(struct wbuf *buf, uchar c) -{ - if (buf->isfp) { - buf->err = fputc(c, buf->fp) != EOF; - return; - } - if (buf->len == buf->cap) { - if (buf->fd < 0) { - buf->err = 1; - return; - } - ioflush(buf); - } - buf->buf[buf->len++] = c; -} - -static int -putquoted(struct wbuf *buf, uchar c, uchar qchar, int next) -{ - if (c == qchar || c == '\\' || !aisprint(c)) { - int n = (ioputc(buf, '\\'), 1); - uchar cseq; - - switch (c) { - case '\\': - case '\'': - case '"': - cseq = c; - Charseq: - n += (ioputc(buf, cseq), 1); - break; - case '\a': cseq = 'a'; goto Charseq; - case '\b': cseq = 'b'; goto Charseq; - case '\f': cseq = 'f'; goto Charseq; - case '\r': cseq = 'r'; goto Charseq; - case '\t': cseq = 't'; goto Charseq; - case '\v': cseq = 'v'; goto Charseq; - case '\n': cseq = 'n'; goto Charseq; - default: - if (!next || in_range(next, '0', '7')) - n += bfmt(buf, "%.3o", c); - else - n += bfmt(buf, "%o", c); - } - return n; - } - if (c == '?' && (!next || next == '?')) { - return ioputc(buf, c), ioputc(buf, '\\'), 2; - } - return ioputc(buf, c), 1; -} - -static int -putuint(struct wbuf *buf, uvlong x, int base, bool lower) -{ - uchar tmp[64]; - uchar *end = tmp + sizeof(tmp); - uchar *s = end; - switch (base) { - case 2: - do *--s = '0' + x%2; while (x >>= 1); - break; - case 8: - do *--s = '0' + x%8; while (x >>= 3); - break; - case 10: - do *--s = '0' + x%10; while (x /= 10); - break; - case 16: - do *--s = "0123456789ABCDEF"[x&15] | (-lower & 0x20); while (x >>= 4); - break; - default: - assert(0&&"base"); - } - iowrite(buf, s, end - s); - return end - s; -} - -static void -fmterr(const char *fmt, ...) -{ - va_list ap; - - efmt("fmt Error: "); - va_start(ap, fmt); - vbfmt(&bstderr, fmt, ap); - va_end(ap); - ioputc(&bstderr, '\n'); - ioflush(&bstderr); - ioflush(&bstdout); - abort(); -} - -#define bwriteS(buf, S) (iowrite(buf, S, sizeof S - 1), sizeof S - 1) -#define bputc(B, C) (ioputc(B, C), 1) - -static int -priquals(struct wbuf *buf, int q) -{ - const char s[] = " const volatile", *p = s; - int m = sizeof s - 1; - if (!q) return 0; - else if (q == QCONST) m -= 9; - else if (q == QVOLATILE) p += 6, m -= 6; - else assert(q == (QCONST | QVOLATILE)); - iowrite(buf, p, m); - return m; -} -static int -pritypebefore(struct wbuf *buf, union type ty, int qual) -{ - const char *s, *s2; - union type chld; - int n; - switch (ty.t) { - case TYVOID: s = "void"; Prim: n = bfmt(buf, "%s", s); return n + priquals(buf, qual); - case TYBOOL: s = "bool"; goto Prim; - case TYCHAR: s = "char"; goto Prim; - case TYSCHAR: s = "signed char"; goto Prim; - case TYUCHAR: s = "unsigned char"; goto Prim; - case TYSHORT: s = "short"; goto Prim; - case TYUSHORT: s = "unsigned short"; goto Prim; - case TYINT: s = "int"; goto Prim; - case TYUINT: s = "unsigned int"; goto Prim; - case TYLONG: s = "long"; goto Prim; - case TYULONG: s = "unsigned long"; goto Prim; - case TYVLONG: s = "long long"; goto Prim; - case TYUVLONG: s = "unsigned long long"; goto Prim; - case TYFLOAT: s = "float"; goto Prim; - case TYDOUBLE: s = "double"; goto Prim; - case TYLDOUBLE:s = "long double"; goto Prim; - case TYCOMPLEXF:s = "float complex"; goto Prim; - case TYCOMPLEX: s = "double complex"; goto Prim; - case TYCOMPLEXL:s = "long double complex"; goto Prim; - case TYPTR: - chld = typechild(ty); - n = pritypebefore(buf, chld, ty.flag & TFCHLDQUAL); - if (!isptrcvtt(chld.t)) - n += bputc(buf, ' '); - if (chld.t == TYARRAY || chld.t == TYFUNC) - n += bputc(buf, '('); - n += bputc(buf, '*'); - n += priquals(buf, qual); - return n; - case TYARRAY: - return pritypebefore(buf, typechild(ty), ty.flag & TFCHLDQUAL); - case TYFUNC: - return pritypebefore(buf, typedata[ty.dat].ret, 0); - case TYSTRUCT: - s = "struct"; - Tagged: - n = bfmt(buf, "%s %s", s, (s2 = (char *)ttypenames[typedata[ty.dat].id]) ? s2 : "(anonymous)"); - return n + priquals(buf, qual); - case TYUNION: - s = "union"; - goto Tagged; - case TYENUM: - s = "enum"; - goto Tagged; - default: - return bfmt(buf, "?\?%d?",ty.t); - } -} - -static int -pritypeafter(struct wbuf *buf, union type ty, int qual) -{ - const struct typedata *td; - int n = 0; - switch (ty.t) { - case TYPTR: - if (typechild(ty).t == TYARRAY || typechild(ty).t == TYFUNC) - n += bputc(buf, ')'); - n += pritypeafter(buf, typechild(ty), ty.flag & TFCHLDQUAL); - break; - case TYARRAY: - n += bputc(buf, '['); - if (typearrlen(ty)) - n += bfmt(buf, "%u", typearrlen(ty)); - n += bputc(buf, ']'); - n += pritypeafter(buf, typechild(ty), ty.flag & TFCHLDQUAL); - break; - case TYFUNC: - td = &typedata[ty.dat]; - n += bputc(buf, '('); - for (int i = 0; i < td->nmemb; ++i) { - n += bfmt(buf, "%ty", td->param[i]); - if (i < td->nmemb - 1 || td->variadic) - n += bwriteS(buf, ", "); - } - if (td->variadic) n += bwriteS(buf, "..."); - else if (td->nmemb == 0 && !td->kandr) n += bwriteS(buf, "void"); - n += bwriteS(buf, ")"); - n += pritypeafter(buf, td->ret, 0); - break; - } - return n; -} - -static int -fmttype(struct wbuf *buf, union type ty, int qual) -{ - int n = pritypebefore(buf, ty, qual); - n += pritypeafter(buf, ty, qual); - return n; -} - -static int -putdouble(struct wbuf *buf, double x) -{ - char tmp[200]; - int n = snprintf(tmp, sizeof tmp, "%f", x); - if (n >= sizeof tmp-1) n = snprintf(tmp, sizeof tmp, "%g", x); - assert(n < sizeof tmp-1); - iowrite(buf, tmp, n); - return n; -} - -int -vbfmt(struct wbuf *out, const char *fmt, va_list ap) -{ - bool quote, umod, lmod, zmod, lower, possign; - int base; - vlong i; - int pad, prec, q; - const char *s; - void *p; - struct token *tok; - union type ty; - double f; - char tmpbuf1[70], tmpbuf2[70]; - struct wbuf tmp1 = MEMBUF(tmpbuf1, sizeof tmpbuf1); - struct wbuf tmp2 = MEMBUF(tmpbuf2, sizeof tmpbuf2); - struct wbuf *buf = out; - int n = 0, prevn; - - while (*fmt) { - buf = out; - if (*fmt++ != '%') { - n += bputc(buf, fmt[-1]); - continue; - } - if (*fmt == '%') { - n += bputc(buf, *fmt++); - continue; - } - fmt += quote = *fmt == '\''; - fmt += possign = *fmt == '+'; - pad = 0; - if (aisdigit(*fmt)) { /* left pad */ - for (; aisdigit(*fmt); ++fmt) - pad = pad*10 + *fmt-'0'; - if (pad) { - tmp1.len = 0; - buf = &tmp1; - } - } else if (*fmt == '-') { /* right pad */ - if (!aisdigit(*++fmt)) - fmterr("padding amount expected"); - for (; aisdigit(*fmt); ++fmt) - pad = pad*10 - (*fmt-'0'); - } - prec = -1; - if (*fmt == '.') { - if (!aisdigit(*++fmt)) - fmterr("precision expected"); - prec = 0; - for (; aisdigit(*fmt); ++fmt) - prec = prec*10 + *fmt-'0'; - } - fmt += umod = *fmt == 'u'; - if ((zmod = *fmt == 'z')) - ++fmt, lmod = 0; - else - fmt += lmod = *fmt == 'l'; - lower = 0; - prevn = n; - switch (*fmt++) { - case 'c': /* character */ - if (quote) { - n += bputc(buf, '\''); - n += putquoted(buf, va_arg(ap, int), '\'', -1); - n += bputc(buf, '\''); - } else { - n += bputc(buf, va_arg(ap, int)); - } - break; - case 's': /* nullterminated string */ - s = va_arg(ap, const char *); - if (quote) { - if (!s) { - n += bwriteS(buf, "(null)"); - break; - } - QuotedStr: - n += bputc(buf, '"'); - if (lmod) /* lower */ - for (; *s; ++s) n += putquoted(buf, aisalpha(*s) ? *s|32 : *s, '"', s[1]); - else - for (; *s; ++s) n += putquoted(buf, *s, '"', s[1]); - n += bputc(buf, '"'); - } else { - assert(s && "%s null!"); - if (lmod) /* lower */ - for (; *s; ++s) n += bputc(buf, aisalpha(*s) ? *s|32 : *s); - else - while (*s) n += bputc(buf, *s++); - } - break; - case 'S': /* string ptr + len */ - s = va_arg(ap, const char *); - i = va_arg(ap, uint); - PriS: - assert(s && "%S null"); - if (quote) { - n += bputc(buf, '"'); - for (; i--; ++s) n += putquoted(buf, *s, '"', i ? s[1] : -1); - n += bputc(buf, '"'); - } else { - iowrite(buf, s, i); - n += i; - } - break; - case 'y': /* symbol: print string literally if valid identifier, or quote it */ - s = va_arg(ap, const char *); - assert(s && "%y null"); - for (i = 0; s[i]; ++i) { - if (aisalpha(s[i]) || s[i] == '_' || (i > 0 && aisdigit(s[i]))) - continue; - goto QuotedStr; - } - /* valid identifier */ - while (*s) n += bputc(buf, *s++); - break; - case 'd': /* decimal */ - base = 10; - Int: - if (base != 10) umod = 1; - i = lmod ? va_arg(ap, vlong) - : umod ? va_arg(ap, uint) - : zmod && sizeof(&i-&i) > sizeof(int) ? va_arg(ap, vlong) - : (vlong)va_arg(ap, int); - tmp2.len = 0; - if (!umod && i < 0) { - n += bputc(buf, '-'); - i = -(uvlong)i; - } else if (possign) { - n += bputc(buf, '+'); - } - if (quote) { - switch (base) { - case 2: n += bwriteS(buf, "0b"); break; - case 8: n += bwriteS(buf, "0"); break; - case 16: n += bwriteS(buf, "0x"); break; - } - } - n += putuint(prec > 0 ? &tmp2 : buf, i, base, lower); - if (prec > 0) { - int fil = prec - tmp2.len; - while (fil-- > 0) n += bputc(buf, '0'); - iowrite(buf, tmp2.buf, tmp2.len); - } - break; - case 'o': /* octal */ - base = 8; - goto Int; - case 'b': /* binary */ - base = 2; - goto Int; - case 'x': case 'X': /* hexadecimal */ - base = 16; - lower = fmt[-1] == 'x'; - goto Int; - case 'p': /* pointer */ - p = va_arg(ap, void *); - if (!p && quote) { - n += bwriteS(buf, "NULL"); - } else { - n += bwriteS(buf, "0x"); - tmp2.len = 0; - n += putuint(prec > 0 ? &tmp2 : buf, (uvlong)p, 16, 1); - if (prec > 0) { - int fil = prec - tmp2.len; - while (fil-- > 0) n += bputc(buf, '0'); - iowrite(buf, tmp2.buf, tmp2.len); - } - } - break; - case 'f': /* float */ - f = va_arg(ap, double); - n += putdouble(buf, f); - break; - case 't': /* token/tokentag/type */ - switch (*fmt++) { - case 'k': /* tk token */ - tok = va_arg(ap, struct token *); - Tok: - switch (tok->t) { - case TKXXX: - n += bwriteS(buf, "\?\?\?"); - break; - case TKNUMLIT: - if (quote) { - n += bputc(buf, '`'); - iowrite(buf, tok->s, tok->len); - n += tok->len; - n += bputc(buf, '\''); - } else { - s = tok->s; - i = tok->len; - goto PriS; - } - break; - case TKCHRLIT: - if (tok->wide) n += bputc(buf, tok->wideuni ? tok->wide == 1 ? 'u' : 'U' : 'L'); - n += bputc(buf, '\''); - if (tok->wide == 0) - for (int i = 0; i < tok->len; ++i) - n += putquoted(buf, tok->s[i], '\'', i < tok->len - 1 ? tok->s[i+1] : -1); - else { - char p[4]; - uint c = tok->wide == 1 ? tok->ws16[0] : tok->ws32[0]; - int l = utf8enc(p, c); - if (l == 1) - n += putquoted(buf, *p, '\'', -1); - else - n += (iowrite(buf, p, l), l); - } - n += bputc(buf, '\''); - break; - case TKSTRLIT: - if (tok->wide == 0) { - s = tok->s; - i = tok->len; - quote = 1; - goto PriS; - } else { - n += bputc(buf, tok->wideuni ? tok->wide == 1 ? 'u' : 'U' : 'L'); - n += bputc(buf, '\"'); - for (int i = 0; i < tok->len; ++i) { - char p[4]; - uint c = tok->wide == 1 ? tok->ws16[i] : tok->ws32[i]; - int l = utf8enc(p, c); - if (l == 1) - n += putquoted(buf, *p, '\"', 0); - else - n += (iowrite(buf, p, l), l); - } - n += bputc(buf, '\"'); - } - break; - case TKPPMACSTR: - if (quote) n += bputc(buf, '`'); - n += bfmt(buf, "#%s", tok->s); - if (quote) n += bputc(buf, '\''); - break; - case TKPPMACARG: - case TKIDENT: - if (quote) n += bputc(buf, '`'); - n += bfmt(buf, "%s", tok->name); - if (quote) n += bputc(buf, '\''); - break; - case TKEOF: - n += bwriteS(buf, ""); - break; - case TKEQU: s = "=="; C2: iowrite(buf, s, 2); n += 2; break; - case TKNEQ: s = "!="; goto C2; - case TKLTE: s = "<="; goto C2; - case TKGTE: s = ">="; goto C2; - case TKSHR: s = ">>"; goto C2; - case TKSHL: s = "<<"; goto C2; - case TKINC: s = "++"; goto C2; - case TKDEC: s = "--"; goto C2; - case TKDOTS: n += bwriteS(buf, "..."); break; - case TKARROW: s = "->"; goto C2; - case TKPPCAT: s = "##"; goto C2; - case TKLOGAND: s = "&&"; goto C2; - case TKLOGIOR: s = "||"; goto C2; - case TKSETADD: s = "+="; goto C2; - case TKSETSUB: s = "-="; goto C2; - case TKSETMUL: s = "*="; goto C2; - case TKSETDIV: s = "/="; goto C2; - case TKSETREM: s = "%="; goto C2; - case TKSETIOR: s = "|="; goto C2; - case TKSETXOR: s = "^="; goto C2; - case TKSETAND: s = "&="; goto C2; - case TKSETSHR: n += bwriteS(buf, ">>="); break; - case TKSETSHL: n += bwriteS(buf, "<<="); break; - default: - if (quote) n += bputc(buf, '`'); - if (in_range(tok->t, TKWBEGIN_, TKWEND_)) { - iowrite(buf, tok->name, tok->len); - n += tok->len; - } else if (aisprint(tok->t)) { - n += bputc(buf, tok->t); - } else { - n += bwriteS(buf, "??"); - } - if (quote) n += bputc(buf, '\''); - break; - } - break; - case 't': /* tt token tag */ - tok = &(struct token) { va_arg(ap, int) }; - switch (tok->t) { - case TKNUMLIT: - n += bwriteS(buf, "numeric literal"); - break; - case TKSTRLIT: - n += bwriteS(buf, "string literal"); - break; - case TKIDENT: - n += bwriteS(buf, "identifier"); - break; - case TKEOF: - n += bwriteS(buf, ""); - break; - default: - if (tok->t >= TKWBEGIN_ && tok->t <= TKWEND_) { - static const char *tab[] = { - #define _(kw, c, ...) #kw, - #include "c/keywords.def" - #undef _ - }; - tok->s = tab[tok->t - TKWBEGIN_]; - tok->len = strlen(tok->s); - } - goto Tok; - } - break; - case 'y': /* ty type */ - ty = va_arg(ap, union type); - n += fmttype(buf, ty, 0); - break; - case 'q': /* tq qualified type */ - ty = va_arg(ap, union type); - q = va_arg(ap, int); - n += fmttype(buf, ty, q); - break; - default: - if (fmt[-1] == ' ' || !aisprint(fmt[-1])) - fmterr("expected format specifier"); - else - fmterr("unknown format specifier 't%c'", fmt[-1]); - } - break; - case 'g': /* graphics rendition (color) */ - if (!ccopt.nocolor) n += bwriteS(buf, "\033["); - while (*fmt++ != '.') { - if (ccopt.nocolor) continue; - n += bputc(buf, fmt[-1]); - } - if (!ccopt.nocolor) n += bputc(buf, 'm'); - break; - case 'M': /* cc mode */ - iowrite(buf, &"C89\0C99\0C11\0C23"[ccopt.cstd*4], 3); - n += 3; - n += bwriteS(buf, " mode"); - break; - default: - if (umod || lmod) { - --fmt; - base = 10; - goto Int; - } - if (fmt[-1] == ' ' || !aisprint(fmt[-1])) - fmterr("expected format specifier"); - else - fmterr("unknown format specifier '%c'", fmt[-1]); - } - if (pad > 0) { /* left pad */ - while (pad-- > buf->len) - n += bputc(out, ' '); - assert(buf != out); - iowrite(out, buf->buf, buf->len); - out->err |= buf->err; - } else if (pad < 0) { /* right pad */ - int len = n - prevn; - while (pad++ < -len) - n += bputc(out, ' '); - } - } - return n; -} - -int -bfmt(struct wbuf *buf, const char *fmt, ...) -{ - va_list ap; - int ret; - - va_start(ap, fmt); - ret = vbfmt(buf, fmt, ap); - va_end(ap); - return ret; -} - -void -gpritype(union type ty) -{ - efmt("%ty\n", ty); - ioflush(&bstderr); -} - -static uint pagesiz; - -extern struct embedfile embedfilesdir[]; - -struct memfile -mapopen(const char **err, const char *path) -{ - struct stat stat; - int fd = -1; - void *p = NULL; - struct memfile f = {0}; - uint mapsiz; - - assert("nullp" && err && path); - - if (!pagesiz) pagesiz = sysconf(_SC_PAGESIZE); - *err = NULL; - - if (*path == '@' && path[1] == ':') { - for (struct embedfile *e = embedfilesdir; e->name; ++e) { - if (!strcmp(e->name, path+2)) { - return (struct memfile) { (const uchar *)e->s, e->len, .statik = 1 }; - } - } - } - - if ((fd = open(path, O_RDONLY)) < 0) - goto Err; - if (fstat(fd, &stat) != 0) - goto Err; - - if (S_ISREG(stat.st_mode)) { - if (stat.st_size > UINT_MAX) { - Big: - errno = EFBIG; - goto Err; - } - mapsiz = alignup(stat.st_size, pagesiz); - if ((p = mmap(NULL, mapsiz + pagesiz, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)) == MAP_FAILED) - goto Err; - if (mapsiz > 0 && mmap(p, mapsiz, PROT_READ, MAP_FIXED|MAP_PRIVATE, fd, 0) == MAP_FAILED) - goto Err; - - close(fd); - f.p = p; - f.n = stat.st_size; - return f; - } else if (S_ISFIFO(stat.st_mode) || S_ISCHR(stat.st_mode)) { - uint cap = 0; - int ret; - - do { - enum { CHUNKSIZ = 1<<10 }; - if (f.n + CHUNKSIZ >= cap && (cap += CHUNKSIZ) < CHUNKSIZ) { - /* overflow */ - free(p); - goto Big; - } - if (!(f.p = p ? realloc(p, cap) : malloc(cap))) { - free(p); - goto Err; - } - p = (void *)f.p; - ret = read(fd, (char *)p + f.n, CHUNKSIZ); - if (ret >= 0) - f.n += ret; - else if (errno != EAGAIN && errno != EWOULDBLOCK) - goto Err; - } while (ret != 0); - - close(fd); - fd = -1; - mapsiz = alignup(f.n, pagesiz); - if ((f.p = mmap(NULL, mapsiz + pagesiz, PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)) == MAP_FAILED) { - free(p); - goto Err; - } - memcpy((void *)f.p, p, f.n); - free(p); - mprotect((void *)f.p, mapsiz + pagesiz, PROT_READ); - return f; - } else { - *err = "Not a file"; - } - -Err: - if (fd >= 0) close(fd); - if (!*err) *err = strerror(errno); - return f; -} - -void -mapclose(struct memfile *f) -{ - assert(f->p); - if (!f->statik) - munmap((void *)f->p, alignup(f->n, pagesiz) + pagesiz); - memset(f, 0, sizeof *f); -} - -void * -mapzeros(uint N) -{ - void *p = mmap(NULL, N, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - return p == MAP_FAILED ? NULL : p; -} - -void -_assertfmt(const char *file, int line, const char *func, const char *expr) -{ - ioflush(&bstdout); - efmt("%s:%d: %s: Assertion `%s' failed.\n", file, line, func, expr); - ioflush(&bstderr); -} - -struct fileuid { - long dev; - union { - long ino; - const char *str; - }; -}; - -/* one entry per #line */ -struct linemap { - int phys; - int toline; - const char *tofile; -}; - -static struct file { - struct fileuid uid; - const char *path; - struct memfile f; - vec_of(uint) lineoffs; - vec_of(struct linemap) linemap; - bool once; - bool seen; - internstr guardmac; -} *fileht[1<uid.dev == uid.dev && f->uid.ino == uid.ino) { - break; - } else if (!f) { - f = allocz(&globarena, sizeof *f, 0); - f->uid = uid; - f->path = name; - f->f = (struct memfile) { .statik = 1 }; - fileht[id] = f; - vinit(&f->lineoffs, NULL, 10); - vpush(&f->lineoffs, 0); - ++nfiles; - break; - } - assert(--n > 0 && "fileht full"); - } - *pf = &f->f; - return id; -} - -int -openfile(const char **err, struct memfile **pf, const char *path) -{ - struct stat st; - struct file *f; - struct fileuid uid; - size_t h, id, n = countof(fileht); - - if (*path == '@' && path[1] == ':') { - /* fast path to rule out filenames we know for sure aren't builtin */ - /* !KEEP SYNC with embedfilesdir */ - if (path[2] != 's' /* std*.h */ - && path[2] != 'f' /* float.h */) return -1; - uid.dev = -1; - uid.str = path; - h = hashs(0, path+2); - } else { - if (stat(path, &st) != 0) { - *err = strerror(errno); - return -1; - } - uid.dev = st.st_dev, uid.ino = st.st_ino; - h = uid.dev ^ uid.ino; - } - for (id = h;; ++id) { - id &= countof(fileht) - 1; - f = fileht[id]; - if (f && f->uid.dev == uid.dev && (uid.dev >= 0 ? f->uid.ino == uid.ino : !strcmp(f->uid.str, uid.str))) { - break; - } else if (!f) { - struct memfile m; - m = mapopen(err, path); - if (*err) return -1; - f = allocz(&globarena, sizeof *f, 0); - f->uid = uid; - f->path = path; - f->f = m; - fileht[id] = f; - vinit(&f->lineoffs, NULL, 50); - vpush(&f->lineoffs, 0); - ++nfiles; - break; - } - assert(--n > 0 && "fileht full"); - } - *pf = &f->f; - return id; -} - -const char * -getfilename(int id, uint atoff) -{ - assert((uint)id < countof(fileht) && fileht[id]); - if (!fileht[id]->linemap.n || !atoff) - return fileht[id]->path; - return getfilepos(NULL, NULL, id, atoff); -} - -struct memfile * -getfile(int id) -{ - assert((uint)id < countof(fileht) && fileht[id]); - return &fileht[id]->f; -} - -void -addfileline(int id, uint off) -{ - assert((uint)id < countof(fileht) && fileht[id]); - vec_of(uint) *lineoffs = (void *)&fileht[id]->lineoffs; - if (lineoffs->n && off > lineoffs->p[lineoffs->n-1]) - vpush(lineoffs, off); -} - -void -setfileline(int id, uint off, int line, const char *file) -{ - assert((uint)id < countof(fileht) && fileht[id]); - vec_of(struct linemap) *linemap = (void *)&fileht[id]->linemap; - vec_of(uint) *lineoffs = (void *)&fileht[id]->lineoffs; - int phys = 2; - for (int i = lineoffs->n-1; i >= 0; --i) { - if (lineoffs->p[i] < off) { - phys = i+2; - break; - } - } - if (linemap->n > 0) { - assert(linemap->p[linemap->n-1].phys < phys); - if (!file) file = linemap->p[linemap->n-1].tofile; - } - vpush(linemap, ((struct linemap){ phys, line, file })); -} - -const char * -getfilepos(int *pline, int *pcol, int id, uint off) -{ - assert((uint)id < countof(fileht) && fileht[id]); - uint *offs = fileht[id]->lineoffs.p; - uint n = fileht[id]->lineoffs.n; - /* binary search over offsets array */ - int l = 0, h = n - 1, i = 0; - while (l <= h) { - i = (l + h) / 2; - if (offs[i] < off) l = i + 1; - else if (offs[i] > off) h = i - 1; - else break; - } - i -= offs[i] > off; - int line = i + 1, col = off - offs[i] + 1; - const char *file = fileht[id]->path; - vec_of(struct linemap) *linemap = (void *)&fileht[id]->linemap; - if (linemap->n) { - /* binary search over linemap array */ - l = 0, h = linemap->n - 1, i = 0; - while (l <= h) { - i = (l + h) / 2; - if (linemap->p[i].phys < line) l = i + 1; - else if (linemap->p[i].phys > line) h = i - 1; - else break; - } - i -= linemap->p[i].phys > line; - if (i >= 0) { - line = linemap->p[i].toline + (line - linemap->p[i].phys); - if (linemap->p[i].tofile) file = linemap->p[i].tofile; - } - } - if (pline) *pline = line; - if (pcol) *pcol = col; - return file; -} - -bool -isoncefile(int id, internstr *guard) -{ - assert(id < countof(fileht) && fileht[id]); - *guard = fileht[id]->guardmac; - return fileht[id]->once; -} - -void -markfileonce(int id, internstr guard) -{ - assert(id < countof(fileht) && fileht[id]); - fileht[id]->once = 1; - fileht[id]->guardmac = guard; -} - -void -markfileseen(int id) -{ - assert(id < countof(fileht) && fileht[id]); - fileht[id]->seen = 1; -} - -bool -isfileseen(int id) -{ - assert(id < countof(fileht) && fileht[id]); - return fileht[id]->seen; -} - -void -closefile(int id) -{ - assert(id < countof(fileht) && fileht[id]); - mapclose(&fileht[id]->f); -} - -void -vdiag(const struct span *span, enum diagkind kind, const char *fmt, va_list ap) -{ - /* to avoid concurrent invocations of the compiler mixing up the diagnostics - * in the unbuffered stderr output, use a separate buffer here and write() - * it all out bypassing stdio */ - static char ebuf[4096]; - static struct wbuf out = FDBUF(ebuf, sizeof ebuf, STDERR_FILENO); - static int depth = 0; /* needed for nested note() calls */ - - static const char *label[] = { "error", "warning", "note" }; - static const char *color[] = { "%g1;31.", "%g1;35.", "%g1;36." }; - int line, col; - struct memfile *f; - const struct span0 *loc; - - ++depth; - if (span) { - loc = span->ex.len ? &span->ex : &span->sl; - f = getfile(loc->file); - const char *file = getfilepos(&line, &col, loc->file, loc->off); - bfmt(&out, "%s:%d:%d: ", file, line, col); - } - bfmt(&out, color[kind]); - bfmt(&out, "%s: %g.", label[kind]); - vbfmt(&out, fmt, ap); - bfmt(&out, "\n"); - if (span) { - uint i; - int nmark; - char mark = '^'; - - /* find start of line */ - for (i = loc->off - 1; i + 1 > 0 && f->p[i] != '\n'; --i) ; - if (i || f->p[i] == '\n') ++i; - - nmark = loc->len; - while (i < loc->off + loc->len) { - int j, end; - int curoff = bfmt(&out, "%5d | ", line); - const uchar *linep = &f->p[i]; - bool begintabs = 1; - for (end = 0; f->p[i] != '\n' && i < f->n; ++i, ++end) { - uchar c = f->p[i]; - if (c == '\t') { - if (!begintabs) c = ' '; - } else { - begintabs = 0; - } - ioputc(&out, c); - } - ioputc(&out, '\n'); - ++i; - - for (j = -curoff; j < 0; ++j) - ioputc(&out, j == -2 ? '|' : ' '); - for (begintabs = 1; j < col-1; ++j) { - uchar c = *linep++; - if (c == '\t') { - if (!begintabs) c = ' '; - } else { - c = ' '; - begintabs = 0; - } - ioputc(&out, c); - } - bfmt(&out, color[kind]); - do { - ioputc(&out, mark); - mark = '~'; - } while (--nmark > 0 && ++j < end); - col = 1; - ++line; - bfmt(&out, "%g.\n"); - --nmark; - } - ioputc(&out, '\n'); - } - - if (span && loc == &span->ex && span->sl.len) - if (span->ex.file != span->sl.file || !((uint) span->sl.off - span->ex.off < span->ex.len)) - note(&(struct span){ span->sl }, "expanded from here"); - - if (--depth == 0) ioflush(&out); -} - -void _Noreturn -fatal(const struct span *span, const char *fmt, ...) -{ - if (fmt) { - va_list ap; - va_start(ap, fmt); - vdiag(span, DGERROR, fmt, ap); - va_end(ap); - } - if (!fmt || span) efmt("Aborting due to previous error.\n"); - exit(1); -} - -int nerror, nwarn; -enum { MAXERROR = 20 }; - -void -error(const struct span *span, const char *fmt, ...) -{ - va_list ap; - - ++nerror; - va_start(ap, fmt); - vdiag(span, DGERROR, fmt, ap); - va_end(ap); - if (nerror > MAXERROR) { - efmt("Too many errors emitted, stopping now.\n"); - exit(1); - } -} - -void -warn(const struct span *span, const char *fmt, ...) -{ - va_list ap; - - if (ccopt.wnone) return; - if (ccopt.werror) ++nerror; - else ++nwarn; - va_start(ap, fmt); - vdiag(span, ccopt.werror ? DGERROR : DGWARN, fmt, ap); - va_end(ap); - if (nerror > MAXERROR) { - efmt("Too many errors emitted, stopping now.\n"); - exit(1); - } -} - -void -note(const struct span *span, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vdiag(span, DGNOTE, fmt, ap); - va_end(ap); -} - -/*** UTF util ***/ - -ushort * -utf8to16(uint *ulen, struct arena **arena, const uchar *s, size_t len) -{ - assert(0 && "nyi"); -} - -uint * -utf8to32(uint *ulen, struct arena **arena, const uchar *s, size_t len) -{ - uint *ret, *w; - const uchar *p, *end; - size_t n = 0; - bool istrunc; - - if (!len) return NULL; - - for (p = end = s; p < s + len; ++n) { - end = p; - if ((*p & 0xF8) == 0xF0) /* 11110xxx */ - p += 4; - else if ((*p & 0xF0) == 0xE0) /* 1110xxxx */ - p += 3; - else if ((*p & 0xE0) == 0xC0) /* 110xxxxx */ - p += 2; - else p += 1; - } - istrunc = p > s+len; - if (!istrunc) end += 1; - - ret = allocz(arena, n * sizeof *ret, sizeof *ret); - for (w = ret, p = s; p < end; ++w) { - if ((*p & 0xF8) == 0xF0) { /* 11110xxx */ - *w = (uint)(p[0] & 0x07) << 18 - | (uint)(p[1] & 0x3F) << 12 - | (uint)(p[2] & 0x3F) << 6 - | (uint)(p[3] & 0x3F); - p += 4; - } else if ((*p & 0xF0) == 0xE0) { /* 1110xxxx */ - *w = (uint)(p[0] & 0x07) << 12 - | (uint)(p[1] & 0x3F) << 6 - | (uint)(p[2] & 0x3F); - p += 3; - } else if ((*p & 0xE0) == 0xC0) { /* 110xxxxx */ - *w = (uint)(p[0] & 0x07) << 6 - | (uint)(p[1] & 0x3F); - p += 2; - } else { - *w = *p; - p += 1; - } - } - if (istrunc) *w++ = 0xFFFD; - *ulen = n; - - return ret; -} - -int -utf8enc(char p[4], uint cp) -{ - if ((cp & 0xffffff80) == 0) { - p[0] = cp; - return 1; - } else if ((cp & 0xfffff800) == 0) { - p[0] = 0xC0 | (cp >> 6 & 0x1F); - p[1] = 0x80 | (cp & 0x3F); - return 2; - } else if ((cp & 0xffff0000) == 0) { - p[0] = 0xE0 | (cp >> 12 & 0x0F); - p[1] = 0x80 | (cp >> 6 & 0x3F); - p[2] = 0x80 | (cp & 0x3F); - return 3; - } else { - p[0] = 0xF0 | (cp >> 18 & 0x07); - p[1] = 0x80 | (cp >> 12 & 0x3F); - p[2] = 0x80 | (cp >> 6 & 0x3F); - p[3] = 0x80 | (cp & 0x3F); - return 4; - } -} - -/* vim:set ts=3 sw=3 expandtab: */ diff --git a/src/ir.c b/src/ir.c index b612143..840ba0b 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1,5 +1,5 @@ #include "ir.h" -#include "../obj/obj.h" +#include "obj.h" uchar type2cls[NTYPETAG]; uchar cls2siz[] = { [KI32] = 4, [KI64] = 8, [KF32] = 4, [KF64] = 8 }; @@ -15,14 +15,14 @@ const uchar siz2intcls[] = { [1] = KI32, [2] = KI32, [4] = KI32, [8] = KI64 }; const char *opnames[] = { "?\??", #define _(o,...) #o, -#include "op.def" +#include "ir_op.def" #undef _ }; const uchar opnarg[] = { 0, #define _(o,n) n, -#include "op.def" +#include "ir_op.def" #undef _ }; diff --git a/src/ir.h b/src/ir.h index ab3e474..0aa5395 100644 --- a/src/ir.h +++ b/src/ir.h @@ -1,5 +1,5 @@ -#include "../common.h" -#include "../type.h" +#include "antcc.h" +#include "c_type.h" enum irclass { KXXX, @@ -93,7 +93,7 @@ struct addr { enum op { Oxxx, #define _(o,...) O##o, -#include "op.def" +#include "ir_op.def" #undef _ NOPER, }; @@ -109,7 +109,7 @@ extern const uchar opnarg[]; enum intrin { INxxx, #define _(b,...) IN##b, -#include "intrin.def" +#include "ir_intrin.def" #undef _ }; diff --git a/src/ir_dump.c b/src/ir_dump.c index b0ce603..1036135 100644 --- a/src/ir_dump.c +++ b/src/ir_dump.c @@ -1,6 +1,6 @@ #include "ir.h" -#include "../obj/obj.h" -#include "../endian.h" +#include "obj.h" +#include "u_endian.h" static int nextdat; @@ -91,7 +91,7 @@ prityp(union irtype typ) static const char *intrinname[] = { "?\??", #define _(b,...) #b, -#include "intrin.def" +#include "ir_intrin.def" #undef _ }; diff --git a/src/ir_fold.c b/src/ir_fold.c index 4c9861e..a7b5c6e 100644 --- a/src/ir_fold.c +++ b/src/ir_fold.c @@ -1,5 +1,5 @@ #include "ir.h" -#include "../endian.h" +#include "u_endian.h" #include #ifdef __clang__ diff --git a/src/o_elf.c b/src/o_elf.c index 5044e56..f652657 100644 --- a/src/o_elf.c +++ b/src/o_elf.c @@ -1,7 +1,7 @@ -#include "elf.h" +#include "o_elf.h" #include "obj.h" -#include "../ir/ir.h" /* mctarg */ -#include "../endian.h" +#include "ir.h" /* mctarg */ +#include "u_endian.h" #include #include /* qsort */ diff --git a/src/o_elf.h b/src/o_elf.h index c96ae8b..c63a2be 100644 --- a/src/o_elf.h +++ b/src/o_elf.h @@ -1,4 +1,9 @@ -#include "../common.h" +typedef unsigned char u8int; +typedef unsigned short u16int; +typedef unsigned int u32int; +typedef signed int s32int; +typedef signed long long s64int; +typedef unsigned long long u64int; #define ELFMAG "\177ELF" enum { @@ -27,55 +32,55 @@ enum { EM_ARM64 = 0xB7, }; -#define ELF_HDRIDENT \ - union { \ - uchar ident[16]; \ - struct { \ - uchar i_mag[4], \ - i_class, \ - i_data, \ - i_version, \ - i_osabi, \ - i_abiversion, \ - i_pad[7]; \ - }; \ +#define ELF_HDRIDENT \ + union { \ + char ident[16]; \ + struct { \ + u8int i_mag[4], \ + i_class, \ + i_data, \ + i_version, \ + i_osabi, \ + i_abiversion, \ + i_pad[7]; \ + }; \ } struct elf64hdr { ELF_HDRIDENT; - ushort type, + u16int type, machine; - uint version; - uvlong entry, + u32int version; + u64int entry, phoff, shoff; - uint flags; - ushort ehsize, + u32int flags; + u16int ehsize, phentsize, phnum, shentsize, shnum, shstrndx; }; -static_assert(sizeof(struct elf64hdr) == 64); +_Static_assert(sizeof(struct elf64hdr) == 64, ""); struct elf32hdr { ELF_HDRIDENT; - ushort type, + u16int type, machine; - uint version; - uint entry, + u32int version; + u32int entry, phoff, shoff; - uint flags; - ushort ehsize, + u32int flags; + u16int ehsize, phentsize, phnum, shentsize, shnum, shstrndx; }; -static_assert(sizeof(struct elf32hdr) == 52); +_Static_assert(sizeof(struct elf32hdr) == 52, ""); enum { SHT_NULL = 0x0, @@ -111,32 +116,32 @@ enum { }; struct elf64shdr { - uint name, + u32int name, type; - uvlong flags, + u64int flags, addr, offset, size; - uint link, + u32int link, info; - uvlong addralign, + u64int addralign, entsize; }; -static_assert(sizeof(struct elf64shdr) == 64); +_Static_assert(sizeof(struct elf64shdr) == 64, ""); struct elf32shdr { - uint name, - type, - flags, - addr, - offset, - size, - link, - info, - addralign, - entsize; -}; -static_assert(sizeof(struct elf32shdr) == 40); + u32int name, + type, + flags, + addr, + offset, + size, + link, + info, + addralign, + entsize; +}; +_Static_assert(sizeof(struct elf32shdr) == 40, ""); enum { STB_LOCAL, @@ -160,47 +165,47 @@ enum { #define ELF_S_INFO(b,t) ((b) << 4 | (t)) struct elf64sym { - uint name; - uchar info, + u32int name; + u8int info, other; - ushort shndx; - uvlong value, + u16int shndx; + u64int value, size; }; -static_assert(sizeof(struct elf64sym) == 24); +_Static_assert(sizeof(struct elf64sym) == 24, ""); struct elf32sym { - uint name, + u32int name, value, size; - uchar info, + u8int info, other; - ushort shndx; + u16int shndx; }; -static_assert(sizeof(struct elf32sym) == 16); +_Static_assert(sizeof(struct elf32sym) == 16, ""); -#define ELF64_R_INFO(s,t) ((uvlong) (s) << 32 | (uint)(t)) +#define ELF64_R_INFO(s,t) ((u64int) (s) << 32 | (u32int)(t)) struct elf64rel { - uvlong offset, info; + u64int offset, info; }; -static_assert(sizeof(struct elf64rel) == 16); +_Static_assert(sizeof(struct elf64rel) == 16, ""); -#define ELF32_R_INFO(s,t) ((s) << 8 | (uchar)(t)) +#define ELF32_R_INFO(s,t) ((s) << 8 | (u8int)(t)) struct elf32rel { - uint offset, info; + u32int offset, info; }; -static_assert(sizeof(struct elf32rel) == 8); +_Static_assert(sizeof(struct elf32rel) == 8, ""); struct elf64rela { - uvlong offset, info; - vlong addend; + u64int offset, info; + s64int addend; }; -static_assert(sizeof(struct elf64rela) == 24); +_Static_assert(sizeof(struct elf64rela) == 24, ""); struct elf32rela { - uint offset, info; - int addend; + u32int offset, info; + s32int addend; }; -static_assert(sizeof(struct elf32rela) == 12); +_Static_assert(sizeof(struct elf32rela) == 12, ""); /* vim:set ts=3 sw=3 expandtab: */ diff --git a/src/obj.c b/src/obj.c index 12f0db7..fc0a711 100644 --- a/src/obj.c +++ b/src/obj.c @@ -1,5 +1,5 @@ #include "obj.h" -#include "../ir/ir.h" +#include "ir.h" #include #include #include diff --git a/src/obj.h b/src/obj.h index 1982033..b421b3f 100644 --- a/src/obj.h +++ b/src/obj.h @@ -1,4 +1,4 @@ -#include "../common.h" +#include "antcc.h" extern struct objfile { const char *infile, *outfile; diff --git a/src/t_aarch64.h b/src/t_aarch64.h index 828909e..ad017c1 100644 --- a/src/t_aarch64.h +++ b/src/t_aarch64.h @@ -1,4 +1,4 @@ -#include "../ir/ir.h" +#include "ir.h" enum reg { R0 = 0, diff --git a/src/t_aarch64_aapcs.c b/src/t_aarch64_aapcs.c index fc08da1..8b90ff2 100644 --- a/src/t_aarch64_aapcs.c +++ b/src/t_aarch64_aapcs.c @@ -1,4 +1,4 @@ -#include "all.h" +#include "t_aarch64.h" static int abiarg(short r[2], uchar cls[2], uchar *r2off, int *ni, int *nf, int *ns, union irtype typ) diff --git a/src/t_aarch64_emit.c b/src/t_aarch64_emit.c index 9fdcd83..ac7004b 100644 --- a/src/t_aarch64_emit.c +++ b/src/t_aarch64_emit.c @@ -1,6 +1,6 @@ -#include "all.h" -#include "../obj/obj.h" -#include "../endian.h" +#include "t_aarch64.h" +#include "obj.h" +#include "u_endian.h" /* References: * ARM ARM https://developer.arm.com/documentation/ddi0628/aa/?lang=en diff --git a/src/t_aarch64_isel.c b/src/t_aarch64_isel.c index 398ea28..7e5057c 100644 --- a/src/t_aarch64_isel.c +++ b/src/t_aarch64_isel.c @@ -1,4 +1,4 @@ -#include "all.h" +#include "t_aarch64.h" #define isimm32(r) (iscon(r) && concls(r) == KI32) diff --git a/src/t_x86-64.h b/src/t_x86-64.h index c0c38ff..91021ed 100644 --- a/src/t_x86-64.h +++ b/src/t_x86-64.h @@ -1,4 +1,4 @@ -#include "../ir/ir.h" +#include "ir.h" #define LIST_REGS(_) \ _(RAX) _(RCX) _(RDX) _(RBX) _(RSP) _(RBP) _(RSI) _(RDI) \ diff --git a/src/t_x86-64_emit.c b/src/t_x86-64_emit.c index d3a466b..37a3f9c 100644 --- a/src/t_x86-64_emit.c +++ b/src/t_x86-64_emit.c @@ -1,6 +1,6 @@ -#include "all.h" -#include "../obj/obj.h" -#include "../endian.h" +#include "t_x86-64.h" +#include "obj.h" +#include "u_endian.h" /** Instruction operands ** * diff --git a/src/t_x86-64_isel.c b/src/t_x86-64_isel.c index 4b4a099..a2c41be 100644 --- a/src/t_x86-64_isel.c +++ b/src/t_x86-64_isel.c @@ -1,5 +1,5 @@ -#include "all.h" -#include "../endian.h" +#include "t_x86-64.h" +#include "u_endian.h" enum flag { ZF = 1 << 0, diff --git a/src/t_x86-64_sysv.c b/src/t_x86-64_sysv.c index 317f40f..b0cf204 100644 --- a/src/t_x86-64_sysv.c +++ b/src/t_x86-64_sysv.c @@ -1,4 +1,4 @@ -#include "all.h" +#include "t_x86-64.h" static int classify(uchar cls[2], const struct typedata *td, uint off); diff --git a/src/u_endian.h b/src/u_endian.h index 34b7721..bf4b008 100644 --- a/src/u_endian.h +++ b/src/u_endian.h @@ -1,7 +1,7 @@ #ifndef ENDIAN_H_ #define ENDIAN_H_ -#include "common.h" +#include "antcc.h" extern bool targ_bigendian; /*** Macros and functions for endian specific memory access ***/ diff --git a/src/u_io.c b/src/u_io.c new file mode 100644 index 0000000..ac5bfdb --- /dev/null +++ b/src/u_io.c @@ -0,0 +1,1255 @@ +#include "c_lex.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct wbuf bstdout, bstderr; + +void +ioinit(void) +{ + bstdout.fp = stdout; + bstdout.isfp = 1; + bstderr.fp = stderr; + bstderr.isfp = 1; +} + +void +iowrite(struct wbuf *buf, const void *Src, int n) +{ + const uchar *src = Src; + + if (buf->isfp) { + fwrite(Src, 1, n, buf->fp); + buf->err = ferror(buf->fp) != 0; + return; + } + while (n > 0) { + int avail = buf->cap - buf->len; + int amt = avail < n ? avail : n; + + memcpy(buf->buf + buf->len, src, amt); + n -= amt; + src += amt; + buf->len += amt; + if (n > 0 && buf->len == buf->cap) { + if (buf->fd < 0) { + buf->err = 1; + return; + } + ioflush(buf); + } + } +} + +void +ioflush(struct wbuf *buf) +{ + int i, ret; + + if (buf->isfp) { + fflush(buf->fp); + buf->err = ferror(buf->fp) != 0; + return; + } + buf->err = 0; + if (buf->fd < 0) { + buf->len = 0; + return; + } + for (i = 0; buf->len > 0;) { + ret = write(buf->fd, buf->buf + i, buf->len); + if (ret > 0) { + assert(ret <= buf->len); + buf->len -= ret; + i += ret; + } else if (errno == EAGAIN || errno == EWOULDBLOCK) { + continue; + } else { + buf->err = 1; + break; + } + } +} + +void +ioputc(struct wbuf *buf, uchar c) +{ + if (buf->isfp) { + buf->err = fputc(c, buf->fp) != EOF; + return; + } + if (buf->len == buf->cap) { + if (buf->fd < 0) { + buf->err = 1; + return; + } + ioflush(buf); + } + buf->buf[buf->len++] = c; +} + +static int +putquoted(struct wbuf *buf, uchar c, uchar qchar, int next) +{ + if (c == qchar || c == '\\' || !aisprint(c)) { + int n = (ioputc(buf, '\\'), 1); + uchar cseq; + + switch (c) { + case '\\': + case '\'': + case '"': + cseq = c; + Charseq: + n += (ioputc(buf, cseq), 1); + break; + case '\a': cseq = 'a'; goto Charseq; + case '\b': cseq = 'b'; goto Charseq; + case '\f': cseq = 'f'; goto Charseq; + case '\r': cseq = 'r'; goto Charseq; + case '\t': cseq = 't'; goto Charseq; + case '\v': cseq = 'v'; goto Charseq; + case '\n': cseq = 'n'; goto Charseq; + default: + if (!next || in_range(next, '0', '7')) + n += bfmt(buf, "%.3o", c); + else + n += bfmt(buf, "%o", c); + } + return n; + } + if (c == '?' && (!next || next == '?')) { + return ioputc(buf, c), ioputc(buf, '\\'), 2; + } + return ioputc(buf, c), 1; +} + +static int +putuint(struct wbuf *buf, uvlong x, int base, bool lower) +{ + uchar tmp[64]; + uchar *end = tmp + sizeof(tmp); + uchar *s = end; + switch (base) { + case 2: + do *--s = '0' + x%2; while (x >>= 1); + break; + case 8: + do *--s = '0' + x%8; while (x >>= 3); + break; + case 10: + do *--s = '0' + x%10; while (x /= 10); + break; + case 16: + do *--s = "0123456789ABCDEF"[x&15] | (-lower & 0x20); while (x >>= 4); + break; + default: + assert(0&&"base"); + } + iowrite(buf, s, end - s); + return end - s; +} + +static void +fmterr(const char *fmt, ...) +{ + va_list ap; + + efmt("fmt Error: "); + va_start(ap, fmt); + vbfmt(&bstderr, fmt, ap); + va_end(ap); + ioputc(&bstderr, '\n'); + ioflush(&bstderr); + ioflush(&bstdout); + abort(); +} + +#define bwriteS(buf, S) (iowrite(buf, S, sizeof S - 1), sizeof S - 1) +#define bputc(B, C) (ioputc(B, C), 1) + +static int +priquals(struct wbuf *buf, int q) +{ + const char s[] = " const volatile", *p = s; + int m = sizeof s - 1; + if (!q) return 0; + else if (q == QCONST) m -= 9; + else if (q == QVOLATILE) p += 6, m -= 6; + else assert(q == (QCONST | QVOLATILE)); + iowrite(buf, p, m); + return m; +} +static int +pritypebefore(struct wbuf *buf, union type ty, int qual) +{ + const char *s, *s2; + union type chld; + int n; + switch (ty.t) { + case TYVOID: s = "void"; Prim: n = bfmt(buf, "%s", s); return n + priquals(buf, qual); + case TYBOOL: s = "bool"; goto Prim; + case TYCHAR: s = "char"; goto Prim; + case TYSCHAR: s = "signed char"; goto Prim; + case TYUCHAR: s = "unsigned char"; goto Prim; + case TYSHORT: s = "short"; goto Prim; + case TYUSHORT: s = "unsigned short"; goto Prim; + case TYINT: s = "int"; goto Prim; + case TYUINT: s = "unsigned int"; goto Prim; + case TYLONG: s = "long"; goto Prim; + case TYULONG: s = "unsigned long"; goto Prim; + case TYVLONG: s = "long long"; goto Prim; + case TYUVLONG: s = "unsigned long long"; goto Prim; + case TYFLOAT: s = "float"; goto Prim; + case TYDOUBLE: s = "double"; goto Prim; + case TYLDOUBLE:s = "long double"; goto Prim; + case TYCOMPLEXF:s = "float complex"; goto Prim; + case TYCOMPLEX: s = "double complex"; goto Prim; + case TYCOMPLEXL:s = "long double complex"; goto Prim; + case TYPTR: + chld = typechild(ty); + n = pritypebefore(buf, chld, ty.flag & TFCHLDQUAL); + if (!isptrcvtt(chld.t)) + n += bputc(buf, ' '); + if (chld.t == TYARRAY || chld.t == TYFUNC) + n += bputc(buf, '('); + n += bputc(buf, '*'); + n += priquals(buf, qual); + return n; + case TYARRAY: + return pritypebefore(buf, typechild(ty), ty.flag & TFCHLDQUAL); + case TYFUNC: + return pritypebefore(buf, typedata[ty.dat].ret, 0); + case TYSTRUCT: + s = "struct"; + Tagged: + n = bfmt(buf, "%s %s", s, (s2 = (char *)ttypenames[typedata[ty.dat].id]) ? s2 : "(anonymous)"); + return n + priquals(buf, qual); + case TYUNION: + s = "union"; + goto Tagged; + case TYENUM: + s = "enum"; + goto Tagged; + default: + return bfmt(buf, "?\?%d?",ty.t); + } +} + +static int +pritypeafter(struct wbuf *buf, union type ty, int qual) +{ + const struct typedata *td; + int n = 0; + switch (ty.t) { + case TYPTR: + if (typechild(ty).t == TYARRAY || typechild(ty).t == TYFUNC) + n += bputc(buf, ')'); + n += pritypeafter(buf, typechild(ty), ty.flag & TFCHLDQUAL); + break; + case TYARRAY: + n += bputc(buf, '['); + if (typearrlen(ty)) + n += bfmt(buf, "%u", typearrlen(ty)); + n += bputc(buf, ']'); + n += pritypeafter(buf, typechild(ty), ty.flag & TFCHLDQUAL); + break; + case TYFUNC: + td = &typedata[ty.dat]; + n += bputc(buf, '('); + for (int i = 0; i < td->nmemb; ++i) { + n += bfmt(buf, "%ty", td->param[i]); + if (i < td->nmemb - 1 || td->variadic) + n += bwriteS(buf, ", "); + } + if (td->variadic) n += bwriteS(buf, "..."); + else if (td->nmemb == 0 && !td->kandr) n += bwriteS(buf, "void"); + n += bwriteS(buf, ")"); + n += pritypeafter(buf, td->ret, 0); + break; + } + return n; +} + +static int +fmttype(struct wbuf *buf, union type ty, int qual) +{ + int n = pritypebefore(buf, ty, qual); + n += pritypeafter(buf, ty, qual); + return n; +} + +static int +putdouble(struct wbuf *buf, double x) +{ + char tmp[200]; + int n = snprintf(tmp, sizeof tmp, "%f", x); + if (n >= sizeof tmp-1) n = snprintf(tmp, sizeof tmp, "%g", x); + assert(n < sizeof tmp-1); + iowrite(buf, tmp, n); + return n; +} + +int +vbfmt(struct wbuf *out, const char *fmt, va_list ap) +{ + bool quote, umod, lmod, zmod, lower, possign; + int base; + vlong i; + int pad, prec, q; + const char *s; + void *p; + struct token *tok; + union type ty; + double f; + char tmpbuf1[70], tmpbuf2[70]; + struct wbuf tmp1 = MEMBUF(tmpbuf1, sizeof tmpbuf1); + struct wbuf tmp2 = MEMBUF(tmpbuf2, sizeof tmpbuf2); + struct wbuf *buf = out; + int n = 0, prevn; + + while (*fmt) { + buf = out; + if (*fmt++ != '%') { + n += bputc(buf, fmt[-1]); + continue; + } + if (*fmt == '%') { + n += bputc(buf, *fmt++); + continue; + } + fmt += quote = *fmt == '\''; + fmt += possign = *fmt == '+'; + pad = 0; + if (aisdigit(*fmt)) { /* left pad */ + for (; aisdigit(*fmt); ++fmt) + pad = pad*10 + *fmt-'0'; + if (pad) { + tmp1.len = 0; + buf = &tmp1; + } + } else if (*fmt == '-') { /* right pad */ + if (!aisdigit(*++fmt)) + fmterr("padding amount expected"); + for (; aisdigit(*fmt); ++fmt) + pad = pad*10 - (*fmt-'0'); + } + prec = -1; + if (*fmt == '.') { + if (!aisdigit(*++fmt)) + fmterr("precision expected"); + prec = 0; + for (; aisdigit(*fmt); ++fmt) + prec = prec*10 + *fmt-'0'; + } + fmt += umod = *fmt == 'u'; + if ((zmod = *fmt == 'z')) + ++fmt, lmod = 0; + else + fmt += lmod = *fmt == 'l'; + lower = 0; + prevn = n; + switch (*fmt++) { + case 'c': /* character */ + if (quote) { + n += bputc(buf, '\''); + n += putquoted(buf, va_arg(ap, int), '\'', -1); + n += bputc(buf, '\''); + } else { + n += bputc(buf, va_arg(ap, int)); + } + break; + case 's': /* nullterminated string */ + s = va_arg(ap, const char *); + if (quote) { + if (!s) { + n += bwriteS(buf, "(null)"); + break; + } + QuotedStr: + n += bputc(buf, '"'); + if (lmod) /* lower */ + for (; *s; ++s) n += putquoted(buf, aisalpha(*s) ? *s|32 : *s, '"', s[1]); + else + for (; *s; ++s) n += putquoted(buf, *s, '"', s[1]); + n += bputc(buf, '"'); + } else { + assert(s && "%s null!"); + if (lmod) /* lower */ + for (; *s; ++s) n += bputc(buf, aisalpha(*s) ? *s|32 : *s); + else + while (*s) n += bputc(buf, *s++); + } + break; + case 'S': /* string ptr + len */ + s = va_arg(ap, const char *); + i = va_arg(ap, uint); + PriS: + assert(s && "%S null"); + if (quote) { + n += bputc(buf, '"'); + for (; i--; ++s) n += putquoted(buf, *s, '"', i ? s[1] : -1); + n += bputc(buf, '"'); + } else { + iowrite(buf, s, i); + n += i; + } + break; + case 'y': /* symbol: print string literally if valid identifier, or quote it */ + s = va_arg(ap, const char *); + assert(s && "%y null"); + for (i = 0; s[i]; ++i) { + if (aisalpha(s[i]) || s[i] == '_' || (i > 0 && aisdigit(s[i]))) + continue; + goto QuotedStr; + } + /* valid identifier */ + while (*s) n += bputc(buf, *s++); + break; + case 'd': /* decimal */ + base = 10; + Int: + if (base != 10) umod = 1; + i = lmod ? va_arg(ap, vlong) + : umod ? va_arg(ap, uint) + : zmod && sizeof(&i-&i) > sizeof(int) ? va_arg(ap, vlong) + : (vlong)va_arg(ap, int); + tmp2.len = 0; + if (!umod && i < 0) { + n += bputc(buf, '-'); + i = -(uvlong)i; + } else if (possign) { + n += bputc(buf, '+'); + } + if (quote) { + switch (base) { + case 2: n += bwriteS(buf, "0b"); break; + case 8: n += bwriteS(buf, "0"); break; + case 16: n += bwriteS(buf, "0x"); break; + } + } + n += putuint(prec > 0 ? &tmp2 : buf, i, base, lower); + if (prec > 0) { + int fil = prec - tmp2.len; + while (fil-- > 0) n += bputc(buf, '0'); + iowrite(buf, tmp2.buf, tmp2.len); + } + break; + case 'o': /* octal */ + base = 8; + goto Int; + case 'b': /* binary */ + base = 2; + goto Int; + case 'x': case 'X': /* hexadecimal */ + base = 16; + lower = fmt[-1] == 'x'; + goto Int; + case 'p': /* pointer */ + p = va_arg(ap, void *); + if (!p && quote) { + n += bwriteS(buf, "NULL"); + } else { + n += bwriteS(buf, "0x"); + tmp2.len = 0; + n += putuint(prec > 0 ? &tmp2 : buf, (uvlong)p, 16, 1); + if (prec > 0) { + int fil = prec - tmp2.len; + while (fil-- > 0) n += bputc(buf, '0'); + iowrite(buf, tmp2.buf, tmp2.len); + } + } + break; + case 'f': /* float */ + f = va_arg(ap, double); + n += putdouble(buf, f); + break; + case 't': /* token/tokentag/type */ + switch (*fmt++) { + case 'k': /* tk token */ + tok = va_arg(ap, struct token *); + Tok: + switch (tok->t) { + case TKXXX: + n += bwriteS(buf, "\?\?\?"); + break; + case TKNUMLIT: + if (quote) { + n += bputc(buf, '`'); + iowrite(buf, tok->s, tok->len); + n += tok->len; + n += bputc(buf, '\''); + } else { + s = tok->s; + i = tok->len; + goto PriS; + } + break; + case TKCHRLIT: + if (tok->wide) n += bputc(buf, tok->wideuni ? tok->wide == 1 ? 'u' : 'U' : 'L'); + n += bputc(buf, '\''); + if (tok->wide == 0) + for (int i = 0; i < tok->len; ++i) + n += putquoted(buf, tok->s[i], '\'', i < tok->len - 1 ? tok->s[i+1] : -1); + else { + char p[4]; + uint c = tok->wide == 1 ? tok->ws16[0] : tok->ws32[0]; + int l = utf8enc(p, c); + if (l == 1) + n += putquoted(buf, *p, '\'', -1); + else + n += (iowrite(buf, p, l), l); + } + n += bputc(buf, '\''); + break; + case TKSTRLIT: + if (tok->wide == 0) { + s = tok->s; + i = tok->len; + quote = 1; + goto PriS; + } else { + n += bputc(buf, tok->wideuni ? tok->wide == 1 ? 'u' : 'U' : 'L'); + n += bputc(buf, '\"'); + for (int i = 0; i < tok->len; ++i) { + char p[4]; + uint c = tok->wide == 1 ? tok->ws16[i] : tok->ws32[i]; + int l = utf8enc(p, c); + if (l == 1) + n += putquoted(buf, *p, '\"', 0); + else + n += (iowrite(buf, p, l), l); + } + n += bputc(buf, '\"'); + } + break; + case TKPPMACSTR: + if (quote) n += bputc(buf, '`'); + n += bfmt(buf, "#%s", tok->s); + if (quote) n += bputc(buf, '\''); + break; + case TKPPMACARG: + case TKIDENT: + if (quote) n += bputc(buf, '`'); + n += bfmt(buf, "%s", tok->name); + if (quote) n += bputc(buf, '\''); + break; + case TKEOF: + n += bwriteS(buf, ""); + break; + case TKEQU: s = "=="; C2: iowrite(buf, s, 2); n += 2; break; + case TKNEQ: s = "!="; goto C2; + case TKLTE: s = "<="; goto C2; + case TKGTE: s = ">="; goto C2; + case TKSHR: s = ">>"; goto C2; + case TKSHL: s = "<<"; goto C2; + case TKINC: s = "++"; goto C2; + case TKDEC: s = "--"; goto C2; + case TKDOTS: n += bwriteS(buf, "..."); break; + case TKARROW: s = "->"; goto C2; + case TKPPCAT: s = "##"; goto C2; + case TKLOGAND: s = "&&"; goto C2; + case TKLOGIOR: s = "||"; goto C2; + case TKSETADD: s = "+="; goto C2; + case TKSETSUB: s = "-="; goto C2; + case TKSETMUL: s = "*="; goto C2; + case TKSETDIV: s = "/="; goto C2; + case TKSETREM: s = "%="; goto C2; + case TKSETIOR: s = "|="; goto C2; + case TKSETXOR: s = "^="; goto C2; + case TKSETAND: s = "&="; goto C2; + case TKSETSHR: n += bwriteS(buf, ">>="); break; + case TKSETSHL: n += bwriteS(buf, "<<="); break; + default: + if (quote) n += bputc(buf, '`'); + if (in_range(tok->t, TKWBEGIN_, TKWEND_)) { + iowrite(buf, tok->name, tok->len); + n += tok->len; + } else if (aisprint(tok->t)) { + n += bputc(buf, tok->t); + } else { + n += bwriteS(buf, "??"); + } + if (quote) n += bputc(buf, '\''); + break; + } + break; + case 't': /* tt token tag */ + tok = &(struct token) { va_arg(ap, int) }; + switch (tok->t) { + case TKNUMLIT: + n += bwriteS(buf, "numeric literal"); + break; + case TKSTRLIT: + n += bwriteS(buf, "string literal"); + break; + case TKIDENT: + n += bwriteS(buf, "identifier"); + break; + case TKEOF: + n += bwriteS(buf, ""); + break; + default: + if (tok->t >= TKWBEGIN_ && tok->t <= TKWEND_) { + static const char *tab[] = { + #define _(kw, c, ...) #kw, + #include "c_keywords.def" + #undef _ + }; + tok->s = tab[tok->t - TKWBEGIN_]; + tok->len = strlen(tok->s); + } + goto Tok; + } + break; + case 'y': /* ty type */ + ty = va_arg(ap, union type); + n += fmttype(buf, ty, 0); + break; + case 'q': /* tq qualified type */ + ty = va_arg(ap, union type); + q = va_arg(ap, int); + n += fmttype(buf, ty, q); + break; + default: + if (fmt[-1] == ' ' || !aisprint(fmt[-1])) + fmterr("expected format specifier"); + else + fmterr("unknown format specifier 't%c'", fmt[-1]); + } + break; + case 'g': /* graphics rendition (color) */ + if (!ccopt.nocolor) n += bwriteS(buf, "\033["); + while (*fmt++ != '.') { + if (ccopt.nocolor) continue; + n += bputc(buf, fmt[-1]); + } + if (!ccopt.nocolor) n += bputc(buf, 'm'); + break; + case 'M': /* cc mode */ + iowrite(buf, &"C89\0C99\0C11\0C23"[ccopt.cstd*4], 3); + n += 3; + n += bwriteS(buf, " mode"); + break; + default: + if (umod || lmod) { + --fmt; + base = 10; + goto Int; + } + if (fmt[-1] == ' ' || !aisprint(fmt[-1])) + fmterr("expected format specifier"); + else + fmterr("unknown format specifier '%c'", fmt[-1]); + } + if (pad > 0) { /* left pad */ + while (pad-- > buf->len) + n += bputc(out, ' '); + assert(buf != out); + iowrite(out, buf->buf, buf->len); + out->err |= buf->err; + } else if (pad < 0) { /* right pad */ + int len = n - prevn; + while (pad++ < -len) + n += bputc(out, ' '); + } + } + return n; +} + +int +bfmt(struct wbuf *buf, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vbfmt(buf, fmt, ap); + va_end(ap); + return ret; +} + +void +gpritype(union type ty) +{ + efmt("%ty\n", ty); + ioflush(&bstderr); +} + +static uint pagesiz; + +extern struct embedfile embedfilesdir[]; + +struct memfile +mapopen(const char **err, const char *path) +{ + struct stat stat; + int fd = -1; + void *p = NULL; + struct memfile f = {0}; + uint mapsiz; + + assert("nullp" && err && path); + + if (!pagesiz) pagesiz = sysconf(_SC_PAGESIZE); + *err = NULL; + + if (*path == '@' && path[1] == ':') { + for (struct embedfile *e = embedfilesdir; e->name; ++e) { + if (!strcmp(e->name, path+2)) { + return (struct memfile) { (const uchar *)e->s, e->len, .statik = 1 }; + } + } + } + + if ((fd = open(path, O_RDONLY)) < 0) + goto Err; + if (fstat(fd, &stat) != 0) + goto Err; + + if (S_ISREG(stat.st_mode)) { + if (stat.st_size > UINT_MAX) { + Big: + errno = EFBIG; + goto Err; + } + mapsiz = alignup(stat.st_size, pagesiz); + if ((p = mmap(NULL, mapsiz + pagesiz, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)) == MAP_FAILED) + goto Err; + if (mapsiz > 0 && mmap(p, mapsiz, PROT_READ, MAP_FIXED|MAP_PRIVATE, fd, 0) == MAP_FAILED) + goto Err; + + close(fd); + f.p = p; + f.n = stat.st_size; + return f; + } else if (S_ISFIFO(stat.st_mode) || S_ISCHR(stat.st_mode)) { + uint cap = 0; + int ret; + + do { + enum { CHUNKSIZ = 1<<10 }; + if (f.n + CHUNKSIZ >= cap && (cap += CHUNKSIZ) < CHUNKSIZ) { + /* overflow */ + free(p); + goto Big; + } + if (!(f.p = p ? realloc(p, cap) : malloc(cap))) { + free(p); + goto Err; + } + p = (void *)f.p; + ret = read(fd, (char *)p + f.n, CHUNKSIZ); + if (ret >= 0) + f.n += ret; + else if (errno != EAGAIN && errno != EWOULDBLOCK) + goto Err; + } while (ret != 0); + + close(fd); + fd = -1; + mapsiz = alignup(f.n, pagesiz); + if ((f.p = mmap(NULL, mapsiz + pagesiz, PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)) == MAP_FAILED) { + free(p); + goto Err; + } + memcpy((void *)f.p, p, f.n); + free(p); + mprotect((void *)f.p, mapsiz + pagesiz, PROT_READ); + return f; + } else { + *err = "Not a file"; + } + +Err: + if (fd >= 0) close(fd); + if (!*err) *err = strerror(errno); + return f; +} + +void +mapclose(struct memfile *f) +{ + assert(f->p); + if (!f->statik) + munmap((void *)f->p, alignup(f->n, pagesiz) + pagesiz); + memset(f, 0, sizeof *f); +} + +void * +mapzeros(uint N) +{ + void *p = mmap(NULL, N, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + return p == MAP_FAILED ? NULL : p; +} + +void +_assertfmt(const char *file, int line, const char *func, const char *expr) +{ + ioflush(&bstdout); + efmt("%s:%d: %s: Assertion `%s' failed.\n", file, line, func, expr); + ioflush(&bstderr); +} + +struct fileuid { + long dev; + union { + long ino; + const char *str; + }; +}; + +/* one entry per #line */ +struct linemap { + int phys; + int toline; + const char *tofile; +}; + +static struct file { + struct fileuid uid; + const char *path; + struct memfile f; + vec_of(uint) lineoffs; + vec_of(struct linemap) linemap; + bool once; + bool seen; + internstr guardmac; +} *fileht[1<uid.dev == uid.dev && f->uid.ino == uid.ino) { + break; + } else if (!f) { + f = allocz(&globarena, sizeof *f, 0); + f->uid = uid; + f->path = name; + f->f = (struct memfile) { .statik = 1 }; + fileht[id] = f; + vinit(&f->lineoffs, NULL, 10); + vpush(&f->lineoffs, 0); + ++nfiles; + break; + } + assert(--n > 0 && "fileht full"); + } + *pf = &f->f; + return id; +} + +int +openfile(const char **err, struct memfile **pf, const char *path) +{ + struct stat st; + struct file *f; + struct fileuid uid; + size_t h, id, n = countof(fileht); + + if (*path == '@' && path[1] == ':') { + /* fast path to rule out filenames we know for sure aren't builtin */ + /* !KEEP SYNC with embedfilesdir */ + if (path[2] != 's' /* std*.h */ + && path[2] != 'f' /* float.h */) return -1; + uid.dev = -1; + uid.str = path; + h = hashs(0, path+2); + } else { + if (stat(path, &st) != 0) { + *err = strerror(errno); + return -1; + } + uid.dev = st.st_dev, uid.ino = st.st_ino; + h = uid.dev ^ uid.ino; + } + for (id = h;; ++id) { + id &= countof(fileht) - 1; + f = fileht[id]; + if (f && f->uid.dev == uid.dev && (uid.dev >= 0 ? f->uid.ino == uid.ino : !strcmp(f->uid.str, uid.str))) { + break; + } else if (!f) { + struct memfile m; + m = mapopen(err, path); + if (*err) return -1; + f = allocz(&globarena, sizeof *f, 0); + f->uid = uid; + f->path = path; + f->f = m; + fileht[id] = f; + vinit(&f->lineoffs, NULL, 50); + vpush(&f->lineoffs, 0); + ++nfiles; + break; + } + assert(--n > 0 && "fileht full"); + } + *pf = &f->f; + return id; +} + +const char * +getfilename(int id, uint atoff) +{ + assert((uint)id < countof(fileht) && fileht[id]); + if (!fileht[id]->linemap.n || !atoff) + return fileht[id]->path; + return getfilepos(NULL, NULL, id, atoff); +} + +struct memfile * +getfile(int id) +{ + assert((uint)id < countof(fileht) && fileht[id]); + return &fileht[id]->f; +} + +void +addfileline(int id, uint off) +{ + assert((uint)id < countof(fileht) && fileht[id]); + vec_of(uint) *lineoffs = (void *)&fileht[id]->lineoffs; + if (lineoffs->n && off > lineoffs->p[lineoffs->n-1]) + vpush(lineoffs, off); +} + +void +setfileline(int id, uint off, int line, const char *file) +{ + assert((uint)id < countof(fileht) && fileht[id]); + vec_of(struct linemap) *linemap = (void *)&fileht[id]->linemap; + vec_of(uint) *lineoffs = (void *)&fileht[id]->lineoffs; + int phys = 2; + for (int i = lineoffs->n-1; i >= 0; --i) { + if (lineoffs->p[i] < off) { + phys = i+2; + break; + } + } + if (linemap->n > 0) { + assert(linemap->p[linemap->n-1].phys < phys); + if (!file) file = linemap->p[linemap->n-1].tofile; + } + vpush(linemap, ((struct linemap){ phys, line, file })); +} + +const char * +getfilepos(int *pline, int *pcol, int id, uint off) +{ + assert((uint)id < countof(fileht) && fileht[id]); + uint *offs = fileht[id]->lineoffs.p; + uint n = fileht[id]->lineoffs.n; + /* binary search over offsets array */ + int l = 0, h = n - 1, i = 0; + while (l <= h) { + i = (l + h) / 2; + if (offs[i] < off) l = i + 1; + else if (offs[i] > off) h = i - 1; + else break; + } + i -= offs[i] > off; + int line = i + 1, col = off - offs[i] + 1; + const char *file = fileht[id]->path; + vec_of(struct linemap) *linemap = (void *)&fileht[id]->linemap; + if (linemap->n) { + /* binary search over linemap array */ + l = 0, h = linemap->n - 1, i = 0; + while (l <= h) { + i = (l + h) / 2; + if (linemap->p[i].phys < line) l = i + 1; + else if (linemap->p[i].phys > line) h = i - 1; + else break; + } + i -= linemap->p[i].phys > line; + if (i >= 0) { + line = linemap->p[i].toline + (line - linemap->p[i].phys); + if (linemap->p[i].tofile) file = linemap->p[i].tofile; + } + } + if (pline) *pline = line; + if (pcol) *pcol = col; + return file; +} + +bool +isoncefile(int id, internstr *guard) +{ + assert(id < countof(fileht) && fileht[id]); + *guard = fileht[id]->guardmac; + return fileht[id]->once; +} + +void +markfileonce(int id, internstr guard) +{ + assert(id < countof(fileht) && fileht[id]); + fileht[id]->once = 1; + fileht[id]->guardmac = guard; +} + +void +markfileseen(int id) +{ + assert(id < countof(fileht) && fileht[id]); + fileht[id]->seen = 1; +} + +bool +isfileseen(int id) +{ + assert(id < countof(fileht) && fileht[id]); + return fileht[id]->seen; +} + +void +closefile(int id) +{ + assert(id < countof(fileht) && fileht[id]); + mapclose(&fileht[id]->f); +} + +void +vdiag(const struct span *span, enum diagkind kind, const char *fmt, va_list ap) +{ + /* to avoid concurrent invocations of the compiler mixing up the diagnostics + * in the unbuffered stderr output, use a separate buffer here and write() + * it all out bypassing stdio */ + static char ebuf[4096]; + static struct wbuf out = FDBUF(ebuf, sizeof ebuf, STDERR_FILENO); + static int depth = 0; /* needed for nested note() calls */ + + static const char *label[] = { "error", "warning", "note" }; + static const char *color[] = { "%g1;31.", "%g1;35.", "%g1;36." }; + int line, col; + struct memfile *f; + const struct span0 *loc; + + ++depth; + if (span) { + loc = span->ex.len ? &span->ex : &span->sl; + f = getfile(loc->file); + const char *file = getfilepos(&line, &col, loc->file, loc->off); + bfmt(&out, "%s:%d:%d: ", file, line, col); + } + bfmt(&out, color[kind]); + bfmt(&out, "%s: %g.", label[kind]); + vbfmt(&out, fmt, ap); + bfmt(&out, "\n"); + if (span) { + uint i; + int nmark; + char mark = '^'; + + /* find start of line */ + for (i = loc->off - 1; i + 1 > 0 && f->p[i] != '\n'; --i) ; + if (i || f->p[i] == '\n') ++i; + + nmark = loc->len; + while (i < loc->off + loc->len) { + int j, end; + int curoff = bfmt(&out, "%5d | ", line); + const uchar *linep = &f->p[i]; + bool begintabs = 1; + for (end = 0; f->p[i] != '\n' && i < f->n; ++i, ++end) { + uchar c = f->p[i]; + if (c == '\t') { + if (!begintabs) c = ' '; + } else { + begintabs = 0; + } + ioputc(&out, c); + } + ioputc(&out, '\n'); + ++i; + + for (j = -curoff; j < 0; ++j) + ioputc(&out, j == -2 ? '|' : ' '); + for (begintabs = 1; j < col-1; ++j) { + uchar c = *linep++; + if (c == '\t') { + if (!begintabs) c = ' '; + } else { + c = ' '; + begintabs = 0; + } + ioputc(&out, c); + } + bfmt(&out, color[kind]); + do { + ioputc(&out, mark); + mark = '~'; + } while (--nmark > 0 && ++j < end); + col = 1; + ++line; + bfmt(&out, "%g.\n"); + --nmark; + } + ioputc(&out, '\n'); + } + + if (span && loc == &span->ex && span->sl.len) + if (span->ex.file != span->sl.file || !((uint) span->sl.off - span->ex.off < span->ex.len)) + note(&(struct span){ span->sl }, "expanded from here"); + + if (--depth == 0) ioflush(&out); +} + +void _Noreturn +fatal(const struct span *span, const char *fmt, ...) +{ + if (fmt) { + va_list ap; + va_start(ap, fmt); + vdiag(span, DGERROR, fmt, ap); + va_end(ap); + } + if (!fmt || span) efmt("Aborting due to previous error.\n"); + exit(1); +} + +int nerror, nwarn; +enum { MAXERROR = 20 }; + +void +error(const struct span *span, const char *fmt, ...) +{ + va_list ap; + + ++nerror; + va_start(ap, fmt); + vdiag(span, DGERROR, fmt, ap); + va_end(ap); + if (nerror > MAXERROR) { + efmt("Too many errors emitted, stopping now.\n"); + exit(1); + } +} + +void +warn(const struct span *span, const char *fmt, ...) +{ + va_list ap; + + if (ccopt.wnone) return; + if (ccopt.werror) ++nerror; + else ++nwarn; + va_start(ap, fmt); + vdiag(span, ccopt.werror ? DGERROR : DGWARN, fmt, ap); + va_end(ap); + if (nerror > MAXERROR) { + efmt("Too many errors emitted, stopping now.\n"); + exit(1); + } +} + +void +note(const struct span *span, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vdiag(span, DGNOTE, fmt, ap); + va_end(ap); +} + +/*** UTF util ***/ + +ushort * +utf8to16(uint *ulen, struct arena **arena, const uchar *s, size_t len) +{ + assert(0 && "nyi"); +} + +uint * +utf8to32(uint *ulen, struct arena **arena, const uchar *s, size_t len) +{ + uint *ret, *w; + const uchar *p, *end; + size_t n = 0; + bool istrunc; + + if (!len) return NULL; + + for (p = end = s; p < s + len; ++n) { + end = p; + if ((*p & 0xF8) == 0xF0) /* 11110xxx */ + p += 4; + else if ((*p & 0xF0) == 0xE0) /* 1110xxxx */ + p += 3; + else if ((*p & 0xE0) == 0xC0) /* 110xxxxx */ + p += 2; + else p += 1; + } + istrunc = p > s+len; + if (!istrunc) end += 1; + + ret = allocz(arena, n * sizeof *ret, sizeof *ret); + for (w = ret, p = s; p < end; ++w) { + if ((*p & 0xF8) == 0xF0) { /* 11110xxx */ + *w = (uint)(p[0] & 0x07) << 18 + | (uint)(p[1] & 0x3F) << 12 + | (uint)(p[2] & 0x3F) << 6 + | (uint)(p[3] & 0x3F); + p += 4; + } else if ((*p & 0xF0) == 0xE0) { /* 1110xxxx */ + *w = (uint)(p[0] & 0x07) << 12 + | (uint)(p[1] & 0x3F) << 6 + | (uint)(p[2] & 0x3F); + p += 3; + } else if ((*p & 0xE0) == 0xC0) { /* 110xxxxx */ + *w = (uint)(p[0] & 0x07) << 6 + | (uint)(p[1] & 0x3F); + p += 2; + } else { + *w = *p; + p += 1; + } + } + if (istrunc) *w++ = 0xFFFD; + *ulen = n; + + return ret; +} + +int +utf8enc(char p[4], uint cp) +{ + if ((cp & 0xffffff80) == 0) { + p[0] = cp; + return 1; + } else if ((cp & 0xfffff800) == 0) { + p[0] = 0xC0 | (cp >> 6 & 0x1F); + p[1] = 0x80 | (cp & 0x3F); + return 2; + } else if ((cp & 0xffff0000) == 0) { + p[0] = 0xE0 | (cp >> 12 & 0x0F); + p[1] = 0x80 | (cp >> 6 & 0x3F); + p[2] = 0x80 | (cp & 0x3F); + return 3; + } else { + p[0] = 0xF0 | (cp >> 18 & 0x07); + p[1] = 0x80 | (cp >> 12 & 0x3F); + p[2] = 0x80 | (cp >> 6 & 0x3F); + p[3] = 0x80 | (cp & 0x3F); + return 4; + } +} + +/* vim:set ts=3 sw=3 expandtab: */ diff --git a/src/u_mem.c b/src/u_mem.c index 9ee8864..9495a5f 100644 --- a/src/u_mem.c +++ b/src/u_mem.c @@ -1,4 +1,4 @@ -#include "common.h" +#include "antcc.h" #include #include #include diff --git a/tool/depgen.c b/tool/depgen.c index 0291859..2e880d1 100644 --- a/tool/depgen.c +++ b/tool/depgen.c @@ -95,18 +95,22 @@ dofile(const char *f) files[nfiles++] = f; FILE *fp = fopen(f, "r"); if (!fp) { + fprintf(stderr, "depgen ERR: "); perror(f); return 1; } char line[MAXLINE], hdr[MAXLINE]; - while (fgets(line, sizeof line, fp)) { + for (int ln = 1; fgets(line, sizeof line, fp); ++ln) { if (sscanf(line, " # include \"%[^\"]\"", hdr) == 1) { const char *abspath = catpath(dirname(f), hdr); for (int i = 0; files[i] && i < MAXFILES; ++i) { if (!strcmp(files[i], abspath)) goto Skip; } fprintf(out, " %s", abspath); - ret |= dofile(abspath); + if (dofile(abspath) != 0) { + fprintf(stderr, " #included from %s:%d\n", f, ln); + ret = 1; + } } Skip:; } @@ -118,7 +122,7 @@ dofile(const char *f) int main(int argc, char **argv) { -#define DIE(...) return fprintf(stderr, "? "__VA_ARGS__), fputc('\n', stderr), 1 +#define DIE(...) return fprintf(stderr, "depgen ERR: "__VA_ARGS__), fputc('\n', stderr), 1 const char *src = NULL, *targ = NULL, *mf = NULL; int mp = 0; for (int i = 1; i < argc; ++i) { -- cgit v1.2.3