code wiki / _hdl_build / nx_eoe_fn.nx

nx_eoe_fn.nx source

↩ module page · 162 lines · 9436 B

1// nx_eoe_fn.nx -- EMITTER-OF-EMITTERS, GENERALITY RUNG 6: FUNCTIONS + CALL STACK. 2// 3// Rung 5 (006j, nx_eoe_prog) gave the mini-language compositional control flow 4// (nested op/if/while) but a single straight-line main(). This rung gives it a 5// CALL STACK: the spec can DEFINE named functions and CALL them, including functions 6// that call OTHER functions (a real >=2-deep call graph), so emitted programs 7// COMPOSE reusable logic instead of inlining everything. Each function is an 8// acc-transformer `func name(p) -> i64 { var acc = p; <body>; return acc }`; a call 9// is `acc = name(acc)`. Bodies use the full rung-5 grammar (op/if/while) PLUS call, 10// recursively. nx_cc compiles the defs + the call ABI (frames/return) -- delegated 11// to the compiler the team owns. 12// 13// nx_eoe_fn <basename> <start> [def <name> [ <stmt...> ]]... [main] <stmt...> 14// stmt grammar (extends 006j): a<n>|m<n>|s<n> | if <pred> [..] | while <pred> [..] 15// | call <name> (acc = name(acc)) 16// top level: zero or more `def <name> [ <body> ]`, then optional `main`, then the 17// main statement list. `[` `]` are their own tokens; everything NESTS. 18// -> emits the func defs (in spec order; a def may call an EARLIER def) + main(). 19// 20// no-false-green (X-AUT-006d): a function calling a function (quad=dbl(dbl(p))) 21// exercises a 2-deep stack; tampering the INNER function's body changes the final 22// result THROUGH the nested call -- proving the call ABI really threads values, not 23// a templated constant. Sovereign, no gcc/.sh. HONEST: one i64 param/return per 24// fn (acc-transformer convention), one-armed if, int ops; not yet multi-param/typed 25// /imports. ONE rung -- but the language now has FUNCTIONS. license_tier: ORIGINAL 26import "nx_syscalls.nx" 27const K_MAGIC_262144: i64 = 262144 28 29func efn_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[off+i] = s[i]; i = i + 1 } return off + i } 30func efn_catn(dst: *u8, off: i64, v: i64) -> i64 { 31 var o: i64 = off 32 if v < 0 { dst[o] = 45 as u8; o = o + 1; return efn_catn(dst, o, 0 - v) } 33 if v == 0 { dst[o] = 48 as u8; return o + 1 } 34 var m: i64 = v 35 let t: *u8 = sys_mmap(28) 36 var k: i64 = 0 37 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 38 var i: i64 = 0 39 while i < k { dst[o+i] = t[k-1-i]; i = i + 1 } 40 return o + k 41} 42func efn_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 43func efn_atoi_from(s: *u8, from: i64) -> i64 { 44 var n: i64 = 0; var i: i64 = from 45 while s[i] != (0 as u8) { if s[i] >= (48 as u8) { if s[i] <= (57 as u8) { n = n * 10 + ((s[i] as i64) - 48) } } i = i + 1 } 46 return n 47} 48func efn_indent(buf: *u8, off: i64, depth: i64) -> i64 { 49 var o: i64 = off; var d: i64 = 0 50 while d < depth { o = efn_cat(buf, o, " " as *u8); d = d + 1 } 51 return o 52} 53func efn_cmp(buf: *u8, off: i64, pred: *u8) -> i64 { 54 var o: i64 = off 55 let pc: i64 = pred[0] as i64 56 if pc == 103 { o = efn_cat(buf, o, "> " as *u8) } 57 if pc == 108 { o = efn_cat(buf, o, "< " as *u8) } 58 if pc == 101 { o = efn_cat(buf, o, "== " as *u8) } 59 o = efn_catn(buf, o, efn_atoi_from(pred, 1)) 60 return o 61} 62 63// recursive descent (extends 006j eop_emit_stmts with the `call` statement). 64func efn_emit_stmts(buf: *u8, off: i64, argv: *i64, argc: i64, ti: i64, depth: i64, out_ti: *i64, gid: *i64) -> i64 { 65 var o: i64 = off 66 var i: i64 = ti 67 while i < argc { 68 let tok: *u8 = argv[i] as *u8 69 let c0: i64 = tok[0] as i64 70 if c0 == 93 { i = i + 1; out_ti[0] = i; return o } // ']' end block 71 if c0 == 97 { // 'a' add 72 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "acc = acc + " as *u8); o = efn_catn(buf, o, efn_atoi_from(tok, 1)); o = efn_cat(buf, o, "\n" as *u8); i = i + 1 73 } else { if c0 == 109 { // 'm' mul 74 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "acc = acc * " as *u8); o = efn_catn(buf, o, efn_atoi_from(tok, 1)); o = efn_cat(buf, o, "\n" as *u8); i = i + 1 75 } else { if c0 == 115 { // 's' sub 76 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "acc = acc - " as *u8); o = efn_catn(buf, o, efn_atoi_from(tok, 1)); o = efn_cat(buf, o, "\n" as *u8); i = i + 1 77 } else { if c0 == 99 { // 'c' call <name> -> acc = name(acc) 78 let nm: *u8 = argv[i+1] as *u8 79 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "acc = " as *u8); o = efn_cat(buf, o, nm); o = efn_cat(buf, o, "(acc)\n" as *u8); i = i + 2 80 } else { if c0 == 105 { // 'i' if 81 let pred: *u8 = argv[i+1] as *u8 82 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "if acc " as *u8); o = efn_cmp(buf, o, pred); o = efn_cat(buf, o, " {\n" as *u8) 83 let nti: *i64 = sys_mmap(8) as *i64 84 o = efn_emit_stmts(buf, o, argv, argc, i + 3, depth + 1, nti, gid) 85 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "}\n" as *u8) 86 i = nti[0] 87 } else { if c0 == 119 { // 'w' while 88 let pred: *u8 = argv[i+1] as *u8 89 let myid: i64 = gid[0]; gid[0] = gid[0] + 1 90 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "var g" as *u8); o = efn_catn(buf, o, myid); o = efn_cat(buf, o, ": i64 = 0\n" as *u8) 91 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "while acc " as *u8); o = efn_cmp(buf, o, pred); o = efn_cat(buf, o, " {\n" as *u8) 92 let nti: *i64 = sys_mmap(8) as *i64 93 o = efn_emit_stmts(buf, o, argv, argc, i + 3, depth + 1, nti, gid) 94 o = efn_indent(buf, o, depth + 1); o = efn_cat(buf, o, "g" as *u8); o = efn_catn(buf, o, myid); o = efn_cat(buf, o, " = g" as *u8); o = efn_catn(buf, o, myid); o = efn_cat(buf, o, " + 1\n" as *u8) 95 o = efn_indent(buf, o, depth + 1); o = efn_cat(buf, o, "if g" as *u8); o = efn_catn(buf, o, myid); o = efn_cat(buf, o, " >= 100000 { break }\n" as *u8) 96 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "}\n" as *u8) 97 i = nti[0] 98 } else { i = i + 1 } } } } } } 99 } 100 out_ti[0] = i 101 return o 102} 103 104func main(argc: i64, argv: *i64) -> i64 { 105 if argc < 3 { efn_p("usage: nx_eoe_fn <basename> <start> [def <name> [ stmts ]]... [main] <stmts>\n" as *u8); return 2 } 106 let base: *u8 = argv[1] as *u8 107 let start: i64 = efn_atoi_from(argv[2] as *u8, 0) 108 109 let path: *u8 = sys_mmap(512) 110 var po: i64 = 0 111 po = efn_cat(path, po, "runtime/_hdl_build/" as *u8) 112 po = efn_cat(path, po, base) 113 po = efn_cat(path, po, ".nx" as *u8) 114 path[po] = 0 as u8 115 116 let buf: *u8 = sys_mmap(K_MAGIC_262144) 117 var o: i64 = 0 118 o = efn_cat(buf, o, "// GENERATED BY nx_eoe_fn (emitter-of-emitters, functions+call-stack) -- defs + calls synthesized from a DATA spec, compiled by nx_cc. license_tier: ORIGINAL\n" as *u8) 119 o = efn_cat(buf, o, "import \"nx_syscalls.nx\"\n" as *u8) 120 121 let gid: *i64 = sys_mmap(8) as *i64; gid[0] = 0 122 let nti: *i64 = sys_mmap(8) as *i64 123 124 // ---- emit function defs (top-level `def <name> [ body ]`, spec order) ---- 125 var ti: i64 = 3 126 var more: i64 = 1 127 while more == 1 { 128 if ti >= argc { more = 0 } else { 129 let tok: *u8 = argv[ti] as *u8 130 if (tok[0] as i64) == 100 { // 'd' def 131 let nm: *u8 = argv[ti+1] as *u8 132 o = efn_cat(buf, o, "func " as *u8); o = efn_cat(buf, o, nm); o = efn_cat(buf, o, "(p: i64) -> i64 {\n var acc: i64 = p\n" as *u8) 133 o = efn_emit_stmts(buf, o, argv, argc, ti + 3, 1, nti, gid) // body after 'def' name '[' 134 o = efn_cat(buf, o, " return acc\n}\n" as *u8) 135 ti = nti[0] 136 } else { more = 0 } 137 } 138 } 139 // optional `main` separator token 140 if ti < argc { let mt: *u8 = argv[ti] as *u8; if (mt[0] as i64) == 109 { if (mt[1] as i64) == 97 { ti = ti + 1 } } } 141 142 // ---- emit main() ---- 143 o = efn_cat(buf, o, "func main() -> i64 {\n var acc: i64 = " as *u8); o = efn_catn(buf, o, start); o = efn_cat(buf, o, "\n" as *u8) 144 o = efn_emit_stmts(buf, o, argv, argc, ti, 1, nti, gid) 145 o = efn_cat(buf, o, " sys_write(1, \"RESULT=\" as *u8, 7)\n" as *u8) 146 o = efn_cat(buf, o, " var mm: i64 = acc\n" as *u8) 147 o = efn_cat(buf, o, " if mm < 0 { sys_write(1, \"-\" as *u8, 1); mm = 0 - mm }\n" as *u8) 148 o = efn_cat(buf, o, " let t: *u8 = sys_mmap(28)\n" as *u8) 149 o = efn_cat(buf, o, " var k: i64 = 0\n" as *u8) 150 o = efn_cat(buf, o, " if mm == 0 { t[0] = 48 as u8; k = 1 }\n" as *u8) 151 o = efn_cat(buf, o, " while mm > 0 { t[k] = (48 + (mm % 10)) as u8; mm = mm / 10; k = k + 1 }\n" as *u8) 152 o = efn_cat(buf, o, " while k > 0 { k = k - 1; sys_write(1, (((t as i64)+k) as *u8), 1) }\n" as *u8) 153 o = efn_cat(buf, o, " sys_write(1, \"\\n\" as *u8, 1)\n" as *u8) 154 o = efn_cat(buf, o, " return 0\n}\n" as *u8) 155 156 let fd: i64 = sys_openat_wr(path, 420) 157 if fd < 0 { efn_p("EOEFN verdict=RED reason=out-unwritable\n" as *u8); return 1 } 158 sys_write(fd, buf, o) 159 sys_close(fd) 160 efn_p("EOEFN name=" as *u8); efn_p(path); efn_p(" verdict=EMITTED\n" as *u8) 161 return 0 162}