| Ilya Zakharevich on Tue, 2 Jul 2002 11:48:51 -0400 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
| Re: [PATCH 2.2.2] mnemonics for flags [NEW PATCH] |
On Thu, Jun 27, 2002 at 09:30:26AM -0400, I wrote:
> Three intertwined questions remain:
>
> a) Should the "pattern" for the flags be exposed via the struct entree;
>
> b) Should the corresponding C function take a long or a GEN;
>
> c) Should the pattern be embedded into the argument signature
> string, or be available elsewhere?
The following patch answers these question "yes", "long", "embedded".
The differences with the previous implementation:
1) to avoid ambiguity, the flags should be enclosed in quotes (or
otherwise made into t_STR);
2) to avoid any slowdown, the flag descriptor is moved into the end
of the entree->code. It is separated by '\n' from the body of the
signature; in particular, this part is entered only if a
processing of a mneumonic flag is requested.
Enjoy,
Ilya
*** ././src/gp/highlvl.c.orig Fri Apr 19 22:12:31 2002
--- ././src/gp/highlvl.c Tue Jul 2 17:10:20 2002
***************
*** 244,250 ****
{"plotcursor",11,(void*)rectcursor,10,"L"},
{"plotdraw",99,(void*)rectdraw_flag,10,"vGD0,L,"},
{"plotfile",16,(void*)plot_outfile_set,10,"ls"},
! {"ploth",99,(void*)ploth,10,"V=GGIpD0,L,D0,L,"},
{"plothraw",25,(void*)plothraw,10,"GGD0,L,"},
{"plothsizes",0,(void*)plothsizes_flag,10,"D0,L,"},
{"plotinit",99,(void*)initrect_gen,10,"vLD0,G,D0,G,D0,L,"},
--- 244,250 ----
{"plotcursor",11,(void*)rectcursor,10,"L"},
{"plotdraw",99,(void*)rectdraw_flag,10,"vGD0,L,"},
{"plotfile",16,(void*)plot_outfile_set,10,"ls"},
! {"ploth",99,(void*)ploth,10,"V=GGIpD0,M,D0,L,\nParametric|1; Recursive|2; no-X-axis|8; no-Y-axis|16; no-Frame|32; no-Lines|64; Points-too|128; Splines|256; no-X-ticks|512; no-Y-ticks|1024; Same-ticks|2048"},
{"plothraw",25,(void*)plothraw,10,"GGD0,L,"},
{"plothsizes",0,(void*)plothsizes_flag,10,"D0,L,"},
{"plotinit",99,(void*)initrect_gen,10,"vLD0,G,D0,G,D0,L,"},
***************
*** 284,290 ****
"plotcursor(w): current position of cursor in rectwindow w",
"plotdraw(list, {flag=0}): draw vector of rectwindows list at indicated x,y positions; list is a vector w1,x1,y1,w2,x2,y2,etc. . If flag!=0, x1, y1 etc. express fractions of the size of the current output device",
"plotfile(filename): set the output file for plotting output. \"-\" redirects to the same place as PARI output",
! "ploth(X=a,b,expr,{flags=0},{n=0}): plot of expression expr, X goes from a to b in high resolution. Both flags and n are optional. Binary digits of flags mean : 1 parametric plot, 2 recursive plot, 8 omit x-axis, 16 omit y-axis, 32 omit frame, 64 do not join points, 128 plot both lines and points, 256 use cubic splines, 512/1024 no x/y ticks, 2048 plot all ticks with the same length. n specifies number of reference points on the graph (0=use default value). Returns a vector for the bounding box",
"plothraw(listx,listy,{flag=0}): plot in high resolution points whose x (resp. y) coordinates are in listx (resp. listy). If flag is 1, join points, other non-0 flags should be combinations of bits 8,16,32,64,128,256 meaning the same as for ploth()",
"plothsizes({flag=0}): returns array of 6 elements: terminal width and height, sizes for ticks in horizontal and vertical directions, width and height of characters. If flag=0, sizes of ticks and characters are in pixels, otherwise are fractions of the screen size",
"plotinit(w,{x=0},{y=0},{flag=0}): initialize rectwindow w to size x,y. If flag!=0, x and y express fractions of the size of the current output device. x=0 or y=0 means use the full size of the device",
--- 284,290 ----
"plotcursor(w): current position of cursor in rectwindow w",
"plotdraw(list, {flag=0}): draw vector of rectwindows list at indicated x,y positions; list is a vector w1,x1,y1,w2,x2,y2,etc. . If flag!=0, x1, y1 etc. express fractions of the size of the current output device",
"plotfile(filename): set the output file for plotting output. \"-\" redirects to the same place as PARI output",
! "ploth(X=a,b,expr,{flags=0},{n=0}): plot of expression expr, X goes from a to b in high resolution. Both flags and n are optional. Binary digits of flags mean (and can be replaced by punctyation-separated mneumonics): 1=Parametric, 2=Recursive, 8=no-X-axis, 16=no-Y-axis, 32=no-Frame, 64=no-Lines (do not join points), 128=Points-too (plot both lines and points), 256=Splines (use cubic splines), 512=no-X-ticks, 1024= no-Y-ticks, 2048=Same-ticks (plot all ticks with the same length). n specifies number of reference points on the graph (0=use default value). Returns a vector for the bounding box",
"plothraw(listx,listy,{flag=0}): plot in high resolution points whose x (resp. y) coordinates are in listx (resp. listy). If flag is 1, join points, other non-0 flags should be combinations of bits 8,16,32,64,128,256 meaning the same as for ploth()",
"plothsizes({flag=0}): returns array of 6 elements: terminal width and height, sizes for ticks in horizontal and vertical directions, width and height of characters. If flag=0, sizes of ticks and characters are in pixels, otherwise are fractions of the screen size",
"plotinit(w,{x=0},{y=0},{flag=0}): initialize rectwindow w to size x,y. If flag!=0, x and y express fractions of the size of the current output device. x=0 or y=0 means use the full size of the device",
*** ././src/language/init.c.orig Mon Jun 10 00:45:47 2002
--- ././src/language/init.c Tue Jul 2 17:03:44 2002
***************
*** 1888,1893 ****
--- 1888,1895 ----
* The unquoted components can be of any pari type (converted according to
* the current output format)
* s* any number of strings (see s)
+ * M Mneumonic or a flag (converted to a long); description follows
+ * after \n at the end of the argument description
* D Has a default value. Format is "Dvalue,type," (the ending comma is
* mandatory). Ex: D0,L, (arg is long, 0 by default).
* Special syntax:
*** ././src/language/anal.c.orig Sat Jun 8 16:37:45 2002
--- ././src/language/anal.c Tue Jul 2 17:38:33 2002
***************
*** 82,87 ****
--- 82,276 ----
static long br_status, br_count;
static GEN br_res = NULL;
+ /* TEMPLATE is assumed to be ";"-separated list of items. Each item
+ may have one of the following forms: id=value id==value id|value id&~value.
+ Each id consists of alphanum characters, dashes and underscores.
+ IDs are case-sensitive.
+
+ ARG consists of several IDs separated by punctuation (and optional
+ whitespace). Each modifies the return value in a "natural" way: an
+ ID from id=value should be the first in the sequence and sets RETVAL to
+ VALUE (and cannot be negated), ID from id|value bit-ORs RETVAL with
+ VALUE (and bit-ANDs RETVAL with ~VALUE if negated), ID from
+ id&~value behaves as if it were noid|value, ID from
+ id==value behaves the same as id=value, but should come alone.
+
+ For items of the form id|value and id&~value negated forms are
+ allowed: either when arg looks like no[-_]id, or when id looks like
+ this, and arg is not-negated.
+ */
+
+ #define A_ACTION_ASSIGN 1
+ #define A_ACTION_SET 2
+ #define A_ACTION_UNSET 3
+
+ #define PARSEMNU_TEMPL_TERM_NL 1
+ #define PARSEMNU_ARG_WHITESP 2
+
+ #define IS_ID(c) (isalnum((int)c) || ((c) == '_') || ((c) == '-'))
+ #define STMT_START do
+ #define STMT_END while (0)
+ #define ERR(reason) STMT_START { \
+ if (failure && first) { \
+ *failure = reason; *failure_arg = NULL; return 0; \
+ } else err(talker,reason); } STMT_END
+ #define ERR2(reason,s) STMT_START { \
+ if (failure && first) { \
+ *failure = reason; *failure_arg = s; return 0; \
+ } else err(talker,reason,s); } STMT_END
+
+ unsigned long
+ parse_option_string(char *arg, char *template, long flag, char **failure, char **failure_arg)
+ {
+ unsigned long retval = 0;
+ char *etemplate = NULL;
+
+ if (flag & PARSEMNU_TEMPL_TERM_NL)
+ etemplate = strchr(template, '\n');
+ if (!etemplate)
+ etemplate = template + strlen(template);
+
+ if (failure)
+ *failure = NULL;
+ while (1) {
+ long numarg;
+ char *e, *id;
+ char *negated; /* action found with 'no'-ID */
+ int negate; /* Arg has 'no' prefix removed */
+ int l, action = 0, first = 1, singleton = 0;
+ char b[80], *buf, *inibuf;
+
+ if (flag & PARSEMNU_ARG_WHITESP)
+ while (isspace((int)*arg)) arg++;
+ if (!*arg)
+ break;
+ e = arg;
+ while (IS_ID(*e))
+ e++;
+ /* Now the ID is whatever is between arg and e. */
+ l = e - arg;
+ if (l >= sizeof(b))
+ ERR("id too long in a stringified flag");
+ if (!l) /* Garbage after whitespace? */
+ ERR("a stringified flag does not start with an id");
+ strncpy(b, arg, l);
+ b[l] = 0;
+ arg = e;
+ e = inibuf = buf = b;
+ while (('0' <= *e) && (*e <= '9'))
+ e++;
+ if (*e == 0)
+ ERR("numeric id in a stringified flag");
+ negate = 0;
+ negated = NULL;
+ find:
+ id = template;
+ while ((id = strstr(id, buf)) && id < etemplate) {
+ if (IS_ID(id[l])) { /* We do not allow abbreviations yet */
+ id = id + l; /* False positive */
+ continue;
+ }
+ if ((id >= template + 2) && (IS_ID(id[-1]))) {
+ char *s = id;
+
+ if ( !negate && s >= template+3
+ && ((id[-1] == '_') || (id[-1] == '-')) )
+ s--;
+ /* Check whether we are preceeded by "no" */
+ if ( negate /* buf initially started with "no" */
+ || (s < template+2) || (s[-1] != 'o') || (s[-2] != 'n')
+ || (s >= template+3 && IS_ID(s[-3]))) {
+ id = id + l; /* False positive */
+ continue;
+ }
+ /* Found noID in the template! */
+ negated = id + l;
+ id = id + l;
+ continue; /* Try to find without 'no'. */
+ }
+ /* Found as is */
+ id = id + l;
+ break;
+ }
+ if ( !id && !negated && !negate
+ && (l > 2) && buf[0] == 'n' && buf[1] == 'o' ) {
+ /* Try to find the flag without the prefix "no". */
+ buf += 2;
+ if ((buf[0] == '_') || (buf[0] == '-'))
+ buf++;
+ negate = 1;
+ if (buf[0])
+ goto find;
+ }
+ if (!id && negated) { /* Negated and AS_IS forms, prefer AS_IS */
+ id = negated; /* Otherwise, use negated form */
+ negate = 1;
+ }
+ if (!id)
+ ERR2("Unrecognized id '%s' in a stringified flag", inibuf);
+ if (singleton && !first)
+ ERR("Singleton id non-single in a stringified flag");
+ if (id[0] == '=') {
+ if (negate)
+ ERR("Cannot negate id=value in a stringified flag");
+ if (!first)
+ ERR("Assign action should be first in a stringified flag");
+ action = A_ACTION_ASSIGN;
+ id++;
+ if (id[0] == '=') {
+ singleton = 1;
+ id++;
+ }
+ } else if (id[0] == '^') {
+ if (id[1] != '~')
+ err(talker, "Unrecognized action in a template");
+ id += 2;
+ if (negate)
+ action = A_ACTION_SET;
+ else
+ action = A_ACTION_UNSET;
+ } else if (id[0] == '|') {
+ id++;
+ if (negate)
+ action = A_ACTION_UNSET;
+ else
+ action = A_ACTION_SET;
+ }
+
+ e = id;
+
+ while ((*e >= '0' && *e <= '9')) e++;
+ while (isspace((int)*e))
+ e++;
+ if (*e && (*e != ';') && (*e != ','))
+ err(talker, "Non-numeric argument of an action in a template");
+ numarg = atol(id); /* Now it is safe to get it... */
+ switch (action) {
+ case A_ACTION_SET:
+ retval |= numarg;
+ break;
+ case A_ACTION_UNSET:
+ retval &= ~numarg;
+ break;
+ case A_ACTION_ASSIGN:
+ retval = numarg;
+ break;
+ default:
+ ERR("error in parse_option_string");
+ }
+ first = 0;
+ if (flag & PARSEMNU_ARG_WHITESP)
+ while (isspace((int)*arg))
+ arg++;
+ if (*arg && !(ispunct((int)*arg) && *arg != '-'))
+ ERR("Junk after an id in a stringified flag");
+ /* Skip punctuation */
+ if (*arg)
+ arg++;
+ }
+ return retval;
+ }
+
/* Special characters:
* ' ', '\t', '\n', '\\' are forbidden internally (suppressed by filtre).
* { } are forbidden everywhere and will be used to denote optional
***************
*** 1485,1490 ****
--- 1674,1680 ----
void *call = ep->value;
GEN argvec[9];
matcomp *init[9];
+ char *flags = NULL;
deriv = (*analyseur == '\'' && analyseur[1] == '(') && analyseur++;
if (*analyseur == '(')
***************
*** 1514,1520 ****
}
if (*s == 'p') { argvec[i++] = (GEN) prec; s++; }
! while (*s)
switch (*s++)
{
case 'G': /* GEN */
--- 1704,1710 ----
}
if (*s == 'p') { argvec[i++] = (GEN) prec; s++; }
! while (*s && *s != '\n')
switch (*s++)
{
case 'G': /* GEN */
***************
*** 1583,1588 ****
--- 1773,1796 ----
*bp++ = 0; argvec[i++] = (GEN) buf;
break;
+ case 'M': /* Mneumonic flag */
+ match_comma(); argvec[i] = expr();
+ if (br_status) err(breaker,"here (argument reading)");
+ if (typ(argvec[i]) == t_STR) {
+ if (!flags)
+ flags = ep->code;
+ flags = strchr(flags, '\n'); /* Skip to the following '\n' */
+ if (!flags)
+ err(talker, "not enough flags in string function signature");
+ flags++;
+ argvec[i] = (GEN) parse_option_string((char*)(argvec[i] + 1),
+ flags, PARSEMNU_ARG_WHITESP | PARSEMNU_TEMPL_TERM_NL,
+ NULL, NULL);
+ } else
+ argvec[i] = (GEN)itos(argvec[i]);
+ i++;
+ break;
+
case 's': /* expanded string; empty arg yields "" */
match_comma();
if (*s == '*') /* any number of string objects */
***************
*** 2523,2531 ****
/* Optimized for G and p. */
while (*s == 'G') { match_comma(); skipexpr(); s++; }
if (*s == 'p') s++;
! while (*s) switch (*s++)
{
! case 'G': case 'n': case 'L':
match_comma();
if (*analyseur == ',' || *analyseur == ')') break;
skipexpr(); break;
--- 2731,2739 ----
/* Optimized for G and p. */
while (*s == 'G') { match_comma(); skipexpr(); s++; }
if (*s == 'p') s++;
! while (*s && *s != '\n') switch (*s++)
{
! case 'G': case 'n': case 'L': case 'M':
match_comma();
if (*analyseur == ',' || *analyseur == ')') break;
skipexpr(); break;
***************
*** 2583,2588 ****
--- 2791,2798 ----
match('='); matchcomma = 0; break;
case ',':
matchcomma=1; break;
+ case '\n': /* Before the mneumonic */
+ break;
default:
err(bugparier,"skipidentifier (unknown code)");
}