diff --git a/doc/teapot.lyx b/doc/teapot.lyx index 141df62..7c55552 100644 --- a/doc/teapot.lyx +++ b/doc/teapot.lyx @@ -5900,7 +5900,65 @@ env \series default evaluates to the contents of the specified environment variable. If the variable does not exist, then an empty string will be returned. +\end_layout + +\begin_layout Description +above|below|left|right|up|down +\series medium +[([location +\emph on + +\begin_inset space ~ +\end_inset + +l +\emph default +])] As bare words (without any arguments and also without the parentheses) + these symbols return a one-cell displacement in the named direction, e.g. +\family sans +\series bold +D +\series default +(above) +\family default +\series medium +gives the location of the same cell as the current on but in the previous + layer and +\family sans +\series bold +R +\series default +(up) +\family default +\series medium + yields the value of the cell one up from the current cell. + With parentheses, they act like +\series bold +@ +\series default +() +\series medium + but displaced by one cell in the named direction, so +\family sans +\series default +right() +\family default +\series medium + returns the value of the cell immediately to the right of the current one, + and +\family sans +\series default +down(MYTABLE) +\family default +\series medium + gives the value one line down from the cell labeled +\family sans +\series default +MYTABLE +\family default +\series medium +, etc. \end_layout \begin_layout Description @@ -6153,6 +6211,30 @@ x is given in radians. \end_layout +\begin_layout Description +below +\series medium +[([location +\emph on + +\begin_inset space ~ +\end_inset + +l +\emph default +])] displacement by one cell in the positive +\series default +\emph on +z +\emph default + direction; see the fuller description at +\family sans +\series bold +above +\series default +. +\end_layout + \begin_layout Description \series medium @@ -6385,6 +6467,30 @@ x \end_layout +\begin_layout Description +down +\series medium +[([location +\emph on + +\begin_inset space ~ +\end_inset + +l +\emph default +])] displacement by one cell in the positive +\series default +\emph on +y +\emph default + direction; see the fuller description at +\family sans +\series bold +above +\series default +. +\end_layout + \begin_layout Description \series medium @@ -6809,6 +6915,30 @@ trunc value is returned. \end_layout +\begin_layout Description +left +\series medium +[([location +\emph on + +\begin_inset space ~ +\end_inset + +l +\emph default +])] displacement by one cell in the negative +\series default +\emph on +x +\emph default + direction; see the fuller description at +\family sans +\series bold +above +\series default +. +\end_layout + \begin_layout Description \series medium @@ -7248,6 +7378,30 @@ x \end_layout +\begin_layout Description +right +\series medium +[([location +\emph on + +\begin_inset space ~ +\end_inset + +l +\emph default +])] displacement by one cell in the positive +\series default +\emph on +x +\emph default + direction; see the fuller description at +\family sans +\series bold +above +\series default +. +\end_layout + \begin_layout Description \series medium @@ -7882,6 +8036,23 @@ x ). \end_layout +\begin_layout Description +up +\series medium +[([location +\emph on + +\begin_inset space ~ +\end_inset + +l +\emph default +])] displacement by one cell in the negative +\series default +\emph on +y +\end_layout + \begin_layout Description \series medium @@ -8405,28 +8576,61 @@ func – in the former case it receives an argument count of 0, and in the latter an argument count of -1. So the same symbol can have different semantics depending on which way - it is called, but in most cases that would probably be counterintuitive. - The no-parentheses form is useful, however, for constants like + it is called. + In most cases such a difference is counterintuitive, but it seems to work + fairly well for the directional \begin_inset Quotes eld \end_inset -e, +constants, \begin_inset Quotes erd \end_inset - and it is also used to allow, for example, the names of the functions + i.e. + bare \begin_inset Quotes eld \end_inset -floor, -\begin_inset Quotes eld -\end_inset - -round, +left \begin_inset Quotes erd \end_inset - etc. + is the displacement &(-1,0,0), whereas left() is the location one to the + left. + The no-parentheses form is also useful for constants like +\begin_inset Quotes eld +\end_inset + +e +\begin_inset Quotes erd +\end_inset + + and +\begin_inset Quotes eld +\end_inset + +tau +\begin_inset Quotes erd +\end_inset + +, and it is also used, for example, to allow the names of the functions + +\begin_inset Quotes eld +\end_inset + +floor +\begin_inset Quotes erd +\end_inset + +, +\begin_inset Quotes eld +\end_inset + +round +\begin_inset Quotes erd +\end_inset + +, etc. to be used as keywords for the int() function. \end_layout diff --git a/src/common/eval.c b/src/common/eval.c index ffbfd21..e53bb49 100644 --- a/src/common/eval.c +++ b/src/common/eval.c @@ -513,12 +513,28 @@ Token tmul(Token l, Token r) else result.u.flt = l.u.flt * ((FltT)r.u.integer); } /*}}}*/ + else if ((l.type == EMPTY && r.type == LOCATION) + || (l.type == LOCATION && r.type == EMPTY)) + /* result is 0 location */ /*{{{*/ + { + result.type = LOCATION; + OLOCATION(result.u.location); + } + /*}}}*/ else if (l.type == LOCATION && r.type == INT) /* result is each component of location times right */ /*{{{*/ { result.type = LOCATION; - for (size_t len = 0; len < 3; ++len) - result.u.location[len] = l.u.location[len] * r.u.integer; + for (Dimensions dim = X; dim < HYPER; ++dim) + result.u.location[dim] = l.u.location[dim] * r.u.integer; + } + /*}}}*/ + else if (l.type == INT && r.type == LOCATION) + /* result is each component of right location times left */ /*{{{*/ + { + result.type = LOCATION; + for (Dimensions dim = X; dim < HYPER; ++dim) + result.u.location[dim] = l.u.integer * r.u.location[dim]; } /*}}}*/ else if (l.type == LOCATION && r.type == LOCATION) @@ -526,8 +542,8 @@ Token tmul(Token l, Token r) { result.type = INT; result.u.integer = 0; - for (size_t len = 0; len < 3; ++len) - result.u.integer += l.u.location[len] * r.u.location[len]; + for (Dimensions dim = X; dim < HYPER; ++dim) + result.u.integer += l.u.location[dim] * r.u.location[dim]; } /*}}}*/ else if ((l.type == INT && r.type == STRING) @@ -681,9 +697,9 @@ Token tpow(Token l, Token r) /*}}}*/ /* tfuncall -- function operator */ /*{{{*/ -Token tfuncall(int fident, int argc, Token argv[]) +Token tfuncall(FunctionIdentifier fident, int argc, Token argv[]) { - return tfunc[fident].func(argc, argv); + return tfunc[fident].func(fident, argc, argv); } /*}}}*/ diff --git a/src/common/eval.h b/src/common/eval.h index 50c2eaf..b508353 100644 --- a/src/common/eval.h +++ b/src/common/eval.h @@ -17,7 +17,7 @@ Token tadd(Token l, Token r); Token tconcat(Token l, Token r); Token tsub(Token l, Token r); Token tneg(Token x); -Token tfuncall(int fident, int argc, Token argv[]); +Token tfuncall(FunctionIdentifier fident, int argc, Token argv[]); Token tlt(Token l, Token r); Token tle(Token l, Token r); Token tge(Token l, Token r); diff --git a/src/common/func.c b/src/common/func.c index 9fff2dc..83657e2 100644 --- a/src/common/func.c +++ b/src/common/func.c @@ -245,7 +245,8 @@ FunctionIdentifier identcode(const char *s, size_t len) /* sci_func -- map a double to a double */ /*{{{*/ -static Token sci_func(int argc, const Token argv[], FltT (*func)(FltT), const char *func_name) +static Token sci_func(int argc, const Token argv[], FltT (*func)(FltT), + const char *func_name) { Token result; @@ -324,105 +325,14 @@ static FltT deg2rad(FltT x) } /*}}}*/ -typedef enum {ABSOLUTE, RELATIVE, EXCEL} LocConvention; - -static Token excel_adr_func(int argc, const Token argv[]); - -/* & */ /*{{{*/ -static Token adr_func(int argc, const Token argv[], LocConvention lcon) +/* fracpart */ /*{{{*/ +static FltT fracpart(FltT x) { - /* variables */ /*{{{*/ - Token result; - Dimensions dim; - /*}}}*/ - - if (lcon == EXCEL) return excel_adr_func(argc, argv); - - /* asserts */ /*{{{*/ - assert(argc < 1 || argv != NULLTOKEN); - /*}}}*/ - - result.type = LOCATION; - LOCATION_GETS(result.u.location, upd_l); - int offset = 0; - if (argc > 0 && argv[0].type == LOCATION) - { - if (argc == 1 && lcon == RELATIVE) - { - LOCATION_ADD(result.u.location, argv[0].u.location); - return result; - } - LOCATION_GETS(result.u.location, argv[0].u.location); - offset = 1; - } - int i = offset; - while (i < argc && i - offset < HYPER) - { - if (argv[i].type == EEK) return argv[i]; - if (argv[i].type == INT) - if (lcon == ABSOLUTE) result.u.location[i-offset] = argv[i].u.integer; - else result.u.location[i-offset] += argv[i].u.integer; - else if (argv[i].type != EMPTY) break; - ++i; - } - if (i < argc) - duperror(&result, - _("Usage: &([location l,][integer x][,[integer y][,[integer z]]])")); - return result; + FltT intpart; + return MODFFLT(x, &intpart); } /*}}}*/ -/* @ */ /*{{{*/ -static Token at_func(int argc, const Token argv[], LocConvention lcon) -{ - Token location; - - location = adr_func(argc, argv, lcon); - if (location.type == EEK) - { - Token result; - result.type = EEK; - char *pref = _("Inside @: "); - if (lcon == RELATIVE) pref = _("Inside R(): "); - if (lcon == EXCEL) pref = _("Inside X(): "); - result.u.err = malloc(strlen(location.u.err) + strlen(pref) + 1); - strcpy(result.u.err, pref); - strcat(result.u.err, location.u.err); - /* don't free the location if it is the same as an argument, because - those get freed later: */ - for (int i = 0; i < argc; ++i) - if (argv[i].type == EEK & argv[i].u.err == location.u.err) return result; - tfree(&location); - return result; - } - return recompvalue(upd_sheet, location.u.location); -} - -static Token abs_adr_func(int argc, const Token argv[]) -{ - return adr_func(argc, argv, ABSOLUTE); -} - -static Token abs_at_func(int argc, const Token argv[]) -{ - return at_func(argc, argv, ABSOLUTE); -} - -static Token rel_adr_func(int argc, const Token argv[]) -{ - return adr_func(argc, argv, RELATIVE); -} - -static Token rel_at_func(int argc, const Token argv[]) -{ - return at_func(argc, argv, RELATIVE); -} - -static Token excel_at_func(int argc, const Token argv[]) -{ - return at_func(argc, argv, EXCEL); -} - #define INTPATIBLE(t) (t.type == INT || t.type == EMPTY) static Token excel_adr_func(int argc, const Token argv[]) @@ -455,9 +365,130 @@ static Token excel_adr_func(int argc, const Token argv[]) return result; } -/* dim_func -- common implementation of the coordinate functions */ /*{{{*/ -static Token dim_func(int argc, const Token argv[], Dimensions dim) +/* & */ /*{{{*/ +static Token adr_func(FunctionIdentifier self, int argc, const Token argv[]) { + bool absolute = true; + switch (self) { + case FUNC_AMPERSAND: break; + case FUNC_D: absolute = false; break; + case FUNC_X_AMPERSAND: return excel_adr_func(argc, argv); + default: assert(0); + } + + assert(argc < 1 || argv != NULLTOKEN); + + Token result; + result.type = LOCATION; + LOCATION_GETS(result.u.location, upd_l); + int offset = 0; + if (argc > 0 && argv[0].type == LOCATION) + { + if (argc == 1 && !absolute) + { + LOCATION_ADD(result.u.location, argv[0].u.location); + return result; + } + LOCATION_GETS(result.u.location, argv[0].u.location); + offset = 1; + } + int i = offset; + while (i < argc && i - offset < HYPER) + { + if (argv[i].type == EEK) return argv[i]; + if (argv[i].type == INT) + if (absolute) result.u.location[i-offset] = argv[i].u.integer; + else result.u.location[i-offset] += argv[i].u.integer; + else if (argv[i].type != EMPTY) break; + ++i; + } + if (i < argc) { + const char *templ = + _("Usage: %s([location l,][integer x][,[integer y][,[integer z]]])"); + result.type = EEK; + result.u.err = malloc(strlen(templ) + MAX_FUNC_NAME_LENGTH + 1); + sprintf(result.u.err, templ, tfunc[self].name); + } + return result; +} +/*}}}*/ + +/* @ */ /*{{{*/ +static Token at_func(FunctionIdentifier self, int argc, const Token argv[]) +{ + FunctionIdentifier sub = FUNC_AMPERSAND; + switch (self) { + case FUNC_AT_SYMBOL: break; + case FUNC_R: sub = FUNC_D; break; + case FUNC_CAP_X: sub = FUNC_X_AMPERSAND; break; + default: assert(0); + } + + Token location = adr_func(sub, argc, argv); + if (location.type == EEK) + { + Token result; + result.type = EEK; + char *templ = _("Inside %s(): %s"); + result.u.err = malloc(strlen(templ) + MAX_FUNC_NAME_LENGTH + + strlen(location.u.err) + 1); + sprintf(result.u.err, templ, tfunc[self].name, location.u.err); + /* don't free the location if it is the same as an argument, because + those get freed later: */ + for (int i = 0; i < argc; ++i) + if (argv[i].type == EEK & argv[i].u.err == location.u.err) return result; + tfree(&location); + return result; + } + assert(location.type == LOCATION); + return recompvalue(upd_sheet, location.u.location); +} + +/* disp_func -- common implementation of the displacement functions */ /*{{{*/ +static Token disp_func(FunctionIdentifier self, int argc, const Token argv[]) +{ + Token off; + off.type = LOCATION; + OLOCATION(off.u.location); + switch (self) { + case FUNC_RIGHT: off.u.location[X] = 1; break; + case FUNC_LEFT: off.u.location[X] = -1; break; + case FUNC_DOWN: off.u.location[Y] = 1; break; + case FUNC_UP: off.u.location[Y] = -1; break; + case FUNC_BELOW: off.u.location[Z] = 1; break; + case FUNC_ABOVE: off.u.location[Z] = -1; break; + default: assert(0); + } + switch (argc) { + case -1: return off; + case 0: + LOCATION_ADD(off.u.location, upd_l); + return recompvalue(upd_sheet, off.u.location); + case 1: + if (argv[0].type == LOCATION) { + LOCATION_ADD(off.u.location, argv[0].u.location); + return recompvalue(upd_sheet, off.u.location); + } + /* drop through */ + default: break; + } + const char* usage = _("Usage: %s[([location])]"); + off.type = EEK; + off.u.err = malloc(strlen(usage) + MAX_FUNC_NAME_LENGTH + 1); + sprintf(off.u.err, usage, tfunc[self].name); + return off; +} + +/* dim_func -- common implementation of the coordinate functions */ /*{{{*/ +static Token dim_func(FunctionIdentifier self, int argc, const Token argv[]) +{ + Dimensions dim = X; + switch (self) { + case FUNC_X: break; + case FUNC_Y: dim = Y; break; + case FUNC_Z: dim = Z; break; + default: assert(0); + } Token result; result.type = INT; @@ -481,97 +512,51 @@ static Token dim_func(int argc, const Token argv[], Dimensions dim) } /*}}}/ -/* x */ /*{{{*/ -static Token x_func(int argc, const Token argv[]) -{ - return dim_func(argc, argv, X); -} -/*}}}*/ - -/* y */ /*{{{*/ -static Token y_func(int argc, const Token argv[]) -{ - return dim_func(argc, argv, Y); -} -/*}}}*/ - -/* z */ /*{{{*/ -static Token z_func(int argc, const Token argv[]) -{ - return dim_func(argc, argv, Z); -} -/*}}}*/ - -typedef enum { LOG_AND, LOG_OR } LogicalFunction; - -static Token bitwise_func(int argc, const Token argv[], LogicalFunction lop) +/* bit_func -- common implementation of the bitwise functions */ /*{{{*/ +static Token bit_func(FunctionIdentifier self, int argc, const Token argv[]) { Token result; int accum; - if (lop == LOG_AND) accum = -1; + if (self == FUNC_BITAND) accum = -1; else accum = 0; for (size_t i = 0; i < argc; ++i) { if (!INTPATIBLE(argv[i])) return duperror(&result, _("Bitwise functions need integer arguments.")); int val = 0; if (argv[i].type == INT) val = argv[i].u.integer; - if (lop == LOG_AND) accum = accum & val; + if (self == FUNC_BITAND) accum = accum & val; else accum = accum | val; } result.type = INT; result.u.integer = accum; return result; } - -static Token bitand_func(int argc, const Token argv[]) -{ - return bitwise_func(argc, argv, LOG_AND); -} - -static Token bitor_func(int argc, const Token argv[]) -{ - return bitwise_func(argc, argv, LOG_OR); -} - -/* e */ /*{{{*/ -static Token e_func(int argc, const Token argv[]) -{ - /* variables */ /*{{{*/ - Token result; - /*}}}*/ - - if (argc < 1) /* result is constant e */ /*{{{*/ - { - result.type = FLOAT; - result.u.flt = CONST_E; - return result; - } - - return duperror(&result, _("Usage: e()")); -} /*}}}*/ -/* tau = 2pi */ /*{{{*/ -static Token tau_func(int argc, const Token argv[]) +/* constant_func - common implementation of constants */ /*{{{*/ +static Token constant_func(FunctionIdentifier fi, int argc, const Token argv[]) { - /* variables */ /*{{{*/ Token result; - /*}}}*/ - - if (argc < 1) /* result is constant e */ /*{{{*/ - { + if (argc < 1) { result.type = FLOAT; - result.u.flt = 2.0*CONST_PI; + switch (fi) { + case FUNC_E: result.u.flt = CONST_E; + case FUNC_TAU: result.u.flt = 2*CONST_PI; + default: assert(0); + } return result; } - - return duperror(&result, _("Usage: tau()")); + const char *usage = _("Usage: %s[()]"); + result.type = EEK; + result.u.err = malloc(strlen(usage) + MAX_FUNC_NAME_LENGTH + 1); + sprintf(result.u.err, usage, tfunc[fi].name); } /*}}}*/ /* eval */ /*{{{*/ -static Token eval_func(int argc, const Token argv[]) +static Token eval_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_EVAL); /* variables */ /*{{{*/ Token result; /*}}}*/ @@ -597,8 +582,9 @@ static Token eval_func(int argc, const Token argv[]) /*}}}*/ /* error */ /*{{{*/ -static Token error_func(int argc, const Token argv[]) +static Token error_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_ERROR); /* variables */ /*{{{*/ Token result; /*}}}*/ @@ -613,8 +599,9 @@ static Token error_func(int argc, const Token argv[]) } /*}}}*/ /* string */ /*{{{*/ -static Token string_func(int argc, const Token argv[]) +static Token string_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_STRING); /* variables */ /*{{{*/ Token result; const char *usage = _("Usage: string(x[,[int prec][,format_for_floats]])"); @@ -652,83 +639,155 @@ static Token string_func(int argc, const Token argv[]) } /*}}}*/ -/* plus */ /*{{{*/ -static Token concat_func(int argc, const Token argv[]) +/* accum_func -- common implementation of functions that accumulate all of + their arguments into a final value. +*/ +static Token accum_func(FunctionIdentifier self, int argc, const Token argv[]) { - Token result, tmp; - /* Try to add up the args */ - result.type = EMPTY; - for (size_t i = 0; i < argc; ++i) - { - tmp = tconcat(result, argv[i]); - tfree(&result); - result = tmp; - if (result.type == EEK) return result; + Token (*tbin)(Token, Token); + int start = 0; + switch (self) { + case FUNC_CONCAT: tbin = tconcat; break; + case FUNC_PLUS_SYMBOL: tbin = tadd; break; + case FUNC_ASTERISK: tbin = tmul; start = 1; break; + case FUNC_CARET: tbin = tpow; start = 1; break; + default: assert(0); } - return result; -} -/*}}}*/ - -/* plus */ /*{{{*/ -static Token plus_func(int argc, const Token argv[]) -{ - Token result, tmp; - /* Try to add up the args */ - result.type = EMPTY; - if (argc > 0) result = tcopy(argv[0]); - for (size_t i = 1; i < argc; ++i) - { - tmp = tadd(result, argv[i]); - tfree(&result); - result = tmp; - if (result.type == EEK) return result; - } - return result; -} -/*}}}*/ - -/* sum */ /*{{{*/ -static Token sum_func(int argc, const Token argv[]) -{ Token result; - const char *usage = _("Usage: sum(loc_start, loc_end)|sum(val1, val2,...)"); + result.type = EMPTY; + if (start > 0) { result = tcopy(argv[start-1]); } + for (int i = start; i < argc; ++i) { + Token tmp = tbin(result, argv[i]); + tfree(&result); + result = tmp; + if (result.type == EEK) return result; + } + return result; +} - if (argc <= 0) return duperror(&result, usage); +typedef void (*RegFuncInit)(FunctionIdentifier id, Location *loc, Token *tok); +typedef void (*RegFuncUpdt)(FunctionIdentifier id, Location *loc, Token *tok, + const Location *newloc, const Token* newtok); +typedef void (*RegFuncFinl)(FunctionIdentifier id, Location *loc, Token *tok); + +/* region_func -- apply an operation over a whole region */ +static Token region_func(RegFuncInit init, RegFuncUpdt updt, RegFuncFinl finl, + FunctionIdentifier id, int argc, const Token argv[]) +{ if (argc == 2 && argv[0].type == LOCATION && argv[1].type == LOCATION) - /* result is sum of entries in range */ /*{{{*/ { - /* variables */ /*{{{*/ - Location w; - int x1,y1,z1; - int x2,y2,z2; - Token tmp; - /*}}}*/ + int x1 = argv[0].u.location[X]; + int x2 = argv[1].u.location[X]; + posorder(&x1, &x2); + int y1 = argv[0].u.location[Y]; + int y2 = argv[1].u.location[Y]; + posorder(&y1, &y2); + int z1 = argv[0].u.location[Z]; + int z2 = argv[1].u.location[Z]; + posorder(&z1,&z2); - x1=argv[0].u.location[0]; x2=argv[1].u.location[0]; posorder(&x1,&x2); - y1=argv[0].u.location[1]; y2=argv[1].u.location[1]; posorder(&y1,&y2); - z1=argv[0].u.location[2]; z2=argv[1].u.location[2]; posorder(&z1,&z2); - result.type = EMPTY; + Location l; l[X] = x1; l[Y] = y1; l[Z] = z1; + Token t = recompvalue(upd_sheet, l); + if (init != (RegFuncInit)0) init(id, &l, &t); + if (t.type == EEK) return t; + + Location w; for (w[X]=x1; w[X]<=x2; ++(w[X])) for (w[Y]=y1; w[Y]<=y2; ++(w[Y])) for (w[Z]=z1; w[Z]<=z2; ++(w[Z])) { - Token t; - - tmp = tadd(result, t=recompvalue(upd_sheet,w)); - tfree(&t); - tfree(&result); - result=tmp; - if (result.type==EEK) return result; + Token tmp = recompvalue(upd_sheet, w); + updt(id, &l, &t, &w, &tmp); + tfree_protected(&tmp, t); + if (t.type == EEK) return t; } - return result; + if (finl != (RegFuncFinl)0) finl(id, &l, &t); + return t; } - return plus_func(argc, argv); + if (argc > 0) /* try to accumulate over all arguments */ + { + Location l; OLOCATION(l); + Token t = argv[0]; + if (init != (RegFuncInit)0) init(id, &l, &t); + for (int i = 0; i < argc; ++i) { + Location fake; OLOCATION(fake); fake[X] = i; + updt(id, &l, &t, &fake, argv + i); + if (t.type == EEK) return t; + } + /* don't call finalize in this case because the region is fake */ + return t; + } + const char* templ = _("Usage:%s(loc_start,loc_end)|%s(val2,val2,...)"); + Token err; + err.type = EEK; + err.u.err = malloc(strlen(templ) + 2*MAX_FUNC_NAME_LENGTH + 1); + sprintf(err.u.err, templ, tfunc[id].name, tfunc[id].name); + return err; } -/*}}}*/ -/* n */ /*{{{*/ -static Token n_func(int argc, const Token argv[]) +static void sum_init(FunctionIdentifier id, Location *loc, Token *tok) { + assert(id == FUNC_SUM); + tfree(tok); + tok->type = EMPTY; +} + +static void sum_updt(FunctionIdentifier id, Location *loc, Token *tok, + const Location* newloc, const Token *newtok) +{ + assert(id == FUNC_SUM); + Token tmp = tadd(*tok, *newtok); + tfree(tok); + *tok = tmp; +} + +static void minmax_updt(FunctionIdentifier id, Location *loc, Token *tok, + const Location* newloc, const Token *newtok) +{ + Token tmp = (id == FUNC_MIN) ? tle(*tok, *newtok) : tge(*tok, *newtok); + if (tmp.type == INT) /* Succesful comparison */ + { + if (tmp.u.integer == 0) + { + tfree(tok); + *tok = *newtok; + LOCATION_GETS(*loc, *newloc); + } + tfree(&tmp); + } else { /* failed comparison */ + tfree(tok); + *tok = tmp; + } +} + +static void minmax_finl(FunctionIdentifier id, Location *loc, Token *tok) +{ + tfree(tok); + tok->type = LOCATION; + LOCATION_GETS(tok->u.location, *loc); +} + +static Token reg_disp(FunctionIdentifier self, int argc, const Token argv[]) +{ + RegFuncInit i = 0; + RegFuncUpdt u = 0; + RegFuncFinl f = 0; + switch (self) { + case FUNC_SUM: + i = sum_init; u = sum_updt; break; + case FUNC_MIN: + case FUNC_MAX: + u = minmax_updt; f = minmax_finl; break; + default: assert(0); + } + return region_func(i, u, f, self, argc, argv); +} + +/* n -- return whether a value is non-empty, or count the number of + non-empty values in a region or in the argument list */ /*{{{*/ +static Token n_func(FunctionIdentifier self, int argc, const Token argv[]) +{ + assert(self == FUNC_N); /* variables */ /*{{{*/ Token result; const char *usage = _("Usage: n([location[,location]])|n(val1,val2,...)"); @@ -789,106 +848,35 @@ static Token n_func(int argc, const Token argv[]) } /*}}}*/ -/* mul */ /*{{{*/ -static Token mul_func(int argc, const Token argv[]) +/* binop_func -- common implementation of all binary operations + as function calls */ /*{{{*/ +static Token binop_func(FunctionIdentifier self, int argc, const Token argv[]) { - Token result, tmp; - /* Try to multiply up the args */ - result.type = EMPTY; - if (argc > 0) result = tcopy(argv[0]); - for (size_t i = 1; i < argc; ++i) - { - tmp = tmul(result, argv[i]); - tfree(&result); - result = tmp; - if (result.type == EEK) return result; + Token (*tbin)(Token, Token); + switch (self) { + case FUNC_MINUS_SYMBOL: tbin = tsub; break; + case FUNC_SLASH: tbin = tdiv; break; + case FUNC_LESS_EQUAL: tbin = tle; break; + case FUNC_GREATER_EQUAL: tbin = tge; break; + case FUNC_LESS_THAN: tbin = tlt; break; + case FUNC_GREATER_THAN: tbin = tgt; break; + case FUNC_EQUAL_EQUAL: tbin = teq; break; + case FUNC_TILDE_EQUAL: tbin = tabouteq; break; + case FUNC_BANG_EQUAL: tbin = tne; break; + case FUNC_PER_CENT: tbin = tmod; break; + default: assert(0); } - return result; -} -/*}}}*/ - -/* pow */ /*{{{*/ -static Token pow_func(int argc, const Token argv[]) -{ - Token result, tmp; - /* Try to power up the args, ((a^b)^c)^d etc */ - result.type = EMPTY; - if (argc > 0) result = tcopy(argv[0]); - for (size_t i = 1; i < argc; ++i) - { - tmp = tpow(result, argv[i]); - tfree(&result); - result = tmp; - if (result.type == EEK) return result; - } - return result; -} -/*}}}*/ - -/* binop_func -- handles all binary operations as function calls */ -static Token binop_func(int argc, const Token argv[], - Token (*tfunc)(Token, Token)) /*{{{*/ -{ - if (argc == 2) return tfunc(argv[0], argv[1]); + if (argc == 2) return tbin(argv[0], argv[1]); Token err; return duperror(&err, _("Binary infix op as function requires exactly 2 args")); } /*}}}*/ -static Token minus_func(int argc, const Token argv[]) -{ - return binop_func(argc, argv, tsub); -} - -static Token div_func(int argc, const Token argv[]) -{ - return binop_func(argc, argv, tdiv); -} - -static Token le_func(int argc, const Token argv[]) -{ - return binop_func(argc, argv, tle); -} - -static Token ge_func(int argc, const Token argv[]) -{ - return binop_func(argc, argv, tge); -} - -static Token lt_func(int argc, const Token argv[]) -{ - return binop_func(argc, argv, tlt); -} - -static Token gt_func(int argc, const Token argv[]) -{ - return binop_func(argc, argv, tgt); -} - -static Token isequal_func(int argc, const Token argv[]) -{ - return binop_func(argc, argv, teq); -} - -static Token abouteq_func(int argc, const Token argv[]) -{ - return binop_func(argc, argv, tabouteq); -} - -static Token ne_func(int argc, const Token argv[]) -{ - return binop_func(argc, argv, tne); -} - -static Token mod_func(int argc, const Token argv[]) -{ - return binop_func(argc, argv, tmod); -} - /* int */ /*{{{*/ -static Token int_func(int argc, const Token argv[]) +static Token int_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_INT); /* variables */ /*{{{*/ Token result; /*}}}*/ @@ -935,29 +923,10 @@ static Token int_func(int argc, const Token argv[]) } /*}}}*/ -/* frac */ /*{{{*/ -static Token frac_func(int argc, const Token argv[]) -{ - /* variables */ /*{{{*/ - Token result; - FltT foo; - /*}}}*/ - - if (argc==1 && argv[0].type==FLOAT) - /* result is fractional part */ /*{{{*/ - { - result.type = FLOAT; - result.u.flt = MODFFLT(argv[0].u.flt, &foo); - } - /*}}}*/ - else duperror(&result, _("Usage: frac(float)")); - return result; -} -/*}}}*/ - /* len */ /*{{{*/ -static Token len_func(int argc, const Token argv[]) +static Token len_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_LEN); /* variables */ /*{{{*/ Token result; /*}}}*/ @@ -973,9 +942,11 @@ static Token len_func(int argc, const Token argv[]) return result; } /*}}}*/ + /* log */ /*{{{*/ -static Token log_func(int argc, const Token argv[]) +static Token log_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_LOG); /* variables */ /*{{{*/ FltT x=-1.0, y=-1.0; Token result; @@ -1013,105 +984,10 @@ static Token log_func(int argc, const Token argv[]) } /*}}}*/ -/* minmax */ /*{{{*/ -static Token minmax_func(int argc, const Token argv[], int min) -{ - /* variables */ /*{{{*/ - Token result, tmp; - Location minloc; - /*}}}*/ - - if (argc==2 && argv[0].type==LOCATION && argv[1].type==LOCATION) - /* result is min/max */ /*{{{*/ - { - /* variables */ /*{{{*/ - Location w; - int x1,y1,z1; - int x2,y2,z2; - /*}}}*/ - - x1=argv[0].u.location[0]; x2=argv[1].u.location[0]; posorder(&x1,&x2); - y1=argv[0].u.location[1]; y2=argv[1].u.location[1]; posorder(&y1,&y2); - z1=argv[0].u.location[2]; z2=argv[1].u.location[2]; posorder(&z1,&z2); - - minloc[X] = x1; minloc[Y] = y1; minloc[Z] = z1; - result = recompvalue(upd_sheet, minloc); - - for (w[X]=x1; w[X]<=x2; ++(w[X])) - for (w[Y]=y1; w[Y]<=y2; ++(w[Y])) - for (w[Z]=z1; w[Z]<=z2; ++(w[Z])) - { - Token t; - - t = recompvalue(upd_sheet, w); - tmp = (min ? tle(result,t) : tge(result, t)); - if (tmp.type == INT) - /* successful comparison */ /*{{{*/ - { - if (tmp.u.integer == 0) - { - tfree(&result); - result = t; - LOCATION_GETS(minloc, w); - } - else tfree(&t); - tfree(&tmp); - } - /*}}}*/ - else - /* successless comparison, return with error */ /*{{{*/ - { - tfree(&result); - tfree(&t); - return tmp; - } - /*}}}*/ - } - tfree(&result); - result.type=LOCATION; - LOCATION_GETS(result.u.location, minloc); - return result; - } - /*}}}*/ - else if (argc > 0) /* try to take min/max of all arguments */ - { - size_t i, mini; - mini = 0; - for (i = 1; i < argc; ++i) { - tmp = (min ? tlt(argv[i], argv[mini]) : tgt(argv[i], argv[mini])); - if (tmp.type == INT) /* comparison succeeded */ - { - if (tmp.u.integer) mini = i; - tfree(&tmp); - } - else /* failed comparison, return the error */ - return tmp; - } - return argv[mini]; - } - else - 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[]) -{ - return minmax_func(argc,argv,1); -} -/*}}}*/ -/* max */ /*{{{*/ -static Token max_func(int argc, const Token argv[]) -{ - return minmax_func(argc,argv,0); -} -/*}}}*/ /* abs */ /*{{{*/ -static Token abs_func(int argc, const Token argv[]) +static Token abs_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_ABS); /* variables */ /*{{{*/ Token result; /*}}}*/ @@ -1134,9 +1010,11 @@ static Token abs_func(int argc, const Token argv[]) return result; } /*}}}*/ + /* $ */ /*{{{*/ -static Token env_func(int argc, const Token argv[]) +static Token env_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_DOLLAR_SIGN); /* variables */ /*{{{*/ Token result; /*}}}*/ @@ -1155,8 +1033,9 @@ static Token env_func(int argc, const Token argv[]) /*}}}*/ /* float */ /*{{{*/ -static Token float_func(int argc, const Token argv[]) +static Token float_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_FLOAT); Token result; const char *usage = _("Usage: float(string|int)"); @@ -1184,8 +1063,9 @@ static Token float_func(int argc, const Token argv[]) /*}}}*/ /* strftime */ /*{{{*/ -static Token strftime_func(int argc, const Token argv[]) +static Token strftime_func(FunctionIdentifier fi, int argc, const Token argv[]) { + assert(fi == FUNC_STRFTIME); /* variables */ /*{{{*/ Token result; /*}}}*/ @@ -1224,8 +1104,9 @@ static Token strftime_func(int argc, const Token argv[]) /*}}}*/ /* clock */ /*{{{*/ -static Token clock_func(int argc, const Token argv[]) +static Token clock_func(FunctionIdentifier self,int argc, const Token argv[]) { + assert(self == FUNC_CLOCK); /* variables */ /*{{{*/ Token result; /*}}}*/ @@ -1264,8 +1145,9 @@ static Token clock_func(int argc, const Token argv[]) /*}}}*/ /* poly */ /*{{{*/ -static Token poly_func(int argc, const Token argv[]) +static Token poly_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_POLY); Token result, tmp; const char *usage = _("Usage: poly(float|integer,float|integer,...)"); @@ -1290,197 +1172,70 @@ static Token poly_func(int argc, const Token argv[]) } /*}}}*/ -/* sqrt */ /*{{{*/ -static Token sqrt_func(int argc, const Token argv[]) +static Token sci_disp(FunctionIdentifier self, int argc, const Token argv[]) { - return sci_func(argc, argv, SQRTFLT, "sqrt"); + FltT (*fsci)(FltT); + switch (self) { + case FUNC_SQRT: fsci = SQRTFLT; break; + case FUNC_SIN: fsci = SINFLT; break; + case FUNC_COS: fsci = COSFLT; break; + case FUNC_TAN: fsci = TANFLT; break; + case FUNC_SINH: fsci = SINHFLT; break; + case FUNC_COSH: fsci = COSHFLT; break; + case FUNC_TANH: fsci = TANHFLT; break; + case FUNC_ASIN: fsci = ASINFLT; break; + case FUNC_ACOS: fsci = ACOSFLT; break; + case FUNC_ATAN: fsci = ATANFLT; break; + case FUNC_ARSINH: fsci = arsinh; break; + case FUNC_ARCOSH: fsci = arcosh; break; + case FUNC_ARTANH: fsci = artanh; break; + case FUNC_RAD2DEG: fsci = rad2deg; break; + case FUNC_DEG2RAD: fsci = deg2rad; break; + case FUNC_FRAC: fsci = fracpart; break; + default: assert(0); + } + return sci_func(argc, argv, fsci, tfunc[self].name); } -/* sin */ /*{{{*/ -static Token sin_func(int argc, const Token argv[]) -{ - return sci_func(argc, argv, SINFLT, "sin"); -} -/*}}}*/ - -/* cos */ /*{{{*/ -static Token cos_func(int argc, const Token argv[]) -{ - return sci_func(argc, argv, COSFLT, "cos"); -} -/*}}}*/ - -/* tan */ /*{{{*/ -static Token tan_func(int argc, const Token argv[]) -{ - return sci_func(argc, argv, TANFLT, "tan"); -} -/*}}}*/ - -/* sinh */ /*{{{*/ -static Token sinh_func(int argc, const Token argv[]) -{ - return sci_func(argc, argv, SINHFLT, "sinh"); -} -/*}}}*/ - -/* cosh */ /*{{{*/ -static Token cosh_func(int argc, const Token argv[]) -{ - return sci_func(argc, argv, COSHFLT, "cosh"); -} -/*}}}*/ - -/* tanh */ /*{{{*/ -static Token tanh_func(int argc, const Token argv[]) -{ - return sci_func(argc, argv, TANHFLT, "tanh"); -} -/*}}}*/ - -/* asin */ /*{{{*/ -static Token asin_func(int argc, const Token argv[]) -{ - return sci_func(argc, argv, ASINFLT, "asin"); -} -/*}}}*/ - -/* acos */ /*{{{*/ -static Token acos_func(int argc, const Token argv[]) -{ - return sci_func(argc, argv, ACOSFLT, "acos"); -} -/*}}}*/ - -/* atan */ /*{{{*/ -static Token atan_func(int argc, const Token argv[]) -{ - return sci_func(argc, argv, ATANFLT, "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, tfunc[FUNC_RAD2DEG].name); -} -/*}}}*/ - -/* deg2rad */ /*{{{*/ -static Token deg2rad_func(int argc, const Token argv[]) -{ - return sci_func(argc, argv, deg2rad, tfunc[FUNC_DEG2RAD].name); -} -/*}}}*/ /* self function, typically used for keywords */ /*{{{*/ -static Token self_func(int argc, const Token argv[], FunctionIdentifier which) +static Token self_func(FunctionIdentifier self, int argc, const Token argv[]) { Token result; if (argc == -1) { result.type = FIDENT; - result.u.fident = which; + result.u.fident = self; return result; } const char *templ = _("%s may only be used as a bare identifier"); result.type = EEK; result.u.err = malloc(strlen(templ) + MAX_FUNC_NAME_LENGTH + 1); - sprintf(result.u.err, templ, tfunc[which].name); + sprintf(result.u.err, templ, tfunc[self].name); return result; } /*}}}*/ -/* decimal keyword */ /*{{{*/ -static Token decimal_func(int argc, const Token argv[]) +/* nearby integer (rounding) function */ /*{{{*/ +static Token near_func(FunctionIdentifier self, int argc, const Token argv[]) { - return self_func(argc, argv, FUNC_DECIMAL); -} -/*}}}*/ - -/* compact keyword */ /*{{{*/ -static Token compact_func(int argc, const Token argv[]) -{ - return self_func(argc, argv, FUNC_COMPACT); -} -/*}}}*/ - -/* hexact keyword */ /*{{{*/ -static Token hexact_func(int argc, const Token argv[]) -{ - return self_func(argc, argv, FUNC_HEXACT); -} -/*}}}*/ - -/* scientific keyword */ /*{{{*/ -static Token scientific_func(int argc, const Token argv[]) -{ - return self_func(argc, argv, FUNC_SCIENTIFIC); -} -/*}}}*/ - -/* rounding function */ /*{{{*/ -static Token rounding_func(int argc, const Token argv[], - FunctionIdentifier which_func, - FltT (*func)(FltT)) -{ - if (argc == -1) return self_func(argc, argv, which_func); - return sci_func(argc, argv, func, tfunc[which_func].name); -} -/*}}}*/ - -/* floor */ /*{{{*/ -static Token floor_func(int argc, const Token argv[]) -{ - return rounding_func(argc, argv, FUNC_FLOOR, FLOORFLT); -} -/*}}}*/ - -/* ceil */ /*{{{*/ -static Token ceil_func(int argc, const Token argv[]) -{ - return rounding_func(argc, argv, FUNC_CEIL, CEILFLT); -} -/*}}}*/ - -/* round */ /*{{{*/ -static Token round_func(int argc, const Token argv[]) -{ - return rounding_func(argc, argv, FUNC_ROUND, ROUNDFLT); -} -/*}}}*/ - -/* round */ /*{{{*/ -static Token trunc_func(int argc, const Token argv[]) -{ - return rounding_func(argc, argv, FUNC_TRUNC, TRUNCFLT); + FltT (*frnd)(FltT); + switch (self) { + case FUNC_FLOOR: frnd = FLOORFLT; break; + case FUNC_CEIL: frnd = CEILFLT; break; + case FUNC_TRUNC: frnd = TRUNCFLT; break; + case FUNC_ROUND: frnd = ROUNDFLT; break; + default: assert(0); + } + if (argc == -1) return self_func(self, argc, argv); + return sci_func(argc, argv, frnd, tfunc[self].name); } /*}}}*/ /* rnd */ /*{{{*/ -static Token rnd_func(int argc, const Token argv[]) +static Token rnd_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_RND); /* variables */ /*{{{*/ Token result; /*}}}*/ @@ -1496,8 +1251,9 @@ static Token rnd_func(int argc, const Token argv[]) /*}}}*/ /* substr */ /*{{{*/ -static Token substr_func(int argc, const Token argv[]) +static Token substr_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_SUBSTR); /* variables */ /*{{{*/ Token result; const char *usage = _("Usage: substr(string,integer[,integer])"); @@ -1534,8 +1290,9 @@ static Token substr_func(int argc, const Token argv[]) /*}}}*/ /* strptime */ /*{{{*/ -static Token strptime_func(int argc, const Token argv[]) +static Token strptime_func(FunctionIdentifier fi, int argc, const Token argv[]) { + assert(fi == FUNC_STRPTIME); /* variables */ /*{{{*/ Token result; /*}}}*/ @@ -1558,8 +1315,9 @@ static Token strptime_func(int argc, const Token argv[]) /*}}}*/ /* time */ /*{{{*/ -static Token time_func(int argc, const Token argv[]) +static Token time_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_TIME); Token result; if (argc < 1) @@ -1573,8 +1331,9 @@ static Token time_func(int argc, const Token argv[]) /*}}}*/ /* negate -- unary - */ -static Token negate_func(int argc, const Token argv[]) +static Token negate_func(FunctionIdentifier self, int argc, const Token argv[]) { + assert(self == FUNC_NEGATE); if (argc != 1) { Token err; @@ -1589,32 +1348,38 @@ static Token negate_func(int argc, const Token argv[]) Tfunc tfunc[]= { /* Operators in order of increasing precedence */ - [FUNC_CONCAT] = { "concat", concat_func, INFIX_CONC, FUNCT, "" }, - [FUNC_LESS_EQUAL] = { "<=", le_func, INFIX_REL, FUNCT, 0 }, - [FUNC_GREATER_EQUAL] = { ">=", ge_func, INFIX_REL, FUNCT, 0 }, - [FUNC_LESS_THAN] = { "<", lt_func, INFIX_REL, FUNCT, 0 }, - [FUNC_GREATER_THAN] = { ">", gt_func, INFIX_REL, FUNCT, 0 }, - [FUNC_EQUAL_EQUAL] = { "==", isequal_func, INFIX_REL, FUNCT, 0 }, - [FUNC_TILDE_EQUAL] = { "~=", abouteq_func, INFIX_REL, FUNCT, 0 }, - [FUNC_BANG_EQUAL] = { "!=", ne_func, INFIX_REL, FUNCT, 0 }, - [FUNC_PLUS_SYMBOL] = { "+", plus_func, INFIX_PLUS, FUNCT, 0 }, - [FUNC_MINUS_SYMBOL] = { "-", minus_func, INFIX_PLUS, FUNCT, 0 }, - [FUNC_ASTERISK] = { "*", mul_func, INFIX_MUL, FUNCT, 0 }, - [FUNC_SLASH] = { "/", div_func, INFIX_MUL, FUNCT, 0 }, - [FUNC_PER_CENT] = { "%", mod_func, INFIX_MUL, FUNCT, 0 }, - [FUNC_NEGATE] = { "negate", negate_func, PREFIX_NEG, FUNCT, "-" }, - [FUNC_CARET] = { "^", pow_func, INFIX_POW, FUNCT, 0 }, + [FUNC_CONCAT] = { "concat", accum_func, INFIX_CONC, FUNCT, "" }, + [FUNC_LESS_EQUAL] = { "<=", binop_func, INFIX_REL, FUNCT, 0 }, + [FUNC_GREATER_EQUAL] = { ">=", binop_func, INFIX_REL, FUNCT, 0 }, + [FUNC_LESS_THAN] = { "<", binop_func, INFIX_REL, FUNCT, 0 }, + [FUNC_GREATER_THAN] = { ">", binop_func, INFIX_REL, FUNCT, 0 }, + [FUNC_EQUAL_EQUAL] = { "==", binop_func, INFIX_REL, FUNCT, 0 }, + [FUNC_TILDE_EQUAL] = { "~=", binop_func, INFIX_REL, FUNCT, 0 }, + [FUNC_BANG_EQUAL] = { "!=", binop_func, INFIX_REL, FUNCT, 0 }, + [FUNC_PLUS_SYMBOL] = { "+", accum_func, INFIX_PLUS, FUNCT, 0 }, + [FUNC_MINUS_SYMBOL] = { "-", binop_func, INFIX_PLUS, FUNCT, 0 }, + [FUNC_ASTERISK] = { "*", accum_func, INFIX_MUL, FUNCT, 0 }, + [FUNC_SLASH] = { "/", binop_func, INFIX_MUL, FUNCT, 0 }, + [FUNC_PER_CENT] = { "%", binop_func, INFIX_MUL, FUNCT, 0 }, + [FUNC_NEGATE] = { "negate", negate_func, PREFIX_NEG, FUNCT, "-" }, + [FUNC_CARET] = { "^", accum_func, INFIX_POW, FUNCT, 0 }, /* Addressing/cell fetching/cell-position functions */ - [FUNC_AMPERSAND] = { "&", abs_adr_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_D] = { "D", rel_adr_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_X_AMPERSAND] = { "X&", excel_adr_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_AT_SYMBOL] = { "@", abs_at_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_R] = { "R", rel_at_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_CAP_X] = { "X", excel_at_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_X] = { "x", x_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_Y] = { "y", y_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_Z] = { "z", z_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_AMPERSAND] = { "&", adr_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_D] = { "D", adr_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_X_AMPERSAND] = { "X&", adr_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_AT_SYMBOL] = { "@", at_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_R] = { "R", at_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_CAP_X] = { "X", at_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_RIGHT] = { "right", disp_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_LEFT] = { "left", disp_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_DOWN] = { "down", disp_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_UP] = { "up", disp_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_BELOW] = { "below", disp_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_ABOVE] = { "above", disp_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_X] = { "x", dim_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_Y] = { "y", dim_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_Z] = { "z", dim_func, PREFIX_FUNC, FUNCT, 0 }, /* Evaluation control functions */ [FUNC_CLOCK] = { "clock", clock_func, PREFIX_FUNC, FUNCT, 0 }, @@ -1627,46 +1392,46 @@ Tfunc tfunc[]= [FUNC_STRING] = { "string", string_func, PREFIX_FUNC, FUNCT, 0 }, /* Block operations */ - [FUNC_MAX] = { "max", max_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_MIN] = { "min", min_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_MAX] = { "max", reg_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_MIN] = { "min", reg_disp, PREFIX_FUNC, FUNCT, 0 }, [FUNC_N] = { "n", n_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_SUM] = { "sum", sum_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_SUM] = { "sum", reg_disp, PREFIX_FUNC, FUNCT, 0 }, /* String functions */ [FUNC_LEN] = { "len", len_func, PREFIX_FUNC, FUNCT, 0 }, [FUNC_SUBSTR] = { "substr", substr_func, PREFIX_FUNC, FUNCT, 0 }, /* Transcendental functions */ - [FUNC_ACOS] = { "acos", acos_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_ARCOSH] = { "arcosh", arcosh_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_ARSINH] = { "arsinh", arsinh_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_ARTANH] = { "artanh", artanh_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_ASIN] = { "asin", asin_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_ATAN] = { "atan", atan_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_DEG2RAD] = { "deg2rad", deg2rad_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_E] = { "e", e_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_COS] = { "cos", cos_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_COSH] = { "cosh", cosh_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_LOG] = { "log", log_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_RAD2DEG] = { "rad2deg", rad2deg_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_SIN] = { "sin", sin_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_SINH] = { "sinh", sinh_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_TAN] = { "tan", tan_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_TANH] = { "tanh", tanh_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_TAU] = { "tau", tau_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_ACOS] = { "acos", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_ARCOSH] = { "arcosh", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_ARSINH] = { "arsinh", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_ARTANH] = { "artanh", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_ASIN] = { "asin", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_ATAN] = { "atan", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_DEG2RAD] = { "deg2rad", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_E] = { "e", constant_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_COS] = { "cos", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_COSH] = { "cosh", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_LOG] = { "log", log_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_RAD2DEG] = { "rad2deg", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_SIN] = { "sin", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_SINH] = { "sinh", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_TAN] = { "tan", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_TANH] = { "tanh", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_TAU] = { "tau", constant_func, PREFIX_FUNC, FUNCT, 0 }, /* Other mathematical functions */ - [FUNC_ABS] = { "abs", abs_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_BITAND] = { "bitand", bitand_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_BITOR] = { "bitor", bitor_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_CEIL] = { "ceil", ceil_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_FLOOR] = { "floor", floor_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_FRAC] = { "frac", frac_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_POLY] = { "poly", poly_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_RND] = { "rnd", rnd_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_ROUND] = { "round", round_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_SQRT] = { "sqrt", sqrt_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_TRUNC] = { "trunc", trunc_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_ABS] = { "abs", abs_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_BITAND] = { "bitand", bit_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_BITOR] = { "bitor", bit_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_CEIL] = { "ceil", near_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_FLOOR] = { "floor", near_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_FRAC] = { "frac", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_POLY] = { "poly", poly_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_RND] = { "rnd", rnd_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_ROUND] = { "round", near_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_SQRT] = { "sqrt", sci_disp, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_TRUNC] = { "trunc", near_func, PREFIX_FUNC, FUNCT, 0 }, /* Time functions */ [FUNC_STRFTIME] = { "strftime", strftime_func, PREFIX_FUNC, FUNCT, 0 }, @@ -1674,11 +1439,11 @@ Tfunc tfunc[]= [FUNC_TIME] = { "time", time_func, PREFIX_FUNC, FUNCT, 0 }, /* Miscellaneous other functions/keywords */ - [FUNC_DOLLAR_SIGN] = { "$", env_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_COMPACT] = { "compact", compact_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_DECIMAL] = { "decimal", decimal_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_HEXACT] = { "hexact", hexact_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_SCIENTIFIC] = { "scientific", scientific_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_DOLLAR_SIGN] = { "$", env_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_COMPACT] = { "compact", self_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_DECIMAL] = { "decimal", self_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_HEXACT] = { "hexact", self_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_SCIENTIFIC] = { "scientific", self_func, PREFIX_FUNC, FUNCT, 0 }, }; /*}}}*/ diff --git a/src/common/func.h b/src/common/func.h index 5fe5cf1..ba20381 100644 --- a/src/common/func.h +++ b/src/common/func.h @@ -26,7 +26,7 @@ typedef enum FUNC_EQUAL_EQUAL, FUNC_TILDE_EQUAL, FUNC_BANG_EQUAL, FUNC_CARET, FUNC_PER_CENT, FUNC_CONCAT, FUNC_TAU, FUNC_SQRT, FUNC_FLOOR, FUNC_CEIL, FUNC_TRUNC, FUNC_ROUND, FUNC_DECIMAL, FUNC_SCIENTIFIC, FUNC_COMPACT, - FUNC_HEXACT, + FUNC_HEXACT, FUNC_RIGHT, FUNC_LEFT, FUNC_DOWN, FUNC_UP, FUNC_BELOW, FUNC_ABOVE, N_FUNCTION_IDS } FunctionIdentifier; @@ -45,7 +45,7 @@ typedef enum { FUNCT, MACRO } EvaluationStrategy; typedef struct { const char name[MAX_FUNC_NAME_LENGTH + 1]; - Token (*func)(int, const Token*); + Token (*func)(FunctionIdentifier self, int, const Token*); FunctionPrecedence precedence; EvaluationStrategy eval_as; const char* display_symbol;