aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile36
-rw-r--r--README.md33
-rw-r--r--builtins.c225
-rw-r--r--builtins.h11
-rw-r--r--memory.h8
-rw-r--r--old.tar.gzbin0 -> 46683 bytes
-rw-r--r--ops.c236
-rw-r--r--ops.h11
-rw-r--r--parser.c780
-rw-r--r--parser.h38
-rw-r--r--script7
-rw-r--r--shell.c40
-rw-r--r--shelpers.c64
-rw-r--r--shelpers.h62
-rw-r--r--stack.c38
-rw-r--r--stack.h16
-rw-r--r--stdlib.h9
-rw-r--r--test113
-rw-r--r--test216
-rw-r--r--test325
-rw-r--r--test46
-rw-r--r--variable.c135
-rw-r--r--variable.h23
23 files changed, 785 insertions, 1047 deletions
diff --git a/Makefile b/Makefile
index b4a7bfc..57f022c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,23 +1,13 @@
-#CC = gcc -m32
-#AR = ar
-CC = arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16
-AR = arm-none-eabi-ar
-
-CFLAGS = -Wall -Wextra -Werror -pedantic \
- -Wno-discarded-qualifiers \
- -I. -fsigned-char -fno-builtin -ggdb
-
-FILES = $(wildcard *.c)
-OUTFILES = $(patsubst %.c, %.o, $(FILES))
-
-all: $(OUTFILES)
- @#$(CC) $(CFLAGS) *.o -o shell
- @$(AR) r libinterp.a *.o
-
-clean:
- @echo " CLEAN"
- @rm -f *.o shell libinterp.a
-
-%.o: %.c
- @echo " CC " $<
- @$(CC) $(CFLAGS) -c $< -o $@
+CFLAGS = -ggdb
+CFILES = $(wildcard *.c)
+
+all:
+ @echo $(CFILES)
+ @gcc -m32 $(CFLAGS) $(CFILES) -o shell
+
+arm:
+ @mv shell.c shell.c.bak
+ @arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 $(CFLAGS) -c *.c
+ @arm-none-eabi-ar r libinterp.a *.o
+ @mv shell.c.bak shell.c
+ @rm *.o
diff --git a/README.md b/README.md
index 6084d7c..7ef1f34 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,23 @@
# interpreter
-This project aims to provide a very minimal scripting language for embedded systems. Many other languages already exist, such as Lua, Tcl, or BASIC; however, most implementations require certain system calls like a read() and write(), as they expect a filesystem. This interpreter aims to be as independent and portable as possible: parsing script from strings one at a time, having minimal built-in functions (so the user can define their own prints and such), and only requiring a few standard library functions.
+This project aims to provide a very minimal scripting language for embedded systems. Many other languages already exist, such as Lua, Tcl, or BASIC; however, most implementations require certain system calls like read() and write(), as they expect a filesystem. This interpreter wants to be as system-independent and portable as possible: parsing script from strings one at a time, having minimal built-in functions (so the user can define their own IO calls and such), and only requiring a few standard library functions.
-To use this program with your own device, you need some malloc/free implementation, and string functions like those in string.h, atoi, and snprintf. Some of these functions may become coded in so that a standard library isn't required.
+To use this program with your own device, you'll need some malloc/free implementation, and a freestanding standard library. Newlib works well for this; however, functions like atoi() and snprintf() will probably need to be rewritten (if you don't have an \_sbrk defined).
-Only a few commands are built in to the interpreter:
-* set - set variables
-* func/end - define functions
-* if/end - if conditional
-* do/while
-* ret - return value from function
+Interpreter features:
+* Variable/function definition - in C and in script
+* if/else and while loops
+* a solve function to parse strings at runtime
-Other features:
-* function/variable defining in c
-* expression solving
+Inconvenient features:
* no local variables
-* whitespace hopefully ignored
+* whitespace sometimes ignored
-Soon:
-* error messages
+Some TODO items:
+* fix all memory leaks
+* add better 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.
+* for loops
+
+
+This project can be made for the host system (```make```) or an ARM system (```make arm```).
+This project is still in heavy development, so don't expect much. To include it in your own project, just link in libinterp.a (for ARM) and use the header files.
diff --git a/builtins.c b/builtins.c
index 0ab6f3b..ea1cc95 100644
--- a/builtins.c
+++ b/builtins.c
@@ -1,179 +1,124 @@
#include "builtins.h"
-#include "stack.h"
-#include "shelpers.h"
-
-#include <memory.h>
-#include <string.h>
-
-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);
-int ifunc_else(interpreter *it);
-int ifunc_solve(interpreter *it);
-
-const func_t indent_up[IUP_COUNT] = {
- ifunc_if, ifunc_do, ifunc_label
-};
-
-const func_t indent_down[IDOWN_COUNT] = {
- ifunc_else, ifunc_end, ifunc_while,
-};
-
-void iload_core(interpreter *interp)
+
+#include <stdlib.h>
+
+#define IF_SIG (uint32_t)-1
+#define WHILE_SIG (uint32_t)-2
+#define ELSE_SIG (uint32_t)-3
+#define FUNC_SIG (uint32_t)-4
+
+int bn_set(instance *it);
+int bn_if(instance *it);
+int bn_else(instance *it);
+int bn_end(instance *it);
+int bn_while(instance *it);
+int bn_func(instance *it);
+int bn_solve(instance *it);
+
+void iload_builtins(instance *it)
{
- 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);
- inew_cfunc(interp, "else", ifunc_else);
- inew_cfunc(interp, "solve", ifunc_solve);
+ inew_cfunc(it, "set", bn_set);
+ inew_cfunc(it, "if", bn_if);
+ inew_cfunc(it, "else", bn_else);
+ inew_cfunc(it, "while", bn_while);
+ inew_cfunc(it, "func", bn_func);
+ inew_cfunc(it, "solve", bn_solve);
}
-int ifunc_solve(interpreter *it)
+int bn_set(instance *it)
{
- const char *expr = igetarg_string(it, 0);
- int len = strlen(expr);
- char *buf = (char *)malloc(len + 2);
- strcpy(buf, expr);
- buf[len] = ')';
- buf[len + 1] = '\0';
- variable *r = idoexpr(it, buf);
- free(buf);
- if (r == 0)
- r = make_varn(0, 0.0f);
- iret(it, r);
- free(r);
+ variable *var = igetarg(it, 0);
+ variable *value = igetarg(it, 1);
+ var->type = value->type;
+ var->value.p = value->value.p;
+ ipush(it, (uint32_t)var);
return 0;
}
-int ifunc_set(interpreter *it)
+int bn_if(instance *it)
{
- variable *n = igetarg(it, 0);
- variable *v = igetarg(it, 1);
+ variable *cond = (variable *)ipop(it);
+ uint32_t result = cond->value.p;
- if (n == 0)
- return -1;
+ ipush(it, result);
+ ipush(it, IF_SIG);
+ if (result == 0)
+ it->sindent = SKIP | it->indent;
+ ipush(it, 0);
+ ipush(it, 0); // need to return because stack modify
- if (n->valtype == STRING)
- free((void *)n->value.p);
- n->valtype = v->valtype;
- n->value.p = v->value.p;
return 0;
}
-int ifunc_label(interpreter *it)
+static uint32_t if_cond = 0;
+int bn_else(instance *it)
{
- variable *n = igetarg(it, 0);
-
- if (n == 0)
- return -1;
-
- n->valtype = FUNC;
- n->value.p = it->lnidx;
- iskip(it);
+ uint32_t cond = if_cond;
+ if (cond != 0)
+ it->sindent = SKIP | it->indent;
+ ipush(it, ELSE_SIG);
+ ipush(it, 0); // for ret
return 0;
}
-int ifunc_if(interpreter *it)
+int bn_end(instance *it)
{
- int v = igetarg(it, 0)->value.p;
- if (v == 0)
- iskip(it);
- void *arg = ipop(it);
- ipush(it, (void *)v);
- ipush(it, (void *)-1);
- ipush(it, arg);
- return 0;
+ uint32_t sig = ipop(it);
+ if (sig == IF_SIG) {
+ if_cond = ipop(it);
+ } else if (sig == WHILE_SIG) {
+ uint32_t lnidx = ipop(it);
+ if (lnidx != (int32_t)-1)
+ it->lnidx = lnidx - 1;
+ } else if (sig == CALL_SIG) {
+ it->lnidx = ipop(it);
+ it->indent++;
+ }
+ return 0;
}
-int ifunc_end(interpreter *it)
+int bn_while(instance *it)
{
- if (it->stidx == 0)
- return 0;
+ variable *cond = (variable *)ipop(it);
+ uint32_t result = cond->value.p;
- uint32_t lnidx = (uint32_t)ipop(it) + 1;
- if (lnidx == 0) { // from an if, have conditional
- ipop(it); // whatever
+ if (result == 0) {
+ it->sindent = SKIP | it->indent;
+ ipush(it, (uint32_t)-1);
} else {
- if (lnidx == (uint32_t)-1) {
- // script-func call
- lnidx = (uint32_t)ipop(it);
- it->indent = (uint32_t)ipop(it);
- }
- it->lnidx = lnidx;
+ ipush(it, it->lnidx);
}
- return 0;
-}
-
-int ifunc_else(interpreter *it)
-{
- if (it->stidx == 0)
- return 0;
-
- ipop(it); // the -1
- int cond = (int)ipop(it);
- it->indent++;
- if (cond != 0)
- iskip(it);
- // otherwise it's whatever?
+ ipush(it, WHILE_SIG);
ipush(it, 0);
- ipush(it, (void *)-1);
-
+ ipush(it, 0); // need to ret
return 0;
}
-int ifunc_do(interpreter *it)
+int bn_func(instance *it)
{
- ipush(it, (void *)it->lnidx);
- return 0;
-}
+ variable *f = igetarg(it, 0);
+ if (f == 0)
+ return -1;
-int ifunc_while(interpreter *it)
-{
- int c = igetarg(it, 0)->value.p;
- ipop(it);
- int nidx = (int)ipop(it);
- if (c != 0) {
- //ipush(it, (void *)nidx);
- it->lnidx = nidx - 1;
- }
- ipush(it, 0);
+ f->type = FUNC;
+ f->value.p = it->lnidx;
+ it->sindent = SKIP | it->indent;
+ ipush(it, FUNC_SIG);
+ ipush(it, 0); // for ret
return 0;
}
-void iret(interpreter *it, variable *v)
+int bn_solve(instance *it)
{
- switch (v->valtype) {
- case NUMBER:
- inew_number(it, "RET", v->value.f);
- break;
- case STRING:
- inew_string(it, "RET", (char *)v->value.p);
- break;
- default:
- return;
- break;
- }
- if (it->ret != 0) {
- if (it->ret->valtype == STRING && it->ret->value.p != 0)
- free((void *)it->ret->value.p);
- it->ret->valtype = v->valtype;
- it->ret->value.p = v->value.p;
- it->ret = 0;
- }
-}
+ variable *s = igetarg(it, 0);
+ variable **ops = iparse(it, (const char *)s->value.p);
+ if (ops == 0)
+ return -1;
-int ifunc_ret(interpreter *it)
-{
- variable *v = igetarg(it, 0);
- iret(it, v);
+ variable *a = isolve(it, ops, 0);
+ free(ops);
+
+ ipush(it, (uint32_t)a);
return 0;
}
diff --git a/builtins.h b/builtins.h
index 5c8e350..7570eab 100644
--- a/builtins.h
+++ b/builtins.h
@@ -3,14 +3,11 @@
#include "parser.h"
-#define IUP_COUNT 3
-#define IDOWN_COUNT 3
+#define SKIP_SIG (uint32_t)-5
+#define CALL_SIG (uint32_t)-6
-void iload_core(interpreter *it);
+void iload_builtins(instance *it);
-void iret(interpreter *it, variable *v);
-
-const func_t indent_up[IUP_COUNT];
-const func_t indent_down[IDOWN_COUNT];
+int bn_end(instance *it);
#endif // BUILTINS_H_
diff --git a/memory.h b/memory.h
deleted file mode 100644
index 546aa2d..0000000
--- a/memory.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef MEMORY_H_
-#define MEMORY_H_
-
-void *malloc(unsigned int);
-void *calloc(unsigned int, unsigned int);
-void free(void *);
-
-#endif // MEMORY_H_
diff --git a/old.tar.gz b/old.tar.gz
new file mode 100644
index 0000000..0a2e13f
--- /dev/null
+++ b/old.tar.gz
Binary files differ
diff --git a/ops.c b/ops.c
index 5267b6f..0d6b292 100644
--- a/ops.c
+++ b/ops.c
@@ -1,117 +1,197 @@
#include "ops.h"
+#include <stdlib.h>
#include <string.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] = {
- "*", "/", "%", "+", "-", "<<", ">>", "<=",
- "<", ">=", ">", "==", "!=", "&", "^", "|"
+#define OP_DEF(o) int op_##o(variable *r, variable *a, variable *b)
+#define OP_VAR(o) {0, OPERATOR, 0, {.p = (uint32_t)op_##o}}
+#define OP_NONE {0, OPERATOR, 0, {.p = 0x0BADCAFE}}
+
+extern char *strclone(const char *s);
+
+OP_DEF(mul);
+OP_DEF(div);
+OP_DEF(mod);
+OP_DEF(add);
+OP_DEF(sub);
+OP_DEF(shl);
+OP_DEF(shr);
+OP_DEF(lte);
+OP_DEF(lt);
+OP_DEF(gte);
+OP_DEF(gt);
+OP_DEF(eq);
+OP_DEF(ne);
+OP_DEF(and);
+OP_DEF(xor);
+OP_DEF(or);
+OP_DEF(set);
+
+variable opvars[] = {
+ OP_VAR(mul), OP_VAR(div), OP_VAR(mod), OP_NONE,
+ OP_VAR(add), OP_VAR(sub), OP_VAR(shl), OP_VAR(shr),
+ OP_VAR(lte), OP_VAR(lt), OP_VAR(gte), OP_VAR(gt),
+ OP_VAR(eq), OP_VAR(ne), OP_VAR(and), OP_VAR(xor),
+ OP_VAR(or), OP_VAR(set)
};
-operation_t iopfuncs[IOPS_COUNT] = {
- iop_mult, iop_div, iop_mod, iop_add, iop_sub,
- iop_shl, iop_shr, iop_lte, iop_lt, iop_gte,
- iop_gt, iop_eq, iop_ne, iop_and, iop_xor,
- iop_or
+const char *opnames[] = {
+ "*", "/", "%", 0,
+ "+", "-", "<<", ">>",
+ "<=", "<", ">=", ">",
+ "==", "!=", "&", "^",
+ "|", "="
};
-
-void iop_add(variable *r, variable *a, variable *b)
-{
- r->value.f = a->value.f + b->value.f;
-}
-
-void iop_sub(variable *r, variable *a, variable *b)
-{
- r->value.f = a->value.f - b->value.f;
-}
-
-void iop_mult(variable *r, variable *a, variable *b)
+OP_DEF(mul)
{
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
r->value.f = a->value.f * b->value.f;
+ return 0;
}
-
-void iop_div(variable *r, variable *a, variable *b)
+OP_DEF(div)
{
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
r->value.f = a->value.f / b->value.f;
+ return 0;
}
-
-void iop_and(variable *r, variable *a, variable *b)
+OP_DEF(mod)
{
- r->value.f = (float)((int)a->value.f & (int)b->value.f);
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
+ r->value.f = (int)a->value.f % (int)b->value.f;
+ return 0;
}
-
-void iop_or(variable *r, variable *a, variable *b)
+OP_DEF(add)
{
- r->value.f = (float)((int)a->value.f | (int)b->value.f);
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
+ r->value.f = a->value.f + b->value.f;
+ return 0;
}
-
-void iop_xor(variable *r, variable *a, variable *b)
+OP_DEF(sub)
{
- r->value.f = (float)((int)a->value.f ^ (int)b->value.f);
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
+ r->value.f = a->value.f - b->value.f;
+ return 0;
}
-
-void iop_shr(variable *r, variable *a, variable *b)
+OP_DEF(shl)
{
- r->value.f = (float)((int)a->value.f >> (int)b->value.f);
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
+ r->value.f = (int)a->value.f << (int)b->value.f;
+ return 0;
}
-
-void iop_shl(variable *r, variable *a, variable *b)
+OP_DEF(shr)
{
- r->value.f = (float)((int)a->value.f << (int)b->value.f);
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
+ r->value.f = (int)a->value.f >> (int)b->value.f;
+ return 0;
}
-
-void iop_eq(variable *r, variable *a, variable *b)
+OP_DEF(lte)
{
- if (a->valtype == STRING && b->valtype == STRING)
- r->value.f = (float)!strcmp((char *)a->value.p, (char *)b->value.p);
- else
- r->value.f = a->value.f == b->value.f;
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
+ r->value.f = a->value.f <= b->value.f;
+ return 0;
}
-
-void iop_lt(variable *r, variable *a, variable *b)
+OP_DEF(lt)
{
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
r->value.f = a->value.f < b->value.f;
+ return 0;
}
-
-void iop_gt(variable *r, variable *a, variable *b)
+OP_DEF(gte)
{
- r->value.f = a->value.f > b->value.f;
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
+ r->value.f = a->value.f >= b->value.f;
+ return 0;
}
-
-void iop_lte(variable *r, variable *a, variable *b)
+OP_DEF(gt)
{
- r->value.f = a->value.f <= b->value.f;
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
+ r->value.f = a->value.f > b->value.f;
+ return 0;
}
-
-void iop_gte(variable *r, variable *a, variable *b)
+OP_DEF(eq)
{
- r->value.f = a->value.f >= b->value.f;
-}
+ r->type = NUMBER;
+ if (a->type == NUMBER && b->type == NUMBER)
+ r->value.f = a->value.f == b->value.f;
+ else if (a->type == STRING && b->type == STRING)
+ r->value.f = !strcmp((const char *)a->value.p, (const char *)b->value.p);
+ else
+ return -1;
-void iop_ne(variable *r, variable *a, variable *b)
-{
- r->value.f = a->value.f != b->value.f;
+ return 0;
}
-
-void iop_mod(variable *r, variable *a, variable *b)
+OP_DEF(ne)
{
- r->value.f = (float)((int)a->value.f % (int)b->value.f);
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
+ r->value.f = a->value.f != b->value.f;
+ return 0;
+}
+OP_DEF(and)
+{
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
+ r->value.f = (int)a->value.f & (int)b->value.f;
+ return 0;
+}
+OP_DEF(xor)
+{
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
+ r->value.f = (int)a->value.f ^ (int)b->value.f;
+ return 0;
+}
+OP_DEF(or)
+{
+ if (a->type != NUMBER || b->type != NUMBER)
+ return -1;
+ r->type = NUMBER;
+ r->value.f = (int)a->value.f | (int)b->value.f;
+ return 0;
+}
+OP_DEF(set)
+{
+ if (b->type == NUMBER) {
+ a->type = NUMBER;
+ a->value.f = b->value.f;
+ r->type = NUMBER;
+ r->value.f = a->value.f;
+ } else if (b->type == STRING) {
+ a->type = STRING;
+ if (a->value.p != 0)
+ free((void *)a->value.p);
+ a->value.p = (uint32_t)strclone((char *)b->value.p);
+ r->type = STRING;
+ r->value.p = (uint32_t)strclone((char *)a->value.p);
+ } else {
+ return -1;
+ }
+ return 0;
}
diff --git a/ops.h b/ops.h
index 5c7832f..8296cbe 100644
--- a/ops.h
+++ b/ops.h
@@ -1,13 +1,14 @@
#ifndef OPS_H_
#define OPS_H_
-#include "parser.h"
+#include "variable.h"
-#define IOPS_COUNT 16
+#define OPS_COUNT 18
+#define OP_MAGIC 0xCAFE3900
-typedef void (*operation_t)(variable *, variable *, variable *);
+typedef int (*opfunc_t)(variable *, variable *, variable *);
-extern char *iops[IOPS_COUNT];
-extern operation_t iopfuncs[IOPS_COUNT];
+extern variable opvars[];
+extern const char *opnames[];
#endif // OPS_H_
diff --git a/parser.c b/parser.c
index 886d27b..a2ab8d5 100644
--- a/parser.c
+++ b/parser.c
@@ -1,478 +1,486 @@
-#include <parser.h>
+#include "parser.h"
-#include "shelpers.h"
#include "builtins.h"
-#include "stack.h"
#include "ops.h"
#include <ctype.h>
#include <stdlib.h>
-#include <memory.h>
+#include <stdio.h>
#include <string.h>
-#define MAX_VARS 100
-#define MAX_STACK 32
+#define MAX_VARS 256
+#define MAX_STACK 64
#define MAX_LINES 1000
-void iinit(interpreter *interp)
+char *strnclone(const char *s, size_t c)
{
- 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->stidx = 0;
- interp->lines = (variable ***)calloc(MAX_LINES, sizeof(variable **));
- interp->lnidx = 0;
- interp->indent = 0;
- interp->sindent = 0;
- interp->ret = 0;
-
- iload_core(interp);
+ char *b = strncpy((char *)malloc(c + 1), s, c);
+ b[c] = '\0';
+ return b;
}
-
-void iend(interpreter *it)
+char *strclone(const char *s)
{
- for (unsigned int i = 0; i < MAX_VARS; i++) {
- if (it->vars[i].used == 1) {
- if (it->vars[i].valtype == STRING ||
- it->vars[i].valtype == EXPR)
- free((void *)it->vars[i].value.p);
- free(it->vnames[i]);
- }
- }
- for (unsigned int i = 0; i < MAX_LINES; i++) {
- if (it->lines[i] != 0) {
- for (unsigned int j = 0; (int32_t)it->lines[i][j] > 0; j++) {
- switch (it->lines[i][j]->valtype) {
- case STRING:
- if (!it->lines[i][j]->used)
- free(it->lines[i][j]);
- break;
- case EXPR:
- free((void *)it->lines[i][j]->value.p);
- free(it->lines[i][j]);
- break;
- case NUMBER:
- if (!it->lines[i][j]->used)
- free(it->lines[i][j]);
- break;
- }
- }
+ return strnclone(s, strlen(s));
+}
+char *fixstring(const char *s)
+{
+ char *n = malloc(strlen(s) + 1 - 2);
+ int j = 0;
+ for (int i = 1; s[i] != '\"'; i++, j++) {
+ if (s[i] == '\\') {
+ if (s[i + 1] == 'n')
+ n[j] = '\n';
+ i++;
+ } else {
+ n[j] = s[i];
}
- free(it->lines[i]);
}
+ n[j] = '\0';
+ return n;
+}
+
+void itryfree(variable *v)
+{
+ if (v == 0 || v->tmp == 0)
+ return;
+ if (v->type == STRING)
+ free((void *)v->value.p);
+ free(v);
+}
+
+instance *inewinstance(void)
+{
+ instance *it = (instance *)malloc(sizeof(instance));
+ it->vars = (variable *)calloc(MAX_VARS, sizeof(variable));
+ it->names = (char **)calloc(MAX_VARS, sizeof(char *));
+ it->stack = (uint32_t *)malloc(MAX_STACK * sizeof(uint32_t));
+ it->stidx = 0;
+ it->lines = (char **)calloc(MAX_LINES, sizeof(char *));
+ it->lnidx = 0;
+ it->ret = 0;
+ it->indent = 0;
+ it->sindent = 0;
+
+ iload_builtins(it);
+ return it;
+}
+
+void idelinstance(instance *it)
+{
free(it->vars);
- free(it->vnames);
+ for (uint32_t i = 0; i < MAX_VARS; i++)
+ free(it->names[i]);
+ free(it->names);
free(it->stack);
+ for (uint32_t i = 0; i < MAX_VARS; i++)
+ free(it->lines[i]);
free(it->lines);
+ itryfree(it->ret);
+ free(it);
}
-void iskip(interpreter *it)
+void ipush(instance *it, uint32_t v)
{
- if (!(it->sindent & SKIP))
- it->sindent = it->indent | SKIP;
+ it->stack[it->stidx++] = v;
}
-variable *interpreter_get_variable(interpreter *interp, const char *name)
+uint32_t ipop(instance *it)
{
- for (uint32_t i = 0; i < MAX_VARS; i++) {
- if (!interp->vars[i].used) {
- variable *v = make_vars(&interp->vars[i], 0);
- v->used = 1;
- interp->vnames[i] = strclone(name);
- return v;
- } else if (interp->vnames[i] != 0 && !strcmp(interp->vnames[i], name)) {
- return &interp->vars[i];
- }
- }
- return 0;
+ return it->stack[--it->stidx];
}
-char *interpreter_get_name(interpreter *interp, variable *v)
+void ipopm(instance *it, uint32_t count)
{
- for (uint32_t i = 0; i < MAX_VARS; i++) {
- if (v == &interp->vars[i])
- return interp->vnames[i];
- }
- return "(undefined)";
+ it->stidx -= count;
}
-variable *inew_string(interpreter *interp, const char *name, const char *value)
+variable *igetarg(instance *it, uint32_t n)
{
- variable *v = interpreter_get_variable(interp, name);
- if (v != 0) {
- if (v->valtype == STRING && v->value.p != 0)
- free((void *)v->value.p);
- v->valtype = STRING;
- v->value.p = (uint32_t)strclone(value);
- }
- return v;
+ return (variable *)it->stack[it->stidx - n - 1];
}
-variable *inew_number(interpreter *interp, const char *name, float value)
+variable *igetvar(instance *it, const char *name);
+void inew_cfunc(instance *it, const char *name, func_t func)
{
- variable *v = interpreter_get_variable(interp, name);
- if (v != 0) {
- v->valtype = NUMBER;
- v->value.f = value;
- }
+ variable *v = igetvar(it, name);
+ v->type = CFUNC;
+ v->value.p = (uint32_t)func;
+}
+
+void inew_number(instance *it, const char *name, float f)
+{
+ variable *v = igetvar(it, name);
+ v->type = NUMBER;
+ v->value.f = f;
+}
+
+void inew_string(instance *it, const char *name, const char *s)
+{
+ variable *v = igetvar(it, name);
+ v->type = STRING;
+ v->value.p = (uint32_t)strclone(s);
+}
+
+variable *varclone(variable *n)
+{
+ variable *v = (variable *)malloc(sizeof(variable));
+ v->tmp = 1;
+ v->type = n->type;
+ if (n->type == STRING)
+ v->value.p = (uint32_t)strclone((char *)n->value.p);
+ else
+ v->value.p = n->value.p;
return v;
}
-variable *inew_cfunc(interpreter *interp, const char *name, func_t func)
+variable *make_varf(variable *v, float f)
{
- variable *v = interpreter_get_variable(interp, name);
- if (v != 0) {
- v->fromc = 1;
- v->valtype = FUNC;
- v->value.p = (uint32_t)func;
+ if (v == 0) {
+ v = (variable *)malloc(sizeof(variable));
+ v->tmp = 1;
}
+ v->type = NUMBER;
+ v->value.f = f;
return v;
}
-variable *make_var(interpreter *interp, const char *line, uint32_t *next)
+variable *make_vars(variable *v, const char *s)
{
- if (line[0] == '\"') { // string literal
- uint32_t end = 1;
- while (!eol(line[end])) {
- if (line[end] == '\"'/* && line[end - 1] != '\\'*/) {
- if (!eot(line[end + 1]))
- return 0;
- // TODO string breakdown
- *next = end + 1;
- char *str = strnclone(line + 1, end - 1);
- variable *v = make_vars(0, str);
- free(str);
- return v;
- }
- end++;
- }
- return 0;
- } else if (line[0] == '(') { // equation literal
- uint32_t end = findend(line, '(', ')');
- if (eot(line[end]))
- return 0;
- *next = end + 1;
- char *expr = strnclone(line + 1, end);
- variable *v = make_vare(0, expr);
- free(expr);
- return v;
- } else {
- variable *v = make_varn(0, 0.0f);
- int inc = try_number(v, line);
- if (inc != 0) {
- *next = inc;
- return v;
- }
- free(v);
- char *name = 0;
- inc = try_variable(&name, line);
- if (inc != 0) {
- *next = (inc > 0) ? inc : -inc;
- variable *v = interpreter_get_variable(interp, name);
- free(name);
- return v;
- }
+ if (v == 0) {
+ v = (variable *)malloc(sizeof(variable));
+ v->tmp = 1;
}
- return 0;
+ v->type = STRING;
+ v->value.p = (uint32_t)strclone(s);
+ return v;
}
-int idoline(interpreter *interp, const char *line)
+variable *make_num(const char *text)
{
- uint32_t ooffset = 0, offset = 0, next;
- int fret = 0;
-
- if (line[0] == '\0')
- return 0;
- skipblank(line, eol, &offset);
- if (line[offset] == '#' || eol(line[offset]))
- return 0;
-
- variable **linebuf = (variable **)calloc(8, sizeof(variable *));
- interp->lines[interp->lnidx] = linebuf;
- variable **ops = interp->lines[interp->lnidx];
-
- // step 1 - convert to tokens
- while (!eol(line[offset])) {
- if (offset > 0 && line[offset] == '>') {
- offset++;
- skipblank(line, eol, &offset);
- variable *r = make_var(interp, line + offset, &next);
- ops[ooffset] = (void *)-1;
- ops[ooffset + 1] = r;
- offset += next;
- skipblank(line, eol, &offset);
- continue;
- }
- variable *v = make_var(interp, line + offset, &next);
- ops[ooffset] = v;
- if (ops[ooffset] == 0) {
- fret = -4;
- goto fail;
+ int decimal = -1;
+ char valid = 0;
+
+ int i = 0;
+ if (text[0] == '-')
+ i++;
+ do {
+ if (text[i] == '.') {
+ if (decimal >= 0) {
+ valid = 0;
+ break;
+ }
+ decimal = i;
+ } else if (isdigit(text[i])) {
+ valid |= 1;
} else {
- ooffset++;
- offset += next;
+ break;
}
- skipblank(line, eol, &offset);
- }
+ } while (text[++i] != '\0');
- // step 2 - execute
- if (ooffset == 0) {
- fret = -1;
- goto fail;
- }
-
- if (ops[0]->valtype != FUNC) {
- fret = -2;
- goto fail;
- }
+ if (valid == 0)
+ return 0;
- if (ops[0]->fromc && ops[0]->value.p == 0) {
- fret = -3;
- goto fail;
- }
+ char *buf = (char *)malloc(i + 1);
+ strncpy(buf, text, i);
+ buf[i] = '\0';
- if (ops[ooffset] != (void *)-1)
- ops[ooffset] = 0;
+ variable *v = make_varf(0, strtof(buf, 0));
+ free(buf);
+ return v;
+}
-loop:
- for (uint8_t i = 0; i < IUP_COUNT; i++) {
- if (interp->lines[interp->lnidx][0]->value.p
- == (uint32_t)indent_up[i]) {
- interp->indent++;
- goto cont;
+variable *igetop(instance *it, const char *name)
+{
+ for (uint32_t i = 0; i < OPS_COUNT; i++) {
+ if (opnames[i] != 0 && !strcmp(name, opnames[i])) {
+ return &opvars[i];
}
}
- for (uint8_t i = 0; i < IDOWN_COUNT; i++) {
- if (interp->lines[interp->lnidx][0]->value.p
- == (uint32_t)indent_down[i]) {
- if (--interp->indent < 0) {
- fret = -6;
- goto fail;
+ return 0;
+}
+variable *igetvar(instance *it, const char *name)
+{
+ if (isalpha(name[0])) {
+ for (uint32_t i = 0; i < MAX_VARS; i++) {
+ if (it->names[i] == 0) {
+ it->names[i] = strclone(name);
+ // default to 0 float
+ return make_varf(&it->vars[i], 0.0f);
+ } else if (!strcmp(name, it->names[i])) {
+ return &it->vars[i];
}
- if (interp->indent < (interp->sindent & ~(SKIP)))
- interp->sindent &= ~(SKIP);
- else
- goto cont;
- break;
}
}
-cont:
- if (interp->indent > 0 && interp->sindent & SKIP)
- goto norun;
-
- ops = (variable **)malloc(8 * sizeof(variable *));
- for (uint8_t i = 0; i < 8; i++)
- ops[i] = interp->lines[interp->lnidx][i];
- uint32_t oldLnidx = interp->lnidx;
-
- // eval expressions
- ooffset = 1;
- for (; ops[ooffset] != 0 && ops[ooffset] != (void *)-1; ooffset++) {
- if (ops[ooffset]->valtype == EXPR) {
- char *expr = strclone((char *)ops[ooffset]->value.p);
- variable *r = idoexpr(interp, expr);
- ops[ooffset] = r;
- free(expr);
- }
- }
+ return igetop(it, name);
+}
- if (ops[ooffset] == (void *)-1)
- interp->ret = ops[ooffset + 1];
-
- if (ops[0]->fromc) {
- for (uint32_t i = ooffset; --i > 0;)
- ipush(interp, ops[i]);
-
- int ret = ((func_t)ops[0]->value.p)(interp);
- if (ret != 0)
- return ret;
- ipopm(interp, ooffset - 1);
- } else {
- char an[6];
- for (uint32_t i = 1; i < ooffset; i++) {
- snprintf(an, 6, "arg%d", (int)(i - 1));
- switch (ops[i]->valtype) {
- case STRING:
- inew_string(interp, an, (char *)ops[i]->value.p);
- break;
- case NUMBER:
- inew_number(interp, an, ops[i]->value.f);
- break;
- default:
- break;
- }
- }
+int idoline(instance *it, const char *s)
+{
+ it->lines[it->lnidx] = strclone(s);
+ variable **ops;
+loop:
+ ops = iparse(it, it->lines[it->lnidx]);
- ipush(interp, (void *)(uint32_t)interp->indent);
- ipush(interp, (void *)interp->lnidx);
- ipush(interp, (void *)-2); // magic
- interp->lnidx = ops[0]->value.p;
- interp->indent++;
- }
+ if (it->ret != 0)
+ itryfree(it->ret);
+ it->ret = 0;
- if ((int32_t)interp->stidx < 0) {
- interp->stidx = 0;
- return -5;
- }
+ if (ops == 0)
+ goto next;
+ it->ret = isolve(it, ops, 0);
- for (uint32_t i = 1; i < ooffset; i++) {
- if (ops[i] != interp->lines[oldLnidx][i]) {
- if (ops[i]->valtype == STRING || ops[i]->valtype == EXPR)
- free((void *)ops[i]->value.p);
- free(ops[i]);
- }
- }
+next:
free(ops);
-norun:
- interp->lnidx++;
- if (interp->lines[interp->lnidx] != 0)
+ it->lnidx++;
+ if (it->lines[it->lnidx] != 0)
goto loop;
return 0;
+}
+
+variable *isolve_(instance *it, variable **ops, uint32_t count);
+variable *isolve(instance *it, variable **ops, uint32_t count)
+{
+ if (count == 0)
+ for (count = 0; ops[count] != 0; count++);
+
+ for (uint32_t i = 0; i < count; i++) {
+ if (((uint32_t)ops[i] & OP_MAGIC) == OP_MAGIC) {
+ uint32_t count_ = (uint32_t)ops[i] & 0xFF;
+ ops[i] = isolve(it, ops + i + 1, count_);
+ for (uint32_t j = 1; j <= count_; j++)
+ ops[i + j] = 0;
+ }
+ }
-fail:
- free(interp->lines[interp->lnidx]);
- interp->lines[interp->lnidx] = 0;
- return fret;
+ return isolve_(it, ops, count);
}
-variable *idoexpr(interpreter *interp, const char *line)
+variable *isolve_(instance *it, variable **ops, uint32_t count)
{
- void *ops[16];
- uint32_t ooffset = 0;
- uint32_t offset = 0;
-
- // step 1 - break apart line
- for (uint8_t i = 0; i < 16; i++)
- ops[i] = 0;
-
- // skip whitespace
- skipblank(line, eol, &offset);
- while (!eoe(line[offset])) {
- if (line[offset] == '(') {
- uint8_t indent = 0;
- uint32_t i;
- for (i = offset + 1; !eol(line[i]); i++) {
- if (line[i] == '(') {
- indent++;
- } else if (line[i] == ')') {
- if (indent == 0) {
- break;
+ // first, look for functions
+ for (uint32_t i = 0; i < count; i++) {
+ if (ops[i] == 0)
+ continue;
+ if (ops[i]->type == CFUNC || ops[i]->type == FUNC) {
+ uint32_t nargs = (uint32_t)ops[i + 1];
+ uint32_t start = i;
+ i += 2;
+ int32_t j;
+ for (j = nargs; j > 0 && i < count; i++) {
+ if (ops[i] != 0) {
+ if (ops[start]->type == CFUNC) {
+ it->stack[it->stidx + j - 1] = (uint32_t)ops[i];
} else {
- indent--;
- }
+ char namebuf[6];
+ snprintf(namebuf, 6, "arg%d", nargs - j);
+ if (ops[i]->type == NUMBER)
+ inew_number(it, namebuf, ops[i]->value.f);
+ else
+ inew_string(it, namebuf,
+ (const char *)ops[i]->value.p);
+ }
+ j--;
}
}
- if (eol(line[i]))
+ if (j != 0)
return 0;
- ops[ooffset] = idoexpr(interp, line + offset + 1);
- offset = i + 1;
- } else {
- variable *v = make_varn(0, 0.0f);
- int inc = try_number(v, line + offset);
- if (inc != 0) {
- ops[ooffset] = v;
- offset += inc;
- } else {
- free(v);
- char *name;
- inc = try_variable(&name, line + offset);
- if (inc != 0) {
- v = interpreter_get_variable(interp, name);
- ops[ooffset] = v;
- free(name);
- if (inc < 0) {
- inc = -inc;
- ops[ooffset + 2] = v;
- ops[ooffset + 1] = (void *)5; // -
- ops[ooffset] = make_varn(0, 0.0f);
- ooffset += 2;
- }
- offset += inc;
- } else {
+
+ if (ops[start]->type == CFUNC) {
+ func_t func = (func_t)ops[start]->value.p;
+ it->stidx += nargs;
+
+ uint32_t sidx = it->stidx;
+ int ret = 0;
+ if (!(it->sindent & SKIP))
+ ret = func(it);
+ if (ret != 0)
return 0;
- }
+ if (it->stidx > sidx)
+ ops[start] = (variable *)ipop(it);
+ else
+ ops[start] = 0;
+ ipopm(it, nargs);
+ } else {
+ ipush(it, it->lnidx);
+ ipush(it, CALL_SIG);
+ it->lnidx = ops[start]->value.p;
+ }
+
+ ops[start + 1] = 0;
+ for (uint32_t j = start + 2; j < i; j++) {
+ itryfree(ops[j]);
+ ops[j] = 0;
}
}
+ }
- if (ops[ooffset] == 0)
- return 0;
-
- ooffset++;
+ // next, operators
+ for (uint32_t j = 0; j < OPS_COUNT; j += 2) {
+ for (uint32_t i = 0; i < count; i++) {
+ if (ops[i] == 0)
+ continue;
+ if (ops[i]->type == OPERATOR) {
+ if (ops[i]->value.p != (uint32_t)opvars[j].value.p) {
+ if (ops[i]->value.p != (uint32_t)opvars[j + 1].value.p)
+ continue;
+ }
- // skip whitespace
- skipblank(line, eoe, &offset);
- if (eoe(line[offset]))
- break;
+ opfunc_t func = (opfunc_t)ops[i]->value.p;
+ uint32_t aidx = i - 1;
+ while (ops[aidx] == 0 && aidx != 0)
+ aidx--;
+ if (ops[aidx] == 0)
+ return 0;
+ uint32_t bidx = i + 1;
+ while (ops[bidx] == 0 && ++bidx < count);
+ if (bidx == count)
+ return 0;
- for (uint32_t i = 0; i < IOPS_COUNT; i++) {
- int len = strlen(iops[i]);
- if (!strncmp(iops[i], line + offset, len)) {
- ops[ooffset] = (void *)(i + 1);
- offset += len;
- break;
+ if (it->sindent & SKIP) {
+ itryfree(ops[aidx]);
+ itryfree(ops[bidx]);
+ ops[aidx] = 0;
+ } else {
+ variable *v = varclone(ops[aidx]);
+ if (func(v, ops[aidx], ops[bidx]) != 0)
+ return 0;
+ itryfree(ops[aidx]);
+ ops[aidx] = v;
+ itryfree(ops[bidx]);
+ }
+ ops[i] = 0;
+ ops[bidx] = 0;
}
}
+ }
- if (ops[ooffset] == 0) // implicit multiply
- ops[ooffset] = (void *)1;
+ return ops[0];
+}
- ooffset++;
- // skip whitespace
- skipblank(line, eol, &offset);
- }
+variable **iparse(instance *it, const char *s)
+{
+ uint32_t ooffset = 0;
+ size_t offset = 0;
- if (ooffset % 2 == 0)
+ while (isblank(s[offset]))
+ offset++;
+ if (s[offset] == '#' || s[offset] == '\0' || s[offset] == '\n')
return 0;
- // step 2 - do operations
- // for every operator, ordered by importance
- for (uint32_t i = 0; i < IOPS_COUNT; i++) {
- // find instances of the operation
- for (uint32_t j = 1; j < ooffset; j += 2) {
- // if a match
- if ((uint32_t)ops[j] == i + 1) {
- // find args
- uint32_t ai = j - 1;
- uint32_t bi = j + 1;
- while (ops[ai] == 0)
- ai--;
- while (ops[bi] == 0)
- bi++;
-
- variable *r = (variable *)calloc(1, sizeof(variable));
- iopfuncs[i](r, ops[ai], ops[bi]);
-
- variable *v = (variable *)ops[ai];
- if (!v->used)
- free(v);
- ops[ai] = r;
- v = (variable *)ops[bi];
- if (!v->used)
- free(v);
- ops[bi] = 0;
- ops[j] = 0;
+ variable **ops = (variable **)calloc(32, sizeof(variable *));
+ while (s[offset] != '\0' && s[offset] != '\n') {
+ if (isalpha(s[offset])) {
+ size_t end = offset + 1;
+ while (isalnum(s[end]))
+ end++;
+ char *name = strnclone(s + offset, end - offset);
+ ops[ooffset++] = igetvar(it, name);
+ free(name);
+ while (isblank(s[end]))
+ end++;
+ if (s[end] == '(') {
+ uint32_t argidx = ooffset;
+ uint32_t argcount = 0;
+ ooffset++;
+ end++;
+ for (int last = end, c = 0; c >= 0; end++) {
+ if (s[end] == '(')
+ c++;
+ if (c == 0 && last != end && (s[end] == ',' || s[end] == ')')) {
+ argcount++;
+ char *arg = strnclone(s + last, end - last);
+ uint32_t parenidx = ooffset;
+ ooffset++;
+ variable **moreops = iparse(it, arg);
+ uint32_t count = 0;
+ if (moreops != 0) {
+ for (uint32_t i = 0; moreops[i] != 0; count++, i++)
+ ops[ooffset++] = moreops[i];
+ free(moreops);
+ }
+ free(arg);
+ ops[parenidx] = (variable *)(OP_MAGIC | count);
+ last = end + 1;
+ }
+ if (s[end] == ')')
+ c--;
+ }
+ if (s[end] != '\0')
+ end++;
+ ops[argidx] = (variable *)argcount;
+ }
+ offset = end;
+ } else if (isdigit(s[offset])) {
+ size_t end = offset + 1;
+ while (isdigit(s[end]) || s[end] == '.')
+ end++;
+ char *word = strnclone(s + offset, end - offset);
+ ops[ooffset++] = make_num(word);
+ free(word);
+ offset = end;
+ } else if (s[offset] == '\"') {
+ size_t end = offset + 1;
+ while (s[end] != '\"')// && s[end - 1] == '\\')
+ end++;
+ end++;
+ char *word = strnclone(s + offset, end - offset);
+ char *fword = fixstring(word);
+ ops[ooffset++] = make_vars(0, fword);
+ free(word);
+ free(fword);
+ offset = end;
+ } else if (s[offset] == '(') {
+ size_t i = offset + 1;
+ for (int c = 0; s[i] != ')' || --c >= 0; i++) {
+ if (s[i] == '(')
+ c++;
}
+ i++;
+ char *word = strnclone(s + offset + 1, i - offset - 2);
+ uint32_t parenidx = ooffset;
+ ooffset++;
+ variable **moreops = iparse(it, word);
+ uint32_t count = 0;
+ if (moreops != 0) {
+ for (uint32_t i = 0; moreops[i] != 0; count++, i++)
+ ops[ooffset++] = moreops[i];
+ free(moreops);
+ }
+ free(word);
+ ops[parenidx] = (variable *)(OP_MAGIC | count);
+ offset = i;
+ } else if (!isblank(s[offset])) {
+ size_t end = offset + 1;
+ while (!isblank(s[end]) && s[end] != '\0')
+ end++;
+ char *word = strnclone(s + offset, end - offset);
+
+ // bracket?
+ if (!strcmp(word, "{")) {
+ it->indent++;
+ if (it->sindent & SKIP)
+ ipush(it, SKIP_SIG);
+ } else if (!strcmp(word, "}")) {
+ it->indent--;
+ if (it->indent < (it->sindent & ~(SKIP)))
+ it->sindent = 0;
+ bn_end(it);
+ } else {
+ variable *v = igetop(it, word);
+ if (v == 0)
+ return 0;
+ ops[ooffset++] = v;
+ }
+ free(word);
+ offset = end;
+ } else {
+ offset++;
}
}
- variable *result = make_varn(0, ((variable *)ops[0])->value.f);
- if (!((variable *)ops[0])->used)
- free(ops[0]);
-
- //for (uint32_t i = 1; i < ooffset; i += 2)
- // iopfuncs[(uint32_t)ops[i] - 1](result, result, ops[i + 1]);
-
- //for (uint32_t i = 0; i < ooffset; i += 2) {
- // variable *v = (variable *)ops[i];
- // if (!v->used) {
- // if (v->valtype == STRING || v->valtype == EXPR)
- // free((void *)v->value.p);
- // free(ops[i]);
- // }
- //}
-
- return result;
+ // mark end
+ ops[ooffset] = 0;
+ return ops;
}
-
diff --git a/parser.h b/parser.h
index 1b0fdd6..57763c8 100644
--- a/parser.h
+++ b/parser.h
@@ -1,36 +1,40 @@
#ifndef PARSER_H_
#define PARSER_H_
-#include <variable.h>
+#include "variable.h"
-typedef variable *stack_t;
+#include <stdint.h>
typedef struct {
variable *vars;
- char **vnames;
- stack_t *stack;
+ char **names;
+ uint32_t *stack;
uint32_t stidx;
- variable ***lines;
+ char **lines;
uint32_t lnidx;
- int8_t indent;
- uint8_t sindent;
variable *ret;
-} interpreter;
+ uint8_t indent;
+ uint8_t sindent;
+} instance;
#define SKIP (1 << 7)
-typedef int (*func_t)(interpreter *);
+typedef int (*func_t)(instance *);
+
+instance *inewinstance(void);
+void idelinstance(instance *it);
-void iinit(interpreter *);
-void iend(interpreter *);
+int idoline(instance *it, const char *s);
+variable **iparse(instance *it, const char *s);
+variable *isolve(instance *it, variable **ops, uint32_t count);
-void iskip(interpreter *);
+void inew_cfunc(instance *it, const char *name, func_t func);
-variable *inew_string(interpreter *, const char *, const char *);
-variable *inew_number(interpreter *, const char *, float);
-variable *inew_cfunc(interpreter *, const char *, func_t);
+variable *make_varf(variable *v, float f);
+variable *make_vars(variable *v, const char *s);
-int idoline(interpreter *, const char *);
-variable *idoexpr(interpreter *, const char *);
+uint32_t ipop(instance *it);
+void ipush(instance *it, uint32_t v);
+variable *igetarg(instance *it, uint32_t n);
#endif // PARSER_H_
diff --git a/script b/script
deleted file mode 100644
index 35497fe..0000000
--- a/script
+++ /dev/null
@@ -1,7 +0,0 @@
-set x 42
-set eq ".a/a"
-
-solve eq > ans
-
-print ans
-print "\n"
diff --git a/shell.c b/shell.c
index 8704db6..ade66b9 100644
--- a/shell.c
+++ b/shell.c
@@ -1,27 +1,24 @@
-#include <parser.h>
-#include <builtins.h>
-
-#include "stack.h"
-
-#include <memory.h>
#include <stdio.h>
-//#include <stdlib.h>
#include <string.h>
-int s_put(interpreter *it)
+#include "parser.h"
+
+int print(instance *it)
{
- variable *v = igetarg(it, 0);
- if (v->valtype == NUMBER)
- printf("%.f", v->value.f);
- else
- printf("%s", (char *)v->value.p);
+ variable *s = igetarg(it, 0);
+ if (s->type == NUMBER) {
+ if (s->value.f == (int)s->value.f)
+ printf("%d\n", (int)s->value.f);
+ else
+ printf("%.3f\n", s->value.f);
+ } else if (s->value.p != 0) {
+ printf("%s\n", (char *)s->value.p);
+ }
return 0;
}
int main(int argc, char **argv)
{
- interpreter interp;
-
if (argc != 2) {
printf("Usage: %s file\n", argv[0]);
return -1;
@@ -33,20 +30,23 @@ int main(int argc, char **argv)
return -1;
}
- iinit(&interp);
- inew_cfunc(&interp, "print", s_put);
+ instance *it = inewinstance();
+ inew_cfunc(it, "print", print);
char *line = 0;
- unsigned int size;
+ size_t size;
int result;
while (getline(&line, &size, fp) != -1) {
*strchr(line, '\n') = '\0';
- result = idoline(&interp, line);
+ result = idoline(it, line);
if (result != 0)
printf("Error: %d\n", result);
+ //if (it->ret != 0)
+ // printf("%s = %f\n", line, it->ret->value.f);
}
fclose(fp);
- iend(&interp);
+ idelinstance(it);
return 0;
}
+
diff --git a/shelpers.c b/shelpers.c
deleted file mode 100644
index 20ec0cc..0000000
--- a/shelpers.c
+++ /dev/null
@@ -1,64 +0,0 @@
-#include "shelpers.h"
-
-#include <memory.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);
- clone[n] = '\0';
- 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;
-}
-
diff --git a/shelpers.h b/shelpers.h
deleted file mode 100644
index 7f2ad63..0000000
--- a/shelpers.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#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_
diff --git a/stack.c b/stack.c
deleted file mode 100644
index 8ada8ea..0000000
--- a/stack.c
+++ /dev/null
@@ -1,38 +0,0 @@
-#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];
-}
-
-const char *igetarg_string(interpreter *interp, uint32_t index)
-{
- if (index >= interp->stidx)
- return 0;
- variable *v = igetarg(interp, index);
- return (const char *)v->value.p;
-}
-
-float igetarg_number(interpreter *interp, uint32_t index)
-{
- if (index >= interp->stidx)
- return 0;
- variable *v = igetarg(interp, index);
- return v->value.f;
-}
-
diff --git a/stack.h b/stack.h
deleted file mode 100644
index 18821a1..0000000
--- a/stack.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#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);
-const char *igetarg_string(interpreter *interp, uint32_t index);
-float igetarg_number(interpreter *interp, uint32_t index);
-
-#define igetarg_integer(i, x) (int)igetarg_number(i, x)
-
-#endif // STACK_H_
diff --git a/stdlib.h b/stdlib.h
deleted file mode 100644
index b87a823..0000000
--- a/stdlib.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef STDLIB_H_
-#define STDLIB_H_
-
-char *snprintf(char *buf, unsigned int max, const char *format, ...);
-float strtof(const char *s, char **endptr);
-
-int atoi(const char *);
-
-#endif // STDLIB_H_
diff --git a/test1 b/test1
new file mode 100644
index 0000000..1d8588c
--- /dev/null
+++ b/test1
@@ -0,0 +1,13 @@
+# test1
+# arithmetic tests
+# looking for proper basic function, respect for order of ops,
+# and respect for parentheses
+
+2 + 5
+14 - 9
+3 * 8 + 3
+9 - 3 / 2
+3 * (8 + 3)
+(9 - 3) / 2
+(4 + 5) * ((9 - 1) + 3)
+5 - 3 + 4
diff --git a/test2 b/test2
new file mode 100644
index 0000000..f836124
--- /dev/null
+++ b/test2
@@ -0,0 +1,16 @@
+# test2
+# variable and function tests
+# show variable recognition and proper c-function handling
+
+a * 1
+3 + b
+
+set(a, 5)
+a * 1
+
+set(c, 4)
+a / c
+
+set(b, 2) set(d, 8)
+
+d + set(e, 4)
diff --git a/test3 b/test3
new file mode 100644
index 0000000..940ed6f
--- /dev/null
+++ b/test3
@@ -0,0 +1,25 @@
+# test3
+# verify builtin functions, conditionals and such
+
+a = 5
+
+func(checka) {
+ if (a == 5) {
+ print("a == 5")
+ } else {
+ print("a != 5")
+ }
+}
+
+checka
+
+print("Increment a...")
+a = a + 1
+checka
+
+d = 0
+while (d < 10) {
+ print(d)
+ d = d + 1
+}
+
diff --git a/test4 b/test4
new file mode 100644
index 0000000..af8595e
--- /dev/null
+++ b/test4
@@ -0,0 +1,6 @@
+# test4
+# find memory leaks
+
+x = 4
+y = solve("x-2")
+print(y)
diff --git a/variable.c b/variable.c
deleted file mode 100644
index 957a130..0000000
--- a/variable.c
+++ /dev/null
@@ -1,135 +0,0 @@
-#include "variable.h"
-#include "parser.h"
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <memory.h>
-#include <string.h>
-#include <shelpers.h>
-
-extern int atoi(const char *);
-
-char *fixstring(char *s)
-{
- char *n = malloc(strlen(s) + 1);
- int j = 0;
- for (int i = 0; s[i] != '\0'; i++, j++) {
- if (s[i] == '\\') {
- if (s[i + 1] == 'n')
- n[j] = '\n';
- i++;
- } else {
- n[j] = s[i];
- }
- }
- n[j] = '\0';
- return n;
-}
-
-variable *make_varn(variable *v, float value)
-{
- if (v == 0)
- v = (variable *)malloc(sizeof(variable));
- v->used = 0;
- v->fromc = 0;
- v->valtype = NUMBER;
- v->value.f = value;
- return v;
-}
-
-variable *make_vars(variable *v, const char *value)
-{
- if (v == 0)
- v = (variable *)malloc(sizeof(variable));
- v->used = 0;
- v->fromc = 0;
- v->valtype = STRING;
- v->value.p = (value != 0) ? (uint32_t)fixstring(value) : 0;
- return v;
-}
-
-variable *make_varf(variable *v, uint8_t fromc, uint32_t func)
-{
- if (v == 0)
- v = (variable *)malloc(sizeof(variable));
- v->used = 0;
- v->fromc = fromc;
- v->valtype = FUNC;
- v->value.p = func;
- return v;
-}
-
-variable *make_vare(variable *v, const char *expr)
-{
- if (v == 0)
- v = (variable *)malloc(sizeof(variable));
- v->used = 0;
- v->fromc = 0;
- v->valtype = EXPR;
- v->value.p = (uint32_t)strclone(expr);
- return v;
-}
-
-int try_variable(char **name, const char *text)
-{
- if (name == 0)
- return 0;
-
- int neg = 1;
- int i = 0;
-
- if (text[0] == '-') {
- neg = -1;
- i++;
- }
- if (!isalpha(text[i]))
- return 0;
-
- for (i++; isalnum(text[i]); i++);
-
- int o = (neg < 0);
- if (neg < 0)
- i--;
- *name = (char *)malloc(i + 1);
- strncpy(*name, text + o, i);
- (*name)[i] = '\0';
- return (neg > 0) ? i : -(i + 1);
-}
-
-int try_number(variable *v, const char *text)
-{
- if (v == 0)
- return 0;
-
- int decimal = -1;
- char valid = 0;
-
- int i = 0;
- if (text[0] == '-')
- i++;
- do {
- if (text[i] == '.') {
- if (decimal >= 0) {
- valid = 0;
- break;
- }
- decimal = i;
- } else if (isdigit(text[i])) {
- valid |= 1;
- } else {
- break;
- }
- } while (text[++i] != '\0');
-
- if (valid == 0)
- return 0;
-
- char *buf = (char *)malloc(i + 1);
- strncpy(buf, text, i);
- buf[i] = '\0';
-
- make_varn(v, strtof(buf, 0));
-
- free(buf);
- return i;
-}
diff --git a/variable.h b/variable.h
index da3badc..4c7b987 100644
--- a/variable.h
+++ b/variable.h
@@ -4,28 +4,21 @@
#include <stdint.h>
typedef struct {
- uint8_t used :1;
- uint8_t fromc :1;
- uint8_t valtype :4;
+ uint8_t tmp :1;
+ uint8_t type :3;
+ uint8_t unused :4;
union {
float f;
uint32_t p;
} value;
} variable;
-enum valtype {
- STRING = 0,
- NUMBER,
+enum VARTYPE {
+ NUMBER = 0,
+ STRING,
+ OPERATOR,
FUNC,
- EXPR
+ CFUNC,
};
-variable *make_varn(variable *v, float value);
-variable *make_vars(variable *v, const char *s);
-variable *make_varf(variable *v, uint8_t fromc, uint32_t func);
-variable *make_vare(variable *v, const char *e);
-
-int try_number(variable *v, const char *text);
-int try_variable(char **name, const char *text);
-
#endif // VARIABLE_H_