/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *                       TERMS                            * */
/* *                                                        * */
/* *  $Module:   TERM                                       * */
/* *                                                        * */
/* *  Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001      * */
/* *  MPI fuer Informatik                                   * */
/* *                                                        * */
/* *  This program is free software; you can redistribute   * */
/* *  it and/or modify it under the terms of the FreeBSD    * */
/* *  Licence.                                              * */
/* *                                                        * */
/* *  This program is distributed in the hope that it will  * */
/* *  be useful, but WITHOUT ANY WARRANTY; without even     * */
/* *  the implied warranty of MERCHANTABILITY or FITNESS    * */
/* *  FOR A PARTICULAR PURPOSE.  See the LICENCE file       * */ 
/* *  for more details.                                     * */
/* *                                                        * */
/* *                                                        * */
/* $Revision: 1.5 $                                         * */
/* $State: Exp $                                            * */
/* $Date: 2011-05-25 10:05:32 $                             * */
/* $Author: weidenb $                                       * */
/* *                                                        * */
/* *             Contact:                                   * */
/* *             Christoph Weidenbach                       * */
/* *             MPI fuer Informatik                        * */
/* *             Stuhlsatzenhausweg 85                      * */
/* *             66123 Saarbruecken                         * */
/* *             Email: spass@mpi-inf.mpg.de                * */
/* *             Germany                                    * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/


/* $RCSfile: term.c,v $ */


#include "term.h"
/**************************************************************/
/* previously Inlined Functions                               */
/**************************************************************/

#ifdef CHECK
extern BOOL term_BINDPHASE;
void term_StartBinding(void)   { term_BINDPHASE=TRUE; }
void term_StopBinding(void)    { term_BINDPHASE=FALSE; }
BOOL term_InBindingPhase(void) { return term_BINDPHASE; }
#else
void term_StartBinding(void)   { }
void term_StopBinding(void)    { }
#endif

 NAT term_NullMark(void)
{
  return 0;
}


 NAT term_BindingMark(SYMBOL Var)
{
  return (NAT) term_BIND[symbol_VarIndex(Var)][0];
}


 void term_SetBindingMark(SYMBOL Var, NAT Mark)
{
  term_BIND[symbol_VarIndex(Var)][0] = (POINTER) Mark;
}


 POINTER term_BindingValue(SYMBOL Var)
{
  return term_BIND[symbol_VarIndex(Var)][1];
}


 void term_SetBindingValue(SYMBOL Var, POINTER Value)
{
  term_BIND[symbol_VarIndex(Var)][1] = Value;
}

 void term_CreateBinding(SYMBOL Var, NAT Mark)
{
  term_SetBindingMark(Var, Mark);
}

 void term_ClearBinding(SYMBOL Var)
{
  term_SetBindingMark(Var, term_NullMark());
}

 void term_CreateValueBinding(SYMBOL Var, NAT Mark, POINTER Value)
{
  term_SetBindingMark(Var, Mark);
  term_SetBindingValue(Var, Value);
}


 BOOL term_VarIsMarked(SYMBOL Var, NAT Mark)
{
  return term_BindingMark(Var) >= Mark;
}


 NAT term_ActMark(void)
{
  NAT MarkVar;
  if (term_MARK == NAT_MAX) {
    int i;
    for (i = 0; i < symbol_MaxVars(); i++)
      term_BIND[i][0] = (POINTER) term_NullMark();
    term_MARK = 1;
  }
  MarkVar = term_MARK++;
  return MarkVar;
}


 void term_NewMark(void)
{
  if (term_MARK == NAT_MAX) {
    int i;
    for (i = 0; i < symbol_MaxVars(); i++)
      term_BIND[i][0] = (POINTER) term_NullMark();
    term_MARK = 1;
  }
  term_MARK++;
}


 NAT term_OldMark(void)
{
  return term_MARK - 1;
}


/**************************************************************/
/* Macros                                                     */
/**************************************************************/

 TERM term_Null(void)
{
 return (TERM)NULL;
}

 SYMBOL term_TopSymbol(TERM T)
{
  return T->symbol;
}


 void term_RplacTop(TERM T, SYMBOL S)
{
  T->symbol = S;
}


 LIST term_SupertermList(TERM T)
{
  return T->super.termlist;
}


 void term_RplacSupertermList(TERM T, LIST L)
{
  T->super.termlist = L;
}


 LIST term_AtomsLiterals(TERM T)
{
  return T->super.termlist;
}


 TERM term_Superterm(TERM T)
{
  return T->super.term;
}


 void term_RplacSuperterm(TERM T1, TERM T2)
{
  T1->super.term = T2;
}


 BOOL term_IsVariable(TERM T)
{
  return symbol_IsVariable(term_TopSymbol(T));
}


 BOOL term_IsStandardVariable(TERM T)
{
  return symbol_IsStandardVariable(term_TopSymbol(T));
}


 BOOL term_IsIndexVariable(TERM T)
{
  return symbol_IsIndexVariable(term_TopSymbol(T));
}


 LIST term_ArgumentList(TERM T)
{
  return T->args;
}


 void term_RplacArgumentList(TERM T, LIST A)
{
  T->args = A;
}


 BOOL term_IsComplex(TERM T)
{
  return term_ArgumentList(T) != NULL;
}


 BOOL term_IsConstant(TERM T)
{
  return !term_IsComplex(T) && !term_IsVariable(T);
}


 BOOL term_IsAtom(TERM T)
{
  return symbol_IsPredicate(term_TopSymbol(T));
}

 BOOL term_IsDeclaration(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: TRUE, if the term is a monadic atom, FALSE otherwise.
***************************************************************/
{
  return (term_IsAtom(Term) && symbol_IsBaseSort(term_TopSymbol(Term)));
}


 TERM term_FirstArgument(TERM T)
{
  return (TERM) list_First(T->args);
}


 void term_RplacFirstArgument(TERM T1, TERM T2)
{
  list_Rplaca(T1->args, T2);
}


 TERM term_SecondArgument(TERM T)
{
  return (TERM) list_Second(T->args);
}


 void term_RplacSecondArgument(TERM T1, TERM T2)
{
  list_RplacSecond(T1->args, T2);
}


 void term_Free(TERM T)
{
  memory_Free((char*) T, sizeof(TERM_NODE));
}


 BOOL term_EqualTopSymbols(TERM T, TERM S)
{
  return symbol_Equal(term_TopSymbol(T), term_TopSymbol(S));
}

 void term_EqualitySwap(TERM T)
{
  TERM Aux;
  Aux = term_FirstArgument(T);
  list_Rplaca(term_ArgumentList(T), (POINTER) term_SecondArgument(T));
  list_Rplaca(list_Cdr(term_ArgumentList(T)), (POINTER) Aux);
}
#ifdef CHECK

/* In CHECK mode 'term_StartStamp' is a real function defined in    */
/* 'term.c'.                                                        */
void term_StopStamp(void)
{
  term_STAMPBLOCKED = FALSE;
}
/* Attention:                                                       */
/* You should check for Overflow before calling this function !!!!! */
/* Use "term_StampOverflow" to do this.                             */
/* If an overflow occurred, you have to reset the stamp of all terms */
/* you're using.                                                    */
#else

void term_StartStamp(void)
{
  term_STAMP++;
}

void term_StopStamp(void)
{ }

#endif

 NAT term_TermStamp(TERM T)
{
  return T->stamp;
}

 void term_SetTermStamp(TERM T)
{
  T->stamp = term_STAMP;
}

 NAT term_Size(TERM T)
{
  return T->size;
}

 void term_SetSize(TERM T, NAT s)
{
  T->size = s;
}

 BOOL term_AlreadyVisited(TERM T)
{
  return T->stamp == term_STAMP;
}

 BOOL term_HasTermStamp(TERM T)
{
  return T->stamp == term_STAMP;
}

 void  term_ResetTermStamp(TERM T)
{
  T->stamp = 0;
}

 BOOL term_StampAlreadyReset(TERM T)
{
  return T->stamp == 0;
}



 LIST term_CopyTermList(LIST List)
/**************************************************************
  INPUT:   A list of TERMs.
  RETURNS: A deep copy of the list, i.e. the terms are copied, too.
***************************************************************/
{
  return list_CopyWithElement(List, (POINTER (*)(POINTER))term_Copy);
}

 void term_CopyTermsInList(LIST List)
/**************************************************************
  INPUT:   A list of TERMs.
  EFFECT:  Replaces every term in the list with its copy. 
***************************************************************/
{
  list_NMapCar(List, (POINTER (*)(POINTER)) term_Copy);
}

 void term_DeleteTermList(LIST List)
/**************************************************************
  INPUT:   A list of TERMs.
  RETURNS: Nothing.
  EFFECT:  The list is freed together with its elements.
***************************************************************/
{
  list_DeleteWithElement(List, (void (*)(POINTER))term_Delete);
}

 BOOL term_ListContainsTerm(LIST List, TERM Term)
/**************************************************************
  INPUT:   A list of TERMs.
  RETURNS: TRUE, if <List> contains <Term>, FALSE otherwise.
           Terms are compared with respect to the term_Equal function.
***************************************************************/
{
  return list_Member(List, Term, (BOOL (*)(POINTER,POINTER))term_Equal);
}

 LIST term_DeleteDuplicatesFromList(LIST List)
/**************************************************************
  INPUT:   A list of TERMs.
  RETURNS: The list where duplicate terms are removed.
  EFFECT:  Terms are compared with respect to the term_Equal function.
           The duplicate terms are not deleted.
***************************************************************/
{
  return list_DeleteDuplicates(List, (BOOL (*)(POINTER, POINTER))term_Equal);
}


LIST term_DestroyDuplicatesInList(LIST Terms)
/**************************************************************
  INPUT:   A list of terms.
  RETURNS: The list where all duplicate terms are removed.
  EFFECTS: The terms are compared with respect to the term_Equal function.
           The duplicate terms are deleted, too.
***************************************************************/
{
  return list_DeleteDuplicatesFree(Terms, (BOOL (*)(POINTER,POINTER))term_Equal,
				   (void (*)(POINTER))term_Delete);
}

void term_PrintPosition(TERM TopTerm, TERM Subterm)
{
  term_FPrintPosition(stdout, TopTerm, Subterm);
}
/**************************************************************/
/* Inline Functions ends here                                 */
/**************************************************************/
/**************************************************************/
/* Global variables                                           */
/**************************************************************/

NAT      term_MARK;
POINTER  term_BIND[symbol__MAXVARIABLES][2];
#ifdef CHECK
BOOL term_BINDPHASE;
#endif

NAT  term_STAMP;
BOOL term_STAMPBLOCKED;
static BOOL term_STAMPOVERFLOW[term_MAXSTAMPUSERS];
static NAT  term_STAMPUSERS;


/**************************************************************/
/* ********************************************************** */
/* *							    * */
/* *  TERM CREATION FUNCTIONS			            * */
/* *							    * */
/* ********************************************************** */
/**************************************************************/

void term_Init(void)
/**********************************************************
  INPUT:   None.
  RETURNS: None.
  CAUTION: The term module is initialized.
***********************************************************/
{
  int i;

  term_MARK = 1;

  term_STAMP = 0;
  term_STAMPBLOCKED = FALSE;
  for (i = 0; i < term_MAXSTAMPUSERS; i++)
    term_STAMPOVERFLOW[i] = FALSE;
  term_STAMPUSERS = 0;
#ifdef CHECK
  term_BINDPHASE = FALSE;
#endif
}


TERM term_Create(SYMBOL Symbol, LIST List)
/**********************************************************
  INPUT:   A symbol and a list of arguments.
  RETURNS: A term consisting of the top symbol 'Symbol' and
           the arguments stored in 'List'.
  CAUTION: None.
********************************************************/
{
  TERM Result;

#ifdef CHECK
  if (!symbol_IsSymbol(Symbol)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_Create: Illegal symbol.");
    misc_FinishErrorReport();
  }
  if (!term_IsTermList(List)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_Create: Illegal term list.");
    misc_FinishErrorReport();
  }
#endif

  Result         = (TERM)memory_Malloc(sizeof(TERM_NODE));
  Result->symbol = Symbol;
  Result->args   = List;
  Result->super.termlist = list_Nil();
  Result->stamp = 0;
  Result->size = 0;
  return Result;
}

TERM term_CreateAddFather(SYMBOL Symbol, LIST List)
/**********************************************************
  INPUT:   A symbol and a list of arguments.
  RETURNS: A term consisting of the top symbol 'Symbol' and
           the arguments stored in 'List'.
           In contrast to term_Create the superterm members are set for the arguments.
  CAUTION: None.
********************************************************/
{
  TERM Result;
  LIST l;
  Result = term_Create(Symbol, List);
  for (l=term_ArgumentList(Result); !list_Empty(l); l = list_Cdr(l))
    term_RplacSuperterm((TERM) list_Car(l), Result);
  return Result;
}

TERM term_CreateStandardVariable(void)
/**********************************************************
  RETURNS: Returns a term with a new variable as top symbol.
***********************************************************/
{
  return term_Create(symbol_CreateStandardVariable(), list_Nil());
}


void term_Delete(TERM Term)
/**********************************************************
  INPUT:   A term.
  SUMMARY: Deletes the term and frees the storage.
  CAUTION: The arguments of Term are also deleted.
********************************************************/
{
  if (term_IsComplex(Term)) {
    LIST Scan;
    for (Scan = term_ArgumentList(Term);
	 list_Exist(Scan);
	 Scan = list_Cdr(Scan))
      term_Delete(list_Car(Scan));
    list_Delete(term_ArgumentList(Term));
  }
  term_Free(Term);
}


void term_DeleteIterative(TERM Term)
/**********************************************************
  INPUT:   A term.
  SUMMARY: Deletes the term and frees the storage.
  CAUTION: The arguments of Term are also deleted.
********************************************************/
{
  if (term_IsComplex(Term)) {
    LIST Stack, Aux;
    Stack = list_StackBottom();
    do {
      if (term_IsComplex(Term))
	Stack = list_Push(term_ArgumentList(Term),Stack);
      term_Free(Term);
      while (!list_StackEmpty(Stack) && list_Empty(list_Top(Stack)))
	Stack = list_Pop(Stack);
      if (!list_StackEmpty(Stack)) {
	Aux  = list_Top(Stack);
	Term = (TERM)list_Car(Aux);
	list_RplacTop(Stack, list_Cdr(Aux));
	list_Free(Aux);
      }
    } while (!list_StackEmpty(Stack));
  }
  else
    term_Free(Term);
}

/**************************************************************/
/* ********************************************************** */
/* *			                                    * */
/* *  PRIMITIVE TERM FUNCTIONS                              * */
/* *							    * */
/* ********************************************************** */
/**************************************************************/

BOOL term_Equal(TERM Term1, TERM Term2)
/*********************************************************
  INPUT:   Two terms.
  RETURNS: The boolean value TRUE if the terms are equal.
  CAUTION: EQUAL FUNCTION- OR PREDICATE SYMBOLS SHARE THE
           SAME ARITY. THIS IS NOT VALID FOR JUNCTORS!
**********************************************************/
{
#ifdef CHECK
  if (!term_IsTerm(Term1) || !term_IsTerm(Term2)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_Equal: Illegal input.");
    misc_FinishErrorReport();
  }
#endif
  
  /* if (term_IsIndexVariable(Term1))
     puts("\nterm_Equal: Left index variable.");
     else if (term_IsIndexVariable(Term2))
     puts("\nterm_Equal: Right index variable.");

     fflush(stdout); */

  if (Term1 == Term2)   /* pointers are equal */
    return TRUE;
  else if (!term_EqualTopSymbols(Term1, Term2))
    return FALSE;
  else if (term_ArgumentList(Term1)) {
    LIST Scan1, Scan2;
    for (Scan1=term_ArgumentList(Term1), Scan2=term_ArgumentList(Term2);
	list_Exist(Scan1) && list_Exist(Scan2);
	Scan1=list_Cdr(Scan1), Scan2=list_Cdr(Scan2))
      if (!term_Equal(list_Car(Scan1),list_Car(Scan2)))
	return FALSE;
    return (list_Empty(Scan1) ? list_Empty(Scan2) : FALSE);
  } else
    return TRUE;
}


BOOL term_EqualIterative(TERM Term1, TERM Term2)
/*********************************************************
  INPUT:   Two terms.
  RETURNS: The boolean value TRUE if the terms are equal.
  CAUTION: Notice that there may be symbols with arbitrary arity
*******************************************************/
{
  LIST Stack1,Stack2;

#ifdef CHECK
  if (!term_IsTerm(Term1) || !term_IsTerm(Term2)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_EqualIterative: Illegal input.");
    misc_FinishErrorReport();
  }
#endif
  
  Stack1 = Stack2 = list_StackBottom();
  do {
    if (term_EqualTopSymbols(Term1,Term2) &&
	term_IsComplex(Term1) && term_IsComplex(Term2)) {
      Stack1 = list_Push(term_ArgumentList(Term1),Stack1);
      Stack2 = list_Push(term_ArgumentList(Term2),Stack2);
    }
    if (!term_EqualTopSymbols(Term1,Term2) ||
	term_IsComplex(Term1) != term_IsComplex(Term2)) {
      Stack1 = list_StackFree(Stack1);
      Stack2 = list_StackFree(Stack2);
      return FALSE;
    }
    while (!list_StackEmpty(Stack1) && list_Empty(list_Top(Stack1)))
      if (!list_StackEmpty(Stack2) && list_Empty(list_Top(Stack2))) {
	Stack1 = list_Pop(Stack1);
	Stack2 = list_Pop(Stack2);
      }
      else {
	Stack1 = list_StackFree(Stack1);
	Stack2 = list_StackFree(Stack2);
	return FALSE;
      }
    if (!list_StackEmpty(Stack1)) {
      if (!list_Empty(list_Top(Stack2))) {
	Term1 = (TERM)list_Car(list_Top(Stack1));
	list_RplacTop(Stack1, list_Cdr(list_Top(Stack1)));
	Term2 = (TERM)list_Car(list_Top(Stack2));
	list_RplacTop(Stack2, list_Cdr(list_Top(Stack2)));
      }
      else {
	Stack1 = list_StackFree(Stack1);
	Stack2 = list_StackFree(Stack2);
	return FALSE;
      }
    }
  } while (!list_StackEmpty(Stack1));
  return TRUE;
}


BOOL term_VariableEqual(TERM Variable1, TERM Variable2)
/*********************************************************
  INPUT:   Two Variables.
  RETURNS: The boolean value TRUE, if the variables are
           equal.
**********************************************************/
{
  return term_EqualTopSymbols(Variable1, Variable2);
}


BOOL term_IsGround(TERM Term)
/**********************************************************
  INPUT:   A term.
  RETURNS: A boolean value which is TRUE, if 'Term' is a
           ground term, i.e. does not contain variables.
********************************************************/
{
#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_IsGround: Illegal input.");
    misc_FinishErrorReport();
  }
#endif
  
  if (term_IsComplex(Term)) {
    LIST Stack;
    Stack = list_StackBottom();
    do {
      if (term_IsComplex(Term))
	Stack = list_Push(term_ArgumentList(Term),Stack);
      else
	if (term_IsVariable(Term)) {
	  Stack = list_StackFree(Stack);
	  return FALSE;
	}
      while (!list_StackEmpty(Stack) && list_Empty(list_Top(Stack)))
	Stack = list_Pop(Stack);
      if (!list_StackEmpty(Stack)) {
	Term = (TERM)list_Car(list_Top(Stack));
	list_RplacTop(Stack, list_Cdr(list_Top(Stack)));
      }
    } while (!list_StackEmpty(Stack));
    return TRUE;
  } else
    return !term_IsVariable(Term);
}


BOOL term_IsTerm(TERM Term)
/*********************************************************
  INPUT:   A term.
  RETURNS: TRUE, if 'Term' is not NULL
           and has a symbol as its top symbol.
**********************************************************/
{
  return (Term != (TERM)NULL && symbol_IsSymbol(term_TopSymbol(Term)));
}


BOOL term_IsTermList(LIST TermList)
/*********************************************************
  INPUT:   A term.
  RETURNS: TRUE iff <TermList> is a list of terms.
*******************************************************/
{
  for ( ; !list_Empty(TermList); TermList=list_Cdr(TermList))
    if (!(term_IsTerm((TERM)list_Car(TermList))))
      return FALSE;

  return TRUE;
}


BOOL term_AllArgsAreVar(TERM Term)
/*********************************************************
  INPUT:   A term.
  RETURNS: The boolean value TRUE, if all arguments of the
           term are variables.
*******************************************************/
{
  LIST Scan;
  for (Scan = term_ArgumentList(Term);
       !list_Empty(Scan); Scan = list_Cdr(Scan))
    if (!term_IsVariable(list_Car(Scan)))
      return FALSE;
  return TRUE;
}


/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *			LOW LEVEL FUNCTIONS	            * */
/* *							    * */
/* ********************************************************** */
/**************************************************************/


TERM term_Copy(TERM Term)
/**********************************************************
  INPUT:   A term.
  RETURNS: A copy of 'Term' where the stamp field is copied, too.
  SUMMARY: Copies "Term" and returns a pointer to the copy.
*********************************************************/
{
  TERM Result;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_Copy: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  if (term_IsComplex(Term)) {
    LIST Scan, ArgumentList;
    for (Scan = ArgumentList = list_Copy(term_ArgumentList(Term));
	 list_Exist(Scan);
	 Scan = list_Cdr(Scan))
      list_Rplaca(Scan, term_Copy(list_Car(Scan)));
    Result = term_Create(term_TopSymbol(Term), ArgumentList);
  } else
    Result = term_Create(term_TopSymbol(Term), list_Nil());

  Result->stamp = Term->stamp;
  Result->size  = Term->size;

  return Result;
}


TERM term_CopyIterative(TERM Term)
/**********************************************************
  INPUT:   A term.
  RETURNS: A copy of <Term>.
  SUMMARY: Copies <Term> and returns a pointer to the copy.
*********************************************************/
{
#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_CopyIterative: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  if (term_IsComplex(Term)) {
    LIST TopStack, ArgumentStack, ActStack;
    TopStack      = list_Push((POINTER)term_TopSymbol(Term),
			      list_StackBottom());
    ArgumentStack = list_Push(list_Copy(term_ArgumentList(Term)),
			      list_StackBottom());
    ActStack      = list_Push(list_Top(ArgumentStack),
			      list_StackBottom());

    while (!list_StackEmpty(TopStack)) {
      if (list_Empty(list_Top(ActStack))) {
	Term = term_Create((SYMBOL)list_Top(TopStack),
			   (LIST)list_Top(ArgumentStack));
	TopStack = list_Pop(TopStack);
	ArgumentStack = list_Pop(ArgumentStack);
	ActStack = list_Pop(ActStack);
	if (!list_StackEmpty(TopStack)) {
	  list_Rplaca(list_Top(ActStack), Term);
	  list_RplacTop(ActStack, list_Cdr(list_Top(ActStack)));
	}
      }
      else {
	Term = (TERM)list_Car(list_Top(ActStack));
	if (term_IsComplex(Term)) {
	  TopStack      = list_Push((POINTER)term_TopSymbol(Term), TopStack);
	  ArgumentStack = list_Push(list_Copy(term_ArgumentList(Term)),
				    ArgumentStack);
	  ActStack      = list_Push(list_Top(ArgumentStack), ActStack);
	}
	else {
	  list_Rplaca(list_Top(ActStack),
		      term_Create(term_TopSymbol(Term), list_Nil()));
	  list_RplacTop(ActStack, list_Cdr(list_Top(ActStack)));
	}
      }
    }
    return Term;
  }
  else
    return term_Create(term_TopSymbol(Term), list_Nil());
}


TERM term_CopyWithEmptyArgListNode(TERM Term, LIST ArgListNode,
				   LIST* ListNodeCopyPt)
/**********************************************************
  INPUT:   A term and a pointer to an argument list node of
           this term.
  RETURNS: A copy of 'Term' with a NULL as list_Car(ListNodeCopy).
  SUMMARY: Copies "Term" and returns a pointer to the copy.
*********************************************************/
{
#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_CopyWithEmptyArgListNode: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  if (term_IsComplex(Term)) {
    LIST Scan, ArgumentList, HelpScan;
    TERM Result;

    HelpScan = term_ArgumentList(Term);
    ArgumentList = list_Copy(HelpScan);

    for (Scan = ArgumentList;
	 list_Exist(Scan);
	 Scan = list_Cdr(Scan),HelpScan = list_Cdr(HelpScan))
      if (HelpScan != ArgListNode)
	list_Rplaca(Scan,
		    term_CopyWithEmptyArgListNode(list_Car(Scan),
						  ArgListNode,
						  ListNodeCopyPt));
      else{
	list_Rplaca(Scan, (TERM)NULL);
	*ListNodeCopyPt = Scan;
      }

    Result         = (TERM)memory_Malloc(sizeof(TERM_NODE));
    Result->symbol = term_TopSymbol(Term);
    Result->args   = ArgumentList;
    Result->super.termlist = list_Nil();

    return Result;

  } else
    return term_Create(term_TopSymbol(Term), list_Nil());
}


void term_PrintWithEmptyArgListNode(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: none.
  SUMMARY: Prints any term to stdout, especially terms with empty
           argument list nodes.
  CAUTION: Uses the other term_Output functions.
*************************************************************/
{
  if (Term == (TERM)NULL)
    fputs("(NULL)", stdout);
  
  else if (term_IsComplex(Term)) {
    putchar('(');
    symbol_Print(term_TopSymbol(Term));
    putchar(' ');
    list_Apply((void (*)(POINTER)) term_PrintWithEmptyArgListNode,
	       term_ArgumentList(Term));
    putchar(')');
    
  } else if (term_IsVariable(Term)) {
    
    symbol_Print(term_TopSymbol(Term));
    
  } else {
    
    /* term_IsConstant(Term) */
    putchar('(');
    symbol_Print(term_TopSymbol(Term));
    putchar(')');
  }
}


BOOL term_ReplaceSubtermBy(TERM Atom, TERM TermS, TERM TermT)
/**************************************************************
  INPUT:   Three terms.
  RETURNS: None.
  EFFECT:  Replaces all occurrences of TermS in Atom by TermT.
           Top level is NOT considered!
*************************************************************/
{
  LIST ArgListNode;
  BOOL Replaced;
  int B_Stack;

#ifdef CHECK
  if (!term_IsTerm(Atom) || !term_IsTerm(TermS) ||
      !term_IsTerm(TermT) || term_Equal(Atom, TermS)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_ReplaceSubtermBy: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  /*fputs("\nWe look for: ",stdout);term_Print(TermS);
    fputs("\nin: ",stdout);term_Print(Atom);
  */

  Replaced = FALSE;
  TermS    = term_Copy(TermS);

  if (!term_Equal(Atom, TermS) && !list_Empty(term_ArgumentList(Atom))) {

    B_Stack = stack_Bottom();
    stack_Push(term_ArgumentList(Atom));
    
    while (!stack_Empty(B_Stack)) {
      ArgListNode = stack_Top();
      Atom        = (TERM)list_Car(ArgListNode);
      stack_RplacTop(list_Cdr(ArgListNode));
      
      if (term_Equal(Atom, TermS)) {
	Replaced = TRUE;
	list_Rplaca(ArgListNode, term_Copy(TermT));
	term_Delete(Atom);
      }
      else
	if (term_IsComplex(Atom))
	  stack_Push(term_ArgumentList(Atom));
      
      while (!stack_Empty(B_Stack) && list_Empty(stack_Top()))
	stack_Pop();
    }
  }
  term_Delete(TermS);
  return Replaced;
}


void term_ReplaceVariable(TERM Term, SYMBOL Symbol, TERM Repl)
/**************************************************************
  INPUT:   A term, a variable symbol and a replacement term.
  RETURNS: void
  EFFECT:  All variables with <Symbol> in <Term> are replaced 
           with copies of <Repl>
  CAUTION: Destructive
***************************************************************/
{
  LIST Scan;

#ifdef CHECK
  if (!term_IsTerm(Term) || !term_IsTerm(Repl) || !symbol_IsVariable(Symbol)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_ReplaceVariable: Illegal input.");
    misc_FinishErrorReport();
  }
#endif
  
  if (symbol_Equal(term_TopSymbol(Term), Symbol)) {
    term_RplacTop(Term,term_TopSymbol(Repl));
    term_RplacArgumentList(Term,term_CopyTermList(term_ArgumentList(Repl)));
  }
  else
    for (Scan = term_ArgumentList(Term); !list_Empty(Scan); Scan = list_Cdr(Scan))
      term_ReplaceVariable(list_Car(Scan),Symbol,Repl);
}

void term_ExchangeVariable(TERM Term, SYMBOL Old, SYMBOL New)
/**************************************************************
  INPUT:   A term, and two variable symbols.
  RETURNS: void
  EFFECT:  All variables <Old> in <Term> are replaced with <New>
  CAUTION: Destructive
***************************************************************/
{
  LIST Scan;

#ifdef CHECK
  if (!term_IsTerm(Term) || !symbol_IsVariable(Old) || !symbol_IsVariable(New)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_ExchangeVariable: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  if (symbol_Equal(term_TopSymbol(Term), Old))
    term_RplacTop(Term,New);
  else
    for (Scan = term_ArgumentList(Term); !list_Empty(Scan); Scan = list_Cdr(Scan))
      term_ExchangeVariable(list_Car(Scan),Old,New);
}


BOOL term_SubstituteVariable(SYMBOL Symbol, TERM Repl, TERM Term)
/******************************************************
   INPUT:   A Symbol which has to be found in the Term,
            a term which is the replacement for the    
            'Symbol', and a term in which the substitu-
            tions take place.                          
   RETURNS: A boolean value which is TRUE, if any sub- 
            stitutions were made.                      
   SUMMARY: term_Substitute works recursively and repl.
            every occurence of 'Symbol' in 'Term' by   
            'Repl'.                                    
   CAUTION: FUNCTION IS DESTRUCTIVE ON 'Term'. REPLACE-
            MENT IS COPIED EACH TIME A SUB. TAKES PLACE
*******************************************************/
{
#ifdef CHECK
  if (!term_IsTerm(Term) || !term_IsTerm(Repl) || !symbol_IsSymbol(Symbol)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_SubstituteVariable: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  if (symbol_Equal(term_TopSymbol(Term), Symbol)) {
    
    TERM New;
    New          = term_Copy(Repl);
    Term->symbol = Repl->symbol;
    Term->args   = term_ArgumentList(New);
    
    /* Free Top-Node of New, as the symbol has been written */
    /* into the node pointed to by `Term'. */
    memory_Free(New, sizeof(TERM_NODE));
    return TRUE;
 
  } else {
    
    BOOL Result;
    LIST List;
    
    Result	= FALSE;
    for (List	= term_ArgumentList(Term);
	 list_Exist(List); List = list_Cdr(List))
      if (term_SubstituteVariable(Symbol, Repl, List->car))
	Result  = TRUE;
    return Result;
  }
}


static int term_CompareByConstants(TERM Left, TERM Right)
/**************************************************************
  INPUT:   Two terms.
  RETURNS:  1 if left term < right term
            0 if left term = right term
	   -1 if left term > right term
  EFFECT:  The terms are compared by their multisets of 
           constants. The frequency of elements in the
	   multisets is a multiset itself. The frequencies
	   are sorted and the resulting sorted multisets
	   compared.
***************************************************************/
{
  LIST lconsts, rconsts;
  int result;

  /* Get multiset of constants. */

  lconsts = term_ListOfConstants(Left);
  rconsts = term_ListOfConstants(Right);

  result  = list_CompareMultisetsByElementDistribution(lconsts, rconsts); 

  list_Delete(lconsts);
  list_Delete(rconsts);

  return result;
}

static int term_CompareByFunctions(TERM Left, TERM Right) 
/**************************************************************
  INPUT:   Two terms.
  RETURNS:  1 if left term < right term
            0 if left term = right term
	   -1 if left term > right term
  EFFECT:  The terms are compared by their multisets of 
           functions. The frequency of elements in the
	   multisets is a multiset itself. The frequencies
	   are sorted and the resulting sorted multisets
	   compared.
***************************************************************/
{
  LIST lfuns, rfuns;
  int result;

  /* Get multiset of functions. */

  lfuns = term_ListOfFunctions(Left);
  rfuns = term_ListOfFunctions(Right);

  result  = list_CompareMultisetsByElementDistribution(lfuns, rfuns); 

  list_Delete(lfuns);
  list_Delete(rfuns);

  return result;
}

static int term_CompareByVariables(TERM Left, TERM Right) 
/**************************************************************
  INPUT:   Two terms.
  RETURNS:  1 if left term < right term
            0 if left term = right term
	   -1 if left term > right term
  EFFECT:  The terms are compared by their multisets of 
           variables. The frequency of elements in the
	   multisets is a multiset itself. The frequencies
	   are sorted and the resulting sorted multisets
	   compared.
***************************************************************/
{
  LIST lvars, rvars;
  int result;

  /* Get multiset of variables. */

  lvars = term_ListOfVariables(Left);
  rvars = term_ListOfVariables(Right);

  result  = list_CompareMultisetsByElementDistribution(lvars, rvars); 

  list_Delete(lvars);
  list_Delete(rvars);

  return result;
}

LIST term_ListOfConstants(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: A list of constants.
  EFFECT:  Creates a list of constants used in a term. If no
           constants are used in a term, it returns an empty 
	   list.
***************************************************************/
{
#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_ListOfConstants: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  if (symbol_IsConstant(term_TopSymbol(Term)))
    return list_List((POINTER) term_TopSymbol(Term));
  else {
    LIST result;
    LIST scan;
  
    result = list_Nil();
    for (scan = term_ArgumentList(Term); 
	 !list_Empty(scan); 
	 scan = list_Cdr(scan)) {
      /* Append to the smaller list for efficiency. 
	 A subterm's list of constants will usually 
	 be smaller than the intermediate result.
      */
      result = list_Nconc(term_ListOfConstants((TERM) list_Car(scan)), result);
    }

    return result;
  }
}

LIST term_ListOfFunctions(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: A list of functions.
  EFFECT:  Creates a list of functions used in a term. If no
           functions are used in a term, it returns an empty 
	   list.
***************************************************************/
{
  LIST result;
  LIST scan;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_ListOfFunctions: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  result = list_Nil();

  /* If the term starts with a function, add the function symbol
     to the result.
  */
  if (symbol_IsFunction(term_TopSymbol(Term))) {
    result = list_Nconc(result, list_List((POINTER) term_TopSymbol(Term)));
  }
  
  /* A function can utilize other functions, so
     traverse the argument list for further
     functions.
  */
  for (scan = term_ArgumentList(Term); 
       !list_Empty(scan); 
       scan = list_Cdr(scan)) {
    /* Append to the smaller list for efficiency. 
       A subterm's list of functions will usually 
       be smaller than the intermediate result.
    */
    result = list_Nconc(term_ListOfFunctions((TERM) list_Car(scan)), result);
  }

  return result;
}

void term_CountSymbols(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: None.
  EFFECT:  Counts the non-variable symbols in the term, and 
           increases their counts accordingly.
***************************************************************/
{
  LIST scan;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_CountSymbols: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  /* If the term starts with a function, increase the count for
     the function symbol.
  */
  if (symbol_IsFunction(term_TopSymbol(Term))) {
    SYMBOL S;

    S = term_TopSymbol(Term);
    symbol_SetCount(S, symbol_GetCount(S) + 1);
  }

  /* A function can utilize other functions, so
     traverse the argument list for further
     function symbols.
  */
  for (scan = term_ArgumentList(Term); 
       !list_Empty(scan); 
       scan = list_Cdr(scan)) {
    term_CountSymbols((TERM) list_Car(scan));
  }
}

static int term_CompareByArity(TERM Left, TERM Right)
/**************************************************************
  INPUT:   Two terms.
  RETURNS:  1 if left term < right term
            0 if left term = right term
	   -1 if left term > right term
  EFFECT:  Terms are compared top down, left to right with 
           respect to the arity of their signature symbols,
	   where variables in addition are defined to be smaller
	   than constants.
***************************************************************/
{
  NAT    lval, rval;
  SYMBOL lsymb, rsymb;
  LIST   largs, rargs;
  int    result;

  result = 0;

  /* Compare top symbols first */
  lsymb = term_TopSymbol(Left);
  rsymb = term_TopSymbol(Right);

  if (symbol_IsVariable(lsymb)) {
    if (symbol_IsVariable(rsymb))
      return 0;
    else
      return 1;
  }
  else
    if (symbol_IsVariable(rsymb))
      return -1;

  lval = symbol_Arity(lsymb);
  rval = symbol_Arity(rsymb);
  
  if (lval > rval)
    return -1;

  if (lval < rval)
    return 1;

  /* If top symbol arities are equal, compare subterms left to right */
  largs = term_ArgumentList(Left);
  rargs = term_ArgumentList(Right);

  while(!list_Empty(largs)) {
    result = term_CompareByArity(list_Car(largs), list_Car(rargs));	
    if (result != 0)
      break;

    largs = list_Cdr(largs);
    rargs = list_Cdr(rargs);
  }

  return result;
}

int term_CompareBySymbolOccurences(TERM Left, TERM Right)
/**************************************************************
  INPUT:   Two terms.
  RETURNS:  1 if left term < right term
            0 if left term = right term
	   -1 if left term > right term
  EFFECT:  Terms are compared top down, left to right with 
           respect to the frequency of their symbols.
***************************************************************/
{
  unsigned long  lval, rval;
  SYMBOL         lsymb, rsymb;
  LIST           largs, rargs;
  int            result;

  result = 0;

  /* Compare top symbols first */
  lsymb = term_TopSymbol(Left);
  rsymb = term_TopSymbol(Right);

  if (symbol_IsFunction(lsymb)) {
    if (symbol_IsFunction(rsymb)) {

      lval = symbol_GetCount(lsymb);
      rval = symbol_GetCount(rsymb);
  
      if (lval > rval)
	return -1;

      if (lval < rval)
	return 1;
    
      /* If top symbol arities are equal, compare subterms left to right */
      largs = term_ArgumentList(Left);
      rargs = term_ArgumentList(Right);

      while(!list_Empty(largs)) {
	result = term_CompareBySymbolOccurences(list_Car(largs), 
						list_Car(rargs));	
	if (result != 0)
	  break;

	largs = list_Cdr(largs);
	rargs = list_Cdr(rargs);
      }
    }
    else {
      return -1;
    }
  }
  else {
    if (symbol_IsFunction(rsymb)) {
      return 1;
    }
  }

  return result;
}

int term_CompareAbstract(TERM Left, TERM Right)
/**************************************************************
  INPUT:   Two terms.
  RETURNS:  1 if left term < right term
            0 if left term = right term
	   -1 if left term > right term
  EFFECT:  Compares two terms using an internal array of term 
           comparison functions. As soon as a term is found to 
	   compare greater than the other, the result of the 
	   comparison is returned. If all term comparison 
	   functions yield an "equal", then 0 is returned.
***************************************************************/
{
  int result;
  int i;
  int functions;

  typedef int (*TERM_COMPARE_FUNCTION) (TERM, TERM);

  static const TERM_COMPARE_FUNCTION term_compare_functions [] = {
    term_CompareByArity,
    term_CompareBySymbolOccurences,
    term_CompareByConstants,
    term_CompareByVariables,
    term_CompareByFunctions
  };

#ifdef CHECK
  if (!(term_IsTerm(Left) && term_IsTerm(Right))) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_CompareAbstract: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  result    = 0;
  functions = sizeof(term_compare_functions)/sizeof(TERM_COMPARE_FUNCTION);

  for (i = 0; i < functions; i++) {
    result = term_compare_functions[i](Left, Right);

    if ( result != 0) {
      return result;
    }
  }

  return result;
}

BOOL term_CompareAbstractLEQ(TERM Left, TERM Right)
/**************************************************************
  INPUT:   Two terms.
  RETURNS: TRUE if left term <= right term, FALSE otherwise.
  EFFECT:  Terms are compared top down, left to right with 
           respect to the arity of their signature symbols,
	   where variables in addition are defined to be smaller
	   than constants.
***************************************************************/
{
  return (term_CompareAbstract(Left, Right) >= 0);
}


NAT term_ComputeSize(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: The number of symbols in the term.
  EFFECT:  None
***************************************************************/
{
  NAT  Weight;
  LIST Scan;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_ComputeSize: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  Weight = 1;
  for (Scan=term_ArgumentList(Term); !list_Empty(Scan); Scan=list_Cdr(Scan))
    Weight += term_ComputeSize((TERM)list_Car(Scan));
  return Weight;
}

NAT term_RootDistance(TERM Term)
/**************************************************************
  INPUT:   A term with establised father links.
  RETURNS: The distance from <Term> to its root father term.
  EFFECT:  None
***************************************************************/
{
  NAT  Distance;

  Distance = 0;

  while (term_Superterm(Term) != (TERM)NULL) {
    Distance++;
    Term = term_Superterm(Term);
  }

  return Distance;
}

BOOL term_RootDistanceSmaller(TERM Term1, TERM Term2)
/**************************************************************
  INPUT:   Two terms with establised father links.
  RETURNS: TRUE iff root distance of <Term1> is smaller than
           root distance of <Term2>
  EFFECT:  None
***************************************************************/
{
  return (term_RootDistance(Term1)<term_RootDistance(Term2));
}

void term_InstallSize(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: None
  EFFECT:  Sets for every subterm the size.
***************************************************************/
{
  NAT  Weight;
  LIST Scan;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_InstallSize: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  Weight = 1;
  for (Scan=term_ArgumentList(Term); !list_Empty(Scan); Scan=list_Cdr(Scan)) {
    term_InstallSize((TERM)list_Car(Scan));
    Weight += term_Size((TERM)list_Car(Scan));
  };
  term_SetSize(Term, Weight);
}

NAT term_Depth(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: The depth of the term.
  EFFECT:  None
***************************************************************/
{
  NAT  Depth,Help;
  LIST Scan;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_Depth: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  Depth = 0;
  for (Scan=term_ArgumentList(Term); !list_Empty(Scan); Scan=list_Cdr(Scan)) {
    Help = term_Depth(list_Car(Scan));
    if (Help > Depth)
      Depth = Help;
  }
  return (Depth+1);
}

BOOL term_ContainsSymbol(TERM Term, SYMBOL Symbol)
/**************************************************************
  INPUT:   A term and a symbol.
  RETURNS: TRUE, if the symbol occurs somewhere in the term,
           FALSE otherwise.
***************************************************************/
{
  int Stack;

#ifdef CHECK
  if (!term_IsTerm(Term) || !symbol_IsSymbol(Symbol)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_ContainsSymbol: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  Stack = stack_Bottom();

  do {
    if (term_TopSymbol(Term) == Symbol) {
      stack_SetBottom(Stack);    /* Clean up the stack */
      return TRUE;
    }
    else
      if (term_IsComplex(Term))
	stack_Push(term_ArgumentList(Term));

    while (!stack_Empty(Stack) && list_Empty(stack_Top()))
      stack_Pop();

    if (!stack_Empty(Stack)) {
      Term = list_Car(stack_Top());
      stack_RplacTop(list_Cdr(stack_Top()));
    }
  } while (!stack_Empty(Stack));

  return FALSE;
}

TERM term_FindSubterm(TERM Term, SYMBOL Symbol)
/**************************************************************
  INPUT:   A term and a symbol.
  RETURNS: If the symbol occurs in the Term the subterm is returned.
           NULL otherwise.
***************************************************************/
{
  int stack;

#ifdef CHECK
  if (!term_IsTerm(Term) || !symbol_IsSymbol(Symbol)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_FindSubterm: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  stack = stack_Bottom();

  do {
    if (term_TopSymbol(Term) == Symbol) {
      stack_SetBottom(stack);    /* Clean up the stack */
      return Term;
    } else if (term_IsComplex(Term))
      stack_Push(term_ArgumentList(Term));

    while (!stack_Empty(stack) && list_Empty(stack_Top()))
      stack_Pop();

    if (!stack_Empty(stack)) {
      Term = list_Car(stack_Top());
      stack_RplacTop(list_Cdr(stack_Top()));
    }
  } while (!stack_Empty(stack));

  return NULL;
}

static int term_SharingList(TERM Term, LIST List)
/**************************************************************
  INPUT:   A term and a list cell.
  RETURNS: The number of times <List> occurs in <Term>
  EFFECT:  None
***************************************************************/
{
  LIST Scan;
  int  n;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_SharingList: Illegal input.");
    misc_FinishErrorReport();
  }
#endif
  
  n = 0;

  for (Scan=term_ArgumentList(Term); !list_Empty(Scan); Scan=list_Cdr(Scan)) {
    if (Scan == List)
      n++;
    n += term_SharingList(list_Car(Scan), List);
  }

  return n;
}


static int term_SharingTerm(TERM Term, TERM CompareTerm)
/**************************************************************
  INPUT:   A term and a compare term
  RETURNS: The number of occurrences of <CompareTerm> in <Term>
  EFFECT:  None
***************************************************************/
{
  LIST Scan;
  int  n;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_SharingTerm: Illegal input.");
    misc_FinishErrorReport();
  }
#endif
  
  n = 0;

  if (Term == CompareTerm)
    n = 1;

  for (Scan=term_ArgumentList(Term); !list_Empty(Scan); Scan=list_Cdr(Scan))
    n += term_SharingTerm(list_Car(Scan),CompareTerm);

  return n;
}


BOOL term_Sharing(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: TRUE iff the term shares list cells or subterms.
  EFFECT:  None
***************************************************************/
{
  LIST Scan;
  int  stack;
  TERM ActTerm;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_Sharing: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  stack = stack_Bottom();
  stack_Push(Term);

  while (!stack_Empty(stack)) {
    ActTerm = (TERM)stack_Top();
    stack_Pop();
    
    if (term_SharingTerm(Term,ActTerm)>1)
      return TRUE;
  
    if (term_IsComplex(Term)) {
      for (Scan = term_ArgumentList(ActTerm);
	   !list_Empty(Scan);
	   Scan=list_Cdr(Scan))
	if (term_SharingList(Term, Scan) > 1)
	  return TRUE;
	else
	  stack_Push(list_Car(Scan));
    }
  }
  
  return FALSE;
}


void term_AddFatherLinks(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: void.
  EFFECT:  The super term links of Term are cleared and then all
           its subterms are set.
***************************************************************/
{
  LIST Scan;
  TERM ActTerm;

  term_RplacSuperterm(Term,(TERM)NULL);
  
  for (Scan=term_ArgumentList(Term);!list_Empty(Scan);Scan=list_Cdr(Scan)) {
    ActTerm  = (TERM)list_Car(Scan);
    term_AddFatherLinks(ActTerm);
    term_RplacSuperterm(ActTerm,Term);
  }

}

BOOL term_FatherLinksEstablished(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: TRUE iff all father links in Term are established.
  EFFECT:  None.
***************************************************************/
{
  LIST Scan;
  
  for (Scan=term_ArgumentList(Term);!list_Empty(Scan);Scan=list_Cdr(Scan))
   if (Term != term_Superterm(list_Car(Scan)) || !term_FatherLinksEstablished(list_Car(Scan)))
     return FALSE;

  return TRUE;
}

TERM term_TopLevelTerm(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: The top level father of the term.
  EFFECT:  The father links have to be established!
***************************************************************/
{
  while (term_Superterm(Term))
    Term = term_Superterm(Term);
  return Term;
}


BOOL term_HasPointerSubterm(TERM Term, TERM Subterm)
/**************************************************************
  INPUT:   Two terms.
  RETURNS: TRUE, if <Term> has <Subterm> as a subterm.
  CAUTION: Only term pointers are compared, term_Equal isn't used.
***************************************************************/
{
  if (Term == Subterm)
    return TRUE;
  else {
    LIST scan = term_ArgumentList(Term);

    while (!list_Empty(scan)) {
      if (term_HasPointerSubterm((TERM) list_Car(scan), Subterm))
	return TRUE;
      scan = list_Cdr(scan);
    }
  }

  return FALSE;
}

BOOL term_HasSubterm(TERM Term, TERM Subterm)
/**************************************************************
  INPUT:   Two terms.
  RETURNS: TRUE, if <Term> has <Subterm> as a subterm.
  CAUTION: term_Equal is used.
***************************************************************/
{
  if (term_Equal(Term,Subterm))
    return TRUE;
  else {
    LIST Scan;
    Scan = term_ArgumentList(Term);

    while (!list_Empty(Scan)) {
      if (term_HasSubterm((TERM) list_Car(Scan), Subterm))
	return TRUE;
      Scan = list_Cdr(Scan);
    }
  }

  return FALSE;
}

BOOL term_HasProperSuperterm(TERM Term, TERM Super)
/**********************************************************
  INPUT   : Two terms.
  RETURNS : TRUE iff Super can be reached from Term by following
            the superterm member of the TERM structure.
  CAUTION : not reflexive
**********************************************************/
{
  if (Term == Super)
    return FALSE;
  while (Term != (TERM) NULL) {
    if (Term == Super)            /* Pointer equality ! */
      return TRUE;
    else
      Term = term_Superterm(Term);
  }
  return FALSE;
}


/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *  TERM OUTPUT FUNCTIONS                                 * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/

void term_Print(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: none.
  SUMMARY: Prints the term to stdout.
  CAUTION: Uses the other term output functions.
***************************************************************/
{
  if (term_IsComplex(Term)) {
    putchar('(');
    symbol_Print(term_TopSymbol(Term));
    putchar(' ');
    term_TermListPrint(term_ArgumentList(Term));
    putchar(')');

  } else if (term_IsVariable(Term)) {

    symbol_Print(term_TopSymbol(Term));

  } else {

    /* term_IsConstant(Term) */
    putchar('(');
    symbol_Print(term_TopSymbol(Term));
    putchar(')');
  }
}

static void term_PrettyPrintIntern(TERM Term, int Depth)
/**************************************************************
  INPUT:   A term and a depth parameter for indentation.
  RETURNS: none.
  SUMMARY: Prints the term hopefully more pretty to stdout.
***************************************************************/
{
  int i;
  LIST scan;


  for (i=0; i < Depth; i++)
    fputs("  ", stdout);
  if (symbol_IsJunctor(term_TopSymbol(Term))) {
    if (term_IsComplex(Term)) {
      symbol_Print(term_TopSymbol(Term));
      putchar('(');
      fputs("\n", stdout);
      for (scan=term_ArgumentList(Term); !list_Empty(scan); scan= list_Cdr(scan)) {
	term_PrettyPrintIntern((TERM) list_Car(scan), Depth+1);
	if (!list_Empty(list_Cdr(scan)))
	  fputs(",\n", stdout);
      }
      putchar(')');
    }
    else {
      if (term_IsVariable(Term)) {
	symbol_Print(term_TopSymbol(Term));
      }
      else {
	putchar('(');
	symbol_Print(term_TopSymbol(Term));
	putchar(')');
      }
    }
  }
  else {
    term_PrintPrefix(Term);
  }
}

void term_PrettyPrint(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: none.
  SUMMARY: Prints the term hopefully more pretty to stdout.
***************************************************************/
{
  term_PrettyPrintIntern(Term, 0);
}


void term_FPrint(FILE* File,TERM Term)
/**************************************************************
  INPUT:   A file and a term.
  RETURNS: none.
  SUMMARY: Prints the term to the file.
  CAUTION: Uses the other term output functions.
***************************************************************/
{
  if (term_IsComplex(Term)) {
    putc('(', File);
    symbol_FPrint(File,term_TopSymbol(Term));
    putc(' ', File);
    term_TermListFPrint(File,term_ArgumentList(Term));
    putc(')', File);

  } else if (term_IsVariable(Term)) {

    symbol_FPrint(File,term_TopSymbol(Term));

  } else {

    /* term_IsConstant(Term) */
    putc('(', File);
    symbol_FPrint(File,term_TopSymbol(Term));
    putc(')', File);
  }
}


void term_TermListPrint(LIST List)
/**************************************************************
  INPUT:   A list of terms.
  RETURNS: None.
***************************************************************/
{
  for (; !list_Empty(List); List=list_Cdr(List)) {
    term_Print(list_Car(List)); fflush(stdout);
    if (!list_Empty(list_Cdr(List)))
      putchar(' ');
  }
}


void term_TermListFPrint(FILE* File, LIST List)
/**************************************************************
  INPUT:   A list of terms.
  RETURNS: None.
***************************************************************/
{
  for (; !list_Empty(List); List=list_Cdr(List)) {
    term_FPrint(File,list_Car(List));
    if (!list_Empty(list_Cdr(List)))
      putc(' ', File);
  }
}


void term_PrintPrefix(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: none.
  SUMMARY: Prints the term in prefix notation to stdout.
  CAUTION: Uses the other term output functions.
***************************************************************/
{
  if (term_IsComplex(Term)) {
    symbol_Print(term_TopSymbol(Term));
    putchar('(');
    term_TermListPrintPrefix(term_ArgumentList(Term));
    putchar(')');

  } else
    symbol_Print(term_TopSymbol(Term));
}


void term_FPrintPrefix(FILE* File, TERM Term)
/**************************************************************
  INPUT:   A file and a term.
  RETURNS: none.
  SUMMARY: Prints the term in prefix notation to the file.
  CAUTION: Uses the other term output functions.
***************************************************************/
{
  if (term_IsComplex(Term)) {
    symbol_FPrint(File,term_TopSymbol(Term));
    putc('(', File);
    term_TermListFPrintPrefix(File,term_ArgumentList(Term));
    putc(')', File);

  } else
    symbol_FPrint(File,term_TopSymbol(Term));
}


void term_TermListPrintPrefix(LIST List)
/**************************************************************
  INPUT:   A list of terms.
  RETURNS: None.
***************************************************************/
{
  for (; !list_Empty(List); List=list_Cdr(List)) {
    term_PrintPrefix(list_Car(List));
    if (!list_Empty(list_Cdr(List)))
      putchar(',');
  }
}


void term_TermListFPrintPrefix(FILE* File, LIST List)
/**************************************************************
  INPUT:   A list of terms.
  RETURNS: None.
***************************************************************/
{
  for (; !list_Empty(List); List=list_Cdr(List)) {
    term_FPrintPrefix(File,list_Car(List));
    if (!list_Empty(list_Cdr(List)))
      putc(',', File);
  }
}



void term_FPrintOtterPrefix(FILE* File, TERM Term)
/**************************************************************
  INPUT:   A file and a term.
  RETURNS: none.
  SUMMARY: Prints the term in prefix notation to the file.
  CAUTION: Uses the other term_Output functions.
***************************************************************/
{
  if (term_IsComplex(Term)) {
    symbol_FPrintOtter(File, term_TopSymbol(Term));
    putc('(', File);
    term_TermListFPrintOtterPrefix(File, term_ArgumentList(Term));
    putc(')', File);
  } else
    symbol_FPrintOtter(File, term_TopSymbol(Term));
}


void term_TermListFPrintOtterPrefix(FILE* File, LIST List)
/**************************************************************
  INPUT:   A list of terms.
  RETURNS: None.
***************************************************************/
{
  for (; !list_Empty(List); List=list_Cdr(List)) {
    term_FPrintOtterPrefix(File,list_Car(List));
    if (!list_Empty(list_Cdr(List)))
      putc(',', File);
  }
}


void term_FPrintPosition(FILE* File, TERM TopTerm, TERM Subterm)
/**************************************************************
  INPUT:   An output file and two terms where <Subterm> is a subterm
           of <TopTerm>.
  RETURNS: Nothing.
  SUMMARY: The position of <Subterm> relative to <TopTerm> is
           printed to the output file. A simple top-down search
	   is done, so the superterm pointers are not needed.
	   Note that we compare terms with respect to pointers!
	   If <Subterm> isn't a subterm of <TopTerm> at all,
	   this causes an error message followed by a core dump.
***************************************************************/
{
  NAT  pos;
  LIST Scan;

  if (TopTerm == Subterm)
    return;

  for (Scan = term_ArgumentList(TopTerm), pos = 1; !list_Empty(Scan);
       Scan = list_Cdr(Scan), pos++) {
    if (term_HasPointerSubterm(list_Car(Scan), Subterm)) {
      fprintf(File, "%zu", pos);
      if (Subterm != list_Car(Scan)) {
	putc('.', File);
	term_FPrintPosition(File, list_Car(Scan), Subterm);
      }
      return;
    }
  }
  misc_StartErrorReport();
  misc_ErrorReport("\n In term_FPrintPosition: Term isn't subterm of the other one.");
  misc_FinishErrorReport();
}


/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *			HIGH LEVEL FUNCTIONS		    * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/

NAT term_Bytes(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: The number of bytes occupied by the term.
  EFFECT:  None
***************************************************************/
{
  NAT  Bytes;
  LIST Scan;

  Bytes = sizeof(TERM_NODE) + list_Bytes(term_ArgumentList(Term));
  for (Scan=term_ArgumentList(Term); !list_Empty(Scan); Scan=list_Cdr(Scan))
    Bytes += term_Bytes((TERM)list_Car(Scan));
  return Bytes;
}


LIST term_ListOfVariables(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: The list of variables occurring in the term.
           Note that there may be many terms with same variable symbol.
***************************************************************/
{
  LIST         Stack, Variables;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_ListOfVariables: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  Variables = list_Nil();
  Stack     = list_StackBottom();
  do {
    if (term_IsComplex(Term))
      Stack = list_Push(term_ArgumentList(Term),Stack);
    else
      if (term_IsVariable(Term))
	Variables = list_Cons(Term, Variables);
    while (!list_StackEmpty(Stack) && list_Empty(list_Top(Stack)))
      Stack = list_Pop(Stack);
    if (!list_StackEmpty(Stack)) {
      Term = (TERM)list_Car(list_Top(Stack));
      list_RplacTop(Stack, list_Cdr(list_Top(Stack)));
    }
  } while (!list_StackEmpty(Stack));
  return Variables;
}


void term_MarkVariables(TERM Term, NAT Mark)
/**************************************************************
  INPUT:   A term.
  RETURNS: Nothing.
  EFFECT:  All variables from <Term> are marked with <Mark>.
  CAUTION: The term module must be in a binding phase (started with
           term_StartBinding)!
***************************************************************/
{
  int Stack;

#ifdef CHECK
  if (!term_InBindingPhase()) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_MarkVariables:");
    misc_ErrorReport(" Called while not in binding phase.");
    misc_FinishErrorReport();
  }
#endif

  Stack = stack_Bottom();
  do {
    if (term_IsComplex(Term)) {
      stack_Push(term_ArgumentList(Term));
    }
    else if (term_IsVariable(Term))
      term_CreateBinding(term_TopSymbol(Term), Mark);
    while (!stack_Empty(Stack) && list_Empty(stack_Top()))
      stack_Pop();
    if (!stack_Empty(Stack)) {
      Term = (TERM)list_Car(stack_Top());
      stack_RplacTop(list_Cdr(stack_Top()));
    }
  } while (!stack_Empty(Stack));
}


LIST term_VariableSymbols(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: The list of variable symbols occurring in the term.
***************************************************************/
{
  LIST    Variables;
  int     Stack;
  SYMBOL  Top;
  NAT     ActMark;

#ifdef CHECK
  if (!term_IsTerm(Term) || term_InBindingPhase()) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_VariableSymbols: Illegal input or context.");
    misc_FinishErrorReport();
  }
#endif

  term_StartBinding();

  Variables = list_Nil();
  Stack     = stack_Bottom();
  ActMark   = term_ActMark();
  do {
    if (term_IsComplex(Term)) {
      stack_Push(term_ArgumentList(Term));
    }
    else {
      Top = term_TopSymbol(Term);
      if (symbol_IsVariable(Top) && !term_VarIsMarked(Top, ActMark)) {
	Variables = list_Cons((POINTER)Top, Variables);
	term_CreateBinding(Top, ActMark);
      }
    }
    while (!stack_Empty(Stack) && list_Empty(stack_Top()))
      stack_Pop();
    if (!stack_Empty(Stack)) {
      Term = (TERM)list_Car(stack_Top());
      stack_RplacTop(list_Cdr(stack_Top()));
    }
  } while (!stack_Empty(Stack));

  term_StopBinding();

  return Variables;
}


NAT term_NumberOfVarOccs(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: The list of variable symbols occurring in the term.
***************************************************************/
{
  NAT      Result;
  int      Stack;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_NumberOfVarOccs: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  Result = 0;
  Stack = stack_Bottom();
  do {
    if (term_IsComplex(Term)) {
      stack_Push(term_ArgumentList(Term));
    }
    else {
      if (symbol_IsVariable(term_TopSymbol(Term)))
	Result++;
    }
    while (!stack_Empty(Stack) && list_Empty(stack_Top()))
      stack_Pop();
    if (!stack_Empty(Stack)) {
      Term = (TERM)list_Car(stack_Top());
      stack_RplacTop(list_Cdr(stack_Top()));
    }
  } while (!stack_Empty(Stack));

  return Result;
}

NAT term_NumberOfSymbolOccurrences(TERM Term, SYMBOL Symbol)
/**************************************************************
  INPUT:   A term and a symbol.
  RETURNS: The number of occurrences of <Symbol> in <Term>
***************************************************************/
{
  NAT   Result;
  LIST  Scan;

#ifdef CHECK
  if (!term_IsTerm(Term) || !symbol_IsSymbol(Symbol)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_NumberOfSymbolOccurrences: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  Result = 0;
  
  if (symbol_Equal(term_TopSymbol(Term),Symbol))
    Result++;

  for (Scan = term_ArgumentList(Term); !list_Empty(Scan);  Scan=list_Cdr(Scan))
    Result += term_NumberOfSymbolOccurrences(list_Car(Scan), Symbol);

  return Result;
}


BOOL term_ContainsFunctions(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: TRUE iff the term contains a function symbol
***************************************************************/
{
  int      Stack;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_ContainsFunctions: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  Stack = stack_Bottom();
  do {
    if (term_IsComplex(Term)) {
      if (symbol_IsFunction(term_TopSymbol(Term)) && !symbol_IsConstant(term_TopSymbol(Term))) {
	stack_SetBottom(Stack);
	return TRUE;
      }
      stack_Push(term_ArgumentList(Term));
    }

    while (!stack_Empty(Stack) && list_Empty(stack_Top()))
      stack_Pop();
    if (!stack_Empty(Stack)) {
      Term = (TERM)list_Car(stack_Top());
      stack_RplacTop(list_Cdr(stack_Top()));
    }
  } while (!stack_Empty(Stack));

  return FALSE;
}

BOOL term_ContainsVariable(TERM Term, SYMBOL Var)
/**************************************************************
  INPUT:   A term and a variable symbol.
  RETURNS: TRUE iff the term contains the variable symbol
***************************************************************/
{
  int      Stack;

#ifdef CHECK
  if (!term_IsTerm(Term) || !symbol_IsSymbol(Var)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_ContainsVariable: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  Stack = stack_Bottom();
  do {
    if (term_IsComplex(Term))
      stack_Push(term_ArgumentList(Term));
    else
      if (symbol_Equal(term_TopSymbol(Term),Var)) {
	stack_SetBottom(Stack);
	return TRUE;
      }

    while (!stack_Empty(Stack) && list_Empty(stack_Top()))
      stack_Pop();
    if (!stack_Empty(Stack)) {
      Term = (TERM)list_Car(stack_Top());
      stack_RplacTop(list_Cdr(stack_Top()));
    }
  } while (!stack_Empty(Stack));

  return FALSE;
}

SYMBOL term_MaxVar(TERM Term)
/*********************************************************
  INPUT:   A term.
  RETURNS: The maximal variable in <Term>, NULL otherwise
********************************************************/
{
  LIST   Scan;
  int    Stack;
  SYMBOL Result;

#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_MaxVar: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  Result = (SYMBOL)NULL;
  Stack  = stack_Bottom();

  if (term_IsStandardVariable(Term)) {
    if (term_TopSymbol(Term)>Result)
      Result = term_TopSymbol(Term);
  }
  else
    if (term_IsComplex(Term))
      stack_Push(term_ArgumentList(Term));
  
  while (!stack_Empty(Stack)) {
    Scan = stack_Top();
    Term = (TERM)list_Car(Scan);
    stack_RplacTop(list_Cdr(Scan));
    
    if (term_IsStandardVariable(Term)) {
      if (term_TopSymbol(Term)>Result)
	Result = term_TopSymbol(Term);
    }
    else
      if (term_IsComplex(Term))
	stack_Push(term_ArgumentList(Term));
    
    while (!stack_Empty(Stack) && list_Empty(stack_Top()))
      stack_Pop();
  }
  
  return Result;
}



/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *			Renaming           		    * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/


void term_StartMinRenaming(void)
/**************************************************************
  INPUT:   None
  EFFECT:  Initializes the term and symbol modules for min co var renaming
***************************************************************/
{
  symbol_ResetStandardVarCounter();
  term_NewMark();
}


void term_StartMaxRenaming(SYMBOL MaxVar)
/**************************************************************
  INPUT:   A variable symbol.
  EFFECT:  Initializes the term and symbol modules for renaming above <MaxVar>
***************************************************************/
{
  symbol_SetStandardVarCounter(MaxVar);
  term_NewMark();
}


TERM term_Rename(TERM Term)
/**************************************************************
  INPUT:   A Term.
  RETURNS: The destructively renamed term.
  EFFECT:  All co variables are destructively renamed in <TERM>
***************************************************************/
{
  int     Stack;
  SYMBOL  Top;
  NAT     ActMark;
  TERM    ActTerm;
  
#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_Rename: Illegal input.");
    misc_FinishErrorReport();
  }
  if (term_InBindingPhase()) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_Rename: Illegal context.");
    misc_FinishErrorReport();
  }
#endif

  term_StartBinding();
  
  Stack = stack_Bottom();
  ActMark = term_OldMark();
  ActTerm = Term;
  do {
    if (term_IsComplex(ActTerm)) {
      stack_Push(term_ArgumentList(ActTerm));
    }
    else {
      Top = term_TopSymbol(ActTerm);
      if (symbol_IsVariable(Top)) {
	if (!term_VarIsMarked(Top, ActMark))
	  term_CreateValueBinding(Top, ActMark, (POINTER)symbol_CreateStandardVariable());
	term_RplacTop(ActTerm,(SYMBOL)term_BindingValue(Top));
      }
    }
    
    while (!stack_Empty(Stack) && list_Empty(stack_Top()))
      stack_Pop();
    if (!stack_Empty(Stack)) {
      ActTerm = (TERM)list_Car(stack_Top());
      stack_RplacTop(list_Cdr(stack_Top()));
    }
  } while (!stack_Empty(Stack));

  term_StopBinding();
  
  return Term;
}

SYMBOL term_GetRenamedVarSymbol(SYMBOL Var)
/**************************************************************
  INPUT:   A variable symbol.
  RETURNS: The renamed variable for symbol for <var> with respect
           to the current renaming. If it does not exist, <var>
	   itself is returned.
  EFFECT:  None.
***************************************************************/
{
  NAT ActMark;

#ifdef CHECK
  if (!symbol_IsStandardVariable(Var)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_GetRenamedVarSymbol: Illegal input.");
    misc_FinishErrorReport();
  }
#endif
  
  ActMark = term_OldMark();
  
  if (term_VarIsMarked(Var, ActMark))
    return (SYMBOL)term_BindingValue(Var);

  return Var;
}


static LIST term_MakePseudoLinear(TERM Term, NAT Depth, NAT Mark)
/**************************************************************
  INPUT:   A Term and a variable and the current depth.
  RETURNS: A list of pairs (<oldvar>,<newvar>)
  EFFECT:  The term is destructively made pseudo_linear.
***************************************************************/
{
  LIST   Result,Scan;
  SYMBOL Top;

  Result = list_Nil();

  if (term_IsComplex(Term))
    for (Scan=term_ArgumentList(Term);!list_Empty(Scan);Scan=list_Cdr(Scan))
      Result = list_Nconc(term_MakePseudoLinear(list_Car(Scan),Depth+1,Mark),
			  Result);
  else {
    Top = term_TopSymbol(Term);
    if (symbol_IsVariable(Top)) {
      if (term_VarIsMarked(Top, Mark)) {
	if (Depth != (NAT)term_BindingValue(Top))
	  term_RplacTop(Term,symbol_CreateStandardVariable());
	Result = list_Cons(list_PairCreate((POINTER)Top,
					   (POINTER)term_TopSymbol(Term)),
			   Result);
      }
      else {
	term_CreateValueBinding(Top, Mark, (POINTER)Depth);
      }
    }
  }
  
  return Result;
}


LIST term_RenamePseudoLinear(TERM Term, SYMBOL Var)
/**************************************************************
  INPUT:   A Term and a variable.
  RETURNS: A list of pairs (<oldvar>,<newvar>)
  EFFECT:  The term is destructively renamed.
***************************************************************/
{
  NAT  Mark;
  LIST Result;

#ifdef CHECK
  if (!term_IsTerm(Term) || !symbol_IsVariable(Var) || term_InBindingPhase()) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_RenamePseudoLinear: Illegal input or context.");
    misc_FinishErrorReport();
  }
#endif
  
  term_StartBinding();
  symbol_SetStandardVarCounter(Var);

  term_NewMark();
  Mark   = term_ActMark();
  Result = term_MakePseudoLinear(Term,0,Mark);

  term_StopBinding();

  return Result;
}


/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *			STAMP FUNCTIONS  	            * */
/* *							    * */
/* ********************************************************** */
/**************************************************************/

NAT term_GetStampID(void)
/**************************************************************
  INPUT:   None
  RETURNS: An identifier that must be used for some stamp functions
  EFFECT:  Each module using the term stamp has to request an
           identifier that is needed for function term_StampOverflow
           The purpose of this identifier is to synchronize
           different modules in case of an overflow of the variable
           term_STAMP.
***************************************************************/
{
  if (term_STAMPUSERS >= term_MAXSTAMPUSERS) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In term_GetStampID: no more free stamp IDs.");
    misc_UserErrorReport("\n You have to increase the constant term_MAXSTAMPUSERS.");
    misc_FinishUserErrorReport();
  }

  return term_STAMPUSERS++;
}


BOOL term_StampOverflow(NAT ID)
/**************************************************************
  INPUT:   The identifier of the calling module as returned by
           the function term_GetStampID.
  RETURNS: True if an overflow of the variable term_STAMP occurred
           for the module with the identifier ID.
  CAUTION: If an overflow occurred for a module you can test that
           only once!!! After the first test the overflow flag
	   is cleared for that module.
***************************************************************/
{
  BOOL Result = FALSE;
  NAT i;

#ifdef CHECK
  if (ID >= term_MAXSTAMPUSERS) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_StampOverflow: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  if (term_STAMP == NAT_MAX) {
    term_STAMP = 0;
    /* set overflow flag for all other modules */
    for (i = 0; i < term_MAXSTAMPUSERS; i++)
      term_STAMPOVERFLOW[i] = TRUE;
    term_STAMPOVERFLOW[ID] = FALSE;
    Result = TRUE;
  } else if (term_STAMPOVERFLOW[ID]) {
    term_STAMPOVERFLOW[ID] = FALSE;
    Result = TRUE;
  }
  return Result;
}

void term_SetTermSubtermStamp(TERM Term)
/**************************************************************
  INPUT:   A term.
  RETURNS: void.
  EFFECT:  Sets the current stamp to <Term> and its subterms.
***************************************************************/
{
#ifdef CHECK
  if (!term_IsTerm(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_SetTermSubtermStamp: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  term_SetTermStamp(Term);
  list_Apply((void (*)(POINTER)) term_SetTermSubtermStamp,
	     term_ArgumentList(Term));
}

LIST term_ListOfAtoms(TERM Term, SYMBOL Predicate)
/**************************************************************
  INPUT:   A term and a predicate symbol.
  RETURNS: A list of pointers to all atoms in Term with
           predicate symbol <Predicate>.
***************************************************************/
{
  if (symbol_Equal(term_TopSymbol(Term), Predicate))
    return list_List(Term);
  else {
    LIST Result, List;

    Result = list_Nil();
    for (List = term_ArgumentList(Term); !list_Empty(List); List = list_Cdr(List))
      Result = list_Nconc(Result, term_ListOfAtoms(list_Car(List), Predicate));
    return Result;
  }
}

/* Currently only in CHECK mode */
#ifdef CHECK

void term_StartStamp(void)
/**************************************************************
  INPUT:   None
  RETURNS: Nothing
  EFFECT:  The stamp is prepared for a new term traversal.
***************************************************************/
{
  if (term_STAMPBLOCKED) {
    /* Error: the Stamp is already used */
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_StartStamp: Illegal context, term stamp is already used.");
    misc_FinishErrorReport();
  }
  else {
    term_STAMP++;
    term_STAMPBLOCKED = TRUE;
  }
}

#endif

LIST term_FindAllAtoms(TERM Term, SYMBOL Predicate)
/**********************************************************************
   INPUT:  A term Term and a symbol Predicate.
   RETURN: A list of all atoms of Term with Symbol as top symbol.
***********************************************************************/
{
  int stack;
  LIST Result;

#ifdef CHECK
  if (!term_IsTerm(Term) || !symbol_IsPredicate(Predicate)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In term_FindAllPredicates: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  stack  = stack_Bottom();
  Result = list_Nil();

  do {
    if (term_TopSymbol(Term) == Predicate) {
      Result = list_Cons(Term, Result);
    } else if (term_IsComplex(Term))
      stack_Push(term_ArgumentList(Term));

    while (!stack_Empty(stack) && list_Empty(stack_Top()))
      stack_Pop();

    if (!stack_Empty(stack)) {
      Term = list_Car(stack_Top());
      stack_RplacTop(list_Cdr(stack_Top()));
    }
  } while (!stack_Empty(stack));

  return Result;
}

BOOL term_CheckTermIntern(TERM Term, BOOL Links)
/**************************************************************************
  INPUT:  A term and a boolean.
  RETURN: True iff  1) the arity of each top symbol is equal to the number
                       of arguments of symbol's term.
		and 2) either all father links are set correctly iff Links is TRUE
		       or none is set iff Links is FALSE.
  COMMENT: Intern function of term_CheckTerm.
***************************************************************************/
{
  LIST Scan;
  SYMBOL Top;
  
  if (!term_IsTerm(Term))
    return FALSE;

  Top = term_TopSymbol(Term);
  if (symbol_IsSignature(Top) &&
      symbol_Arity(Top) != -1 &&
      symbol_Arity(Top) != (int)list_Length(term_ArgumentList(Term)))
    return FALSE;

  if (symbol_IsVariable(Top) && !list_Empty(term_ArgumentList(Term)))
    return FALSE;

  if (Links) {
    for (Scan = term_ArgumentList(Term); !list_Empty(Scan); Scan = list_Cdr(Scan)) {
      if (term_Superterm(list_Car(Scan)) != Term ||
	  !term_CheckTermIntern(list_Car(Scan), Links))
	return FALSE;
    }
  }
  else {
    for (Scan = term_ArgumentList(Term); !list_Empty(Scan); Scan = list_Cdr(Scan)) {
      if (term_Superterm(list_Car(Scan)) != term_Null() ||
	  !term_CheckTermIntern(list_Car(Scan), Links))
	return FALSE;
    }
  }
  return TRUE;
}

BOOL term_CheckTerm(TERM Term)
/********************************************************************************
   INPUT : A term Term.
   RETURN: TRUE iff  eihter all or no father links are set AND
                     the length of any argument list matches the arity of the respective symbol
*********************************************************************************/
{
  if (term_IsComplex(Term) &&
      term_Superterm(term_FirstArgument(Term)) != term_Null())
    /* check father links as well */
    return term_CheckTermIntern(Term, TRUE);
  else
    return term_CheckTermIntern(Term, FALSE);
}
