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