diff --git a/builtins.c b/builtins.c index 5186e8b..0ab6f3b 100644 --- a/builtins.c +++ b/builtins.c @@ -13,6 +13,7 @@ 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 @@ -32,6 +33,24 @@ void iload_core(interpreter *interp) inew_cfunc(interp, "while", ifunc_while); inew_cfunc(interp, "ret", ifunc_ret); inew_cfunc(interp, "else", ifunc_else); + inew_cfunc(interp, "solve", ifunc_solve); +} + +int ifunc_solve(interpreter *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); + return 0; } int ifunc_set(interpreter *it) diff --git a/parser.c b/parser.c index d7ba5ac..886d27b 100644 --- a/parser.c +++ b/parser.c @@ -14,9 +14,6 @@ #define MAX_STACK 32 #define MAX_LINES 1000 -extern int atoi(const char *); -extern float strtof(const char *, char **); - void iinit(interpreter *interp) { interp->vars = (variable *)calloc(MAX_VARS, sizeof(variable)); @@ -47,6 +44,9 @@ void iend(interpreter *it) 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]); @@ -156,44 +156,22 @@ variable *make_var(interpreter *interp, const char *line, uint32_t *next) variable *v = make_vare(0, expr); free(expr); return v; - } else if (isalpha(line[0])) { // variable/func - uint32_t end = 1; - for (; isalnum(line[end]); end++); - if (!eot(line[end])) - return 0; - char *name = (char *)malloc(end + 1); - strncpy(name, line, end); - name[end] = '\0'; - *next = end; - 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; - for (; !eot(line[end]); end++) { - if (!isdigit(line[end])) { - if (line[end] == '.') { - if (!dec) - dec = 1; - else - return 0; - } else { - return 0; - } - } + } 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; } - char *copy = (char *)malloc(end + 1); - strncpy(copy, line, end); - copy[end] = '\0'; - variable *v; - if (dec) - v = make_varn(0, strtof(copy, 0)); - else - v = make_varn(0, (float)atoi(copy)); - free(copy); - *next = end; - return v; } return 0; } @@ -364,7 +342,6 @@ variable *idoexpr(interpreter *interp, const char *line) void *ops[16]; uint32_t ooffset = 0; uint32_t offset = 0; - uint32_t next = 0; // step 1 - break apart line for (uint8_t i = 0; i < 16; i++) @@ -392,17 +369,33 @@ variable *idoexpr(interpreter *interp, const char *line) ops[ooffset] = idoexpr(interp, line + offset + 1); offset = i + 1; } else { - uint32_t len = offset; - for (; isalnum(line[len]) || line[len] == '.'; len++); - len -= offset; - char *copy = (char *)malloc(len + 1); - strncpy(copy, line + offset, len); - copy[len] = '\0'; - variable *v = make_var(interp, copy, &next); - free(copy); - ops[ooffset] = v; - offset += next; + 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 { + return 0; + } + } } + if (ops[ooffset] == 0) return 0; @@ -421,10 +414,11 @@ variable *idoexpr(interpreter *interp, const char *line) break; } } - if (ops[ooffset] == 0) - return 0; - ooffset++; + if (ops[ooffset] == 0) // implicit multiply + ops[ooffset] = (void *)1; + + ooffset++; // skip whitespace skipblank(line, eol, &offset); } diff --git a/parser.h b/parser.h index 1b821cd..1b0fdd6 100644 --- a/parser.h +++ b/parser.h @@ -22,15 +22,15 @@ typedef struct { typedef int (*func_t)(interpreter *); void iinit(interpreter *); -void iend(interpreter *it); +void iend(interpreter *); -void iskip(interpreter *it); +void iskip(interpreter *); variable *inew_string(interpreter *, const char *, const char *); variable *inew_number(interpreter *, const char *, float); variable *inew_cfunc(interpreter *, const char *, func_t); int idoline(interpreter *, const char *); -variable *idoexpr(interpreter *interp, const char *line); +variable *idoexpr(interpreter *, const char *); #endif // PARSER_H_ diff --git a/script b/script index c3837a3..35497fe 100644 --- a/script +++ b/script @@ -1,15 +1,7 @@ -set a "Het\n" -set b a -print b +set x 42 +set eq ".a/a" -#set a 0 -#do -# print "> " -# gets text -# set input "(" -# concat input text -# concat input ")" -# expr input a -# print a -# print "\n" -#while (1) +solve eq > ans + +print ans +print "\n" diff --git a/shell.c b/shell.c new file mode 100644 index 0000000..8704db6 --- /dev/null +++ b/shell.c @@ -0,0 +1,52 @@ +#include +#include + +#include "stack.h" + +#include +#include +//#include +#include + +int s_put(interpreter *it) +{ + variable *v = igetarg(it, 0); + if (v->valtype == NUMBER) + printf("%.f", v->value.f); + else + printf("%s", (char *)v->value.p); + return 0; +} + +int main(int argc, char **argv) +{ + interpreter interp; + + if (argc != 2) { + printf("Usage: %s file\n", argv[0]); + return -1; + } + + FILE *fp = fopen(argv[1], "r"); + if (fp == 0) { + printf("Could not open file: %s\n", argv[1]); + return -1; + } + + iinit(&interp); + inew_cfunc(&interp, "print", s_put); + + char *line = 0; + unsigned int size; + int result; + while (getline(&line, &size, fp) != -1) { + *strchr(line, '\n') = '\0'; + result = idoline(&interp, line); + if (result != 0) + printf("Error: %d\n", result); + } + + fclose(fp); + iend(&interp); + return 0; +} diff --git a/variable.c b/variable.c index c170f79..957a130 100644 --- a/variable.c +++ b/variable.c @@ -1,6 +1,7 @@ #include "variable.h" #include "parser.h" +#include #include #include #include @@ -69,3 +70,66 @@ variable *make_vare(variable *v, const char *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 b4a7c72..da3badc 100644 --- a/variable.h +++ b/variable.h @@ -25,4 +25,7 @@ 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_