aboutsummaryrefslogtreecommitdiff
path: root/src/interp.c
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 /src/interp.c
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
Diffstat (limited to 'src/interp.c')
-rw-r--r--src/interp.c210
1 files changed, 68 insertions, 142 deletions
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);