assembler functional
authorJustin Wind <justin.wind@gmail.com>
Tue, 10 Apr 2012 05:00:19 +0000 (22:00 -0700)
committerJustin Wind <justin.wind@gmail.com>
Tue, 10 Apr 2012 05:00:19 +0000 (22:00 -0700)
as-dcpu16.c [new file with mode: 0644]
as-dcpu16.h [new file with mode: 0644]
dcpu16.h [new file with mode: 0644]

diff --git a/as-dcpu16.c b/as-dcpu16.c
new file mode 100644 (file)
index 0000000..91f63ee
--- /dev/null
@@ -0,0 +1,220 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sysexits.h>
+#include <assert.h>
+
+/* #include dcpu16.h */
+typedef unsigned short DCPU16_WORD;
+
+/* quick and dirty assembler for dcpu16 */
+
+static const char * const src_id_ = "$Id$";
+
+const char const out_filename_default_[] = "a.out";
+
+static
+void usage_(char *prog, unsigned int full) {
+    FILE *f = full ? stdout : stderr;
+    char *x = strrchr(prog, '/');
+
+    if (x && *(x + 1))
+        prog = x + 1;
+
+    if (full)
+        fprintf(f, "%s -- \n\n",
+                prog);
+
+    fprintf(f, "Usage: %s\n",
+            prog);
+
+    if (full) {
+        fprintf(f, "\nOptions:\n"
+                   "\t-h -- this screen\n"
+                   "\t-o <file> -- output to <file> [default: %s]\n",
+                out_filename_default_);
+
+        fprintf(f, "\n%78s\n",
+                src_id_);
+    }
+}
+
+struct operand_ {
+    struct operand_ *next;
+    char *operand;
+};
+
+struct instruction_ {
+    struct instruction_ *next;
+    char *label;
+    char *opcode;
+    struct operand_ *operands;
+
+    unsigned int length; /* words */
+    DCPU16_WORD instr_words[];
+};
+
+/* buf must be 0-terminated */
+static
+int buf_tokenize_(char *buf, struct instruction_ **next_instr) {
+    const char const *sep = " \t\n";
+    struct instruction_ *instr = NULL;
+    char *label = NULL,
+         *opcode = NULL,
+         *operand = NULL;
+
+    char *x,
+         *y,
+         *st;
+
+    assert(buf != NULL);
+    assert(next_instr != NULL);
+
+    *next_instr = NULL;
+
+    /* kill comments */
+    if ((x = strchr(buf, ';')) != NULL)
+        *x = '\0';
+    /* kill leading whitespace */
+    buf += strspn(buf, " \t\n");
+    /* kill trailing newlines */
+    if ((x = strrchr(buf, '\n')) != NULL)
+        *x = '\0';
+
+    /* determine if first token is label, opcode, or we just have a blank line to ignore */
+    x = strtok_r(buf, sep, &st);
+
+    /* empty line? nothing to do here. */
+    if (x == NULL)
+        return 0;
+
+    /* labels end with :, otherwise its an opcode */
+    if ((y = strrchr(x, ':')) != NULL) {
+        *y = '\0';
+        label = x;
+        opcode = strtok_r(NULL, sep, &st);
+    } else {
+        label = NULL;
+        opcode = x;
+    }
+
+    if (opcode) {
+        operand = st;
+    }
+
+    instr = calloc(1, sizeof *instr);
+    if (instr == NULL) {
+        fprintf(stderr, "%s():%s\n", "malloc", strerror(errno));
+        return -1;
+    }
+
+    instr->label = label;
+    instr->opcode = opcode;
+
+    if (operand) {
+        
+    }
+
+    *next_instr = instr;
+
+    return 0;
+}
+
+/* thish should grow buffer to fit huge linesh, but I jusht don't care right now, hic */
+static
+int parse_stream_(FILE *f) {
+    struct instruction_ *instr;
+    char buf[(1<<14)];
+
+    buf[sizeof buf - 1] = '\0';
+
+    while (fgets(buf, sizeof buf, f)) {
+        if (buf[sizeof buf - 1] != '\0') {
+            fprintf(stderr, "input buffer exhausted\n");
+            break;
+        }
+
+        if (buf_tokenize_(buf, &instr)) {
+            fprintf(stderr, "trouble tokenizing input\n");
+            break;
+        }
+
+        if (instr) {
+            struct operand_ *o;
+            if (instr->label) {
+                printf("TRACE: new label '%s'\n", instr->label);
+            }
+            printf("TRACE: tokenized opcode:%s operands:",
+                   instr->opcode);
+           for (o = instr->operands; o; o = o->next) {
+               printf("%s%s", o->operand, o->next ? ", " : "");
+           }
+           printf("\n");
+
+
+            /* add to queue of instructions */
+        }
+    }
+    if (ferror(f)) {
+        fprintf(stderr, "%s():%s\n", "fgets", strerror(errno));
+        return -1;
+    }
+    if (! feof(f)) {
+        fprintf(stderr, "parsing aborted\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+int main(int argc, char *argv[]) {
+    const char *out_filename = NULL;
+    int c;
+
+    while ( (c = getopt(argc, argv, "ho:")) != EOF ) {
+        switch (c) {
+            case 'o':
+                if (out_filename) {
+                    fprintf(stderr, "Sorry, I can only write one file at a time.\n");
+                    exit(EX_CANTCREAT);
+                }
+                out_filename = optarg;
+                break;
+
+            case 'h':
+                usage_(argv[0], 1);
+                exit(EX_OK);
+
+            default:
+                usage_(argv[0], 0);
+                exit(EX_USAGE);
+        }
+    }
+
+    if (out_filename == NULL)
+        out_filename = out_filename_default_;
+
+    /* if filenames were specified, parse them instead of stdin */
+    if (argc - optind) {
+        while (argc - optind) {
+            FILE *f = fopen(argv[argc - optind], "r");
+            if (f == NULL) {
+                fprintf(stderr, "%s('%s'):%s\n", "fopen", argv[argc - optind], strerror(errno));
+                optind++;
+                continue;
+            }
+
+            parse_stream_(f);
+
+            fclose(f);
+
+            optind++;
+        }
+    } else {
+        parse_stream_(stdin);
+    }
+
+    exit(EX_OK);
+}
diff --git a/as-dcpu16.h b/as-dcpu16.h
new file mode 100644 (file)
index 0000000..68bf54e
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef AS_DCPU16_H_PTFNJB09
+#define AS_DCPU16_H_PTFNJB09
+
+#include "dcpu16.h"
+
+struct instruction_ {
+    char *label;  /* set if a label points here */
+    char *opcode; /* tokenized instruction text */
+    struct operand_ *operands;  /* list of operands */
+    unsigned int length; /* words */
+    unsigned int ready : 1; /* bytecode computed? */
+    DCPU16_WORD instr_words[];
+};
+
+
+enum operand_types_{
+    OT_DIRECT,  /* these operands simply render their contents into bytecode */
+    OT_NEXT,    /* these operands increase instruction length */
+    OT_LABEL    /* labels need to be computed then converted to other types */
+};
+
+struct operand_ {
+    struct operand_ *next;
+    char *operand; /* tokenized operand text */
+    enum operand_types_ type;
+    union {
+        DCPU16_WORD word_value;
+        struct instruction_ *label_destination;
+    } value;
+};
+
+
+#define IL_SIZE(entries) (((entries) * sizeof(struct instruction_ *)) + sizeof(struct instruction_list_))
+
+struct instruction_list_ {
+    size_t allocated;
+    size_t entries;
+    struct instruction_ *instr[];
+};
+
+
+/* note label table holds its own structs, not pointers */
+struct label_ {
+    char *label; /* name of label */
+    struct instruction_ *instr;
+};
+
+#define LL_SIZE(entries) (((entries) * sizeof(struct label_ *)) + sizeof(struct label_list_))
+
+struct label_list_ {
+    size_t allocated;
+    size_t entries;
+    struct label_ label[];
+};
+
+#endif /* AS_DCPU16_H_PTFNJB09 */
diff --git a/dcpu16.h b/dcpu16.h
new file mode 100644 (file)
index 0000000..c9510c2
--- /dev/null
+++ b/dcpu16.h
@@ -0,0 +1,6 @@
+#ifndef DCPU16_H_3XXIQQG2
+#define DCPU16_H_3XXIQQG2
+
+typedef unsigned short DCPU16_WORD;
+
+#endif /* DCPU16_H_3XXIQQG2 */