#pragma once #include #include #define iota(x) 1 << (x) /* core types */ typedef struct Io Io; typedef struct Pos Pos; typedef struct Range Range; typedef struct Token Token; typedef struct Lexer Lexer; typedef struct Sym Sym; typedef struct Type Type; typedef struct Spec Spec; typedef struct Decl Decl; typedef struct Stmt Stmt; typedef struct Expr Expr; /* maps */ typedef struct SymTab SymTab; typedef struct StrTab StrTab; typedef struct Compiler Compiler; /* keywords of language */ #define KEYWORDS \ KEYWORD(Kauto,"auto") \ KEYWORD(Kregister,"register") \ KEYWORD(Kstatic,"static") \ KEYWORD(Kextern,"extern") \ KEYWORD(Ktypedef,"typedef") \ KEYWORD(Kconst,"const") \ KEYWORD(Kvolatile,"volatile") \ KEYWORD(Krestrict,"restrict") \ KEYWORD(Kinline,"inline") \ KEYWORD(Kvoid,"void") \ KEYWORD(Kchar,"char") \ KEYWORD(Kint,"int") \ KEYWORD(Kfloat,"float") \ KEYWORD(Kdouble,"double") \ KEYWORD(Ksigned,"signed") \ KEYWORD(Kunsigned,"unsigned") \ KEYWORD(Kshort,"short") \ KEYWORD(Klong,"long") \ KEYWORD(Kvlong,"vlong") \ KEYWORD(Kstruct,"struct") \ KEYWORD(Kunion,"union") \ KEYWORD(Kenum,"enum") \ KEYWORD(Kfor,"for") \ KEYWORD(Kdo,"do") \ KEYWORD(Kwhile,"while") \ KEYWORD(Kcontinue,"continue") \ KEYWORD(Kif,"if") \ KEYWORD(Kelse,"else") \ KEYWORD(Kswitch,"switch") \ KEYWORD(Kcase,"case") \ KEYWORD(Kdefault,"default") \ KEYWORD(Kbreak,"break") \ KEYWORD(Kgoto,"goto") \ KEYWORD(Kreturn,"return") \ KEYWORD(Ksizeof,"sizeof") \ KEYWORD(Kalignof,"alignof") #define KEYWORD(a, b) a, enum { KEYWORDS NUM_KEYWORDS }; #undef KEYWORD extern byte *keywords[NUM_KEYWORDS]; // ----------------------------------------------------------------------- // lexing: byte stream -> tokens // pre-processor built in /* source position: error reporting */ struct Pos { int col; int line; string path; }; struct Range { Pos beg; Pos end; }; void errorat(Pos x, byte *fmt, ...); /* pre-processor */ #define DIRECTIVES \ DIRECTIVE(Dpragma,"pragma", ppprag) \ DIRECTIVE(Dinclude,"include", ppinc) \ DIRECTIVE(Ddefine,"define", ppdef) \ DIRECTIVE(Dundef,"undef", ppund) \ DIRECTIVE(Dif,"if", ppif0) \ DIRECTIVE(Delse, "else", ppif1) \ DIRECTIVE(Difdef,"ifdef", ppif2) \ DIRECTIVE(Difndef,"ifndef", ppif3) \ DIRECTIVE(Dendif,"endif", ppend) #define DIRECTIVE(a, b, c) a, enum { DIRECTIVES NUM_DIRECTIVES }; #undef DIRECTIVE extern byte *directives[NUM_DIRECTIVES]; error domacro(Lexer*); error dodefine(Lexer *lx, string s); int expandmacro(Lexer *lx, Sym *s, byte *dst); extern error (*macros[NUM_DIRECTIVES])(Lexer*); /* tokenization of byte stream */ #define TOKENS \ TOK(Anil,"nil") \ TOK(Aeof,"eof") \ TOK(Aeq, "==") \ TOK(Aneq, "!=") \ TOK(Anot, "!") \ TOK(Aneg, "~") \ TOK(Axor, "^") \ TOK(Aor, "|") \ TOK(Aand, "&") \ TOK(Aoror, "||") \ TOK(Aandand, "&&") \ TOK(Aadd,"+") \ TOK(Asub,"-") \ TOK(Astar,"*") \ TOK(Adiv,"/") \ TOK(Amod,"%") \ TOK(Agt,">") \ TOK(Alt,"<") \ TOK(Agteq,">=") \ TOK(Alteq,"<=") \ TOK(Alsft,"<<") \ TOK(Arsft,">>") \ TOK(Ainc,"++") \ TOK(Adec,"--") \ TOK(Aasn,"=") \ TOK(Aorasn,"|=") \ TOK(Axorasn,"^=") \ TOK(Aandasn,"&=") \ TOK(Aaddasn,"+=") \ TOK(Asubasn,"-=") \ TOK(Amulasn,"*=") \ TOK(Adivasn,"/=") \ TOK(Amodasn,"%=") \ TOK(Alsftasn,"<<=") \ TOK(Arsftasn,">>=") \ TOK(Acomma,",") \ TOK(Acolon,":") \ TOK(Asemi,";") \ TOK(Alparen,"(") \ TOK(Arparen,")") \ TOK(Albrace,"{") \ TOK(Arbrace,"}") \ TOK(Albrakt,"[") \ TOK(Arbrakt,"]") \ TOK(Adot,".") \ TOK(Aarrow,"->") \ TOK(Aqmark,"?") \ TOK(Aellip,"...") \ TOK(Alit,"") \ TOK(Aident,"") \ TOK(Akeywd,"") \ #define TOK(a, b) a, enum { TOKENS NUM_TOKENS, Vchar = iota(8), Vint = iota(9), Vlong = iota(10), Vvlong = iota(11), Vusgn = iota(12), Vfloat = iota(13), Vstr = iota(14), }; #undef TOK extern byte *tokens[NUM_TOKENS]; /* TODO: store literals in a big val */ struct Token { uint32 kind; Range pos; union { byte *s; double f; vlong i; uvlong ui; byte c; ubyte uc; } val; }; enum { Svar = 1 << 0, Sfunc = 1 << 1, Smacro = 1 << 2, }; struct Sym { uint32 kind; string name; union { string macro; /*Func *func;*/ }; }; Sym *lookup(SymTab *tab, string ident); Sym *define(SymTab *tab, string ident, int kind); struct Lexer { Pos pos; Io *io; SymTab *sym; byte *b; byte buf[2*1024]; }; /* lex.c functions */ Token lex(Lexer *); byte getbyte(Lexer *); byte getnsbyte(Lexer *l); rune getrune(Lexer *); byte ungetbyte(Lexer *); rune ungetrune(Lexer *, rune r); void pushio(Lexer *lx, Io *new); void popio(Lexer *lx); // ----------------------------------------------------------------------- // parsing & type resolution // tokens -> ast /* statements */ enum { Sbad, Slabel, Sblock, Sexpr, Sselect, Sloop, Sjump, }; struct Stmt { union { }; }; /* expressions */ enum { Xbad, Xparen, Xident, Xlit, Xassign, Xcomma, Xternary, Xbinary, Xprefix, Xunary, Xpostfix, Xcast, }; struct Expr { union { }; }; /* declarations */ // specifiers enum { Mauto = iota(0), // Corresponds to auto int Mtype = iota(1), Mstatic = iota(2), Mreg = iota(3), Qconst = iota(4), Qrestr = iota(5), Qvoltl = iota(6), Finlne = iota(7), Tlong = iota(8), Tvlong = iota(9), Tsign = iota(10), Tunsign = iota(11), Tvoid = iota(12), Tchar = iota(13), Tshort = iota(14), Tfloat = iota(15), Tdouble = iota(16), Tcmplx = iota(17), Timag = iota(18), Taggr = iota(19), Tenum = iota(20), Tname = iota(21), }; enum { Dnil, Dbad, Dfunc, Dvar, }; struct Decl { Pos pos; uint kind; }; // ----------------------------------------------------------------------- // compiler enum { IOnil = iota(0), IOonce = iota(1), IOmac = iota(2), }; struct Io { io·Buffer buf; string path; uint32 kind; union { Stream *f; byte *b; }; Pos store; struct Io *link; }; Io* openio(byte *path); Io* makeio(); void freeio(Io *io); struct StrTab { int32 n_buckets; int32 size; int32 n_occupied; int32 upper_bound; int32 *flags; string *keys; int32 *vals; }; int32 intern(byte **str); string internview(byte* beg, byte *end); /* main data */ struct Compiler { mem·Arena *heap; StrTab strs; struct { int cap; int len; string *dir; } inc; Io *io; Io iostk[100]; string outfile; Lexer lxr; }; extern Compiler C; void init(); #undef iota