Sindbad~EG File Manager

Current Path : /usr/home/beeson/Otter-Lambda/otter2/
Upload File :
Current File : /usr/home/beeson/Otter-Lambda/otter2/mpstring.c

/* M. Beeson, for MathpXert (but this copy modified for Otter-lambda) */
/* Given a term t, produce a string that parses to t */
/* This version produces a string that Otter-lambda can parse; it 
   is not required that MathXpert can parse the string.  In particular
   SUM, PRODUCT, and INTEGRAL terms have arguments in a different order,
   so the bound variable comes first.
/*
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.
11.15.03 Changed name of file and function to mpstring; now this is 
part of the Otter2/ExternalSimp project and no longer part of mathpert.
11.15.03 modified so it uses an explicit '*' when writing out product terms,
as that's what Otter needs to see.
6.26.05 modified mpsize and mpstring to insert an extra space after '+' and '*' (and '-' in sums) as that's what Otter needs.
7.22.05 modified mpsize and mpstring for AND and OR
5.17.06 replaced ltoa and itoa with sprintf 
*/

#include <assert.h>
#include <string.h>
#include <stdio.h>  // sprintf
#include "export.h"
#include "terms.h"
#include "display.h"
#include "display1.h"
#include "dispfunc.h"
#include "pstring.h"   /* my_gcvt0 */

static char *defined_atom_string(term t);
/*_______________________________________________________________*/
term preProcess(term t)
/* Assumes f = FUNCTOR(t) is SUM, PRODUCT, INTEGRAL, LIMIT, or DIFF.
Change the order or arguments and/or the form of the term to be 
what Otter-lambda wants to see.  Otter needs the bound variable to be the first argument. */
/* Doesn't yet handle derivatives, indefinite integrals, and one-sided limits */
/* FINISH THIS */
{ unsigned short f,n;
  int i;
  term ans;
  f = FUNCTOR(t);
  n = ARITY(t);
  
  if(f == LIMIT && n == 2) 
    { /* given lim(x->a,t)  produce lim(x,t,a) */
      ans = make_term(f,3);
      ARGREP(ans,0,ARG(0,ARG(0,t)));
      ARGREP(ans,1,ARG(1,t));
      ARGREP(ans,2,ARG(1,ARG(0,t)));
      return ans;
    }
  if(f == SUM || f == PRODUCT || (f == INTEGRAL && n == 4))
     { ans = make_term(f,n);    
       // switch the first two arguments 
       ARGREP(ans,0,ARG(1,t));
       ARGREP(ans,1,ARG(0,t));
       for(i=2;i<n;i++)
          ARGREP(ans,i,ARG(i,t));
       return ans;
     }
  assert(0);
  ans = make_term(0,0);  // avoid a warning message
  return ans;   
}  
/*_______________________________________________________________*/
int  mpsize(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(f == SUM || f == PRODUCT || f == INTEGRAL || f == LIMIT || f == DIFF)
     t = preProcess(t);  // convert to Otter-lambda's desired form first 
  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 == '*')
     { ans = 0;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            ans += mpsize(u);
            ans += 2;  /* +1 for the '+' or '*' sign and one more for a 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 if(f == '+' && NEGATIVE(u))
               needparen = 1;  // unlike in MathXpert
            else
               needparen = paren(f,FUNCTOR(u),(unsigned short)(i == 0 ? LEFT : i == n-1 ? RIGHT: CENTRAL));

            if(needparen)
               ans += 4;  /* two for the parentheses, two more for spaces before the '(' */
          }
       return ans-1;  /* -1 because no '+' needed after last arg */
     }
  if(f == FACTORIAL)
     { ans = 2 + mpsize(ARG(0,t));
       if(!ATOMIC(ARG(0,t)))
          ans += 2;  /* for parentheses */
       return ans;
     }
  if(INEQUALITY(f) || f == '/' || f == '^' || f == ':')
     { ans = mpsize(ARG(0,t)) + mpsize(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 + 2;
            if(ATOMIC(ARG(0,t)) || ATOMIC(ARG(1,t)))
               return ans + 4;
            return ans +6;
          }
       if(f == '/')
          { if(paren(FRACT, FUNCTOR(ARG(0,t)),LEFT))
               ans += 3;
            if(paren(FRACT, FUNCTOR(ARG(1,t)),RIGHT))
               ans += 3;
            return ans + 2;  /* 1 for the '/' sign */
          }
       if(f == ':')
          return ans + 1; /* 1 for the ':'  */
     }
  if(f == AND)
      strcpy(buffer,"and");
  else if (f == OR)
      strcpy(buffer,"or");
  else
     functor_string(f,0,buffer);
  ans = (int) strlen(buffer) + 2;  /* 2 for parentheses */
  for(i=0;i<n;i++)
    ans += mpsize(ARG(i,t)) + 1;  /* 1 for the comma */
  return ans-1;  /* we counted one comma too many */
}
/*_______________________________________________________________*/
 int mpstring(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);
  if(f == SUM || f == PRODUCT || f == INTEGRAL || f == LIMIT || f == DIFF)
     t = preProcess(t);  // convert to Otter-lambda's desired form first 
  if(OBJECT(t))
     { switch(TYPE(t))
          { case INTEGER:
               sprintf(temp,"%ld",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(f == '+' || f == '*' )
     { /* a + b + c  is the desired output form */
       marker = buffer;
       ans = 0;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
#if 0   // '-' is not treated specially as an arg of '+' as it is in MathXpert.        
            if(f == '+' && NEGATIVE(u))
               { u = ARG(0,u);
                 if(i==0)
                    { *marker = '-';
                      ++marker;
                      ++ans;
                    }
               }
#endif                
            /* 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 if(f == '+' && NEGATIVE(u) && n > 2)
               needparen = 1;  // Otter can't parse 2-c+a, it needs 2 + (-c) +a
            else
               needparen = paren(f,FUNCTOR(u),(unsigned short)(i == 0 ? LEFT : i == n-1 ? RIGHT: CENTRAL));
            if(needparen)
               { strcat(marker," (");
                 --m;
                 ans+=2;   /*  a+ (b+c)  not a+(b+c)  because Otter chokes on the latter */
                 marker+=2;
               }
            k = mpstring(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)
               { strcat(marker,f == '+' ? "+ " :
                                   f == '*' ?  "* " : ", "
                       );
                 marker+=2;
                 ans+=2;
                 --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 = mpstring(ARG(0,t),buffer+1,m-1);
             if(ans == 0 || ans >= m-2)
                return 0;
             strcat(buffer,")! ");
             return ans+4;
           }
        else
           { ans = mpstring(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 = mpstring(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 = mpstring(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 = mpstring(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)
          { mpstring(ARG(1,t),marker,m);  /* '+' or '-' is written */
            ++marker;
            --m;
            ++ans;
          }
       *marker = ',';
       ++marker;
       --m;
       ++ans;
       k = mpstring(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 -= 2;
       ans += k+2;
       return ans;
     }
  /* Now the string will be in prefix form */
  if(f == AND) 
     strcpy(temp,"and");
  else if (f == OR)
     strcpy(temp,"or");
  else
     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=mpstring(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 INFINITY:        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 SETOF:           return "set";
      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 */
      default: assert(0);
    }
 return "";
}

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists