diff options
-rw-r--r-- | Makefile | 36 | ||||
-rw-r--r-- | README.md | 32 | ||||
-rw-r--r-- | builtins.c | 225 | ||||
-rw-r--r-- | builtins.h | 11 | ||||
-rw-r--r-- | memory.h | 8 | ||||
-rw-r--r-- | old.tar.gz | bin | 0 -> 46683 bytes | |||
-rw-r--r-- | ops.c | 236 | ||||
-rw-r--r-- | ops.h | 11 | ||||
-rw-r--r-- | parser.c | 780 | ||||
-rw-r--r-- | parser.h | 38 | ||||
-rw-r--r-- | script | 7 | ||||
-rw-r--r-- | shell.c | 40 | ||||
-rw-r--r-- | shelpers.c | 64 | ||||
-rw-r--r-- | shelpers.h | 62 | ||||
-rw-r--r-- | stack.c | 38 | ||||
-rw-r--r-- | stack.h | 16 | ||||
-rw-r--r-- | stdlib.h | 9 | ||||
-rw-r--r-- | test1 | 13 | ||||
-rw-r--r-- | test2 | 16 | ||||
-rw-r--r-- | test3 | 25 | ||||
-rw-r--r-- | test4 | 6 | ||||
-rw-r--r-- | variable.c | 135 | ||||
-rw-r--r-- | variable.h | 23 |
23 files changed, 788 insertions, 1043 deletions
@@ -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 @@ -1,18 +1,24 @@ # 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 script interpreter intends 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, atoi, strtof, and snprintf. Some other standard library functions are needed, but something like newlib should be able to provide them without needing any system calls. +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). -Features: -* function/variable defining through C -* functions and variables in script -* conditionals - if/else/end, do/while -* solve - solve expressions stored in string variables +Interpreter features: +* Variable/function definition - in C and in script +* if/else and while loops +* a solve function to parse strings at runtime -Todo list: -* scopes for variables -* error messages -* arrays? -* maybe for loops +Inconvenient features: +* no local variables +* whitespace sometimes ignored -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, link all .o's for x86) and use the header files. +Some TODO items: +* fix all memory leaks +* add better error messages +* arrays? +* 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. + @@ -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; } @@ -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 Binary files differnew file mode 100644 index 0000000..0a2e13f --- /dev/null +++ b/old.tar.gz @@ -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; } @@ -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_ @@ -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; } - @@ -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_ @@ -1,7 +0,0 @@ -set x 42 -set eq ".a/a" - -solve eq > ans - -print ans -print "\n" @@ -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_ @@ -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 @@ -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) @@ -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 +} + @@ -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; -} @@ -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_ |