From: Justin Wind Date: Tue, 10 Apr 2012 05:00:19 +0000 (-0700) Subject: assembler functional X-Git-Url: http://git.squeep.com/?p=dcpu16;a=commitdiff_plain;h=f4a3d9f3bf88f2b3840067674b3eed636516fcee assembler functional --- diff --git a/as-dcpu16.c b/as-dcpu16.c new file mode 100644 index 0000000..91f63ee --- /dev/null +++ b/as-dcpu16.c @@ -0,0 +1,220 @@ +#include +#include +#include +#include +#include +#include +#include + +/* #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 -- output to [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 index 0000000..68bf54e --- /dev/null +++ b/as-dcpu16.h @@ -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 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 */