diff options
| author | 2026-10-14 15:54:04 +0330 | |
|---|---|---|
| committer | 2026-10-14 15:54:04 +0330 | |
| commit | 0879d0a42d137054057cd2a1e37437e6be78ed0b (patch) | |
| tree | fcb16d3185c1f80fae8d54cd9062bd68d6c0c88d /src/tools | |
| parent | merge spec conformance suite (diff) | |
| parent | merge main into work/line-tables (diff) | |
merge line tables
Diffstat (limited to 'src/tools')
| -rwxr-xr-x | src/tools/automap.sh | 14 | ||||
| -rw-r--r-- | src/tools/build.zc | 3 | ||||
| -rw-r--r-- | src/tools/genmap.c | 2 | ||||
| -rwxr-xr-x | src/tools/parity.sh | 4 | ||||
| -rw-r--r-- | src/tools/zc0.c | 65 |
5 files changed, 82 insertions, 6 deletions
diff --git a/src/tools/automap.sh b/src/tools/automap.sh index ff559ac..b4aceb7 100755 --- a/src/tools/automap.sh +++ b/src/tools/automap.sh @@ -35,8 +35,18 @@ lay() { # $1 = genome slot, or empty for the preset's own $CC -O1 -w -fwrapv src/tools/zc0.c -I"$O/map" -Isrc/core -o "$ZC0" $CC -O1 -w -fwrapv src/tools/mkgenome.c -I"$O/map" -o "$O/.mkgenome" } +# the files after the map's own. a run-only image gets line tables for its program (so a fault +# prints a backtrace): zc0 reads the comment //:lines NAME as "from here on, file NAME, count +# its lines from the next one". the files under src/ are the runtime's and have none. +feed() { + local f + for f in "$@"; do + if [ "$P" = run ]; then case "$f" in src/*) ;; *) printf '\n//:lines %s\n' "$f" ;; esac; fi + cat "$f" + done +} build() { - if [ -f "$O/map/compiler.zc" ]; then cat "$O/map/rt.zc" src/core/core.zc "$O/map/compiler.zc" "$@"; else cat "$O/map/rt.zc" src/core/core.zc "$@"; fi | "$ZC0" > "$O/image.bin" + if [ -f "$O/map/compiler.zc" ]; then { cat "$O/map/rt.zc" src/core/core.zc "$O/map/compiler.zc"; feed "$@"; }; else { cat "$O/map/rt.zc" src/core/core.zc; feed "$@"; }; fi | "$ZC0" > "$O/image.bin" "$O/.mkgenome" < "$O/image.bin" > "$O/genome.bin" } # with DOCS=1 the genome is made again with zc0 built for docs (ZC0DOCS), so the @@ -44,7 +54,7 @@ build() { # docofs(). the image is the same code either way; the docs are stored after it. docs() { $CC -O1 -w -fwrapv -DZC0DOCS src/tools/zc0.c -I"$O/map" -Isrc/core -o "$O/.zc0docs" - if [ -f "$O/map/compiler.zc" ]; then cat "$O/map/rt.zc" src/core/core.zc "$O/map/compiler.zc" "$@"; else cat "$O/map/rt.zc" src/core/core.zc "$@"; fi | "$O/.zc0docs" > "$O/image.bin" + if [ -f "$O/map/compiler.zc" ]; then { cat "$O/map/rt.zc" src/core/core.zc "$O/map/compiler.zc"; feed "$@"; }; else { cat "$O/map/rt.zc" src/core/core.zc; feed "$@"; }; fi | "$O/.zc0docs" > "$O/image.bin" "$O/.mkgenome" < "$O/image.bin" > "$O/genome.bin" } len() { echo $(( $(wc -c < "$1") / 8 )); } diff --git a/src/tools/build.zc b/src/tools/build.zc index b0e3da0..b628a33 100644 --- a/src/tools/build.zc +++ b/src/tools/build.zc @@ -6,6 +6,9 @@ include rt, run; docs on; +// the genome has no line tables: its code is the runtime's and the compiler's, and a program +// built into an image turns them on for itself (lines on;) +lines off; // writes the compiled genome image to stdout as little-endian 64-bit words. int main() { int n = run.build_image_grow(rt.GORG, 4096), i = 0, w; diff --git a/src/tools/genmap.c b/src/tools/genmap.c index d515778..6d8db55 100644 --- a/src/tools/genmap.c +++ b/src/tools/genmap.c @@ -242,7 +242,7 @@ static void preset_default(Spec *s) s->compiler = 1; s->heap_top = 1; s->code_end = 0x80000; s->types = 65536; s->heap = 0x60000; s->total = 0x8000000; - s->genome = 0x60000; s->frame = 0x40000; s->ret = 0x10000; s->mark = 0x8000; + s->genome = 0x68000; s->frame = 0x40000; s->ret = 0x10000; s->mark = 0x8000; s->data = 0x7FF0; tables_big(s); } diff --git a/src/tools/parity.sh b/src/tools/parity.sh index 00245a8..2b9b870 100755 --- a/src/tools/parity.sh +++ b/src/tools/parity.sh @@ -63,7 +63,9 @@ KNOWN=tests/parity.known mkdir -p "$W" # what every image starts with, and how many lines that is (zc0 counts from the top) SRCS="src/runtime/rt.zc src/core/core.zc src/runtime/run.zc" -{ cat $SRCS; echo 'namespace;'; } > "$W/prefix.new" +# the marker turns zc0's line tables on for the program, named <stdin> as under zy, so faults +# and rt.trace() print the same backtrace on both sides (src/tools/automap.sh does the same) +{ cat $SRCS; echo 'namespace;'; echo '//:lines <stdin>'; } > "$W/prefix.new" if cmp -s "$W/prefix.new" "$W/prefix.zc"; then rm "$W/prefix.new"; else mv "$W/prefix.new" "$W/prefix.zc"; fi nprefix=$(wc -l < "$W/prefix.zc") # what the compiled image depends on besides the program diff --git a/src/tools/zc0.c b/src/tools/zc0.c index 040a4ea..5846e22 100644 --- a/src/tools/zc0.c +++ b/src/tools/zc0.c @@ -73,6 +73,13 @@ static int esc(void) switch (c) { case 'n': return 10; case 't': return 9; case 'r': return 13; case '0': return 0; case 'e': return 27; } return c; } +/* line tables, as the self-hosted compiler makes them with lines on (see rt.line_blocks in rt.zc). + they are off until a program says lines on; or a marker comment //:lines NAME comes by, which + src/tools/automap.sh puts in front of the program of a run-only image: it turns them on, names + the file, and counts the lines from the next one. */ +static int zl_on, zl_base, zl_head, zl_entry, zl_open, zl_fline, zl_file_at, zl_n, zl_cap; +static char zl_file[256] = "<stdin>", zl_file_done[256], zl_name[64]; +static int64_t *zl_pairs; /* doc comments, as the self-hosted compiler reads them with docs on: the // lines directly above a declaration, up to a blank line or any other text */ static char dbuf[2100], dsnap[2100], dnm[64]; static int dn, dlast, dline, dsn, docpending; @@ -82,7 +89,15 @@ static void doccomment(void) /* pos is on the first slash */ while (k >= 0 && (src[k] == ' ' || src[k] == '\t')) k--; bol = k < 0 || src[k] == '\n'; pos += 2; - if (src[pos] == ':') { dn = 0; dlast = cl; docpending = 0; while (src[pos] && src[pos] != '\n') pos++; return; } + if (src[pos] == ':') { + if (!strncmp(src + pos, ":lines ", 7)) { + int n = 0; + pos += 7; + while (src[pos] && src[pos] != '\n' && src[pos] != '\r' && n < 255) zl_file[n++] = src[pos++]; + zl_file[n] = 0; zl_on = 1; zl_base = cl; + } + dn = 0; dlast = cl; docpending = 0; while (src[pos] && src[pos] != '\n') pos++; return; + } if (!bol) { while (src[pos] && src[pos] != '\n') pos++; return; } if (dn && dlast != cl - 1) dn = 0; if (src[pos] == ' ') pos++; @@ -500,6 +515,42 @@ static int bstrwords(const unsigned char *b, long n) if ((n & 7) == 0) emit(0); return a; } +/* line tables. zl_begin starts recording the function whose code begins at entry, zl_stmt notes + that a statement starts at the current line, and zl_end puts the function's line block among + the code, as lt_end does in the resident compiler: [next, entry, end, name, file, count, then + count words of offset << 32 | line]. */ +static void zl_begin(int entry, const char *name, int fline) +{ + if (!zl_on) { zl_open = 0; return; } + zl_open = 1; zl_entry = entry; zl_n = 0; zl_fline = fline - zl_base; + strncpy(zl_name, name, 63); zl_name[63] = 0; + if (zl_n == zl_cap) { zl_cap = zl_cap ? zl_cap * 2 : 1024; zl_pairs = realloc(zl_pairs, (size_t)zl_cap * sizeof *zl_pairs); } + zl_pairs[zl_n++] = zl_fline; +} +static void zl_stmt(void) +{ + int off = here - zl_entry; + if (!zl_open) return; + if (zl_n == zl_cap) { zl_cap *= 2; zl_pairs = realloc(zl_pairs, (size_t)zl_cap * sizeof *zl_pairs); } + if (zl_n && (zl_pairs[zl_n - 1] >> 32) == off) zl_n--; + if (zl_n && (zl_pairs[zl_n - 1] & 0xffffffffLL) == line - zl_base) return; + zl_pairs[zl_n++] = (int64_t)off * 4294967296LL + (line - zl_base); +} +static void zl_end(void) +{ + int end = here, name, file, blk, i; + if (!zl_open) return; + zl_open = 0; + name = bstrwords((const unsigned char *)zl_name, (long)strlen(zl_name)); + if (!zl_file_at || strcmp(zl_file, zl_file_done)) { + zl_file_at = bstrwords((const unsigned char *)zl_file, (long)strlen(zl_file)); strcpy(zl_file_done, zl_file); + } + file = zl_file_at; + blk = here; + emit(zl_head); emit(zl_entry); emit(end); emit(name); emit(file); emit(zl_n); + for (i = 0; i < zl_n; i++) emit(zl_pairs[i]); + zl_head = blk; +} /* b"...": the words inline, jumped over, then the address pushed */ static void bstrlit(void) { @@ -691,6 +742,7 @@ static void patchbreaks(void) { int i; for (i = 0; i < nbrk[nloop]; i++) setlit( static void stmt(void) { int a, b, c, d; + zl_stmt(); if (accept(";")) return; if (is("{")) { block(); return; } { @@ -759,7 +811,7 @@ static void stmt(void) /* ---- top level ---- */ static void fndef(int ret, int rstr) /* rstr: the return type is bstr */ { - char *n = ident(); Sym *s; int np = 0, tags = 0, t, frame, i, helper, busy, done, check, node; + char *n = ident(); int zfl = line; Sym *s; int np = 0, tags = 0, t, frame, i, helper, busy, done, check, node; if (dsn && !dnm[0]) strcpy(dnm, n); char pn[16][64]; int pstr[16]; char full_name[256]; qualify(full_name, sizeof full_name, n); s = find_raw(full_name); @@ -794,6 +846,7 @@ static void fndef(int ret, int rstr) /* rstr: the return type is bstr */ } #endif nlo = 0; nslot = 0; nepi = 0; infn = 1; + zl_begin(here, s->name, zfl); for (i = 0; i < np; i++) { strcpy(lo[nlo].name, pn[i]); lo[nlo].arr = 0; lo[nlo].flt = 0; lo[nlo].dstr = lo[nlo].str = pstr[i & 15]; lo[nlo++].slot = nslot++; } /* retain the caller's pointer until the frame has its final segment. */ helper = !find("frame_busy") || !strcmp(s->name, "rt.frame_grow") || !strcmp(s->name, "rt.frame_leave"); @@ -823,6 +876,7 @@ static void fndef(int ret, int rstr) /* rstr: the return type is bstr */ op(O_RET); setlit(frame, nslot); infn = 0; + zl_end(); } /* enhance name(params) [-> n] micro "recipe"; or ... vm { asm }; emits the install descriptor; the booted genome installs it */ @@ -953,6 +1007,11 @@ static void top1(void) expect(";"); return; } if (accept("include")) { do { ident(); } while (accept(",")); expect(";"); return; } + if (is("lines")) { /* lines on; and lines off; (anything else is a name) */ + Lex L; lexsave(&L); next(); + if (is("on") || is("off")) { zl_on = is("on"); next(); expect(";"); return; } + lexrest(&L); + } if (accept("embed")) { embeddecl(0); return; } { if (accept("unchecked")) { top1(); return; } @@ -1088,6 +1147,8 @@ int main(int argc, char **argv) setlit(fx[i].at, s->val); } if (!(st = find("start")) || !st->defd) { fprintf(stderr, "zc0: no start\n"); return 1; } + /* the line tables are reached through rt.line_blocks, which starts out as the newest block */ + if (zl_head && (st = find_raw("rt.line_blocks"))) img[st->val - GORG] = zl_head; /* symbol blob: kind, value, sig, name chars, 0 ... then a 0 kind */ img[5] = here; for (i = 0; i < nsy; i++) { |
