#pragma once #include "vec.h" #include #include #include #include #include #include #include #include #include /***********/ /** Types **/ /***********/ typedef uint8_t u8; typedef uint32_t u32; typedef uint64_t u64; typedef int64_t i64; #define bool _Bool #define noreturn _Noreturn #define slice_t(T) struct { T *d; unsigned n; } struct span { short fileid; int idx, col, line; }; /* must be alpha sorted */ #define LIST_KEYWORDS(_) \ _(alignof) \ _(and) \ _(as) \ _(break) \ _(case) \ _(const) \ _(continue) \ _(def) \ _(defer) \ _(defmacro) \ _(do) \ _(else) \ _(enum) \ _(extern) \ _(fn) \ _(for) \ _(if) \ _(import) \ _(let) \ _(offsetof) \ _(or) \ _(return) \ _(sizeof) \ _(static) \ _(struct) \ _(switch) \ _(typedef) \ _(typeof) \ _(union) \ _(while) enum toktype { #define KWTK(kw) TKkw_##kw, LIST_KEYWORDS(KWTK) #undef KWTK NUM_KEYWORDS, TKintlit = -100, TKflolit, TKboolit, TKstrlit, TKchrlit, TKnullit, TKident, TKmacident, TKgensym, TKtype, TKexpr, TKlabel, TKstrify, TKhwhen, TKeof, }; struct tok { int t; struct span span; union { struct { const struct type *ty; u64 i; } ilit; struct { const struct type *ty; double f; } flit; bool boolit; struct { const char *str; int strlen; }; const struct type *ty; struct expr *ex; }; }; struct toktree { slice_t(struct tok); }; struct expanarg { const char *name; struct toktree toks; }; struct parser { FILE *fp; const char *curfile; struct span tokspan; struct span curspan; bool eof; int peekchr; bool have_peektok; struct tok peektok; struct env *primenv; struct env *tlenv; struct env *curenv; struct blockstmt *curblock; struct fn *curfn; struct expan { struct expan *prev; slice_t(struct expanarg) args; struct toktree toks; const char *name; struct span span; struct tok peektok; bool have_peektok; int idx; bool tepl; } *curexpan; // macro expansions int expanno; const struct type *targty; bool used_targty; bool is_header; bool save_envage; int envage; int varid; int loopid, curloop; const struct type *container; }; enum typetype { TYvoid, TYbool, TYint, TYfloat, TYptr, TYarr, TYslice, TYfn, TYenum, TYstruct, TYunion, TYeunion, TYvalist, }; struct type { enum typetype t; size_t size, align; bool konst; int _id; union { bool int_signed; struct { const struct type *child; i64 length; }; struct { slice_t(const struct type *) params; const struct type *retty; bool variadic; } fn; struct { const struct type *intty; const char *name; slice_t(struct enumval { const char *name; i64 i; }) vals; bool lax; int id; } enu; struct { const char *name; const struct type *enumty; slice_t(struct aggfield { size_t off; const char *name; const struct type *ty; }) flds; slice_t(struct decl *) decls; slice_t(struct teplarg { bool typ; union { const struct type *ty; struct tok tok; }; }) tpargs; bool fwd; int id; } agg; }; // for cgen.c hack (mutated later, not hashed or involved in equality) const char *_cname; bool _defined; }; struct fnparam { const struct type *ty; const char *name; }; struct fn { const char *name, *asmname; slice_t(struct fnparam) params; const struct type *selfty; const struct type *retty; bool variadic; int id; struct stmt *body; }; struct macrocase { bool variadic, bodyarg; slice_t(const char *) params; struct toktree body; }; struct macro { const char *name; slice_t(struct macrocase) cs; }; enum decltype { Dtype, Dfn, Dlet, Dstatic, Ddef, Dmacro, Dtepl, Dlabel, }; struct attr { union { struct { uint lax : 1; }; uint bits; }; }; struct decl { enum decltype t; const char *name; char **_cname; bool externp; struct span span; const struct type *container; union { const struct type *ty; struct fn fn; struct var { const struct type *ty; struct expr *ini; int id, fnid; } var; struct macro macro; struct tepl { enum decltype t; enum typetype tkind; const char *name; struct env *env; slice_t(struct teplparam) params; struct teplcache { struct teplcache *next; slice_t(struct teplarg) args; const struct type *ty; } *cache; struct toktree toks; int envage; } tepl; int loopid; }; int age; bool _gen; }; struct teplparam { const char *name; bool typ; }; struct env { struct env *parent; struct decls { struct decls *next; struct decl decl; } *decls; }; enum exprtype { Eintlit, Eflolit, Estrlit, Eboolit, Enullit, Ename, Eprefix, Epostfix, // (unops) Ebinop, Econd, Ecall, Eindex, Eblock, Eas, Eenumval, Ezeroini, Eini, Eget, Emcall, Eslice, Elen, Eptr, Eeuini, Eeutag, Evastart, Evaarg, Evaend, }; struct blockstmt { struct env env; slice_t(struct stmt) stmts; struct defer *defers; int id; }; struct expr { enum exprtype t; struct span span; const struct type *ty; union { union { i64 i; // also for bool lit u64 u; double f; }; struct { const char *d; u64 n; } strlit; const struct decl *ref; struct { int op; // operator token struct expr *child; } unop; struct { int op; // operator token struct expr *lhs, *rhs; } binop; struct { struct expr *test, *t, *f; } cond; struct { struct expr *callee; slice_t(struct expr) args; } call; struct { struct expr *lhs, *rhs; } index; struct blockstmt block; struct expr *child; // cast, len, eutag struct { i64 i; const char *vname; } enu; struct { slice_t(struct iniarg) args; i64 maxn; } ini; struct { struct expr *lhs; const char *fld; } get; struct { struct fn *met; slice_t(struct expr) args; } mcall; struct { struct expr *lhs, *start, *end; } slice; struct { const char *fnam; i64 tag; struct expr *ini; } euini; }; }; struct iniarg { union { i64 idx; const char *fld; }; struct expr ex; }; enum stmttype { Sblock, Sexpr, Sdecl, Sifelse, Swhile, Sdowhile, Sfor, Siswitch, Sreturn, Seuswitch, Sbreak, Scontinue, Scswitch, }; struct iswitchcase { slice_t(struct expr) es; struct blockstmt t; }; struct euswitchcase { const char *capt; bool captptr; int captid, vval; const struct type *captty; struct aggfield *fld; struct blockstmt t; }; struct stmt { enum stmttype t; struct span span; union { struct blockstmt block; struct expr expr; struct decl decl; struct { struct expr test; struct blockstmt t; struct stmt *f; } ifelse; struct { slice_t(struct stmt) ini; int id; struct expr test; struct expr *next; struct blockstmt body; } loop; struct { struct expr test; slice_t(struct iswitchcase) cs; struct blockstmt *f; } iswitch; struct { struct expr test; slice_t(struct euswitchcase) cs; struct blockstmt *f; bool byptr; } euswitch; struct { struct expr *ex; int deferage; } ret; struct { int id; } brkcon; struct { slice_t(struct cswitchcase { struct expr test; struct blockstmt t; }) cs; struct blockstmt *f; } cswitch; }; }; struct defer { struct defer *next; int blockid, age; struct expr ex; } ; struct comfile { slice_t(struct decl *) decls; }; /************/ /** Target **/ /************/ #define alignof _Alignof static const struct targ { size_t ptrsize, shortsize, intsize, i32align, i64align, longsize, longalign, llongsize, llongalign, sizesize, f32align, f64align, valistsize, valistalign; bool charsigned; } g_targ = { .ptrsize = sizeof(void *), .shortsize = sizeof(short), .intsize = sizeof(int), .i32align = alignof(int32_t), .i64align = alignof(int64_t), .longsize = sizeof(long), .longalign = alignof(long), .llongalign = alignof(long long), .llongsize = sizeof(long long), .sizesize = sizeof(size_t), .f32align = alignof(float), .f64align = alignof(double), .valistsize = sizeof(va_list), .valistalign = alignof(va_list), .charsigned = CHAR_MIN < 0, }; /*********************************/ /** Macros and inline functions **/ /*********************************/ #define ARRAY_LENGTH(a) (sizeof a / sizeof *a) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define WITH_TMPCHANGE(T,var,new) \ for (T __old = (var), *__dummy = ((var) = (new), NULL); \ !__dummy; \ __dummy++, (var) = __old) #define ALIGNUP(x,a) (((x) + ((a) - 1)) & -(a)) static inline u32 bswap32(u32 x) { return (x >> 24) | (x >> 8 & 0xFF00) | (x << 8 & 0xFF0000) | (x << 24 & 0xFF000000u); } static inline u64 bswap64(u64 x) { return ((u64)bswap32(x) << 32) | bswap32(x >> 32) ; } #define vec_slice_cpy(slice, v) \ ((slice)->d = vec_compact(v), \ (slice)->n = (v)->length) #define container_of(x, T, fld) \ ((T *)((char *)(x) - offsetof(T, fld))) /// ///////////////////////////////// /** util.c **/ #define FNV1A_INI 0x811c9dc5u u32 fnv1a(u32 hash, const void *data, size_t length); u32 fnv1ai(u32 hash, int i); u32 fnv1aI(u32 hash, i64 i); u32 fnv1az(u32 hash, size_t i); int addfilepath(const char *); const char *fileid2path(int); void *xmalloc(size_t); void *xcalloc(size_t, size_t); void *xrealloc(void *, size_t); char *xstrdup(const char *); char *xasprintf(const char *fmt, ...); void noreturn fatal(struct parser *, struct span, const char *fmt, ...); /** parse.c **/ extern const char *keyword2str[]; void parse(struct comfile *, struct parser *); void initparser(struct parser *, const char *fname); /** types.c **/ extern const struct type *ty_void, *ty_bool, *ty_f32, *ty_f64, *ty_i8, *ty_u8, *ty_i16, *ty_u16, *ty_i32, *ty_u32, *ty_i64, *ty_u64, *ty_int, *ty_uint, *ty_isize, *ty_usize, *ty_iptrint, *ty_uptrint, *ty_c_int, *ty_c_uint, *ty_c_char, *ty_c_schar, *ty_c_uchar, *ty_c_short, *ty_c_ushort, *ty_c_long, *ty_c_ulong, *ty_c_llong, *ty_c_ullong; void inittypes(void); const struct type *interntype(struct type); void uninterntype(const struct type *); bool typeeql(const struct type *lhs, const struct type *rhs); bool completetype(const struct type *); void putprimtypes(struct env *); void visittypes(void (*visitor)(const struct type *, void *), void *arg); const struct type *constify(const struct type *ty); const struct type *unconstify(const struct type *ty); const struct type *constifychild(const struct type *ty); const struct type *unconstifychild(const struct type *ty); int numtype2rank(const struct type *a); const struct type * rank2numtype(int r); bool isnumtype(const struct type *a); const struct type *typeof2(const struct type *a, const struct type *b); /** env.c **/ struct decl *envfind(const struct env *, int age, const char *name); struct decl *envput(struct env *, const struct decl *decl); struct env *mkenv(const struct env *parent); /** dump.c **/ void dumpcomfile(const struct comfile *); const char *tokt2str(int); const char *tok2str(struct tok); void pritoktree(struct toktree); void epri(const char *fmt, ...); void vepri(const char *fmt, va_list); /** cgen.c **/ void cgen(FILE *, const struct comfile *); /** fold.c **/ int fold(struct expr *);