diff options
author | Clyne Sullivan <tullivan99@gmail.com> | 2018-03-21 12:29:09 -0400 |
---|---|---|
committer | Clyne Sullivan <tullivan99@gmail.com> | 2018-03-21 12:29:09 -0400 |
commit | 140a0bbecc144e554c1954f594a9f0d0b2276e9c (patch) | |
tree | f2c4d0223b8659e259d5efa0a98f99a4a54264aa /parser.c | |
parent | 28447df15ac80d7dad1f4889d3d61fe7bfe42a12 (diff) |
interpreter overhaul, should be better
Diffstat (limited to 'parser.c')
-rw-r--r-- | parser.c | 780 |
1 files changed, 394 insertions, 386 deletions
@@ -1,478 +1,486 @@ -#include <parser.h> +#include "parser.h" -#include "shelpers.h" #include "builtins.h" -#include "stack.h" #include "ops.h" #include <ctype.h> #include <stdlib.h> -#include <memory.h> +#include <stdio.h> #include <string.h> -#define MAX_VARS 100 -#define MAX_STACK 32 +#define MAX_VARS 256 +#define MAX_STACK 64 #define MAX_LINES 1000 -void iinit(interpreter *interp) +char *strnclone(const char *s, size_t c) { - interp->vars = (variable *)calloc(MAX_VARS, sizeof(variable)); - interp->vnames = (char **)calloc(MAX_VARS, sizeof(char *)); - interp->stack = (stack_t *)calloc(MAX_STACK, sizeof(stack_t)); - interp->stidx = 0; - interp->lines = (variable ***)calloc(MAX_LINES, sizeof(variable **)); - interp->lnidx = 0; - interp->indent = 0; - interp->sindent = 0; - interp->ret = 0; - - iload_core(interp); + char *b = strncpy((char *)malloc(c + 1), s, c); + b[c] = '\0'; + return b; } - -void iend(interpreter *it) +char *strclone(const char *s) { - for (unsigned int i = 0; i < MAX_VARS; i++) { - if (it->vars[i].used == 1) { - if (it->vars[i].valtype == STRING || - it->vars[i].valtype == EXPR) - free((void *)it->vars[i].value.p); - free(it->vnames[i]); - } - } - for (unsigned int i = 0; i < MAX_LINES; i++) { - if (it->lines[i] != 0) { - for (unsigned int j = 0; (int32_t)it->lines[i][j] > 0; j++) { - switch (it->lines[i][j]->valtype) { - case STRING: - if (!it->lines[i][j]->used) - free(it->lines[i][j]); - break; - case EXPR: - free((void *)it->lines[i][j]->value.p); - free(it->lines[i][j]); - break; - case NUMBER: - if (!it->lines[i][j]->used) - free(it->lines[i][j]); - break; - } - } + return strnclone(s, strlen(s)); +} +char *fixstring(const char *s) +{ + char *n = malloc(strlen(s) + 1 - 2); + int j = 0; + for (int i = 1; s[i] != '\"'; i++, j++) { + if (s[i] == '\\') { + if (s[i + 1] == 'n') + n[j] = '\n'; + i++; + } else { + n[j] = s[i]; } - free(it->lines[i]); } + n[j] = '\0'; + return n; +} + +void itryfree(variable *v) +{ + if (v == 0 || v->tmp == 0) + return; + if (v->type == STRING) + free((void *)v->value.p); + free(v); +} + +instance *inewinstance(void) +{ + instance *it = (instance *)malloc(sizeof(instance)); + it->vars = (variable *)calloc(MAX_VARS, sizeof(variable)); + it->names = (char **)calloc(MAX_VARS, sizeof(char *)); + it->stack = (uint32_t *)malloc(MAX_STACK * sizeof(uint32_t)); + it->stidx = 0; + it->lines = (char **)calloc(MAX_LINES, sizeof(char *)); + it->lnidx = 0; + it->ret = 0; + it->indent = 0; + it->sindent = 0; + + iload_builtins(it); + return it; +} + +void idelinstance(instance *it) +{ free(it->vars); - free(it->vnames); + for (uint32_t i = 0; i < MAX_VARS; i++) + free(it->names[i]); + free(it->names); free(it->stack); + for (uint32_t i = 0; i < MAX_VARS; i++) + free(it->lines[i]); free(it->lines); + itryfree(it->ret); + free(it); } -void iskip(interpreter *it) +void ipush(instance *it, uint32_t v) { - if (!(it->sindent & SKIP)) - it->sindent = it->indent | SKIP; + it->stack[it->stidx++] = v; } -variable *interpreter_get_variable(interpreter *interp, const char *name) +uint32_t ipop(instance *it) { - for (uint32_t i = 0; i < MAX_VARS; i++) { - if (!interp->vars[i].used) { - variable *v = make_vars(&interp->vars[i], 0); - v->used = 1; - interp->vnames[i] = strclone(name); - return v; - } else if (interp->vnames[i] != 0 && !strcmp(interp->vnames[i], name)) { - return &interp->vars[i]; - } - } - return 0; + return it->stack[--it->stidx]; } -char *interpreter_get_name(interpreter *interp, variable *v) +void ipopm(instance *it, uint32_t count) { - for (uint32_t i = 0; i < MAX_VARS; i++) { - if (v == &interp->vars[i]) - return interp->vnames[i]; - } - return "(undefined)"; + it->stidx -= count; } -variable *inew_string(interpreter *interp, const char *name, const char *value) +variable *igetarg(instance *it, uint32_t n) { - variable *v = interpreter_get_variable(interp, name); - if (v != 0) { - if (v->valtype == STRING && v->value.p != 0) - free((void *)v->value.p); - v->valtype = STRING; - v->value.p = (uint32_t)strclone(value); - } - return v; + return (variable *)it->stack[it->stidx - n - 1]; } -variable *inew_number(interpreter *interp, const char *name, float value) +variable *igetvar(instance *it, const char *name); +void inew_cfunc(instance *it, const char *name, func_t func) { - variable *v = interpreter_get_variable(interp, name); - if (v != 0) { - v->valtype = NUMBER; - v->value.f = value; - } + variable *v = igetvar(it, name); + v->type = CFUNC; + v->value.p = (uint32_t)func; +} + +void inew_number(instance *it, const char *name, float f) +{ + variable *v = igetvar(it, name); + v->type = NUMBER; + v->value.f = f; +} + +void inew_string(instance *it, const char *name, const char *s) +{ + variable *v = igetvar(it, name); + v->type = STRING; + v->value.p = (uint32_t)strclone(s); +} + +variable *varclone(variable *n) +{ + variable *v = (variable *)malloc(sizeof(variable)); + v->tmp = 1; + v->type = n->type; + if (n->type == STRING) + v->value.p = (uint32_t)strclone((char *)n->value.p); + else + v->value.p = n->value.p; return v; } -variable *inew_cfunc(interpreter *interp, const char *name, func_t func) +variable *make_varf(variable *v, float f) { - variable *v = interpreter_get_variable(interp, name); - if (v != 0) { - v->fromc = 1; - v->valtype = FUNC; - v->value.p = (uint32_t)func; + if (v == 0) { + v = (variable *)malloc(sizeof(variable)); + v->tmp = 1; } + v->type = NUMBER; + v->value.f = f; return v; } -variable *make_var(interpreter *interp, const char *line, uint32_t *next) +variable *make_vars(variable *v, const char *s) { - if (line[0] == '\"') { // string literal - uint32_t end = 1; - while (!eol(line[end])) { - if (line[end] == '\"'/* && line[end - 1] != '\\'*/) { - if (!eot(line[end + 1])) - return 0; - // TODO string breakdown - *next = end + 1; - char *str = strnclone(line + 1, end - 1); - variable *v = make_vars(0, str); - free(str); - return v; - } - end++; - } - return 0; - } else if (line[0] == '(') { // equation literal - uint32_t end = findend(line, '(', ')'); - if (eot(line[end])) - return 0; - *next = end + 1; - char *expr = strnclone(line + 1, end); - variable *v = make_vare(0, expr); - free(expr); - return v; - } else { - variable *v = make_varn(0, 0.0f); - int inc = try_number(v, line); - if (inc != 0) { - *next = inc; - return v; - } - free(v); - char *name = 0; - inc = try_variable(&name, line); - if (inc != 0) { - *next = (inc > 0) ? inc : -inc; - variable *v = interpreter_get_variable(interp, name); - free(name); - return v; - } + if (v == 0) { + v = (variable *)malloc(sizeof(variable)); + v->tmp = 1; } - return 0; + v->type = STRING; + v->value.p = (uint32_t)strclone(s); + return v; } -int idoline(interpreter *interp, const char *line) +variable *make_num(const char *text) { - uint32_t ooffset = 0, offset = 0, next; - int fret = 0; - - if (line[0] == '\0') - return 0; - skipblank(line, eol, &offset); - if (line[offset] == '#' || eol(line[offset])) - return 0; - - variable **linebuf = (variable **)calloc(8, sizeof(variable *)); - interp->lines[interp->lnidx] = linebuf; - variable **ops = interp->lines[interp->lnidx]; - - // step 1 - convert to tokens - while (!eol(line[offset])) { - if (offset > 0 && line[offset] == '>') { - offset++; - skipblank(line, eol, &offset); - variable *r = make_var(interp, line + offset, &next); - ops[ooffset] = (void *)-1; - ops[ooffset + 1] = r; - offset += next; - skipblank(line, eol, &offset); - continue; - } - variable *v = make_var(interp, line + offset, &next); - ops[ooffset] = v; - if (ops[ooffset] == 0) { - fret = -4; - goto fail; + int decimal = -1; + char valid = 0; + + int i = 0; + if (text[0] == '-') + i++; + do { + if (text[i] == '.') { + if (decimal >= 0) { + valid = 0; + break; + } + decimal = i; + } else if (isdigit(text[i])) { + valid |= 1; } else { - ooffset++; - offset += next; + break; } - skipblank(line, eol, &offset); - } + } while (text[++i] != '\0'); - // step 2 - execute - if (ooffset == 0) { - fret = -1; - goto fail; - } - - if (ops[0]->valtype != FUNC) { - fret = -2; - goto fail; - } + if (valid == 0) + return 0; - if (ops[0]->fromc && ops[0]->value.p == 0) { - fret = -3; - goto fail; - } + char *buf = (char *)malloc(i + 1); + strncpy(buf, text, i); + buf[i] = '\0'; - if (ops[ooffset] != (void *)-1) - ops[ooffset] = 0; + variable *v = make_varf(0, strtof(buf, 0)); + free(buf); + return v; +} -loop: - for (uint8_t i = 0; i < IUP_COUNT; i++) { - if (interp->lines[interp->lnidx][0]->value.p - == (uint32_t)indent_up[i]) { - interp->indent++; - goto cont; +variable *igetop(instance *it, const char *name) +{ + for (uint32_t i = 0; i < OPS_COUNT; i++) { + if (opnames[i] != 0 && !strcmp(name, opnames[i])) { + return &opvars[i]; } } - for (uint8_t i = 0; i < IDOWN_COUNT; i++) { - if (interp->lines[interp->lnidx][0]->value.p - == (uint32_t)indent_down[i]) { - if (--interp->indent < 0) { - fret = -6; - goto fail; + return 0; +} +variable *igetvar(instance *it, const char *name) +{ + if (isalpha(name[0])) { + for (uint32_t i = 0; i < MAX_VARS; i++) { + if (it->names[i] == 0) { + it->names[i] = strclone(name); + // default to 0 float + return make_varf(&it->vars[i], 0.0f); + } else if (!strcmp(name, it->names[i])) { + return &it->vars[i]; } - if (interp->indent < (interp->sindent & ~(SKIP))) - interp->sindent &= ~(SKIP); - else - goto cont; - break; } } -cont: - if (interp->indent > 0 && interp->sindent & SKIP) - goto norun; - - ops = (variable **)malloc(8 * sizeof(variable *)); - for (uint8_t i = 0; i < 8; i++) - ops[i] = interp->lines[interp->lnidx][i]; - uint32_t oldLnidx = interp->lnidx; - - // eval expressions - ooffset = 1; - for (; ops[ooffset] != 0 && ops[ooffset] != (void *)-1; ooffset++) { - if (ops[ooffset]->valtype == EXPR) { - char *expr = strclone((char *)ops[ooffset]->value.p); - variable *r = idoexpr(interp, expr); - ops[ooffset] = r; - free(expr); - } - } + return igetop(it, name); +} - if (ops[ooffset] == (void *)-1) - interp->ret = ops[ooffset + 1]; - - if (ops[0]->fromc) { - for (uint32_t i = ooffset; --i > 0;) - ipush(interp, ops[i]); - - int ret = ((func_t)ops[0]->value.p)(interp); - if (ret != 0) - return ret; - ipopm(interp, ooffset - 1); - } else { - char an[6]; - for (uint32_t i = 1; i < ooffset; i++) { - snprintf(an, 6, "arg%d", (int)(i - 1)); - switch (ops[i]->valtype) { - case STRING: - inew_string(interp, an, (char *)ops[i]->value.p); - break; - case NUMBER: - inew_number(interp, an, ops[i]->value.f); - break; - default: - break; - } - } +int idoline(instance *it, const char *s) +{ + it->lines[it->lnidx] = strclone(s); + variable **ops; +loop: + ops = iparse(it, it->lines[it->lnidx]); - ipush(interp, (void *)(uint32_t)interp->indent); - ipush(interp, (void *)interp->lnidx); - ipush(interp, (void *)-2); // magic - interp->lnidx = ops[0]->value.p; - interp->indent++; - } + if (it->ret != 0) + itryfree(it->ret); + it->ret = 0; - if ((int32_t)interp->stidx < 0) { - interp->stidx = 0; - return -5; - } + if (ops == 0) + goto next; + it->ret = isolve(it, ops, 0); - for (uint32_t i = 1; i < ooffset; i++) { - if (ops[i] != interp->lines[oldLnidx][i]) { - if (ops[i]->valtype == STRING || ops[i]->valtype == EXPR) - free((void *)ops[i]->value.p); - free(ops[i]); - } - } +next: free(ops); -norun: - interp->lnidx++; - if (interp->lines[interp->lnidx] != 0) + it->lnidx++; + if (it->lines[it->lnidx] != 0) goto loop; return 0; +} + +variable *isolve_(instance *it, variable **ops, uint32_t count); +variable *isolve(instance *it, variable **ops, uint32_t count) +{ + if (count == 0) + for (count = 0; ops[count] != 0; count++); + + for (uint32_t i = 0; i < count; i++) { + if (((uint32_t)ops[i] & OP_MAGIC) == OP_MAGIC) { + uint32_t count_ = (uint32_t)ops[i] & 0xFF; + ops[i] = isolve(it, ops + i + 1, count_); + for (uint32_t j = 1; j <= count_; j++) + ops[i + j] = 0; + } + } -fail: - free(interp->lines[interp->lnidx]); - interp->lines[interp->lnidx] = 0; - return fret; + return isolve_(it, ops, count); } -variable *idoexpr(interpreter *interp, const char *line) +variable *isolve_(instance *it, variable **ops, uint32_t count) { - void *ops[16]; - uint32_t ooffset = 0; - uint32_t offset = 0; - - // step 1 - break apart line - for (uint8_t i = 0; i < 16; i++) - ops[i] = 0; - - // skip whitespace - skipblank(line, eol, &offset); - while (!eoe(line[offset])) { - if (line[offset] == '(') { - uint8_t indent = 0; - uint32_t i; - for (i = offset + 1; !eol(line[i]); i++) { - if (line[i] == '(') { - indent++; - } else if (line[i] == ')') { - if (indent == 0) { - break; + // first, look for functions + for (uint32_t i = 0; i < count; i++) { + if (ops[i] == 0) + continue; + if (ops[i]->type == CFUNC || ops[i]->type == FUNC) { + uint32_t nargs = (uint32_t)ops[i + 1]; + uint32_t start = i; + i += 2; + int32_t j; + for (j = nargs; j > 0 && i < count; i++) { + if (ops[i] != 0) { + if (ops[start]->type == CFUNC) { + it->stack[it->stidx + j - 1] = (uint32_t)ops[i]; } else { - indent--; - } + char namebuf[6]; + snprintf(namebuf, 6, "arg%d", nargs - j); + if (ops[i]->type == NUMBER) + inew_number(it, namebuf, ops[i]->value.f); + else + inew_string(it, namebuf, + (const char *)ops[i]->value.p); + } + j--; } } - if (eol(line[i])) + if (j != 0) return 0; - ops[ooffset] = idoexpr(interp, line + offset + 1); - offset = i + 1; - } else { - variable *v = make_varn(0, 0.0f); - int inc = try_number(v, line + offset); - if (inc != 0) { - ops[ooffset] = v; - offset += inc; - } else { - free(v); - char *name; - inc = try_variable(&name, line + offset); - if (inc != 0) { - v = interpreter_get_variable(interp, name); - ops[ooffset] = v; - free(name); - if (inc < 0) { - inc = -inc; - ops[ooffset + 2] = v; - ops[ooffset + 1] = (void *)5; // - - ops[ooffset] = make_varn(0, 0.0f); - ooffset += 2; - } - offset += inc; - } else { + + if (ops[start]->type == CFUNC) { + func_t func = (func_t)ops[start]->value.p; + it->stidx += nargs; + + uint32_t sidx = it->stidx; + int ret = 0; + if (!(it->sindent & SKIP)) + ret = func(it); + if (ret != 0) return 0; - } + if (it->stidx > sidx) + ops[start] = (variable *)ipop(it); + else + ops[start] = 0; + ipopm(it, nargs); + } else { + ipush(it, it->lnidx); + ipush(it, CALL_SIG); + it->lnidx = ops[start]->value.p; + } + + ops[start + 1] = 0; + for (uint32_t j = start + 2; j < i; j++) { + itryfree(ops[j]); + ops[j] = 0; } } + } - if (ops[ooffset] == 0) - return 0; - - ooffset++; + // next, operators + for (uint32_t j = 0; j < OPS_COUNT; j += 2) { + for (uint32_t i = 0; i < count; i++) { + if (ops[i] == 0) + continue; + if (ops[i]->type == OPERATOR) { + if (ops[i]->value.p != (uint32_t)opvars[j].value.p) { + if (ops[i]->value.p != (uint32_t)opvars[j + 1].value.p) + continue; + } - // skip whitespace - skipblank(line, eoe, &offset); - if (eoe(line[offset])) - break; + opfunc_t func = (opfunc_t)ops[i]->value.p; + uint32_t aidx = i - 1; + while (ops[aidx] == 0 && aidx != 0) + aidx--; + if (ops[aidx] == 0) + return 0; + uint32_t bidx = i + 1; + while (ops[bidx] == 0 && ++bidx < count); + if (bidx == count) + return 0; - for (uint32_t i = 0; i < IOPS_COUNT; i++) { - int len = strlen(iops[i]); - if (!strncmp(iops[i], line + offset, len)) { - ops[ooffset] = (void *)(i + 1); - offset += len; - break; + if (it->sindent & SKIP) { + itryfree(ops[aidx]); + itryfree(ops[bidx]); + ops[aidx] = 0; + } else { + variable *v = varclone(ops[aidx]); + if (func(v, ops[aidx], ops[bidx]) != 0) + return 0; + itryfree(ops[aidx]); + ops[aidx] = v; + itryfree(ops[bidx]); + } + ops[i] = 0; + ops[bidx] = 0; } } + } - if (ops[ooffset] == 0) // implicit multiply - ops[ooffset] = (void *)1; + return ops[0]; +} - ooffset++; - // skip whitespace - skipblank(line, eol, &offset); - } +variable **iparse(instance *it, const char *s) +{ + uint32_t ooffset = 0; + size_t offset = 0; - if (ooffset % 2 == 0) + while (isblank(s[offset])) + offset++; + if (s[offset] == '#' || s[offset] == '\0' || s[offset] == '\n') return 0; - // step 2 - do operations - // for every operator, ordered by importance - for (uint32_t i = 0; i < IOPS_COUNT; i++) { - // find instances of the operation - for (uint32_t j = 1; j < ooffset; j += 2) { - // if a match - if ((uint32_t)ops[j] == i + 1) { - // find args - uint32_t ai = j - 1; - uint32_t bi = j + 1; - while (ops[ai] == 0) - ai--; - while (ops[bi] == 0) - bi++; - - variable *r = (variable *)calloc(1, sizeof(variable)); - iopfuncs[i](r, ops[ai], ops[bi]); - - variable *v = (variable *)ops[ai]; - if (!v->used) - free(v); - ops[ai] = r; - v = (variable *)ops[bi]; - if (!v->used) - free(v); - ops[bi] = 0; - ops[j] = 0; + variable **ops = (variable **)calloc(32, sizeof(variable *)); + while (s[offset] != '\0' && s[offset] != '\n') { + if (isalpha(s[offset])) { + size_t end = offset + 1; + while (isalnum(s[end])) + end++; + char *name = strnclone(s + offset, end - offset); + ops[ooffset++] = igetvar(it, name); + free(name); + while (isblank(s[end])) + end++; + if (s[end] == '(') { + uint32_t argidx = ooffset; + uint32_t argcount = 0; + ooffset++; + end++; + for (int last = end, c = 0; c >= 0; end++) { + if (s[end] == '(') + c++; + if (c == 0 && last != end && (s[end] == ',' || s[end] == ')')) { + argcount++; + char *arg = strnclone(s + last, end - last); + uint32_t parenidx = ooffset; + ooffset++; + variable **moreops = iparse(it, arg); + uint32_t count = 0; + if (moreops != 0) { + for (uint32_t i = 0; moreops[i] != 0; count++, i++) + ops[ooffset++] = moreops[i]; + free(moreops); + } + free(arg); + ops[parenidx] = (variable *)(OP_MAGIC | count); + last = end + 1; + } + if (s[end] == ')') + c--; + } + if (s[end] != '\0') + end++; + ops[argidx] = (variable *)argcount; + } + offset = end; + } else if (isdigit(s[offset])) { + size_t end = offset + 1; + while (isdigit(s[end]) || s[end] == '.') + end++; + char *word = strnclone(s + offset, end - offset); + ops[ooffset++] = make_num(word); + free(word); + offset = end; + } else if (s[offset] == '\"') { + size_t end = offset + 1; + while (s[end] != '\"')// && s[end - 1] == '\\') + end++; + end++; + char *word = strnclone(s + offset, end - offset); + char *fword = fixstring(word); + ops[ooffset++] = make_vars(0, fword); + free(word); + free(fword); + offset = end; + } else if (s[offset] == '(') { + size_t i = offset + 1; + for (int c = 0; s[i] != ')' || --c >= 0; i++) { + if (s[i] == '(') + c++; } + i++; + char *word = strnclone(s + offset + 1, i - offset - 2); + uint32_t parenidx = ooffset; + ooffset++; + variable **moreops = iparse(it, word); + uint32_t count = 0; + if (moreops != 0) { + for (uint32_t i = 0; moreops[i] != 0; count++, i++) + ops[ooffset++] = moreops[i]; + free(moreops); + } + free(word); + ops[parenidx] = (variable *)(OP_MAGIC | count); + offset = i; + } else if (!isblank(s[offset])) { + size_t end = offset + 1; + while (!isblank(s[end]) && s[end] != '\0') + end++; + char *word = strnclone(s + offset, end - offset); + + // bracket? + if (!strcmp(word, "{")) { + it->indent++; + if (it->sindent & SKIP) + ipush(it, SKIP_SIG); + } else if (!strcmp(word, "}")) { + it->indent--; + if (it->indent < (it->sindent & ~(SKIP))) + it->sindent = 0; + bn_end(it); + } else { + variable *v = igetop(it, word); + if (v == 0) + return 0; + ops[ooffset++] = v; + } + free(word); + offset = end; + } else { + offset++; } } - variable *result = make_varn(0, ((variable *)ops[0])->value.f); - if (!((variable *)ops[0])->used) - free(ops[0]); - - //for (uint32_t i = 1; i < ooffset; i += 2) - // iopfuncs[(uint32_t)ops[i] - 1](result, result, ops[i + 1]); - - //for (uint32_t i = 0; i < ooffset; i += 2) { - // variable *v = (variable *)ops[i]; - // if (!v->used) { - // if (v->valtype == STRING || v->valtype == EXPR) - // free((void *)v->value.p); - // free(ops[i]); - // } - //} - - return result; + // mark end + ops[ooffset] = 0; + return ops; } - |