diff --git a/old/parser.c b/old/parser.c new file mode 100644 index 0000000..5e94e79 --- /dev/null +++ b/old/parser.c @@ -0,0 +1,225 @@ +#include + +#include +#include + +static const char *interpreter_operators = "=("; + +bool strcmp(const char *a, const char *b) +{ + int i = 0; + for (; a[i] == b[i] && a[i] != '\0'; i++); + return a[i] == b[i]; +} + +bool strncmp(const char *a, const char *b, int count) +{ + int i = 0; + for (; a[i] == b[i] && i < count; i++); + return i == count; +} + +uint8_t isalpha(char c) +{ + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + +uint8_t isnum(char c) +{ + return (c >= '0' && c <= '9'); +} + +uint8_t isname(char c) +{ + return isalpha(c) || isnum(c); +} + +uint8_t isspace(char c) +{ + return (c == ' ' || c == '\t' || c == '\n'); +} + +uint8_t isoper(char c) +{ + for (uint8_t i = 0; i < sizeof(interpreter_operators); i++) { + if (c == interpreter_operators[i]) + return 1; + } + + return 0; +} + +void interpreter_init(interpreter *interp) +{ + interp->status = READY; + interp->vcount = 0; + interp->vars = (variable *)calloc(32, sizeof(variable)); + interp->names = (char **)calloc(32, sizeof(char *)); + interp->stack = (stack_t *)calloc(64, sizeof(stack_t)); +} + +void interpreter_define_value(interpreter *interp, const char *name, int32_t value) +{ + interp->names[interp->vcount] = (char *)name; + interp->vars[interp->vcount].nameidx = interp->vcount; + interp->vars[interp->vcount].type = VALUE; + interp->vars[interp->vcount].value = (uint32_t)value; + interp->vcount++; +} + +void interpreter_define_cfunc(interpreter *interp, const char *name, func_t addr) +{ + interp->names[interp->vcount] = (char *)name; + interp->vars[interp->vcount].nameidx = interp->vcount; + interp->vars[interp->vcount].type = CFUNCTION; + interp->vars[interp->vcount].value = (uint32_t)addr; + interp->vcount++; +} + +int32_t interpreter_get_value(interpreter *interp, const char *name) +{ + for (uint16_t i = 0; i < interp->vcount; i++) { + if (!strcmp(interp->names[i], name)) + return (int32_t)interp->vars[i].value; + } + + return 0; +} + +/** + * doline section + */ + +bool namencmp(const char *name, const char *s) +{ + uint16_t i; + for (i = 0; name[i] == s[i] && s[i] != '\0'; i++); + return (name[i] == '\0' && !isname(s[i])); +} + +uint16_t spacecount(const char *s) +{ + uint16_t i; + for (i = 0; isspace(s[i]); i++); + return i; +} + +char *copystr(const char *s, char end) +{ + uint16_t len = 0; + while (s[len++] != end); + char *buf = (char *)malloc(len); + for (uint16_t i = 0; i < len; i++) + buf[i] = s[i]; + return buf; +} + +char *copysubstr(const char *s, int end) +{ + char *buf = (char *)malloc(end); + for (uint16_t i = 0; i < end; i++) + buf[i] = s[i]; + return buf; +} + +variable *interpreter_getvar(interpreter *interp, const char *line) +{ + for (uint16_t i = 0; i < interp->vcount; i++) { + if (namencmp(interp->names[i], line)) + return &interp->vars[i]; + } + + return 0; +} + +int interpreter_doline(interpreter *interp, const char *line) +{ + variable *bits[16]; + uint16_t offset = 0, boffset = 0; + + // check for var/func set or usage + int end; +getvar: + for (end = 0; isname(line[end]); end++); + variable *var = interpreter_getvar(interp, line); + + if (var != 0) { + bits[boffset++] = var; + } else { + // defining new variable + interpreter_define_value(interp, copysubstr(line, end), 0); + goto getvar; // try again + } + + // skip whitespace/name + offset += end; + offset += spacecount(line + offset); + + if (boffset == 0 && line[offset] != '=') + return -1; // variable not found + + // find operator + if (line[offset] == '\0') { + // print value + return -99; + } else if (line[offset] == '=') { + // assignment/expression + offset++; + offset += spacecount(line + offset); + bits[0]->value = (uint32_t)copystr(line + offset, '\0'); + } else if (line[offset] == '(') { + // function call + offset++; + if (bits[0]->type != FUNCTION && bits[0]->type != CFUNCTION) + return -2; + offset += spacecount(line + offset); + + // collect arg offsets + uint16_t offsets[8]; + uint8_t ooffset = 0; + while (line[offset] != ')' && line[offset] != '\0') { + offsets[ooffset] = offset; + offset += spacecount(line + offset); + + uint8_t isvn = 1; + do { + if (line[offset] == ' ' || line[offset] == '\t') { + offset += spacecount(line + offset); + isvn = 0; + } + + if (line[offset] == ',') { + offset++; + ooffset++; + break; + } else if (line[offset] == ')') { + ooffset++; + break; + } else if (isvn == 0) { + return -3; + } + } while (++offset); + } + + // populate stack + for (uint8_t i = 0; i < ooffset; i++) { + uint16_t j; + for (j = offsets[i]; line[j] != ' ' && line[j] != '\t' && + line[j] != ',' && line[j] != ')'; j++); + j -= offsets[i]; + + variable *var = interpreter_getvar(interp, line + offsets[i]); + if (var != 0) + interp->stack[i] = copystr((char *)var->value, '\0'); + else + interp->stack[i] = copysubstr(line + offsets[i], j); + } + + ((func_t)bits[0]->value)(interp->stack); + } else { + return -2; // invalid operation + } + + return 0; +} + diff --git a/old/parser.h b/old/parser.h new file mode 100644 index 0000000..c6a2b17 --- /dev/null +++ b/old/parser.h @@ -0,0 +1,31 @@ +#ifndef PARSER_H_ +#define PARSER_H_ + +#include + +typedef void *stack_t; + +typedef struct { + uint16_t status; + uint16_t vcount; + variable *vars; + char **names; + stack_t *stack; +} interpreter; + +enum status { + READY = 0 +}; + +typedef void (*func_t)(stack_t *); + +void interpreter_init(interpreter *); + +void interpreter_define_value(interpreter *, const char *, int32_t); +void interpreter_define_cfunc(interpreter *, const char *, func_t); + +int32_t interpreter_get_value(interpreter *, const char *); + +int interpreter_doline(interpreter *, const char *); + +#endif // PARSER_H_ diff --git a/old/variable.h b/old/variable.h new file mode 100644 index 0000000..fd84a6e --- /dev/null +++ b/old/variable.h @@ -0,0 +1,24 @@ +#ifndef TOKEN_H_ +#define TOKEN_H_ + +#include + +typedef struct { + uint16_t nameidx; + uint8_t type; + uint8_t info; + uint32_t value; +} variable; + +#define INFO_ARGS(x) ((x) & 0x07) +#define INFO_RET (1 << 3) + +enum vartype { + VALUE = 0, + VARIABLE, + OPERATOR, + FUNCTION, + CFUNCTION +}; + +#endif // TOKEN_H_ diff --git a/parser.c b/parser.c index 5e94e79..6ad7daf 100644 --- a/parser.c +++ b/parser.c @@ -1,225 +1,238 @@ #include -#include +#include #include +#include -static const char *interpreter_operators = "=("; +#define MAX_VARS 16 +#define MAX_STACK 32 -bool strcmp(const char *a, const char *b) +char *strclone(const char *s) { - int i = 0; - for (; a[i] == b[i] && a[i] != '\0'; i++); - return a[i] == b[i]; + char *clone = (char *)malloc(strlen(s)); + strcpy(clone, s); + return clone; } -bool strncmp(const char *a, const char *b, int count) +char *strnclone(const char *s, uint32_t n) { - int i = 0; - for (; a[i] == b[i] && i < count; i++); - return i == count; + char *clone = (char *)malloc(n); + strncpy(clone, s, n); + return clone; } -uint8_t isalpha(char c) +void iinit(interpreter *interp) { - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + 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; } -uint8_t isnum(char c) +variable *interpreter_get_variable(interpreter *interp, const char *name) { - return (c >= '0' && c <= '9'); + for (uint32_t i = 0; i < MAX_VARS; i++) { + if (!interp->vars[i].used) { + interp->vars[i].used = 1; + interp->vars[i].valtype = FUNC; + interp->vars[i].value = 0; + interp->vnames[i] = strclone(name); + return &interp->vars[i]; + } else if (interp->vnames[i] != 0 && !strcmp(interp->vnames[i], name)) { + return &interp->vars[i]; + } + } + return 0; } -uint8_t isname(char c) +void inew_string(interpreter *interp, const char *name, char *value) { - return isalpha(c) || isnum(c); + variable *v = interpreter_get_variable(interp, name); + if (v != 0) { + v->valtype = STRING; + v->value = (uint32_t)value; + } } -uint8_t isspace(char c) +void inew_integer(interpreter *interp, const char *name, int32_t value) { - return (c == ' ' || c == '\t' || c == '\n'); + variable *v = interpreter_get_variable(interp, name); + if (v != 0) { + v->valtype = INTEGER; + v->value = (uint32_t)value; + } } -uint8_t isoper(char c) +void inew_float(interpreter *interp, const char *name, float value) { - for (uint8_t i = 0; i < sizeof(interpreter_operators); i++) { - if (c == interpreter_operators[i]) - return 1; + variable *v = interpreter_get_variable(interp, name); + if (v != 0) { + v->valtype = FLOAT; + v->value = (uint32_t)value; } - - return 0; } -void interpreter_init(interpreter *interp) +void inew_cfunc(interpreter *interp, const char *name, func_t func) { - interp->status = READY; - interp->vcount = 0; - interp->vars = (variable *)calloc(32, sizeof(variable)); - interp->names = (char **)calloc(32, sizeof(char *)); - interp->stack = (stack_t *)calloc(64, sizeof(stack_t)); + variable *v = interpreter_get_variable(interp, name); + if (v != 0) { + v->fromc = 1; + v->valtype = FUNC; + v->value = (uint32_t)func; + } } -void interpreter_define_value(interpreter *interp, const char *name, int32_t value) +uint8_t eol(int c) { - interp->names[interp->vcount] = (char *)name; - interp->vars[interp->vcount].nameidx = interp->vcount; - interp->vars[interp->vcount].type = VALUE; - interp->vars[interp->vcount].value = (uint32_t)value; - interp->vcount++; + return c == '\n' || c == '\0'; } -void interpreter_define_cfunc(interpreter *interp, const char *name, func_t addr) +uint8_t eot(int c) { - interp->names[interp->vcount] = (char *)name; - interp->vars[interp->vcount].nameidx = interp->vcount; - interp->vars[interp->vcount].type = CFUNCTION; - interp->vars[interp->vcount].value = (uint32_t)addr; - interp->vcount++; + return eol(c) || c == ' '; } -int32_t interpreter_get_value(interpreter *interp, const char *name) +variable *make_var(interpreter *interp, const char *line, uint32_t *next) { - for (uint16_t i = 0; i < interp->vcount; i++) { - if (!strcmp(interp->names[i], name)) - return (int32_t)interp->vars[i].value; + 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 + variable *v = (variable *)malloc(sizeof(variable)); + v->valtype = STRING; + v->value = (uint32_t)strnclone(line + 1, end - 1); + *next = end + 1; + return v; + } + end++; + } + return 0; + } else if (line[0] == '(') { // equation 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 + // TODO make var + return 0; + } + end++; + } + } 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; + return interpreter_get_variable(interp, name); + } 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; + } + return 0; + } + } + variable *v = (variable *)malloc(sizeof(variable)); + v->valtype = INTEGER; + v->value = atoi(line); + *next = end; + return v; } - return 0; } -/** - * doline section - */ - -bool namencmp(const char *name, const char *s) +int idoline(interpreter *interp, const char *line) { - uint16_t i; - for (i = 0; name[i] == s[i] && s[i] != '\0'; i++); - return (name[i] == '\0' && !isname(s[i])); + variable *ops[8]; + uint32_t ooffset = 0; + uint32_t offset = 0; + uint32_t next; + + // step 1 - convert to tokens + while (!eol(line[offset])) { + ops[ooffset] = make_var(interp, line + offset, &next); + if (ops[ooffset] == 0) { + return -4; + } else { + ooffset++; + offset += next; + } + + // skip whitespace + for (; line[offset] == ' ' && !eol(line[offset]); offset++); + } + + // step 2 - execute + if (ooffset == 0) + return -1; + + if (ops[0]->valtype != FUNC) + return -2; + + if (ops[0]->value == 0) + return -3; + + for (uint32_t i = 0; i < ooffset - 1; i++, interp->stidx++) + interp->stack[i] = ops[i + 1]; + + ((func_t)ops[0]->value)(interp); + + return 0; } -uint16_t spacecount(const char *s) +char *igetarg_string(interpreter *interp, uint32_t index) { - uint16_t i; - for (i = 0; isspace(s[i]); i++); - return i; + if (index >= interp->stidx) + return 0; + if (interp->stack[index]->valtype != STRING) + return 0; + return (char *)interp->stack[index]->value; } -char *copystr(const char *s, char end) +int igetarg_integer(interpreter *interp, uint32_t index) { - uint16_t len = 0; - while (s[len++] != end); - char *buf = (char *)malloc(len); - for (uint16_t i = 0; i < len; i++) - buf[i] = s[i]; - return buf; + if (index >= interp->stidx) + return 0; + if (interp->stack[index]->valtype != INTEGER) + return 0; + return (int)interp->stack[index]->value; } -char *copysubstr(const char *s, int end) +float igetarg_float(interpreter *interp, uint32_t index) { - char *buf = (char *)malloc(end); - for (uint16_t i = 0; i < end; i++) - buf[i] = s[i]; - return buf; + if (index >= interp->stidx) + return 0; + if (interp->stack[index]->valtype != FLOAT) + return 0; + return (float)interp->stack[index]->value; } -variable *interpreter_getvar(interpreter *interp, const char *line) +/*char *iget_string(interpreter *, const char *) { - for (uint16_t i = 0; i < interp->vcount; i++) { - if (namencmp(interp->names[i], line)) - return &interp->vars[i]; - } - return 0; } -int interpreter_doline(interpreter *interp, const char *line) +int iget_integer(interpreter *, const char *) { - variable *bits[16]; - uint16_t offset = 0, boffset = 0; - - // check for var/func set or usage - int end; -getvar: - for (end = 0; isname(line[end]); end++); - variable *var = interpreter_getvar(interp, line); - - if (var != 0) { - bits[boffset++] = var; - } else { - // defining new variable - interpreter_define_value(interp, copysubstr(line, end), 0); - goto getvar; // try again - } - // skip whitespace/name - offset += end; - offset += spacecount(line + offset); - - if (boffset == 0 && line[offset] != '=') - return -1; // variable not found - - // find operator - if (line[offset] == '\0') { - // print value - return -99; - } else if (line[offset] == '=') { - // assignment/expression - offset++; - offset += spacecount(line + offset); - bits[0]->value = (uint32_t)copystr(line + offset, '\0'); - } else if (line[offset] == '(') { - // function call - offset++; - if (bits[0]->type != FUNCTION && bits[0]->type != CFUNCTION) - return -2; - offset += spacecount(line + offset); - - // collect arg offsets - uint16_t offsets[8]; - uint8_t ooffset = 0; - while (line[offset] != ')' && line[offset] != '\0') { - offsets[ooffset] = offset; - offset += spacecount(line + offset); - - uint8_t isvn = 1; - do { - if (line[offset] == ' ' || line[offset] == '\t') { - offset += spacecount(line + offset); - isvn = 0; - } - - if (line[offset] == ',') { - offset++; - ooffset++; - break; - } else if (line[offset] == ')') { - ooffset++; - break; - } else if (isvn == 0) { - return -3; - } - } while (++offset); - } - - // populate stack - for (uint8_t i = 0; i < ooffset; i++) { - uint16_t j; - for (j = offsets[i]; line[j] != ' ' && line[j] != '\t' && - line[j] != ',' && line[j] != ')'; j++); - j -= offsets[i]; - - variable *var = interpreter_getvar(interp, line + offsets[i]); - if (var != 0) - interp->stack[i] = copystr((char *)var->value, '\0'); - else - interp->stack[i] = copysubstr(line + offsets[i], j); - } +} - ((func_t)bits[0]->value)(interp->stack); - } else { - return -2; // invalid operation - } +float iget_float(interpreter *, const char *) +{ - return 0; -} +}*/ diff --git a/parser.h b/parser.h index c6a2b17..c2efba3 100644 --- a/parser.h +++ b/parser.h @@ -3,29 +3,32 @@ #include -typedef void *stack_t; +typedef variable *stack_t; typedef struct { - uint16_t status; - uint16_t vcount; variable *vars; - char **names; + char **vnames; stack_t *stack; + uint32_t stidx; } interpreter; -enum status { - READY = 0 -}; +typedef void (*func_t)(interpreter *); -typedef void (*func_t)(stack_t *); +void iinit(interpreter *); -void interpreter_init(interpreter *); +void inew_string(interpreter *, const char *, char *); +void inew_integer(interpreter *, const char *, int32_t); +void inew_float(interpreter *, const char *, float); +void inew_cfunc(interpreter *, const char *, func_t); -void interpreter_define_value(interpreter *, const char *, int32_t); -void interpreter_define_cfunc(interpreter *, const char *, func_t); +int idoline(interpreter *, const char *); -int32_t interpreter_get_value(interpreter *, const char *); +char *igetarg_string(interpreter *, uint32_t); +int igetarg_integer(interpreter *, uint32_t); +float igetarg_float(interpreter *, uint32_t); -int interpreter_doline(interpreter *, const char *); +char *iget_string(interpreter *, const char *); +int iget_integer(interpreter *, const char *); +float iget_float(interpreter *, const char *); #endif // PARSER_H_ diff --git a/shell.c b/shell.c index b19add8..578cabe 100644 --- a/shell.c +++ b/shell.c @@ -1,26 +1,42 @@ #include #include +#include +#include -void test(stack_t *stack) +void test(interpreter *it) { - printf("%s\n", stack[0]); + char *s = igetarg_string(it, 0); + if (s == 0) + s = "(null)"; + printf("%s\n", s); } -int main(int argc, char *argv[]) +void quit(interpreter *it) +{ + (void)it; + exit(0); +} + +int main() { interpreter interp; - interpreter_init(&interp); - interpreter_define_value(&interp, "answer", "42"); - interpreter_define_cfunc(&interp, "test", test); + iinit(&interp); + inew_integer(&interp, "answer", 42); + inew_cfunc(&interp, "put", test); + inew_cfunc(&interp, "exit", quit); + - if (argc > 1) { - for (int i = 1; i < argc; i++) { - int result = interpreter_doline(&interp, argv[i]); - if (result != 0) - printf("%d\n", result); - } + char *line = 0; + unsigned int size; + int result; + while (1) { + getline(&line, &size, stdin); + *strchr(line, '\n') = '\0'; + result = idoline(&interp, line); + if (result != 0) + printf("Error: %d\n", result); } return 0; diff --git a/variable.h b/variable.h index fd84a6e..b0f27d2 100644 --- a/variable.h +++ b/variable.h @@ -1,24 +1,20 @@ -#ifndef TOKEN_H_ -#define TOKEN_H_ +#ifndef VARIABLE_H_ +#define VARIABLE_H_ #include typedef struct { - uint16_t nameidx; - uint8_t type; - uint8_t info; + uint8_t used :1; + uint8_t fromc :1; + uint8_t valtype :2; uint32_t value; } variable; -#define INFO_ARGS(x) ((x) & 0x07) -#define INFO_RET (1 << 3) - -enum vartype { - VALUE = 0, - VARIABLE, - OPERATOR, - FUNCTION, - CFUNCTION +enum valtype { + STRING = 0, + INTEGER, + FLOAT, + FUNC }; -#endif // TOKEN_H_ +#endif // VARIABLE_H_