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.
This commit is contained in:
Glen Whitney 2019-07-25 06:05:24 -07:00
parent 08b42bf424
commit d24b8c5ead
3 changed files with 151 additions and 3 deletions

146
eval.c
View File

@ -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.flt;
}
/*}}}*/
else if (l.type == LOCATION && r.type == LOCATION)
/* result is true if l is strictly in rectangle from origin to r
In addition the value tells how many coordinates were strictly less */ /*{{{*/
{
result.type = INT;
result.u.integer = 0;
for (len = 0; len < 3; ++len)
if (l.u.location[len] > 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;

View File

@ -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)
{

View File

@ -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