Sindbad~EG File Manager
/* M. Beeson, for Mathpert */
/* Given a term t, produce a string that parses to t */
/*
Original data 8.1.96
modified 6.21.99
1.8.00 corrected psize and pstring on bignums
1.21.00 corrected psize, adding needparen to match pstring
1.20.00 added #ifdef PRODUCTION to block assertion failure in release version
3.9.01 corrected pstring and psize on 9*2 etc.
3.26.01 corrected pstring for CONSTANTOFINTEGRATION
5.31.01 eliminated needparen from pstring--always use parentheses when arity is 1.
6.17.04 removed conditional 16-bit compilation.
9.5.04 moved this file into parser.dll; put in call to get_decimalchar
Changed ltoa to sprintf.
9.6.04 changed itoa to sprintf.
9.11.04 initialized buffer[0]= 0 in pstring.
4.7.06 changed gcvt to _gcvt
8.19.07 added EulerGamma to defined_atom_string
4.18.13 added casts (int) strlen..
5.4.13 changed _gcvt to gcvt twice.
5.8.13 introduced conditional compilation for gcvt
12.8.14 modified pstring at line 353
added code to psize at line 86.
8.8.24 changed my_gcvt to snprint (some time ago!)
and today put 32 for its size limit.
9.4.24 modified pstring to work on interval_as_and
9.5.24 and again, for Greeks
10.2.24 corrected pstring on interval_as_and, was returning 0
10.14.24 corrected pstring at line 219 (in the previous correction!)
11.10.24 added pstring.h
12.11.24 made pstring handle OR, as A | B [undone 1.6.25 now that |m| parses as ABS ]
12.26.24 corrected pstring at lines 435-436
1.6.25 undid change of 12.11.24
*/
#include <assert.h>
#include <string.h>
#include <stdio.h> /* sprintf */
#include "terms.h"
#include "pstring.h"
#include "dispfunc.h"
#include "parser.h" /* get_decimalchar */
#include "prover.h" /* interval_as_and */
#include "mygcvt.h"
#include "pstring.h" /* pstring */
static char *defined_atom_string(term t);
/*_______________________________________________________________*/
int psize(term t)
/* return a number of bytes sufficient for the output of pstring,
not counting the null terminator. */
/* This function counts 23 bytes per double and 10 bytes per integer
over 100, but only 2 bytes for integers less than 100,
and sizeof(int) times the length of a bignum.
*/
{ unsigned short f,n;
int i,ans;
term u;
int needparen;
char buffer[32];
f = FUNCTOR(t);
if(OBJECT(t))
{ switch(TYPE(t))
{ case INTEGER:
return INTDATA(t) < 100 ? 2 : 10;
case DOUBLE:
return 23; /* 18 digits plus "e+030" */
case BIGNUM:
ans = (int) (1.6054934 * (BIGNUMDATA(t)).ln + 1) +1;
/* see btod and bignum_string in bignum.c
for explanation of this line. */
return 6*ans + 1;
}
}
if(ISATOM(t))
{ if(('a' <= f && f <= 'z') ||
('A' <= f && f <= 'Z')
)
return (int) strlen(atom_string(t));
if(PREDEFINED_ATOM(f))
return (int) strlen(defined_atom_string(t));
if(SUBSCRIPT(f))
return (int) strlen(atom_string(t)) + 10;
}
n = ARITY(t);
if(f == '+' || f == '*' || f == AND)
{ ans = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(f == '+' && NEGATIVE(u))
{ u = ARG(0,u);
if(i==0)
++ans; // an initial minus sign as in -u+1
}
ans += psize(u);
if(f != '*' || !INTEGERP(u) || (i < n-1 && INTEGERP(ARG(i+1,u))))
++ans; /* +1 for the '+' or '-' sign, comma, or space */
if(f == '*' && FRACTION(u))
needparen = 1;
/* in 2d display a fraction in a product does not need parens,
but in parseable text, it does: 3 (sqrt(3)/2) is
different from 3 sqrt(3)/2. */
else
needparen = paren(f,FUNCTOR(u),(unsigned short)(i == 0 ? LEFT : i == n-1 ? RIGHT: CENTRAL));
if(needparen)
ans += 2; /* two for the parentheses */
}
return ans-1; /* -1 because no '+' needed after last arg */
}
if(f == FACTORIAL)
{ ans = 2 + psize(ARG(0,t));
if(!ATOMIC(ARG(0,t)))
ans += 2; /* for parentheses */
return ans;
}
if(INEQUALITY(f) || f == '/' || f == '^' || f == ':')
{ ans = psize(ARG(0,t)) + psize(ARG(1,t));
if(f == '=' || f == '<' || f == '>')
return ans+3;
if(f == LE || f == GE)
return ans+4;
if(f == '^')
{ if(ATOMIC(ARG(0,t)) && ATOMIC(ARG(1,t)))
return ans + 1;
if(ATOMIC(ARG(0,t)) || ATOMIC(ARG(1,t)))
return ans + 3;
return ans +5;
}
if(f == '/')
{ if(paren(FRACT, FUNCTOR(ARG(0,t)),LEFT))
ans += 2;
if(paren(FRACT, FUNCTOR(ARG(1,t)),RIGHT))
ans += 2;
return ans + 1; /* 1 for the '/' sign */
}
if(f == ':')
return ans + 1; /* 1 for the ':' */
}
functor_string(f,0,buffer);
ans = (int) strlen(buffer) + 2; /* 2 for parentheses */
for(i=0;i<n;i++)
ans += psize(ARG(i,t)) + 1; /* 1 for the comma */
return ans-1; /* we counted one comma too many */
}
/*_______________________________________________________________*/
int pstring(term t, char *buffer, int m)
/* write into buffer a string that will parse to t.
Assumes that there are m+1 bytes available in buffer.
Return the number of bytes actually used, not counting the null
terminator, or 0 if m bytes is not enough space.
*/
{ char *printstring,*fstring,*marker;
int k,i,ans;
term u;
unsigned short f,n;
char temp[40];
int needparen;
f = FUNCTOR(t);
buffer[0] = 0; // so strcat will work
if(OBJECT(t))
{ switch(TYPE(t))
{ case INTEGER:
sprintf(temp,"%lu",INTDATA(t));
if((int)strlen(temp) > m)
return 0;
strcpy(buffer,temp);
return (int) strlen(buffer);
case DOUBLE:
my_gcvt0(DOUBLEDATA(t),16,temp);
/* 16 is the precision to use. Even though we
use less precision for display, for capturing terms
we want the full precision available.
*/
if((int) strlen(temp) > m)
return 0;
strcpy(buffer,temp);
return (int) strlen(buffer);
case BIGNUM:
printstring = bignum_string(BIGNUMDATA(t),1);
/* the 1 says not to separate the digits by comma or any other character.
Commas in a bignum won't parse */
ans = (int) strlen(printstring);
if(ans > m)
{ free2(printstring);
return 0;
}
strcpy(buffer,printstring);
free2(printstring);
return ans;
}
}
if(ISATOM(t))
{ if(('a' <= f && f <= 'z') ||
('A' <= f && f <= 'Z')
)
{ printstring = atom_string(t);
strcpy(buffer,printstring);
return (int) strlen(buffer);
}
if(PREDEFINED_ATOM(f))
{ printstring = defined_atom_string(t);
strcpy(buffer,printstring);
return (int) strlen(buffer);
}
if(SUBSCRIPT(f))
{ int subscript;
term temp = t;
SETFUNCTOR(temp,VARNAME(f),0);
strcpy(buffer,atom_string(temp));
subscript = SUBSCRIPT(f)-1;
sprintf(buffer + strlen(buffer), "%d", subscript);
return (int) strlen(buffer);
}
}
n = ARITY(t);
if(interval_as_and(t))
{ /* then put the answer in buffer without AND, e.g. 0 <= x <= 2 pi */
int half = pstring(ARG(0,t),buffer, m); // 0 <= x
term x = ARG(0,ARG(1,t)); // the variable in the middle
// x might be a single-letter variable or a Greek variable
char varbuf[32];
int k = pstring(x,varbuf,32);
// k is more than one if and only if x is a Greek variable
ans = half -k + pstring(ARG(1,t), buffer+half-k,m-half+k);
return ans;
}
if(f == '+' || f == '*' || f == AND )
{ /* a + b + c is the desired output form */
marker = buffer;
ans = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(f == '+' && NEGATIVE(u))
{ u = ARG(0,u);
if(i==0)
{ *marker = '-';
++marker;
++ans;
}
}
/* does u need parentheses? */
if(f == '*' && FRACTION(u))
needparen = 1;
/* in 2d display a fraction in a product does not need parens,
but in parseable text, it does: 3 (sqrt(3)/2) is
different from 3 sqrt(3)/2. */
else
needparen = paren(f,FUNCTOR(u),(unsigned short)(i == 0 ? LEFT : i == n-1 ? RIGHT: CENTRAL));
if(needparen)
{ strcat(marker,"(");
--m;
++ans;
++marker;
}
k = pstring(u,marker,m);
if(k==0)
return 0; /* doesn't fit */
if(k > m)
return 0;
m -= k;
marker += k;
ans += k;
if(needparen)
{ strcat(marker,")");
--m;
++ans;
++marker;
}
if(i < n-1 && (f != '*' || !INTEGERP(ARG(i,t)) || INTEGERP(ARG(i+1,t))))
{ strcat(marker,f == '+' ?
(NEGATIVE(ARG(i+1,t)) ? "-" : "+" ):
f == '*' ? " " :
f == OR ? "|" :
"," // f == AND
);
++marker;
++ans;
--m;
}
}
if(ans != (int) strlen(buffer))
assert(0);
return ans;
}
if(f == FACTORIAL)
/* DEGREE is postfix on output, but it is typed in as deg(30); so FACTORIAL
is the only postfix function on input. */
{ if(!ATOMIC(ARG(0,t)))
{ buffer[0] = '(';
ans = pstring(ARG(0,t),buffer+1,m-1);
if(ans == 0 || ans >= m-2)
return 0;
strcat(buffer,")! ");
return ans+4;
}
else
{ ans = pstring(ARG(0,t),buffer,m);
if(ans == 0 || ans >= m-1)
return 0;
strcat(buffer,"! "); /* extra space to avoid writing != which parses as NE */
return ans+2;
}
}
if(f == ':' && ISINTEGER(ARG(1,t))) /* a type judgement like x:N */
{ marker = buffer;
buffer[0] = 0;
ans = 0;
k = pstring(ARG(0,t),marker,m);
if(k == 0 || k >= m)
return 0;
ans +=k;
marker += k;
m -= k;
strcat(buffer,":");
++marker;
++ans;
--m;
if(m == 0)
return 0;
switch(INTDATA(ARG(1,t)))
{ case INTEGER:
fstring = "Z";
break;
case DCOMPLEX:
fstring = "C";
break;
case NATNUM:
fstring = "N";
break;
case R:
fstring = "R";
break;
case RATIONAL:
fstring = "Q";
break;
default:
assert(0);
}
strcat(buffer,fstring);
++ans;
return ans;
}
if(INEQUALITY(f) || f == '/' || f == '^' || f == ARROW || f == ':')
{ fstring = f == '=' ? " = " :
f == '<' ? " < " :
f == '>' ? " > " :
f == LE ? " <= ":
f == GE ? " >= ":
f == '/' ? "/" :
f == '^' ? "^" :
f == ARROW ? "->" :
f == ':' ? ":" : /* used only for compound or variable types */
/* atomic types are handled above */
" != "; /* NE */
marker = buffer;
buffer[0] = 0;
ans = 0;
for(i=0;i<2;i++)
{ u = ARG(i,t);
/* does u need parentheses? */
if(f == '/')
needparen = paren(FRACT, FUNCTOR(u), (unsigned short)(i ? RIGHT: LEFT));
else if(f == '^' && !ATOMIC(u))
needparen = 1;
else
needparen = 0;
if(needparen)
{ if(m==0)
return 0;
strcat(buffer,"(");
--m;
++ans;
++marker;
}
k = pstring(u,marker,m);
if(k == 0 || k > m)
return 0;
ans +=k;
marker += k;
m -= k;
if(needparen)
{ if(m==0)
return 0;
strcat(buffer,")");
--m;
++ans;
++marker;
}
if(i==0)
{ int len = (int) strlen(fstring);
if(m < len)
return 0;
strcat(buffer,fstring);
ans += len;
marker += len;
m -= len;
}
}
return ans;
}
if(f == LIMIT)
{ strcpy(buffer,"lim(");
ans = (int) strlen(buffer);
marker = buffer + ans;
m -= ans;
k = pstring(ARG(0,t),marker,m);
ans += k;
if(k == 0)
return 0;
if(k >= m-3)
return 0;
m-=k;
marker += k;
if(n == 3)
{ pstring(ARG(1,t),marker,m); /* '+' or '-' is written */
++marker;
--m;
++ans;
}
*marker = ',';
++marker;
--m;
++ans;
k = pstring(ARG(n-1,t),marker,m);
if(k == 0)
return 0;
if(k >= m-2)
return 0;
m -= k;
marker += k;
*marker = ')';
++marker;
*marker = '\0';
m -= 1;
ans += k+1;
return ans;
}
/* Now the string will be in prefix form */
functor_string(f,0,temp);
if(m < 4)
return 0;
if(m < 10)
{ if((int) strlen(temp) > m-3)
return 0;
}
strcpy(buffer,temp);
strcat(buffer,"(");
marker = buffer + strlen(buffer);
m -= (int) strlen(buffer);
ans = (int) strlen(buffer);
for(i=0;i<n;i++)
{ k=pstring(ARG(i,t),marker,m);
if(k == 0)
return 0;
if(k >= m-3 && i < n-1)
return 0;
m-=k;
marker += k;
ans += k;
if(i < n-1)
{ strcat(marker,",");
++marker;
++ans;
--m;
}
}
strcat(buffer,")");
++ans;
if(ans != (int) strlen(buffer))
assert(0);
return ans;
}
/*_______________________________________________________________________*/
static char *defined_atom_string(term t)
/* return e.g. "theta" for THETA, etc. */
{ unsigned short f = FUNCTOR(t);
switch(f)
{ case FALSEFUNCTOR: return "false";
case TRUEFUNCTOR: return "true";
case ALPHA: return "alpha";
case BETA: return "beta";
case LITTLEGAMMA: return "gamma";
case INFINITYFUNCTOR: return "infinity";
case DELTA: return "delta";
case EPSILON: return "epsilon";
case LAMBDA: return "lambda";
case MU: return "mu";
case SIGMA: return "sigma";
case PI_ATOM: return "pi";
case THETA: return "theta";
case PHI: return "phi";
case LEFT: return "-";
case RIGHT: return "+";
case UNDEFINED: return "undefined";
case BOUNDED_OSCILLATIONS: return "undefined";
/* used only internally */
case UNBOUNDED_OSCILLATIONS: return "undefined";
/* used only internally */
case TINY: assert(0);
/* an infinitesimal for internal use by the theorem-prover */
case EULERGAMMA: return "EulerGamma";
default:
printf("defined_atom_string received %u\n", f);
assert(0);
}
return "";
}
/*________________________________________________________________________*/
void my_gcvt(double x, int n, char *s)
/* convert double x to %g format using no more than
n digits to the right of the decimal point,
and no more than 10 significant digits altogether.
Don't leave a terminating period like gcvt does,
and don't leave more than one trailing zero to the
right of the decimal point.
Assumes s has enough characters allocated to write an extra 0
at the end. Will not write more than 32 characters.
*/
{ char *marker, *marker2;
int i,k,m;
char notused;
char buffer[32];
if(x == 0.0)
{ strcpy(s,"0");
return;
}
if(x < 0.0)
{ s[0] = '-';
my_gcvt(-x,n,s+1);
return;
}
snprintf(s, 32, "%.12g", x); // gcvt is now "LEGACY"
if(strchr(s,'e'))
{ snprintf(s, 32, "%.*g", n,x);
// The * means the precision will be supplied as an extra arg to snprintf
marker = strchr(s,'e');
if(marker)
{ /* eliminate e-notation in some cases */
if(marker[1] == '-')
{ /* change 6.5e-002 to .065 etc. */
if(marker[2] == '0' && marker[3] == '0' && marker[4] <= '4')
{ m = marker[4]-'0'; /* so m is 1,2,3, or 4 */
buffer[0] = '0';
buffer[1] = '.';
for(i=0;i<m-1;i++)
buffer[2+i] = '0';
*marker = 0;
buffer[m+1] = s[0];
assert(s[1] == '.');
strcpy(buffer+m+2,s+2);
strcpy(s,buffer);
return;
}
}
/* 6.544455454e-010 needs to show fewer decimal places.
Otherwise it can happen that the 0 at the extreme right
gets truncated because it doesn't fit in the PointSlope window.
*/
/* find the place to start deleting extra digits */
/* s[1] contains the decimal point since the number is positive and in e-notation */
for(i=2;i<n+2;i++)
{ if(s[i] == 'e')
return; /* there are not too many digits after all */
}
/* strcpy(s+n+2,marker) would be dangerous since the source and
destination strings overlap, and the behaviour of strcpy is
undefined in that case. */
strcpy(buffer,marker);
strcpy(s+n+2,buffer); /* accomplishes the desired result */
return;
}
}
marker = strchr(s,'.');
if(!marker)
return; /* no decimal point to worry about */
/* strip trailing zeroes */
marker2 = s + strlen(s); /* points to the null terminator */
--marker2;
while(*marker2 == '0')
{ *marker2 = 0;
--marker2;
}
if(*marker2 == '.')
{ marker2[0] = get_decimalchar(); /* perhaps it isn't '.' */
marker2[1] = '0';
marker2[2] = 0;
}
if(marker && !marker[1])
{ marker[1] = '0'; /* add a trailing zero */
marker[2] = 0;
}
*marker = get_decimalchar();
for(i=1;i<=n+1;i++)
{ if(!marker[i])
return;
}
/* Now we have at least n+1 digits to the right
of the decimal point. Some will not be used. */
/* Round off, don't just truncate, provided the
last digit to remain isn't already '9' */
notused = marker[n+1];
marker[n+1] = 0;
if(notused < '5' ||
(notused == '5' && n > 0 && !(marker[n] & 1)) ||
(notused == '5' && n == 0 && !(marker[-1] & 1))
)
return; /* rounding same as truncating */
if(n >= 1) /* at least one digit right of the decimal point will remain */
{ i = n;
while(marker[i] == '9' && i > 0)
{ marker[i] = '0';
--i;
}
if(i > 0)
{ ++ marker[i];
return;
}
}
/* Now we have to round up to the left of the decimal point */
k = (int)(marker-s);
for(i=k-1; i >= 0; i--)
{ if(s[i] == '9')
s[i] = '0';
else
{ ++ s[i];
return;
}
}
/* If we get here, all the digits we passed over were 9's, and
we have to add a 1 at the very left and make everything else zeroes. */
marker[1] = get_decimalchar(); /* move the decimal point one to the right */
marker[0] = '0';
marker[n+1] = '0';
marker[n+2] = 0;
s[0] = '1';
}
/*__________________________________________________________________*/
void my_gcvt0(double x,int precision,char *ans)
/* convert double to string removing .0 from end */
{ int k;
my_gcvt(x,precision,ans);
k = (int) strlen(ans);
if(!strchr(ans,'.'))
return;
--k;
while(ans[k] == '0')
--k;
if(ans[k] == '.' )
ans[k] = '\0';
}
/*________________________________________________________________________*/
int paren(unsigned short op, unsigned short child, unsigned short dir)
/* not static because also called in display.c; EXPORTED so select.c can use it. */
/* return 1 if an expression with functor 'child' occurring in direction 'dir'
as daughter of a functor 'op' requires parentheses when displayed.
'dir' can also be passed as FORCED, which means "force parentheses".
The problem this solves is this:
(log 5) x is correct but (log x) log y is not;
we want log x log y. So you can't decide paren('*',LOG,LEFT) without knowing
the other child of *. We solve this by calling bound_block with FORCED for
the direction argument when we need to force parentheses.
*/
{ if( dir == FORCED)
return 1;
if( child == MATRIX)
{ if( op == ABSFUNCTOR)
return 0; /* abs(matrix(x)) is used to print det(x) */
else
return 1;
}
if( child == EVAL && (op != 0) && op != '=')
return 1;
/* toplevel call to bblock puts 0 in op place */
if(child == BINOMIAL)
return 1; /* this line must come before the next one! */
if( op == ABSFUNCTOR || op == SQRT)
/* no parens required under these operators ever;
ROOT isn't included here, but will fall through to the end */
return 0;
if(PREFIX(op) && (dir == CENTRAL)) /* a prefix-on-input operator */
/* but ABSFUNCTOR, SQRT have already been disposed of */
switch(child)
{ case '*' : return 1;
case '/' : return 0;
case '^' : return 0;
case SQRT: return 0;
case ABSFUNCTOR : return 0;
case ARROW: return 0;
case DEG: return 0;
case ROOT: return 0;
case FACTORIAL : return 0;
case FLOOR : return 0;
case GAMMA: return 0;
case WEIERSTRASSP: return 0;
case RIEMANNZETA: return 0;
default: return 1;
}
switch(op) /* now op is not a prefix operator */
{ case '-' :
if ((dir == CENTRAL) || (dir == RIGHT))
{ if (child == '+')
return 1;
if (child == '-')
return 1;
}
return 0;
case '+' :
if (child == '+')
return 1;
return 0;
case OR :
if (child == AND)
return 1;
if (child == IMPLIES)
return 1;
return 0;
case PR:
if( dir == RIGHT)
return 1;
if( dir == LEFT)
{ if PREFIX(child)
return 1;
if POSTFIX(child)
return 1;
/* somebody might write (x!)' even though it
isn't sensible */
switch (child)
{ case '+': return 1;
case '*': return 1;
case '-': return 1;
case '^': return 1;
case '/': return 1;
case FRACT: return 1;
}
return 0;
}
case AND:
if (child == OR)
return 1;
if (child == IMPLIES)
return 1;
return 0;
case NOT :
if (child == AND)
return 1;
if (child == OR)
return 1;
if (child == IMPLIES)
return 1;
return 0;
case '*' :
if (child == '*') /* (ab)(cd) and a(cd) and (ab)c will
be displayed that way if you type them that way */
return 1;
if (child == SQRT || child == ROOT || child == ABSFUNCTOR)
return 0;
if ((PREFIX(child)) &&
((dir == CENTRAL) || (dir == LEFT))
)
return 0; /* sin x sin y; u sin x sin y */
/* We will achieve (sin x) y and u ( sin x ) v
using force_paren.
*/
if (child == '+')
return 1;
if(child == SUM && dir == LEFT)
return 1;
if (child == '-')
return 1;
if (child == FRACT)
return 1;
if (child == LIMIT)
{ if(dir == CENTRAL)
return 1;
if(dir == LEFT)
return 1;
}
if (child == DIFF)
{ if(dir == CENTRAL)
return 1;
if(dir == LEFT)
return 1;
}
return 0;
case '/' :
if (child == '/')
return 1;
return 0;
case FRACT :
if(child == '*' || child == '-')
return dir == RIGHT ? 1 : 0; /* ab/c not (ab)/c; but a/(bc) */
if (child == '+' ||
child == '/' ||
child == FRACT
)
return 1;
return 0;
case '^' :
if (dir == LEFT)
return 1;
return 0;
case LOGB :
if (dir == RIGHT)
{ if (child == '*')
return 0;
if (child == '/')
return 0;
if (child == SQRT)
return 0;
if (child == ABSFUNCTOR)
return 0;
}
if (dir == LEFT)
return 0; /* don't use parens in the subscript */
return 1;
case DEG :
if (dir == CENTRAL)
return 1;
return 0;
case FACTORIAL:
if (dir == CENTRAL)
{ if (child < PREFIXBOUND)
return 1;
if (child == '*')
return 1;
if (child == '+')
return 1;
if (child == '-')
return 1;
if (child == '/')
return 1;
if (child == '^')
return 1;
if (child == FRACT)
return 1;
}
return 0;
case IF :
return 0;
case EVAL :
if(dir == LEFT)
return (child == '^' ? 0 : 1);
return 0;
case DIFF :
if (dir == LEFT) /* function to be differentiated */
{ if( child == '+')
return 1;
if( child == '-')
return 1;
if( child == FRACT)
return 1;
return 0;
}
if (dir == RIGHT) /* independent variable position */
{ if (child == SQRT)
return 0;
if (child == ABSFUNCTOR)
return 0;
return 1;
}
return 0;
case INTEGRAL :
if (dir == LEFT) /* function to be integrated */
{ if( child == '+')
return 1;
if( child == '-')
return 1;
if( child == FRACT)
return 1;
return 0;
}
if (dir == RIGHT) /* independent variable position */
{ if (child == SQRT)
return 0;
if (child == ABSFUNCTOR)
return 0;
return 1;
}
return 0; /* in case of a definite integral, the limits of
integration will have dir == CENTRAL and
will come here, not getting parenthesized */
case SUM :
if (dir == LEFT)
{ if( child == '+')
return 1;
if( child == '-')
return 1;
return 0;
}
return 0;
case MATRIX:
return 0; /* entries of a matrix not parenthesized */
case FORALL: /* fall through */
case EXISTS:
if(dir != RIGHT)
return 0;
if(child == FORALL || child == EXISTS)
return 0;
return 1;
case LAMBDA:
if(dir != RIGHT)
return 0;
if(child == LAMBDA || child == EXISTS || child == FORALL)
return 0;
return 1;
default :
return 0; /* parentheses not needed unless required above */
}
}
/* Expressions inside sqrt, root, and abs requires no parenthesizing.
Exponent of root requires no parenthesizing.
Limits of integration/summing requires no parenthesizing.
Index of sum requires no parenthesizing. */
void log_term(char *label, term t)
// print pstring of t to the console
{ char buffer[5000];
pstring(t,buffer,5000);
printf("\n%s %s\n",label,buffer);
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists