code wiki / (root) / main.nx

main.nx source

↩ module page · 84 lines · 3203 B

1// main.nx -- NishiLang-side compiler driver. 2// 3// Pipeline: source text -> lex -> parse -> opt -> regalloc -> riscv 4// -> write-to-stdout. Stands in for main.c. Real source-file reading 5// (openat + read + grow buffer) is a follow-up; this turn drives the 6// pipeline from an in-memory source string so the whole stack of 7// nx-side modules links cleanly through a single entry point. 8// 9// Once file I/O is in syscalls.nx and string concatenation lands, this 10// driver becomes the authoritative NishiLang compiler -- the C nxc2 11// retires behind it. 12 13import "syscalls.nx" 14import "types.nx" 15import "lex_kinds.nx" 16import "ir.nx" 17import "lex.nx" 18import "parse.nx" 19import "opt.nx" 20import "regalloc.nx" 21import "riscv.nx" 22 23// Compile one source string end-to-end, emit asm to stdout. Each 24// function gets opt_run + regalloc + emit_function. Output format 25// matches the C-side backend's .s output closely enough that a nxasm 26// pass can assemble it to ELF. 27func compile(src: *u8) -> i64 { 28 let toks: *Tok = lex_source(src, 4096) 29 if toks == (0 as *Tok) { return 1 } 30 31 let m: *Module = parse_module(toks, 0 as *Module) 32 if m == (0 as *Module) { return 2 } 33 34 let o: *OutBuf = out_new(65536) 35 out_str(o, "# Auto-generated by nxc2.nx (NishiLang-side driver).\n") 36 37 var fi: i64 = 0 38 while fi < m.n_functions { 39 let fn_base: i64 = m.functions as i64 40 let f: *Function = (fn_base + fi * 176) as *Function 41 42 opt_run(f) 43 44 let locs_raw: *u8 = sys_mmap(f.n_values * 24 + 64) 45 let locs: *ValueLoc = locs_raw as *ValueLoc 46 47 let cs_raw: *u8 = sys_mmap(16) 48 let cs: *i64 = cs_raw as *i64 49 *cs = 0 50 let cs_fpr_raw: *u8 = sys_mmap(16) 51 let cs_fpr: *i64 = cs_fpr_raw as *i64 52 *cs_fpr = 0 53 54 let sb_raw: *u8 = sys_mmap(16) 55 let sb: *i64 = sb_raw as *i64 56 *sb = 0 57 58 regalloc_function(f, locs, cs, cs_fpr, sb) 59 60 // Real function name: ir_function_new stashed the *u8 name 61 // pointer in f.name_start so the driver can emit `name:` as 62 // the label instead of the hardcoded "main". Frame size + 63 // ra slot are still stubbed (16/8); per-function layout is 64 // a follow-up that threads the regalloc result through. 65 let fn_name_addr: i64 = f.name_start 66 let fn_name: *u8 = fn_name_addr as *u8 67 emit_function(f, locs, o, fn_name, 16, 8, *cs, *cs_fpr) 68 fi = fi + 1 69 } 70 71 sys_write(1, o.buf, o.pos) 72 return 0 73} 74 75func main() -> i64 { 76 // Real NishiLang source covering the breadth of what the 77 // nx-side front-end handles: syscall intrinsic, const folding, 78 // for-loop, function call. The resulting IR exercises every 79 // critical path (lex → parse_module → parse_primary w/ __syscall 80 // → ir_emit_syscall → opt_run → regalloc_function → rv emit w/ 81 // OP_SYSCALL → ecall). 82 let src: *u8 = "const N: i64 = 5\nfunc add(a: i64, b: i64) -> i64 { return a + b }\nfunc main() -> i64 { var acc: i64 = 0\nfor i in 0..N { acc = add(acc, i) }\nreturn __syscall(93, acc, 0, 0, 0, 0, 0) }" 83 return compile(src) 84}