Ilya Zakharevich on Fri, 11 Jan 2002 21:21:20 -0500 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
[PATCH 2.2.2] mneumonics for flags |
This patch adds a possibility to use mneumonic flags instead of numberic flags. E.g., instead of 6+1024 one can use Runge-Kutta/Known-Prime (for a silly example ;-), if the correponding function descriptor uses "MRunge-Kutta=6;Known-Prime|1024" instead of "L". There are 3 allowed actions after "M": id==value # id should appear alone in the argument id=value # id should appear first, and may be followed # by flags of two remaining forms id|value # bit-or the flag with value id&~value # bit-and the flag with ~value The options of the last two types may be "negated" by prepending one of "no", "no_" or "no-". Either the descriptor in the "M"-string may be negated, or the mneumonic. In othere words, the descriptors id|value no-id&~value id|value;no-id&~value behave identically: you can use either "id", or "no-id" in your mneumonic. [So far I only instrumented ploth() - see the first chunk, and did only rudimentary testing.] Note that "front-ends" to PARI which read the descriptors need to be modifed to support "Mjunk," the same way as "L," (e.g., Math::Pari). Note also that there are some shortcomings: a) For backward compatibility, if the first word of the argument is not a known flag, we read the argument as a PARI expression. Thus one does not get meaningful error messages for the first word; b) Allowing dashes in mneumonics is not 100% intuitive (taking into account that the argument may be an expression too); c) This is a (minor) CPU burner even if you do not use mneumonic flags (due to the need to check the first word for being a mneumonic, and skipping over the chars between "M" and ","); d) If falling back to expression-mode, we use readlong(), which behaves as skipexpr() - while we do skipseq() in the other modes; so an expression with ";" will give a non-intuitive result. [This is easily fixable.] e) mneumonics may be separated by an arbitrary punctuation, except "," and "-". Again, this may lead to wrong expectations about '*' being an opposite of "/" etc. Enjoy, Ilya --- ./src/gp/highlvl.c-pre Thu Dec 6 09:53:14 2001 +++ ./src/gp/highlvl.c Fri Jan 11 15:07:02 2002 @@ -238,7 +238,7 @@ entree functions_highlevel[]={ {"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,"}, +{"ploth",99,(void*)ploth,10,"V=GGIpD0,MParametric|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,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,"}, @@ -278,7 +278,7 @@ char *helpmessages_highlevel[]={ "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", + "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-pre Thu Jan 10 03:39:06 2002 +++ ./src/language/init.c Fri Jan 11 15:05:20 2002 @@ -1913,6 +1913,7 @@ geni(void) { return gi; } * 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 up to ',' * 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-pre Wed Jan 9 07:30:02 2002 +++ ./src/language/anal.c Fri Jan 11 17:45:44 2002 @@ -83,6 +83,186 @@ static entree *check_new_fun; 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 IS_ID(c) (isalnum((int)c) || ((c) == '_') || ((c) == '-')) +#define STMT_START do +#define STMT_END while (0) +#define ERR2(a1,a2) STMT_START { \ + if (flag && first) { \ + *failure = 1; return 0; \ + } else err(a1,a2); } STMT_END +#define ERR3(a1,a2,a3) STMT_START { \ + if (flag && first) { \ + *failure = 1; return 0; \ + } else err(a1,a2,a3); } STMT_END + +unsigned long +parse_option_string(char *arg, char *template, long flag, long *failure) +{ + unsigned long retval = 0; + + if (flag) + *failure = 0; + while (1) { + long numarg; + char *e, *id; + char *negated; /* action found with 'no'-ID */ + int negate; /* Arg has 'no' prefix removed */ + int l, action, first = 1, singleton = 0; + char b[80], *buf, *inibuf; + +#ifdef WHITESPACE_INPUT_ALLOWED + while (isspace((int)*arg)) arg++; +#endif + 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)) + ERR2(talker, "id too long in a stringified flag"); + if (!l) /* Garbage after whitespace? */ + ERR2(talker, "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) + ERR2(talker, "numeric id in a stringified flag"); + negate = 0; + negated = NULL; + find: + id = template; + while ((id = strstr(id, buf))) { + if (IS_ID(id[l])) { + 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 ASIS forms, prefer ASIS */ + id = negated; /* Otherwise, use negated form */ + negate = 1; + } + if (!id) + ERR3(talker, "Unrecognized id '%s' in a stringified flag", inibuf); + if (singleton && !first) + ERR2(talker, "Singleton id non-single in a stringified flag"); + if (id[0] == '=') { + if (negate) + ERR2(talker, "Cannot negate id=value in a stringified flag"); + if (!first) + ERR2(talker, "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; + } + first = 0; +#ifdef WHITESPACE_INPUT_ALLOWED + while (isspace((int)*arg)) + arg++; +#endif + if (*arg && !(ispunct((int)*arg) && *arg != '-')) + ERR2(talker, "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 @@ -1472,7 +1652,7 @@ identifier(void) { char *s = ep->code, *oldanalyseur = NULL, *buf, *limit, *bp; unsigned int ret, noparen, has_pointer=0; - long fake; + long fake, result; void *call = ep->value; GEN argvec[9]; matcomp *init[9]; @@ -1574,6 +1754,24 @@ identifier(void) *bp++ = 0; argvec[i++] = (GEN) buf; break; + case 'M': /* Mneumonics or flag */ + match_comma(); mark.raw = analyseur; + skipseq(); + bp = init_buf(analyseur - mark.raw, &buf,&limit); + strncpy(buf, mark.raw, analyseur - mark.raw); + buf[analyseur - mark.raw] = 0; + /* Try processing as a flag */ + result = parse_option_string(buf, s, 1, &fake); + while (*s && *s != ',') + s++; + if (fake) { /* Error, retry as an expression */ + analyseur = mark.raw; + argvec[i++] = (GEN) readlong(); + break; + } + argvec[i++] = (GEN) result; + break; + case 's': /* expanded string; empty arg yields "" */ match_comma(); if (*s == '*') /* any number of string objects */ @@ -2525,6 +2723,12 @@ skipidentifier(void) if (*analyseur == ',' || *analyseur == ')') break; analyseur++; } + break; + case 'M': + match_comma(); + skipseq(); + while (*s && *s != ',') + s++; break; case 's': match_comma();