]> code.bitgloo.com Git - clyne/interpreter.git/commitdiff
interpreter overhaul, should be better
authorClyne Sullivan <tullivan99@gmail.com>
Wed, 21 Mar 2018 16:29:09 +0000 (12:29 -0400)
committerClyne Sullivan <tullivan99@gmail.com>
Wed, 21 Mar 2018 16:29:09 +0000 (12:29 -0400)
23 files changed:
Makefile
README.md
builtins.c
builtins.h
memory.h [deleted file]
old.tar.gz [new file with mode: 0644]
ops.c
ops.h
parser.c
parser.h
script [deleted file]
shell.c
shelpers.c [deleted file]
shelpers.h [deleted file]
stack.c [deleted file]
stack.h [deleted file]
stdlib.h [deleted file]
test1 [new file with mode: 0644]
test2 [new file with mode: 0644]
test3 [new file with mode: 0644]
test4 [new file with mode: 0644]
variable.c [deleted file]
variable.h

index b4a7bfce5dbd29e1ed381356f6d2a93383f1a623..57f022ced54c213d496388b663a59492f8cf0b81 100644 (file)
--- 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
index 6084d7c55d25b7f89edc17b1efbbbb11049b6142..7ef1f3400ca3ec28143c16f089ffc660c2d28ca3 100644 (file)
--- 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.
index 0ab6f3b993d3e6ea657fe7607a98e1fb09a3f843..ea1cc954a30073f66c7a8986549b9149756d1b45 100644 (file)
 #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;
 }
 
index 5c8e350897bdb77a421944125f0a15bd76a781bd..7570eabbf3a0c9dee7a1f3a68a3a176dd6014d6e 100644 (file)
@@ -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 (file)
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 (file)
index 0000000..0a2e13f
Binary files /dev/null and b/old.tar.gz differ
diff --git a/ops.c b/ops.c
index 5267b6ff150f59b458a5ec68e63dbd4fd3a3fc8f..0d6b2927183c8756240e4f50e4b3646a1f4b8f58 100644 (file)
--- a/ops.c
+++ b/ops.c
 #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 5c7832fe26f34fad7c3f9bc8c4bc086f2fe062bd..8296cbe0b25bb1591701f5b07713abd1a954afa6 100644 (file)
--- 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_
index 886d27bdbe0460851d6f426b93ce608839dfaef2..a2ab8d55834b4568571b806139a0e56b6d181960 100644 (file)
--- a/parser.c
+++ b/parser.c
-#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;
 }
-
index 1b0fdd67f57ac235636ec366e25b4ebb339f5b35..57763c84900ca957ba84561d9215c965d2d2ec9c 100644 (file)
--- 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 (file)
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 8704db6b0103f766f4d20e48df618d6630441a81..ade66b9adad4cc76d75dbfb9fcc3952218b8e97d 100644 (file)
--- 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 (file)
index 20ec0cc..0000000
+++ /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 (file)
index 7f2ad63..0000000
+++ /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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
index 957a130..0000000
+++ /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;
-}
index da3badc0a37d13f6d2d5199df80541e52c8c7314..4c7b98740bd9a39f8c92ec7522e4b9e6b94e8092 100644 (file)
@@ -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_