#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(_) \ _(and) \ _(as) \ _(break) \ _(case) \ _(const) \ _(defmacro) \ _(do) \ _(else) \ _(enum) \ _(extern) \ _(fn) \ _(for) \ _(if) \ _(import) \ _(let) \ _(not) \ _(or) \ _(return) \ _(sizeof) \ _(static) \ _(struct) \ _(switch) \ _(typedef) \ _(typeof) \ _(union) \ _(while) enum toktype { #define KWTK(kw) TKkw_##kw, LIST_KEYWORDS(KWTK) #undef KWTK TKintlit, TKflolit, TKboolit, TKstrlit, TKchrlit, TKnullit, TKident, TKmacident, TKgensym, TKeof, }; #define NUM_KEYWORDS TKintlit 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; }; }; }; 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 fn *curfn; struct expan { struct expan *prev; slice_t(struct expanarg) args; struct toktree toks; const char *name; struct span spp,span; int idx; } *curexpan; // macro expansions int expanno; const struct type *targty; bool used_targty; bool is_header; }; enum typetype { TYvoid, TYbool, TYint, TYfloat, TYptr, TYarr, TYslice, TYfn, TYenum, TYstruct, TYunion, TYeunion, }; 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; int id; } enu; struct { const char *name; slice_t(struct aggfield { size_t off; const char *name; const struct type *ty; }) flds; slice_t(struct decl *) decls; bool fwd; int id; } agg; }; // for cgen.c hack (mutated later, not hashed or involved in equality) const char *_cname; }; 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; slice_t(const char *) params; struct toktree body; }; struct macro { const char *name; slice_t(struct macrocase) cs; }; enum decltype { Dtype, Dfn, Dlet, Dstatic, Dmacro, }; struct decl { enum decltype t; const char *name; char **_cname; bool externp; struct span span; 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 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, }; struct blockstmt { struct env env; slice_t(struct stmt) stmts; }; 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 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 iniarg { union { i64 idx; const char *fld; }; struct expr ex; }; enum stmttype { Sblock, Sexpr, Sdecl, Sifelse, Swhile, Sfor, Siswitch, Sreturn, }; struct iswitchcase { slice_t(struct expr) es; 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; struct expr test; struct expr *next; struct blockstmt body; } loop; struct { struct expr test; slice_t(struct iswitchcase) cs; struct blockstmt *f; } iswitch; struct expr *retex; }; }; struct comfile { slice_t(struct decl *) decls; }; /************/ /** Target **/ /************/ #define alignof __alignof__ static const struct targ { size_t ptrsize, shortsize, intsize, longsize, llongsize, sizesize, f32align, f64align; bool charsigned; } g_targ = { .ptrsize = sizeof(void *), .shortsize = sizeof(short), .intsize = sizeof(int), .longsize = sizeof(long), .llongsize = sizeof(long long), .sizesize = sizeof(size_t), .f32align = alignof(float), .f64align = alignof(double), .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); 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 *, 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 *);