aboutsummaryrefslogtreecommitdiff
path: root/src/tools/zc0.c
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-14 15:52:01 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-14 15:52:01 +0330
commit7c54e48bca711a6596be4bb17fcaa4330b9928e3 (patch)
treefd426755976847e368fe298db1c7c757f58799b9 /src/tools/zc0.c
parenttodo: record each agent's state at the end of the session and the merge order (diff)
line tables and backtraces: port agent/line-tables onto main, op 56 on the x86-64 jit, docs, measurements, tests; default genome reservation 0x68000
Diffstat (limited to 'src/tools/zc0.c')
-rw-r--r--src/tools/zc0.c65
1 files changed, 63 insertions, 2 deletions
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++) {