Sindbad~EG File Manager
/* 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