aboutsummaryrefslogtreecommitdiffstats
path: root/ops.c
diff options
context:
space:
mode:
Diffstat (limited to 'ops.c')
-rw-r--r--ops.c74
1 files changed, 54 insertions, 20 deletions
diff --git a/ops.c b/ops.c
index 1fb878d..e4874e8 100644
--- a/ops.c
+++ b/ops.c
@@ -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;
}