summaryrefslogtreecommitdiff
path: root/nqdasm.c
diff options
context:
space:
mode:
Diffstat (limited to 'nqdasm.c')
-rw-r--r--nqdasm.c81
1 files changed, 71 insertions, 10 deletions
diff --git a/nqdasm.c b/nqdasm.c
index 3245570..86f8560 100644
--- a/nqdasm.c
+++ b/nqdasm.c
@@ -1,25 +1,34 @@
#include <errno.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mnemonics.h"
-#define ERROR(prog,...) \
+const char *progname;
+
+#define ERROR(...) \
do { \
- fprintf(stderr, "%s: ", prog); \
+ fprintf(stderr, "%s: ", progname); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
} while (0)
-#define PERROR(prog,str) \
+#define PERROR(str) \
do { \
int err = errno; \
- fprintf(stderr, "%s: ", prog); \
+ fprintf(stderr, "%s: ", progname); \
errno = err; \
perror(str); \
} while (0)
+struct line {
+ const struct mnemonic *mnem;
+ uint16_t addr;
+ uint16_t value;
+};
+
static const struct mnemonic *match_instruction(unsigned bits)
{
for (int i = 0; i < MNEM_LAST; i++) {
@@ -39,11 +48,59 @@ static void print_operand(FILE *out, unsigned bits, const struct operand *op)
}
}
-static void disassemble(FILE *in, FILE *out)
+static int resize_lines(struct line **lines, size_t alloc)
+{
+ struct line *result = realloc(*lines, alloc * sizeof **lines);
+ if (result) *lines = result;
+ else PERROR("Error allocating memory");
+ return !result;
+}
+
+static struct line *read_lines(FILE *in, size_t *count)
{
- unsigned bits;
+ size_t alloc = 16;
+ struct line *lines = NULL;
+
+ *count = 0;
+ if (resize_lines(&lines, alloc)) goto fail;
+
+ unsigned bits, addr = 0;
while (fscanf(in, " %x\n", &bits) > 0) {
- const struct mnemonic *m = match_instruction(bits);
+ if (addr > 0xffff) {
+ ERROR("Input exceeds 16-bit address space");
+ goto fail;
+ }
+ if (*count >= alloc && resize_lines(&lines, alloc *= 2)) {
+ goto fail;
+ }
+
+ lines[*count] = (struct line) {
+ .mnem = match_instruction(bits),
+ .value = bits,
+ .addr = addr,
+ };
+
+ addr += 2;
+ *count += 1;
+ }
+
+ return lines;
+
+fail:
+ free(lines);
+ return NULL;
+}
+
+static void disassemble(FILE *in, FILE *out)
+{
+ size_t count;
+ struct line *lines = read_lines(in, &count);
+ if (!lines) return;
+
+ for (size_t i = 0; i < count; i++) {
+ unsigned bits = lines[i].value;
+ const struct mnemonic *m = lines[i].mnem;
+
if (!m) {
fprintf(out, "\t.word 0x%04x\n", bits);
continue;
@@ -57,6 +114,8 @@ static void disassemble(FILE *in, FILE *out)
}
fprintf(out, "\n");
}
+
+ free(lines);
}
static void usage(const char *progname)
@@ -76,6 +135,8 @@ int main(int argc, char **argv)
extern int optind;
extern char *optarg;
+
+ progname = argv[0];
for (int opt; (opt = getopt(argc, argv, "+ho:")) != -1;) {
switch (opt) {
case 'h':
@@ -90,7 +151,7 @@ int main(int argc, char **argv)
}
if (optind < argc - 1) {
- ERROR(argv[0], "Too many input files");
+ ERROR("Too many input files");
return 1;
}
if (error) return 1;
@@ -99,11 +160,11 @@ int main(int argc, char **argv)
FILE *out = stdout;
if (optind < argc && !(in = fopen(argv[optind], "r"))) {
- PERROR(argv[0], "Error opening input file");
+ PERROR("Error opening input file");
return 1;
}
if (outname && !(out = fopen(outname, "w"))) {
- PERROR(argv[0], "Error opening output file");
+ PERROR("Error opening output file");
fclose(in);
return 1;
}