Extend sum() to cover the case of just adding up all of its arguments.

Also a small amount of preparation of storing parse trees instead of
  linear sequences of tokens got mixed in here, namely a new type of
  token called a "FUNCALL".
This commit is contained in:
Glen Whitney 2019-08-03 16:29:00 -04:00
parent 07bf78c7bb
commit 26ea0e05b3
3 changed files with 121 additions and 198 deletions

View File

@ -45,6 +45,7 @@ extern char *strdup(const char* s);
#else
#define CONST_PI ((double)3.14159265358979323846)
#endif
/*}}}*/
#ifdef WIN32
@ -304,6 +305,11 @@ static double deg2rad(double x)
}
/*}}}*/
static void duperror(Token* tok, const char* erro) {
tok->type = EEK;
tok->u.err = strdup(erro);
}
typedef enum {ABSOLUTE, RELATIVE, EXCEL} LocConvention;
static Token excel_adr_func(int argc, const Token argv[]);
@ -340,12 +346,8 @@ static Token adr_func(int argc, const Token argv[], LocConvention lcon)
else if (argv[i].type != EMPTY) break;
}
if (i < argc)
{
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_("Usage: &([integer x][,[integer y][,[integer z]]])"))+1),_("Usage: &([integer x][,[integer y][,[integer z]]])"));
}
else
result.type = LOCATION;
duperror(&result, _("Usage: &([integer x][,[integer y][,[integer z]]])"));
else result.type = LOCATION;
return result;
}
/*}}}*/
@ -408,16 +410,14 @@ static Token excel_adr_func(int argc, const Token argv[])
Token result;
char *usage = _("Usage: X&(THERE_LABEL, HERE_LABEL, [fix_x], [fix_y], [fix_z])");
if (argc < 2) {
result.type = EEK;
result.u.err = strdup(usage);
duperror(&result, usage);
return result;
}
if (argv[0].type == EEK) return argv[0];
if (argv[1].type == EEK) return argv[1];
if (argv[0].type != LOCATION || argv[1].type != LOCATION)
{
result.type = EEK;
result.u.err = strdup(usage);
duperror(&result, usage);
return result;
}
@ -432,8 +432,7 @@ static Token excel_adr_func(int argc, const Token argv[])
if (argv[i].type == EEK) return argv[i];
if (!INTPATIBLE(argv[i]))
{
result.type = EEK;
result.u.err = strdup(usage);
duperror(&result, usage);
return result;
}
if (argv[i].type == INT && argv[i].u.integer > 0) fixed = true;
@ -503,9 +502,7 @@ static Token bitwise_func(int argc, const Token argv[], LogicalFunction lop)
for (size_t i = 0; i < argc; ++i) {
if (!INTPATIBLE(argv[i]))
{
result.type = EEK;
result.u.err =
strdup(_("Bitwise functions operate only on integers."));
duperror(&result, _("Bitwise functions operate only on integers."));
return result;
}
int val = 0;
@ -541,15 +538,11 @@ static Token e_func(int argc, const Token argv[])
result.u.flt=CONST_E;
}
/*}}}*/
else /* result is e type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strdup(_("Usage: e()"));
}
/*}}}*/
else duperror(&result, _("Usage: e()"));
return result;
}
/*}}}*/
/* eval */ /*{{{*/
static Token eval_func(int argc, const Token argv[])
{
@ -558,13 +551,7 @@ static Token eval_func(int argc, const Token argv[])
/*}}}*/
--max_eval;
if (max_eval<0)
/* nesting error */ /*{{{*/
{
result.type=EEK;
result.u.err=strdup(_("nested eval()"));
}
/*}}}*/
if (max_eval<0) duperror(&result, _("nested eval()"));
else if (argc==1 && argv[0].type==LOCATION)
/* evaluate expression in cell at given position */ /*{{{*/
{
@ -577,13 +564,7 @@ static Token eval_func(int argc, const Token argv[])
else result=eval(contents);
}
/*}}}*/
else
/* eval type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_("Usage: eval(location)"))+1),_("Usage: eval(location)"));
}
/*}}}*/
else duperror(&result, _("Usage: eval(location)"));
++max_eval;
return result;
}
@ -599,15 +580,9 @@ static Token error_func(int argc, const Token argv[])
/* asserts */ /*{{{*/
assert(argv!=(Token*)0);
/*}}}*/
result.type=EEK;
if (argc!=1 || argv[0].type!=STRING)
/* result is type error */ /*{{{*/
result.u.err=strcpy(malloc(strlen(_("Usage: error(string message)"))+1),_("Usage: error(string message)"));
/*}}}*/
else
/* result is user defined error */ /*{{{*/
result.u.err=strcpy(malloc(strlen(argv[0].u.string)+1),argv[0].u.string);
/*}}}*/
if (argc != 1 || argv[0].type != STRING)
duperror(&result, _("Usage: error(string message)"));
else duperror(&result, argv[0].u.string);
return result;
}
/*}}}*/
@ -673,22 +648,21 @@ static Token string_func(int argc, const Token argv[])
}
/*}}}*/
else /* return string type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_("Usage: string(location) or string(float[,[integer][,integer]])"))+1),_("Usage: string(location) or string(float[,[integer][,integer]])"));
return result;
}
/*}}}*/
duperror(&result, _("Usage: string(location)|string(int)|string(float[,[int][,integer]])"));
return result;
}
/*}}}*/
/* sum */ /*{{{*/
static Token sum_func(int argc, const Token argv[])
{
/* variables */ /*{{{*/
Token result;
/*}}}*/
const char *usage = _("Usage: sum(loc_start, loc_end)|sum(val1, val2,...)");
if (argc == 0) {
duperror(&result, usage);
return result;
}
if (argc==2 && argv[0].type==LOCATION && argv[1].type==LOCATION) /* result is sum */ /*{{{*/
{
/* variables */ /*{{{*/
@ -714,17 +688,22 @@ static Token sum_func(int argc, const Token argv[])
result=tmp;
if (result.type==EEK) return result;
}
}
/*}}}*/
else /* result is sum type error */ /*{{{*/
} else {
Token tmp;
/* Try to add up the args */
result = tcopy(argv[0]);
for (size_t i = 1; i < argc; ++i)
{
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_("Usage: sum(location,location)"))+1),_("Usage: sum(location,location)"));
tmp = tadd(result, argv[i]);
tfree(&result);
result = tmp;
if (result.type == EEK) return result;
}
}
/*}}}*/
return result;
}
/*}}}*/
/* n */ /*{{{*/
static Token n_func(int argc, const Token argv[])
{
@ -759,13 +738,7 @@ static Token n_func(int argc, const Token argv[])
result.u.integer = n;
}
/*}}}*/
else
/* result is n type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_("Usage: n(location,location)"))+1),_("Usage: n(location,location)"));
}
/*}}}*/
else duperror(&result, _("Usage: n(location,location)"));
return result;
}
/*}}}*/
@ -813,29 +786,18 @@ static Token int_func(int argc, const Token argv[])
errno=0;
result.u.integer=strtol(argv[0].u.string,&s,10);
if (s==(char*)0 || *s)
{
result.type=EEK;
result.u.err=strdup(_("int(string): invalid string"));
}
else if (errno==ERANGE && (result.u.integer==LONG_MAX || result.u.integer==LONG_MIN))
{
result.type=EEK;
result.u.err=strdup(_("int(string): domain error"));
}
if (s==(char*)0 || *s) duperror(&result, _("int(string): invalid string"));
else if (errno==ERANGE &&
(result.u.integer==LONG_MAX || result.u.integer==LONG_MIN))
duperror(&result, _("int(string): domain error"));
else result.type=INT;
}
/*}}}*/
else
/* result is int type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_("Usage: int(float[,integer,integer])"))+1),_("Usage: int(float[,integer,integer])"));
}
/*}}}*/
else duperror(&result, _("Usage: int(float[,integer,integer])"));
return result;
}
/*}}}*/
/* frac */ /*{{{*/
static Token frac_func(int argc, const Token argv[])
{
@ -851,16 +813,11 @@ static Token frac_func(int argc, const Token argv[])
result.u.flt=modf(argv[0].u.flt,&foo);
}
/*}}}*/
else
/* result is frac type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_("Usage: frac(float)"))+1),_("Usage: frac(float)"));
}
/*}}}*/
else duperror(&result, _("Usage: frac(float)"));
return result;
}
/*}}}*/
/* len */ /*{{{*/
static Token len_func(int argc, const Token argv[])
{
@ -875,13 +832,7 @@ static Token len_func(int argc, const Token argv[])
result.u.integer=strlen(argv[0].u.string);
}
/*}}}*/
else
/* result is frac type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strdup(_("Usage: len(string)"));
}
/*}}}*/
else duperror(&result, _("Usage: len(string)"));
return result;
}
/*}}}*/
@ -919,15 +870,11 @@ static Token log_func(int argc, const Token argv[])
else result.u.flt=log(x)/log(y);
}
/*}}}*/
else /* result is log type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strdup(_("Usage: log(float[,float])"));
}
/*}}}*/
else duperror(&result, _("Usage: log(float[,float])"));
return result;
}
/*}}}*/
/* minmax */ /*{{{*/
static Token minmax_func(int argc, const Token argv[], int min)
{
@ -1005,15 +952,13 @@ static Token minmax_func(int argc, const Token argv[], int min)
return argv[mini];
}
else
/* result is min/max type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strdup(min ? _("Usage: min(location,location) or min(val1, val2,...)") : _("Usage: max(location,location) or max(val1,val2,...)"));
duperror(&result,
min ? _("Usage: min(location,location) or min(val1, val2,...)")
: _("Usage: max(location,location) or max(val1,val2,...)"));
return result;
}
/*}}}*/
}
/*}}}*/
/* min */ /*{{{*/
static Token min_func(int argc, const Token argv[])
{
@ -1047,13 +992,7 @@ static Token abs_func(int argc, const Token argv[])
result.u.integer=(argv[0].u.integer<0 ? -argv[0].u.integer : argv[0].u.integer);
}
/*}}}*/
else
/* result is abs type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strdup(_("Usage: abs(float|integer)"));
}
/*}}}*/
else duperror(&result, _("Usage: abs(float|integer)"));
return result;
}
/*}}}*/
@ -1072,14 +1011,11 @@ static Token env_func(int argc, const Token argv[])
result.type=STRING;
result.u.string=strdup(e);
}
else
{
result.type=EEK;
result.u.err=strdup(_("Usage: $(string)"));
}
else duperror(&result, _("Usage: $(string)"));
return result;
}
/*}}}*/
/* float */ /*{{{*/
static Token float_func(int argc, const Token argv[])
{
@ -1090,28 +1026,18 @@ static Token float_func(int argc, const Token argv[])
{
char *p;
result.u.flt=strtod(argv[0].u.string,&p);
if (p!=argv[0].u.string && *p=='\0' && dblfinite(result.u.flt)==(const char*)0)
{
result.type=FLOAT;
}
else
{
result.type=EEK;
result.u.err=strdup(_("Not a (finite) floating point number"));
}
}
/*}}}*/
else
/* float type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strdup(_("Usage: float(string)"));
result.u.flt = strtod(argv[0].u.string, &p);
if (p != argv[0].u.string && *p=='\0'
&& dblfinite(result.u.flt) == (const char*)0)
result.type = FLOAT;
else duperror(&result, _("Not a (finite) floating point number"));
}
/*}}}*/
else duperror(&result, _("Usage: float(string)"));
return result;
}
/*}}}*/
/* strftime */ /*{{{*/
static Token strftime_func(int argc, const Token argv[])
{
@ -1147,15 +1073,11 @@ static Token strftime_func(int argc, const Token argv[])
result.type=STRING;
}
/*}}}*/
else /* strftime type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strdup(_("Usage: strftime(string[,integer])"));
}
/*}}}*/
else duperror(&result, _("Usage: strftime(string[,integer])"));
return result;
}
/*}}}*/
/* clock */ /*{{{*/
static Token clock_func(int argc, const Token argv[])
{
@ -1191,132 +1113,137 @@ static Token clock_func(int argc, const Token argv[])
result.type=EMPTY;
}
/*}}}*/
else /* wrong usage */ /*{{{*/
{
result.type=EEK;
result.u.err=strdup(_("Usage: clock(condition,location[,location])"));
}
/*}}}*/
else duperror(&result, _("Usage: clock(condition,location[,location])"));
return result;
}
/*}}}*/
/* poly */ /*{{{*/
static Token poly_func(int argc, const Token argv[])
{
/* variables */ /*{{{*/
Token result;
int i;
/*}}}*/
Token result, tmp;
const char *usage = _("Usage: poly(float|integer,float|integer,...)");
for (i=0; i<argc; ++i) if (argc<2 || (argv[i].type!=INT && argv[i].type!=FLOAT)) /* type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strcpy(malloc(strlen(_("Usage: poly(float|integer,float|integer,...)"))+1),_("Usage: poly(float|integer,float|integer,...)"));
}
/*}}}*/
else
{
Token tmp;
result.type = EMPTY;
if (argc < 2) duperror(&result, usage);
else for (size_t i = 0; i < argc; ++i)
if (argv[i].type != INT && argv[i].type != FLOAT)
duperror(&result, usage);
if (result.type == EEK) return result;
result=tcopy(argv[1]);
for (i=2; i<argc; ++i)
result = tcopy(argv[1]);
for (size_t i = 2; i < argc; ++i)
{
tmp=tmul(result,argv[0]);
tmp = tmul(result,argv[0]);
tfree(&result);
result=tmp;
tmp=tadd(result,argv[i]);
result = tmp;
tmp = tadd(result,argv[i]);
tfree(&result);
result=tmp;
if (result.type==EEK) return result;
}
result = tmp;
if (result.type == EEK) return result;
}
return result;
}
/*}}}*/
/* sin */ /*{{{*/
static Token sin_func(int argc, const Token argv[])
{
return sci_func(argc,argv,sin,"sin");
}
/*}}}*/
/* cos */ /*{{{*/
static Token cos_func(int argc, const Token argv[])
{
return sci_func(argc,argv,cos,"cos");
}
/*}}}*/
/* tan */ /*{{{*/
static Token tan_func(int argc, const Token argv[])
{
return sci_func(argc,argv,tan,"tan");
}
/*}}}*/
/* sinh */ /*{{{*/
static Token sinh_func(int argc, const Token argv[])
{
return sci_func(argc,argv,sinh,"sinh");
}
/*}}}*/
/* cosh */ /*{{{*/
static Token cosh_func(int argc, const Token argv[])
{
return sci_func(argc,argv,cosh,"cosh");
}
/*}}}*/
/* tanh */ /*{{{*/
static Token tanh_func(int argc, const Token argv[])
{
return sci_func(argc,argv,tanh,"tanh");
}
/*}}}*/
/* asin */ /*{{{*/
static Token asin_func(int argc, const Token argv[])
{
return sci_func(argc,argv,asin,"asin");
}
/*}}}*/
/* acos */ /*{{{*/
static Token acos_func(int argc, const Token argv[])
{
return sci_func(argc,argv,acos,"acos");
}
/*}}}*/
/* atan */ /*{{{*/
static Token atan_func(int argc, const Token argv[])
{
return sci_func(argc,argv,atan,"atan");
}
/*}}}*/
/* arsinh */ /*{{{*/
static Token arsinh_func(int argc, const Token argv[])
{
return sci_func(argc,argv,arsinh,"arsinh");
}
/*}}}*/
/* arcosh */ /*{{{*/
static Token arcosh_func(int argc, const Token argv[])
{
return sci_func(argc,argv,arcosh,"arcosh");
}
/*}}}*/
/* artanh */ /*{{{*/
static Token artanh_func(int argc, const Token argv[])
{
return sci_func(argc,argv,artanh,"artanh");
}
/*}}}*/
/* rad2deg */ /*{{{*/
static Token rad2deg_func(int argc, const Token argv[])
{
return sci_func(argc,argv,rad2deg,"rad2deg");
}
/*}}}*/
/* deg2rad */ /*{{{*/
static Token deg2rad_func(int argc, const Token argv[])
{
return sci_func(argc,argv,deg2rad,"deg2rad");
}
/*}}}*/
/* rnd */ /*{{{*/
static Token rnd_func(int argc, const Token argv[])
{
@ -1329,14 +1256,11 @@ static Token rnd_func(int argc, const Token argv[])
result.type=FLOAT;
result.u.flt=rand()/((double)RAND_MAX);
}
else
{
result.type=EEK;
result.u.err=strdup(_("Usage: rnd()"));
}
else duperror(&result, _("Usage: rnd()"));
return result;
}
/*}}}*/
/* substr */ /*{{{*/
static Token substr_func(int argc, const Token argv[])
{
@ -1367,14 +1291,11 @@ static Token substr_func(int argc, const Token argv[])
result.type=EMPTY;
}
}
else
{
result.type=EEK;
result.u.err=strdup(_("Usage: substr(string,integer,integer)"));
}
else duperror(&result, _("Usage: substr(string,integer,integer)"));
return result;
}
/*}}}*/
/* strptime */ /*{{{*/
static Token strptime_func(int argc, const Token argv[])
{
@ -1394,15 +1315,11 @@ static Token strptime_func(int argc, const Token argv[])
result.type=INT;
}
/*}}}*/
else /* strftime type error */ /*{{{*/
{
result.type=EEK;
result.u.err=strdup(_("Usage: strptime(string,string)"));
}
/*}}}*/
else duperror(&result, _("Usage: strptime(string,string)"));
return result;
}
/*}}}*/
/* time */ /*{{{*/
static Token time_func(int argc, const Token argv[])
{
@ -1413,11 +1330,7 @@ static Token time_func(int argc, const Token argv[])
result.type=INT;
result.u.integer=time((time_t*)0);
}
else
{
result.type=EEK;
result.u.err=strdup(_("Usage: time()"));
}
else duperror(&result, _("Usage: time()"));
return result;
}
/*}}}*/

View File

@ -31,7 +31,7 @@ extern double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */
const char *Type_Name[] =
{ [EMPTY] = "EMPTY", [STRING] = "STRING", [FLOAT] = "FLOAT", [INT] = "INT",
[OPERATOR] = "OPERATOR", [LIDENT] = "LABEL", [FIDENT] = "FUNCTION",
[LOCATION] = "LOCATION", [EEK] = "ERROR"
[LOCATION] = "LOCATION", [FUNCALL] = "FUNCTION-CALL", [EEK] = "ERROR"
};
/* identcode -- return number of identifier */ /*{{{*/

View File

@ -11,7 +11,7 @@ extern "C" {
typedef enum {
EMPTY
#ifndef __cplusplus
, STRING, FLOAT, INT, OPERATOR, LIDENT, FIDENT, LOCATION, EEK
, STRING, FLOAT, INT, OPERATOR, LIDENT, FIDENT, LOCATION, FUNCALL, EEK
#endif
} Type;
@ -37,7 +37,16 @@ typedef enum { X=0, Y=1, Z=2, HYPER} Dimensions;
bool loc_in_box(const Location test,
const Location b, const Location c);
typedef struct Token_struc Token;
typedef struct
{
int fident;
int argc;
Token *argv;
} FunctionCall;
typedef struct Token_struc
{
Type type;
union
@ -49,6 +58,7 @@ typedef struct
char *lident;
int fident;
Location location;
FunctionCall funcall;
char *err;
} u;
} Token;