diff --git a/.gitignore b/.gitignore index 6a2f0f7..fc79a9e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ shell *.o +libinterp.a diff --git a/Makefile b/Makefile index f81b589..1d66f11 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ -CC = gcc -m32 +#CC = gcc -m32 +#AR = ar +CC = arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsigned-char +AR = arm-none-eabi-ar -CFLAGS = -Wall -Wextra -Wno-strict-aliasing -I. -ggdb -fno-builtin +CFLAGS = -Wall -Wextra -I. -fno-builtin -ggdb all: $(CC) $(CFLAGS) -c shelpers.c @@ -9,4 +12,6 @@ all: $(CC) $(CFLAGS) -c stack.c $(CC) $(CFLAGS) -c ops.c $(CC) $(CFLAGS) -c variable.c - $(CC) $(CFLAGS) shell.c *.o -o shell + $(AR) r libinterp.a *.o + @rm -f *.o + #$(CC) $(CFLAGS) shell.c -o shell -L. -l interp diff --git a/builtins.c b/builtins.c index cda7a93..c77c8b9 100644 --- a/builtins.c +++ b/builtins.c @@ -1,7 +1,11 @@ #include "builtins.h" #include "stack.h" +#include "shelpers.h" + +#include extern char *str_func; +extern char *str_undef; int ifunc_set(interpreter *it); int ifunc_label(interpreter *it); @@ -11,6 +15,14 @@ int ifunc_do(interpreter *it); int ifunc_while(interpreter *it); int ifunc_ret(interpreter *it); +const func_t indent_up[IUP_COUNT] = { + ifunc_if, ifunc_do, ifunc_label +}; + +const func_t indent_down[IDOWN_COUNT] = { + ifunc_end, ifunc_while +}; + void iload_core(interpreter *interp) { inew_cfunc(interp, "set", ifunc_set); @@ -32,7 +44,9 @@ int ifunc_set(interpreter *it) n->valtype = v->valtype; n->value = v->value; - n->svalue = v->svalue; + if (n->svalue != 0 && n->svalue != str_func && n->svalue != str_undef) + free(n->svalue); + n->svalue = strclone(v->svalue); return 0; } @@ -46,25 +60,26 @@ int ifunc_label(interpreter *it) n->valtype = FUNC; n->value = it->lnidx; n->svalue = str_func; - it->indent++; + iskip(it); 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); - } + if (v == 0) + iskip(it); + void *tmp = ipop(it); + ipush(it, (void *)-1); + ipush(it, tmp); return 0; } int ifunc_end(interpreter *it) { + if (it->stidx == 0) + return 0; + uint32_t lnidx = (uint32_t)ipop(it) + 1; if (lnidx != 0) it->lnidx = lnidx; @@ -83,8 +98,8 @@ int ifunc_while(interpreter *it) ipop(it); int nidx = (int)ipop(it); if (c != 0) { - ipush(it, (void *)nidx); - it->lnidx = nidx; + //ipush(it, (void *)nidx); + it->lnidx = nidx - 1; } ipush(it, 0); return 0; diff --git a/builtins.h b/builtins.h index 8739778..91c6e8c 100644 --- a/builtins.h +++ b/builtins.h @@ -3,6 +3,12 @@ #include "parser.h" +#define IUP_COUNT 3 +#define IDOWN_COUNT 2 + void iload_core(interpreter *it); +const func_t indent_up[IUP_COUNT]; +const func_t indent_down[IDOWN_COUNT]; + #endif // BUILTINS_H_ diff --git a/parser.c b/parser.c index ac739a0..b100123 100644 --- a/parser.c +++ b/parser.c @@ -7,6 +7,7 @@ #include #include +#include #include #define MAX_VARS 48 @@ -24,9 +25,10 @@ void iinit(interpreter *interp) 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(MAX_LINES, sizeof(char *)); + interp->lines = (variable ***)malloc(MAX_LINES * sizeof(variable **)); interp->lnidx = 0; interp->indent = 0; + interp->sindent = 0; for (unsigned int i = 0; i < MAX_VARS; i++) { interp->vars[i].used = 0; @@ -38,6 +40,30 @@ void iinit(interpreter *interp) iload_core(interp); } +void iend(interpreter *it) +{ + for (unsigned int i = 0; i < MAX_VARS; i++) { + if (it->vars[i].used == 1) { + char *s = it->vars[i].svalue; + if (s != 0 && s != str_undef && s != str_func) + free(s); + free(it->vnames[i]); + } + } + for (unsigned int i = 0; i < MAX_LINES; i++) + free(it->lines[i]); + free(it->vars); + free(it->vnames); + free(it->stack); + free(it->lines); +} + +void iskip(interpreter *it) +{ + if (!(it->sindent & SKIP)) + it->sindent = it->indent | SKIP; +} + variable *interpreter_get_variable(interpreter *interp, const char *name) { for (uint32_t i = 0; i < MAX_VARS; i++) { @@ -66,7 +92,7 @@ char *interpreter_get_name(interpreter *interp, variable *v) return str_undef; } -void inew_string(interpreter *interp, const char *name, char *value) +variable *inew_string(interpreter *interp, const char *name, char *value) { variable *v = interpreter_get_variable(interp, name); if (v != 0) { @@ -74,9 +100,10 @@ void inew_string(interpreter *interp, const char *name, char *value) INT(v) = 0; v->svalue = strclone(value); } + return v; } -void inew_integer(interpreter *interp, const char *name, int32_t value) +variable *inew_integer(interpreter *interp, const char *name, int32_t value) { variable *v = interpreter_get_variable(interp, name); if (v != 0) { @@ -84,9 +111,10 @@ void inew_integer(interpreter *interp, const char *name, int32_t value) INT(v) = value; isetstr(v); } + return v; } -void inew_float(interpreter *interp, const char *name, float value) +variable *inew_float(interpreter *interp, const char *name, float value) { variable *v = interpreter_get_variable(interp, name); if (v != 0) { @@ -94,6 +122,7 @@ void inew_float(interpreter *interp, const char *name, float value) FLOAT(v) = value; fsetstr(v); } + return v; } void inew_cfunc(interpreter *interp, const char *name, func_t func) @@ -116,12 +145,8 @@ variable *make_var(interpreter *interp, const char *line, uint32_t *next) if (!eot(line[end + 1])) return 0; // TODO string breakdown - variable *v = (variable *)malloc(sizeof(variable)); - v->used = 0; - v->valtype = STRING; - v->svalue = strnclone(line + 1, end - 1); *next = end + 1; - return v; + return vmake(0, STRING, strnclone(line + 1, end - 1)); } end++; } @@ -131,7 +156,8 @@ variable *make_var(interpreter *interp, const char *line, uint32_t *next) if (eot(line[end])) return 0; *next = end + 1; - return idoexpr(interp, line + 1); + return vmake(0, EXPR, strnclone(line + 1, end)); + //return idoexpr(interp, line + 1); } else if (isalpha(line[0])) { // variable/func uint32_t end = 1; for (; isalnum(line[end]); end++); @@ -141,7 +167,9 @@ variable *make_var(interpreter *interp, const char *line, uint32_t *next) strncpy(name, line, end); name[end] = '\0'; *next = end; - return interpreter_get_variable(interp, name); + variable *v = interpreter_get_variable(interp, name); + free(name); + return v; } else if (isdigit(line[0])) { // number uint32_t end = 1; uint8_t dec = 0; @@ -157,17 +185,11 @@ variable *make_var(interpreter *interp, const char *line, uint32_t *next) } } } - variable *v = (variable *)malloc(sizeof(variable)); - v->used = 0; + variable *v; if (dec) { - v->valtype = FLOAT; - FLOAT(v) = strtof(line, 0); - fsetstr(v); - } else { - v->valtype = INTEGER; - INT(v) = atoi(line); - isetstr(v); - } + v = vmakef(strtof(line, 0)); + } else + v = vmake(0, INTEGER, (void *)atoi(line)); *next = end; return v; } @@ -176,39 +198,34 @@ variable *make_var(interpreter *interp, const char *line, uint32_t *next) int idoline(interpreter *interp, const char *line) { - variable *ops[8]; - uint32_t ooffset, offset, next; + uint32_t ooffset = 0, offset = 0, next; + int fret = 0; if (line[0] == '\0') return 0; - - interp->lines[interp->lnidx] = strclone(line); -loop: - ooffset = 0; - offset = 0; skipblank(line, eol, &offset); + if (line[offset] == '#') + return 0; - if (line[offset] == '#') { - goto norun; - } else if (interp->indent > 0) { - if (!strcmp(line + offset, "end")) - interp->indent--; - goto norun; - } + interp->lines[interp->lnidx] = (variable **)calloc(8, sizeof(variable *)); + 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); - interp->ret = make_var(interp, line + offset, &next); + variable *r = make_var(interp, line + offset, &next); + ops[ooffset] = (void *)-1; + ops[ooffset + 1] = r; offset += next; skipblank(line, eol, &offset); continue; } ops[ooffset] = make_var(interp, line + offset, &next); if (ops[ooffset] == 0) { - return -4; + fret = -4; + goto fail; } else { ooffset++; offset += next; @@ -217,14 +234,61 @@ loop: } // step 2 - execute - if (ooffset == 0) - return -1; + if (ooffset == 0) { + fret = -1; + goto fail; + } + + if (ops[0]->valtype != FUNC) { + fret = -2; + goto fail; + } - if (ops[0]->valtype != FUNC) - return -2; + if (ops[0]->fromc && ops[0]->value == 0) { + fret = -3; + goto fail; + } - if (ops[0]->fromc && ops[0]->value == 0) - return -3; + if (ops[ooffset] != (void *)-1) + ops[ooffset] = 0; + +loop: + for (uint8_t i = 0; i < IUP_COUNT; i++) { + if (interp->lines[interp->lnidx][0]->value + == (uint32_t)indent_up[i]) { + interp->indent++; + goto cont; + } + } + for (uint8_t i = 0; i < IDOWN_COUNT; i++) { + if (interp->lines[interp->lnidx][0]->value + == (uint32_t)indent_down[i]) { + if (--interp->indent < 0) { + fret = -6; + goto fail; + } + 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 *)); + memcpy(ops, interp->lines[interp->lnidx], 8 * sizeof(variable *)); + uint32_t oldLnidx = interp->lnidx; + + // eval expressions + ooffset = 1; + for (; ops[ooffset] != 0 && ops[ooffset] != (void *)-1; ooffset++) { + if (ops[ooffset]->valtype == EXPR) + ops[ooffset] = idoexpr(interp, ops[ooffset]->svalue); + } if (ops[0]->fromc) { for (uint32_t i = ooffset; --i > 0;) @@ -237,7 +301,7 @@ loop: } else { char an[6]; for (uint32_t i = 1; i < ooffset; i++) { - snprintf(an, 6, "arg%d", i - 1); + snprintf(an, 6, "arg%d", (int)(i - 1)); switch (ops[i]->valtype) { case STRING: inew_string(interp, an, ops[i]->svalue); @@ -255,26 +319,35 @@ loop: ipush(interp, (void *)(interp->lnidx)); interp->lnidx = ops[0]->value; + interp->indent++; } + if (ops[ooffset] == (void *)-1) + interp->ret = ops[ooffset + 1]; + if ((int32_t)interp->stidx < 0) { interp->stidx = 0; return -5; } - for (uint32_t i = 0; i < ooffset; i++) { - if (!ops[i]->used) + for (uint32_t i = 1; i < ooffset; i++) { + if (ops[i] != interp->lines[oldLnidx][i]) { + free(ops[i]->svalue); free(ops[i]); + } } - + free(ops); norun: interp->lnidx++; - if (interp->lines[interp->lnidx] != 0) { - line = interp->lines[interp->lnidx]; + if (interp->lines[interp->lnidx] != 0) goto loop; - } return 0; + +fail: + free(interp->lines[interp->lnidx]); + interp->lines[interp->lnidx] = 0; + return fret; } variable *idoexpr(interpreter *interp, const char *line) @@ -359,10 +432,16 @@ variable *idoexpr(interpreter *interp, const char *line) } for (uint32_t i = 0; i < ooffset; i += 2) { - if (!((variable *)ops[i])->used) + if (!((variable *)ops[i])->used) { + char *s = ((variable *)ops[i])->svalue; + if (s != 0 && s != str_undef) + free(s); free(ops[i]); + } } - + + result->used = 0; + result->svalue = 0; if (result->valtype == INTEGER) isetstr(result); else diff --git a/parser.h b/parser.h index 4e4699e..92a8eb3 100644 --- a/parser.h +++ b/parser.h @@ -10,19 +10,25 @@ typedef struct { char **vnames; stack_t *stack; uint32_t stidx; - char **lines; + variable ***lines; uint32_t lnidx; - uint8_t indent; + int8_t indent; + uint8_t sindent; variable *ret; } interpreter; +#define SKIP (1 << 7) + typedef int (*func_t)(interpreter *); void iinit(interpreter *); +void iend(interpreter *it); + +void iskip(interpreter *it); -void inew_string(interpreter *, const char *, char *); -void inew_integer(interpreter *, const char *, int32_t); -void inew_float(interpreter *, const char *, float); +variable *inew_string(interpreter *, const char *, char *); +variable *inew_integer(interpreter *, const char *, int32_t); +variable *inew_float(interpreter *, const char *, float); void inew_cfunc(interpreter *, const char *, func_t); int idoline(interpreter *, const char *); diff --git a/script b/script index 3b807a2..dac7da5 100644 --- a/script +++ b/script @@ -1,17 +1,18 @@ -func inc - set arg0 (arg0 + 1) - ret arg0 +func divisible + if (arg1 == 0) + ret 0 + end + ret (arg0 % arg1) end set a 0 +set b 4 do - inc a > a - if ((a % 9) == 0) - put a + set a (a + 1) + divisible a b > i + if (i == 0) + print a end while (a < 100) -if (a == 100) - put "All good!" -end - +print "All done!" diff --git a/shell.c b/shell.c index 0c0c4df..c63b1bc 100644 --- a/shell.c +++ b/shell.c @@ -59,7 +59,7 @@ int main(int argc, char **argv) } iinit(&interp); - inew_cfunc(&interp, "put", s_put); + inew_cfunc(&interp, "print", s_put); inew_cfunc(&interp, "tp", s_type); inew_cfunc(&interp, "q", quit); @@ -75,5 +75,6 @@ int main(int argc, char **argv) } fclose(fp); + iend(&interp); return 0; } diff --git a/shelpers.c b/shelpers.c index 0d2da24..fbde4ab 100644 --- a/shelpers.c +++ b/shelpers.c @@ -14,6 +14,7 @@ char *strnclone(const char *s, uint32_t n) { char *clone = (char *)malloc(n + 1); strncpy(clone, s, n); + clone[n] = '\0'; return clone; } diff --git a/variable.c b/variable.c index 727ca0c..620a4b6 100644 --- a/variable.c +++ b/variable.c @@ -5,6 +5,47 @@ #include extern char *str_undef; +extern char *str_func; + +variable *vmake(uint8_t fromc, uint8_t valtype, void *value) +{ + variable *v = (variable *)malloc(sizeof(variable)); + v->used = 0; + v->fromc = fromc; + v->valtype = valtype; + v->value = 0; + v->svalue = 0; + switch (valtype) { + case STRING: + v->value = 0; + v->svalue = value; + break; + case INTEGER: + INT(v) = (int32_t)value; + isetstr(v); + break; + case FUNC: + v->value = (uint32_t)value; + v->svalue = str_func; + break; + case EXPR: + v->value = 0; + v->svalue = value; + break; + } + return v; +} + +variable *vmakef(float value) +{ + variable *v = (variable *)malloc(sizeof(variable)); + v->used = 0; + v->fromc = 0; + v->valtype = FLOAT; + FLOAT(v) = value; + fsetstr(v); + return v; +} void fsetstr(variable *f) { @@ -17,7 +58,7 @@ void isetstr(variable *i) { if (i->svalue == 0 || i->svalue == str_undef) i->svalue = (char *)malloc(12); - snprintf(i->svalue, 12, "%d", INT(i)); + snprintf(i->svalue, 12, "%d", (int)INT(i)); } variable *itostring(variable *v) diff --git a/variable.h b/variable.h index 82c6b25..e5aa20c 100644 --- a/variable.h +++ b/variable.h @@ -9,7 +9,7 @@ typedef struct { uint8_t used :1; uint8_t fromc :1; - uint8_t valtype :2; + uint8_t valtype :4; uint32_t value; char *svalue; } variable; @@ -18,9 +18,13 @@ enum valtype { STRING = 0, INTEGER, FLOAT, - FUNC + FUNC, + EXPR }; +variable *vmake(uint8_t fromc, uint8_t valtype, void *value); +variable *vmakef(float value); + void isetstr(variable *i); void fsetstr(variable *f);