/*******************************************************************/ /* */ /* SYNTACTICAL ANALYZER FOR GP */ /* */ /*******************************************************************/ /* $Id: anal.c,v 1.1.1.1 1999/09/16 13:48:02 karim Exp $ */ #include "pari.h" #include "anal.h" #include "parinf.h" typedef struct var_cell { struct var_cell *prev; GEN value; char flag; } var_cell; #define PUSH_VAL 0 #define COPY_VAL 1 #define copyvalue(v,x) new_val_cell(get_ep(v), gclone(x), COPY_VAL) #define pushvalue(v,x) new_val_cell(get_ep(v), x, PUSH_VAL) #define killvalue(v) pop_val(get_ep(v)) #define separe(c) ((c)==';' || (c)==':') typedef GEN (*PFGEN)(ANYARG); static GEN constante(void); static GEN expr(void); static GEN facteur(void); static GEN identifier(void); static GEN matrix_block(GEN p, entree *ep); static GEN read_member(GEN x); static GEN seq(void); static GEN truc(void); static long number(long *nb); static void doskipseq(char *s, int strict); static void skipconstante(void); static void skipexpr(void); static void skipfacteur(void); static void skipidentifier(void); static void skipseq(void); static void skipstring(void); static long skiptruc(void); static GEN strtoGENstr_t(); static entree *entry(void); static entree *installep(void *f,char *name,int l,int v,int add,entree **table); static entree *skipentry(void); void killbloc0(GEN x, int inspect); /* last time we began parsing an object of specified type */ static struct { char *identifier, *symbol, *raw, *member, *start; } mark; /* when skipidentifier() detects that user function f() is being redefined, * (f()= ... ) this is set pointing to the opening parenthesis. Checked in * identifier(). Otherwise definition like f(x=1)= would change the value of * global variable x */ static char *redefine_fun = NULL; /* points to the part of the string that remains to be parsed */ static char *analyseur; /* when non-0, we are checking the syntax of a new function body */ static long skipping_fun_def; /* when non-NULL, points to the entree of a new user function (currently * being checked). Used by the compatibility engine in the following way: * when user types in a function whose name has changed, it is understood * as EpNEW; first syntax error (missing = after function definition * usually) triggers err_new_fun() if check_new_fun is set. */ static entree *check_new_fun; /* for control statements (check_break) */ static long br_status, br_count; static GEN br_res = NULL; /* Special characters: * ' ', '\t', '\n', '\\' are forbidden internally (suppressed by filtre). * { } are forbidden everywhere and will be used to denote optional * lexemes in the sequel. * * Definitions: The sequence * { a }* means any number (possibly 0) of object a. * { x|y } means an optional x or y. * * seq : only this one can be empty. * sequence of { expr{ :|; } }* * * expr : * expression = sequence of "facteurs" separated by binary operators * whose priority are: * 1: *, /, \, \/, %, >>, << (highest) * 2: +, - * 3: <, <=, >, >=, !=, ==, <> * 4: &, &&, |, || (lowest) * read from left to right. * * facteur : * Optional leading sign (meaningfull only when "facteur" is enclosed * in parentheses), followed by a "truc", then by any succession of the * following: * * ~, _, ', ! * or ^ facteur * or matrix_block * or .member (see gp_member_list) * * truc: * identifier * or constante * or ! truc * or ' identifier * or matrix_block (no_affect=1) * or (expr) * or %{ ` }* or %number * * identifier: * entry ( { expr } { ,expr }* ) * The () are optional when arg list is void. * * matrix_block : * [ A { { ; }A }*] where A = { expr } { { , }{ expr } }* * All A must share the same length. * If (no_affect=0 || ep !=NULL): follows an optional "= expr" * or ++, --, op= where op is one of the operators in expr 1: and 2: * * entry : * any succesion of alphanumeric characters, the first of which is not * a digit. * * constante: * number { . } { number } { e|E } { +|- } { number }. * * number: * any non-negative integer. */ char* _analyseur(void) { return analyseur; } /* Do not modify (analyseur,mark.start) */ static GEN lisseq0(char *t, GEN (*f)(void)) { const long av = avma; char *olds = analyseur, *olde = mark.start; GEN res; if (foreignExprHandler && *t == foreignExprSwitch) return (*foreignExprHandler)(t); check_new_fun=NULL; skipping_fun_def=0; mark.start = analyseur = t; br_status = br_NONE; if (br_res) { killbloc(br_res); br_res = NULL; } res = f(); analyseur = olds; mark.start = olde; if (br_status) { if (!br_res) { avma = av; return gnil; } res = forcecopy(br_res); } return gerepileupto(av, res); } GEN lisseq(char *t) { return lisseq0(t, seq); } GEN lisexpr(char *t) { return lisseq0(t, expr); } /* filtered lisexpr = remove blanks and comments */ GEN flisexpr(char *t) { char *tmp = pari_strdup(t); GEN x; filtre(tmp, f_INIT | f_REG); x = lisseq0(tmp, expr); free(tmp); return x; } /* check syntax, then execute */ GEN readseq(char *c, int strict) { check_new_fun=NULL; skipping_fun_def=0; doskipseq(c, strict); return lisseq(c); } entree * install(void *f, char *name, char *code) { long hash; entree *ep = is_entry_intern(name, functions_hash, &hash); if (ep) err(warner,"[install] '%s' already there. Not replaced", name); else { ep = installep(f, name, strlen(name), EpINSTALL, 0, functions_hash + hash); ep->code = pari_strdup(code); } return ep; } static void free_args(gp_args *f) { long i; GEN *y = f->arg; for (i = f->narg + f->nloc - 1; i>=0; i--) if (isclone(y[i])) gunclone(y[i]); } void freeep(entree *ep) { if (foreignFuncFree && ep->code && (*ep->code == 'x')) (*foreignFuncFree)(ep); /* function created by foreign interpreter */ if (EpSTATIC(ep)) return; /* gp function loaded at init time */ if (ep->help) free(ep->help); if (ep->code) free(ep->code); if (ep->args) { switch(EpVALENCE(ep)) { case EpVAR: case EpGVAR: break; default: free_args((gp_args*)ep->args); } free((void*)ep->args); } free(ep); } /*******************************************************************/ /* */ /* VARIABLES */ /* */ /*******************************************************************/ /* push_val and pop_val are private functions for use in sumiter and bibli2: * we want a temporary value for ep, which is NOT a clone, to avoid * unnecessary gaffect calls. * * Assumptions: * EpVALENCE(ep) = EpVAR or EpGVAR * ep->args initilized to NULL in installep() */ static void new_val_cell(entree *ep, GEN a, char flag) { var_cell *v = (var_cell*) gpmalloc(sizeof(var_cell)); v->value = (GEN)ep->value; v->prev = (var_cell*) ep->args; v->flag = flag; ep->args = (void*) v; ep->value = a; } void push_val(entree *ep, GEN a) { new_val_cell(ep,a,PUSH_VAL); } void pop_val(entree *ep) { var_cell *v = (var_cell*) ep->args; if (!v) return; /* initial value */ if (v->flag == COPY_VAL) killbloc((GEN)ep->value); ep->value = v->value; ep->args = (void*) v->prev; free((void*)v); } int pop_val_if_newer(entree *ep, long loc) { var_cell *v = (var_cell*) ep->args; if (!v) return 0; /* initial value */ if (v->flag == COPY_VAL) { GEN x = (GEN)ep->value; if (bl_num(x) < loc) return 0; /* older */ killbloc((GEN)ep->value); } ep->value = v->value; ep->args = (void*) v->prev; free((void*)v); return 1; } static void changevalue(entree *ep, GEN val) { GEN x = gclone(val); var_cell *v = (var_cell*) ep->args; if (!v) new_val_cell(ep,x, COPY_VAL); else { if (v->flag == COPY_VAL) killbloc((GEN)ep->value); else v->flag = COPY_VAL; ep->value = x; } } void kill_from_hashlist(entree *ep) { long hash = hashvalue(ep->name); entree *ep1; if (functions_hash[hash] == ep) { functions_hash[hash] = ep->next; freeep(ep); return; } for (ep1 = functions_hash[hash]; ep1; ep1 = ep1->next) if (ep1->next == ep) { ep1->next = ep->next; freeep(ep); return; } } static entree* get_ep(long v) { entree *ep = varentries[v]; if (!ep) err(talker2,"this function uses a killed variable", mark.identifier, mark.start); return ep; } /* Kill entree ep, i.e free all memory it occupies, remove it from hashtable. * If it's a variable set a "black hole" in polx[v], etc. x = 0-th variable * can NOT be killed (only the value). That's because we use explicitly * polx[0] at many places. */ void kill0(entree *ep) { long v; if (EpSTATIC(ep)) err(talker2,"can't kill that",mark.symbol,mark.start); switch(EpVALENCE(ep)) { case EpVAR: case EpGVAR: v = varn(initial_value(ep)); killvalue(v); if (!v) return; /* never kill x */ polx[v] = polun[v] = gnil; polvar[v+1] = (long)gnil; varentries[v] = NULL; break; case EpUSER: gunclone((GEN)ep->value); break; } kill_from_hashlist(ep); } /*******************************************************************/ /* */ /* PARSER */ /* */ /*******************************************************************/ static GEN seq(void) { const long av=avma, lim=stack_lim(av,1); GEN res=gnil; for(;;) { while (separe(*analyseur)) analyseur++; if (!*analyseur || *analyseur == ')' || *analyseur == ',') return res; res = expr(); if (br_status || !separe(*analyseur)) return res; if (low_stack(lim, stack_lim(av,1))) { if(DEBUGMEM>1) err(warnmem,"seq"); if (is_universal_constant(res)) avma = av; else res = gerepileupto(av, gcopy(res)); } } } static GEN gshift_l(GEN x, GEN n) { return gshift(x, itos(n)); } static GEN gshift_r(GEN x, GEN n) { return gshift(x,-itos(n)); } static GEN expr(void) { PFGEN f[] = { NULL,NULL,NULL,NULL }; GEN aux,e,e1,e2,e3; long av = avma, lim = stack_lim(av,2); e1 = e2 = e3 = NULL; L3: aux = facteur(); if (br_status) return NULL; e3 = f[3]? f[3](e3,aux): aux; switch(*analyseur) { case '*': analyseur++; f[3] = (PFGEN)&gmul; goto L3; case '/': analyseur++; f[3] = (PFGEN)&gdiv; goto L3; case '%': analyseur++; f[3] = (PFGEN)&gmod; goto L3; case '\\': if (*++analyseur == '/') { analyseur++; f[3]=(PFGEN)&gdivround; goto L3; } f[3] = (PFGEN)&gdivent; goto L3; case '<': case '>': if (analyseur[1] == *analyseur) { f[3] = (*analyseur == '<')? (PFGEN)&gshift_l : (PFGEN)&gshift_r; analyseur += 2; goto L3; } } f[3] = NULL; L2: if (!e3) goto L3; e2 = f[2]? f[2](e2,e3): e3; e3 = NULL; if (low_stack(lim, stack_lim(av,2))) { GEN *gptr[2]; int n = 1; gptr[0]=&e2; if (e1) gptr[n++]=&e1; if(DEBUGMEM>1) err(warnmem,"expr"); gerepilemany(av,gptr,n); } switch(*analyseur) { case '+': analyseur++; f[2]=(PFGEN)&gadd; goto L3; case '-': analyseur++; f[2]=(PFGEN)&gsub; goto L3; } f[2] = NULL; L1: if (!e2) goto L2; e1 = f[1]? f[1](e1,e2): e2; e2 = NULL; switch(*analyseur) { case '<': switch(*++analyseur) { case '=': analyseur++; f[1]=(PFGEN)&gle; goto L2; case '>': analyseur++; f[1]=(PFGEN)⪈ goto L2; } f[1]=(PFGEN)&glt; goto L2; case '>': if (*++analyseur == '=') { analyseur++; f[1]=(PFGEN)&gge; goto L2; } f[1]=(PFGEN)&ggt; goto L2; case '=': if (analyseur[1] == '=') { analyseur+=2; f[1]=(PFGEN)≥ goto L2; } goto L1; case '!': if (analyseur[1] == '=') { analyseur+=2; f[1]=(PFGEN)⪈ goto L2; } goto L1; } f[1] = NULL; /* L0: */ if (!e1) goto L1; e = f[0]? (gcmp0(e1)? gzero: gun): e1; e1 = NULL; switch(*analyseur) { case '&': if (*++analyseur == '&') analyseur++; if (gcmp0(e)) { skipexpr(); return gzero; } f[0]=(PFGEN)1; goto L1; case '|': if (*++analyseur == '|') analyseur++; if (!gcmp0(e)) { skipexpr(); return gun; } f[0]=(PFGEN)1; goto L1; } return e; } /********************************************************************/ /** **/ /** CHECK FUNCTIONS **/ /** **/ /********************************************************************/ /* if current identifier was a function in 1.39.15, raise "obsolete" error */ static void err_new_fun() { char *s = NULL, str[128]; if (check_new_fun) { if (check_new_fun != NOT_CREATED_YET) { s = strcpy(str,check_new_fun->name); kill0(check_new_fun); } check_new_fun=NULL; } if (compatible == NONE) { char *v, *u = str, *lim = str + 127; int n; if (!s) { /* guess that the offending function was last identifier */ v = mark.identifier; while (is_keyword_char(*v) && u < lim) *u++ = *v++; *u = 0; s = str; } if (whatnow_fun) n = whatnow_fun(s,1); else n = is_entry_intern(s,funct_old_hash,NULL)? 1: 0; if (n) err(obsoler,mark.identifier,mark.start, s,n); } } #ifdef INLINE INLINE #endif void match2(char *s, char c) { if (*s != c) { char str[64]; if (check_new_fun && (c == '(' || c == '=' || c == ',')) err_new_fun(); sprintf(str,"expected character: '%c' instead of",c); err(talker2,str,s,mark.start); } } #define match(c) match2(analyseur++, (c)) static long readlong() { const long av = avma; const char *old = analyseur; long m; GEN arg = expr(); if (br_status) err(breaker,"here (reading long)"); if (typ(arg) != t_INT) err(caseer,old,mark.start); m = itos(arg); avma=av; return m; } static long check_array_index(long max) { const char *old = analyseur; const long c = readlong(); if (c < 1 || c >= max) { char s[80]; sprintf(s,"array index (%ld) out of allowed range ",c); if (max == 1) strcat(s, "[none]"); else if (max == 2) strcat(s, "[1]"); else sprintf(s,"%s[1-%ld]",s,max-1); err(talker2,s,old,mark.start); } return c; } static long readvar() { const char *old = analyseur; const GEN x = expr(); if (typ(x) != t_POL || lgef(x) != 4 || !gcmp0((GEN)x[2]) || !gcmp1((GEN)x[3])) err(varer1,old,mark.start); return varn(x); } /* alright !=0 means function was called without () */ static int do_switch(int alright, int matchcomma) { if (alright || !*analyseur || *analyseur == ')' || separe(*analyseur)) return 1; if (*analyseur == ',') /* we just read an arg, or first arg */ { if (!matchcomma && analyseur[-1] == '(') return 1; /* first arg */ if (analyseur[1] == ',' || analyseur[1] == ')') { analyseur++; return 1; } } return 0; } /********************************************************************/ /** **/ /** READ FUNCTIONS **/ /** **/ /********************************************************************/ static GEN facteur(void) { const char *old = analyseur; GEN x,p1; int plus=1; switch(*analyseur) { case '-': plus=0; /* fall through */ case '+': analyseur++; break; } x = truc(); if (br_status) return NULL; for(;;) switch(*analyseur) { case '.': analyseur++; x = read_member(x); if (!x) err(talker2, "not a proper member definition", mark.member, mark.start); break; case '^': analyseur++; p1 = facteur(); if (br_status) err(breaker,"here (after ^)"); x = gpui(x,p1,prec); break; case '\'': analyseur++; x = deriv(x,gvar9(x)); break; case '~': analyseur++; x = gtrans(x); break; case '[': x = matrix_block(x,NULL); break; case '!': if (analyseur[1] != '=') { if (typ(x) != t_INT) err(caseer,old,mark.start); analyseur++; x=mpfact(itos(x)); break; } /* Fall through */ default: return (plus || x==gnil)? x: gneg(x); } } #define check_var_name() \ if (!isalpha((int)*analyseur)) err(varer1,analyseur,mark.start); static GEN truc(void) { long i,j, n=0, p=0, m=1, sizetab; GEN *table,p1; char *old; if (*analyseur == '!') { analyseur++; p1 = truc(); if (br_status) err(breaker,"here (after !)"); return gcmp0(p1)? gun: gzero; } if (*analyseur == '\'') { const char* old; entree *ep; analyseur++; check_var_name(); old = analyseur; ep = entry(); switch(EpVALENCE(ep)) { case EpVAR: case EpGVAR: return (GEN)initial_value(ep); default: err(varer1,old,mark.start); } } if (isalpha((int)*analyseur)) return identifier(); if (*analyseur == '"') return strtoGENstr_t(); if (isdigit((int)*analyseur) || *analyseur == '.') return constante(); switch(*analyseur++) { case '(': p1=expr(); match(')'); return p1; case '[': if (*analyseur == ';' && analyseur[1] == ']') { analyseur+=2; return cgetg(1,t_MAT); } old=analyseur; analyseur--; sizetab=skiptruc(); analyseur=old; table = (GEN*) gpmalloc((sizetab+1)*sizeof(GEN)); if (*analyseur != ']') { table[++n] = expr(); if (br_status) err(breaker,"array context"); } while (*analyseur == ',') { analyseur++; table[++n] = expr(); if (br_status) err(breaker,"array context"); } switch (*analyseur++) { case ']': p1=cgetg(n+1,t_VEC); for (i=1; i<=n; i++) p1[i] = lcopy(table[i]); break; case ';': m = n; do { table[++n] = expr(); if (br_status) err(breaker,"array context"); } while (*analyseur++ != ']'); p = n/m + 1; p1 = cgetg(m+1,t_MAT); for (j=1; j<=m; j++) { p1[j] = lgetg(p,t_COL); for (i=1; i' : if (analyseur[1]=='>') f = &gshift_r; break; case '<' : if (analyseur[1]=='<') f = &gshift_l; break; case '\\': if (analyseur[1]=='/') f = &gdivround; break; } if (!f) return (ep && !full_row)? cpt: gcopy(cpt); analyseur += 3; } old = analyseur; res = expr(); if (br_status) err(breaker,"assignment"); res = f(cpt, res); } /* assignment */ if (!ep) err(caracer1,analyseur,mark.start); if (!tx) /* simple variable */ { changevalue(ep,res); return (GEN) ep->value; } if (full_row) /* whole row (index r) */ { if (typ(res) != t_VEC || lg(res) != lg(p)) err(caseer2,old,mark.start); for (c=1; c *ptlimit) bp = realloc_buf(bp, len, ptbuf,ptlimit); memcpy(bp,tmp,len); /* ignore trailing \0 */ if (alloc) free(tmp); return bp + len; } static char * translate(char **src, char *s, char **ptbuf, char **ptlim) { char *t = *src; while (*t) { while (*t == '\\') { switch(*++t) { case 'e': *s='\033'; break; /* escape */ case 'n': *s='\n'; break; case 't': *s='\t'; break; default: *s=*t; if (!*t) err(talker,"unfinished string"); } t++; s++; } if (*t == '"') break; if (ptlim && s >= *ptlim) s = realloc_buf(s,1, ptbuf,ptlim); *s++ = *t++; } *s=0; *src=t; return s; } static char * readstring_i(char *s, char **ptbuf, char **ptlim) { match('"'); s = translate(&analyseur,s, ptbuf,ptlim); match('"'); return s; } static GEN any_string() { long n = 0, len = 16; GEN p1, res = new_chunk(len + 1); while (*analyseur) { if (*analyseur == '"') { res[n++] = (long) strtoGENstr_t(); continue; } if (*analyseur == ')' || *analyseur == ';') break; if (*analyseur == ',') analyseur++; else { p1 = expr(); if (br_status) err(breaker,"here (print)"); res[n++] = (long) p1; } if (n == len) { long newlen = len << 1; p1 = new_chunk(newlen + 1); for (n = 0; n < len; n++) p1[n] = res[n]; res = p1; len = newlen; } } res[n] = 0; /* end the sequence with NULL */ return res; } /* Read a "string" from src. Format then copy it, starting at s. Return * pointer to the \0 which terminates the string. */ char * readstring(char *src, char *s) { match2(src++, '"'); s = translate(&src, s, NULL,NULL); match2(src, '"'); return s; } static GEN strtoGENstr_t() { char *old = analyseur; long n; GEN x; skipstring(); n = analyseur-old - 1; /* don't count the enclosing '"' */ old++; /* skip '"' */ n = (n+BYTES_IN_LONG) >> TWOPOTBYTES_IN_LONG; x = cgetg(n+1, t_STR); translate(&old, GSTR(x), NULL,NULL); return x; } GEN strtoGENstr(char *s, long flag) { long n; GEN x; if (flag) s = expand_tilde(s); n = strlen(s)+1; n = (n+BYTES_IN_LONG) >> TWOPOTBYTES_IN_LONG; x = cgetg(n+1, t_STR); strcpy(GSTR(x), s); if (flag) free(s); return x; } /* p = NULL + array of variable numbers (longs) + function text */ static GEN call_fun(GEN p, GEN *arg, GEN *loc, int narg, int nloc) { GEN res; long i; p++; /* skip NULL */ /* push new values for formal parameters */ for (i=0; ivalence == EpALIAS) ep = (entree *) ((GEN)ep->value)[1]; return ep; } static GEN global0() { GEN res = gnil; long i,n; for (i=0,n=lg(polvar)-1; n>=0; n--) { entree *ep = varentries[n]; if (ep && EpVALENCE(ep) == EpGVAR) { res=new_chunk(1); res[0]=(long)polx[n]; i++; } } if (i) { res = cgetg(1,t_VEC); setlg(res, i+1); } return res; } static void check_pointer(unsigned int ptrs, GEN argvec[]) { unsigned int i; for (i=0; ptrs; i++,ptrs>>=1) if (ptrs & 1) *((GEN*)argvec[i]) = gclone(*((GEN*)argvec[i])); } #define match_comma() if (matchcomma) match(','); else matchcomma = 1 long check_args() { long nparam = 0, matchcomma = 0; entree *ep; char *old; GEN cell; while (*analyseur != ')') { old=analyseur; nparam++; match_comma(); cell = new_chunk(2); if (!isalpha((int)*analyseur)) { err_new_fun(); err(paramer1, mark.identifier, mark.start); } ep = entry(); if (EpVALENCE(ep) != EpVAR) { err_new_fun(); if (EpVALENCE(ep) == EpGVAR) err(talker2,"global variable: ",old , mark.start); err(paramer1, old, mark.start); } cell[0] = varn(initial_value(ep)); if (*analyseur == '=') { long av = avma; GEN p1; analyseur++; p1 = expr(); if (br_status) err(breaker,"here (default args)"); cell[1] = lclone(p1); avma = av; } else cell[1] = zero; } return nparam; } #define DFT_VAR (GEN)-1 #define DFT_GEN (GEN)NULL static GEN identifier(void) { long m,i,av,matchcomma; char *ch1; entree *ep; GEN res, newfun, ptr; mark.identifier = analyseur; ep = entry(); if (EpVALENCE(ep)==EpVAR || EpVALENCE(ep)==EpGVAR) { /* optimized for simple variables */ switch (*analyseur) { case ')': case ',': return (GEN)ep->value; case '.': { long len, v; analyseur++; ch1 = analyseur; if ((res = read_member((GEN)ep->value))) return res; /* define a new member function */ v = varn(initial_value(ep)); len = analyseur - ch1; analyseur++; /* skip = */ ep = installep(NULL,ch1,len,EpMEMBER,0, members_hash + hashvalue(ch1)); ch1 = analyseur; skipseq(); len = analyseur-ch1; newfun=ptr= (GEN) newbloc(1 + (len>>TWOPOTBYTES_IN_LONG) + 4); newfun++; /* this bloc is no GEN, leave the first cell alone ( = 0) */ *newfun++ = v; /* record text */ strncpy((char *)newfun, ch1, len); ((char *) newfun)[len] = 0; ep->value = (void *)ptr; return gnil; } } return matrix_block((GEN) ep->value,ep); } ep = do_alias(ep); matchcomma = 0; if (ep->code) { char *s = ep->code, *oldanalyseur = NULL, *buf, *limit, *bp; unsigned int ret = RET_GEN, alright=0, has_pointer=0; long fake; void *call = ep->value; GEN argvec[9]; if (*analyseur == '(') analyseur++; else { /* if no mandatory argument, no () needed */ if (EpVALENCE(ep)) match('('); /* error */ if (!*s || (!s[1] && *s == 'p')) return ((GEN (*)(long))ep->value)(prec); alright=1; /* no arg was given, but valence is ok */ } i = 0; /* Optimized for G and p. */ while (*s == 'G') { match_comma(); s++; argvec[i++] = expr(); if (br_status) err(breaker,"here (argument reading)"); } if (*s == 'p') { argvec[i++] = (GEN) prec; s++; } while (*s) switch (*s++) { case 'G': /* GEN */ match_comma(); argvec[i++] = expr(); if (br_status) err(breaker,"here (argument reading)"); break; case 'L': /* long */ match_comma(); argvec[i++] = (GEN) readlong(); break; case 'n': /* var number */ match_comma(); argvec[i++] = (GEN) readvar(); break; case 'V': case 'S': /* variable or symbol */ match_comma(); mark.symbol=analyseur; argvec[i++] = (GEN)entry(); break; case '&': /* *GEN */ match_comma(); match('&'); mark.symbol=analyseur; { entree *e = entry(); if (e->value == (void*)initial_value(e)) changevalue(e, gzero); /* don't overwrite initial value */ has_pointer |= (1 << i); argvec[i++] = (GEN) &(e->value); break; } case 'I': /* Input position */ match_comma(); argvec[i++] = (GEN) analyseur; skipseq(); break; case 'r': /* raw */ match_comma(); mark.raw = analyseur; bp = init_buf(256, &buf,&limit); while (*analyseur) { if (*analyseur == ',' || *analyseur == ')') break; if (*analyseur == '"') bp = readstring_i(bp, &buf,&limit); else { if (bp > limit) bp = realloc_buf(bp,1, &buf,&limit); *bp++ = *analyseur++; } } *bp++ = 0; argvec[i++] = (GEN) buf; break; case 's': /* expanded string; empty arg yields "" */ match_comma(); if (*s == '*') /* any number of string objects */ { argvec[i++] = any_string(); s++; break; } bp = init_buf(256, &buf,&limit); while (*analyseur) { if (*analyseur == ',' || *analyseur == ')') break; if (*analyseur == '"') bp = readstring_i(bp, &buf,&limit); else bp = expand_string(bp, &buf,&limit); } *bp++ = 0; argvec[i++] = (GEN)buf; break; case 'p': /* precision */ argvec[i++] = (GEN) prec; break; case '=': match('='); matchcomma = 0; break; case 'D': /* Has a default value */ if (do_switch(alright,matchcomma)) switch (*s) { case 'G': case '&': case 'I': case 'V': argvec[i++]=DFT_GEN; s++; break; case 'n': argvec[i++]=DFT_VAR; s++; break; default: oldanalyseur = analyseur; analyseur = s; matchcomma = 0; while (*s++ != ','); } else switch (*s) { case 'G': case '&': case 'I': case 'V': case 'n': break; default: while (*s++ != ','); } break; case 'P': /* series precision */ argvec[i++] = (GEN) precdl; break; case 'f': /* Fake *long argument */ argvec[i++] = (GEN) &fake; break; case 'x': /* Foreign function */ argvec[i++] = (GEN) ep; call = foreignHandler; break; case 'l': /* Return long */ ret = RET_INT; break; case 'v': /* Return void */ ret = RET_VOID; break; case ',': /* Clean up default */ if (oldanalyseur) { analyseur = oldanalyseur; oldanalyseur = NULL; matchcomma=1; } break; default: err(bugparier,"identifier (unknown code)"); } #if 0 /* uncomment if using purify: unitialized read otherwise */ for ( ; i<9; i++) argvec[i]=NULL; #endif switch (ret) { case RET_GEN: res = ((PFGEN)call)(argvec[0], argvec[1], argvec[2], argvec[3], argvec[4], argvec[5], argvec[6], argvec[7], argvec[8]); break; case RET_INT: m = ((long (*)(ANYARG))call)(argvec[0], argvec[1], argvec[2], argvec[3], argvec[4], argvec[5], argvec[6], argvec[7], argvec[8]); res = stoi(m); break; case RET_VOID: ((void (*)(ANYARG))call)(argvec[0], argvec[1], argvec[2], argvec[3], argvec[4], argvec[5], argvec[6], argvec[7], argvec[8]); res = gnil; break; } if (has_pointer) check_pointer(has_pointer,argvec); if (!alright) match(')'); return res; } if (EpPREDEFINED(ep)) { if (*analyseur != '(') { if (EpVALENCE(ep) == 88) return global0(); match('('); /* error */ } analyseur++; switch(EpVALENCE(ep)) { case 50: /* O */ res = truc(); if (br_status) err(breaker,"here (in O()))"); if (*analyseur=='^') { analyseur++; m = readlong(); } else m = 1; res = ggrando(res,m); break; case 80: /* if then else */ av = avma; res = expr(); if (br_status) err(breaker,"test expressions"); m = gcmp0(res); avma = av; match(','); if (m) /* false */ { skipseq(); if (*analyseur == ')') res = gnil; else { match(','); res = seq(); if (br_status) { res = NULL; skipseq(); } } } else /* true */ { res = seq(); if (br_status) { res = NULL; skipseq(); } if (*analyseur != ')') { match(','); skipseq(); } } break; case 81: /* while do */ av = avma; ch1 = analyseur; for(;;) { res = expr(); if (br_status) err(breaker,"test expressions"); if (gcmp0(res)) { match(','); break; } avma = av; match(','); (void)seq(); if (loop_break()) break; analyseur = ch1; } avma = av; skipseq(); res = gnil; break; case 82: /* repeat until */ av = avma; ch1 = analyseur; skipexpr(); for(;;) { avma = av; match(','); (void)seq(); if (loop_break()) break; analyseur = ch1; res = expr(); if (br_status) err(breaker,"test expressions"); if (!gcmp0(res)) { match(','); break; } } avma = av; skipseq(); res = gnil; break; case 88: /* global */ if (*analyseur == ')') return global0(); while (*analyseur != ')') { match_comma(); ch1=analyseur; ep = skipentry(); switch(EpVALENCE(ep)) { case EpGVAR: err(warner,"%s already declared global", ep->name); /* fall through */ case EpVAR: break; default: err(talker2,"symbol already in use",ch1,mark.start); } analyseur=ch1; ep = entry(); if (*analyseur == '=') { long av=avma; analyseur++; res = expr(); if (br_status) err(breaker,"here (defining global var)"); changevalue(ep, res); avma=av; } ep->valence = EpGVAR; } res = gnil; break; default: err(valencer1); } match(')'); return res; } switch (EpVALENCE(ep)) { GEN *defarg; /* = default args, and values for local variables */ int narg, nloc; gp_args *f; case EpUSER: /* user-defined functions */ f = (gp_args*)ep->args; defarg = f->arg; narg = f->narg; nloc = f->nloc; if (*analyseur != '(') /* no args */ { if (*analyseur != '=' || analyseur[1] == '=') return call_fun((GEN)ep->value, defarg, defarg+narg, narg, nloc); match('('); /* ==> error */ } if (analyseur != redefine_fun) { GEN *arglist = (GEN*) new_chunk(narg); ch1 = analyseur; analyseur++; for (i=0; i>TWOPOTBYTES_IN_LONG) + 4); newfun++; /* this bloc is no GEN, leave the first cell alone ( = 0) */ /* record default args */ f = (gp_args*) gpmalloc((narg+nloc)*sizeof(GEN) + sizeof(gp_args)); ep->args = (void*) f; f->nloc = nloc; f->narg = narg; f->arg = defarg = (GEN*)(f + 1); narg += nloc; /* record default args and local variables */ for (i = 1; i <= narg; i++) { GEN cell = tmpargs-(i<<1); *newfun++ = cell[0]; *defarg++ = (GEN)cell[1]; } if (narg > 1) { /* check for duplicates */ GEN x = new_chunk(narg), v = ptr+1; long k; for (i=0; iname, polx[k]); } /* record text */ strncpy((char *)newfun, start, len); ((char *) newfun)[len] = 0; if (EpVALENCE(ep) == EpUSER) gunclone((GEN)ep->value); /* have to wait till here because of the above line. (f()=f()=x). Text * of new fun is given by value of the old one, which had to be kept */ ep->value = (void *)ptr; ep->valence = EpUSER; check_new_fun=NULL; avma = (long)tmpargs; return gnil; } } err(valencer1); return NULL; /* not reached */ } static long number(long *nb) { long m = 0; for (*nb = 0; *nb < 9 && isdigit((int)*analyseur); (*nb)++) m = 10*m + (*analyseur++ - '0'); return m; } static GEN constante() { static long pw10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; long l,m,n = 0,nb, av = avma, limite = stack_lim(av,1); GEN z,y; y = stoi(number(&nb)); while (isdigit((int)*analyseur)) { m = number(&nb); y = addsi(m, mulsi(pw10[nb],y)); if (low_stack(limite, stack_lim(av,1))) y = gerepileupto(av,y); } switch(*analyseur) { default: return y; /* integer */ case '.': analyseur++; while (isdigit((int)*analyseur)) { m = number(&nb); n -= nb; y = addsi(m, mulsi(pw10[nb],y)); if (low_stack(limite, stack_lim(av,1))) y = gerepileupto(av,y); } if (*analyseur != 'E' && *analyseur != 'e') break; /* Fall through */ case 'E': case 'e': { char *old = analyseur; switch(*++analyseur) { case '-': analyseur++; n -= number(&nb); break; case '+': analyseur++; /* Fall through */ default: n += number(&nb); } if (nb > 8) err(talker2,"exponent too large: ",old,mark.start); } } l=lgefint(y); if (l