From d24b8c5ead160f35867e478b4414c0384bbf1927 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Thu, 25 Jul 2019 06:05:24 -0700 Subject: [PATCH] Add arithmetic for locations Nearly all of the basic operations in eval.c have been implemented for values of type LOCATION. The behavior is generally modeled after typical vector arithmetic. For "<", as a particular case, every component must be less than or equal the corresponding component, and at least one must be strictly less (<= drops the latter condition, of course). Note "<" returns the number of strictly less coordinates, but 0 (false) if any coordinate is greater. Also implements a mechanism (string array Type_Names) for printing type information and slightly enhanced the error message for type mismatch in + Closes #16. --- eval.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- scanner.c | 6 +++ scanner.h | 2 + 3 files changed, 151 insertions(+), 3 deletions(-) diff --git a/eval.c b/eval.c index 554ac5f..8b89b98 100644 --- a/eval.c +++ b/eval.c @@ -99,6 +99,8 @@ Token tadd(Token l, Token r) /* variables */ /*{{{*/ Token result; const char *msg; + char *buf; + int len; /*}}}*/ if (l.type==EEK) @@ -154,6 +156,14 @@ Token tadd(Token l, Token r) result.u.flt=l.u.flt+r.u.flt; } /*}}}*/ + else if (l.type == LOCATION && r.type == LOCATION) + /* result is component-wise sum of locations */ /*{{{*/ + { + result.type = LOCATION; + for (len = 0; len < 3; ++len) + result.u.location[len] = l.u.location[len] + r.u.location[len]; + } + /*}}}*/ else if (l.type==EMPTY && r.type==EMPTY) /* result is emty */ /*{{{*/ { @@ -164,7 +174,11 @@ Token tadd(Token l, Token r) /* result is type error */ /*{{{*/ { result.type=EEK; - result.u.err=strcpy(malloc(strlen(_("wrong types for + operator"))+1),_("wrong types for + operator")); + len = strlen(_("wrong types for + operator")); + buf = malloc(len + 128); + strcpy(buf, _("wrong types for + operator")); + snprintf(buf + len, 128, ": %s + %s", Type_Name[l.type], Type_Name[r.type]); + result.u.err = buf; } /*}}}*/ if (result.type==FLOAT && (msg=dblfinite(result.u.flt))!=(const char*)0) @@ -185,6 +199,7 @@ Token tsub(Token l, Token r) /* variables */ /*{{{*/ Token result; const char *msg; + int len; /*}}}*/ if (l.type==EEK) @@ -231,6 +246,14 @@ Token tsub(Token l, Token r) result.u.flt=l.u.flt-((double)r.u.integer); } /*}}}*/ + else if (l.type == LOCATION && r.type == LOCATION) + /* result is component-wise difference of locations */ /*{{{*/ + { + result.type = LOCATION; + for (len = 0; len < 3; ++len) + result.u.location[len] = l.u.location[len] - r.u.location[len]; + } + /*}}}*/ else /* result is difference type error */ /*{{{*/ { @@ -256,6 +279,7 @@ Token tdiv(Token l, Token r) /* variables */ /*{{{*/ Token result; const char *msg; + int len; /*}}}*/ if (l.type==EEK) @@ -315,6 +339,14 @@ Token tdiv(Token l, Token r) result.u.flt=l.u.flt/((double)r.u.integer); } /*}}}*/ + else if (l.type == LOCATION && r.type == INT) + /* result is divide each component of location by right */ /*{{{*/ + { + result.type = LOCATION; + for (len = 0; len < 3; ++len) + result.u.location[len] = l.u.location[len] / r.u.integer; + } + /*}}}*/ else /* result is quotient type error */ /*{{{*/ { @@ -340,6 +372,7 @@ Token tmod(Token l, Token r) /* variables */ /*{{{*/ Token result; const char *msg; + int len; /*}}}*/ if (l.type==EEK) /* return left error */ /*{{{*/ @@ -390,6 +423,22 @@ Token tmod(Token l, Token r) result.u.flt=fmod(l.u.flt,(double)r.u.integer); } /*}}}*/ + else if (l.type == LOCATION && r.type == LOCATION) + /* result is component-wise mod of locations */ /*{{{*/ + { + result.type = LOCATION; + for (len = 0; len < 3; ++len) + result.u.location[len] = l.u.location[len] % r.u.location[len]; + } + /*}}}*/ + else if (l.type == LOCATION && r.type == INT) + /* result is mod each component of location by right */ /*{{{*/ + { + result.type = LOCATION; + for (len = 0; len < 3; ++len) + result.u.location[len] = l.u.location[len] % r.u.integer; + } + /*}}}*/ else /* result is remainder type error */ /*{{{*/ { result.type=EEK; @@ -413,6 +462,7 @@ Token tmul(Token l, Token r) /* variables */ /*{{{*/ Token result; const char *msg; + int len; /*}}}*/ if (l.type==EEK) @@ -471,6 +521,23 @@ Token tmul(Token l, Token r) result.type=EMPTY; } /*}}}*/ + else if (l.type == LOCATION && r.type == INT) + /* result is each component of location times right */ /*{{{*/ + { + result.type = LOCATION; + for (len = 0; len < 3; ++len) + result.u.location[len] = l.u.location[len] * r.u.integer; + } + /*}}}*/ + else if (l.type == LOCATION && r.type == LOCATION) + /* result is dot product of locations */ /*{{{*/ + { + result.type = INT; + result.u.integer = 0; + for (len = 0; len < 3; ++len) + result.u.integer += l.u.location[len] * r.u.location[len]; + } + /*}}}*/ else /* result is product type error */ /*{{{*/ { @@ -495,6 +562,7 @@ Token tneg(Token x) { /* variables */ /*{{{*/ Token result; + int len; /*}}}*/ if (x.type==EEK) @@ -521,6 +589,14 @@ Token tneg(Token x) result=tcopy(x); } /*}}}*/ + else if (x.type == LOCATION) + /* result is component-wise negation of location */ /*{{{*/ + { + result.type = LOCATION; + for (len = 0; len < 3; ++len) + result.u.location[len] = -x.u.location[len]; + } + /*}}}*/ else /* result is negation error */ /*{{{*/ { @@ -634,6 +710,7 @@ Token tlt(Token l, Token r) /* variables */ /*{{{*/ Token result; static char empty[]=""; + int len; /*}}}*/ if (l.type==EEK) /* return left error argument */ /*{{{*/ @@ -696,6 +773,18 @@ Token tlt(Token l, Token r) result.u.integer=((double)l.u.integer) r.u.location[len]) break; + else if (l.u.location[len] < r.u.location[len]) ++result.u.integer; + if (len < 3) result.u.integer = 0; + } + /*}}}*/ else /* return < type error */ /*{{{*/ { result.type=EEK; @@ -711,6 +800,7 @@ Token tle(Token l, Token r) /* variables */ /*{{{*/ Token result; static char empty[]=""; + int len; /*}}}*/ if (l.type==EEK) /* return left error argument */ /*{{{*/ @@ -778,6 +868,16 @@ Token tle(Token l, Token r) result.type=INT; result.u.integer=1; } + /*}}}*/ + else if (l.type == LOCATION && r.type == LOCATION) + /* result is true if l is in rectangle from origin to r */ /*{{{*/ + { + result.type = INT; + result.u.integer = 1; + for (len = 0; len < 3; ++len) + if (l.u.location[len] > r.u.location[len]) break; + if (len < 3) result.u.integer = 0; + } /*}}}*/ else /* result is <= type error */ /*{{{*/ { @@ -794,6 +894,7 @@ Token tge(Token l, Token r) /* variables */ /*{{{*/ Token result; static char empty[]=""; + int len; /*}}}*/ if (l.type==EEK) /* return left error argument */ /*{{{*/ @@ -856,6 +957,16 @@ Token tge(Token l, Token r) result.u.integer=((double)l.u.integer)>=r.u.flt; } /*}}}*/ + else if (l.type == LOCATION && r.type == LOCATION) + /* result is true if r is in rectangle from origin to l */ /*{{{*/ + { + result.type = INT; + result.u.integer = 1; + for (len = 0; len < 3; ++len) + if (r.u.location[len] > l.u.location[len]) break; + if (len < 3) result.u.integer = 0; + } + /*}}}*/ else /* return >= type error */ /*{{{*/ { result.type=EEK; @@ -871,6 +982,7 @@ Token tgt(Token l, Token r) /* variables */ /*{{{*/ Token result; static char empty[]=""; + int len; /*}}}*/ if (l.type==EEK) /* return left error argument */ /*{{{*/ @@ -933,7 +1045,18 @@ Token tgt(Token l, Token r) result.u.integer=((double)l.u.integer)>r.u.flt; } /*}}}*/ - else /* result is relation op type error */ /*{{{*/ + else if (l.type == LOCATION && r.type == LOCATION) + /* result is true if r is strictly in rectangle from origin to l + In addition the value tells how many coordinates were strictly greater */ /*{{{*/ + { + result.type = INT; + result.u.integer = 0; + for (len = 0; len < 3; ++len) + if (r.u.location[len] > l.u.location[len]) break; + else if (r.u.location[len] < l.u.location[len]) ++result.u.integer; + if (len < 3) result.u.integer = 0; + } + /*}}}*/ else /* result is relation op type error */ /*{{{*/ { result.type=EEK; result.u.err=mystrmalloc(_("type mismatch for relational operator")); @@ -948,6 +1071,7 @@ Token teq(Token l, Token r) /* variables */ /*{{{*/ Token result; static char empty[]=""; + int len; /*}}}*/ if (l.type==EEK) return tcopy(l); @@ -1013,6 +1137,15 @@ Token teq(Token l, Token r) result.type=INT; result.u.integer=1; } + else if (l.type == LOCATION) + /* result is true if locations are component-wise equal */ /*{{{*/ + { + result.type = INT; + result.u.integer = 1; + for (len = 0; len < 3 && l.u.location[len] == r.u.location[len]; ++len); + if (len < 3) result.u.integer = 0; + } + /*}}}*/ else { result.type=EEK; @@ -1071,6 +1204,7 @@ Token tne(Token l, Token r) /* variables */ /*{{{*/ Token result; static char empty[]=""; + int len; /*}}}*/ if (l.type==EEK) return tcopy(l); @@ -1131,11 +1265,17 @@ Token tne(Token l, Token r) result.type=INT; result.u.integer=l.u.flt!=r.u.flt; } - else if (l.type==EMPTY) + else if (l.type==EMPTY) /* both empty, so equal, i.e. not inequal */ { result.type=INT; result.u.integer=0; } + else if (l.type == LOCATION) { + result.type = INT; + result.u.integer = 0; + for (len = 0; len < 3 && l.u.location[len] == r.u.location[len]; ++len); + if (len < 3) result.u.integer = 1; + } else { result.type=EEK; diff --git a/scanner.c b/scanner.c index 115c764..b579e32 100644 --- a/scanner.c +++ b/scanner.c @@ -28,6 +28,12 @@ extern double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */ #include "scanner.h" /*}}}*/ +const char *Type_Name[] = + { [EMPTY] = "EMPTY", [STRING] = "STRING", [FLOAT] = "FLOAT", [INT] = "INT", + [OPERATOR] = "OPERATOR", [LIDENT] = "LABEL", [FIDENT] = "FUNCTION", + [LOCATION] = "LOCATION", [EEK] = "ERROR" + }; + /* identcode -- return number of identifier */ /*{{{*/ int identcode(const char *s, size_t len) { diff --git a/scanner.h b/scanner.h index 501ebdc..6a4721d 100644 --- a/scanner.h +++ b/scanner.h @@ -14,6 +14,8 @@ typedef enum { #endif } Type; +extern const char *Type_Name[]; + typedef enum { PLUS, MINUS, MUL, DIV, OP, CP, COMMA, LT, LE, GE, GT, ISEQUAL, ABOUTEQ, NE, POW, MOD } Operator; typedef struct