From 5493bbbc07240d04abc51ea56d5017d200bc9eba Mon Sep 17 00:00:00 2001 From: kdx Date: Thu, 13 Apr 2023 13:15:08 +0200 Subject: lemme take that --- .gitignore | 1 + build.sh | 4 +- src/main.c | 265 ---------------------------------------------------------- src/orgaasm.c | 265 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/orgaemu.c | 8 ++ 5 files changed, 277 insertions(+), 266 deletions(-) delete mode 100644 src/main.c create mode 100644 src/orgaasm.c create mode 100644 src/orgaemu.c diff --git a/.gitignore b/.gitignore index 0573d9f..dee9757 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /orgaasm +/orgaemu diff --git a/build.sh b/build.sh index 8bdeef8..c8b9b9f 100755 --- a/build.sh +++ b/build.sh @@ -1,2 +1,4 @@ #!/bin/sh -tcc -std=c99 -Wall -Wextra -o orgaasm src/*.c +CFLAGS='-std=c99 -Wall -Wextra' +tcc $CFLAGS -o orgaasm src/orgaasm.c +tcc $CFLAGS -o orgaemu src/orgaemu.c diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 8e1aa3f..0000000 --- a/src/main.c +++ /dev/null @@ -1,265 +0,0 @@ -#include -#include -#include -#include - -typedef struct Label Label; -struct Label { - const char *s; - size_t addr; - Label *next; -}; - -static const char ops[][4] = { - "NOP", "LIT", "POP", "NIP", "SWP", "ROT", "DUP", "OVR", "EQU", "NEQ", - "GTH", "LTH", "JEZ", "JNZ", "JMP", "JRT", "RET", "LDA", "STA", "RED", - "WRT", "ADD", "SUB", "MUL", "DIV", "AND", "ORA", "XOR", "LSF", "RSF", - "SLP" -}; -static const int hextable[256] = { - ['0'] = 0x0, ['1'] = 0x1, ['2'] = 0x2, ['3'] = 0x3, ['4'] = 0x4, - ['5'] = 0x5, ['6'] = 0x6, ['7'] = 0x7, ['8'] = 0x8, ['9'] = 0x9, - ['a'] = 0xa, ['b'] = 0xb, ['c'] = 0xc, ['d'] = 0xd, ['e'] = 0xe, - ['f'] = 0xf, -}; -static const char *sep = "\t\n\v\f\r "; -static int verbose = 0; -static char *data = NULL, *data_dup = NULL; -FILE *outfile = NULL; -static Label *label_root = NULL; - -static int -fail(void) -{ - if (data != NULL) - free(data); - if (data_dup != NULL) - free(data_dup); - while (label_root != NULL) { - Label *const next = label_root->next; - free(label_root); - label_root = next; - } - if (outfile != NULL) - fclose(outfile); - return 1; -} - -static void -skip_comments(void) -{ - char *tok; - do - tok = strtok(NULL, sep); - while (tok != NULL && strcmp(tok, ")") != 0); - - if (tok == NULL) { - fprintf(stderr, "unclosed comment"); - exit(fail()); - } -} - -static void -write_short(uint_least16_t v) -{ - if (verbose) printf("write: %04x\n", v); - if (fputc(v & 0x00ff, outfile) == EOF || - fputc(v / 0x0100, outfile) == EOF) { - fprintf(stderr, "fputc failed\n"); - exit(fail()); - } -} - -static void -register_label(const char *s, size_t pc) -{ - Label *const label = malloc(sizeof(Label)); - if (label == NULL) { - perror("register_label:malloc"); - exit(fail()); - } - - label->s = s; - label->addr = pc; - label->next = label_root; - label_root = label; - if (verbose) printf("label: '%s' at pc %zu\n", s, pc); -} - -static void -write_label(const char *s) -{ - for (Label *label = label_root; label != NULL; label = label->next) { - if (strcmp(s, label->s) == 0) { - write_short(label->addr); - return; - } - } - fprintf(stderr, "unknown label '%s'\n", s); -} - -static int -opcmp(const char *s0, const char *s1) -{ - return (s0[0] == s1[0] && s0[1] == s1[1] && s0[2] == s1[2]); -} - -static void -write_opcode(const char *s) -{ - for (unsigned i = 0; i < sizeof(ops) / sizeof(ops[0]); i++) { - if (opcmp(s, ops[i])) { - write_short(i); - return; - } - } - fprintf(stderr, "unknown opcode '%s'\n", s); - exit(fail()); -} - -static int -ishex(int c) -{ - return ((c >= 'a' && c <= 'f') || (c >= '0' && c <= '9')); -} - -static void -write_literal(const char *s) -{ - if (!ishex(s[0]) && !ishex(s[1]) && !ishex(s[2]) && !ishex(s[3])) { - fprintf(stderr, "invalid literal '%s'\n", s); - exit(fail()); - } - write_short((hextable[(int)s[0]] * 0x1000) | - (hextable[(int)s[1]] * 0x100) | - (hextable[(int)s[2]] * 0x10) | - (hextable[(int)s[3]])); -} - -static void -first_pass(char *s) -{ - char *tok; - size_t pc = 0; - for (tok = strtok(s, sep); tok != NULL; tok = strtok(NULL, sep)) { - /* Skip comment. */ - if (strcmp(tok, "(") == 0) { - skip_comments(); - continue; - } - - /* Label marker. */ - if (tok[0] == '@') - register_label(tok + 1, pc); - else - pc += 1; - } -} - -static void -second_pass(char *s) -{ - char *tok; - for (tok = strtok(s, sep); tok != NULL; tok = strtok(NULL, sep)) { - switch (tok[0]) { - case '@': /* label declaration, skip */ - continue; - case ',': /* label insertion */ - write_label(tok + 1); - continue; - default: - break; - } - - /* Skip comment. */ - if (strcmp(tok, "(") == 0) { - skip_comments(); - continue; - } - - const size_t tok_len = strlen(tok); - switch (tok_len) { - case 3: /* opcode */ - if (verbose) printf("opcode: %s\n", tok); - write_opcode(tok); - break; - case 4: /* literal */ - if (verbose) printf("literal: %s\n", tok); - write_literal(tok); - break; - default: /* wtf */ - fprintf(stderr, "unknown token '%s'\n", tok); - exit(fail()); - } - } -} - -static char * -drain(FILE *fp) -{ - if (fseek(fp, 0, SEEK_END) < 0) { - perror("drain:SEEK_END"); - return NULL; - } - const long size = ftell(fp); - if (fseek(fp, 0, SEEK_SET) < 0) { - perror("drain:SEEK_SET"); - return NULL; - } - char *const data = malloc(size + 1); - if (data == NULL) { - perror("drain:malloc"); - return NULL; - } - if ((long)fread(data, 1, size, fp) != size) { - perror("drain:fread"); - free(data); - return NULL; - } - data[size] = '\0'; - return data; -} - -int -main(int argc, char **argv) -{ - if (!(argc == 3 || (argc == 4 && strcmp(argv[3], "-v") == 0))) { - fprintf(stderr, "usage: %s [-v]\n", argv[0]); - return fail(); - } - verbose = (argc == 4); - - /* Dump file to memory. */ - FILE *const fp = fopen(argv[1], "rb"); - if (fp == NULL) { - perror(argv[1]); - return fail(); - } - data = drain(fp); - fclose(fp); - if (data == NULL) - return fail(); - - /* Duplicate data. */ - data_dup = malloc(strlen(data) + 1); - if (data_dup == NULL) { - perror("main:malloc"); - return fail(); - } - strcpy(data_dup, data); - - /* First pass, find labels. */ - first_pass(data); - - /* Open out file. */ - outfile = fopen(argv[2], "wb"); - if (outfile == NULL) { - perror(argv[2]); - return fail(); - } - - /* Second pass, generate bytecode. */ - second_pass(data_dup); - - return fail(), 0; -} diff --git a/src/orgaasm.c b/src/orgaasm.c new file mode 100644 index 0000000..8e1aa3f --- /dev/null +++ b/src/orgaasm.c @@ -0,0 +1,265 @@ +#include +#include +#include +#include + +typedef struct Label Label; +struct Label { + const char *s; + size_t addr; + Label *next; +}; + +static const char ops[][4] = { + "NOP", "LIT", "POP", "NIP", "SWP", "ROT", "DUP", "OVR", "EQU", "NEQ", + "GTH", "LTH", "JEZ", "JNZ", "JMP", "JRT", "RET", "LDA", "STA", "RED", + "WRT", "ADD", "SUB", "MUL", "DIV", "AND", "ORA", "XOR", "LSF", "RSF", + "SLP" +}; +static const int hextable[256] = { + ['0'] = 0x0, ['1'] = 0x1, ['2'] = 0x2, ['3'] = 0x3, ['4'] = 0x4, + ['5'] = 0x5, ['6'] = 0x6, ['7'] = 0x7, ['8'] = 0x8, ['9'] = 0x9, + ['a'] = 0xa, ['b'] = 0xb, ['c'] = 0xc, ['d'] = 0xd, ['e'] = 0xe, + ['f'] = 0xf, +}; +static const char *sep = "\t\n\v\f\r "; +static int verbose = 0; +static char *data = NULL, *data_dup = NULL; +FILE *outfile = NULL; +static Label *label_root = NULL; + +static int +fail(void) +{ + if (data != NULL) + free(data); + if (data_dup != NULL) + free(data_dup); + while (label_root != NULL) { + Label *const next = label_root->next; + free(label_root); + label_root = next; + } + if (outfile != NULL) + fclose(outfile); + return 1; +} + +static void +skip_comments(void) +{ + char *tok; + do + tok = strtok(NULL, sep); + while (tok != NULL && strcmp(tok, ")") != 0); + + if (tok == NULL) { + fprintf(stderr, "unclosed comment"); + exit(fail()); + } +} + +static void +write_short(uint_least16_t v) +{ + if (verbose) printf("write: %04x\n", v); + if (fputc(v & 0x00ff, outfile) == EOF || + fputc(v / 0x0100, outfile) == EOF) { + fprintf(stderr, "fputc failed\n"); + exit(fail()); + } +} + +static void +register_label(const char *s, size_t pc) +{ + Label *const label = malloc(sizeof(Label)); + if (label == NULL) { + perror("register_label:malloc"); + exit(fail()); + } + + label->s = s; + label->addr = pc; + label->next = label_root; + label_root = label; + if (verbose) printf("label: '%s' at pc %zu\n", s, pc); +} + +static void +write_label(const char *s) +{ + for (Label *label = label_root; label != NULL; label = label->next) { + if (strcmp(s, label->s) == 0) { + write_short(label->addr); + return; + } + } + fprintf(stderr, "unknown label '%s'\n", s); +} + +static int +opcmp(const char *s0, const char *s1) +{ + return (s0[0] == s1[0] && s0[1] == s1[1] && s0[2] == s1[2]); +} + +static void +write_opcode(const char *s) +{ + for (unsigned i = 0; i < sizeof(ops) / sizeof(ops[0]); i++) { + if (opcmp(s, ops[i])) { + write_short(i); + return; + } + } + fprintf(stderr, "unknown opcode '%s'\n", s); + exit(fail()); +} + +static int +ishex(int c) +{ + return ((c >= 'a' && c <= 'f') || (c >= '0' && c <= '9')); +} + +static void +write_literal(const char *s) +{ + if (!ishex(s[0]) && !ishex(s[1]) && !ishex(s[2]) && !ishex(s[3])) { + fprintf(stderr, "invalid literal '%s'\n", s); + exit(fail()); + } + write_short((hextable[(int)s[0]] * 0x1000) | + (hextable[(int)s[1]] * 0x100) | + (hextable[(int)s[2]] * 0x10) | + (hextable[(int)s[3]])); +} + +static void +first_pass(char *s) +{ + char *tok; + size_t pc = 0; + for (tok = strtok(s, sep); tok != NULL; tok = strtok(NULL, sep)) { + /* Skip comment. */ + if (strcmp(tok, "(") == 0) { + skip_comments(); + continue; + } + + /* Label marker. */ + if (tok[0] == '@') + register_label(tok + 1, pc); + else + pc += 1; + } +} + +static void +second_pass(char *s) +{ + char *tok; + for (tok = strtok(s, sep); tok != NULL; tok = strtok(NULL, sep)) { + switch (tok[0]) { + case '@': /* label declaration, skip */ + continue; + case ',': /* label insertion */ + write_label(tok + 1); + continue; + default: + break; + } + + /* Skip comment. */ + if (strcmp(tok, "(") == 0) { + skip_comments(); + continue; + } + + const size_t tok_len = strlen(tok); + switch (tok_len) { + case 3: /* opcode */ + if (verbose) printf("opcode: %s\n", tok); + write_opcode(tok); + break; + case 4: /* literal */ + if (verbose) printf("literal: %s\n", tok); + write_literal(tok); + break; + default: /* wtf */ + fprintf(stderr, "unknown token '%s'\n", tok); + exit(fail()); + } + } +} + +static char * +drain(FILE *fp) +{ + if (fseek(fp, 0, SEEK_END) < 0) { + perror("drain:SEEK_END"); + return NULL; + } + const long size = ftell(fp); + if (fseek(fp, 0, SEEK_SET) < 0) { + perror("drain:SEEK_SET"); + return NULL; + } + char *const data = malloc(size + 1); + if (data == NULL) { + perror("drain:malloc"); + return NULL; + } + if ((long)fread(data, 1, size, fp) != size) { + perror("drain:fread"); + free(data); + return NULL; + } + data[size] = '\0'; + return data; +} + +int +main(int argc, char **argv) +{ + if (!(argc == 3 || (argc == 4 && strcmp(argv[3], "-v") == 0))) { + fprintf(stderr, "usage: %s [-v]\n", argv[0]); + return fail(); + } + verbose = (argc == 4); + + /* Dump file to memory. */ + FILE *const fp = fopen(argv[1], "rb"); + if (fp == NULL) { + perror(argv[1]); + return fail(); + } + data = drain(fp); + fclose(fp); + if (data == NULL) + return fail(); + + /* Duplicate data. */ + data_dup = malloc(strlen(data) + 1); + if (data_dup == NULL) { + perror("main:malloc"); + return fail(); + } + strcpy(data_dup, data); + + /* First pass, find labels. */ + first_pass(data); + + /* Open out file. */ + outfile = fopen(argv[2], "wb"); + if (outfile == NULL) { + perror(argv[2]); + return fail(); + } + + /* Second pass, generate bytecode. */ + second_pass(data_dup); + + return fail(), 0; +} diff --git a/src/orgaemu.c b/src/orgaemu.c new file mode 100644 index 0000000..00c30cf --- /dev/null +++ b/src/orgaemu.c @@ -0,0 +1,8 @@ +#include + +int +main(int argc, char **argv) +{ + (void)argc, (void)argv; + return 0; +} -- cgit v1.2.3