// selfhost/cmd/w6c/main.ww — port of cmd/w6c/main.c. // // w6c = amd64 compiler. Read .ww, parse, codegen, emit Plan 9 amd64 // asm to stdout (or the file given by -o). // // w6c_ww -o file.s file.ww // // The cgen routines in selfhost/cmd/wcc/cgen.ww write directly to // fd 1 via os.write(1, ...). For -o, we open the output file and // dup2 it onto fd 1 before invoking cgfile. This is the same trick // the bootstrap uses with shell redirection, just in-process. package main; import os; import mem; import tok; import lex; import ast; import parse; import typ; import sym; import check; import cgen; fn cstreq(a: *u8, lit: str) bool = { let n: u64 = lit.len: u64; let i: u64 = 0u64; for (i < n) { let li: i32 = i: i32; if (a[i] != lit[li]) { return false; }; i += 1u64; }; if (a[i] != 0u8) { return false; }; return true; }; fn cstrlen(p: *u8) u64 = { let n: u64 = 0u64; for (p[n] != 0u8) { n += 1u64; }; return n; }; // pathstr — view a NUL-terminated *u8 as a str. lib/os entrypoints // take str post-task-#23; this bridges call sites that still hold // C-string paths (argv entries, arena-allocated buffers). fn pathstr(p: *u8) str = { let r: str; r.ptr = p; r.len = cstrlen(p): i32; return r; }; fn slurp(path: *u8) (*u8, u64) = { let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32); if (fd < 0) { return nil, 0u64; }; let szr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = 0i64; match (szr) { case let v: i64 => n = v; case let e: os.oserror => { os.close(fd); return nil, 0u64; }; }; let nz: u64 = n: u64; let buf: *u8 = os.alloc(nz + 1u64): *u8; let rr: (i64 | os.oserror) = os.readall(fd, buf, nz); os.close(fd); let got: i64 = 0i64; match (rr) { case let v: i64 => got = v; case let e: os.oserror => return nil, 0u64; }; if (got != n) { return nil, 0u64; }; buf[nz] = 0u8; return buf, nz; }; export fn main(argc: i32, argv: **u8) i32 = { let src: *u8 = nil; let out: *u8 = nil; let i: i32 = 1; for (i < argc) { let a: *u8 = argv[i]; if (cstreq(a, "-o")) { i += 1; if (i >= argc) { os.write(2, "w6c: -o requires arg\n".ptr, 20u64); return 2; }; out = argv[i]; } else { if (a[0u64] == 45u8) { os.write(2, "w6c: unknown flag\n".ptr, 17u64); return 2; } else { if (src != nil) { os.write(2, "w6c: only one input\n".ptr, 19u64); return 2; }; src = a; }; }; i += 1; }; if (src == nil) { os.write(2, "usage: w6c_ww [-o out.s] file.ww\n".ptr, 32u64); return 2; }; let buf: *u8; let blen: u64; buf, blen = slurp(src); if (buf == nil) { os.write(2, "w6c: cannot read input\n".ptr, 22u64); return 1; }; // Redirect fd 1 to the output file before any cgen emit runs. // cgen.ww writes directly to fd 1; dup2 lets us reuse it without // threading a file descriptor through the emit helpers. if (out != nil) { let ofd: i32 = os.open(pathstr(out), os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644 if (ofd < 0) { os.write(2, "w6c: cannot open output\n".ptr, 23u64); return 1; }; if (os.dup2(ofd, 1i32) < 0) { os.write(2, "w6c: dup2 failed\n".ptr, 16u64); os.close(ofd); return 1; }; os.close(ofd); }; let ar: *arena = newarena(); let nlen: u64 = cstrlen(src); let fname: str = astrndup(ar, src, nlen); let l: lex; lexinit(&l, ar, fname, buf, blen); let ps: parser; parserinit(&ps, ar, &l); let f: *node = parsefile(&ps); let cg: cgen; cgeninit(&cg, ar); cgfile(&cg, f); if (l.errs > 0) { return 1; }; return 0; };