CFLAGS = -Wall -Wextra -Wno-strict-aliasing -I. -ggdb -fno-builtin
all:
+ $(CC) $(CFLAGS) -c shelpers.c
$(CC) $(CFLAGS) -c parser.c
- $(CC) $(CFLAGS) shell.c parser.o -o shell
+ $(CC) $(CFLAGS) -c builtins.c
+ $(CC) $(CFLAGS) -c stack.c
+ $(CC) $(CFLAGS) -c ops.c
+ $(CC) $(CFLAGS) -c variable.c
+ $(CC) $(CFLAGS) shell.c *.o -o shell
Only a few commands are built in to the interpreter:
* set - set variables
* func/end - define functions
-* jmp - jump to line
-
+* if/end - if conditional
+* do/while
+* ret - return value from function
+
Other features:
* function/variable defining in c
* expression solving
+* no local variables
+* whitespace hopefully ignored
Soon:
-* conditionals
* error messages
+* arrays?
+* maybe for loops
This project is still in heavy development, so don't expect much. To include it in your own project, just link in parser.o and use the header files.
--- /dev/null
+#include "builtins.h"
+#include "stack.h"
+
+extern char *str_func;
+
+int ifunc_set(interpreter *it);
+int ifunc_label(interpreter *it);
+int ifunc_end(interpreter *it);
+int ifunc_if(interpreter *it);
+int ifunc_do(interpreter *it);
+int ifunc_while(interpreter *it);
+int ifunc_ret(interpreter *it);
+
+void iload_core(interpreter *interp)
+{
+ inew_cfunc(interp, "set", ifunc_set);
+ inew_cfunc(interp, "func", ifunc_label);
+ inew_cfunc(interp, "end", ifunc_end);
+ inew_cfunc(interp, "if", ifunc_if);
+ inew_cfunc(interp, "do", ifunc_do);
+ inew_cfunc(interp, "while", ifunc_while);
+ inew_cfunc(interp, "ret", ifunc_ret);
+}
+
+int ifunc_set(interpreter *it)
+{
+ variable *n = igetarg(it, 0);
+ variable *v = igetarg(it, 1);
+
+ if (n == 0)
+ return -1;
+
+ n->valtype = v->valtype;
+ n->value = v->value;
+ n->svalue = v->svalue;
+ return 0;
+}
+
+int ifunc_label(interpreter *it)
+{
+ variable *n = igetarg(it, 0);
+
+ if (n == 0)
+ return -1;
+
+ n->valtype = FUNC;
+ n->value = it->lnidx;
+ n->svalue = str_func;
+ it->indent++;
+ return 0;
+}
+
+int ifunc_if(interpreter *it)
+{
+ int v = igetarg_integer(it, 0);
+ if (v == 0) {
+ it->indent++;
+ } else {
+ void *tmp = ipop(it);
+ ipush(it, (void *)-1);
+ ipush(it, tmp);
+ }
+ return 0;
+}
+
+int ifunc_end(interpreter *it)
+{
+ uint32_t lnidx = (uint32_t)ipop(it) + 1;
+ if (lnidx != 0)
+ it->lnidx = lnidx;
+ return 0;
+}
+
+int ifunc_do(interpreter *it)
+{
+ ipush(it, (void *)it->lnidx);
+ return 0;
+}
+
+int ifunc_while(interpreter *it)
+{
+ int c = igetarg_integer(it, 0);
+ ipop(it);
+ int nidx = (int)ipop(it);
+ if (c != 0) {
+ ipush(it, (void *)nidx);
+ it->lnidx = nidx;
+ }
+ ipush(it, 0);
+ return 0;
+}
+
+int ifunc_ret(interpreter *it)
+{
+ variable *v = igetarg(it, 0);
+ switch (v->valtype) {
+ case INTEGER:
+ inew_integer(it, "RET", INT(v));
+ break;
+ case FLOAT:
+ inew_float(it, "RET", FLOAT(v));
+ break;
+ case STRING:
+ inew_string(it, "RET", v->svalue);
+ break;
+ default:
+ return -1;
+ break;
+ }
+ if (it->ret != 0) {
+ it->ret->valtype = v->valtype;
+ it->ret->value = v->value;
+ it->ret->svalue = v->svalue;
+ it->ret = 0;
+ }
+ return 0;
+}
+
--- /dev/null
+#ifndef BUILTINS_H_
+#define BUILTINS_H_
+
+#include "parser.h"
+
+void iload_core(interpreter *it);
+
+#endif // BUILTINS_H_
--- /dev/null
+#include "ops.h"
+
+void iop_add(variable *, variable *, variable *);
+void iop_sub(variable *, variable *, variable *);
+void iop_mult(variable *, variable *, variable *);
+void iop_div(variable *, variable *, variable *);
+void iop_and(variable *, variable *, variable *);
+void iop_or(variable *, variable *, variable *);
+void iop_xor(variable *, variable *, variable *);
+void iop_shr(variable *, variable *, variable *);
+void iop_shl(variable *, variable *, variable *);
+void iop_eq(variable *, variable *, variable *);
+void iop_lt(variable *, variable *, variable *);
+void iop_gt(variable *, variable *, variable *);
+void iop_lte(variable *, variable *, variable *);
+void iop_gte(variable *, variable *, variable *);
+void iop_ne(variable *, variable *, variable *);
+void iop_mod(variable *, variable *, variable *);
+
+char *iops[IOPS_COUNT] = {
+ "+", "-", "*", "/", "&", "|", "^", ">>", "<<",
+ "==", "<", ">", "<=", ">=", "!=", "%"
+};
+
+operation_t iopfuncs[IOPS_COUNT] = {
+ iop_add, iop_sub, iop_mult, iop_div, iop_and,
+ iop_or, iop_xor, iop_shr, iop_shl,
+ iop_eq, iop_lt, iop_gt, iop_lte, iop_gte, iop_ne,
+ iop_mod
+};
+
+
+void iop_add(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER) {
+ INT(r) = INT(a) + INT(b);
+ } else {
+ itofloat(a);
+ itofloat(b);
+ FLOAT(r) = FLOAT(a) + FLOAT(b);
+ }
+}
+
+void iop_sub(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER) {
+ INT(r) = INT(a) - INT(b);
+ } else {
+ itofloat(a);
+ itofloat(b);
+ FLOAT(r) = FLOAT(a) - FLOAT(b);
+ }
+}
+
+void iop_mult(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER) {
+ INT(r) = INT(a) * INT(b);
+ } else {
+ itofloat(a);
+ itofloat(b);
+ FLOAT(r) = FLOAT(a) * FLOAT(b);
+ }
+}
+
+void iop_div(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER) {
+ INT(r) = INT(a) / INT(b);
+ } else {
+ itofloat(a);
+ itofloat(b);
+ FLOAT(r) = FLOAT(a) / FLOAT(b);
+ }
+}
+
+void iop_and(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER) {
+ INT(r) = INT(a) & INT(b);
+ }
+}
+
+void iop_or(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER) {
+ INT(r) = INT(a) | INT(b);
+ }
+}
+
+void iop_xor(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER) {
+ INT(r) = INT(a) ^ INT(b);
+ }
+}
+
+void iop_shr(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER) {
+ INT(r) = INT(a) >> INT(b);
+ }
+}
+
+void iop_shl(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER) {
+ INT(r) = INT(a) << INT(b);
+ }
+}
+
+void iop_eq(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER)
+ INT(r) = INT(a) == INT(b);
+ else
+ INT(r) = FLOAT(a) == FLOAT(b);
+}
+
+void iop_lt(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER)
+ INT(r) = INT(a) < INT(b);
+ else
+ INT(r) = FLOAT(a) < FLOAT(b);
+}
+
+void iop_gt(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER)
+ INT(r) = INT(a) > INT(b);
+ else
+ INT(r) = FLOAT(a) > FLOAT(b);
+}
+
+void iop_lte(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER)
+ INT(r) = INT(a) <= INT(b);
+ else
+ INT(r) = FLOAT(a) <= FLOAT(b);
+}
+
+void iop_gte(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER)
+ INT(r) = INT(a) >= INT(b);
+ else
+ INT(r) = FLOAT(a) >= FLOAT(b);
+}
+
+void iop_ne(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER)
+ INT(r) = INT(a) != INT(b);
+ else
+ INT(r) = FLOAT(a) != FLOAT(b);
+}
+
+void iop_mod(variable *r, variable *a, variable *b)
+{
+ if (a->valtype == INTEGER && b->valtype == INTEGER)
+ INT(r) = INT(a) % INT(b);
+ else
+ INT(r) = 0;
+}
+
--- /dev/null
+#ifndef OPS_H_
+#define OPS_H_
+
+#include "parser.h"
+
+#define IOPS_COUNT 16
+
+typedef void (*operation_t)(variable *, variable *, variable *);
+
+extern char *iops[IOPS_COUNT];
+extern operation_t iopfuncs[IOPS_COUNT];
+
+#endif // OPS_H_
#include <parser.h>
+#include "shelpers.h"
+#include "builtins.h"
+#include "stack.h"
+#include "ops.h"
+
#include <ctype.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#define MAX_VARS 32
-#define MAX_STACK 32
-
-#define INT(v) (*((int32_t *)&v->value))
-#define FLOAT(v) (*((float *)&v->value))
-
-static char *str_func = "(func)";
-static char *str_undef = "(undefined)";
-
-char *strclone(const char *s)
-{
- char *clone = (char *)malloc(strlen(s) + 1);
- strcpy(clone, s);
- return clone;
-}
-
-char *strnclone(const char *s, uint32_t n)
-{
- char *clone = (char *)malloc(n + 1);
- strncpy(clone, s, n);
- return clone;
-}
-
-void fsetstr(variable *f)
-{
- if (f->svalue == 0)
- f->svalue = (char *)malloc(16);
- snprintf(f->svalue, 16, "%f", FLOAT(f));
-}
-
-void isetstr(variable *i)
-{
- if (i->svalue == 0)
- i->svalue = (char *)malloc(12);
- snprintf(i->svalue, 12, "%d", INT(i));
-}
-
-uint8_t eol(int c)
-{
- return c == '\n' || c == '\0';
-}
-
-uint8_t eot(int c)
-{
- return eol(c) || c == ' ';
-}
-
-uint8_t eoe(int c)
-{
- return eol(c) || c == ')';
-}
-
-uint32_t findend(const char *s, char o, char c)
-{
- uint8_t indent = 0;
- uint32_t i;
- for (i = 1; !eol(s[i]); i++) {
- if (s[i] == o) {
- indent++;
- } else if (s[i] == c) {
- if (indent == 0)
- break;
- else
- indent--;
- }
- }
-
- return i;
-}
+#define MAX_VARS 48
+#define MAX_STACK 16
+#define MAX_LINES 1000
-void skipblank(const char *s, uint8_t (*cmp)(int), uint32_t *offset)
-{
- uint32_t i = *offset;
- while (!cmp(s[i])) {
- if (s[i] != ' ' && s[i] != '\t')
- break;
- i++;
- }
- *offset = i;
-}
-
-int ifunc_set(interpreter *it);
-int ifunc_jmp(interpreter *it);
-int ifunc_label(interpreter *it);
-int ifunc_end(interpreter *it);
-int ifunc_if(interpreter *it);
-int ifunc_do(interpreter *it);
-int ifunc_while(interpreter *it);
+char *str_func = "(func)";
+char *str_undef = "(undefined)";
variable *idoexpr(interpreter *interp, const char *line);
-variable *itostring(variable *v);
-variable *itoint(variable *v);
-variable *itofloat(variable *v);
-
void iinit(interpreter *interp)
{
- interp->vars = (variable *)calloc(MAX_VARS, sizeof(variable));
- interp->vnames = (char **)calloc(MAX_VARS, sizeof(char *));
- interp->stack = (stack_t *)calloc(MAX_STACK, sizeof(stack_t));
+ interp->vars = (variable *)malloc(MAX_VARS * sizeof(variable));
+ interp->vnames = (char **)malloc(MAX_VARS * sizeof(char *));
+ interp->stack = (stack_t *)malloc(MAX_STACK * sizeof(stack_t));
interp->stidx = 0;
- interp->lines = (char **)calloc(20, sizeof(char *));
+ interp->lines = (char **)calloc(MAX_LINES, sizeof(char *));
interp->lnidx = 0;
interp->indent = 0;
- inew_cfunc(interp, "set", ifunc_set);
- inew_cfunc(interp, "jmp", ifunc_jmp);
- inew_cfunc(interp, "func", ifunc_label);
- inew_cfunc(interp, "end", ifunc_end);
- inew_cfunc(interp, "if", ifunc_if);
- inew_cfunc(interp, "do", ifunc_do);
- inew_cfunc(interp, "while", ifunc_while);
-}
-
-void ipush(interpreter *it, void *v)
-{
- it->stack[it->stidx++] = v;
-}
+ for (unsigned int i = 0; i < MAX_VARS; i++) {
+ interp->vars[i].used = 0;
+ interp->vnames[i] = 0;
+ }
+ for (unsigned int i = 0; i < MAX_LINES; i++)
+ interp->lines[i] = 0;
-void *ipop(interpreter *it)
-{
- return it->stack[--it->stidx];
+ iload_core(interp);
}
variable *interpreter_get_variable(interpreter *interp, const char *name)
variable *ops[8];
uint32_t ooffset, offset, next;
+ if (line[0] == '\0')
+ return 0;
+
interp->lines[interp->lnidx] = strclone(line);
loop:
+ ooffset = 0;
+ offset = 0;
+
if (line[0] == '#') {
goto norun;
} else if (interp->indent > 0) {
- if (!strcmp(line, "end"))
+ skipblank(line, eol, &offset);
+ if (!strcmp(line + offset, "end"))
interp->indent--;
goto norun;
}
- ooffset = 0;
- offset = 0;
-
// step 1 - convert to tokens
skipblank(line, eol, &offset);
while (!eol(line[offset])) {
+ if (offset > 0 && line[offset] == '>') {
+ offset++;
+ skipblank(line, eol, &offset);
+ interp->ret = make_var(interp, line + offset, &next);
+ offset += next;
+ skipblank(line, eol, &offset);
+ continue;
+ }
ops[ooffset] = make_var(interp, line + offset, &next);
if (ops[ooffset] == 0) {
return -4;
if (ops[0]->valtype != FUNC)
return -2;
- if (ops[0]->value == 0)
+ if (ops[0]->fromc && ops[0]->value == 0)
return -3;
- for (uint32_t i = ooffset; --i > 0;)
- ipush(interp, ops[i]);
-
if (ops[0]->fromc) {
+ for (uint32_t i = ooffset; --i > 0;)
+ ipush(interp, ops[i]);
+
int ret = ((func_t)ops[0]->value)(interp);
if (ret != 0)
return ret;
+ ipopm(interp, ooffset - 1);
} else {
- ipush(interp, (void *)(interp->lnidx + 1));
+ char an[6];
+ for (uint32_t i = 1; i < ooffset; i++) {
+ snprintf(an, 6, "arg%d", i - 1);
+ switch (ops[i]->valtype) {
+ case STRING:
+ inew_string(interp, an, ops[i]->svalue);
+ break;
+ case INTEGER:
+ inew_integer(interp, an, INT(ops[i]));
+ break;
+ case FLOAT:
+ inew_float(interp, an, FLOAT(ops[i]));
+ break;
+ default:
+ break;
+ }
+ }
+
+ ipush(interp, (void *)(interp->lnidx));
interp->lnidx = ops[0]->value;
}
- interp->stidx -= ooffset - 1;
-
if ((int32_t)interp->stidx < 0) {
interp->stidx = 0;
return -5;
return 0;
}
-typedef void (*operation_t)(variable *, variable *, variable *);
-
-#define IOPS_COUNT 15
-static char *iops[IOPS_COUNT] = {
- "+", "-", "*", "/", "&", "|", "^", ">>", "<<",
- "==", "<", ">", "<=", ">=", "!="
-};
-
-void iop_add(variable *, variable *, variable *);
-void iop_sub(variable *, variable *, variable *);
-void iop_mult(variable *, variable *, variable *);
-void iop_div(variable *, variable *, variable *);
-void iop_and(variable *, variable *, variable *);
-void iop_or(variable *, variable *, variable *);
-void iop_xor(variable *, variable *, variable *);
-void iop_shr(variable *, variable *, variable *);
-void iop_shl(variable *, variable *, variable *);
-void iop_eq(variable *, variable *, variable *);
-void iop_lt(variable *, variable *, variable *);
-void iop_gt(variable *, variable *, variable *);
-void iop_lte(variable *, variable *, variable *);
-void iop_gte(variable *, variable *, variable *);
-void iop_ne(variable *, variable *, variable *);
-
-static operation_t iopfuncs[IOPS_COUNT] = {
- iop_add, iop_sub, iop_mult, iop_div, iop_and,
- iop_or, iop_xor, iop_shr, iop_shl,
- iop_eq, iop_lt, iop_gt, iop_lte, iop_gte, iop_ne
-};
-
variable *idoexpr(interpreter *interp, const char *line)
{
variable *result = (variable *)malloc(sizeof(variable));
ops[ooffset] = make_var(interp, line + offset, &next);
if (end != 0)
mline[end] = cend;
+ offset += next;
}
if (ops[ooffset] == 0)
return 0;
ooffset++;
- offset += next;
// skip whitespace
skipblank(line, eoe, &offset);
return result;
}
-variable *igetarg(interpreter *interp, uint32_t index)
-{
- return interp->stack[interp->stidx - index - 1];
-}
-
-char *igetarg_string(interpreter *interp, uint32_t index)
-{
- if (index >= interp->stidx)
- return 0;
- variable *v = igetarg(interp, index);
- return v->svalue;
-}
-
-int igetarg_integer(interpreter *interp, uint32_t index)
-{
- if (index >= interp->stidx)
- return 0;
- variable *v = igetarg(interp, index);
- return INT(itoint(v));
-}
-
-float igetarg_float(interpreter *interp, uint32_t index)
-{
- if (index >= interp->stidx)
- return 0;
- variable *v = igetarg(interp, index);
- return FLOAT(itofloat(v));
-}
-
-variable *itostring(variable *v)
-{
- switch (v->valtype) {
- case INTEGER:
- v->valtype = STRING;
- isetstr(v);
- break;
- case FLOAT:
- v->valtype = STRING;
- fsetstr(v);
- break;
- }
- return v;
-}
-
-variable *itoint(variable *v)
-{
- switch (v->valtype) {
- case STRING:
- v->valtype = INTEGER;
- INT(v) = atoi(v->svalue);
- isetstr(v);
- break;
- case FLOAT:
- v->valtype = INTEGER;
- INT(v) = (int32_t)FLOAT(v);
- isetstr(v);
- break;
- }
- return v;
-}
-
-variable *itofloat(variable *v)
-{
- switch (v->valtype) {
- case STRING:
- v->valtype = FLOAT;
- FLOAT(v) = strtof(v->svalue, 0);
- fsetstr(v);
- break;
- case INTEGER:
- v->valtype = FLOAT;
- FLOAT(v) = (float)INT(v);
- fsetstr(v);
- break;
- }
- return v;
-}
-
-/**
- * Builtin functions
- */
-
-int ifunc_set(interpreter *it)
-{
- variable *n = igetarg(it, 0);
- variable *v = igetarg(it, 1);
-
- if (n == 0)
- return -1;
-
- n->valtype = v->valtype;
- n->value = v->value;
- n->svalue = v->svalue;
- return 0;
-}
-
-int ifunc_label(interpreter *it)
-{
- variable *n = igetarg(it, 0);
-
- if (n == 0)
- return -1;
-
- n->valtype = FUNC;
- n->value = it->lnidx;
- n->svalue = str_func;
- it->indent++;
- return 0;
-}
-
-int ifunc_if(interpreter *it)
-{
- int v = igetarg_integer(it, 0);
- if (v == 0)
- it->indent++;
- return 0;
-}
-
-int ifunc_end(interpreter *it)
-{
- if (it->stidx > 0) {
- uint32_t line = (uint32_t)ipop(it);
- it->lnidx = line - 1;
- }
- return 0;
-}
-
-int ifunc_jmp(interpreter *it)
-{
- int newidx = igetarg_integer(it, 0);
- ipop(it);
- ipush(it, (void *)(it->lnidx + 1));
- ipush(it, 0);
- it->lnidx = newidx - 1;
- return 0;
-}
-
-int ifunc_do(interpreter *it)
-{
- ipush(it, (void *)it->lnidx);
- return 0;
-}
-
-int ifunc_while(interpreter *it)
-{
- int c = igetarg_integer(it, 0);
- ipop(it);
- int nidx = (int)ipop(it);
- if (c != 0) {
- ipush(it, (void *)nidx);
- it->lnidx = nidx;
- }
- ipush(it, 0);
- return 0;
-}
-
-/**
- * Builtin operations
- */
-
-void iop_add(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER) {
- INT(r) = INT(a) + INT(b);
- } else {
- itofloat(a);
- itofloat(b);
- FLOAT(r) = FLOAT(a) + FLOAT(b);
- }
-}
-
-void iop_sub(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER) {
- INT(r) = INT(a) - INT(b);
- } else {
- itofloat(a);
- itofloat(b);
- FLOAT(r) = FLOAT(a) - FLOAT(b);
- }
-}
-
-void iop_mult(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER) {
- INT(r) = INT(a) * INT(b);
- } else {
- itofloat(a);
- itofloat(b);
- FLOAT(r) = FLOAT(a) * FLOAT(b);
- }
-}
-
-void iop_div(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER) {
- INT(r) = INT(a) / INT(b);
- } else {
- itofloat(a);
- itofloat(b);
- FLOAT(r) = FLOAT(a) / FLOAT(b);
- }
-}
-
-void iop_and(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER) {
- INT(r) = INT(a) & INT(b);
- }
-}
-
-void iop_or(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER) {
- INT(r) = INT(a) | INT(b);
- }
-}
-
-void iop_xor(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER) {
- INT(r) = INT(a) ^ INT(b);
- }
-}
-
-void iop_shr(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER) {
- INT(r) = INT(a) >> INT(b);
- }
-}
-
-void iop_shl(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER) {
- INT(r) = INT(a) << INT(b);
- }
-}
-
-void iop_eq(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER)
- INT(r) = INT(a) == INT(b);
- else
- INT(r) = FLOAT(a) == FLOAT(b);
-}
-
-void iop_lt(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER)
- INT(r) = INT(a) < INT(b);
- else
- INT(r) = FLOAT(a) < FLOAT(b);
-}
-
-void iop_gt(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER)
- INT(r) = INT(a) > INT(b);
- else
- INT(r) = FLOAT(a) > FLOAT(b);
-}
-
-void iop_lte(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER)
- INT(r) = INT(a) <= INT(b);
- else
- INT(r) = FLOAT(a) <= FLOAT(b);
-}
-
-void iop_gte(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER)
- INT(r) = INT(a) >= INT(b);
- else
- INT(r) = FLOAT(a) >= FLOAT(b);
-}
-
-void iop_ne(variable *r, variable *a, variable *b)
-{
- if (a->valtype == INTEGER && b->valtype == INTEGER)
- INT(r) = INT(a) != INT(b);
- else
- INT(r) = FLOAT(a) != FLOAT(b);
-}
-
char **lines;
uint32_t lnidx;
uint8_t indent;
+ variable *ret;
} interpreter;
typedef int (*func_t)(interpreter *);
int idoline(interpreter *, const char *);
-variable *igetarg(interpreter *, uint32_t);
-char *igetarg_string(interpreter *, uint32_t);
-int igetarg_integer(interpreter *, uint32_t);
-float igetarg_float(interpreter *, uint32_t);
-
#endif // PARSER_H_
+func inc
+ set arg0 (arg0 + 1)
+ ret arg0
+end
+
set a 0
do
- put a
- set a (a+1)
-while (a<5)
+ inc a > a
+ if ((a % 9) == 0)
+ put a
+ end
+while (a < 100)
+
+if (a == 100)
+ put "All good!"
+end
+
#include <parser.h>
+#include "stack.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
--- /dev/null
+#include "shelpers.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+char *strclone(const char *s)
+{
+ char *clone = (char *)malloc(strlen(s) + 1);
+ strcpy(clone, s);
+ return clone;
+}
+
+char *strnclone(const char *s, uint32_t n)
+{
+ char *clone = (char *)malloc(n + 1);
+ strncpy(clone, s, n);
+ return clone;
+}
+
+uint8_t eol(int c)
+{
+ return c == '\n' || c == '\0';
+}
+
+uint8_t eot(int c)
+{
+ return eol(c) || c == ' ';
+}
+
+uint8_t eoe(int c)
+{
+ return eol(c) || c == ')';
+}
+
+uint32_t findend(const char *s, char o, char c)
+{
+ uint8_t indent = 0;
+ uint32_t i;
+ for (i = 1; !eol(s[i]); i++) {
+ if (s[i] == o) {
+ indent++;
+ } else if (s[i] == c) {
+ if (indent == 0)
+ break;
+ else
+ indent--;
+ }
+ }
+
+ return i;
+}
+
+void skipblank(const char *s, uint8_t (*cmp)(int), uint32_t *offset)
+{
+ uint32_t i = *offset;
+ while (!cmp(s[i])) {
+ if (s[i] != ' ' && s[i] != '\t')
+ break;
+ i++;
+ }
+ *offset = i;
+}
+
--- /dev/null
+#ifndef SHELPERS_H_
+#define SHELPERS_H_
+
+#include <stdint.h>
+
+/**
+ * Clones the given string, malloc'ing a new one.
+ * @param s the string to clone
+ * @return the malloc'd copy
+ */
+char *strclone(const char *s);
+
+/**
+ * Clones the given string until the given count.
+ * @param s the string to clone
+ * @param n the number of characters to clone
+ * @return the malloc'd copy
+ */
+char *strnclone(const char *s, uint32_t n);
+
+
+/**
+ * Returns non-zero if the character is considered an end-of-line.
+ * @param c a character
+ * @return non-zero if eol, zero if not
+ */
+uint8_t eol(int c);
+
+/**
+ * Returns non-zero if the character is considered an end-of-token.
+ * @param c a character
+ * @return non-zero if eot, zero if not
+ */
+uint8_t eot(int c);
+
+/**
+ * Returns non-zero if the character is considered an end-of-expression.
+ * @param c a character
+ * @return non-zero if eoe, zero if not
+ */
+uint8_t eoe(int c);
+
+
+/**
+ * Finds the matching end character in a string, e.g. matching parens.
+ * @param s the string to search
+ * @param o the starting, opening character (e.g. '(')
+ * @param c the end, closing character (e.g. ')')
+ * @return offset of the end character in the string
+ */
+uint32_t findend(const char *s, char o, char c);
+
+/**
+ * Increments offset until the character in the string is not blank or fails
+ * the given comparison.
+ * @param s the string to use
+ * @param cmp a comparing function, stops search if returns true
+ * @param offset the variable to increment while searching
+ */
+void skipblank(const char *s, uint8_t (*cmp)(int), uint32_t *offset);
+
+#endif // SHELPERS_H_
--- /dev/null
+#include "stack.h"
+
+void ipush(interpreter *it, void *v)
+{
+ it->stack[it->stidx++] = v;
+}
+
+void *ipop(interpreter *it)
+{
+ return it->stack[--it->stidx];
+}
+
+void ipopm(interpreter *it, uint32_t count)
+{
+ it->stidx -= count;
+}
+
+variable *igetarg(interpreter *interp, uint32_t index)
+{
+ return interp->stack[interp->stidx - index - 1];
+}
+
+char *igetarg_string(interpreter *interp, uint32_t index)
+{
+ if (index >= interp->stidx)
+ return 0;
+ variable *v = igetarg(interp, index);
+ return v->svalue;
+}
+
+int igetarg_integer(interpreter *interp, uint32_t index)
+{
+ if (index >= interp->stidx)
+ return 0;
+ variable *v = igetarg(interp, index);
+ return INT(itoint(v));
+}
+
+float igetarg_float(interpreter *interp, uint32_t index)
+{
+ if (index >= interp->stidx)
+ return 0;
+ variable *v = igetarg(interp, index);
+ return FLOAT(itofloat(v));
+}
+
--- /dev/null
+#ifndef STACK_H_
+#define STACK_H_
+
+#include "parser.h"
+
+void ipush(interpreter *it, void *v);
+void *ipop(interpreter *it);
+void ipopm(interpreter *it, uint32_t count);
+variable *igetarg(interpreter *interp, uint32_t index);
+char *igetarg_string(interpreter *interp, uint32_t index);
+int igetarg_integer(interpreter *interp, uint32_t index);
+float igetarg_float(interpreter *interp, uint32_t index);
+
+
+#endif // STACK_H_
--- /dev/null
+#include "variable.h"
+#include "parser.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern char *str_undef;
+
+void fsetstr(variable *f)
+{
+ if (f->svalue == 0 || f->svalue == str_undef)
+ f->svalue = (char *)malloc(16);
+ snprintf(f->svalue, 16, "%f", FLOAT(f));
+}
+
+void isetstr(variable *i)
+{
+ if (i->svalue == 0 || i->svalue == str_undef)
+ i->svalue = (char *)malloc(12);
+ snprintf(i->svalue, 12, "%d", INT(i));
+}
+
+variable *itostring(variable *v)
+{
+ switch (v->valtype) {
+ case INTEGER:
+ v->valtype = STRING;
+ isetstr(v);
+ break;
+ case FLOAT:
+ v->valtype = STRING;
+ fsetstr(v);
+ break;
+ }
+ return v;
+}
+
+variable *itoint(variable *v)
+{
+ switch (v->valtype) {
+ case STRING:
+ v->valtype = INTEGER;
+ INT(v) = atoi(v->svalue);
+ isetstr(v);
+ break;
+ case FLOAT:
+ v->valtype = INTEGER;
+ INT(v) = (int32_t)FLOAT(v);
+ isetstr(v);
+ break;
+ }
+ return v;
+}
+
+variable *itofloat(variable *v)
+{
+ switch (v->valtype) {
+ case STRING:
+ v->valtype = FLOAT;
+ FLOAT(v) = strtof(v->svalue, 0);
+ fsetstr(v);
+ break;
+ case INTEGER:
+ v->valtype = FLOAT;
+ FLOAT(v) = (float)INT(v);
+ fsetstr(v);
+ break;
+ }
+ return v;
+}
+
#include <stdint.h>
+#define INT(v) (*((int32_t *)&v->value))
+#define FLOAT(v) (*((float *)&v->value))
+
typedef struct {
uint8_t used :1;
uint8_t fromc :1;
FUNC
};
+void isetstr(variable *i);
+void fsetstr(variable *f);
+
+variable *itostring(variable *v);
+variable *itoint(variable *v);
+variable *itofloat(variable *v);
+
#endif // VARIABLE_H_