From 2b8cf5e771cac4c2b087dc96a7ca05a459f630b5 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Wed, 7 Feb 2018 09:26:36 -0500 Subject: [PATCH] conditionals, returns, cleaner code --- Makefile | 7 +- README.md | 11 +- builtins.c | 118 +++++++++++++ builtins.h | 8 + ops.c | 167 ++++++++++++++++++ ops.h | 13 ++ parser.c | 503 +++++++---------------------------------------------- parser.h | 6 +- script | 18 +- shell.c | 2 + shelpers.c | 63 +++++++ shelpers.h | 62 +++++++ stack.c | 46 +++++ stack.h | 15 ++ variable.c | 71 ++++++++ variable.h | 10 ++ 16 files changed, 667 insertions(+), 453 deletions(-) create mode 100644 builtins.c create mode 100644 builtins.h create mode 100644 ops.c create mode 100644 ops.h create mode 100644 shelpers.c create mode 100644 shelpers.h create mode 100644 stack.c create mode 100644 stack.h create mode 100644 variable.c diff --git a/Makefile b/Makefile index 7fcb26c..f81b589 100644 --- a/Makefile +++ b/Makefile @@ -3,5 +3,10 @@ CC = gcc -m32 CFLAGS = -Wall -Wextra -Wno-strict-aliasing -I. -ggdb -fno-builtin all: + $(CC) $(CFLAGS) -c shelpers.c $(CC) $(CFLAGS) -c parser.c - $(CC) $(CFLAGS) shell.c parser.o -o shell + $(CC) $(CFLAGS) -c builtins.c + $(CC) $(CFLAGS) -c stack.c + $(CC) $(CFLAGS) -c ops.c + $(CC) $(CFLAGS) -c variable.c + $(CC) $(CFLAGS) shell.c *.o -o shell diff --git a/README.md b/README.md index 1a11269..6084d7c 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,19 @@ To use this program with your own device, you need some malloc/free implementati Only a few commands are built in to the interpreter: * set - set variables * func/end - define functions -* jmp - jump to line - +* if/end - if conditional +* do/while +* ret - return value from function + Other features: * function/variable defining in c * expression solving +* no local variables +* whitespace hopefully ignored Soon: -* conditionals * error messages +* arrays? +* maybe for loops This project is still in heavy development, so don't expect much. To include it in your own project, just link in parser.o and use the header files. diff --git a/builtins.c b/builtins.c new file mode 100644 index 0000000..cda7a93 --- /dev/null +++ b/builtins.c @@ -0,0 +1,118 @@ +#include "builtins.h" +#include "stack.h" + +extern char *str_func; + +int ifunc_set(interpreter *it); +int ifunc_label(interpreter *it); +int ifunc_end(interpreter *it); +int ifunc_if(interpreter *it); +int ifunc_do(interpreter *it); +int ifunc_while(interpreter *it); +int ifunc_ret(interpreter *it); + +void iload_core(interpreter *interp) +{ + inew_cfunc(interp, "set", ifunc_set); + inew_cfunc(interp, "func", ifunc_label); + inew_cfunc(interp, "end", ifunc_end); + inew_cfunc(interp, "if", ifunc_if); + inew_cfunc(interp, "do", ifunc_do); + inew_cfunc(interp, "while", ifunc_while); + inew_cfunc(interp, "ret", ifunc_ret); +} + +int ifunc_set(interpreter *it) +{ + variable *n = igetarg(it, 0); + variable *v = igetarg(it, 1); + + if (n == 0) + return -1; + + n->valtype = v->valtype; + n->value = v->value; + n->svalue = v->svalue; + return 0; +} + +int ifunc_label(interpreter *it) +{ + variable *n = igetarg(it, 0); + + if (n == 0) + return -1; + + n->valtype = FUNC; + n->value = it->lnidx; + n->svalue = str_func; + it->indent++; + return 0; +} + +int ifunc_if(interpreter *it) +{ + int v = igetarg_integer(it, 0); + if (v == 0) { + it->indent++; + } else { + void *tmp = ipop(it); + ipush(it, (void *)-1); + ipush(it, tmp); + } + return 0; +} + +int ifunc_end(interpreter *it) +{ + uint32_t lnidx = (uint32_t)ipop(it) + 1; + if (lnidx != 0) + it->lnidx = lnidx; + return 0; +} + +int ifunc_do(interpreter *it) +{ + ipush(it, (void *)it->lnidx); + return 0; +} + +int ifunc_while(interpreter *it) +{ + int c = igetarg_integer(it, 0); + ipop(it); + int nidx = (int)ipop(it); + if (c != 0) { + ipush(it, (void *)nidx); + it->lnidx = nidx; + } + ipush(it, 0); + return 0; +} + +int ifunc_ret(interpreter *it) +{ + variable *v = igetarg(it, 0); + switch (v->valtype) { + case INTEGER: + inew_integer(it, "RET", INT(v)); + break; + case FLOAT: + inew_float(it, "RET", FLOAT(v)); + break; + case STRING: + inew_string(it, "RET", v->svalue); + break; + default: + return -1; + break; + } + if (it->ret != 0) { + it->ret->valtype = v->valtype; + it->ret->value = v->value; + it->ret->svalue = v->svalue; + it->ret = 0; + } + return 0; +} + diff --git a/builtins.h b/builtins.h new file mode 100644 index 0000000..8739778 --- /dev/null +++ b/builtins.h @@ -0,0 +1,8 @@ +#ifndef BUILTINS_H_ +#define BUILTINS_H_ + +#include "parser.h" + +void iload_core(interpreter *it); + +#endif // BUILTINS_H_ diff --git a/ops.c b/ops.c new file mode 100644 index 0000000..34e7986 --- /dev/null +++ b/ops.c @@ -0,0 +1,167 @@ +#include "ops.h" + +void iop_add(variable *, variable *, variable *); +void iop_sub(variable *, variable *, variable *); +void iop_mult(variable *, variable *, variable *); +void iop_div(variable *, variable *, variable *); +void iop_and(variable *, variable *, variable *); +void iop_or(variable *, variable *, variable *); +void iop_xor(variable *, variable *, variable *); +void iop_shr(variable *, variable *, variable *); +void iop_shl(variable *, variable *, variable *); +void iop_eq(variable *, variable *, variable *); +void iop_lt(variable *, variable *, variable *); +void iop_gt(variable *, variable *, variable *); +void iop_lte(variable *, variable *, variable *); +void iop_gte(variable *, variable *, variable *); +void iop_ne(variable *, variable *, variable *); +void iop_mod(variable *, variable *, variable *); + +char *iops[IOPS_COUNT] = { + "+", "-", "*", "/", "&", "|", "^", ">>", "<<", + "==", "<", ">", "<=", ">=", "!=", "%" +}; + +operation_t iopfuncs[IOPS_COUNT] = { + iop_add, iop_sub, iop_mult, iop_div, iop_and, + iop_or, iop_xor, iop_shr, iop_shl, + iop_eq, iop_lt, iop_gt, iop_lte, iop_gte, iop_ne, + iop_mod +}; + + +void iop_add(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) { + INT(r) = INT(a) + INT(b); + } else { + itofloat(a); + itofloat(b); + FLOAT(r) = FLOAT(a) + FLOAT(b); + } +} + +void iop_sub(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) { + INT(r) = INT(a) - INT(b); + } else { + itofloat(a); + itofloat(b); + FLOAT(r) = FLOAT(a) - FLOAT(b); + } +} + +void iop_mult(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) { + INT(r) = INT(a) * INT(b); + } else { + itofloat(a); + itofloat(b); + FLOAT(r) = FLOAT(a) * FLOAT(b); + } +} + +void iop_div(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) { + INT(r) = INT(a) / INT(b); + } else { + itofloat(a); + itofloat(b); + FLOAT(r) = FLOAT(a) / FLOAT(b); + } +} + +void iop_and(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) { + INT(r) = INT(a) & INT(b); + } +} + +void iop_or(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) { + INT(r) = INT(a) | INT(b); + } +} + +void iop_xor(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) { + INT(r) = INT(a) ^ INT(b); + } +} + +void iop_shr(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) { + INT(r) = INT(a) >> INT(b); + } +} + +void iop_shl(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) { + INT(r) = INT(a) << INT(b); + } +} + +void iop_eq(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) + INT(r) = INT(a) == INT(b); + else + INT(r) = FLOAT(a) == FLOAT(b); +} + +void iop_lt(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) + INT(r) = INT(a) < INT(b); + else + INT(r) = FLOAT(a) < FLOAT(b); +} + +void iop_gt(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) + INT(r) = INT(a) > INT(b); + else + INT(r) = FLOAT(a) > FLOAT(b); +} + +void iop_lte(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) + INT(r) = INT(a) <= INT(b); + else + INT(r) = FLOAT(a) <= FLOAT(b); +} + +void iop_gte(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) + INT(r) = INT(a) >= INT(b); + else + INT(r) = FLOAT(a) >= FLOAT(b); +} + +void iop_ne(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) + INT(r) = INT(a) != INT(b); + else + INT(r) = FLOAT(a) != FLOAT(b); +} + +void iop_mod(variable *r, variable *a, variable *b) +{ + if (a->valtype == INTEGER && b->valtype == INTEGER) + INT(r) = INT(a) % INT(b); + else + INT(r) = 0; +} + diff --git a/ops.h b/ops.h new file mode 100644 index 0000000..5c7832f --- /dev/null +++ b/ops.h @@ -0,0 +1,13 @@ +#ifndef OPS_H_ +#define OPS_H_ + +#include "parser.h" + +#define IOPS_COUNT 16 + +typedef void (*operation_t)(variable *, variable *, variable *); + +extern char *iops[IOPS_COUNT]; +extern operation_t iopfuncs[IOPS_COUNT]; + +#endif // OPS_H_ diff --git a/parser.c b/parser.c index 0f75c9e..bd540e0 100644 --- a/parser.c +++ b/parser.c @@ -1,132 +1,41 @@ #include +#include "shelpers.h" +#include "builtins.h" +#include "stack.h" +#include "ops.h" + #include -#include #include #include -#define MAX_VARS 32 -#define MAX_STACK 32 - -#define INT(v) (*((int32_t *)&v->value)) -#define FLOAT(v) (*((float *)&v->value)) - -static char *str_func = "(func)"; -static char *str_undef = "(undefined)"; - -char *strclone(const char *s) -{ - char *clone = (char *)malloc(strlen(s) + 1); - strcpy(clone, s); - return clone; -} - -char *strnclone(const char *s, uint32_t n) -{ - char *clone = (char *)malloc(n + 1); - strncpy(clone, s, n); - return clone; -} - -void fsetstr(variable *f) -{ - if (f->svalue == 0) - f->svalue = (char *)malloc(16); - snprintf(f->svalue, 16, "%f", FLOAT(f)); -} - -void isetstr(variable *i) -{ - if (i->svalue == 0) - i->svalue = (char *)malloc(12); - snprintf(i->svalue, 12, "%d", INT(i)); -} - -uint8_t eol(int c) -{ - return c == '\n' || c == '\0'; -} - -uint8_t eot(int c) -{ - return eol(c) || c == ' '; -} - -uint8_t eoe(int c) -{ - return eol(c) || c == ')'; -} - -uint32_t findend(const char *s, char o, char c) -{ - uint8_t indent = 0; - uint32_t i; - for (i = 1; !eol(s[i]); i++) { - if (s[i] == o) { - indent++; - } else if (s[i] == c) { - if (indent == 0) - break; - else - indent--; - } - } - - return i; -} +#define MAX_VARS 48 +#define MAX_STACK 16 +#define MAX_LINES 1000 -void skipblank(const char *s, uint8_t (*cmp)(int), uint32_t *offset) -{ - uint32_t i = *offset; - while (!cmp(s[i])) { - if (s[i] != ' ' && s[i] != '\t') - break; - i++; - } - *offset = i; -} - -int ifunc_set(interpreter *it); -int ifunc_jmp(interpreter *it); -int ifunc_label(interpreter *it); -int ifunc_end(interpreter *it); -int ifunc_if(interpreter *it); -int ifunc_do(interpreter *it); -int ifunc_while(interpreter *it); +char *str_func = "(func)"; +char *str_undef = "(undefined)"; variable *idoexpr(interpreter *interp, const char *line); -variable *itostring(variable *v); -variable *itoint(variable *v); -variable *itofloat(variable *v); - void iinit(interpreter *interp) { - interp->vars = (variable *)calloc(MAX_VARS, sizeof(variable)); - interp->vnames = (char **)calloc(MAX_VARS, sizeof(char *)); - interp->stack = (stack_t *)calloc(MAX_STACK, sizeof(stack_t)); + interp->vars = (variable *)malloc(MAX_VARS * sizeof(variable)); + interp->vnames = (char **)malloc(MAX_VARS * sizeof(char *)); + interp->stack = (stack_t *)malloc(MAX_STACK * sizeof(stack_t)); interp->stidx = 0; - interp->lines = (char **)calloc(20, sizeof(char *)); + interp->lines = (char **)calloc(MAX_LINES, sizeof(char *)); interp->lnidx = 0; interp->indent = 0; - inew_cfunc(interp, "set", ifunc_set); - inew_cfunc(interp, "jmp", ifunc_jmp); - inew_cfunc(interp, "func", ifunc_label); - inew_cfunc(interp, "end", ifunc_end); - inew_cfunc(interp, "if", ifunc_if); - inew_cfunc(interp, "do", ifunc_do); - inew_cfunc(interp, "while", ifunc_while); -} - -void ipush(interpreter *it, void *v) -{ - it->stack[it->stidx++] = v; -} + for (unsigned int i = 0; i < MAX_VARS; i++) { + interp->vars[i].used = 0; + interp->vnames[i] = 0; + } + for (unsigned int i = 0; i < MAX_LINES; i++) + interp->lines[i] = 0; -void *ipop(interpreter *it) -{ - return it->stack[--it->stidx]; + iload_core(interp); } variable *interpreter_get_variable(interpreter *interp, const char *name) @@ -270,22 +179,34 @@ int idoline(interpreter *interp, const char *line) variable *ops[8]; uint32_t ooffset, offset, next; + if (line[0] == '\0') + return 0; + interp->lines[interp->lnidx] = strclone(line); loop: + ooffset = 0; + offset = 0; + if (line[0] == '#') { goto norun; } else if (interp->indent > 0) { - if (!strcmp(line, "end")) + skipblank(line, eol, &offset); + if (!strcmp(line + offset, "end")) interp->indent--; goto norun; } - ooffset = 0; - offset = 0; - // step 1 - convert to tokens skipblank(line, eol, &offset); while (!eol(line[offset])) { + if (offset > 0 && line[offset] == '>') { + offset++; + skipblank(line, eol, &offset); + interp->ret = make_var(interp, line + offset, &next); + offset += next; + skipblank(line, eol, &offset); + continue; + } ops[ooffset] = make_var(interp, line + offset, &next); if (ops[ooffset] == 0) { return -4; @@ -303,23 +224,40 @@ loop: if (ops[0]->valtype != FUNC) return -2; - if (ops[0]->value == 0) + if (ops[0]->fromc && ops[0]->value == 0) return -3; - for (uint32_t i = ooffset; --i > 0;) - ipush(interp, ops[i]); - if (ops[0]->fromc) { + for (uint32_t i = ooffset; --i > 0;) + ipush(interp, ops[i]); + int ret = ((func_t)ops[0]->value)(interp); if (ret != 0) return ret; + ipopm(interp, ooffset - 1); } else { - ipush(interp, (void *)(interp->lnidx + 1)); + char an[6]; + for (uint32_t i = 1; i < ooffset; i++) { + snprintf(an, 6, "arg%d", i - 1); + switch (ops[i]->valtype) { + case STRING: + inew_string(interp, an, ops[i]->svalue); + break; + case INTEGER: + inew_integer(interp, an, INT(ops[i])); + break; + case FLOAT: + inew_float(interp, an, FLOAT(ops[i])); + break; + default: + break; + } + } + + ipush(interp, (void *)(interp->lnidx)); interp->lnidx = ops[0]->value; } - interp->stidx -= ooffset - 1; - if ((int32_t)interp->stidx < 0) { interp->stidx = 0; return -5; @@ -340,36 +278,6 @@ norun: return 0; } -typedef void (*operation_t)(variable *, variable *, variable *); - -#define IOPS_COUNT 15 -static char *iops[IOPS_COUNT] = { - "+", "-", "*", "/", "&", "|", "^", ">>", "<<", - "==", "<", ">", "<=", ">=", "!=" -}; - -void iop_add(variable *, variable *, variable *); -void iop_sub(variable *, variable *, variable *); -void iop_mult(variable *, variable *, variable *); -void iop_div(variable *, variable *, variable *); -void iop_and(variable *, variable *, variable *); -void iop_or(variable *, variable *, variable *); -void iop_xor(variable *, variable *, variable *); -void iop_shr(variable *, variable *, variable *); -void iop_shl(variable *, variable *, variable *); -void iop_eq(variable *, variable *, variable *); -void iop_lt(variable *, variable *, variable *); -void iop_gt(variable *, variable *, variable *); -void iop_lte(variable *, variable *, variable *); -void iop_gte(variable *, variable *, variable *); -void iop_ne(variable *, variable *, variable *); - -static operation_t iopfuncs[IOPS_COUNT] = { - iop_add, iop_sub, iop_mult, iop_div, iop_and, - iop_or, iop_xor, iop_shr, iop_shl, - iop_eq, iop_lt, iop_gt, iop_lte, iop_gte, iop_ne -}; - variable *idoexpr(interpreter *interp, const char *line) { variable *result = (variable *)malloc(sizeof(variable)); @@ -413,12 +321,12 @@ variable *idoexpr(interpreter *interp, const char *line) ops[ooffset] = make_var(interp, line + offset, &next); if (end != 0) mline[end] = cend; + offset += next; } if (ops[ooffset] == 0) return 0; ooffset++; - offset += next; // skip whitespace skipblank(line, eoe, &offset); @@ -464,290 +372,3 @@ variable *idoexpr(interpreter *interp, const char *line) return result; } -variable *igetarg(interpreter *interp, uint32_t index) -{ - return interp->stack[interp->stidx - index - 1]; -} - -char *igetarg_string(interpreter *interp, uint32_t index) -{ - if (index >= interp->stidx) - return 0; - variable *v = igetarg(interp, index); - return v->svalue; -} - -int igetarg_integer(interpreter *interp, uint32_t index) -{ - if (index >= interp->stidx) - return 0; - variable *v = igetarg(interp, index); - return INT(itoint(v)); -} - -float igetarg_float(interpreter *interp, uint32_t index) -{ - if (index >= interp->stidx) - return 0; - variable *v = igetarg(interp, index); - return FLOAT(itofloat(v)); -} - -variable *itostring(variable *v) -{ - switch (v->valtype) { - case INTEGER: - v->valtype = STRING; - isetstr(v); - break; - case FLOAT: - v->valtype = STRING; - fsetstr(v); - break; - } - return v; -} - -variable *itoint(variable *v) -{ - switch (v->valtype) { - case STRING: - v->valtype = INTEGER; - INT(v) = atoi(v->svalue); - isetstr(v); - break; - case FLOAT: - v->valtype = INTEGER; - INT(v) = (int32_t)FLOAT(v); - isetstr(v); - break; - } - return v; -} - -variable *itofloat(variable *v) -{ - switch (v->valtype) { - case STRING: - v->valtype = FLOAT; - FLOAT(v) = strtof(v->svalue, 0); - fsetstr(v); - break; - case INTEGER: - v->valtype = FLOAT; - FLOAT(v) = (float)INT(v); - fsetstr(v); - break; - } - return v; -} - -/** - * Builtin functions - */ - -int ifunc_set(interpreter *it) -{ - variable *n = igetarg(it, 0); - variable *v = igetarg(it, 1); - - if (n == 0) - return -1; - - n->valtype = v->valtype; - n->value = v->value; - n->svalue = v->svalue; - return 0; -} - -int ifunc_label(interpreter *it) -{ - variable *n = igetarg(it, 0); - - if (n == 0) - return -1; - - n->valtype = FUNC; - n->value = it->lnidx; - n->svalue = str_func; - it->indent++; - return 0; -} - -int ifunc_if(interpreter *it) -{ - int v = igetarg_integer(it, 0); - if (v == 0) - it->indent++; - return 0; -} - -int ifunc_end(interpreter *it) -{ - if (it->stidx > 0) { - uint32_t line = (uint32_t)ipop(it); - it->lnidx = line - 1; - } - return 0; -} - -int ifunc_jmp(interpreter *it) -{ - int newidx = igetarg_integer(it, 0); - ipop(it); - ipush(it, (void *)(it->lnidx + 1)); - ipush(it, 0); - it->lnidx = newidx - 1; - return 0; -} - -int ifunc_do(interpreter *it) -{ - ipush(it, (void *)it->lnidx); - return 0; -} - -int ifunc_while(interpreter *it) -{ - int c = igetarg_integer(it, 0); - ipop(it); - int nidx = (int)ipop(it); - if (c != 0) { - ipush(it, (void *)nidx); - it->lnidx = nidx; - } - ipush(it, 0); - return 0; -} - -/** - * Builtin operations - */ - -void iop_add(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) { - INT(r) = INT(a) + INT(b); - } else { - itofloat(a); - itofloat(b); - FLOAT(r) = FLOAT(a) + FLOAT(b); - } -} - -void iop_sub(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) { - INT(r) = INT(a) - INT(b); - } else { - itofloat(a); - itofloat(b); - FLOAT(r) = FLOAT(a) - FLOAT(b); - } -} - -void iop_mult(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) { - INT(r) = INT(a) * INT(b); - } else { - itofloat(a); - itofloat(b); - FLOAT(r) = FLOAT(a) * FLOAT(b); - } -} - -void iop_div(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) { - INT(r) = INT(a) / INT(b); - } else { - itofloat(a); - itofloat(b); - FLOAT(r) = FLOAT(a) / FLOAT(b); - } -} - -void iop_and(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) { - INT(r) = INT(a) & INT(b); - } -} - -void iop_or(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) { - INT(r) = INT(a) | INT(b); - } -} - -void iop_xor(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) { - INT(r) = INT(a) ^ INT(b); - } -} - -void iop_shr(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) { - INT(r) = INT(a) >> INT(b); - } -} - -void iop_shl(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) { - INT(r) = INT(a) << INT(b); - } -} - -void iop_eq(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) - INT(r) = INT(a) == INT(b); - else - INT(r) = FLOAT(a) == FLOAT(b); -} - -void iop_lt(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) - INT(r) = INT(a) < INT(b); - else - INT(r) = FLOAT(a) < FLOAT(b); -} - -void iop_gt(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) - INT(r) = INT(a) > INT(b); - else - INT(r) = FLOAT(a) > FLOAT(b); -} - -void iop_lte(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) - INT(r) = INT(a) <= INT(b); - else - INT(r) = FLOAT(a) <= FLOAT(b); -} - -void iop_gte(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) - INT(r) = INT(a) >= INT(b); - else - INT(r) = FLOAT(a) >= FLOAT(b); -} - -void iop_ne(variable *r, variable *a, variable *b) -{ - if (a->valtype == INTEGER && b->valtype == INTEGER) - INT(r) = INT(a) != INT(b); - else - INT(r) = FLOAT(a) != FLOAT(b); -} - diff --git a/parser.h b/parser.h index 83a81e1..4e4699e 100644 --- a/parser.h +++ b/parser.h @@ -13,6 +13,7 @@ typedef struct { char **lines; uint32_t lnidx; uint8_t indent; + variable *ret; } interpreter; typedef int (*func_t)(interpreter *); @@ -26,9 +27,4 @@ void inew_cfunc(interpreter *, const char *, func_t); int idoline(interpreter *, const char *); -variable *igetarg(interpreter *, uint32_t); -char *igetarg_string(interpreter *, uint32_t); -int igetarg_integer(interpreter *, uint32_t); -float igetarg_float(interpreter *, uint32_t); - #endif // PARSER_H_ diff --git a/script b/script index b31a18e..3b807a2 100644 --- a/script +++ b/script @@ -1,5 +1,17 @@ +func inc + set arg0 (arg0 + 1) + ret arg0 +end + set a 0 do - put a - set a (a+1) -while (a<5) + inc a > a + if ((a % 9) == 0) + put a + end +while (a < 100) + +if (a == 100) + put "All good!" +end + diff --git a/shell.c b/shell.c index 751ef8f..0c0c4df 100644 --- a/shell.c +++ b/shell.c @@ -1,5 +1,7 @@ #include +#include "stack.h" + #include #include #include diff --git a/shelpers.c b/shelpers.c new file mode 100644 index 0000000..0d2da24 --- /dev/null +++ b/shelpers.c @@ -0,0 +1,63 @@ +#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); + 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 new file mode 100644 index 0000000..7f2ad63 --- /dev/null +++ b/shelpers.h @@ -0,0 +1,62 @@ +#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 new file mode 100644 index 0000000..d970bc2 --- /dev/null +++ b/stack.c @@ -0,0 +1,46 @@ +#include "stack.h" + +void ipush(interpreter *it, void *v) +{ + it->stack[it->stidx++] = v; +} + +void *ipop(interpreter *it) +{ + return it->stack[--it->stidx]; +} + +void ipopm(interpreter *it, uint32_t count) +{ + it->stidx -= count; +} + +variable *igetarg(interpreter *interp, uint32_t index) +{ + return interp->stack[interp->stidx - index - 1]; +} + +char *igetarg_string(interpreter *interp, uint32_t index) +{ + if (index >= interp->stidx) + return 0; + variable *v = igetarg(interp, index); + return v->svalue; +} + +int igetarg_integer(interpreter *interp, uint32_t index) +{ + if (index >= interp->stidx) + return 0; + variable *v = igetarg(interp, index); + return INT(itoint(v)); +} + +float igetarg_float(interpreter *interp, uint32_t index) +{ + if (index >= interp->stidx) + return 0; + variable *v = igetarg(interp, index); + return FLOAT(itofloat(v)); +} + diff --git a/stack.h b/stack.h new file mode 100644 index 0000000..d5a7f96 --- /dev/null +++ b/stack.h @@ -0,0 +1,15 @@ +#ifndef STACK_H_ +#define STACK_H_ + +#include "parser.h" + +void ipush(interpreter *it, void *v); +void *ipop(interpreter *it); +void ipopm(interpreter *it, uint32_t count); +variable *igetarg(interpreter *interp, uint32_t index); +char *igetarg_string(interpreter *interp, uint32_t index); +int igetarg_integer(interpreter *interp, uint32_t index); +float igetarg_float(interpreter *interp, uint32_t index); + + +#endif // STACK_H_ diff --git a/variable.c b/variable.c new file mode 100644 index 0000000..727ca0c --- /dev/null +++ b/variable.c @@ -0,0 +1,71 @@ +#include "variable.h" +#include "parser.h" + +#include +#include + +extern char *str_undef; + +void fsetstr(variable *f) +{ + if (f->svalue == 0 || f->svalue == str_undef) + f->svalue = (char *)malloc(16); + snprintf(f->svalue, 16, "%f", FLOAT(f)); +} + +void isetstr(variable *i) +{ + if (i->svalue == 0 || i->svalue == str_undef) + i->svalue = (char *)malloc(12); + snprintf(i->svalue, 12, "%d", INT(i)); +} + +variable *itostring(variable *v) +{ + switch (v->valtype) { + case INTEGER: + v->valtype = STRING; + isetstr(v); + break; + case FLOAT: + v->valtype = STRING; + fsetstr(v); + break; + } + return v; +} + +variable *itoint(variable *v) +{ + switch (v->valtype) { + case STRING: + v->valtype = INTEGER; + INT(v) = atoi(v->svalue); + isetstr(v); + break; + case FLOAT: + v->valtype = INTEGER; + INT(v) = (int32_t)FLOAT(v); + isetstr(v); + break; + } + return v; +} + +variable *itofloat(variable *v) +{ + switch (v->valtype) { + case STRING: + v->valtype = FLOAT; + FLOAT(v) = strtof(v->svalue, 0); + fsetstr(v); + break; + case INTEGER: + v->valtype = FLOAT; + FLOAT(v) = (float)INT(v); + fsetstr(v); + break; + } + return v; +} + diff --git a/variable.h b/variable.h index 067ce13..82c6b25 100644 --- a/variable.h +++ b/variable.h @@ -3,6 +3,9 @@ #include +#define INT(v) (*((int32_t *)&v->value)) +#define FLOAT(v) (*((float *)&v->value)) + typedef struct { uint8_t used :1; uint8_t fromc :1; @@ -18,4 +21,11 @@ enum valtype { FUNC }; +void isetstr(variable *i); +void fsetstr(variable *f); + +variable *itostring(variable *v); +variable *itoint(variable *v); +variable *itofloat(variable *v); + #endif // VARIABLE_H_