aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/setup.zc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/setup.zc')
-rw-r--r--src/compiler/setup.zc191
1 files changed, 191 insertions, 0 deletions
diff --git a/src/compiler/setup.zc b/src/compiler/setup.zc
new file mode 100644
index 0000000..4986fc3
--- /dev/null
+++ b/src/compiler/setup.zc
@@ -0,0 +1,191 @@
+// ---- setup ----
+
+// the collector's roots for the compiler's half of the memory map: the program
+// area (globals live between functions), the genome's globals, the input source
+// frames, the live frame stack and the live data stack. rt.zc declares this
+// and calls it from gc().
+int gc_roots() {
+ int end = ptop; if (end > rt.CODE_END) end = rt.CODE_END;
+ rt.markrange(0, end);
+ if (!hdelta && here > ptop && ptop < rt.CODE_END) { end = here; if (end > rt.CODE_END) end = rt.CODE_END; rt.markrange(ptop, end); } // globals of a unit still compiling
+ rt.markrange(rt.GORG, rt.GORG[6]);
+ rt.markrange(R_IH, R_POOLEND);
+ rt.markrange(sval, sval + nsym);
+ rt.markrange(R_TY, R_TYEND);
+ rt.markrange(R_SRC, R_SRC + R_SRC_cap);
+ rt.gc_frames();
+ rt.markrange(rt.dsp(), rt.data_top);
+ return 0;
+}
+// start-up in two parts. zc_init clears the intern table and interns the
+// spellings the parser compares against; zc_tables fills the operator and
+// keyword tables. an operator is a name, a precedence and a code sequence in
+// the vm's own one-letter mnemonics (see seqasm), so "<=" is "~ < 1 ^": swap,
+// less-than, flip the bit.
+int zc_init() {
+ receiver_methods = 0; closure_expected = 0;
+ effect_floor = 0; effect_symbols = 0; effect_edges = 0; effect_requirements = 0; effect_current = 0;
+ pooltop = R_POOL;
+ poolend = R_POOLEND; poolblocks = 0; namecount = 0;
+ rt.fill_w(namehash, 0, hashcap);
+ nsym = 0; nfixu = 0; fixfree = 0; nbin = 0; nun = 0; nasg = 0; nkop = 0; seqtop = 0;
+ lsp = 0; ctxsp = 0; ntd = 0; snaptop = 0; nloc = 0; lbase = 0; npm = 0; npe = 0; rt.fill_w(lkeys, 0, lkeycap); lkeyn = 0;
+ s_lp = intern("("); s_rp = intern(")"); s_lb = intern("{"); s_rb = intern("}");
+ s_lk = intern("["); s_rk = intern("]"); s_comma = intern(","); s_semi = intern(";");
+ s_eq = intern("="); s_arrow = intern("->"); s_inc = intern("++"); s_dec = intern("--");
+ s_star = intern("*");
+ s_slash = intern("/");
+ s_amp = intern("&");
+ s_colon = intern(":");
+ s_hash = intern("#");
+ s_minus = intern("-");
+ s_dot = intern(".");
+ s_q = intern("?");
+ s_case = intern("case");
+ s_default = intern("default");
+ s_andand = intern("&&");
+ s_oror = intern("||");
+ s_fn = intern("fn"); s_var = intern("let"); s_const = intern("const"); s_else = intern("else");
+ s_as = intern("as"); s_unchecked = intern("unchecked"); s_immediate = intern("immediate");
+ s_m = intern("m"); s_d = intern("d"); s_u = intern("u"); s_static = intern("static");
+ s_start = intern("run.start");
+ s_main = intern("main");
+ s_free = intern("rt.free");
+ s_recycle = intern("rt.recycle"); s_copy_w = intern("rt.copy_w");
+ s_do = intern("do");
+ s_while = intern("while");
+ s_enum = intern("enum");
+ s_include = intern("include");
+ s_memdebug = intern("memdebug"); s_scrub = intern("rt.scrub"); s_alloc = intern("rt.alloc_line");
+ s_check = intern("rt.checkptr"); s_memset = intern("rt.mem_set");
+ s_own = intern("rt.own"); s_qnew = intern("run.qnew"); s_fovf = intern("rt.frame_overflow");
+ s_frame_floor = intern("rt.frame_floor"); s_frame_top = intern("rt.frame_top"); s_frame_node = intern("rt.frame_node");
+ s_frame_busy = intern("rt.frame_busy"); s_frame_guard = intern("rt.frame_guard");
+ s_frame_grow = intern("rt.frame_grow"); s_frame_leave = intern("rt.frame_leave");
+ s_enhance = intern("enhance"); s_micro = intern("micro"); s_vm = intern("vm");
+ return 0;
+}
+// operators and keywords. these are plain tables in memory: a program can
+// add operators, change precedences or replace keywords with its own.
+// (the order of the first binary operators matters: cexpr refers to * + - << >>
+// & | by their index, and the comments mark which ones)
+int zc_tables() {
+ add_unop("!", "0 $ 0 ~ - | 63 > 1 +"); // index 0
+ add_unop("!!", "0 $ 0 ~ - | 63 > 0 ~ -"); // index 1: normalize to 0 or 1
+ add_unop("~", "-1 ^"); // index 2
+ add_unop("-", "0 ~ -");
+ add_binop("*", 10, "*"); // the first few indexes are used by cexpr
+ add_binop("/", 10, "idiv"); // native divide, wired in by rt.zc
+ add_binop("%", 10, "imod");
+ add_binop("+", 9, "+"); // 3
+ add_binop("-", 9, "-"); // 4
+ add_binop("<<", 8, "ishl"); // 5
+ add_binop(">>", 8, ">"); // 6
+ add_binop("<", 7, "<");
+ add_binop(">", 7, "~ <");
+ add_binop("<=", 7, "~ < 1 ^");
+ add_binop(">=", 7, "< 1 ^");
+ add_binop("==", 6, "- 0 $ 0 ~ - | 63 > 1 +");
+ add_binop("!=", 6, "- 0 $ 0 ~ - | 63 > 0 ~ -");
+ add_binop("&", 5, "&"); // 13
+ add_binop("^", 4, "^");
+ add_binop("|", 3, "|"); // 15
+ add_binop("&&", -1, 0);
+ add_binop("||", -2, 0);
+ addkop(s_eq); addkop(s_arrow); addkop(s_inc); addkop(s_dec);
+ add_kw("let", kw_var, F_STMT);
+ add_kw("if", kw_if, F_STMT);
+ add_kw("while", kw_while, F_STMT);
+ add_kw("for", kw_for, F_STMT);
+ add_kw("do", kw_do, F_STMT);
+ add_kw("enum", kw_enum, F_STMT | F_TOP);
+ add_kw("include", kw_include, F_TOP | F_STMT);
+ add_kw("embed", kw_embed, F_TOP | F_STMT);
+ add_kw("run.method", kw_method, F_TOP | F_STMT);
+ add_kw("run.share_value", kw_share_value, F_EXPR);
+ add_kw("run.syntax", kw_syntax, F_TOP | F_STMT);
+ add_kw("run.statement_hook", kw_statement_hook, F_TOP | F_STMT);
+ add_kw("memdebug", kw_memdebug, F_STMT | F_TOP);
+ add_kw("hints", kw_hints, F_STMT | F_TOP);
+ add_kw("switch", kw_switch, F_STMT);
+ add_kw("break", kw_break, F_STMT);
+ add_kw("continue", kw_continue, F_STMT);
+ add_kw("return", kw_return, F_STMT);
+ add_kw("unchecked", kw_unchecked, F_STMT);
+ add_kw("asm", kw_asm, F_STMT | F_EXPR);
+ add_kw("quote", kw_quote, F_EXPR);
+ add_kw("sizeof", kw_sizeof, F_EXPR);
+ add_kw("typeof", kw_typeof, F_EXPR);
+ add_kw("extern", kw_extern, F_TOP);
+ add_kw("cfunc", kw_cfunc, F_EXPR);
+ add_kw("o3", kw_o3, F_STMT);
+ add_kw("len", kw_len, F_EXPR);
+ add_kw("cap", kw_cap, F_EXPR);
+ add_kw("push", kw_push, F_EXPR);
+ add_kw("pop", kw_pop, F_EXPR);
+ add_kw("resize", kw_resize, F_EXPR);
+ return 0;
+}
+// the default map's type records sit in the last 16384 words of the heap.
+// the type list is the first words of that range, so it cannot be kept aside
+// as a buddy block: types_init would overwrite the header and the allocator
+// would hand the range out again. cut the heap off at R_TY until the unit
+// has been compiled, then put the tail back for the program.
+int heldk;
+// the size class of the type area, for the memory map.
+int type_class() {
+ int k = 0, n = R_TYEND - R_TY;
+ while (k < 31 && rt.pow2[k] < n) k++;
+ if (rt.pow2[k] != n) return 0 - 1;
+ return k;
+}
+// keep the type area out of the collector's reach while it is in use.
+int shield_types() {
+ int k;
+ heldk = 0 - 1;
+ if (R_TY <= rt.HEAP_LO || R_TY >= rt.HEAP_HI || R_TYEND > rt.HEAP_HI) return 0;
+ k = type_class();
+ if (k < 0) return 0;
+ if (R_TY + rt.pow2[k] != R_TYEND) return 0;
+ if (rt.heap_reset(R_TY)) heldk = k;
+ return 0;
+}
+// let the collector see the type area again.
+int unshield_types() {
+ if (heldk >= 0) { rt.heap_uncut(R_TY, heldk); heldk = 0 - 1; }
+ return 0;
+}
+// the genome's entry point, run when the image boots: set up the heap and
+// the compiler, then either run the language server (a genome that carries it)
+// or compile the unit on stdin, collect the garbage that compiling made, and
+// call main().
+int start() {
+ int s, f;
+ rt.heap_init(); chk_heap = 1;
+ shield_types();
+ zc_init();
+ blob_load(rt.GORG[5], 0);
+ zc_tables();
+ types_init();
+ here = 0; hdelta = 0; hlimit = rt.CODE_END; ptop = 0;
+ ubase = nsym; vislo = 0;
+ // a genome that carries the language server runs it instead of compiling stdin
+ s = lookup(intern("lsp.lsp_main"));
+ if (s >= 0 && skind[s] == K_FN && (sflag[s] & F_DEF)) { f = sval[s]; f(); rt.halt(); }
+ unit_stdin();
+ if (here > ptop) ptop = here;
+ rt.scrub(); // compilation's stale words would keep quarantined blocks alive
+ rt.gc();
+ // the type area stays out of the allocator. main() may compile again
+ // (the self-host does) and a later new() would otherwise reuse it.
+ if (mdbg_flags) rt.mem_set(mdbg_flags);
+ // a unit that carries src/lib/std.zc has a libinit to fill argc/argv/envc/envp
+ // with. it runs before main, the same way lsp_main runs instead of stdin.
+ s = lookup(intern("std.libinit"));
+ if (s >= 0 && skind[s] == K_FN && (sflag[s] & F_DEF)) { f = sval[s]; f(); }
+ s = lookup(s_main);
+ if (s >= 0 && skind[s] == K_FN && (sflag[s] & F_DEF)) { f = sval[s]; f(); }
+ rt.halt();
+ return 0;
+}
+