commit e32b439cfe7ca72098b2ebe9e1e93f97b7c10ada
parent 40d8eb449ed072b47bfbe953a191708f761c53a0
Author: Louis Burda <quent.burda@gmail.com>
Date: Tue, 25 Jul 2023 01:59:25 +0200
Add inotify-based interactive file reload and fix asm parsing
Diffstat:
6 files changed, 128 insertions(+), 81 deletions(-)
diff --git a/asm.c b/asm.c
@@ -85,12 +85,11 @@ tok_to_optype(enum asm_tok tok)
static size_t
strlcat_op_name(char *buf, struct tpu_inst_op *op, size_t n)
{
- size_t len;
+ char hhbuf[4];
if (op->type == OP_LIT) {
- len = strlen(buf);
- snprintf(buf + len, n - len, "%hhu", op->lit);
- return op->lit;
+ snprintf(hhbuf, 4, "%hhu", op->lit);
+ return strdcat(buf, hhbuf, n);
} else if (op->type == OP_LABEL) {
return strdcat(buf, op->label, n);
} else {
@@ -130,7 +129,7 @@ tok_next(struct asm_tokenizer *tok)
len = strlen(s);
if (len && s[len-1] != '\n' && !feof(tok->file))
- die("tis_load: line %lu too long", tok->lineno);
+ die("load: line %lu too long", tok->lineno);
if (len && s[len-1] == '\n') s[len-1] = '\0';
tok->lineno += 1;
@@ -142,9 +141,10 @@ tok_next(struct asm_tokenizer *tok)
s = tok->linebuf + tok->off;
len = strspn(s, WHITESPACE);
tok->off += len;
- s += len;
- tok->tokstr = s;
- if (!*s) return TOK_NL;
+ if (!s[len]) return TOK_NL;
+ tok->tokstr = (s += len);
+
+ if (*s == ',') die("load: line %lu, misaligned comma", tok->lineno);
len = strcspn(s, WHITESPACE ",");
tok->off += len;
@@ -153,6 +153,8 @@ tok_next(struct asm_tokenizer *tok)
tok->off += 1;
}
+ //printf("> %s\n", tok->tokstr);
+
if (!strcasecmp(s, "stdin")) {
return TOK_STDIN;
} else if (!strcasecmp(s, "stdout")) {
@@ -219,7 +221,7 @@ tok_next(struct asm_tokenizer *tok)
} else if (strspn(s, NAMEALPH) == strlen(s)) {
return TOK_NAME;
} else {
- die("tis_load: line %lu, invalid token '%s'", tok->lineno, s);
+ die("load: line %lu, invalid token '%s'", tok->lineno, s);
}
}
@@ -274,12 +276,15 @@ tis_load(struct tis *tis, const char *filepath)
char *label;
size_t i;
+ tis_deinit(tis);
+ tis_init(tis);
+
stdin_x = stdin_y = 0;
stdout_x = stdout_y = 0;
tokenizer.filepath = filepath;
tokenizer.file = fopen(filepath, "r");
- if (!tokenizer.file) die("tis_load: fopen '%s':", filepath);
+ if (!tokenizer.file) die("load: fopen '%s':", filepath);
tokenizer.lineno = 0;
tokenizer.off = 0;
@@ -331,7 +336,9 @@ tis_load(struct tis *tis, const char *filepath)
TOK_NIL, TOK_LEFT, TOK_RIGHT, TOK_UP, TOK_DOWN,
TOK_ANY, TOK_LAST, TOK_LIT, TOK_NAME, TOK_NL, -1);
if (op1_tok == TOK_NL) {
- tpu_add_inst(tpu, inst, -1, 0, -1, 0);
+ if (!tpu_add_inst(tpu, inst, -1, 0, -1, 0))
+ die("load: line %lu, invalid instruction",
+ tokenizer.lineno);
break;
}
@@ -343,17 +350,21 @@ tis_load(struct tis *tis, const char *filepath)
TOK_NIL, TOK_LEFT, TOK_RIGHT, TOK_UP, TOK_DOWN,
TOK_ANY, TOK_LAST, TOK_LIT, TOK_NAME, TOK_NL, -1);
if (op2_tok == TOK_NL) {
- tpu_add_inst(tpu, inst, (int) op1,
- op1_lit, -1, 0);
+ if (!tpu_add_inst(tpu, inst, (int) op1,
+ op1_lit, -1, 0))
+ die("load: line %lu, invalid instruction",
+ tokenizer.lineno);
break;
}
op2 = tok_to_optype(op2_tok);
if (op2 == OP_LIT)
op2_lit = str_to_lit(tokenizer.tokstr);
+ if (!tpu_add_inst(tpu, inst, (int) op1, op1_lit,
+ (int) op2, op2_lit))
+ die("load: line %lu, invalid instruction",
+ tokenizer.lineno);
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);
@@ -361,7 +372,7 @@ tis_load(struct tis *tis, const char *filepath)
case TOK_LABEL:
label = strdup(tokenizer.tokstr);
if (!label_map_add(&tpu->labels, label, tpu->inst_cnt))
- die("tis_load: line %lu, duplicate label",
+ die("load: line %lu, duplicate label",
tokenizer.lineno);
tok_next_in(&tokenizer, TOK_NL, -1);
break;
@@ -373,10 +384,10 @@ tis_load(struct tis *tis, const char *filepath)
}
if (stdin_x == 0 || stdin_y == 0)
- die("tis_load: stdin tpu not set");
+ die("load: stdin tpu not set");
if (stdout_x == 0 || stdout_y == 0)
- die("tis_load: stdout tpu not set");
+ die("load: stdout tpu not set");
for (i = 0; i < TPU_MAP_BUCKETS; i++) {
for (link = tis->tpu_map.buckets[i]; link; link = link->next) {
@@ -385,7 +396,7 @@ tis_load(struct tis *tis, const char *filepath)
if (link->x == stdin_x && link->y == stdin_y) {
port = &link->tpu->ports[DIR_UP];
if (port->attached)
- die("tis_load: stdin port in use");
+ die("load: stdin port in use");
port->attached = true;
port->dst_tpu = NULL;
port->dst_port = &tis->stdin_port;
@@ -398,7 +409,7 @@ tis_load(struct tis *tis, const char *filepath)
if (link->x == stdout_x && link->y == stdout_y) {
port = &link->tpu->ports[DIR_DOWN];
if (port->attached)
- die("tis_load: stdout port in use");
+ die("load: stdout port in use");
port->attached = true;
port->dst_tpu = NULL;
port->dst_port = &tis->stdout_port;
@@ -411,11 +422,11 @@ tis_load(struct tis *tis, const char *filepath)
}
if (!tis->stdin_port.attached)
- die("tis_load: stdin tpu (X%i Y%i) not found",
+ die("load: stdin tpu (X%i Y%i) not found",
stdin_x, stdin_y);
if (!tis->stdout_port.attached)
- die("tis_load: stdout tpu (X%i Y%i) not found",
+ die("load: stdout tpu (X%i Y%i) not found",
stdout_x, stdout_y);
fclose(tokenizer.file);
@@ -424,10 +435,10 @@ tis_load(struct tis *tis, const char *filepath)
disallowed:
if (tok == TOK_NAME) {
- die("tis_load: line %lu, unexpected token '%s'",
+ die("load: line %lu, unexpected token '%s'",
tokenizer.lineno, tokenizer.tokstr);
} else {
- die("tis_load: line %lu, token %s not allowed here",
+ die("load: line %lu, token %s not allowed here",
tokenizer.lineno, tok_reprs[tok]);
}
}
diff --git a/test/test.asm b/test/test.asm
@@ -1,5 +1,5 @@
stdin X1 Y1
-stdout X3 Y1
+stdout X3 Y2
tpu X1 Y1
mov UP, RIGHT
@@ -7,11 +7,13 @@ end
tpu X2 Y1
mov LEFT, ACC
- NEG
- SUB 1
mov ACC, RIGHT
end
tpu X3 Y1
mov LEFT, DOWN
end
+
+tpu X3 Y2
+ mov UP, DOWN
+end
diff --git a/tis-as.c b/tis-as.c
@@ -14,7 +14,7 @@ static struct tis tis;
static FILE *tis_stdin = NULL;
static FILE *tis_stdout = NULL;
-void (*cleanup)(void) = NULL;
+int (*cleanup)(void) = NULL;
const char *progname = "tis-as";
int
diff --git a/tis-curses.c b/tis-curses.c
@@ -5,8 +5,8 @@
#include "asm.h"
#include <curses.h>
-
-#include <libgen.h>
+#include <sys/inotify.h>
+#include <unistd.h>
#include <locale.h>
#include <errno.h>
#include <stdarg.h>
@@ -18,13 +18,15 @@
#define KEY_ESC 0x1b
#define KEY_CTRL(c) ((c) & ~0x60)
-#define TPUT_INPUT_ROWS 14
-#define TPUT_INPUT_COLS 20
-#define TPUT_INFO_W 6
-#define TPUT_INFO_H 4
-#define TPUT_CNT 6
-#define TPUT_W (TPUT_INPUT_COLS + 2 + 6)
-#define TPUT_H (TPUT_INPUT_ROWS + 2)
+#define TPU_INPUT_ROWS 14
+#define TPU_INPUT_COLS 20
+#define TPU_INFO_W 6
+#define TPU_INFO_H 4
+#define TPU_CNT 6
+#define TPU_W (TPU_INPUT_COLS + 2 + 6)
+#define TPU_H (TPU_INPUT_ROWS + 2)
+
+#define TIMEOUT 50
enum input_mode {
MAIN,
@@ -49,11 +51,13 @@ static struct tis tis;
static FILE *tis_stdin = NULL;
static FILE *tis_stdout = NULL;
+static int show_reloaded = 0;
+
static enum input_mode input_mode = MAIN;
static struct tpu *tpu_sel = NULL;
-void (*cleanup)(void) = (void *) endwin;
+int (*cleanup)(void) = endwin;
const char *progname = "tis-curses";
static const char *
@@ -98,13 +102,13 @@ tpu_last_str(struct tpu *tpu)
static int
tpu_pos_x(struct tpu *tpu)
{
- return 2 + (int) tpu->x * (TPUT_W + 4);
+ return 2 + (int) tpu->x * (TPU_W + 4);
}
static int
tpu_pos_y(struct tpu *tpu)
{
- return 2 * (int) tpu->y * (TPUT_H + 2);
+ return 2 + (int) tpu->y * (TPU_H + 2);
}
static void
@@ -163,15 +167,9 @@ tui_draw_wch(int x, int y, attr_t attr, const cchar_t *c)
}
static void
-tui_set_attr(int x, int y, attr_t attr)
-{
- (void) mvchgat(y - scry, x - scrx, 1, attr, 0, NULL);
-}
-
-static void
tui_draw_tpu(struct tpu *tpu)
{
- char linebuf[TPUT_INPUT_COLS + 1];
+ char linebuf[TPU_INPUT_COLS + 1];
struct tpu_port *port;
int sx, sy, x, y, w, h;
int i, idle, min;
@@ -181,42 +179,42 @@ tui_draw_tpu(struct tpu *tpu)
sx = tpu_pos_x(tpu);
sy = tpu_pos_y(tpu);
- tui_draw_box(sx, sy, TPUT_W, TPUT_H, attr,
+ tui_draw_box(sx, sy, TPU_W, TPU_H, attr,
WACS_D_ULCORNER, WACS_D_URCORNER,
WACS_D_LLCORNER, WACS_D_LRCORNER);
- min = MIN(tpu->pc, MAX(0, (int) tpu->inst_cnt - TPUT_INPUT_ROWS));
- for (i = 0; i < MIN((int) tpu->inst_cnt - min, TPUT_INPUT_ROWS); i++) {
+ min = MIN(tpu->pc, MAX(0, (int) tpu->inst_cnt - TPU_INPUT_ROWS));
+ for (i = 0; i < MIN((int) tpu->inst_cnt - min, TPU_INPUT_ROWS); i++) {
asm_print_inst(linebuf, sizeof(linebuf), &tpu->insts[min + i]);
tui_draw_text(sx + 2, sy + 1 + i, i == tpu->pc ? A_STANDOUT : 0,
- "%-*s", TPUT_INPUT_COLS, linebuf);
+ "%-*s", TPU_INPUT_COLS, linebuf);
}
- x = sx + TPUT_W - TPUT_INFO_W;
+ x = sx + TPU_W - TPU_INFO_W;
y = sy;
- w = TPUT_INFO_W;
- h = TPUT_INFO_H;
+ w = TPU_INFO_W;
+ h = TPU_INFO_H;
tui_draw_box(x, y, w, h, attr,
WACS_D_TTEE, WACS_D_URCORNER, WACS_D_LTEE, WACS_D_RTEE);
tui_draw_text(x + 2, y + 1, A_BOLD, "ACC");
tui_draw_text(x + 2, y + 2, 0, "%03i", tpu->acc);
- tui_draw_box(x, (y += TPUT_INFO_H - 1), w, h, attr,
+ tui_draw_box(x, (y += TPU_INFO_H - 1), w, h, attr,
WACS_D_LTEE, WACS_D_RTEE, WACS_D_LTEE, WACS_D_RTEE);
tui_draw_text(x + 2, y + 1, A_BOLD, "BAK");
tui_draw_text(x + 2, y + 2, 0, "%03i", tpu->bak);
- tui_draw_box(x, (y += TPUT_INFO_H - 1), w, h, attr,
+ tui_draw_box(x, (y += TPU_INFO_H - 1), w, h, attr,
WACS_D_LTEE, WACS_D_RTEE, WACS_D_LTEE, WACS_D_RTEE);
tui_draw_text(x + 2, y + 1, A_BOLD, "LST");
tui_draw_text(x + 2, y + 2, 0, "%s", tpu_last_str(tpu));
- tui_draw_box(x, (y += TPUT_INFO_H - 1), w, h, attr,
+ tui_draw_box(x, (y += TPU_INFO_H - 1), w, h, attr,
WACS_D_LTEE, WACS_D_RTEE, WACS_D_LTEE, WACS_D_RTEE);
tui_draw_text(x + 2, y + 1, A_BOLD, "MOD");
tui_draw_text(x + 2, y + 2, 0, "%s", tpu_mode_str(tpu));
- tui_draw_box(x, (y += TPUT_INFO_H - 1), w, h, attr,
+ tui_draw_box(x, (y += TPU_INFO_H - 1), w, h, attr,
WACS_D_LTEE, WACS_D_RTEE, WACS_D_BTEE, WACS_D_LRCORNER);
tui_draw_text(x + 2, y + 1, A_BOLD, "IDL");
if (tpu->steps > 0)
@@ -244,16 +242,16 @@ tui_draw_tpu(struct tpu *tpu)
if (tpu->ports[DIR_RIGHT].attached) {
port = &tpu->ports[DIR_RIGHT];
if (port->out >= 0)
- tui_draw_text(sx + TPUT_W + 1, sy + 5,
+ tui_draw_text(sx + TPU_W + 1, sy + 5,
A_BOLD, "%03i", port->out);
if (port->type & PORT_OUT)
- tui_draw_wch(sx + TPUT_W + 1, sy + 7,
+ tui_draw_wch(sx + TPU_W + 1, sy + 7,
port->out >= 0 ? A_BOLD : 0, WACS_RARROW);
if (port->type & PORT_IN)
- tui_draw_wch(sx + TPUT_W + 1, sy + 8,
+ tui_draw_wch(sx + TPU_W + 1, sy + 8,
port->in >= 0 ? A_BOLD : 0, WACS_LARROW);
if (port->in >= 0)
- tui_draw_text(sx + TPUT_W + 1, sy + 9,
+ tui_draw_text(sx + TPU_W + 1, sy + 9,
A_BOLD, "%03i", port->in);
}
@@ -276,16 +274,16 @@ tui_draw_tpu(struct tpu *tpu)
if (tpu->ports[DIR_DOWN].attached) {
port = &tpu->ports[DIR_DOWN];
if (port->out >= 0)
- tui_draw_text(sx + 9, sy + TPUT_H,
+ tui_draw_text(sx + 9, sy + TPU_H,
A_BOLD, "%03i", port->out);
if (port->type & PORT_IN)
- tui_draw_wch(sx + 13, sy + TPUT_H,
+ tui_draw_wch(sx + 13, sy + TPU_H,
port->in >= 0 ? A_BOLD : 0, WACS_UARROW);
if (port->type & PORT_OUT)
- tui_draw_wch(sx + 15, sy + TPUT_H,
+ tui_draw_wch(sx + 15, sy + TPU_H,
port->out >= 0 ? A_BOLD : 0, WACS_DARROW);
if (port->in >= 0)
- tui_draw_text(sx + 17, sy + TPUT_H,
+ tui_draw_text(sx + 17, sy + TPU_H,
A_BOLD, "%03i", port->in);
}
}
@@ -295,12 +293,19 @@ tui_draw(void)
{
struct tpu_map_link *link;
size_t i;
+ int tx;
clear();
for (i = 0; i < TPU_MAP_BUCKETS; i++) {
for (link = tis.tpu_map.buckets[i]; link; link = link->next)
tui_draw_tpu(link->tpu);
}
+ if (show_reloaded > 0) {
+ tx = MAX(0, scrx + scrw / 2 - 4);
+ tui_draw_text(scrx, scry, A_STANDOUT, "%-*s", scrw, "");
+ tui_draw_text(tx, scry, A_STANDOUT, "RELOADED");
+ show_reloaded--;
+ }
refresh();
}
@@ -342,12 +347,12 @@ tui_seek(struct tpu *tpu, int dx, int dy)
}
if (dx == MIN) scrx = minx - 2;
- else if (dx == MAX) scrx = maxx + TPUT_W + 2 - scrw;
- else if (dx == MID) scrx = (minx + maxx + TPUT_W - scrw) / 2;
+ else if (dx == MAX) scrx = maxx + TPU_W + 2 - scrw;
+ else if (dx == MID) scrx = (minx + maxx + TPU_W - scrw) / 2;
if (dy == MIN) scry = miny - 2;
- else if (dy == MAX) scry = maxy + TPUT_H + 2 - scrh;
- else if (dy == MID) scry = (miny + maxy + TPUT_H - scrh) / 2;
+ else if (dy == MAX) scry = maxy + TPU_H + 2 - scrh;
+ else if (dy == MID) scry = (miny + maxy + TPU_H - scrh) / 2;
}
static void
@@ -405,11 +410,35 @@ handlekey(int key)
}
}
+void
+reset(int ifd, int argc, char **argv)
+{
+ tis_load(&tis, argv[1]);
+
+ if (inotify_add_watch(ifd, argv[1], IN_MODIFY) < 0)
+ die("inotify_add_watch '%s':", argv[1]);
+
+ if (tis_stdin) fclose(tis_stdin);
+ tis_stdin = fopen(argv[2], "r");
+ if (!tis_stdin) die("fopen '%s':", argv[2]);
+
+ if (tis_stdout) fclose(tis_stdout);
+ tis_stdout = fopen(argv[3], "w+");
+ if (!tis_stdout) die("fopen '%s':", argv[3]);
+
+ tpu_sel = tis.stdin_port.dst_tpu;
+ tui_seek(NULL, MID, MID);
+
+}
+
int
main(int argc, char **argv)
{
+ struct inotify_event event;
+ ssize_t len;
bool quit;
int key;
+ int ifd;
if (argc != 4) {
fprintf(stderr, "Usage: tis-curses FILE STDIN STDOUT\n");
@@ -426,22 +455,25 @@ main(int argc, char **argv)
start_color();
curs_set(0);
tui_resize();
+ timeout(TIMEOUT);
ESCDELAY = 0;
tis_init(&tis);
- tis_load(&tis, argv[1]);
- tis_stdin = fopen(argv[2], "r");
- if (!tis_stdin) die("fopen '%s':", argv[2]);
+ ifd = inotify_init1(IN_NONBLOCK);
- tis_stdout = fopen(argv[3], "w+");
- if (!tis_stdout) die("fopen '%s':", argv[3]);
-
- tpu_sel = tis.stdin_port.dst_tpu;
- tui_seek(NULL, MID, MID);
+ reset(ifd, argc, argv);
quit = false;
while (!quit) {
+ len = read(ifd, &event, sizeof(event));
+ if (len < 0 && errno != EAGAIN)
+ die("inotify_read:");
+ if (len >= 0) {
+ reset(ifd, argc, argv);
+ show_reloaded = 1000 / TIMEOUT;
+ }
+
tui_draw();
key = getch();
switch (key) {
@@ -471,6 +503,8 @@ main(int argc, char **argv)
tis_deinit(&tis);
+ close(ifd);
+
fclose(tis_stdin);
fclose(tis_stdout);
diff --git a/tpu.c b/tpu.c
@@ -262,13 +262,13 @@ tpu_set_inst(struct tpu *tpu, uint8_t pc, enum tpu_inst_type inst_type,
inst = &tpu->insts[pc];
inst->type = inst_type;
- if (op2 > 0) {
+ if (op2 >= 0) {
inst->ops[1].type = (enum tpu_inst_op_type) op2;
inst->ops[1].lit = op2_lit;
inst->ops[0].type = (enum tpu_inst_op_type) op1;
inst->ops[0].lit = op1_lit;
inst->opcnt = 2;
- } else if (op1 > 0) {
+ } else if (op1 >= 0) {
inst->ops[0].type = (enum tpu_inst_op_type) op1;
inst->ops[0].lit = op1_lit;
inst->opcnt = 1;
diff --git a/util.h b/util.h
@@ -14,4 +14,4 @@ size_t strdcpy(char *dst, const char *src, size_t n);
size_t strdcat(char *dst, const char *src, size_t n);
extern const char *progname;
-extern void (*cleanup)(void);
+extern int (*cleanup)(void);