| 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();