From b3ea9f7ad91ed6b3e0c482730479b1138b11a8b7 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Mon, 29 Jul 2019 14:14:36 -0400 Subject: [PATCH] Add relative address and at functions --- doc/teapot.lyx | 118 +++++++++++++++++++++++++------------ src/common/func.c | 144 ++++++++++++++++++---------------------------- 2 files changed, 136 insertions(+), 126 deletions(-) diff --git a/doc/teapot.lyx b/doc/teapot.lyx index 86b5361..d26cd0f 100644 --- a/doc/teapot.lyx +++ b/doc/teapot.lyx @@ -5393,20 +5393,8 @@ l \emph default ) \series default -returns the value of the cell at position -\emph on -x -\emph default -, -\emph on -y -\emph default -, -\emph on -z -\emph default -. - If any of +returns the value of the cell at the specified location. + In the first form, if any of \emph on x \emph default @@ -5465,9 +5453,30 @@ y z \emph default -]]]) +]]]) +\begin_inset space ~ +\end_inset + +| +\begin_inset space ~ +\end_inset + + \series default -returns a pointer to the cell at location +& +\series medium +(location +\emph on + +\begin_inset space ~ +\end_inset + +l +\emph default +) +\series default +returns the specified location. + In the first form, if any of \emph on x \emph default @@ -5475,30 +5484,65 @@ x \emph on y \emph default -, + or \emph on z \emph default -. - If -\emph on -z -\emph default - is omitted, the -\emph on -z -\emph default - position of the current cell is used. - If -\emph on -y -\emph default - is missing as well, the -\emph on -y -\emph default - position (row) of the cell is used. - + is omitted, the coordinate of the cell is used. + The second form is in fact a no-op, but it is allowed for convenience +\end_layout + +\begin_layout Description +R() Exactly the same as +\series bold +@ +\series default +, except the coordinates of the argument are interpreted as an offset to + the current location (rather than as absolute coordinates in the sheet); + think +\begin_inset Quotes eld +\end_inset + +R +\begin_inset Quotes erd +\end_inset + + for +\begin_inset Quotes eld +\end_inset + +relative. +\begin_inset Quotes erd +\end_inset + + Thus R(-1) returns the value of the cell immediately to the left of this + one. +\end_layout + +\begin_layout Description +D() Exactly the same as +\series bold +& +\series default +, except the coordinates of the argument are added to the current location. + Think +\begin_inset Quotes eld +\end_inset + +D +\begin_inset Quotes erd +\end_inset + + for +\begin_inset Quotes eld +\end_inset + +displaced (by). +\begin_inset Quotes erd +\end_inset + + Thus, D(-1) returns the location of the cell immediately to the left of + this one. \end_layout \begin_layout Description diff --git a/src/common/func.c b/src/common/func.c index 5b35490..4bf9d36 100644 --- a/src/common/func.c +++ b/src/common/func.c @@ -305,68 +305,15 @@ static double deg2rad(double x) #define INTPATIBLE(t) (t.type == INT || t.type == EMPTY) -/* @ */ /*{{{*/ -static Token at_func(int argc, const Token argv[]) -{ - /* variables */ /*{{{*/ - Token result; - Location tmp; - Dimensions dim; - /*}}}*/ - - /* asserts */ /*{{{*/ - assert(argv!=(Token*)0); - /*}}}*/ - if (argc==0) - /* return value at current location */ /*{{{*/ - return (getvalue(upd_sheet, upd_l)); - /*}}}*/ - if (argc==1 && argv[0].type==LOCATION) - /* return value at location pointed to by argument */ /*{{{*/ - return (getvalue(upd_sheet, argv[0].u.location)); - /*}}}*/ - LOCATION_GETS(tmp, upd_l); - if (argc==1 && (argv[0].type==INT || argv[0].type==EMPTY)) - /* return value at x on current y,z */ /*{{{*/ - { - if (argv[0].type == INT) tmp[X] = argv[0].u.integer; - return getvalue(upd_sheet, tmp); - } - /*}}}*/ - if (argc==2 && INTPATIBLE(argv[0]) && INTPATIBLE(argv[1])) - /* return value at x,y on current z */ /*{{{*/ - { - if (argv[0].type == INT) tmp[X] = argv[0].u.integer; - if (argv[1].type == INT) tmp[Y] = argv[1].u.integer; - return getvalue(upd_sheet, tmp); - } - /*}}}*/ - if (argc==3 && INTPATIBLE(argv[0]) && INTPATIBLE(argv[1]) && - INTPATIBLE(argv[2])) - /* return value at x,y,z */ /*{{{*/ - { - for (dim = X; dim < HYPER; ++dim) - if (argv[dim].type == INT) tmp[dim] = argv[dim].u.integer; - return getvalue(upd_sheet, tmp); - } - /*}}}*/ - else - /* return error */ /*{{{*/ - { - result.type=EEK; - result.u.err=strcpy(malloc(strlen(_("Usage: @([integer x][,[integer y][,[integer z]]]) or @(location)"))+1),_("Usage: @([integer x][,[integer y][,[integer z]]]) or @(location)")); - return result; - } - /*}}}*/ -} -/*}}}*/ +typedef enum {ABSOLUTE, RELATIVE} LocConvention; /* & */ /*{{{*/ -static Token adr_func(int argc, const Token argv[]) +static Token adr_func(int argc, const Token argv[], LocConvention lcon) { /* variables */ /*{{{*/ Token result; Dimensions dim; + size_t i; /*}}}*/ /* asserts */ /*{{{*/ @@ -374,47 +321,64 @@ static Token adr_func(int argc, const Token argv[]) /*}}}*/ LOCATION_GETS(result.u.location, upd_l); - if (argc==3 && INTPATIBLE(argv[0]) && INTPATIBLE(argv[1]) && - INTPATIBLE(argv[2])) - /* result is location of the given position */ /*{{{*/ + if (argc == 1 && argv[0].type == LOCATION) return argv[0]; + for (i = 0; i < argc && i < HYPER; ++i) { - result.type=LOCATION; - for (dim = X; dim < HYPER; ++dim) - if (argv[dim].type == INT) result.u.location[dim] = argv[dim].u.integer; + if (!INTPATIBLE(argv[i])) break; + if (lcon == ABSOLUTE) result.u.location[i] = argv[i].u.integer; + else result.u.location[i] += argv[i].u.integer; } - /*}}}*/ - else if (argc==2 && INTPATIBLE(argv[0]) && INTPATIBLE(argv[1])) - /* result is location of the given position in the current z layer */ /*{{{*/ - { - result.type=LOCATION; - for (dim = X; dim <= Y; ++dim) - if (argv[dim].type == INT) result.u.location[dim] = argv[dim].u.integer; - } - /*}}}*/ - else if (argc==1 && INTPATIBLE(argv[0])) - /* result is location of the given position in the current y,z layer */ /*{{{*/ - { - result.type=LOCATION; - if (argv[0].type == INT) result.u.location[X] = argv[0].u.integer; - } - /*}}}*/ - else if (argc==0) - /* result is location of the current position */ /*{{{*/ - { - result.type=LOCATION; - } - /*}}}*/ - else - /* result is type error */ /*{{{*/ + 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; return result; } /*}}}*/ +/* @ */ /*{{{*/ +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 @: "); + result.u.err = malloc(strlen(location.u.err) + strlen(pref) + 1); + strcpy(result.u.err, pref); + strcat(result.u.err, location.u.err); + tfree(&location); + return result; + } + return getvalue(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); +} + /* x */ /*{{{*/ static Token x_func(int argc, const Token argv[]) { @@ -1446,8 +1410,8 @@ static Token time_func(int argc, const Token argv[]) compatible, new entries should be appended. */ Tfunc tfunc[]= { - { "@", at_func }, - { "&", adr_func }, + { "@", abs_at_func }, + { "&", abs_adr_func }, { "x", x_func }, { "y", y_func }, { "z", z_func }, @@ -1489,6 +1453,8 @@ Tfunc tfunc[]= { "time", time_func }, { "bitand", bitand_func }, { "bitor", bitor_func }, + { "D", rel_adr_func }, + { "R", rel_at_func }, { "", (Token (*)(int, const Token[]))0 } }; /*}}}*/