diff options
| author | Louis Burda <quent.burda@gmail.com> | 2023-07-24 00:43:33 +0200 |
|---|---|---|
| committer | Louis Burda <quent.burda@gmail.com> | 2023-07-24 00:43:33 +0200 |
| commit | d7865d956f9fe3a08ebe4429dce4428a9f74bc6c (patch) | |
| tree | afcc976934add55eed727a3f782eea8912646122 /tis-as.c | |
| download | tis100-d7865d956f9fe3a08ebe4429dce4428a9f74bc6c.tar.gz tis100-d7865d956f9fe3a08ebe4429dce4428a9f74bc6c.zip | |
Add initial rough outline
Diffstat (limited to 'tis-as.c')
| -rw-r--r-- | tis-as.c | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/tis-as.c b/tis-as.c new file mode 100644 index 0000000..0d3625c --- /dev/null +++ b/tis-as.c @@ -0,0 +1,362 @@ +#include "tpu.h" + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> + +#define WHITESPACE " \t\v\r\n" + +enum tok { + /* Global */ + TOK_STDIN, TOK_STDOUT, TOK_TPU, TOK_END, + + /* Operands (order like OP_*) */ + TOK_ACC, TOK_BAK, TOK_NIL, TOK_LEFT, TOK_RIGHT, + TOK_UP, TOK_DOWN, TOK_ANY, TOK_LAST, TOK_LIT, + + /* Instructions (order like INST_*) */ + TOK_NOP, TOK_MOV, TOK_SWP, TOK_SAV, TOK_ADD, TOK_SUB, + TOK_NEG, TOK_JMP, TOK_JEZ, TOK_JNZ, TOK_JLZ, TOK_JRO, + + /* Misc */ + TOK_COMMENT, TOK_LABEL, TOK_XPOS, TOK_YPOS, TOK_NL, TOK_EOF +}; + +struct tokenizer { + FILE *file; + enum tok tok; + char *tokstr; + size_t lineno, off; + char linebuf[256]; +}; + +static int stdin_x = 0, stdin_y = 0; +static int stdout_x = 0, stdout_y = 0; + +struct tpu_map map; + +static const char *tok_reprs[] = { + /* Global */ + "STDIN", "STDOUT", "BLOCK", "END", + + /* Operands */ + "ACC", "BAK", "NIL", "LEFT", "RIGHT", "UP", + "DOWN", "ANY", "LAST", "<LIT>", + + /* Instructions */ + "NOP", "MOV", "SWP", "SAV", "ADD", "SUB", + "NEG", "JMP", "JEZ", "JNZ", "JLZ", "JRO", + + /* Misc */ + "#<COMMENT>", "<LABEL>", "X<INT>", "Y<INT>", "<NL>", "<EOF>" +}; + +static void +__attribute__((format(printf, 1, 2))) +__attribute__((noreturn)) +die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "tis: "); + vfprintf(stderr, fmt, ap); + if (*fmt && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + va_end(ap); + + exit(1); +} + +bool +is_lit(const char *str) +{ + unsigned long v; + char *end; + + v = strtoul(str, &end, 10); + if (!end || *end) return false; + + return v < 256; +} + +uint8_t +str2lit(const char *str) +{ + return (uint8_t) atoi(str); +} + +enum tpu_inst_type +tok_to_inst(enum tok tok) +{ + if (tok < TOK_NOP || tok >= TOK_JRO) abort(); + return tok - TOK_NOP + INST_NOP; +} + +enum tpu_inst_op_type +tok_to_optype(enum tok tok) +{ + if (tok < TOK_ACC || tok >= TOK_LIT) abort(); + return tok - TOK_ACC + OP_ACC; +} + +enum tok +tok_next(struct tokenizer *tok) +{ + size_t len; + char *s; + + if (!tok->linebuf[tok->off]) { + if (feof(tok->file)) return TOK_EOF; + s = fgets(tok->linebuf, sizeof(tok->linebuf), tok->file); + if (!s && !feof(tok->file)) die("fgets:"); + if (!s) return TOK_EOF; + if (*s && s[strlen(s)-1] != '\n') + die("tokenizer: line %lu too long", tok->lineno); + tok->off = 0; + } + + s = tok->linebuf + tok->off; + len = strspn(s, WHITESPACE); + tok->off += len; + s += len; + + len = strcspn(s, WHITESPACE); + s[len] = '\0'; + tok->off += len; + if (!len) return TOK_NL; + + if (!strcasecmp(s, "stdin")) { + return TOK_STDIN; + } else if (!strcasecmp(s, "stdout")) { + return TOK_STDIN; + } else if (!strcasecmp(s, "block")) { + return TOK_TPU; + } else if (!strcasecmp(s, "end")) { + return TOK_END; + } else if (!strcasecmp(s, "acc")) { + return TOK_ACC; + } else if (!strcasecmp(s, "bak")) { + return TOK_BAK; + } else if (!strcasecmp(s, "nil")) { + return TOK_NIL; + } else if (!strcasecmp(s, "left")) { + return TOK_LEFT; + } else if (!strcasecmp(s, "right")) { + return TOK_RIGHT; + } else if (!strcasecmp(s, "up")) { + return TOK_UP; + } else if (!strcasecmp(s, "down")) { + return TOK_DOWN; + } else if (!strcasecmp(s, "any")) { + return TOK_ANY; + } else if (!strcasecmp(s, "last")) { + return TOK_LAST; + } else if (is_lit(s)) { + return TOK_LIT; + } else if (!strcasecmp(s, "nop")) { + return TOK_NOP; + } else if (!strcasecmp(s, "mov")) { + return TOK_MOV; + } else if (!strcasecmp(s, "swp")) { + return TOK_SWP; + } else if (!strcasecmp(s, "sav")) { + return TOK_SAV; + } else if (!strcasecmp(s, "add")) { + return TOK_ADD; + } else if (!strcasecmp(s, "sub")) { + return TOK_SUB; + } else if (!strcasecmp(s, "neg")) { + return TOK_NEG; + } else if (!strcasecmp(s, "jmp")) { + return TOK_JMP; + } else if (!strcasecmp(s, "jez")) { + return TOK_JEZ; + } else if (!strcasecmp(s, "jnz")) { + return TOK_JNZ; + } else if (!strcasecmp(s, "jlz")) { + return TOK_JLZ; + } else if (!strcasecmp(s, "jro")) { + return TOK_JRO; + } else if (*s == '#') { + tok->off = strlen(s); + return TOK_COMMENT; + } else if (len && s[len-1] == ':') { + return TOK_LABEL; + } else if (*s == 'X' && atoi(s+1) > 0) { + return TOK_XPOS; + } else if (*s == 'Y' && atoi(s+1) > 0) { + return TOK_YPOS; + } else { + die("tokenizer: line %lu, invalid token '%s'", tok->lineno, s); + } +} + +enum tok +tok_next_in(struct tokenizer *tokenizer, ...) +{ + va_list ap, cpy; + enum tok tok; + bool first; + int arg; + + tok = tok_next(tokenizer); + + va_copy(cpy, ap); + + va_start(cpy, tokenizer); + while ((arg = va_arg(cpy, int)) > 0) { + if (tok == arg) return tok; + } + va_end(cpy); + + fprintf(stderr, "tis-as: tokenizer: "); + fprintf(stderr, "line %lu, got tok '%s', expected one of ", + tokenizer->lineno, tok_reprs[tok]); + + first = true; + va_start(ap, tokenizer); + while ((arg = va_arg(ap, int)) > 0) { + if (!first) fputc(',', stderr); + fputs(tok_reprs[arg], stderr); + first = false; + } + va_end(ap); + + fprintf(stderr, "\n"); + exit(1); +} + +static void +load(const char *fname) +{ + struct tokenizer tokenizer; + enum tpu_inst_op_type op1, op2; + enum tok op1_tok, op2_tok; + uint8_t op1_lit, op2_lit; + enum tpu_inst_type inst; + struct tpu *tpu = NULL; + enum tok tok; + FILE *file; + + file = fopen(fname, "r"); + if (!file) die("fopen:"); + + tokenizer.lineno = 1; + tokenizer.file = file; + tokenizer.off = 0; + tokenizer.tokstr = NULL; + tokenizer.linebuf[tokenizer.off] = '\0'; + while ((tok = tok_next(&tokenizer)) != TOK_EOF) { + switch (tok) { + case TOK_STDIN: + if (tpu) goto disallowed; + tok_next_in(&tokenizer, TOK_XPOS, -1); + stdin_x = atoi(tokenizer.tokstr + 1); + tok_next_in(&tokenizer, TOK_YPOS, -1); + stdin_y = atoi(tokenizer.tokstr + 1); + tok_next_in(&tokenizer, TOK_NL, -1); + break; + case TOK_STDOUT: + if (tpu) goto disallowed; + tok_next_in(&tokenizer, TOK_XPOS, -1); + stdout_x = atoi(tokenizer.tokstr + 1); + tok_next_in(&tokenizer, TOK_YPOS, -1); + stdout_y = atoi(tokenizer.tokstr + 1); + tok_next_in(&tokenizer, TOK_NL, -1); + break; + case TOK_TPU: + if (tpu) goto disallowed; + tpu = malloc(sizeof(struct tpu)); + if (!tpu) die("malloc:"); + tpu_init(tpu); + tok_next_in(&tokenizer, TOK_XPOS, -1); + tpu->x = atoi(tokenizer.tokstr + 1); + tok_next_in(&tokenizer, TOK_YPOS, -1); + tpu->y = atoi(tokenizer.tokstr + 1); + tok_next_in(&tokenizer, TOK_NL, -1); + /* TODO insert tpu */ + break; + case TOK_END: + if (!tpu) goto disallowed; + tpu = NULL; + break; + case TOK_NOP: case TOK_MOV: case TOK_SWP: case TOK_SAV: + case TOK_ADD: case TOK_SUB: case TOK_NEG: case TOK_JMP: + case TOK_JEZ: case TOK_JNZ: case TOK_JLZ: case TOK_JRO: + if (!tpu) goto disallowed; + inst = tok_to_inst(tok); + + op1_tok = tok_next_in(&tokenizer, TOK_ACC, + TOK_BAK, TOK_UP, TOK_DOWN, + TOK_LEFT, TOK_RIGHT, TOK_NL, -1); + if (op1_tok == TOK_NL) { + tok_next_in(&tokenizer, TOK_NL, -1); + tpu_add_inst(tpu, inst, -1, 0, -1, 0); + break; + } + + op1 = tok_to_optype(op1_tok); + if (op1 == OP_LIT) + op1_lit = str2lit(tokenizer.tokstr); + + op2_tok = tok_next_in(&tokenizer, TOK_ACC, + TOK_BAK, TOK_UP, TOK_DOWN, + TOK_LEFT, TOK_RIGHT, TOK_NL, -1); + if (op2_tok == TOK_NL) { + tok_next_in(&tokenizer, TOK_NL, -1); + tpu_add_inst(tpu, inst, + (int) op1, op1_lit, -1, 0); + break; + } + + op2 = tok_to_optype(op2_tok); + if (op2 == OP_LIT) + op2_lit = str2lit(tokenizer.tokstr); + tok_next_in(&tokenizer, TOK_NL, -1); + tpu_add_inst(tpu, inst, (int) op1, op1_lit, + (int) op2, op2_lit); + break; + case TOK_COMMENT: + tok_next_in(&tokenizer, TOK_NL, -1); + break; + case TOK_LABEL: + /* TODO */ + break; + default: + goto disallowed; + } + } + + fclose(file); + +disallowed: + die("tokenizer: line %lu, token %s not allowed here", + tokenizer.lineno, tok_reprs[tok]); +} + +void +run(void) +{ + +} + +int +main(int argc, const char **argv) +{ + if (argc != 2) { + fprintf(stderr, "Usage: tis-as FILE\n"); + exit(1); + } + + load(argv[1]); + + run(); +} |
