commit aafa43de711e305b14870fe1661710f4f8390db7
parent 72884f87ef5a4de8d259cf32a41eb1f7b779a20f
Author: Brian Swetland <swetland@frotz.net>
Date: Wed, 4 Apr 2012 20:23:13 -0700
a16: add support for labels and the "word" pseudo-op
Diffstat:
M | a16.c | | | 100 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- |
1 file changed, 94 insertions(+), 6 deletions(-)
diff --git a/a16.c b/a16.c
@@ -38,12 +38,79 @@ void die(const char *fmt, ...) {
exit(1);
}
+struct fixup {
+ struct fixup *next;
+ struct label *label;
+ u16 pc;
+};
+
+struct label {
+ struct label *next;
+ u16 pc;
+ u16 defined;
+ char name[1];
+};
+
+struct label *labels = 0;
+struct fixup *fixups = 0;
+
+struct label *mklabel(const char *name, u16 pc, u16 def) {
+ struct label *l;
+ for (l = labels; l; l = l->next) {
+ if (!strcasecmp(name, l->name)) {
+ if (def) {
+ if (l->defined)
+ die("cannot redefine label: %s", name);
+ l->defined = def;
+ l->pc = pc;
+ }
+ return l;
+ }
+ }
+ l = malloc(sizeof(*l) + strlen(name));
+ l->defined = def;
+ l->pc = pc;
+ strcpy(l->name, name);
+ l->next = labels;
+ labels = l;
+ return l;
+}
+
+void use_label(const char *name, u16 pc) {
+ struct label *l = mklabel(name, 0, 0);
+ if (l->defined) {
+ image[pc] = l->pc;
+ } else {
+ struct fixup *f = malloc(sizeof(*f));
+ f->next = fixups;
+ f->pc = pc;
+ f->label = l;
+ fixups = f;
+ }
+}
+
+void set_label(const char *name, u16 pc) {
+ mklabel(name, pc, 1);
+}
+
+void resolve_fixups(void) {
+ struct fixup *f;
+ for (f = fixups; f; f = f->next) {
+ if (f->label->defined) {
+ image[f->pc] = f->label->pc;
+ } else {
+ die("undefined reference to '%s' at 0x%04x", f->label->name, f->pc);
+ }
+ }
+}
+
enum tokens {
tA, tB, tC, tX, tY, tZ, tI, tJ,
tXXX, tSET, tADD, tSUB, tMUL, tDIV, tMOD, tSHL,
tSHR, tAND, tBOR, tXOR, tIFE, tIFN, tIFG, tIFB,
tJSR,
tPOP, tPEEK, tPUSH, tSP, tPC, tO,
+ tWORD,
tCOMMA, tOBRACK, tCBRACK, tCOLON,
tSTRING, tNUMBER, tEOF,
};
@@ -53,6 +120,7 @@ static const char *tnames[] = {
"SHR", "AND", "BOR", "XOR", "IFE", "IFN", "IFG", "IFB",
"JSR",
"POP", "PEEK", "PUSH", "SP", "PC", "O",
+ "WORD",
",", "[", "]", ":",
"<STRING>", "<NUMBER>", "<EOF>",
};
@@ -60,7 +128,7 @@ static const char *rnames[] = {
"A", "B", "C", "X", "Y", "Z", "I", "J",
};
-#define LASTKEYWORD tO
+#define LASTKEYWORD tWORD
int _next(void) {
char c;
@@ -115,6 +183,18 @@ void expect(int t) {
die("expecting %s, found %s", tnames[t], tnames[token]);
}
+void assemble_imm_or_label(void) {
+ next();
+ if (token == tNUMBER) {
+ image[PC++] = tnumber;
+ } else if (token == tSTRING) {
+ image[PC] = 0;
+ use_label(tstring, PC++);
+ } else {
+ die("expected number or label");
+ }
+}
+
int assemble_operand(void) {
int n;
next();
@@ -131,6 +211,10 @@ int assemble_operand(void) {
case tNUMBER:
image[PC++] = tnumber;
return 0x1f;
+ case tSTRING:
+ image[PC] = 0;
+ use_label(tstring, PC++);
+ return 0x1f;
default:
if (token != tOBRACK)
die("expected [");
@@ -144,15 +228,14 @@ int assemble_operand(void) {
if (token == tCBRACK) {
return n | 0x08;
} else if (token == tCOMMA) {
- expect(tNUMBER); // handle labels
- image[PC++] = tnumber;
+ assemble_imm_or_label();
expect(tCBRACK);
return n | 0x10;
} else {
die("invalid operand");
}
- //case tSTRING:
- // handle labels
+ case tSTRING:
+ use_label(tstring, PC);
case tNUMBER:
image[PC++] = tnumber;
next();
@@ -191,7 +274,10 @@ void assemble(const char *fn) {
goto done;
case tCOLON:
expect(tSTRING);
- //setlabel(tstring, PC);
+ set_label(tstring, PC);
+ continue;
+ case tWORD:
+ assemble_imm_or_label();
continue;
case tSET: case tADD: case tSUB: case tMUL:
case tDIV: case tMOD: case tSHL: case tSHR:
@@ -239,6 +325,8 @@ int main(int argc, char **argv) {
assemble(argv[0]);
}
+ linebuffer[0] = 0;
+ resolve_fixups();
emit(outfn);
return 0;
}