From 3eeb6f219e4d32160fa10895b57a8ddfefff5ff7 Mon Sep 17 00:00:00 2001 From: lemon Date: Tue, 17 Mar 2026 13:43:05 +0100 Subject: REFACTOR: finish renaming --- 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 +- 34 files changed, 1945 insertions(+), 1940 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 (limited to 'src') 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 -- cgit v1.2.3