Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/automode/
Upload File :
Current File : /usr/home/beeson/MathXpert/automode/chkinput.c

/* Input checker for Mathpert.  Called after setup_varlist and before
enhance_problem, from getprob.c.  Later on, after confirm_problem,
we are going to call check1(defined(problem)), so this file does only
a FAST check for obvious errors. */
/* M. Beeson, for Mathpert.  Check legality of input.
5.28.91 Original date
10.24.99 last modified
1.2.00  Modified check_scope
1.9.00  added contains_undefined_functions
1.12.00 modified check_interval to accept -infinity < x < infinity
1.12.00 made check_interval static.
7.10.00 added error 166 to reject complex limits.
6.23.04 modified check_input for lambda terms
7.1.04  changed that last modification. 
8.28.04 modified around line 711 to reject conjunctions of inequalities except as intervals
10.26.04 Added check for too many variables on RELATED_RATES.
11.06.04 Added code to input_check to check for unpaid functors.
1.19.06 changed includes
9.6.11  added if(whichdisk) at line 425 to allow any input in the Grapher.
5.6.13  include stdef.h
5.15.13 added a case for BERNOULLI to check_aux
5.21.13 added a case for EULERNUMBER
1.5.15  corrected check_graph_entry
12.11.23  removed checking whichdisk to see if they've paid.
2.24.24  removed include readinit
3.22.24  modified check_riemann to accept both AND and OR as the main functor.
9.5.24  modified check_graph_entry on POLAR_GRAPH to deal with interval as second arg
9.6.24  modified input_check to accept f(x) = something when comparing f and f'
9.27.24  modified input_check to reject vector under DIFFERENTIATE, as in "sin x,y"
9.30.24  modified check_minmax to meet its spec by disallowing more than one variablemodified check_minmax to meet its spec by disallowing more than one variable
10.1.24  modified input_check to accept an AND(equation, dy/dx) on IMPLICIT_DIFF
10.17.24 modified input_check on comparefandfprime
12.28.24 corrected check_minmax, adding f = FUNCTOR(t)
1.18.25 modified input_check on PARAMETRIC_GRAPH to allow n == 2.
2.4.25 modified input_check on GRAPH_INEQUALITY to reject y < |x| 
*/

#include <assert.h>
#include <string.h>
#include <stddef.h>
#include "globals.h"
#include "tdefn.h"
#include "probtype.h"  /* possible values of problemtype */
#include "ops.h"  /* for defnofi */
#include "prover.h"
#include "graphstr.h"  /* mpdoc.h needs it */
#include "display.h"
#include "mpdoc.h"
#include "checkarg.h"
#include "order.h"
#include "getarg.h"   /* check_interval */
#include "mathmode.h"   /* get_problemtype() */
#include "maxparam.h"
#include "deval.h"
#include "mplimits.h"   /* LIMITAND */
#include "chkinput.h"
#include "islinear.h"
#include "userfunc.h"   /* is_defined */

static int possiblemvpoly(term);
static int possiblemonomial(term);
static int check_graph_entry(int,term);
static int check_scopes(term t);
static int check_scope(term, term, unsigned short, int);
static int check_minmax(term);
static int check_riemann(term,int);
static int count_parameters(void);
static unsigned check_proposition(term t);
static int check_integrals(term t);
static int check_interval(term t);
/*_____________________________________________________________________*/
 unsigned mathematical(term t)
/* if t contains a nonnumerical functor (including LIMIT--but INTEGRAL
and DIFF are ok) , return an index of an error message, else return 0.
*/
{ unsigned short f,n;
  int i,err;
  if(ATOMIC(t))
     { if(equals(t,trueterm))
          return 162;
       if(equals(t,falseterm))
          return 162;
       return 0;
     }
  f = FUNCTOR(t);
  n = ARITY(t);
  switch(f)
     { case '<' :   /* deliberate fall-through */
       case '>' :
       case LE  :
       case GE  :
       case NE  :     return 35;
       case '=' :     return 39;
       case VECTOR :
       case MATRIX :  return 36;
       case AND:      return 37;
       case OR:
       case NOT:
       case ARROW:
       case SEQ:
       case EVEN1:
       case ODD1:     return 38;
       case LIMIT:    return 78;
     }
  if(f == IF)
     /* In that case propositions are allowed in the first arg */
     /* Although the parser requires an inequality or an interval,
        here we allow any proposition */
     { term u = ARG(0,t);
       err = check_proposition(u);
       if(err)
          return err;
       return mathematical(ARG(1,t));
     }
  if(f == LAM)  /* lambda terms can contain a proposition in the second arg; needed for Otter-lambda */
     { term u = ARG(1,t);
       err = check_proposition(u);
       if(!err)
          return 0;
      return mathematical(u);    /* it's not REQUIRED to be a proposition  */
     }
  if(f == DEG)
     { /* arguments of DEG must be numbers or variables */
       if(!OBJECT(ARG(0,t)))
          return 132;  /* Only integers or decimal numbers are allowed inside the degree symbol. */
     }
  for(i=0;i<n;i++)
     { err = mathematical(ARG(i,t));
       if(err)
          return err;
     }
  return 0;
}
/*_____________________________________________________________________*/
static int check_aux(int problemtype,term t)
/* traverse the compound expression t and return the first applicable
error message (by index in input_error_message) */
{ unsigned short n,f;
  int i,err;
  f = FUNCTOR(t);
  n = ARITY(t);
  if(f == ROOT)
     { err = check1(type(ARG(0,t),INTEGER));
       if(err)
         { if(OBJECT(ARG(0,t)) && TYPE(ARG(0,t)) == BIGNUM)
              return 102;
            else
               return 29;
         }
       err = check1(lessthan(zero,ARG(0,t)));
       if(err)
          return 30;
       if(OBJECT(ARG(0,t)) && INTDATA(ARG(0,t)) > 0xffff)
          return 102;
      }
  else if(f == DET)
      { if(FUNCTOR(ARG(0,t)) != MATRIX)
           return 21;
        if(ARITY(t) != ARITY(ARG(0,t)))
           return 21; /* matrix isn't square */
      }
  else if(f == ABSFUNCTOR)
      {  err = mathematical(ARG(0,t));
         if(err)
            return 22;
      }
  else if(f == FLOOR)
      {  err = mathematical(ARG(0,t));
         if(err)
            return 118;
      }
  else if(f == FACTORIAL || f == BERNOULLI || f == EULERNUMBER)
     { if(ATOMIC(ARG(0,t)))
          { err = infer(type(ARG(0,t),INTEGER));
            if(err)
               return 23;
          }
     }  /* don't try to check in general; it may be a bound variable
           and from this point actual_condition won't work; */
  else if(f == GCD)
     { if(ATOMIC(ARG(0,t)))
          { err = infer(type(ARG(0,t),INTEGER));
            if(err)
               return 26;
          }
       if(ATOMIC(ARG(1,t)))
          { err = infer(type(ARG(0,t),INTEGER));
            if(err)
               return 26;
          }
     }
  else if(f == MOD || f == BINOMIAL)
     { err = mathematical(ARG(0,t));
       if(err)
          return 32;
       err = mathematical(ARG(1,t));
       if(err)
          return 32;
     }
  else if (f == LIMIT)
     { term x = ARG(0,ARG(0,t));
       term a = ARG(1,ARG(0,t));
       if(FUNCTOR(ARG(0,t)) != ARROW)
          return 28;
       if(!ISATOM(x))
          return 27;
       if(equals(x,eulere))
          return 139;
          /* You can't use $e$ as a limit variable.  Choose a different letter. */
       if(equals(x,pi_term))
          return 143;
          /* You can't use $pi$ as a limit variable.  Choose a different letter. */
       if(equals(x,infinity) || equals(x,undefined) ||
          equals(x,left) || equals(x,right) || equals(x,bounded_oscillations) ||
          equals(x,unbounded_oscillations)
         )
          return 144;
          /* You can't use a constant as a limit variable. */
       if(FUNCTOR(x) == 'i')
          return 140;
          /* You can't use $i$ as a limit variable. Choose a different letter. */
       if(n==3)
          { if(ISINFINITE(a))
               return 75;  /* one-sided limits at infinity are not defined */
            else if(contains(a,INFINITYFUNCTOR))
               return 20;   /* undefined expression */
          }
       if(contains(a,INFINITYFUNCTOR) && !ISINFINITE(a))
          { /* you can't enter lim(x->pi/infinity,...) */
            return 20;  /* undefined expression */
          }
       if(iscomplex(t))
          { return 166;  /* Limit problems involving complex numbers are not accepted. */
          }
       if(problemtype != LIMITS && problemtype != LHOPITAL)
          return 78;
     }
  else if (f==DIFF)
     { if(contains(t,LIMIT))
          return 72;
     }
  else if (f==INTEGRAL)
     { if(contains(t,LIMIT))
          return 73;
       if(contains(ARG(0,t),INTEGRAL))
          return 145;
          /* An integral within an integral is not allowed.
             Double integrals are beyond the scope of Mathpert. */
       if(n==4 && contains(ARG(2,t),INTEGRAL))
          return 145;
       if(n==4 && contains(ARG(3,t),INTEGRAL))
          return 145;
       if(contains(t,INFINITYFUNCTOR) && get_currenttopic() != _improper_integrals)
          return 146;
          /* Improper integrals may not be entered under this topic. */
       if(!ISATOM(ARG(1,t)))
          { if(FUNCTOR(ARG(1,t)) == '*' &&
               FUNCTOR(ARG(0,ARG(1,t))) == 'd' &&
               ARITY(ARG(1,t)) == 2
              )
               { switch(FUNCTOR(ARG(1,ARG(1,t))))
                    { case 'u' : return 138;  /* Instead of du just type u */
                      case 'x' : return 137;  /* Instead of dx just type x */
                      default  : return 136;  /* Instead of dt just type t */
                    }
               }
            return 135;
            /* Only the variable of integration should appear as the second argument of an integral. */
          }
     }
  else if (f == SUM || f == PRODUCT)
     { if(!ISATOM(ARG(1,t)))
          return (f==SUM ? 16 : 18);
       if(get_currenttopic() < _sum_series)
          { err = check1(and(type(ARG(2,t),INTEGER),type(ARG(3,t),INTEGER)));
            if(err)
               return (f==SUM ? 17 : 18);
          }
       else if(equals(ARG(3,t),infinity) && !equals(ARG(2,t),minusinfinity))
          { err = check1(type(ARG(2,t),INTEGER));
            if(err)
               return (f ==SUM ? 17 : 18);
          }
       else if(equals(ARG(2,t),minusinfinity) && !equals(ARG(3,t),infinity))
          { err = check1(type(ARG(3,t),INTEGER));
            if(err)
               return (f == SUM? 17 : 18);
          }
       if(!ISINFINITE(ARG(2,t)) && !ISINFINITE(ARG(3,t)))
          { err = check1(le(ARG(2,t),ARG(3,t)));
            if(err)
               return 31;
          }
       if(contains(t,LIMIT))
          return 74;
     }
  else if (f == IF)
     { /* then don't pass the first arg to check_aux, or it will
           get rejected as an illegal inequality.  Since
           we've already checked it's a proposition,
           we can safely not check it further. */
       return check_aux(problemtype,ARG(1,t));
     }
  else if (f == '<' || f == '>' || f == LE || f == GE || f == NE)
     { if(problemtype != INEQUALITIES &&
          problemtype != ABSOLUTE_VALUE &&
          problemtype != GRAPH_INEQUALITY &&
          problemtype != GRAPH_RELATION
         )
          return 47;
     }
  if(f == AND && interval_as_and(t) &&
     problemtype == COMPARE_GRAPHS
    )
     return 0;  /* not an error, will be used to set graph ranges */
  for(i=0;i<n;i++)
     { 
       if(!ATOMIC(ARG(i,t)))
           { err = check_aux(problemtype,ARG(i,t));
             if(err)
                return err;
           }
     }
  return 0;
}
/*___________________________________________________________________*/
static int check_ode(term t)
/* return 0 if t is an acceptable ODE, 1 otherwise */
{
  if(FUNCTOR(ARG(0,t)) != PR && FUNCTOR(ARG(0,t)) != DIFF)
     return 1;
  if(!ISATOM(ARG(0,ARG(0,t))))
     return 1;
  if(FUNCTOR(ARG(0,t)) == PR && !equals(ARG(1,ARG(0,t)),one))
     return 1;  /* PR(y,n) entered */
  if(FUNCTOR(ARG(0,t)) == DIFF && !ISATOM(ARG(1,ARG(0,t))))
     return 1;
  if(count_parameters() + 1 > MAXPARAMS)
     return 119;  /* Too many parameters... */
  return 0;
}
/*_____________________________________________________________________*/
static int check_ode_aux(term left, term right, long k)
/*   Return 1 if right contains derivatives which aren't of the
   form diff(left,j,x) for j < k, where x = varlist[0],
   or any non-mathematical functors.
      Else return 0.
*/

{ unsigned short f = FUNCTOR(right);
  int i,err;
  term t;                /* independent variable */
  term y = ARG(0,left);  /* dependent variable   */
  term *varlist = get_varlist();
  unsigned short n;
  assert(FUNCTOR(left) == PR || FUNCTOR(left) == DIFF);
  y = ARG(0,left);
  if(f==DIFF)
     { t = ARG((ARITY(left)==2 ? 1: 2),right);
       if(!equals(varlist[0],t))
          return 1;
       if(ARITY(left)==3)
          { if(!ISINTEGER(ARG(1,right)))
               return 1;
            if(INTDATA(ARG(1,right)) >= k || INTDATA(ARG(1,right)) <= 0)
               return 1;
          }
       if(!equals(ARG(0,right),y))
          return 1;
     }
 if(f==PR)
     { if(!ISINTEGER(ARG(1,right)))
          return 1;
       if(INTDATA(ARG(1,right)) >=k || INTDATA(ARG(1,right)) <=0)
          return 1;
       if(!equals(ARG(0,right),y))
          return 1;
     }
 if(f == INTEGRAL)
    return 1;
 if(ATOMIC(right))
    return 0;
 n = ARITY(right);
 for(i=1;i<n;i++)
    { err = check_ode_aux(left,ARG(i,right),k);
      if(err)
         return err;
    }
 return 0;
}
/*_________________________________________________________________*/
static int check_highode(term t)
/* return 0 if t is of the form y'''... = f(x,y,y'...),
   return error message index if not */
{ term left,right,n;
  long k;
  int err;
  if(FUNCTOR(t) != '=')
     return 61;
  left = ARG(0,t);
  right = ARG(1,t);
  err = mathematical(right);
  if(err)
     return err;
  if(FUNCTOR(left) != PR && FUNCTOR(left) != DIFF)
     return 61;
  if(FUNCTOR(left) == DIFF && ARITY(left) != 3)
     return  63;
  n = ARG(1,left);  /* diff(u,n,x) is correct, not diff(u,x,n) */
  if(!ISINTEGER(n))
     return (FUNCTOR(left) == DIFF ? 64 : 61);
  if(equals(n,one))
     return 63;
  if(FUNCTOR(left)==DIFF && !ISATOM(ARG(1,left)))
     return 61;
  k = INTDATA(n);
  if(k>5)
     return 62;
  if(count_parameters() + k > MAXPARAMS)
     return 119;  /* Too many parameters... */
  return check_ode_aux(left,right,k);
}
/*_____________________________________________________________________*/
 int input_check(term t)
/* Determine whether t is legal input for the current
problemtype and topic.  Return 0 if so, and if not,
return the index of an appropriate error message in the function
input_error_message (see engerr.c).  Values of problemtype are in probtype.h;
bits 0,1,2 of whichdisk tell whether the user owns the algebra,
trig, and/or calculus disks. */

{ int err;
  unsigned short n = ARITY(t);
  unsigned short f = FUNCTOR(t);
  term p,q,x;
  int nvariables = get_nvariables();
  int problemtype = get_problemtype();
  int currenttopic = get_currenttopic();
  int i,nvars;
  term *atomlist;

  if(GRAPHTYPE(problemtype) && FUNCTOR(t) == OR &&
     problemtype != RIEMANN_SUMS &&
     problemtype != SIMPSONS_RULE &&
     problemtype != TRAPEZOID_RULE
    )
     /* accept intervals in the second argument. */
     { if(ARITY(t) != 2)
          return 124; /* Use only one vertical bar.  After the bar, separate
                         inequalities by commas. */
       err = strip_intervals(t,&p,&q);
       if(err)
          return 122;  /* Illegal interval */
       if((problemtype == PARAMETRIC_SURFACE || problemtype == NONPARAMETRIC_SURFACE) &&
          ARITY(q)==2 && graph_interval(q)
         )
          return 126;
          /* If you specify ranges for any variables, you must specify
             ranges for both independent variables. */
       if(!err)
          t=p;
     }
  /* first check the toplevel against the problem type */
  if(problemtype == INTEGRATION)
     { if(f == AND)
         { if(ARITY(t) != 3)
              return 80;
           else for(i=0;i<3;i++)
              { err = mathematical(ARG(i,t));
                if(err)
                   return err;
              }
         }
       else
         { err = mathematical(t);
           if(err)
              return err;
         }
       /* You either have to enter an integral,
          or a linear combination of integrals (with function coefficients),
          or an integrand (not containing INTEGRAL)
       */
       err = check_integrals(t);
       if(err)
          return err;
     }
  else switch(problemtype)
     { case LIMITS:    /* fall through */
       case LHOPITAL:
          if(FUNCTOR(t) != LIMIT)
             return 79;
          break;
       case DIFFERENTIATE:
          if(FUNCTOR(t) == '=')
             { term left = ARG(0,t);
               if(!ATOMIC(left) && (ARITY(left) != 1 || !ATOMIC(ARG(0,left))))
                  return 81;
               err = mathematical(ARG(1,t));
               if(err)
                  return err;
               break;
             }
          if(FUNCTOR(t) == AND)
             return 36;  // illegal vector or matrix
          if(currenttopic == _higher_order_diff)
             { return 103;
                /* Enter an equation like y = x^2 to compute y', y'', etc. */
                /* You MUST enter an equation to be able to compute
                   higher-order derivatives */
             }
          err = mathematical(t);
          if(err)
             return err;
          break;
       case DIFFERENTIATE_FROM_DEFN:
          err = mathematical(t);
          if(err==39)
             return 77;
          if(err)
             return err;
          if(contains(t,LIMIT))
             return 78;
          break;
       case MINMAX:
          return check_minmax(t);
       case POLYROOTS:
          if(!possiblemvpoly(t))
             return 1;
          else
             break;
       case ORDINARY_GRAPH:
          err = check_graph_entry(problemtype,t);
          if(err)
             return err;
          break;
       case SOLVE_ODE:
          if(FUNCTOR(t) != '=')
             return 58;
          err = check_ode(t);
          if(err)
             return 58;
          err = check_graph_entry(problemtype,ARG(1,t));
          if(err)
             return err;
          break;
       case SOLVE_TWO_ODES:
          if(FUNCTOR(t) != AND)
             return 42;
          if(ARITY(t) != 2)
             return 59;
          err = check_ode(ARG(0,t));
          if(err)
             return 60;
          err = check_ode(ARG(1,t));
          if(err)
             return 60;
          err = check_graph_entry(problemtype,ARG(1,ARG(0,t)));
          if(err)
             return err;
          err = check_graph_entry(problemtype,ARG(1,ARG(1,t)));
          if(err)
             return err;
          break;
       case HIGH_ORDER_ODE:
          err = check_highode(t);
          if(err)
             return err;
          break;
       case PARAMETRIC_GRAPH:
          if(f != AND || ( n!= 2 && n != 3))
                 // n can be 2 using the Problem Library,
                 // but the user has to enter the parameter interval, making n == 3
              return 120;  /* Enter two functions... */
          for(i=0;i<2;i++)
             { err = check_graph_entry(problemtype,ARG(i,t));
               if(err)
                  return err;
             }
          if(n == 3 && ! interval_as_and(ARG(2,t)))
             { return 120;
               // this error message is not accurate, but the
               // interface should enforce this requirement so this should never be hit
             }
          return 0;
       case POLAR_GRAPH:
           if(f == '=')
              { err = check_graph_entry(problemtype,t);
                if(err)
                   return err;
              }
           else if(f != AND || n != 2)
              return 120;  // wrong message but it can't happen anyway.
           else
             {  for(i=0;i<1;i++)
                   { err = check_graph_entry(problemtype,ARG(i,t));
                     if(err)
                        return err;
                   }
                if(! interval_as_and(ARG(1,t)))
                   { return 120;
                     // this error message is not accurate, but the
                     // interface should enforce this requirement so this should never be hit
                   }
             }
          return 0;
       case SPACE_CURVE:
          if(f != AND || n != 3)
              return 121;  /* Enter three equations ... */
          for(i=0;i<3;i++)
             { err = check_graph_entry(problemtype,ARG(i,t));
               if(err)
                  return err;
             }
          return 0;

       case NONPARAMETRIC_SURFACE:  /* fall through */
       case POLAR_NONPARAMETRIC_SURFACE:
          err = check_graph_entry(problemtype,t);
          if(err)
             return err;
          break;
       case PARAMETRIC_SURFACE:
          if(f != AND || n != 3)
              return 121;  /* Enter three equations... */
          for(i=0;i<3;i++)
             { if(FUNCTOR(ARG(i,t)) != '=' ||
                  !ISATOM(ARG(0,ARG(i,t)))
                 )
                   return 125; /* Enter three equations in the form x = ..., y = ..., z = ...*/
               err = check_graph_entry(problemtype,ARG(i,t));
               if(err)
                  return err;
             }
          return 0;

       case COMPARE_GRAPHS :
          if(currenttopic == _comparefandfprime || currenttopic == _comparetwoderivs)
             { if(f == '=')
                  { if(!ISATOM(ARG(0,t)) &&  //  y = something is OK
                       !(ARITY(ARG(0,t)) == 1 && ISATOM(ARG(0,ARG(0,t))) &&
                       equals(ARG(0,ARG(0,t)), get_varlist()[0])
                       )  // f(x) = something is OK
                      )
                       return 41;
                    err = check_graph_entry(problemtype,ARG(1,t));
                    if(err)
                       return err;
                    break;
                  }
               else
                  { err = mathematical(t);
                    if(err)
                      return err;
                    break;
                  }
             }
          if(FUNCTOR(t) != AND)
             return 42;
          if(ARITY(t) > MAXGRAPHS)
             return 164;  /* You cannot compare more than six graphs.
                 Try to write a single formula with a parameter, instead. */
          for(i=0;i<ARITY(t);i++)
             { if(interval_as_and(ARG(i,t)))
                  continue; // will be used to set graph ranges
               err = check_graph_entry(problemtype,ARG(i,t));
               if(err)
                  return err;
             }
          break;
       case GRAPH_RELATION:
          if(nvariables < 2)
             return 40;
          if(_graph_circle <= currenttopic && currenttopic <= _graph_relation &&
             (interval_as_and(t) || f == '<' || f == GE || f == LE || f == '>' || f == NE)
            )
             return 133;
             /* Enter inequalities under Graph Inequality Relation */
          err = check_graph_entry(problemtype,t);
          if(err)
             return err;
          break;
       case GRAPH_INEQUALITY:
          { int topic = get_currenttopic();
            if(topic == _graph_ineq)
               {
                  if(INEQUALITY(f))
                      { // you can't enter for example y < |x|.
                        return 2;
                        /* "You must enter both an upper and lower bound, as in sin x < y < cos x."*/
                      }
                  if(!interval_as_and(t))
                     return 12;  /* You must enter an inequality or inequalities */
                  term y = ARG(1,ARG(0,t));
                  if(!ISATOM(y))
                     return 3;   /* The middle term must be a variable, as in sin x < y < cos x." */
                   
                  if(contains(ARG(0,ARG(0,t)),FUNCTOR(y)) ||
                     contains(ARG(1,ARG(1,t)),FUNCTOR(y))
                    )
                     return 4;  /* The upper and lower bounds must not contain the variable in the middle.*/
                  if(f == '=' || f == NE)  // can't get here now as of 2.4.25
                     return 12;
                  err = check_graph_entry(problemtype,t);
                  if(err)
                     return err;
                  return 0;
               }
            if(topic == _graph_set)
               {
                  if(!interval_as_and(t) && !INEQUALITY(f))
                     return 12;  /* You must enter an inequality or inequalities */
                  if(f == '=' || f == NE)
                     return 12;
                  err = check_graph_entry(problemtype,t);
                  if(err)
                     return err;
                  break;
               }
            assert(0);    //topic must be _graph_ineq or _graph_set
          }
          break;

       case SOLVE_EQUATION:
          if(f == AND || f == OR)
             return 34;
          if(f != '=')
             { err = mathematical(t);
               if(err)
                  return err;
             }
          else
             { err = mathematical(ARG(0,t));
               if(err)
                  return err;
               err = mathematical(ARG(1,t));
               if(err)
                  return err;
             }
          if(get_nvariables() == 0)
             return 142;  /* There must be at least one variable */
          break;
       case LINEAR_EQUATION:
          if(f==AND || f == OR)
             return 34;
          if(get_nvariables() == 0)
             return 142;  /* There must be at least one variable */
          x = get_eigenvariable();
          if(f == '=')
             { err = mathematical(ARG(0,t));
               if(err)
                  return err;
               err = mathematical(ARG(1,t));
               if(err)
                  return err;
               if(!is_linear_in(ARG(0,t),x))
                  return 33;
               if(!is_linear_in(ARG(1,t),x))
                  return 33;
             }
          else
             { err = mathematical(t);
               if(err)
                  return err;
               if(!is_linear_in(t,x))
                  return 33;
             }

          break;
       case  LINEAR_EQUATIONS:
       /* if the problem was not linear, the user has been asked to
        call some of the variables constants, so when you get here
        the problem is definitely linear */
          if(f == '=')
              /* You ARE allowed to enter a matrix equation here */
             { if(FUNCTOR(ARG(1,t))==VECTOR
                  && FUNCTOR(ARG(0,t))== '*'
                  && FUNCTOR(ARG(0,ARG(0,t))) == MATRIX
                  && FUNCTOR(ARG(1,ARG(0,t))) == VECTOR
                 )  /* it's a matrix equation */
                  { /* so check the arities */
                    unsigned rows = ARITY(ARG(1,t));
                    if(ARITY(ARG(0,ARG(0,t))) != rows
                       || ARITY(ARG(1,ARG(0,t))) != rows
                      )
                       return 76;  /* dimensions don't match */
                    else
                       break;  /* ok */
                  }
             }
          if(f != AND && f != OR)
             return 10;
          if(get_nvariables() == 0)
             return 142;  /* There must be at least one variable */
          break;
       case INEQUALITIES:
          if(f == AND)
             { unsigned short g;
               for(i=0;i<n;i++)
                  { g = FUNCTOR(ARG(i,t));
                    if(g != '<' && g != '>' && g != LE && g != NE && g != GE)
                       return 12;
                  }
               if(!interval_as_and(t))
                  return 12;
             }
          else if(f != '<' && f != '>' && f != LE && f != NE && f != GE)
             return 12;
          break;
       case INDUCTION:    /* must be an equality or inequality between
                           mathematical terms */
          if(f != '=' && f != LE && f != GE && f != '<' && f != '>')
             return 101;
          break;
       case ABSOLUTE_VALUE:  /* mathematical, or equality or inequality between
                                mathematical terms */
          if(f == '=' || f == '<' || f == '>' || f == LE || f == GE)
             { err = mathematical(ARG(0,t));
               if(err)
                  return err;
               err = mathematical(ARG(1,t));
               if(err)
                  return err;
               break;
             }
          err = mathematical(t);
          if(err)
             return err;
          break;
       case IMPLICIT_DIFF:
          nvars = variablesin(t,&atomlist);
          if(nvars < 2)
             return 134;
             /* There must be at least two variables in the problem */
          if(FUNCTOR(t) == AND)
             { // from user input, it is [equation, diff(y,x)]
               // PHP page should enforce first arg is an equation, second arg a diff of two variables
               assert(FUNCTOR(ARG(0,t)) == '=');
               err = mathematical(ARG(0,ARG(0,t)));
               if(err)
                  return err;
               err = mathematical(ARG(1,ARG(0,t)));
               if(err)
                  return err;
               if(FUNCTOR(ARG(1,t))!= DIFF)
                  return -1;  // assert(0) per above comment
               term y = ARG(0,ARG(1,t));
               term x = ARG(1,ARG(1,t));
               assert(ISATOM((x)));
               assert(ISATOM((y)));
               break;
             }
          if(FUNCTOR(t) == '=')
             { err = mathematical(ARG(0,t));
               if(err)
                  return err;
               err = mathematical(ARG(1,t));
               if(err)
                  return err;
               break;
             }
          err = mathematical(t);
          if(err)
             return err;
          break;
       case RELATED_RATES:
          nvars = variablesin(t,&atomlist);
          if(nvars > 12)
             return 167;    /* Too many variables */
          if(FUNCTOR(t) == AND)
             { for(i=0;i<ARITY(t);i++)
                  { if(FUNCTOR(ARG(i,t)) != '=')
                       return 104;
                    err = input_check(ARG(i,t));
                    if(err)
                       return err;
                  }
               break;
             }

          if(FUNCTOR(t) == OR && ARITY(t) == 2)
               /* the 0th arg is the equation(s) true for all t, and
                  the 1st arg is the equation(s) true at a partilar t */
             { for(i=0;i<ARITY(t);i++)
                  { if(FUNCTOR(ARG(i,t))==OR)
                       return 104;
                    err = input_check(ARG(i,t));
                    if(err)
                       return err;
                  }
               break;
             }

          if(FUNCTOR(t) != '=')
             return 104;
          err = mathematical(ARG(0,t));
          if(err)
             return err;
          err = mathematical(ARG(1,t));
          if(err)
             return err;
          break;
       case TRIG_IDENTITY:
          if(FUNCTOR(t) != '=')
             return 113;  /* You must use an = sign to enter an identity */
          for(i=0;i<2;i++)
             { err = mathematical(ARG(i,t));
               if(err)
                  return err;
             }
          break;
       case SIMPSONS_RULE:
       case TRAPEZOID_RULE:
       case RIEMANN_SUMS:
          err = check_riemann(t,problemtype);
          if(err)
             return err;
          break;
       default:
          err = mathematical(t);
          if(err)
             return err;
     }
  if(!ATOMIC(t))
     { err = check_aux(problemtype,t);
       if(err)
          return err;
     }
  if(problemtype == INEQUALITIES && contains_free(t,'i'))
     return 46;   /* complex numbers not allowed in inequalities */
  /* so the term is locally ok */
  err = check_scopes(t);
  if(err)
     return err;
  return 0;
}

/*___________________________________________________________________*/
static int possiblemvpoly(term t)
/* just like mvpoly in order.c, except will ASSUME exponents are integers
if that can't be inferred or refuted. */

/* tests if t is a multivariate polynomial (sum of monomials) */
/*  x^ny qualifies if n is constant;  (x^2)^2 doesn't qualify until after
    the exponent is simplified */
/* returns 1 if it is, 0 if it is not */

{ int i;
  if(possiblemonomial(t))
     return 1;
  if(FUNCTOR(t) != '+') return 0;
  for(i=0;i<ARITY(t);i++)
     { if(! possiblemonomial(ARG(i,t)))
          return 0;
     }
  return 1;
}

/*_____________________________________________________________________*/
static int possiblemonomial(term t)
/* tests if t is a (multivariate) monomial */

{ int i;
  unsigned short f = FUNCTOR(t);
  if(ATOMIC(t))
     return 1;
  if(FUNCTOR(t)=='-' && FUNCTOR(ARG(0,t)) != '-')
     return possiblemonomial(ARG(0,t));
  if(f == '^')
     { term exponent,temp;
       int err;
       exponent = ARG(1,t);
       if( !ISATOM(ARG(0,t)) )
          return 0;
       if(ZERO(exponent))
          return 0;  /* we don't count x^0 as a monomial,
                        because it's not defined when x=0 */
       if( INTEGERP(exponent) )
          return 1;  /* bignum exponents ok here */
       if( numerical(exponent) ) /* but exponent is not a natnum */
           return 0;  /* so as not to call the theorem-prover unless really needed */
        /* a symbolic natnum exponent is also OK, but we need to call
           the theorem-prover to check it */
       temp = and(type(exponent,INTEGER), lessthan(zero,exponent));
       err = check1(temp);
       RELEASE(ARG(0,temp));
       RELEASE(ARG(1,temp));
       RELEASE(temp);
       if(!err)
          return 1;
       return 0;
     }
  if(f == '*')
     { for(i=0;i<ARITY(t);i++)
         { if(! ATOMIC(ARG(i,t)) && FUNCTOR(ARG(i,t)) != '^')
              return 0;
           if(! possiblemonomial(ARG(i,t)))
              return 0;
         }
       return 1;
     }
  return 0;
}
/*___________________________________________________________________*/
 int is_graph_inequality(term t)
/* return 1 if t is an inequality of the form a < x, a <= x,
where x is an atom, and a is seminumerical; or for x > a, x >= a.
Return 2 for an inequality x < a, x <= a, a > x, a >= x.
Return 0 for all other t.
   EXPORTed because needed in enhance.c
*/
{ unsigned short f = FUNCTOR(t);
  term left, right;
  if(f != LE && f != GE && f != '<' && f != '>')
     return 0;
  if(f == '<' || f == LE)
     { left = ARG(0,t);
       right = ARG(1,t);
     }
  else
     { left = ARG(1,t);
       right = ARG(0,t);
     }
  if(seminumerical(left) && ISATOM(right))
     return 1;
  else if(seminumerical(right) && ISATOM(left))
     return 2;
  return 0;
}
/*___________________________________________________________________*/
 int graph_interval(term t) /* needed in grafinit.c */
/* return 1 if t is an AND of graph_inequalities
of different senses, so it defines an interval */
{ int n,m;
  if(FUNCTOR(t) == AND && ARITY(t) == 2)
     { n = is_graph_inequality(ARG(0,t));
       if(n == 0)
          return 0;
       m = is_graph_inequality(ARG(1,t));
       if(m == 0 || n == m)
          return 0;
       return 1;
     }
  return 0;
}

/*___________________________________________________________________*/
static int contains_undefined_functions(term t)
/* return 1 if t contains a function symbol that has not been
given a definition;  0 otherwise */
{ unsigned short n,f;
  int i;
  if(ATOMIC(t))
     return 0;
  f = FUNCTOR(t);
  if( ('a' <= f && f <= 'z') || ('A' <= f && f <= 'Z'))
     { if(is_defined(f)>= 0)
          return 0;  /* f is defined */
       else
          return 1;  /* f is undefined      */
     }
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(contains_undefined_functions(ARG(i,t)))
          return 1;
     }
  return 0;
}
/*___________________________________________________________________*/
static int check_graph_entry(int problemtype,term t)
/* return 0 for acceptable input, nonzero for an error
*/
{ unsigned short f = FUNCTOR(t);
  term *varlist = get_varlist();
  /* derivatives, limits and integrals may not occur */
  if(contains(t,DIFF))
     return 43;
  if(contains(t,LIMIT))
     return 44;
  if(contains(t,INTEGRAL))
     return 45;
  if(contains_undefined_functions(t))
     return 163;
  if(problemtype == GRAPH_INEQUALITY || problemtype == GRAPH_RELATION)
     { if(INEQUALITY(f))
          return mathematical(sum(ARG(0,t),ARG(1,t)));
       if(f == AND && interval_as_and(t))
          { term u = make_term('+',3);
            ARGREP(u,0,ARG(0,ARG(0,t)));
            ARGREP(u,1,ARG(1,ARG(0,t)));
            ARGREP(u,2,ARG(1,ARG(1,t)));
            return mathematical(u);
          }
       if(f == AND)
          { int i,err;
            for(i=0;i<ARITY(t);i++)
              { err = check_graph_entry(problemtype,ARG(i,t));
                if(err)
                   return err;
              }
            return 0;
          }
     }
  if(f != '=')
    { if(problemtype == POLAR_GRAPH && (contains(t,'x') || contains(t,'y')))
         return 82;
      if(ARITY(t) == 2 && FUNCTOR(t) == AND)
         { term u = ARG(0,t);
           if(! interval_as_and(ARG(1,t)))
              return 120;  // but interface should prevent this
           return mathematical(u);
         }
      return mathematical(t);
    }

  if(!ISATOM(ARG(0,t)))
     return 41;
  if(equals(ARG(0,t),varlist[0]))
     return 83; /* independent variable on left of = is no good */
  if(FUNCTOR(ARG(1,t)) == '=')
     return 39;
  return check_graph_entry(problemtype,ARG(1,t));
}
/*________________________________________________________________*/
static int check_scopes(term t)
/* enforce that limits of integration or sum or product can't contain
the variable of integration (or summation as the case may be);
and makes sure that index variables can't be 'i' when complex is on.
And make sure that bound variables (definite integrals or sums)
can't occur free elsewhere, and don't have overlapping scopes.

Return zero if everything is OK; else return an index of an error
message in input_error_message
*/
{ int i,err;
  unsigned short g;
  int nvariables = get_nvariables();
  term *varlist = get_varlist();
  varinf *varinfo = get_varinfo();
  for(i=0;i<nvariables;i++)
     { if (varinfo[i].scope == BOUND)
          { if(get_complex() && FUNCTOR(varlist[i]) == 'i')
              return 84;
            g = bound_in(varlist[i],t);
            err = check_scope(t,varlist[i],g,0);
            if(err)
               return err;
          }
     }
  return 0;
}
/*_____________________________________________________________*/
static int check_scope(term t, term x, unsigned short g, int flag)
/* x is a bound variable.  Check whether scoping rules described above are
violated for x in term t or not.  Return 0 if not, error message index
if the rules are violated */
/* flag is 0 if we aren't so far inside a scope of x; if we are, it
is the most recent binding operator.  The parameter g passes the
original binding operator. */

{ int err,i;
  unsigned short f,n;
  if(ATOMIC(t))
    { if(flag)  /* already in the scope */
          return 0;
      if(equals(t,x))
          /* encountered x OUTSIDE its scope */
           { switch(g)
                { case INTEGRAL:  return 51;
                  case SUM:       return 52;
                  case PRODUCT:   return 53;
                  case LIMIT:     return 54;
                  default:        assert(0);
                }
           }
      return 0;  /* number or other atom ok */
    }
  f = FUNCTOR(t);
  n = ARITY(t);
  if(
      (f == INTEGRAL || f == SUM || f == PRODUCT )
      && n == 4 && equals(ARG(1,t),x)
    )
      /* a definite integral, sum, or product with respect to x */
    { if(g != f)
         return 56;
      if(flag)
         return 57;  /* nested bound variables */
      if (contains(ARG(2,t),FUNCTOR(x)) || contains(ARG(3,t),FUNCTOR(x)))
          return (f == INTEGRAL ? 48: (f == SUM ? 49 : 50));
      return check_scope(ARG(0,t),x,g,f);
    }
  if( g == LIMIT && flag &&
      (f == SUM || f == PRODUCT)
    )
    { /* reject e.g. lim(n->10, sum(1/k,k,1,n)) */
      if(contains(ARG(2,t),FUNCTOR(x)))
         { return f == SUM ? 111 : 130;
           /* Lower limit of sum [product] must be an integer */
           /* This is also going to reject  floor(n) in the upper limit of a sum,
              but that will be OK. */
         }
      if(contains(ARG(3,t),FUNCTOR(x)))
         { return f == SUM ? 112 : 131;
           /* Upper limit of sum [product] must be an integer */
         }
    }
  if(f == LIMIT  && equals(ARG(0,ARG(0,t)),x))
      /* a limit with respect to x */
    { if(flag)
         return 57;  /* nested bound variables */
      if(g != f)
         return 56;
      if (contains(ARG(1,ARG(0,t)),FUNCTOR(x)))
         return 55;
      err = check_scope(LIMITAND(t),x,g,LIMIT);
      if(err == 111 || err == 112 || err == 130 || err == 131)
         { if(ISINFINITE(ARG(1,ARG(0,t))))
              err = 0;
           /* example:  lim(n->infinity, sum(1/k^2,k,1,n)) */
           /* don't reject this even though we DO want to
              reject a similar limit with 10 instead of infinity. */
         }
      if(err)
         return err;
      return n==2 ? 0 : check_scope(ARG(1,t),x,g,LIMIT);
    }
  for(i=0;i<n;i++)
    { err = check_scope(ARG(i,t),x,g,flag);
      if(err)
         return err;
    }
  return 0;
}

/*___________________________________________________________________*/
static int check_minmax(term t)
/* return 0 if t is acceptable input for a minmax problem,
   index of an error in english_err.c (spanish_err.c, etc.)
   if not.  The input consists of a problem and optionally
   an interval.  The problem may be an equation, in which case
   the left side must be an atom or of the form f(x).  The
   right side must contain only one variable.  */

{ unsigned short f = FUNCTOR(t);
  int nvariables = get_nvariables();
  int flag = 0;
  int err;
  term left,right;
  term arg;
  if(f == AND)
     { if(ARITY(t) > 2)
          return 98;
       arg = ARG(1,t);
       t = ARG(0,t);
       f = FUNCTOR(t);
       flag = 1;
     }
  if(f == '=')
     { left = ARG(0,t);
       right = ARG(1,t);
       if(!ISATOM(left))
          /* then it must be of the form f(x) */
          { if(ARITY(left) != 1 || !ISATOM(ARG(0,left)))
               return 95;
            if(nvariables > 1)
               return 96;
            return 0;
          }
      else if(seminumerical(right))
          return 97;
      else if(nvariables > 2)
          return 96;
      else if(!mathematical(t))
          return 100;
      if (flag)
         goto out;
      return 0;
    }
  else
    {
      if(seminumerical(t))
          return 97;
      else if(nvariables > 1)
          return 96;
      else
         { int err = mathematical(t);  // mathematical returns 0 for success
           if (err)
              return err;
         }
      if (flag)
         goto out;
      return 0;
    }
  out:
  err = check_interval(arg);
  if(err)
     return (err == 46? 99 : 98);
  return 0;
}

/*_____________________________________________________________*/
static int check_interval(term t)
/* Does t define an interval? */
  { term temp,x;
    int i;
    unsigned short f = FUNCTOR(t);
    if(equals(t,trueterm))
        return 0;   /* true means no interval specified */
    x = get_eigenvariable();
    if(FUNCTOR(t) == AND &&
       FUNCTOR(ARG(0,t)) == '<' &&
       equals(ARG(0,ARG(0,t)),minusinfinity) &&
       FUNCTOR(ARG(1,t)) == '<' &&
       equals(ARG(1,ARG(1,t)),infinity) &&
       equals(ARG(1,ARG(0,t)),x) &&
       equals(ARG(0,ARG(1,t)),x)
      )
       return 0;  /* -infinity < x < infinity is acceptable */
    subst(two,x,t,&temp);
    if(FUNCTOR(temp) == AND)
       { if(!seminumerical(ARG(0,temp)) || !seminumerical(ARG(1,temp)))
            return 46;
       }
    else if(!seminumerical(temp))
       return 46;
    if(f == AND && ARITY(t) != 2)
       return 48;
    if(f == AND)
       { for(i=0;i<2;i++)
         { temp = ARG(i,t);
           if(FUNCTOR(temp) != '<' && FUNCTOR(temp) != LE)
               return 47;
         }
         temp = and(ARG(0,ARG(0,t)),ARG(1,ARG(1,t)));
         return check_arg(temp,interval);
       }
    if(f != '<' && f != LE && f != GE && f != '>')
       return 48;
    if(equals(ARG(0,t),get_eigenvariable()) && seminumerical(ARG(1,t)))
       return 0;
    if(equals(ARG(1,t),get_eigenvariable()) && seminumerical(ARG(0,t)))
       return 0;
    return 48;
}

/*____________________________________________________*/
static int check_riemann(term t, int problemtype)
/* check input for graphing Riemann sums */
/* also used for Simpson's rule */
/* Input should be an AND with arity 4,
specifying the function, the left and right endpoints,
and the number of intervals.  The left and right
endpoints have to be numerical and the number of
intervals has to be a positive integer, but it
can be a term containing a parameter that evaluates
to an integer.
*/
{ int err;
  double left, right;
  unsigned short n = ARITY(t);
  unsigned short f = FUNCTOR(t);
  if(problemtype == SIMPSONS_RULE &&
     ((f != OR && f != AND)|| n != 4)
    )
     return 117; /* Specify function, left endpoint... */
  else  if(problemtype == RIEMANN_SUMS &&
     ((f != OR && f != AND) || !(n == 5 || n==4))  /* sumstyle is optional */
    )
     return 117; /* Specify function, left endpoint... */
  if(!seminumerical(ARG(1,t)) || !seminumerical(ARG(2,t)))
     return 115;  /* Endpoints of intervals must be numerical */
  deval(ARG(1,t),&left);
  deval(ARG(2,t),&right);
  if(left >= right)
     return 114;  /* Upper limit must be less than lower limit */
  err = check1(type(ARG(3,t),INTEGER));
  if(err)
     return 116;  /* Number of intervals must be a positive integer */
  err = check1(positive(ARG(3,t)));
  if(err)
     return 116;
  return 0;
}
/*___________________________________________________________*/
static int count_parameters(void)
/* count the non-existential variables in varlist, and
   subtract 2.  */
{ int nvariables = get_nvariables();
  varinf *varinfo = get_varinfo();
  int i,count = 0;
  for(i=0;i<nvariables;i++)
     { if(varinfo[i].scope != EXISTENTIAL)
          ++count;
     }
  count -= 2;
  return count;
}

/*______________________________________________________________*/
static unsigned check_proposition(term t)
/* Return 0 if t is an inequality, equality, or logical combination of
simpler propositions. Else return 1; */
{ unsigned short f = FUNCTOR(t);
  unsigned short n = ARITY(t);
  unsigned i,err;
  if(INEQUALITY(f))
     { for(i=0;i<n;i++)
          { err = mathematical(ARG(i,t));
            if(err)
               return err;
          }
       return 0;
     }
  if(f== AND || f == OR || f == NOT || f == ARROW)
     { for(i=0;i<n;i++)
          { err = check_proposition(ARG(i,t));
            if(err)
               return err;
          }
       return 0;
     }
  return 1;
}
/*__________________________________________________________________*/
 int strip_intervals(term t, term *p, term *q)
/* If t is an OR, return *p = ARG(0,t) and call
strip_intervals on ARG(1,t); in that case ARG(1,t)
must consist entirely of intervals, so the second
call must return an ILLEGAL term in the second parameter.
If ARG(1,t) doesn't consist entirely of intervals, return 2.
  If t is an AND, split it into pieces p and q, where
t = and(p,q) up to associativity, and q consists
of graph_intervals. Return 0 for success, 1 if there
are no such intervals at the end of t.
  If the term consists entirely of intervals, *p is
returned as ILLEGAL.
EXPORTed because needed in process_ok in wgetprob.c
*/

{ unsigned short n = ARITY(t);
  int err,i,j;
  unsigned short m,f;
  term temp;
  if(FUNCTOR(t) == OR)
     { *p = ARG(0,t);
       err = strip_intervals(ARG(1,t),&temp,q);
       if(err)
          return err;
       if(FUNCTOR(temp) != ILLEGAL)
          return 2;
       return 0;
     }
  if(FUNCTOR(t) != AND)
     { *p = t;
       SETFUNCTOR(*q,ILLEGAL,0);
       return 1;
     }
  if(n == 2 && graph_interval(t))
     { SETFUNCTOR(*p,ILLEGAL,0);
       *q = t;
       return 0;
     }
  for(i=n-1;i>=0;i--)
     { if(!graph_interval(ARG(i,t)))
          break;
     }
  if(i==n-1)
     return 1;  /* no intervals */
  f = FUNCTOR(ARG(i,t));
  if(f != '=' && INEQUALITY(f))
     return 122;  /* Illegal interval */
  if(f == AND && INEQUALITY(FUNCTOR(ARG(0,t))))
     return 122;
  m = (unsigned short)(n-1-i);
  if(m==1)
     { *q = ARG(n-1,t);
       if(n==2)
          *p = ARG(0,t);
       else
          { *p = make_term(AND,(unsigned short)(n-1));
            for(j=0;j<n-1;j++)
               ARGREP(*p,j,ARG(j,t));
          }
       return 0;
     }
  *q = make_term(AND,m);
  for(j=0;j<m;j++)
     ARGREP(*q,m-1-j,ARG(n-1-j,t));
  if(m==n)
     { /* all arguments were inequalities */
       SETFUNCTOR(*p,ILLEGAL,0);
       return 0;
     }
  if(m+1==n)
     *p = ARG(0,t);
  else
     { *p = make_term(AND,(unsigned short)(n-m));
       for(j=0;j<n-m;j++)
          ARGREP(*p,j,ARG(j,t));
     }
  return 0;
}
/*_____________________________________________________________*/
static int check_integrals(term t)
/* return 160 if a double integral is entered.
   return 161 if an integral in a denominator or exponent is entered.
   return 159 if integrals appear in other illegal positions.
   return 0 if integrals appear only in linear combinations or not at all
*/
{ unsigned short f,i,n;
  int err;
  f = FUNCTOR(t);
  if(ATOMIC(t))
     return 0;
  if((f == '^' || f == '/') && contains(ARG(1,t), INTEGRAL))
     return 161;
  if(f == INTEGRAL)
     { if(contains(ARG(0,t),INTEGRAL))
          return 160;
       return 0;
     }
  if(f == '^' || f == '/' || f == '-')
     return check_integrals(ARG(0,t));
  if(f == '+')
     { n = ARITY(t);
       for(i=0;i<n;i++)
          { err = check_integrals(ARG(i,t));
            if(err)
               return err;
          }
       return 0;
     }
  if(f == '*')
     { int count = 0;
       int flag;
       n = ARITY(t);
       for(i=0;i<n;i++)
          { if(contains(ARG(i,t), INTEGRAL))
               { if(count)
                    return 159;
                 ++count;
                 flag = i;
               }
          }
       if(count)
          return check_integrals(ARG(flag,t));
       return 0;
     }
  if(contains(t,INTEGRAL))
     return 159;
  /* examples, diff(integral(u,x),x);  sin(integral(u,x)) */
  return 0;
}

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