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:
parent
08b42bf424
commit
d24b8c5ead
146
eval.c
146
eval.c
@ -99,6 +99,8 @@ Token tadd(Token l, Token r)
|
|||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result;
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
char *buf;
|
||||||
|
int len;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (l.type==EEK)
|
if (l.type==EEK)
|
||||||
@ -154,6 +156,14 @@ Token tadd(Token l, Token r)
|
|||||||
result.u.flt=l.u.flt+r.u.flt;
|
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)
|
else if (l.type==EMPTY && r.type==EMPTY)
|
||||||
/* result is emty */ /*{{{*/
|
/* result is emty */ /*{{{*/
|
||||||
{
|
{
|
||||||
@ -164,7 +174,11 @@ Token tadd(Token l, Token r)
|
|||||||
/* result is type error */ /*{{{*/
|
/* result is type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
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)
|
if (result.type==FLOAT && (msg=dblfinite(result.u.flt))!=(const char*)0)
|
||||||
@ -185,6 +199,7 @@ Token tsub(Token l, Token r)
|
|||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result;
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
int len;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (l.type==EEK)
|
if (l.type==EEK)
|
||||||
@ -231,6 +246,14 @@ Token tsub(Token l, Token r)
|
|||||||
result.u.flt=l.u.flt-((double)r.u.integer);
|
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
|
else
|
||||||
/* result is difference type error */ /*{{{*/
|
/* result is difference type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
@ -256,6 +279,7 @@ Token tdiv(Token l, Token r)
|
|||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result;
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
int len;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (l.type==EEK)
|
if (l.type==EEK)
|
||||||
@ -315,6 +339,14 @@ Token tdiv(Token l, Token r)
|
|||||||
result.u.flt=l.u.flt/((double)r.u.integer);
|
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
|
else
|
||||||
/* result is quotient type error */ /*{{{*/
|
/* result is quotient type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
@ -340,6 +372,7 @@ Token tmod(Token l, Token r)
|
|||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result;
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
int len;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (l.type==EEK) /* return left error */ /*{{{*/
|
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);
|
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 */ /*{{{*/
|
else /* result is remainder type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
@ -413,6 +462,7 @@ Token tmul(Token l, Token r)
|
|||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result;
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
int len;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (l.type==EEK)
|
if (l.type==EEK)
|
||||||
@ -471,6 +521,23 @@ Token tmul(Token l, Token r)
|
|||||||
result.type=EMPTY;
|
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
|
else
|
||||||
/* result is product type error */ /*{{{*/
|
/* result is product type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
@ -495,6 +562,7 @@ Token tneg(Token x)
|
|||||||
{
|
{
|
||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result;
|
||||||
|
int len;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (x.type==EEK)
|
if (x.type==EEK)
|
||||||
@ -521,6 +589,14 @@ Token tneg(Token x)
|
|||||||
result=tcopy(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
|
else
|
||||||
/* result is negation error */ /*{{{*/
|
/* result is negation error */ /*{{{*/
|
||||||
{
|
{
|
||||||
@ -634,6 +710,7 @@ Token tlt(Token l, Token r)
|
|||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result;
|
||||||
static char empty[]="";
|
static char empty[]="";
|
||||||
|
int len;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (l.type==EEK) /* return left error argument */ /*{{{*/
|
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;
|
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 */ /*{{{*/
|
else /* return < type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
@ -711,6 +800,7 @@ Token tle(Token l, Token r)
|
|||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result;
|
||||||
static char empty[]="";
|
static char empty[]="";
|
||||||
|
int len;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (l.type==EEK) /* return left error argument */ /*{{{*/
|
if (l.type==EEK) /* return left error argument */ /*{{{*/
|
||||||
@ -778,6 +868,16 @@ Token tle(Token l, Token r)
|
|||||||
result.type=INT;
|
result.type=INT;
|
||||||
result.u.integer=1;
|
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 */ /*{{{*/
|
else /* result is <= type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
@ -794,6 +894,7 @@ Token tge(Token l, Token r)
|
|||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result;
|
||||||
static char empty[]="";
|
static char empty[]="";
|
||||||
|
int len;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (l.type==EEK) /* return left error argument */ /*{{{*/
|
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;
|
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 */ /*{{{*/
|
else /* return >= type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
@ -871,6 +982,7 @@ Token tgt(Token l, Token r)
|
|||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result;
|
||||||
static char empty[]="";
|
static char empty[]="";
|
||||||
|
int len;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (l.type==EEK) /* return left error argument */ /*{{{*/
|
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;
|
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.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("type mismatch for relational operator"));
|
result.u.err=mystrmalloc(_("type mismatch for relational operator"));
|
||||||
@ -948,6 +1071,7 @@ Token teq(Token l, Token r)
|
|||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result;
|
||||||
static char empty[]="";
|
static char empty[]="";
|
||||||
|
int len;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (l.type==EEK) return tcopy(l);
|
if (l.type==EEK) return tcopy(l);
|
||||||
@ -1013,6 +1137,15 @@ Token teq(Token l, Token r)
|
|||||||
result.type=INT;
|
result.type=INT;
|
||||||
result.u.integer=1;
|
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
|
else
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
@ -1071,6 +1204,7 @@ Token tne(Token l, Token r)
|
|||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result;
|
||||||
static char empty[]="";
|
static char empty[]="";
|
||||||
|
int len;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (l.type==EEK) return tcopy(l);
|
if (l.type==EEK) return tcopy(l);
|
||||||
@ -1131,11 +1265,17 @@ Token tne(Token l, Token r)
|
|||||||
result.type=INT;
|
result.type=INT;
|
||||||
result.u.integer=l.u.flt!=r.u.flt;
|
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.type=INT;
|
||||||
result.u.integer=0;
|
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
|
else
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
|
@ -28,6 +28,12 @@ extern double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */
|
|||||||
#include "scanner.h"
|
#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 */ /*{{{*/
|
/* identcode -- return number of identifier */ /*{{{*/
|
||||||
int identcode(const char *s, size_t len)
|
int identcode(const char *s, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,8 @@ typedef enum {
|
|||||||
#endif
|
#endif
|
||||||
} Type;
|
} 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 enum { PLUS, MINUS, MUL, DIV, OP, CP, COMMA, LT, LE, GE, GT, ISEQUAL, ABOUTEQ, NE, POW, MOD } Operator;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
Loading…
Reference in New Issue
Block a user