aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2015-11-25 22:36:40 -0500
committerFranklin Wei <git@fwei.tk>2015-11-25 22:36:40 -0500
commitf9bd70a047c357d7f4ebfadbfe34c30becb380db (patch)
tree7e991c719d0f40a453f9e8a83ccb9760ba6f3a4c
parent3c13f12ac8279ddccf2a20fbc072d6b918ea2096 (diff)
downloadducky-f9bd70a047c357d7f4ebfadbfe34c30becb380db.zip
ducky-f9bd70a047c357d7f4ebfadbfe34c30becb380db.tar.gz
ducky-f9bd70a047c357d7f4ebfadbfe34c30becb380db.tar.bz2
ducky-f9bd70a047c357d7f4ebfadbfe34c30becb380db.tar.xz
refactor, add simple builtin functions, fix osx bug
-rw-r--r--Makefile2
-rw-r--r--src/common.c142
-rw-r--r--src/compile.c233
-rw-r--r--src/ducky.h32
-rw-r--r--src/emitc.c96
-rw-r--r--src/interp.c210
-rw-r--r--src/opcodes.h1
-rw-r--r--src/vm.c77
8 files changed, 416 insertions, 377 deletions
diff --git a/Makefile b/Makefile
index 2a9afd4..6df226c 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ CC = gcc
OUT = build
PLATFORM = unix
-DUCKY_OBJ = src/interp.o src/compile.o src/vm.o src/emitc.o
+DUCKY_OBJ = src/interp.o src/compile.o src/vm.o src/emitc.o src/common.o
CFLAGS = -lm -Og -g -I src/ -I target/$(PLATFORM)
diff --git a/src/common.c b/src/common.c
new file mode 100644
index 0000000..b25b6a2
--- /dev/null
+++ b/src/common.c
@@ -0,0 +1,142 @@
+#include "ducky.h"
+
+vartype spec_zero(void)
+{
+ return 0;
+}
+
+vartype spec_rand(void)
+{
+ return rand();
+}
+
+vartype spec_time(void)
+{
+ return time(NULL);
+}
+
+vartype (*special_funcs[])(void) = {
+ spec_zero,
+ spec_rand,
+ spec_time,
+};
+
+void __attribute__((noreturn,format(printf,3,4))) error(jmp_buf exit_point, int current_line, const char *fmt, ...)
+{
+ char fmtbuf[256];
+
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
+ if(current_line)
+ vid_logf("Line %d: ", current_line);
+ vid_logf("ERROR: %s", fmtbuf);
+ va_end(ap);
+
+ longjmp(exit_point, 1);
+}
+
+vartype get_special(enum special_id special, jmp_buf exit_point, int current_line)
+{
+ if(special < ARRAYLEN(special_funcs))
+ return special_funcs[special]();
+ else
+ error(exit_point, current_line, "unknown special stream");
+}
+
+/* grabs a line from a file, -1 on error, returns # bytes read otherwise */
+int read_line(int fd, char *buf, size_t sz)
+{
+ unsigned i = 0;
+ int bytes_read = 0;
+ int status = 1;
+ while(i < sz)
+ {
+ char c;
+ status = read(fd, &c, 1);
+ if(status != 1)
+ break;
+
+ ++bytes_read;
+
+ if(c == '\r')
+ continue;
+ if(c == '\n' || c == EOF)
+ {
+ break;
+ }
+
+ buf[i++] = c;
+ }
+ buf[MIN(i, sz - 1)] = '\0';
+
+ return (status <= 0)?-1:bytes_read;
+}
+
+/* index_lines() precalculates the offset of each line for faster jumping */
+
+off_t *index_lines(int fd, unsigned *numlines, bool labels, bool (*isValidVariable)(const char*), void (*setConst)(const char*, bool), void (*setVariable)(const char*, vartype))
+{
+ size_t sz = sizeof(off_t);
+ off_t *data = malloc(sz);
+
+ /* this uses 1-indexed line numbers, so the first indice is wasted */
+ unsigned idx = 1;
+
+ while(1)
+ {
+ sz += sizeof(off_t);
+ data = realloc(data, sz);
+ data[idx] = lseek(fd, 0, SEEK_CUR);
+
+ char buf[MAX_LINE_LEN];
+
+ if(read_line(fd, buf, sizeof(buf)) < 0)
+ break;
+
+ if(labels)
+ {
+ char *save = NULL;
+ char *tok = strtok_r(buf, " \t", &save);
+ if(tok && (strcmp(tok, "LABEL") == 0 || strcmp("LBL", tok) == 0))
+ {
+ tok = strtok_r(NULL, " \t", &save);
+ if(tok && isValidVariable(tok))
+ {
+ setVariable(tok, idx);
+ setConst(tok, true);
+ }
+ }
+ }
+
+ ++idx;
+ }
+
+ lseek(fd, 0, SEEK_SET);
+
+ *numlines = idx - 1;
+
+ return data;
+}
+
+void __attribute__((format(printf,1,2))) vid_logf(const char *fmt, ...)
+{
+ char fmtbuf[256];
+
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
+ printf("%s\n", fmtbuf);
+ va_end(ap);
+}
+
+void __attribute__((format(printf,2,3))) warning_real(int current_line, const char *fmt, ...)
+{
+ char fmtbuf[256];
+
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
+ vid_logf("Line %d: WARNING: %s\n", current_line, fmtbuf);
+ va_end(ap);
+}
diff --git a/src/compile.c b/src/compile.c
index 20de9b1..2b53695 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -42,9 +42,7 @@ struct var_t {
bool constant;
};
-static void error(const char *fmt, ...) __attribute__((noreturn,format(print,1,2)));
static void vid_write(const char *str);
-static void vid_logf(const char *fmt, ...) __attribute__((format(printf,1,2)));
static void debug(const char *fmt, ...) __attribute__((format(printf,1,2)));
static bool isValidVariable(const char *c);
@@ -119,6 +117,13 @@ static void setConst(const char *name, bool c)
}
}
+static void setSpecial(const char *name, enum special_id spec)
+{
+ write_instr(MKSPECIAL);
+ write_varid(get_varid(name));
+ write_imm(spec);
+}
+
static void incVar(const char *name)
{
write_instr(INCVAR);
@@ -141,7 +146,7 @@ static void exit_handler(void)
free(line_offset);
}
-static void vid_write(const char *str)
+static void write_str(const char *str)
{
write_instr(WRITE_STR);
while(*str)
@@ -151,134 +156,6 @@ static void vid_write(const char *str)
write_byte('\0');
}
-static void __attribute__((format(printf,1,2))) vid_logf(const char *fmt, ...)
-{
- char fmtbuf[256];
-
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
- printf("%s\n", fmtbuf);
- va_end(ap);
-}
-
-static void __attribute__((noreturn,format(printf,1,2))) error(const char *fmt, ...)
-{
- char fmtbuf[256];
-
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
- if(current_line)
- vid_logf("Line %d: ", current_line);
- vid_logf("ERROR: %s", fmtbuf);
- va_end(ap);
-
- longjmp(exit_point, 1);
-}
-
-static void __attribute__((format(printf,1,2))) warning(const char *fmt, ...)
-{
- char fmtbuf[256];
-
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
- vid_logf("Line %d: WARNING: %s\n", current_line, fmtbuf);
- va_end(ap);
-}
-
-/* grabs a line from a file, -1 on error, returns # bytes read otherwise */
-static int read_line(int fd, char *buf, size_t sz)
-{
- unsigned i = 0;
- int bytes_read = 0;
- int status = 1;
- while(i < sz)
- {
- char c;
- status = read(fd, &c, 1);
- if(status != 1)
- break;
-
- ++bytes_read;
-
- if(c == '\r')
- continue;
- if(c == '\n' || c == EOF)
- {
- break;
- }
-
- buf[i++] = c;
- }
- buf[MIN(i, sz - 1)] = '\0';
-
- return (status <= 0)?-1:bytes_read;
-}
-
-/* depends on index_lines, indexes labels in the file */
-static void index_labels(int fd)
-{
- for(unsigned i = 1; i <= num_lines; ++i)
- {
- lseek(fd, line_offset[i], SEEK_SET);
- char buf[MAX_LINE_LEN];
- int status = read_line(fd, buf, sizeof(buf));
-
- /* exit early if failed or too short for a label */
- if(status < strlen("LBL"))
- break;
-
- char *save = NULL;
- char *tok = strtok_r(buf, " \t", &save);
- if(tok && (strcmp(tok, "LABEL") == 0 || strcmp("LBL", tok) == 0))
- {
- tok = strtok_r(NULL, " \t", &save);
-
- vid_logf("found label %s val %d", tok, i);
- if(tok && isValidVariable(tok))
- {
- setVariable(tok, i);
- setConst(tok, true);
- }
- }
- }
- lseek(fd, 0, SEEK_SET);
-}
-
-/* index_lines() precalculates the offset of each line for faster jumping */
-/* the line data is only used by index_labels */
-
-static off_t *index_lines(int fd, unsigned *numlines)
-{
- size_t sz = sizeof(off_t);
- off_t *data = malloc(sz);
-
- /* this uses 1-indexed line numbers, so the first indice is wasted */
- unsigned idx = 1;
-
- while(1)
- {
- sz += sizeof(off_t);
- data = realloc(data, sz);
- data[idx] = lseek(fd, 0, SEEK_CUR);
-
- char buf[MAX_LINE_LEN];
-
- if(read_line(fd, buf, sizeof(buf)) < 0)
- break;
-
- ++idx;
- }
-
- lseek(fd, 0, SEEK_SET);
-
- *numlines = idx - 1;
-
- return data;
-}
-
static void jump_line(int fd, unsigned where)
{
if(1 <= where && where <= num_lines)
@@ -286,7 +163,7 @@ static void jump_line(int fd, unsigned where)
lseek(fd, line_offset[where], SEEK_SET);
}
else
- error("JUMP target out of range (%u)", where);
+ ERROR("JUMP target out of range (%u)", where);
current_line = where - 1;
}
@@ -481,7 +358,7 @@ static void opmap_insert(struct op_s *op)
uint32_t hash = op_hash(op->op) % OPMAP_SIZE;
if(op_map[hash].op)
- error("hash map collision %lu: %s VS %s", hash, op->op, op_map[hash].op);
+ ERROR("hash map collision %lu: %s VS %s", hash, op->op, op_map[hash].op);
memcpy(op_map+hash, op, sizeof(*op));
}
@@ -519,7 +396,7 @@ static int nopstack;
static void push_opstack(const struct op_s *op)
{
if(nopstack>MAXOPSTACK - 1) {
- error("operator stack overflow");
+ ERROR("operator stack overflow");
}
opstack[nopstack++] = op;
}
@@ -527,7 +404,7 @@ static void push_opstack(const struct op_s *op)
static const struct op_s *pop_opstack(void)
{
if(!nopstack) {
- error("operator stack empty");
+ ERROR("operator stack empty");
}
return opstack[--nopstack];
}
@@ -600,7 +477,7 @@ static void shunt_op(const struct op_s *op)
if(!(pop = pop_opstack()) || strcmp(pop->op,"(") != 0)
{
- error("mismatched parentheses");
+ ERROR("mismatched parentheses");
}
return;
}
@@ -659,7 +536,7 @@ static vartype eval_expr(char *str)
}
else if(strcmp(op->op, "(") != 0 && !op->unary)
{
- error("illegal use of binary operator (%s)", op->op);
+ ERROR("illegal use of binary operator (%s)", op->op);
}
}
shunt_op(op);
@@ -669,7 +546,7 @@ static vartype eval_expr(char *str)
tstart = expr;
else if(!isSpace(*expr))
{
- error("syntax error");
+ ERROR("syntax ERROR");
}
}
else
@@ -719,7 +596,7 @@ static vartype eval_expr(char *str)
}
else if(!isValidNumberOrVariable(expr))
{
- error("syntax error");
+ ERROR("syntax ERROR");
}
}
}
@@ -766,14 +643,14 @@ static int let_handler(char **save)
if(tok)
eval_expr(tok);
else
- error("exprected valid expression after LET");
+ ERROR("exprected valid expression after LET");
write_instr(POP);
write_varid(varid);
}
else
{
- error("invalid variable name for LET");
+ ERROR("invalid variable name for LET");
}
return OK;
}
@@ -791,7 +668,7 @@ static int repeat_handler(char **save)
return OK;
}
else
- error("expected valid expression after REPEAT");
+ ERROR("expected valid expression after REPEAT");
}
static int goto_handler(char **save)
@@ -805,7 +682,7 @@ static int goto_handler(char **save)
return OK;
}
else
- error("expected valid expression after GOTO");
+ ERROR("expected valid expression after GOTO");
}
static int call_handler(char **save)
@@ -820,7 +697,7 @@ static int call_handler(char **save)
return OK;
}
else
- error("expected destination for CALL");
+ ERROR("expected destination for CALL");
}
static int ret_handler(char **save)
@@ -857,7 +734,7 @@ static int if_handler(char **save)
char *tok = strtok_r(NULL, ";", save);
if(!tok)
- error("expected conditional after IF");
+ ERROR("expected conditional after IF");
eval_expr(tok);
write_instr(PUSHIMM);
@@ -878,7 +755,7 @@ static int delay_handler(char **save)
write_instr(DELAY);
}
else
- error("expected valid expression after DELAY");
+ ERROR("expected valid expression after DELAY");
return OK;
}
@@ -888,7 +765,7 @@ static int log_handler(char **save)
(void) save;
char *tok = strtok_r(NULL, "", save);
- vid_write(tok);
+ write_str(tok);
return OK;
}
@@ -903,7 +780,7 @@ static int logvar_handler(char **save)
return OK;
}
else
- error("expected expression after LOGVAR");
+ ERROR("expected expression after LOGVAR");
}
static int rem_handler(char **save)
@@ -936,7 +813,7 @@ static int logchar_handler(char **save)
write_instr(LOGASCII);
}
else
- error("expected expression after LOGCHAR");
+ ERROR("expected expression after LOGCHAR");
return OK;
}
@@ -954,7 +831,7 @@ static int input_handler(char **save)
}
else
{
- error("invalid variable name for INPUT");
+ ERROR("invalid variable name for INPUT");
}
return OK;
}
@@ -967,14 +844,14 @@ static int prompt_handler(char **save)
if(varname && isValidVariable(varname))
{
int varid = get_varid(varname);
- vid_write(varname);
- vid_write("? ");
+ write_str(varname);
+ write_str("? ");
write_instr(READ_VAR);
write_varid(varid);
}
else
{
- error("invalid variable name for PROMPT");
+ ERROR("invalid variable name for PROMPT");
}
return OK;
}
@@ -1039,7 +916,7 @@ static int dfldel_handler(char **save)
write_instr(DFL_DELAY);
}
else
- error("expected expression for DEFAULT_DELAY");
+ ERROR("expected expression for DEFAULT_DELAY");
return OK;
}
@@ -1052,7 +929,7 @@ static int strdel_handler(char **save)
write_instr(STR_DELAY);
}
else
- error("expected expression for STRING_DELAY");
+ ERROR("expected expression for STRING_DELAY");
return OK;
}
@@ -1066,7 +943,7 @@ static int out_handler(char **save)
write_instr(TYPE_DEC);
}
else
- error("expected expression for default delay");
+ ERROR("expected expression for default delay");
return OK;
}
@@ -1639,7 +1516,7 @@ static void tokmap_insert(struct token_t *tok)
{
uint32_t hash = tok_hash(tok->tok) % TOKMAP_SIZE;
if(hash < 0 || tokmap[hash].tok)
- error("FIXME: hash map collision %s %s", tok->tok, tokmap[hash].tok);
+ ERROR("FIXME: hash map collision %s %s", tok->tok, tokmap[hash].tok);
memcpy(tokmap+hash, tok, sizeof(*tok));
}
@@ -1660,6 +1537,35 @@ static void init_globals(void)
bytes_written = 0;
}
+/* depends on index_lines's output, indexes labels in the file */
+void index_labels(int fd)
+{
+ for(unsigned i = 1; i <= num_lines; ++i)
+ {
+ lseek(fd, line_offset[i], SEEK_SET);
+ char buf[MAX_LINE_LEN];
+ int status = read_line(fd, buf, sizeof(buf));
+
+ /* exit early if failed or too short for a label */
+ if(status < strlen("LBL"))
+ break;
+
+ char *save = NULL;
+ char *tok = strtok_r(buf, " \t", &save);
+ if(tok && (strcmp(tok, "LABEL") == 0 || strcmp("LBL", tok) == 0))
+ {
+ tok = strtok_r(NULL, " \t", &save);
+
+ if(tok && isValidVariable(tok))
+ {
+ setVariable(tok, i);
+ setConst(tok, true);
+ }
+ }
+ }
+ lseek(fd, 0, SEEK_SET);
+}
+
int ducky_compile(int fd, bool verbose, int out)
{
if(!setjmp(exit_point))
@@ -1677,12 +1583,12 @@ int ducky_compile(int fd, bool verbose, int out)
atexit(exit_handler);
if(file_des < 0)
- error("invalid file");
+ ERROR("invalid file");
init_optable();
init_tokmap();
- line_offset = index_lines(file_des, &num_lines);
+ line_offset = index_lines(file_des, &num_lines, false, isValidVariable, setConst, setVariable);
write_imm(DUCKY_MAGIC);
write_imm(num_lines);
off_t linetab_off = bytes_written;
@@ -1703,6 +1609,11 @@ int ducky_compile(int fd, bool verbose, int out)
makeConstantVariable("true", 1);
makeConstantVariable("false", 0);
+ /* initialize the special variables */
+ setSpecial("NULL", SPECIAL_NULL);
+ setSpecial("RAND", SPECIAL_RAND);
+ setSpecial("TIME", SPECIAL_TIME);
+
/* initialize labels (using output from index_lines) */
index_labels(file_des);
@@ -1750,7 +1661,7 @@ int ducky_compile(int fd, bool verbose, int out)
case NEXT:
goto next_line;
default:
- error("FIXME: invalid return value");
+ ERROR("FIXME: invalid return value");
}
#ifdef DUCKY_ROCKBOX
else if(strlen(tok) == 1)
@@ -1763,7 +1674,7 @@ int ducky_compile(int fd, bool verbose, int out)
goto next_line;
else
{
- error("unknown token `%s` on line %d %d", tok, current_line);
+ ERROR("unknown token `%s` on line %d %d", tok, current_line);
goto done;
}
} while(tok);
diff --git a/src/ducky.h b/src/ducky.h
index 1552134..2fda55d 100644
--- a/src/ducky.h
+++ b/src/ducky.h
@@ -1,10 +1,20 @@
#include <stdbool.h>
#include <stdint.h>
+#include "platform.h"
#define DUCKY_MAGIC 0x4475634B /* DucK */
#define VARFORMAT "%d"
#define VARNAME_MAX 24
+
+#define DEFAULT_DELAY 0
+#define STRING_DELAY 0
+#define TOKEN_IS(str) (strcmp(tok, str) == 0)
+#define MAX_LINE_LEN 512
+
#define MAXOPSTACK 64
+#define MAXNUMSTACK 64
+#define CALL_STACK_SZ 64
+#define VARMAP_SIZE 256
/* define for rockbox cross-compile */
#define DUCKY_ROCKBOX
@@ -15,12 +25,26 @@
#define OK 0
-int ducky_interp(int fd, bool verbose);
-int ducky_compile(int fd, bool verbose, int out_fd);
-int ducky_vm(int fd);
-int ducky_to_c(int fd, int out_fd);
+enum special_id { SPECIAL_NULL = 0, SPECIAL_RAND, SPECIAL_TIME };
typedef int32_t imm_t;
typedef uint8_t instr_t;
typedef uint16_t varid_t;
typedef imm_t vartype;
+
+int ducky_interp(int fd, bool verbose);
+int ducky_compile(int fd, bool verbose, int out_fd);
+int ducky_vm(int fd);
+int ducky_to_c(int fd, int out_fd);
+
+int read_line(int fd, char *buf, size_t sz);
+
+off_t *index_lines(int fd, unsigned *numlines, bool labels, bool (*isValidVariable)(const char*), void (*setConst)(const char*, bool), void (*setVariable)(const char*, vartype));
+
+void vid_logf(const char *fmt, ...) __attribute__((format(printf,1,2)));
+
+void error(jmp_buf exit_point, int current_line, const char *fmt, ...) __attribute__((noreturn,format(printf,3,4)));
+
+#define ERROR(fmt, ...) (error(exit_point, current_line, fmt, ##__VA_ARGS__))
+void warning_real(int current_line, const char *fmt, ...) __attribute__((format(printf,2,3)));
+#define WARNING(fmt, ...) (warning_real(current_line, fmt, ##__VA_ARGS__))
diff --git a/src/emitc.c b/src/emitc.c
index 6de0401..94d8210 100644
--- a/src/emitc.c
+++ b/src/emitc.c
@@ -23,9 +23,7 @@ static int repeats_left;
static imm_t repeat_line;
static jmp_buf exit_point;
-static void error(const char *fmt, ...) __attribute__((noreturn,format(print,1,2)));
static void vid_write(const char *str);
-static void vid_logf(const char *fmt, ...) __attribute__((format(printf,1,2)));
static instr_t read_instr(void)
{
@@ -133,21 +131,6 @@ static void __attribute__((format(printf,1,2))) vid_writef(const char *fmt, ...)
va_end(ap);
}
-static void __attribute__((noreturn,format(printf,1,2))) error(const char *fmt, ...)
-{
- char fmtbuf[256];
-
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
- if(current_line)
- vid_writef("Line %d: ", current_line);
- vid_writef("ERROR: %s\n", fmtbuf);
- va_end(ap);
-
- longjmp(exit_point, 1);
-}
-
static void __attribute__((format(printf,1,2))) warning(const char *fmt, ...)
{
char fmtbuf[256];
@@ -220,7 +203,7 @@ static void repeat_handler(void)
write_src("if(repeats_left > 0)\n");
write_src("{\n");
write_src("if(repeat_line + 1 != vars[0].val)\n");
- write_src("error(\"nested REPEAT\");\n");
+ write_src("ERROR(\"nested REPEAT\");\n");
write_src("--repeats_left;\n");
write_src("if(repeats_left > 0)\n");
write_src("{\n");
@@ -248,7 +231,7 @@ static void subcall_handler(void)
write_src("JUMP(POP());\n");
write_src("}\n");
write_src("else\n");
- write_src("error(\"call stack overflow\");\n");
+ write_src("ERROR(\"call stack overflow\");\n");
}
static void subret_handler(void)
@@ -258,7 +241,7 @@ static void subret_handler(void)
write_src("JUMP(callstack[--callstack_pointer]);\n");
write_src("}\n");
write_src("else\n");
- write_src("error(\"call stack underflow\");\n");
+ write_src("ERROR(\"call stack underflow\");\n");
}
static void if_handler(void)
@@ -335,7 +318,7 @@ static void mod_handler(void)
write_src("{\n");
write_src("imm_t b = POP();\n");
write_src("imm_t a = POP();\n");
- write_src("PUSH(a%b);\n");
+ write_src("PUSH(a%%b);\n");
write_src("}\n");
}
@@ -511,6 +494,14 @@ static void input_handler(void)
write_src("}\n");
}
+static void mkspecial_handler(void)
+{
+ varid_t varid = read_varid();
+ write_src("vars[%d].constant = true;\n", varid);
+ write_src("vars[%d].type = TYPE_SPECIAL;\n", varid);
+ write_src("vars[%d].special = %d;\n", varid, read_imm());
+}
+
static void inc_line_pointer(void)
{
++current_line;
@@ -568,7 +559,7 @@ static void (*instr_tab[0x100])(void) = {
NULL, /* 0x2d */
newline_handler, /* 0x2e */
input_handler, /* 0x2f */
- NULL, /* 0x30 */
+ mkspecial_handler, /* 0x30 */
NULL, /* 0x31 */
NULL, /* 0x32 */
NULL, /* 0x33 */
@@ -787,7 +778,8 @@ void write_stub_code(int num_lines)
write_src("#include <stdio.h>\n");
write_src("#include <stdint.h>\n");
write_src("#include <stdlib.h>\n\n");
- write_src("#include <math.h>\n\n");
+ write_src("#include <math.h>\n");
+ write_src("#include <time.h>\n\n");
write_src("#define CALLSTACK_SZ %d\n", CALLSTACK_SZ);
write_src("#define MAX_VARS %d\n", MAX_VARS);
write_src("#define STACK_SZ %d\n\n", STACK_SZ);
@@ -797,7 +789,7 @@ void write_stub_code(int num_lines)
write_src("imm_t stack[STACK_SZ];\n");
write_src("imm_t callstack[CALLSTACK_SZ];\n");
write_src("unsigned repeats_left = 0, repeat_line = 0;\n");
- write_src("struct var_t { imm_t val; bool constant; };\n");
+ write_src("struct var_t { enum {TYPE_PLAIN, TYPE_SPECIAL} type; bool constant; union { vartype val; int special;}; };\n");
write_src("struct var_t vars[MAX_VARS];\n\n");
write_src("static inline void vid_write(const char *str)\n");
@@ -815,7 +807,7 @@ void write_stub_code(int num_lines)
write_src("va_end(ap);\n");
write_src("}\n");
- write_src("static void __attribute__((noreturn,format(printf,1,2))) error(const char *fmt, ...)\n");
+ write_src("static void __attribute__((noreturn,format(printf,1,2))) ERROR(const char *fmt, ...)\n");
write_src("{\n");
write_src("char fmtbuf[256];\n");
write_src("va_list ap;\n");
@@ -828,13 +820,45 @@ void write_stub_code(int num_lines)
write_src("exit(EXIT_FAILURE);\n");
write_src("}\n");
+ write_src("vartype spec_zero(void)\n");
+ write_src("{\n");
+ write_src("return 0;\n");
+ write_src("}\n");
+
+ write_src("vartype spec_rand(void)\n");
+ write_src("{\n");
+ write_src("return rand();\n");
+ write_src("}\n");
+
+ write_src("vartype spec_time(void)\n");
+ write_src("{\n");
+ write_src("return time(NULL);\n");
+ write_src("}\n");
+
+ write_src("vartype (*special_funcs[])(void) = ");
+ write_src("{\n");
+ write_src("spec_zero,\n");
+ write_src("spec_rand,\n");
+ write_src("spec_time,\n");
+ write_src("};\n");
+
+ write_src("#define ARRAYLEN(x) (sizeof(x)/sizeof(x[0]))\n");
+
+ write_src("vartype get_special(int special)\n");
+ write_src("{\n");
+ write_src("if(special < ARRAYLEN(special_funcs))\n");
+ write_src("return special_funcs[special]();\n");
+ write_src("else\n");
+ write_src("ERROR(\"unknown special stream\");\n");
+ write_src("}\n");
+
#if 0
write_src("static inline void PUSH(imm_t n)\n");
write_src("{\n");
write_src("if(stack_pointer < STACK_SZ)\n");
write_src("stack[stack_pointer++] = n;\n");
write_src("else\n");
- write_src("error(\"stack overflow\");\n");
+ write_src("ERROR(\"stack overflow\");\n");
write_src("}\n");
write_src("static inline imm_t POP(void)\n");
@@ -842,16 +866,20 @@ void write_stub_code(int num_lines)
write_src("if(stack_pointer > 0)\n");
write_src("return stack[--stack_pointer];\n");
write_src("else\n");
- write_src("error(\"stack underflow\");\n");
+ write_src("ERROR(\"stack underflow\");\n");
write_src("}\n");
#endif
write_src("static inline vartype getvar(varid_t varid)\n");
write_src("{\n");
write_src("if(varid < %d)\n", MAX_VARS);
+ write_src("{\n");
+ write_src("struct var_t *var = vars+varid;\n");
+ write_src("if(var->type == TYPE_PLAIN)\n");
write_src("return vars[varid].val;\n");
write_src("else\n");
- write_src("error(\"cannot access variable\");\n");
+ write_src("return get_special(vars[varid].special);\n");
+ write_src("}\n");
write_src("}\n");
write_src("static inline void setvar(varid_t varid, vartype val)\n");
@@ -859,7 +887,7 @@ void write_stub_code(int num_lines)
write_src("if(varid < %d && !vars[varid].constant)\n", MAX_VARS);
write_src("vars[varid].val = val;\n");
write_src("else\n");
- write_src("error(\"cannot modify variable\");\n");
+ write_src("ERROR(\"cannot modify variable\");\n");
write_src("}\n");
write_src("static inline void mkconst(varid_t varid)\n");
@@ -873,8 +901,8 @@ void write_stub_code(int num_lines)
write_src("return a2<0 ? 0 : (a2==0?1:a1*eval_exp(a1, a2-1));\n");
write_src("}\n");
- write_src("#define JUMP(LINE) do{imm_t x = LINE; if(1 <= x && x <= %d) goto *jump_table[x]; else error(\"jump target out of range\");}while(0);\n\n", num_lines);
- write_src("#define PUSH(VAL) do { imm_t x = VAL; if(stack_pointer < STACK_SZ) stack[stack_pointer++] = x; else error(\"stack overflow\");}while(0);\n\n");
+ write_src("#define JUMP(LINE) do{imm_t x = LINE; if(1 <= x && x <= %d) goto *jump_table[x]; else ERROR(\"jump target out of range\");}while(0);\n\n", num_lines);
+ write_src("#define PUSH(VAL) do { imm_t x = VAL; if(stack_pointer < STACK_SZ) stack[stack_pointer++] = x; else ERROR(\"stack overflow\");}while(0);\n\n");
write_src("#define POP() (stack[--stack_pointer])\n");
write_src("int main()\n");
@@ -882,6 +910,8 @@ void write_stub_code(int num_lines)
write_src("register imm_t stack_pointer = 0, callstack_pointer = 0;\n");
write_src("(void) stack_pointer; (void) callstack_pointer;\n");
write_src("(void) eval_exp;\n");
+ /* prefetch some high-use variables */
+
write_src("/* this uses labels as values, a GCC extension */\n");
write_src("const void *jump_table[%d] = {\n", num_lines + 1);
@@ -905,7 +935,7 @@ int ducky_to_c(int fd, int out)
init_globals();
if(read_imm() != DUCKY_MAGIC)
- error("unknown format");
+ ERROR("unknown format");
num_lines = read_imm();
for(unsigned int i = 1; i <= num_lines; ++i)
@@ -925,7 +955,7 @@ int ducky_to_c(int fd, int out)
if(handler)
handler();
else
- error("invalid instruction %d", instr);
+ ERROR("invalid instruction %d", instr);
}
write_src("}");
return 0;
diff --git a/src/interp.c b/src/interp.c
index c49d13e..1ee91c3 100644
--- a/src/interp.c
+++ b/src/interp.c
@@ -28,18 +28,6 @@
/*** Defines ***/
-#define DEFAULT_DELAY 0
-#define STRING_DELAY 0
-#define TOKEN_IS(str) (strcmp(tok, str) == 0)
-#define MAX_LINE_LEN 512
-
-#define MAXOPSTACK 64
-#define MAXNUMSTACK 64
-#define CALL_STACK_SZ 64
-#define VARMAP_SIZE 256
-
-#define VARNAME_MAX 24
-
/*** Globals ***/
static off_t *line_offset = NULL;
@@ -57,12 +45,17 @@ static jmp_buf exit_point;
struct varnode_t {
char name[VARNAME_MAX + 1];
- vartype val;
- bool constant; /* used by setVariable */
+ enum { TYPE_PLAIN, TYPE_SPECIAL } type;
+ bool constant;
+ union {
+ vartype val;
+ struct {
+ enum special_id special;
+ };
+ };
struct varnode_t *next;
};
-static void error(const char *fmt, ...) __attribute__((noreturn,format(print,1,2)));
static void vid_write(const char *str);
static void vid_writef(const char *fmt, ...) __attribute__((format(printf,1,2)));
static void debug(const char *fmt, ...) __attribute__((format(printf,1,2)));
@@ -108,6 +101,7 @@ static struct varnode_t *lookup_var(const char *name)
strncpy(new->name, name, sizeof(new->name));
new->val = 0;
new->constant = false;
+ new->type = TYPE_PLAIN;
new->next = NULL;
if(!last)
@@ -120,7 +114,13 @@ static struct varnode_t *lookup_var(const char *name)
static vartype getVariable(const char *name)
{
- return lookup_var(name)->val;
+ struct varnode_t *node = lookup_var(name);
+ if(node->type == TYPE_PLAIN)
+ return node->val;
+ else if(node->type == TYPE_SPECIAL)
+ return get_special(node->special);
+ else
+ ERROR("unknown type");
}
static void setVariable(const char *name, vartype val)
@@ -129,7 +129,7 @@ static void setVariable(const char *name, vartype val)
if(!node->constant)
node->val = val;
else
- error("attempted to modify a constant variable");
+ ERROR("attempted to modify a constant variable");
}
static void setConst(const char *name, bool c)
@@ -137,13 +137,21 @@ static void setConst(const char *name, bool c)
lookup_var(name)->constant = c;
}
+static void setSpecial(const char *name, enum special_id spec)
+{
+ struct varnode_t *node = lookup_var(name);
+ node->type = TYPE_SPECIAL;
+ node->special = spec;
+ node->constant = true;
+}
+
static void incVar(const char *name)
{
struct varnode_t *node = lookup_var(name);
if(!node->constant)
++lookup_var(name)->val;
else
- error("attempted to modify a constant variable");
+ ERROR("attempted to modify a constant variable");
}
static void decVar(const char *name)
@@ -152,7 +160,7 @@ static void decVar(const char *name)
if(!node->constant)
--lookup_var(name)->val;
else
- error("attempted to modify a constant variable");
+ ERROR("attempted to modify a constant variable");
}
/*** Utility functions ***/
@@ -193,21 +201,6 @@ static void __attribute__((format(printf,1,2))) vid_writef(const char *fmt, ...)
va_end(ap);
}
-static void __attribute__((noreturn,format(printf,1,2))) error(const char *fmt, ...)
-{
- char fmtbuf[256];
-
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
- if(current_line)
- vid_writef("Line %d: ", current_line);
- vid_writef("ERROR: %s\n", fmtbuf);
- va_end(ap);
-
- longjmp(exit_point, 1);
-}
-
static void __attribute__((format(printf,1,2))) warning(const char *fmt, ...)
{
char fmtbuf[256];
@@ -219,79 +212,6 @@ static void __attribute__((format(printf,1,2))) warning(const char *fmt, ...)
va_end(ap);
}
-/* grabs a line from a file, -1 on error, returns # bytes read otherwise */
-static int read_line(int fd, char *buf, size_t sz)
-{
- unsigned i = 0;
- int bytes_read = 0;
- int status = 1;
- while(i < sz)
- {
- char c;
- status = read(fd, &c, 1);
- if(status != 1)
- break;
-
- ++bytes_read;
-
- if(c == '\r')
- continue;
- if(c == '\n' || c == EOF)
- {
- break;
- }
-
- buf[i++] = c;
- }
- buf[MIN(i, sz - 1)] = '\0';
-
- return (status <= 0)?-1:bytes_read;
-}
-
-/* index_lines() precalculates the offset of each line for faster jumping */
-/* also it does a quick pass to index all the labels */
-
-static off_t *index_lines(int fd, unsigned *numlines)
-{
- size_t sz = sizeof(off_t);
- off_t *data = malloc(sz);
-
- /* this uses 1-indexed line numbers, so the first indice is wasted */
- unsigned idx = 1;
-
- while(1)
- {
- sz += sizeof(off_t);
- data = realloc(data, sz);
- data[idx] = lseek(fd, 0, SEEK_CUR);
-
- char buf[MAX_LINE_LEN];
-
- if(read_line(fd, buf, sizeof(buf)) < 0)
- break;
-
- char *save = NULL;
- char *tok = strtok_r(buf, " \t", &save);
- if(tok && (strcmp(tok, "LABEL") == 0 || strcmp("LBL", tok) == 0))
- {
- tok = strtok_r(NULL, " \t", &save);
- if(tok && isValidVariable(tok))
- {
- setVariable(tok, idx);
- lookup_var(tok)->constant = true;
- }
- }
-
- ++idx;
- }
-
- lseek(fd, 0, SEEK_SET);
-
- *numlines = idx - 1;
-
- return data;
-}
-
static void jump_line(int fd, unsigned where)
{
if(1 <= where && where <= num_lines)
@@ -299,7 +219,7 @@ static void jump_line(int fd, unsigned where)
lseek(fd, line_offset[where], SEEK_SET);
}
else
- error("JUMP target out of range (%u)", where);
+ ERROR("JUMP target out of range (%u)", where);
current_line = where - 1;
}
@@ -312,7 +232,7 @@ static void sub_call(int fd, unsigned where)
jump_line(fd, where);
}
else
- error("call stack overflow");
+ ERROR("call stack overflow");
}
static void sub_return(int fd)
@@ -344,14 +264,14 @@ static vartype eval_mul(vartype a1, vartype a2)
static vartype eval_div(vartype a1, vartype a2)
{
if(!a2) {
- error("division by zero");
+ ERROR("division by zero");
}
return a1/a2;
}
static vartype eval_mod(vartype a1, vartype a2)
{
if(!a2) {
- error("division by zero");
+ ERROR("division by zero");
}
return a1%a2;
}
@@ -525,7 +445,7 @@ static void opmap_insert(struct op_s *op)
uint32_t hash = op_hash(op->op) % OPMAP_SIZE;
if(op_map[hash].op)
- error("hash map collision %lu: %s VS %s", hash, op->op, op_map[hash].op);
+ ERROR("hash map collision %lu: %s VS %s", hash, op->op, op_map[hash].op);
memcpy(op_map+hash, op, sizeof(*op));
}
@@ -566,7 +486,7 @@ static int nnumstack;
static void push_opstack(const struct op_s *op)
{
if(nopstack>MAXOPSTACK - 1) {
- error("operator stack overflow");
+ ERROR("operator stack overflow");
}
opstack[nopstack++] = op;
}
@@ -574,7 +494,7 @@ static void push_opstack(const struct op_s *op)
static const struct op_s *pop_opstack(void)
{
if(!nopstack) {
- error("operator stack empty");
+ ERROR("operator stack empty");
}
return opstack[--nopstack];
}
@@ -582,7 +502,7 @@ static const struct op_s *pop_opstack(void)
static void push_numstack(vartype num)
{
if(nnumstack>MAXNUMSTACK - 1) {
- error("number stack overflow");
+ ERROR("number stack overflow");
}
numstack[nnumstack++] = num;
}
@@ -590,7 +510,7 @@ static void push_numstack(vartype num)
static vartype pop_numstack(void)
{
if(!nnumstack) {
- error("number stack empty");
+ ERROR("number stack empty");
}
return numstack[--nnumstack];
}
@@ -684,7 +604,7 @@ static void shunt_op(const struct op_s *op)
if(!(pop = pop_opstack()) || strcmp(pop->op,"(") != 0)
{
- error("mismatched parentheses");
+ ERROR("mismatched parentheses");
}
return;
}
@@ -760,7 +680,7 @@ static vartype eval_expr(char *str)
}
else if(strcmp(op->op, "(") != 0 && !op->unary)
{
- error("illegal use of binary operator (%s)", op->op);
+ ERROR("illegal use of binary operator (%s)", op->op);
}
}
shunt_op(op);
@@ -770,7 +690,7 @@ static vartype eval_expr(char *str)
tstart = expr;
else if(!isSpace(*expr))
{
- error("syntax error");
+ ERROR("syntax ERROR");
}
}
else
@@ -790,7 +710,7 @@ static vartype eval_expr(char *str)
}
else if(!isValidNumberOrVariable(expr))
{
- error("syntax error");
+ ERROR("syntax ERROR");
}
}
}
@@ -811,7 +731,7 @@ static vartype eval_expr(char *str)
}
if(nnumstack != 1) {
- error("invalid expression");
+ ERROR("invalid expression");
}
return numstack[0];
@@ -831,17 +751,17 @@ static int let_handler(char **save, int *repeats_left)
{
struct varnode_t *node = lookup_var(varname);
if(node->constant)
- error("attempted to modify a constant variable");
+ ERROR("attempted to modify a constant variable");
char *tok = strtok_r(NULL, "=;", save);
if(tok)
node->val = eval_expr(tok);
else
- error("exprected valid expression after LET");
+ ERROR("exprected valid expression after LET");
}
else
{
- error("invalid variable name for LET");
+ ERROR("invalid variable name for LET");
}
return OK;
}
@@ -852,7 +772,7 @@ static int repeat_handler(char **save, int *repeats_left)
if(*repeats_left > 0)
{
if(repeat_line + 1 != current_line)
- error("nested REPEAT");
+ ERROR("nested REPEAT");
--(*repeats_left);
if(*repeats_left)
jump_line(file_des, repeat_line);
@@ -863,7 +783,7 @@ static int repeat_handler(char **save, int *repeats_left)
if(tok)
{
if(current_line == 1)
- error("REPEAT without a previous instruction");
+ ERROR("REPEAT without a previous instruction");
*repeats_left = eval_expr(tok) - 1;
if(*repeats_left)
{
@@ -872,7 +792,7 @@ static int repeat_handler(char **save, int *repeats_left)
}
}
else
- error("expected valid expression after REPEAT");
+ ERROR("expected valid expression after REPEAT");
}
return NEXT;
}
@@ -887,7 +807,7 @@ static int goto_handler(char **save, int *repeats_left)
return NEXT;
}
else
- error("expected valid expression after GOTO");
+ ERROR("expected valid expression after GOTO");
}
static int call_handler(char **save, int *repeats_left)
@@ -900,7 +820,7 @@ static int call_handler(char **save, int *repeats_left)
return NEXT;
}
else
- error("expected destination for CALL");
+ ERROR("expected destination for CALL");
}
static int ret_handler(char **save, int *repeats_left)
@@ -934,7 +854,7 @@ static int if_handler(char **save, int *repeats_left)
char *tok = strtok_r(NULL, ";", save);
if(!tok)
- error("expected conditional after IF");
+ ERROR("expected conditional after IF");
/* break out of the do-while if the condition is false */
if(!eval_expr(tok))
@@ -958,7 +878,7 @@ static int delay_handler(char **save, int *repeats_left)
nanosleep(&t, NULL);
}
else
- error("expected valid expression after DELAY");
+ ERROR("expected valid expression after DELAY");
return OK;
}
@@ -982,7 +902,7 @@ static int logvar_handler(char **save, int *repeats_left)
return OK;
}
else
- error("expected expression after LOGVAR");
+ ERROR("expected expression after LOGVAR");
}
static int rem_handler(char **save, int *repeats_left)
@@ -1014,7 +934,7 @@ static int logchar_handler(char **save, int *repeats_left)
return OK;
}
else
- error("expected expression after LOGCHAR");
+ ERROR("expected expression after LOGCHAR");
}
@@ -1027,12 +947,12 @@ static int input_handler(char **save, int *repeats_left)
{
struct varnode_t *node = lookup_var(varname);
if(node->constant)
- error("attempted to modify a constant variable");
+ ERROR("attempted to modify a constant variable");
scanf(VARFORMAT, &node->val);
}
else
- error("expected valid variable name after INPUT");
+ ERROR("expected valid variable name after INPUT");
return OK;
}
@@ -1046,12 +966,12 @@ static int prompt_handler(char **save, int *repeats_left)
vid_writef("%s? ", varname);
struct varnode_t *node = lookup_var(varname);
if(node->constant)
- error("attempted to modify a constant variable");
+ ERROR("attempted to modify a constant variable");
scanf(VARFORMAT, &node->val);
}
else
- error("expected valid variable name after PROMPT");
+ ERROR("expected valid variable name after PROMPT");
return OK;
}
@@ -1248,7 +1168,7 @@ static void tokmap_insert(struct token_t *tok)
{
uint32_t hash = tok_hash(tok->tok) % TOKMAP_SIZE;
if(hash < 0 || tokmap[hash].tok)
- error("FIXME: hash map collision");
+ ERROR("FIXME: hash map collision");
memcpy(tokmap+hash, tok, sizeof(*tok));
}
@@ -1289,7 +1209,7 @@ int ducky_interp(int fd, bool verbose)
atexit(exit_handler);
if(file_des < 0)
- error("invalid file");
+ ERROR("invalid file");
init_optable();
init_tokmap();
@@ -1307,7 +1227,13 @@ int ducky_interp(int fd, bool verbose)
setVariable("false", 0);
setConst("false", true);
- line_offset = index_lines(file_des, &num_lines);
+ /* initialize the special variables */
+ setSpecial("NULL", SPECIAL_NULL);
+ setSpecial("RAND", SPECIAL_RAND);
+ setSpecial("TIME", SPECIAL_TIME);
+
+ line_offset = index_lines(file_des, &num_lines, true, isValidVariable, setConst, setVariable);
+
if(verbose)
{
vid_writef("Indexing complete (%u lines).", num_lines);
@@ -1356,13 +1282,13 @@ int ducky_interp(int fd, bool verbose)
case NEXT:
goto next_line;
default:
- error("FIXME: invalid return value");
+ ERROR("FIXME: invalid return value");
}
else if(tok[0] == '#')
goto next_line;
else
{
- error("unknown token `%s` on line %d %d", tok, current_line);
+ ERROR("unknown token `%s` on line %d %d", tok, current_line);
goto done;
}
} while(tok);
diff --git a/src/opcodes.h b/src/opcodes.h
index 521afcf..2a0288c 100644
--- a/src/opcodes.h
+++ b/src/opcodes.h
@@ -46,5 +46,6 @@
#define ADD_CHAR 0x2D
#define NEWLINE 0x2E
#define READ_VAR 0x2F
+#define MKSPECIAL 0x30
/* new opcodes here, be sure to update compile.c, vm.c, and emitc.c */
#define LINEMARK 0xFF
diff --git a/src/vm.c b/src/vm.c
index 3e19c20..407762d 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -15,7 +15,15 @@ static unsigned stack_pointer;
static jmp_buf exit_point;
struct var_t {
- vartype val;
+ enum { TYPE_PLAIN, TYPE_SPECIAL } type;
+
+ union {
+ vartype val;
+ struct {
+ enum special_id special;
+ };
+ };
+
bool constant;
};
@@ -29,9 +37,7 @@ static bool want_quit;
static int repeats_left;
static imm_t repeat_line;
-static void error(const char *fmt, ...) __attribute__((noreturn,format(print,1,2)));
static void vid_write(const char *str);
-static void vid_logf(const char *fmt, ...) __attribute__((format(printf,1,2)));
instr_t read_instr(void)
{
@@ -81,21 +87,6 @@ static void __attribute__((format(printf,1,2))) vid_writef(const char *fmt, ...)
va_end(ap);
}
-static void __attribute__((noreturn,format(printf,1,2))) error(const char *fmt, ...)
-{
- char fmtbuf[256];
-
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
- if(current_line)
- vid_writef("Line %d: ", current_line);
- vid_writef("ERROR: %s\n", fmtbuf);
- va_end(ap);
-
- longjmp(exit_point, 1);
-}
-
static void __attribute__((format(printf,1,2))) warning(const char *fmt, ...)
{
char fmtbuf[256];
@@ -122,7 +113,7 @@ static inline void push(imm_t n)
if(stack_pointer < STACK_SZ)
stack[stack_pointer++] = n;
else
- error("stack overflow");
+ ERROR("stack overflow");
}
static inline imm_t pop(void)
@@ -130,13 +121,19 @@ static inline imm_t pop(void)
if(stack_pointer > 0)
return stack[--stack_pointer];
else
- error("stack underflow");
+ ERROR("stack underflow");
}
static inline vartype getvar(varid_t varid)
{
if(varid < ARRAYLEN(vars))
- return vars[varid].val;
+ {
+ struct var_t *var = vars+varid;
+ if(var->type == TYPE_PLAIN)
+ return vars[varid].val;
+ else
+ return get_special(vars[varid].special);
+ }
}
static inline void setvar(varid_t varid, vartype val)
@@ -144,7 +141,7 @@ static inline void setvar(varid_t varid, vartype val)
if(varid < ARRAYLEN(vars) && !vars[varid].constant)
vars[varid].val = val;
else
- error("cannot modify variable");
+ ERROR("cannot modify variable");
}
static inline void mkconst(varid_t varid)
@@ -161,7 +158,7 @@ static inline void jump(imm_t line)
current_line = line;
}
else
- error("jump target out of bounds");
+ ERROR("jump target out of bounds");
}
static void pushimm_handler(void)
@@ -215,7 +212,7 @@ static void repeat_handler(void)
if(repeats_left > 0)
{
if(repeat_line + 1 != current_line)
- error("nested REPEAT");
+ ERROR("nested REPEAT");
--repeats_left;
if(repeats_left > 0)
{
@@ -243,7 +240,7 @@ static void subcall_handler(void)
jump(pop());
}
else
- error("call stack overflow");
+ ERROR("call stack overflow");
}
static void subret_handler(void)
@@ -253,7 +250,7 @@ static void subret_handler(void)
jump(callstack[--callstack_pointer]);
}
else
- error("call stack underflow");
+ ERROR("call stack underflow");
}
static void if_handler(void)
@@ -459,13 +456,6 @@ static void newline_handler(void)
vid_writef("\n");
}
-static void inc_line_pointer(void)
-{
- ++current_line;
-
- vars[0].val = current_line;
-}
-
static void input_handler(void)
{
vartype val;
@@ -473,6 +463,21 @@ static void input_handler(void)
setvar(read_varid(), val);
}
+static void mkspecial_handler(void)
+{
+ varid_t varid = read_varid();
+ vars[varid].constant = true;
+ vars[varid].type = TYPE_SPECIAL;
+ vars[varid].special = read_imm();
+}
+
+static void inc_line_pointer(void)
+{
+ ++current_line;
+
+ vars[0].val = current_line;
+}
+
static void (*instr_tab[0x100])(void) = {
pushimm_handler, /* 0x0 */
pushvar_handler, /* 0x1 */
@@ -522,7 +527,7 @@ static void (*instr_tab[0x100])(void) = {
NULL, /* 0x2d */
newline_handler, /* 0x2e */
input_handler, /* 0x2f */
- NULL, /* 0x30 */
+ mkspecial_handler, /* 0x30 */
NULL, /* 0x31 */
NULL, /* 0x32 */
NULL, /* 0x33 */
@@ -741,7 +746,7 @@ int ducky_vm(int fd)
init_globals();
if(read_imm() != DUCKY_MAGIC)
- error("unknown format");
+ ERROR("unknown format");
num_lines = read_imm();
line_offset = malloc(num_lines + 1);
@@ -760,7 +765,7 @@ int ducky_vm(int fd)
if(handler)
handler();
else
- error("invalid instruction");
+ ERROR("invalid instruction");
}
return 0;
}