build: separate package identity from storage paths

This commit is contained in:
2026-08-13 05:37:56 +09:00
parent 5f0f544157
commit c3df0afeb0
11 changed files with 1167 additions and 505 deletions

View File

@@ -50,16 +50,20 @@ a_intern(Asm *a, const char *name)
return s;
}
/* line iterator: returns the next line as a NUL-terminated buffer in
* line/llen pointers, advances pos. Returns 0 on EOF.
*/
static int
nextline(Asm *a, char **line, size_t *llen, char *buf, size_t bufsz)
nextline(Asm *a, char **line, size_t *llen)
{
if (a->pos >= a->srclen) return 0;
size_t n = 0;
while (a->pos < a->srclen && a->src[a->pos] != '\n' && n + 1 < bufsz)
buf[n++] = a->src[a->pos++];
u64 start = a->pos;
while (a->pos < a->srclen && a->src[a->pos] != '\n') a->pos++;
size_t n = (size_t)(a->pos - start);
char *buf = malloc(n + 1);
if (buf == NULL) {
err(a, "out of memory");
a->pos = a->srclen;
return 0;
}
memcpy(buf, a->src + start, n);
buf[n] = '\0';
if (a->pos < a->srclen && a->src[a->pos] == '\n') a->pos++;
*line = buf;
@@ -206,10 +210,13 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
}
if (a_isidstart((unsigned char)*s)) {
char buf[256] = {0};
int n = 0;
while (a_isidcont((unsigned char)*s) && n < 255) buf[n++] = *s++;
buf[n] = 0;
const char *start = s;
while (a_isidcont((unsigned char)*s)) s++;
size_t n = (size_t)(s - start);
char *name = malloc(n + 1);
if (name == NULL) { err(a, "out of memory"); return -1; }
memcpy(name, start, n);
name[n] = 0;
/* Optional `+disp` between the ident and `(SB)`. Used by
* DATAR to address bytes inside an existing .data slot
@@ -227,12 +234,16 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
int rn = 0;
s++;
while (*s && *s != ')' && rn < 7) rbuf[rn++] = *s++;
if (*s != ')') { err(a, "missing ')'"); return -1; }
if (*s != ')') {
err(a, "missing ')'");
free(name);
return -1;
}
s++;
int r = reg_lookup(rbuf);
if (r == D_PSB) {
out->type = D_EXTERN;
out->sym = strdup(buf);
out->sym = name;
out->offset = sym_disp;
return 0;
}
@@ -241,16 +252,18 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
* reg_lookup and silently discarded the ident and
* +disp (rule 7). */
err(a, "unsupported name(reg) operand");
free(name);
return -1;
}
int r = reg_lookup(buf);
int r = reg_lookup(name);
if (r != 0) {
out->type = r;
free(name);
return 0;
}
out->type = D_BRANCH;
out->sym = strdup(buf);
out->sym = name;
return 0;
}
@@ -261,17 +274,14 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
int
a_parse(Asm *a)
{
/* Big enough for a DATAW emitting a [256]u32 table (1024 bytes
* → ~4100 chars of `\xNN` escapes plus directive boilerplate).
* Selfhost w6a allocates per-line; this is the cstage equivalent. */
static char buf[32768];
char *line;
size_t len;
const char *pending_label = NULL;
while (nextline(a, &line, &len, buf, sizeof buf)) {
while (nextline(a, &line, &len)) {
const char *p = skipws(line);
if (*p == '\0' || (*p == '/' && p[1] == '/')) {
free(line);
a->line++;
continue;
}
@@ -282,6 +292,11 @@ a_parse(Asm *a)
if (*q == ':') {
size_t nl = q - p;
char *name = malloc(nl + 1);
if (name == NULL) {
err(a, "out of memory");
free(line);
return a->errs;
}
memcpy(name, p, nl);
name[nl] = '\0';
/* If a label is already pending we'd lose it
@@ -297,6 +312,7 @@ a_parse(Asm *a)
a->tail = prg;
}
pending_label = name;
free(line);
a->line++;
continue;
}
@@ -311,6 +327,7 @@ a_parse(Asm *a)
int op = opcode_lookup(mnem);
if (op == 0) {
err(a, "unknown opcode");
free(line);
a->line++;
continue;
}
@@ -322,14 +339,20 @@ a_parse(Asm *a)
pending_label = NULL;
while (*m == ' ' || *m == '\t') m++;
const char *rest = m;
char *rest = (char *)m;
if (op == A_TEXT) {
char nbuf[256] = {0};
int nn = 0;
while (*m && *m != ',' && nn < 255) nbuf[nn++] = *m++;
const char *start = m;
while (*m && *m != ',') m++;
size_t nn = (size_t)(m - start);
char *name = malloc(nn + 1);
if (name == NULL) {
err(a, "out of memory"); free(line); return a->errs;
}
memcpy(name, start, nn);
name[nn] = 0;
prg->to.type = D_EXTERN;
prg->to.sym = strdup(nbuf);
prg->to.sym = name;
if (*m == ',') {
m++;
while (*m == ' ' || *m == '$') m++;
@@ -339,11 +362,17 @@ a_parse(Asm *a)
} else if (op == A_DATA || op == A_DATAW) {
/* DATA name(SB),"escaped bytes" — read-only in .text
* DATAW name(SB),"escaped bytes" — writable in .data */
char nbuf[256] = {0};
int nn = 0;
while (*m && *m != '(' && nn < 255) nbuf[nn++] = *m++;
const char *start = m;
while (*m && *m != '(') m++;
size_t nn = (size_t)(m - start);
char *name = malloc(nn + 1);
if (name == NULL) {
err(a, "out of memory"); free(line); return a->errs;
}
memcpy(name, start, nn);
name[nn] = 0;
prg->to.type = D_EXTERN;
prg->to.sym = strdup(nbuf);
prg->to.sym = name;
if (*m == '(') {
while (*m && *m != ')') m++;
if (*m == ')') m++;
@@ -357,6 +386,9 @@ a_parse(Asm *a)
m++;
size_t cap = 32, len = 0;
u8 *buf = malloc(cap);
if (buf == NULL) {
err(a, "out of memory"); free(line); return a->errs;
}
while (*m && *m != '"') {
int c = (unsigned char)*m++;
if (c == '\\' && *m) {
@@ -381,7 +413,12 @@ a_parse(Asm *a)
}
if (len + 1 > cap) {
cap *= 2;
buf = realloc(buf, cap);
u8 *next = realloc(buf, cap);
if (next == NULL) {
free(buf); err(a, "out of memory");
free(line); return a->errs;
}
buf = next;
}
buf[len++] = (u8)c;
}
@@ -389,27 +426,30 @@ a_parse(Asm *a)
prg->nbytes = len;
}
} else {
const char *comma = NULL;
for (const char *q = rest; *q; q++)
int operand_bad = 0;
char *comma = NULL;
for (char *q = rest; *q; q++)
if (*q == ',' && comma == NULL) comma = q;
if (comma) {
char op1[256], op2[256];
size_t l1 = comma - rest;
if (l1 >= sizeof op1) l1 = sizeof op1 - 1;
memcpy(op1, rest, l1); op1[l1] = '\0';
size_t l2 = strlen(comma + 1);
if (l2 >= sizeof op2) l2 = sizeof op2 - 1;
memcpy(op2, comma + 1, l2); op2[l2] = '\0';
parse_operand(a, op1, &prg->from);
parse_operand(a, op2, &prg->to);
*comma = '\0';
if (parse_operand(a, rest, &prg->from) < 0
|| parse_operand(a, comma + 1, &prg->to) < 0)
operand_bad = 1;
} else if (*rest) {
parse_operand(a, rest, &prg->to);
if (parse_operand(a, rest, &prg->to) < 0)
operand_bad = 1;
}
if (operand_bad) {
free(line);
a->line++;
continue;
}
}
if (a->head == NULL) a->head = prg;
else a->tail->link = prg;
a->tail = prg;
free(line);
a->line++;
}
return a->errs;