diff options
Diffstat (limited to 'ops.c')
-rw-r--r-- | ops.c | 74 |
1 files changed, 54 insertions, 20 deletions
@@ -18,17 +18,27 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +/** + * Operators are special functions (though different from those that are built- + * in). Operators have no access to the interpreter instance; instead only the + * two 'argument' variables and a variable to contain the result are passed in. + * The operator function returns an integer, zero for success. + * + * Argument 'a' is the variable on the left side of the operator, and 'b' is + * the variable on the right. 'r' is a non-null variable that the result of the + * operation should be placed in. + */ + +#include "error.h" #include "ops.h" +#include "string.h" #include <stdlib.h> -#include <string.h> #define OP_DEF(o) int op_##o(variable *r, variable *a, variable *b) #define OP_VAR(o) {0, OPERATOR, 0, {.p = (uint32_t)op_##o}} #define OP_NONE {0, OPERATOR, 0, {.p = 0x0BADCAFE}} -extern char *strclone(const char *s); - OP_DEF(mul); OP_DEF(div); OP_DEF(mod); @@ -47,6 +57,15 @@ OP_DEF(xor); OP_DEF(or); OP_DEF(set); +/** + * Operators are stored here in order of significance, meaning those towards + * the beginning of the array are completed before those after them. This + * priority listing is done in pairs of two, so that mathematical order of + * operations can be respected. For example, the first two operators + * multiplication and division) have the same priority. Should an operator not + * have a 'pair', OP_NONE can be used. Should adjacent operators have the same + * priority, they will be evaluated from left-to-right by the parser. + */ variable opvars[] = { OP_VAR(mul), OP_VAR(div), OP_VAR(mod), OP_NONE, OP_VAR(add), OP_VAR(sub), OP_VAR(shl), OP_VAR(shr), @@ -63,10 +82,25 @@ const char *opnames[] = { "|", "=" }; +variable *igetop(const char *name, int *retlen) +{ + for (uint32_t i = 0; i < OPS_COUNT; i++) { + if (opnames[i] == 0) + continue; + int len = strlen(opnames[i]); + if (opnames[i] != 0 && !strncmp(name, opnames[i], len)) { + if (retlen != 0) + *retlen = len; + return &opvars[i]; + } + } + return 0; +} + OP_DEF(mul) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = a->value.f * b->value.f; return 0; @@ -74,7 +108,7 @@ OP_DEF(mul) OP_DEF(div) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = a->value.f / b->value.f; return 0; @@ -82,7 +116,7 @@ OP_DEF(div) OP_DEF(mod) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = (int)a->value.f % (int)b->value.f; return 0; @@ -90,7 +124,7 @@ OP_DEF(mod) OP_DEF(add) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = a->value.f + b->value.f; return 0; @@ -98,7 +132,7 @@ OP_DEF(add) OP_DEF(sub) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = a->value.f - b->value.f; return 0; @@ -106,7 +140,7 @@ OP_DEF(sub) OP_DEF(shl) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = (int)a->value.f << (int)b->value.f; return 0; @@ -114,7 +148,7 @@ OP_DEF(shl) OP_DEF(shr) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = (int)a->value.f >> (int)b->value.f; return 0; @@ -122,7 +156,7 @@ OP_DEF(shr) OP_DEF(lte) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = a->value.f <= b->value.f; return 0; @@ -130,7 +164,7 @@ OP_DEF(lte) OP_DEF(lt) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = a->value.f < b->value.f; return 0; @@ -138,7 +172,7 @@ OP_DEF(lt) OP_DEF(gte) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = a->value.f >= b->value.f; return 0; @@ -146,7 +180,7 @@ OP_DEF(gte) OP_DEF(gt) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = a->value.f > b->value.f; return 0; @@ -159,14 +193,14 @@ OP_DEF(eq) else if (a->type == STRING && b->type == STRING) r->value.f = !strcmp((const char *)a->value.p, (const char *)b->value.p); else - return -1; + return seterror(EBADPARAM); return 0; } OP_DEF(ne) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = a->value.f != b->value.f; return 0; @@ -174,7 +208,7 @@ OP_DEF(ne) OP_DEF(and) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = (int)a->value.f & (int)b->value.f; return 0; @@ -182,7 +216,7 @@ OP_DEF(and) OP_DEF(xor) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = (int)a->value.f ^ (int)b->value.f; return 0; @@ -190,7 +224,7 @@ OP_DEF(xor) OP_DEF(or) { if (a->type != NUMBER || b->type != NUMBER) - return -1; + return seterror(EBADPARAM); r->type = NUMBER; r->value.f = (int)a->value.f | (int)b->value.f; return 0; @@ -210,7 +244,7 @@ OP_DEF(set) r->type = STRING; r->value.p = (uint32_t)strclone((char *)a->value.p); } else { - return -1; + return seterror(EBADPARAM); } return 0; } |