Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/parser/
Upload File :
Current File : /usr/home/beeson/MathXpert/parser/pstring.c

/* 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