Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2000 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314#include "pari.h"15#include "paripriv.h"16#include "anal.h"17#include "parse.h"1819/***************************************************************************20** **21** Mnemonic codes parser **22** **23***************************************************************************/2425/* TEMPLATE is assumed to be ";"-separated list of items. Each item26* may have one of the following forms: id=value id==value id|value id&~value.27* Each id consists of alphanum characters, dashes and underscores.28* IDs are case-sensitive.2930* ARG consists of several IDs separated by punctuation (and optional31* whitespace). Each modifies the return value in a "natural" way: an32* ID from id=value should be the first in the sequence and sets RETVAL to33* VALUE (and cannot be negated), ID from id|value bit-ORs RETVAL with34* VALUE (and bit-ANDs RETVAL with ~VALUE if negated), ID from35* id&~value behaves as if it were noid|value, ID from36* id==value behaves the same as id=value, but should come alone.3738* For items of the form id|value and id&~value negated forms are39* allowed: either when arg looks like no[-_]id, or when id looks like40* this, and arg is not-negated. */4142static int43IS_ID(char c) { return isalnum((int)c) || c == '_'; }44long45eval_mnemonic(GEN str, const char *tmplate)46{47const char *arg, *etmplate;48ulong retval = 0;4950if (typ(str)==t_INT) return itos(str);51if (typ(str)!=t_STR) pari_err_TYPE("eval_mnemonic",str);5253arg = GSTR(str);54etmplate = strchr(tmplate, '\n');55if (!etmplate) etmplate = tmplate + strlen(tmplate);5657while (1)58{59long numarg;60const char *e, *id, *negated = NULL;61int negate = 0; /* Arg has 'no' prefix removed */62ulong l;63char *buf;64static char b[80];6566while (isspace((int)*arg)) arg++;67if (!*arg) break;68e = arg; while (IS_ID(*e)) e++;69/* Now the ID is whatever is between arg and e. */70l = e - arg;71if (l >= sizeof(b)) pari_err(e_MISC,"id too long in a mnemonic");72if (!l) pari_err(e_MISC,"mnemonic does not start with an id");73strncpy(b, arg, l); b[l] = 0;74arg = e; e = buf = b;75while ('0' <= *e && *e <= '9') e++;76if (*e == 0) pari_err(e_MISC,"numeric id in a mnemonic");77FIND:78id = tmplate;79while ((id = strstr(id, buf)) && id < etmplate)80{81const char *s = id;82id += l; if (s[l] != '|') continue; /* False positive */83if (s == tmplate || !IS_ID(s[-1])) break; /* Found as is */84/* If we found "no_ID", negate */85if (!negate && s >= tmplate+3 && (s == tmplate+3 || !IS_ID(s[-4]))86&& s[-3] == 'n' && s[-2] == 'o' && s[-1] == '_')87{ negated = id; break; }88}89if (!id && !negated && !negate && l > 390&& buf[0] == 'n' && buf[1] == 'o' && buf[2] == '_')91{ /* Try to find the flag without the prefix "no_". */92buf += 3; l -= 3; negate = 1;93if (buf[0]) goto FIND;94}95/* Negated and AS_IS forms, prefer AS_IS otherwise use negated form */96if (!id)97{98if (!negated) pari_err(e_MISC,"Unrecognized id '%s' in mnemonic", b);99id = negated; negate = 1;100}101if (*id++ != '|') pari_err(e_MISC,"Missing | in mnemonic template");102e = id;103while (*e >= '0' && *e <= '9') e++;104while (isspace((int)*e)) e++;105if (*e && *e != ';' && *e != ',')106pari_err(e_MISC, "Non-numeric argument in mnemonic template");107numarg = atol(id);108if (negate) retval &= ~numarg; else retval |= numarg;109while (isspace((int)*arg)) arg++;110if (*arg && !ispunct((int)*arg++)) /* skip punctuation */111pari_err(e_MISC,"Junk after id in mnemonic");112}113return retval;114}115116/********************************************************************/117/** **/118/** HASH TABLE MANIPULATIONS **/119/** **/120/********************************************************************/121static void122insertep(entree *ep, entree **table, ulong hash)123{124ep->hash = hash;125hash %= functions_tblsz;126ep->next = table[hash];127table[hash] = ep;128}129130static entree *131initep(const char *name, long len)132{133const long add = 4*sizeof(long);134entree *ep = (entree *) pari_calloc(sizeof(entree) + add + len+1);135entree *ep1 = initial_value(ep);136char *u = (char *) ep1 + add;137ep->name = u; memcpy(u, name,len); u[len]=0;138ep->valence = EpNEW;139ep->value = NULL;140ep->menu = 0;141ep->code = NULL;142ep->help = NULL;143ep->pvalue = NULL;144ep->arity = 0;145return ep;146}147148/* Look for s of length len in T; if 'insert', insert if missing */149static entree *150findentry(const char *s, long len, entree **T, int insert)151{152ulong hash = hash_str_len(s, len);153entree *ep;154for (ep = T[hash % functions_tblsz]; ep; ep = ep->next)155if (ep->hash == hash)156{157const char *t = ep->name;158if (!strncmp(t, s, len) && !t[len]) return ep;159}160/* not found */161if (insert) { ep = initep(s,len); insertep(ep, T, hash); }162return ep;163}164entree *165pari_is_default(const char *s)166{ return findentry(s, strlen(s), defaults_hash, 0); }167entree *168is_entry(const char *s)169{ return findentry(s, strlen(s), functions_hash, 0); }170entree *171fetch_entry_raw(const char *s, long len)172{ return findentry(s, len, functions_hash, 1); }173entree *174fetch_entry(const char *s) { return fetch_entry_raw(s, strlen(s)); }175176/*******************************************************************/177/* */178/* SYNTACTICAL ANALYZER FOR GP */179/* */180/*******************************************************************/181static GEN182readseq_i(char *t)183{184if (gp_meta(t,0)) return gnil;185return closure_evalres(pari_compile_str(t));186}187GEN188readseq(char *t)189{ pari_sp av = avma; return gerepileupto(av, readseq_i(t)); }190191/* filtered readseq = remove blanks and comments */192GEN193gp_read_str(const char *s)194{ pari_sp av = avma; return gerepileupto(av, readseq_i(gp_filter(s))); }195196GEN197compile_str(const char *s) { return pari_compile_str(gp_filter(s)); }198199GEN200gp_read_str_bitprec(const char *s, long bitprec)201{202GEN x;203push_localbitprec(bitprec);204x = gp_read_str(s);205pop_localprec();206return x;207}208209GEN210gp_read_str_prec(const char *s, long prec)211{ return gp_read_str_bitprec(s, prec2nbits(prec)); }212213/* valid return type */214static int215isreturn(char c)216{ return c == 'l' || c == 'v' || c == 'i' || c == 'm' || c == 'u'; }217218/* if is known that 2 commas follow s; base-10 signed integer followed219* by comma? */220static int221is_long(const char *s)222{223while (isspace(*s)) s++;224if (*s == '+' || *s == '-') s++;225while (isdigit(*s)) s++;226return *s == ',';227}228/* if is known that 2 commas follow s; base-10 unsigned integer followed229* by comma? */230static int231is_ulong(const char *s)232{233while (isspace(*s)) s++;234if (*s == '+') s++;235while (isdigit(*s)) s++;236return *s == ',';237}238static long239check_proto(const char *code)240{241long arity = 0;242const char *s = code;243if (isreturn(*s)) s++;244while (*s && *s != '\n') switch (*s++)245{246case '&':247case 'C':248case 'G':249case 'I':250case 'J':251case 'U':252case 'L':253case 'M':254case 'P':255case 'W':256case 'f':257case 'n':258case 'p':259case 'b':260case 'r':261arity++; break;262case 'E':263case 's':264if (*s == '*') s++;265arity++; break;266case 'D':267switch(*s)268{269case 'G': case '&': case 'n': case 'I': case 'E':270case 'P': case 's': case 'r': s++; arity++; break;271case 'V': s++; break;272case 0:273pari_err(e_SYNTAX,"function has incomplete prototype", s,code);274break;275default:276{277const char *p;278long i;279for(i = 0, p = s; *p && i < 2; p++) i += *p==','; /* skip 2 commas */280if (i < 2) pari_err(e_SYNTAX,"missing comma",s,code);281arity++;282switch(p[-2])283{284case 'L':285if (!is_long(s)) pari_err(e_SYNTAX,"not a long",s,code);286break;287case 'U':288if (!is_ulong(s)) pari_err(e_SYNTAX,"not an ulong",s,code);289break;290case 'G': case 'r': case 's': case 'M':291break;292default: pari_err(e_SYNTAX,"incorrect type",s-2,code);293}294s = p;295}296}297break;298case 'V':299case '=':300case ',': break;301case '\n': break; /* Before the mnemonic */302default:303if (isreturn(s[-1]))304pari_err(e_SYNTAX, "this code has to come first", s-1, code);305pari_err(e_SYNTAX, "unknown parser code", s-1, code);306}307if (arity > 20) pari_err_IMPL("functions with more than 20 parameters");308return arity;309}310static void311check_name(const char *name)312{313const char *s = name;314if (isalpha((int)*s))315while (is_keyword_char(*++s)) /* empty */;316if (*s) pari_err(e_SYNTAX,"not a valid identifier", s, name);317}318319entree *320install(void *f, const char *name, const char *code)321{322long arity = check_proto(code);323entree *ep;324325check_name(name);326ep = fetch_entry(name);327if (ep->valence != EpNEW)328{329if (ep->valence != EpINSTALL)330pari_err(e_MISC,"[install] identifier '%s' already in use", name);331pari_warn(warner, "[install] updating '%s' prototype; module not reloaded", name);332if (ep->code) pari_free((void*)ep->code);333}334else335{336ep->value = f;337ep->valence = EpINSTALL;338}339ep->code = pari_strdup(code);340ep->arity = arity; return ep;341}342343static void344killep(entree *ep)345{346GEN p = (GEN)initial_value(ep);347freeep(ep);348*p = 0; /* otherwise pari_var_create won't regenerate it */349ep->valence = EpNEW;350ep->value = NULL;351ep->pvalue = NULL;352}353/* Kill ep, i.e free all memory it references, and reset to initial value */354void355kill0(const char *e)356{357entree *ep = is_entry(e);358if (!ep || EpSTATIC(ep)) pari_err(e_MISC,"can't kill that");359killep(ep);360}361362void363addhelp(const char *e, char *s)364{365entree *ep = fetch_entry(e);366void *f = (void *) ep->help;367ep->help = pari_strdup(s);368if (f && !EpSTATIC(ep)) pari_free(f);369}370371/*******************************************************************/372/* */373/* PARSER */374/* */375/*******************************************************************/376377#ifdef LONG_IS_64BIT378static const long MAX_DIGITS = 19;379#else380static const long MAX_DIGITS = 9;381#endif382383static const long MAX_XDIGITS = BITS_IN_LONG>>2;384static const long MAX_BDIGITS = BITS_IN_LONG;385386static int387ishex(const char **s)388{389if (**s == '0' && ((*s)[1] == 'x' || (*s)[1] == 'X' ))390{391*s += 2;392return 1;393}394else395return 0;396}397398static int399isbin(const char **s)400{401if (**s == '0' && ((*s)[1] == 'b' || (*s)[1] == 'B' ))402{403*s += 2;404return 1;405}406else407return 0;408}409410static ulong411bin_number_len(const char *s, long n)412{413ulong m = 0;414long i;415for (i = 0; i < n; i++,s++)416m = 2*m + (*s - '0');417return m;418}419420static int421pari_isbdigit(int c)422{423return c=='0' || c=='1';424}425426static ulong427hex_number_len(const char *s, long n)428{429ulong m = 0;430long i;431for(i = 0; i < n; i++, s++)432{433ulong c;434if( *s >= '0' && *s <= '9')435c = *s - '0';436else if( *s >= 'A' && *s <= 'F')437c = *s - 'A' + 10;438else439c = *s - 'a' + 10;440m = 16*m + c;441}442return m;443}444445static GEN446strtobin_len(const char *s, long n, long B, ulong num(const char *s, long n))447{448long i, l = (n+B-1)/B;449GEN N, Np;450N = cgetipos(l+2);451Np = int_LSW(N);452for (i=1; i<l; i++, Np = int_nextW(Np))453uel(Np, 0) = num(s+n-i*B, B);454uel(Np, 0) = num(s, n-(i-1)*B);455return int_normalize(N, 0);456}457458static GEN459binary_read(const char **ps, long B, int is(int), ulong num(const char *s, long n))460{461const char *s = *ps;462while (is((int)**ps)) (*ps)++;463return strtobin_len(s, *ps-s, B, num);464}465466static GEN467bin_read(const char **ps)468{469return binary_read(ps, MAX_BDIGITS, pari_isbdigit, bin_number_len);470}471472static GEN473hex_read(const char **ps)474{475return binary_read(ps, MAX_XDIGITS, isxdigit, hex_number_len);476}477478static ulong479dec_number_len(const char *s, long B)480{481ulong m = 0;482long n;483for (n = 0; n < B; n++,s++)484m = 10*m + (*s - '0');485return m;486}487488static GEN489dec_strtoi_len(const char *s, long n)490{491const long B = MAX_DIGITS;492long i, l = (n+B-1)/B;493GEN V = cgetg(l+1, t_VECSMALL);494for (i=1; i<l; i++)495uel(V,i) = dec_number_len(s+n-i*B, B);496uel(V, i) = dec_number_len(s, n-(i-1)*B);497return fromdigitsu(V, powuu(10, B));498}499500static GEN501dec_read_more(const char **ps)502{503pari_sp av = avma;504const char *s = *ps;505while (isdigit((int)**ps)) (*ps)++;506return gerepileuptoint(av, dec_strtoi_len(s, *ps-s));507}508509static ulong510number(int *n, const char **s)511{512ulong m = 0;513for (*n = 0; *n < MAX_DIGITS && isdigit((int)**s); (*n)++,(*s)++)514m = 10*m + (**s - '0');515return m;516}517518static GEN519dec_read(const char **s)520{521int nb;522ulong y = number(&nb, s);523if (nb < MAX_DIGITS)524return utoi(y);525*s -= MAX_DIGITS;526return dec_read_more(s);527}528529static GEN530real_read_more(GEN y, const char **ps)531{532pari_sp av = avma;533const char *s = *ps;534GEN z = dec_read(ps);535long e = *ps-s;536return gerepileuptoint(av, addmulii(z, powuu(10, e), y));537}538539static long540exponent(const char **pts)541{542const char *s = *pts;543long n;544int nb;545switch(*++s)546{547case '-': s++; n = -(long)number(&nb, &s); break;548case '+': s++; /* Fall through */549default: n = (long)number(&nb, &s);550}551*pts = s; return n;552}553554static GEN555real_0_digits(long n) {556long b = (n > 0)? (long)(n/LOG10_2): (long)-((-n)/LOG10_2 + 1);557return real_0_bit(b);558}559560static GEN561real_read(pari_sp av, const char **s, GEN y, long prec)562{563long l, n = 0;564switch(**s)565{566default: return y; /* integer */567case '.':568{569const char *old = ++*s;570if (isalpha((int)**s) || **s=='.')571{572if (**s == 'E' || **s == 'e') {573n = exponent(s);574if (!signe(y)) { set_avma(av); return real_0_digits(n); }575break;576}577--*s; return y; /* member */578}579if (isdigit((int)**s)) y = real_read_more(y, s);580n = old - *s;581if (**s != 'E' && **s != 'e')582{583if (!signe(y)) { set_avma(av); return real_0(prec); }584break;585}586}587/* Fall through */588case 'E': case 'e':589n += exponent(s);590if (!signe(y)) { set_avma(av); return real_0_digits(n); }591}592l = nbits2prec(bit_accuracy(lgefint(y)));593if (l < prec) l = prec; else prec = l;594if (!n) return itor(y, prec);595incrprec(l);596y = itor(y, l);597if (n > 0)598y = mulrr(y, rpowuu(10UL, (ulong)n, l));599else600y = divrr(y, rpowuu(10UL, (ulong)-n, l));601return gerepileuptoleaf(av, rtor(y, prec));602}603604static GEN605int_read(const char **s)606{607GEN y;608if (isbin(s))609y = bin_read(s);610else if (ishex(s))611y = hex_read(s);612else613y = dec_read(s);614return y;615}616617GEN618strtoi(const char *s) { return int_read(&s); }619620GEN621strtor(const char *s, long prec)622{623pari_sp av = avma;624GEN y = dec_read(&s);625y = real_read(av, &s, y, prec);626if (typ(y) == t_REAL) return y;627return gerepileuptoleaf(av, itor(y, prec));628}629630static void631skipdigits(char **lex) {632while (isdigit((int)**lex)) ++*lex;633}634635static int636skipexponent(char **lex)637{638char *old=*lex;639if ((**lex=='e' || **lex=='E'))640{641++*lex;642if ( **lex=='+' || **lex=='-' ) ++*lex;643if (!isdigit((int)**lex))644{645*lex=old;646return KINTEGER;647}648skipdigits(lex);649return KREAL;650}651return KINTEGER;652}653654static int655skipconstante(char **lex)656{657skipdigits(lex);658if (**lex=='.')659{660char *old = ++*lex;661if (**lex == '.') { --*lex; return KINTEGER; }662if (isalpha((int)**lex))663{664skipexponent(lex);665if (*lex == old)666{667--*lex; /* member */668return KINTEGER;669}670return KREAL;671}672skipdigits(lex);673skipexponent(lex);674return KREAL;675}676return skipexponent(lex);677}678679static void680skipstring(char **lex)681{682while (**lex)683{684while (**lex == '\\') *lex+=2;685if (**lex == '"')686{687if ((*lex)[1] != '"') break;688*lex += 2; continue;689}690(*lex)++;691}692}693694int695pari_lex(union token_value *yylval, struct node_loc *yylloc, char **lex)696{697(void) yylval;698yylloc->start=*lex;699if (!**lex)700{701yylloc->end=*lex;702return 0;703}704if (isalpha((int)**lex))705{706while (is_keyword_char(**lex)) ++*lex;707yylloc->end=*lex;708return KENTRY;709}710if (**lex=='"')711{712++*lex;713skipstring(lex);714if (!**lex)715compile_err("run-away string",*lex-1);716++*lex;717yylloc->end=*lex;718return KSTRING;719}720if (**lex == '.')721{722int token;723if ((*lex)[1]== '.')724{725*lex+=2; yylloc->end = *lex; return KDOTDOT;726}727token=skipconstante(lex);728if (token==KREAL)729{730yylloc->end = *lex;731return token;732}733++*lex;734yylloc->end=*lex;735return '.';736}737if (isbin((const char**)lex))738{739while (**lex=='0' || **lex=='1') ++*lex;740return KINTEGER;741}742if (ishex((const char**)lex))743{744while (isxdigit((int)**lex)) ++*lex;745return KINTEGER;746}747if (isdigit((int)**lex))748{749int token=skipconstante(lex);750yylloc->end = *lex;751return token;752}753if ((*lex)[1]=='=')754switch (**lex)755{756case '=':757if ((*lex)[2]=='=')758{ *lex+=3; yylloc->end = *lex; return KID; }759else760{ *lex+=2; yylloc->end = *lex; return KEQ; }761case '>':762*lex+=2; yylloc->end = *lex; return KGE;763case '<':764*lex+=2; yylloc->end = *lex; return KLE;765case '*':766*lex+=2; yylloc->end = *lex; return KME;767case '/':768*lex+=2; yylloc->end = *lex; return KDE;769case '%':770if ((*lex)[2]=='=') break;771*lex+=2; yylloc->end = *lex; return KMODE;772case '!':773if ((*lex)[2]=='=') break;774*lex+=2; yylloc->end = *lex; return KNE;775case '\\':776*lex+=2; yylloc->end = *lex; return KEUCE;777case '+':778*lex+=2; yylloc->end = *lex; return KPE;779case '-':780*lex+=2; yylloc->end = *lex; return KSE;781}782if (**lex==')' && (*lex)[1]=='-' && (*lex)[2]=='>')783{784*lex+=3; yylloc->end = *lex; return KPARROW;785}786if (**lex=='-' && (*lex)[1]=='>')787{788*lex+=2; yylloc->end = *lex; return KARROW;789}790if (**lex=='<' && (*lex)[1]=='>')791{792*lex+=2; yylloc->end = *lex; return KNE;793}794if (**lex=='\\' && (*lex)[1]=='/')795switch((*lex)[2])796{797case '=':798*lex+=3; yylloc->end = *lex; return KDRE;799default:800*lex+=2; yylloc->end = *lex; return KDR;801}802if ((*lex)[1]==**lex)803switch (**lex)804{805case '&':806*lex+=2; yylloc->end = *lex; return KAND;807case '|':808*lex+=2; yylloc->end = *lex; return KOR;809case '+':810*lex+=2; yylloc->end = *lex; return KPP;811case '-':812*lex+=2; yylloc->end = *lex; return KSS;813case '>':814if ((*lex)[2]=='=') { *lex+=3; yylloc->end = *lex; return KSRE;}815*lex+=2; yylloc->end = *lex; return KSR;816case '<':817if ((*lex)[2]=='=')818{ *lex+=3; yylloc->end = *lex; return KSLE; }819*lex+=2; yylloc->end = *lex; return KSL;820}821yylloc->end = *lex+1;822return (unsigned char) *(*lex)++;823}824825/********************************************************************/826/* */827/* Formal variables management */828/* */829/********************************************************************/830static THREAD long max_priority, min_priority;831static THREAD long max_avail; /* max variable not yet used */832static THREAD long nvar; /* first GP free variable */833static hashtable *h_polvar;834835void836varstate_save(struct pari_varstate *s)837{838s->nvar = nvar;839s->max_avail = max_avail;840s->max_priority = max_priority;841s->min_priority = min_priority;842}843844static void845varentries_set(long v, entree *ep)846{847hash_insert(h_polvar, (void*)ep->name, (void*)v);848varentries[v] = ep;849}850static int851_given_value(void *E, hashentry *e) { return e->val == E; }852853static void854varentries_unset(long v)855{856entree *ep = varentries[v];857if (ep)858{859hashentry *e = hash_remove_select(h_polvar, (void*)ep->name, (void*)v,860_given_value);861if (!e) pari_err_BUG("varentries_unset [unknown var]");862varentries[v] = NULL;863pari_free(e);864if (v <= nvar && ep == is_entry(ep->name))865{ /* known to the GP interpreter; entree in functions_hash is permanent */866GEN p = (GEN)initial_value(ep);867if (ep->value == p) { ep->value = NULL; ep->valence = EpNEW; }868*p = 0;869}870else /* from name_var() or a direct pari_var_create() */871pari_free(ep);872}873}874static void875varentries_reset(long v, entree *ep)876{877varentries_unset(v);878varentries_set(v, ep);879}880881static void882var_restore(struct pari_varstate *s)883{884nvar = s->nvar;885max_avail = s->max_avail;886max_priority = s->max_priority;887min_priority = s->min_priority;888}889890void891varstate_restore(struct pari_varstate *s)892{893long i;894for (i = nvar; i >= s->nvar; i--)895{896varentries_unset(i);897varpriority[i] = -i;898}899for (i = max_avail+1; i <= s->max_avail; i++)900{901varentries_unset(i);902varpriority[i] = -i;903}904var_restore(s);905}906907void908pari_set_varstate(long *vp, struct pari_varstate *vs)909{910var_restore(vs);911varpriority = (long*)newblock(MAXVARN+2) + 1;912memcpy(varpriority-1,vp-1,(MAXVARN+2)*sizeof(long));913}914915/* must come before destruction of functions_hash */916void917pari_var_close(void)918{919GEN h = hash_values(h_polvar);920long i, l = lg(h);921for (i = 1; i < l; i++)922{923long v = h[i];924entree *ep = varentries[v];925if (ep && ep != is_entry(ep->name)) pari_free(ep);926}927free((void*)varentries);928free((void*)(varpriority-1));929hash_destroy(h_polvar);930}931932void933pari_var_init(void)934{935long i;936varentries = (entree**) pari_calloc((MAXVARN+1)*sizeof(entree*));937varpriority = (long*)pari_malloc((MAXVARN+2)*sizeof(long)) + 1;938varpriority[-1] = 1-LONG_MAX;939h_polvar = hash_create_str(100, 0);940nvar = 0; max_avail = MAXVARN;941max_priority = min_priority = 0;942(void)fetch_user_var("x");943(void)fetch_user_var("y");944/* initialize so that people can use pol_x(i) directly */945for (i = 2; i <= (long)MAXVARN; i++) varpriority[i] = -i;946/* reserve varnum 1..9 for static temps with predictable priority wrt x */947nvar = 10;948min_priority = -MAXVARN;949}950long pari_var_next(void) { return nvar; }951long pari_var_next_temp(void) { return max_avail; }952long953pari_var_create(entree *ep)954{955GEN p = (GEN)initial_value(ep);956long v;957if (*p) return varn(p);958if (nvar == max_avail) pari_err(e_MISC,"no more variables available");959v = nvar++;960/* set p = pol_x(v) */961p[0] = evaltyp(t_POL) | _evallg(4);962p[1] = evalsigne(1) | evalvarn(v);963gel(p,2) = gen_0;964gel(p,3) = gen_1;965varentries_set(v, ep);966varpriority[v]= min_priority--;967return v;968}969970long971delete_var(void)972{ /* user wants to delete one of his/her/its variables */973if (max_avail == MAXVARN) return 0; /* nothing to delete */974max_avail++;975if (varpriority[max_avail] == min_priority) min_priority++;976else if (varpriority[max_avail] == max_priority) max_priority--;977return max_avail+1;978}979long980fetch_var(void)981{982if (nvar == max_avail) pari_err(e_MISC,"no more variables available");983varpriority[max_avail] = min_priority--;984return max_avail--;985}986long987fetch_var_higher(void)988{989if (nvar == max_avail) pari_err(e_MISC,"no more variables available");990varpriority[max_avail] = ++max_priority;991return max_avail--;992}993994static int995_higher(void *E, hashentry *e)996{ long v = (long)e->val; return (varncmp(v, (long)E) < 0); }997static int998_lower(void *E, hashentry *e)999{ long v = (long)e->val; return (varncmp(v, (long)E) > 0); }10001001static GEN1002var_register(long v, const char *s)1003{1004varentries_reset(v, initep(s, strlen(s)));1005return pol_x(v);1006}1007GEN1008varhigher(const char *s, long w)1009{1010long v;1011if (w >= 0)1012{1013hashentry *e = hash_select(h_polvar, (void*)s, (void*)w, _higher);1014if (e) return pol_x((long)e->val);1015}1016/* no luck: need to create */1017if (nvar == max_avail) pari_err(e_MISC,"no more variables available");1018v = nvar++;1019varpriority[v]= ++max_priority;1020return var_register(v, s);1021}1022GEN1023varlower(const char *s, long w)1024{1025long v;1026if (w >= 0)1027{1028hashentry *e = hash_select(h_polvar, (void*)s, (void*)w, _lower);1029if (e) return pol_x((long)e->val);1030}1031/* no luck: need to create */1032v = fetch_var();1033return var_register(v, s);1034}10351036long1037fetch_user_var(const char *s)1038{1039entree *ep = fetch_entry(s);1040long v;1041switch (EpVALENCE(ep))1042{1043case EpVAR: return varn((GEN)initial_value(ep));1044case EpNEW: break;1045default: pari_err(e_MISC, "%s already exists with incompatible valence", s);1046}1047v = pari_var_create(ep);1048ep->valence = EpVAR;1049ep->value = initial_value(ep);1050return v;1051}10521053GEN1054fetch_var_value(long v, GEN t)1055{1056entree *ep = varentries[v];1057if (!ep) return NULL;1058if (t)1059{1060long vn = localvars_find(t,ep);1061if (vn) return get_lex(vn);1062}1063return (GEN)ep->value;1064}10651066void1067name_var(long n, const char *s)1068{1069entree *ep;1070char *u;10711072if (n < pari_var_next())1073pari_err(e_MISC, "renaming a GP variable is forbidden");1074if (n > (long)MAXVARN)1075pari_err_OVERFLOW("variable number");10761077ep = (entree*)pari_malloc(sizeof(entree) + strlen(s) + 1);1078u = (char *)initial_value(ep);1079ep->valence = EpVAR;1080ep->name = u; strcpy(u,s);1081ep->value = gen_0; /* in case geval is called */1082varentries_reset(n, ep);1083}10841085static int1086cmp_by_var(void *E,GEN x, GEN y)1087{ (void)E; return varncmp((long)x,(long)y); }1088GEN1089vars_sort_inplace(GEN z)1090{ gen_sort_inplace(z,NULL,cmp_by_var,NULL); return z; }1091GEN1092vars_to_RgXV(GEN h)1093{1094long i, l = lg(h);1095GEN z = cgetg(l, t_VEC);1096for (i = 1; i < l; i++) gel(z,i) = pol_x(h[i]);1097return z;1098}1099GEN1100gpolvar(GEN x)1101{1102long v;1103if (!x) {1104GEN h = hash_values(h_polvar);1105return vars_to_RgXV(vars_sort_inplace(h));1106}1107if (typ(x)==t_PADIC) return gcopy( gel(x,2) );1108v = gvar(x);1109if (v==NO_VARIABLE) return gen_0;1110return pol_x(v);1111}11121113static void1114fill_hashtable_single(entree **table, entree *ep)1115{1116EpSETSTATIC(ep);1117insertep(ep, table, hash_str(ep->name));1118if (ep->code) ep->arity = check_proto(ep->code);1119ep->pvalue = NULL;1120}11211122void1123pari_fill_hashtable(entree **table, entree *ep)1124{1125for ( ; ep->name; ep++) fill_hashtable_single(table, ep);1126}11271128void1129pari_add_function(entree *ep)1130{1131fill_hashtable_single(functions_hash, ep);1132}11331134/********************************************************************/1135/** **/1136/** SIMPLE GP FUNCTIONS **/1137/** **/1138/********************************************************************/11391140GEN1141arity0(GEN C)1142{1143if (typ(C)!=t_CLOSURE) pari_err_TYPE("arity", C);1144return utoi(closure_arity(C));1145}11461147#define ALIAS(ep) (entree *) ((GEN)ep->value)[1]11481149entree *1150do_alias(entree *ep)1151{1152while (ep->valence == EpALIAS) ep = ALIAS(ep);1153return ep;1154}11551156void1157alias0(const char *s, const char *old)1158{1159entree *ep, *e;1160GEN x;11611162ep = fetch_entry(old);1163e = fetch_entry(s);1164if (EpVALENCE(e) != EpALIAS && EpVALENCE(e) != EpNEW)1165pari_err(e_MISC,"can't replace an existing symbol by an alias");1166freeep(e);1167x = cgetg_block(2, t_VECSMALL); gel(x,1) = (GEN)ep;1168e->value=x; e->valence=EpALIAS;1169}11701171GEN1172ifpari(GEN g, GEN a/*closure*/, GEN b/*closure*/)1173{1174if (gequal0(g)) /* false */1175return b? closure_evalgen(b): gnil;1176else /* true */1177return a? closure_evalgen(a): gnil;1178}11791180void1181ifpari_void(GEN g, GEN a/*closure*/, GEN b/*closure*/)1182{1183if (gequal0(g)) /* false */1184{ if (b) closure_evalvoid(b); }1185else /* true */1186{ if (a) closure_evalvoid(a); }1187}11881189GEN1190ifpari_multi(GEN g, GEN a/*closure*/)1191{1192long i, nb = lg(a)-1;1193if (!gequal0(g)) /* false */1194return closure_evalgen(gel(a,1));1195for(i=2;i<nb;i+=2)1196{1197GEN g = closure_evalgen(gel(a,i));1198if (!g) return g;1199if (!gequal0(g))1200return closure_evalgen(gel(a,i+1));1201}1202return i<=nb? closure_evalgen(gel(a,i)): gnil;1203}12041205GEN1206andpari(GEN a, GEN b/*closure*/)1207{1208GEN g;1209if (gequal0(a))1210return gen_0;1211g=closure_evalgen(b);1212if (!g) return g;1213return gequal0(g)?gen_0:gen_1;1214}12151216GEN1217orpari(GEN a, GEN b/*closure*/)1218{1219GEN g;1220if (!gequal0(a))1221return gen_1;1222g=closure_evalgen(b);1223if (!g) return g;1224return gequal0(g)?gen_0:gen_1;1225}12261227GEN gmule(GEN *x, GEN y) { *x = gmul(*x,y); return *x; }1228GEN gdive(GEN *x, GEN y) { *x = gdiv(*x,y); return *x; }1229GEN gdivente(GEN *x, GEN y) { *x = gdivent(*x,y); return *x; }1230GEN gdivrounde(GEN *x, GEN y) { *x = gdivround(*x,y); return *x; }1231GEN gmode(GEN *x, GEN y) { *x = gmod(*x,y); return *x; }1232GEN gshiftle(GEN *x, long n) { *x = gshift(*x,n); return *x; }1233GEN gshiftre(GEN *x, long n) { *x = gshift(*x,-n); return *x; }1234GEN gadde(GEN *x, GEN y) { *x = gadd(*x,y); return *x; }1235GEN gadd1e(GEN *x) { *x = typ(*x)==t_INT?addiu(*x,1):gaddgs(*x,1); return *x; }1236GEN gsube(GEN *x, GEN y) { *x = gsub(*x,y); return *x; }1237GEN gsub1e(GEN *x) { *x = typ(*x)==t_INT?subiu(*x,1):gsubgs(*x,1); return *x; }12381239GEN gshift_right(GEN x, long n) { return gshift(x,-n); }124012411242