build: separate package identity from storage paths
This commit is contained in:
124
cmd/w6a/parse.c
124
cmd/w6a/parse.c
@@ -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;
|
||||
|
||||
@@ -22,6 +22,18 @@ slurp(const char *path, char **outbuf, u64 *outlen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
export_owner_matches(const char *buf, u64 len, const char *path)
|
||||
{
|
||||
static const char prefix[] = "//ww:module ";
|
||||
size_t pn = strlen(path);
|
||||
size_t need = sizeof prefix - 1 + pn + 1;
|
||||
return len >= need
|
||||
&& memcmp(buf, prefix, sizeof prefix - 1) == 0
|
||||
&& memcmp(buf + sizeof prefix - 1, path, pn) == 0
|
||||
&& buf[need - 1] == '\n';
|
||||
}
|
||||
|
||||
struct importin {
|
||||
const char *path;
|
||||
const char *file;
|
||||
@@ -164,6 +176,13 @@ main(int argc, char **argv)
|
||||
imports[i].path, imports[i].file);
|
||||
return 1;
|
||||
}
|
||||
if (!export_owner_matches(imports[i].buf, imports[i].len,
|
||||
imports[i].path)) {
|
||||
fprintf(stderr,
|
||||
"w6c: import %s: export owner mismatch in %s\n",
|
||||
imports[i].path, imports[i].file);
|
||||
return 1;
|
||||
}
|
||||
int bad = 0;
|
||||
Node *f = parseinput(a, imports[i].file, imports[i].buf,
|
||||
imports[i].len, imports[i].path, testsupport, 0, &bad);
|
||||
|
||||
@@ -864,6 +864,8 @@ wwi_emit(Checker *c, FILE *of, Node *file)
|
||||
const char *dot = strrchr(file->module, '.');
|
||||
pkg = dot ? dot + 1 : file->module;
|
||||
}
|
||||
if (file->module != NULL && file->module[0] != '\0')
|
||||
fprintf(of, "//ww:module %s\n", file->module);
|
||||
fprintf(of, "package %s;\n", pkg);
|
||||
|
||||
/* imports — primary N_USE, byte-sorted by import path. */
|
||||
|
||||
@@ -82,9 +82,8 @@ resolve_typename(Checker *c, Node *n)
|
||||
* same name as the module itself (e.g. `random.random`). */
|
||||
const char *dot = strrchr(nm, '.');
|
||||
if (dot) {
|
||||
char head[128] = {0};
|
||||
size_t hl = (size_t)(dot - nm);
|
||||
if (hl < sizeof head) memcpy(head, nm, hl);
|
||||
char *head = astrndup(c->a, nm, hl);
|
||||
Sym *m = scope_lookup(c->cur, head);
|
||||
if (m && (m->kind == SK_USE || m->use_alias)) {
|
||||
/* M1 #22: map the qualifier alias to its dotted
|
||||
|
||||
1073
cmd/ww/main.c
1073
cmd/ww/main.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user