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)"); }