blob: 7bbecc680e6a901fa02cd58b20fbdf87d2849085 [file] [log] [blame]
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * CONTEXTS FOR VARIABLES * */
/* * * */
/* * $Module: CONTEXT * */
/* * * */
/* * Copyright (C) 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 GNU * */
/* * General Public License as published by the Free * */
/* * Software Foundation; either version 2 of the License, * */
/* * or (at your option) any later version. * */
/* * * */
/* * 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 GNU General Public * */
/* * License for more details. * */
/* * * */
/* * You should have received a copy of the GNU General * */
/* * Public License along with this program; if not, write * */
/* * to the Free Software Foundation, Inc., 59 Temple * */
/* * Place, Suite 330, Boston, MA 02111-1307 USA * */
/* * * */
/* * * */
/* $Revision$ * */
/* $State$ * */
/* $Date$ * */
/* $Author$ * */
/* * * */
/* * Contact: * */
/* * Christoph Weidenbach * */
/* * MPI fuer Informatik * */
/* * Stuhlsatzenhausweg 85 * */
/* * 66123 Saarbruecken * */
/* * Email: weidenb@mpi-sb.mpg.de * */
/* * Germany * */
/* * * */
/* ********************************************************** */
/**************************************************************/
/* $RCSfile$ */
#include "context.h"
/**************************************************************/
/* Global Variables */
/**************************************************************/
int cont_NOOFCONTEXTS;
LIST cont_LISTOFCONTEXTS;
int cont_BINDINGS;
SYMBOL cont_INDEXVARSCANNER;
CONTEXT cont_LASTBINDING; /* The last binding made. */
CONTEXT cont_CURRENTBINDING; /* Help variable. */
CONTEXT cont_LEFTCONTEXT;
CONTEXT cont_RIGHTCONTEXT;
CONTEXT cont_INSTANCECONTEXT;
cont_STACK_TYPE cont_STACK;
int cont_STACKPOINTER;
cont_CHECKSTACK_TYPE cont_CHECKSTACK;
int cont_CHECKSTACKPOINTER;
CONTEXT cont_STATELASTBINDING; /* Storage to save state of trails. */
int cont_STATEBINDINGS; /* Storage to save number of current bindings. */
int cont_STATESTACK; /* Storage to save state of stack. */
int cont_STATETOPSTACK; /* Storage to save state of the top element of the stack. */
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * INITIALIZATION * */
/* * * */
/* ********************************************************** */
/**************************************************************/
void cont_Init(void)
/**********************************************************
INPUT: None.
RETURNS: None.
EFFECT: Initializes the unify module.
********************************************************/
{
cont_LASTBINDING = (CONTEXT)NULL;
cont_ResetIndexVarScanner();
cont_NOOFCONTEXTS = 0;
cont_LISTOFCONTEXTS = list_Nil();
cont_BINDINGS = 0;
cont_INSTANCECONTEXT = (CONTEXT)memory_Malloc(sizeof(CONTEXT_NODE));
cont_LEFTCONTEXT = cont_Create();
cont_RIGHTCONTEXT = cont_Create();
cont_StackInit();
cont_StackPush(0);
cont_StackPop();
}
void cont_Check(void)
/**********************************************************
INPUT: None.
RETURNS: None.
EFFECT: Frees internal structures of the unify module.
********************************************************/
{
#ifdef CHECK
if (cont_LASTBINDING || (cont_BINDINGS != 0) ||
!symbol_Equal(cont_INDEXVARSCANNER,
symbol_GetInitialIndexVarCounter())) {
misc_StartErrorReport();
misc_ErrorReport("\n In cont_Check: There are variable bindings not reset.\n");
misc_FinishErrorReport();
}
#endif
}
void cont_Free(void)
/**********************************************************
INPUT: None.
RETURNS: None.
EFFECT: Frees internal structures of the unify module.
********************************************************/
{
cont_Check();
while (cont_NOOFCONTEXTS > 0)
cont_Delete(list_Car(cont_LISTOFCONTEXTS)); /* Decreases NOOFCONTEXTS */
cont_BINDINGS = 0;
memory_Free(cont_INSTANCECONTEXT, sizeof(CONTEXT_NODE));
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * TERM EQUALITY WITH RESPECT TO BOUND VARIABLES * */
/* * * */
/* ********************************************************** */
/**************************************************************/
BOOL cont_TermEqual(CONTEXT Context1, TERM Term1, CONTEXT Context2, TERM Term2)
/*********************************************************
INPUT: Two terms and two contexts.
RETURNS: TRUE iff the two terms are equal, where
variables are interpreted with respect to
the bindings in the contexts.
********************************************************/
{
#ifdef CHECK
if (!(term_IsTerm(Term1) && term_IsTerm(Term2))) {
misc_StartErrorReport();
misc_ErrorReport("\n In cont_TermEqual: Input terms are corrupted.\n");
misc_FinishErrorReport();
}
#endif
Term1 = cont_Deref(&Context1,Term1);
Term2 = cont_Deref(&Context2,Term2);
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 (!cont_TermEqual(Context1,list_Car(Scan1), Context2,list_Car(Scan2)))
return FALSE;
return (list_Empty(Scan1) ? list_Empty(Scan2) : FALSE);
} else
return TRUE;
}
BOOL cont_TermEqualModuloBindings(CONTEXT IndexContext, CONTEXT CtL, TERM TermL,
CONTEXT CtR, TERM TermR)
/*********************************************************
INPUT: Two contexts, 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(TermL) && term_IsTerm(TermR))) {
misc_StartErrorReport();
misc_ErrorReport("\n In cont_TermEqualModuloBindings: Input terms are corrupted.\n");
misc_FinishErrorReport();
}
#endif
while (term_IsVariable(TermL)) {
SYMBOL TermTop;
TermTop = term_TopSymbol(TermL);
if (symbol_IsIndexVariable(TermTop))
CtL = IndexContext;
else if (CtL == cont_InstanceContext())
break;
if (cont_VarIsBound(CtL, TermTop)) {
CONTEXT CHelp;
CHelp = cont_ContextBindingContext(CtL, TermTop);
TermL = cont_ContextBindingTerm(CtL, TermTop);
CtL = CHelp;
} else
break;
}
while (term_IsVariable(TermR)) {
SYMBOL TermTop;
TermTop = term_TopSymbol(TermR);
if (symbol_IsIndexVariable(TermTop))
CtR = IndexContext;
else if (CtR == cont_InstanceContext())
break;
if (cont_VarIsBound(CtR, TermTop)) {
CONTEXT CHelp;
CHelp = cont_ContextBindingContext(CtR, TermTop);
TermR = cont_ContextBindingTerm(CtR, TermTop);
CtR = CHelp;
} else
break;
}
if (!term_EqualTopSymbols(TermL, TermR))
return FALSE;
else
if (term_IsVariable(TermL)) {
if (CtL == CtR)
return TRUE;
else
return FALSE;
}
else
if (term_IsComplex(TermL)) {
LIST ScanL, ScanR;
for (ScanL=term_ArgumentList(TermL), ScanR=term_ArgumentList(TermR);
list_Exist(ScanL) && list_Exist(ScanR);
ScanL=list_Cdr(ScanL), ScanR=list_Cdr(ScanR))
if (!cont_TermEqualModuloBindings(IndexContext, CtL, list_Car(ScanL),
CtR, list_Car(ScanR)))
return FALSE;
return (list_Empty(ScanL) ? list_Empty(ScanR) : FALSE);
}
else
return TRUE;
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * APPLY BINDINGS * */
/* * * */
/* ********************************************************** */
/**************************************************************/
TERM cont_CopyAndApplyBindings(CONTEXT TermContext, TERM Term)
{
while (term_IsVariable(Term)) {
SYMBOL TermTop;
TermTop = term_TopSymbol(Term);
if (cont_VarIsBound(TermContext, TermTop)) {
CONTEXT HelpContext;
HelpContext = cont_ContextBindingContext(TermContext, TermTop);
Term = cont_ContextBindingTerm(TermContext, TermTop);
TermContext = HelpContext;
} else
break;
}
if (term_IsComplex(Term)) {
LIST Scan, ArgumentList;
for (Scan = ArgumentList = list_Copy(term_ArgumentList(Term));
!list_Empty(Scan);
Scan = list_Cdr(Scan))
list_Rplaca(Scan, cont_CopyAndApplyBindings(TermContext, list_Car(Scan)));
return term_Create(term_TopSymbol(Term), ArgumentList);
} else
return term_Create(term_TopSymbol(Term), list_Nil());
}
TERM cont_CopyAndApplyBindingsCom(const CONTEXT Context, TERM Term)
{
while (term_IsVariable(Term) && cont_VarIsBound(Context, term_TopSymbol(Term)))
Term = cont_ContextBindingTerm(Context, term_TopSymbol(Term));
if (term_IsComplex(Term)) {
LIST Scan, ArgumentList;
for (Scan = ArgumentList = list_Copy(term_ArgumentList(Term));
!list_Empty(Scan);
Scan = list_Cdr(Scan))
list_Rplaca(Scan, cont_CopyAndApplyBindingsCom(Context, list_Car(Scan)));
return term_Create(term_TopSymbol(Term), ArgumentList);
} else
return term_Create(term_TopSymbol(Term), list_Nil());
}
TERM cont_ApplyBindingsModuloMatching(const CONTEXT Context, TERM Term,
BOOL VarCheck)
/**********************************************************
INPUT: A context, a term, and a boolean flag.
RETURNS: <Term> is destructively changed with respect to
established bindings in the context.
If <VarCheck> is true, all variables in <Term>
must be bound in the context. When compiled with
"CHECK" on, this condition is in fact checked.
This function only makes sense after a matching operation.
***********************************************************/
{
TERM RplacTerm;
LIST Arglist;
SYMBOL Top;
#ifdef CHECK
if (VarCheck && symbol_IsVariable(term_TopSymbol(Term)) &&
!cont_VarIsBound(Context, term_TopSymbol(Term))) {
misc_StartErrorReport();
misc_ErrorReport("\n In cont_ApplyBindingsModuloMatching:");
misc_ErrorReport(" Used in forbidden context.\n");
misc_FinishErrorReport();
}
#endif
Top = term_TopSymbol(Term);
if (symbol_IsVariable(Top)) {
if (cont_VarIsBound(Context, Top)) {
RplacTerm = cont_ContextBindingTerm(Context, Top);
Arglist = term_CopyTermList(term_ArgumentList(RplacTerm));
term_RplacTop(Term, term_TopSymbol(RplacTerm));
term_DeleteTermList(term_ArgumentList(Term));
term_RplacArgumentList(Term, Arglist);
}
}
else {
for (Arglist = term_ArgumentList(Term);
!list_Empty(Arglist);
Arglist = list_Cdr(Arglist))
cont_ApplyBindingsModuloMatching(Context, list_Car(Arglist), VarCheck);
}
return Term;
}
static TERM cont_CopyAndApplyIndexVariableBindings(const CONTEXT Context, TERM Term)
{
SYMBOL TermTop;
#ifdef CHECK
if (symbol_IsIndexVariable(term_TopSymbol(Term)) &&
!cont_VarIsBound(Context, term_TopSymbol(Term))) {
misc_StartErrorReport();
misc_ErrorReport("\n In cont_CopyAndApplyIndexVariableBindings:");
misc_ErrorReport(" Expected bound index variable.");
misc_FinishErrorReport();
}
#endif
TermTop = term_TopSymbol(Term);
while (symbol_IsIndexVariable(TermTop)) {
if (cont_VarIsBound(Context, TermTop)) {
Term = cont_ContextBindingTerm(Context, TermTop);
TermTop = term_TopSymbol(Term);
}
}
if (term_IsComplex(Term)) {
LIST Scan, ArgumentList;
for (Scan = ArgumentList = list_Copy(term_ArgumentList(Term));
!list_Empty(Scan);
Scan = list_Cdr(Scan))
list_Rplaca(Scan, cont_CopyAndApplyIndexVariableBindings(Context, list_Car(Scan)));
return term_Create(TermTop, ArgumentList);
} else
return term_Create(TermTop, list_Nil());
}
TERM cont_ApplyBindingsModuloMatchingReverse(const CONTEXT Context, TERM Term)
/**********************************************************
INPUT: A term.
RETURNS: <Term> is destructively changed with respect to
established bindings in the leftmost context. This
function only make sense after a matching operation (reverse).
***********************************************************/
{
TERM RplacTerm;
LIST Arglist;
SYMBOL Top;
#ifdef CHECK
if (symbol_IsVariable(term_TopSymbol(Term)) &&
!cont_VarIsBound(Context, term_TopSymbol(Term))) {
misc_StartErrorReport();
misc_ErrorReport("\n In cont_ApplyBindingsModuloMatchingReverse:");
misc_ErrorReport(" Used in forbidden context.\n");
misc_FinishErrorReport();
}
#endif
Top = term_TopSymbol(Term);
if (symbol_IsVariable(Top)) {
if (cont_VarIsBound(Context, Top)) {
RplacTerm =
cont_CopyAndApplyIndexVariableBindings(Context,
cont_ContextBindingTerm(Context, Top));
term_RplacTop(Term, term_TopSymbol(RplacTerm));
term_DeleteTermList(term_ArgumentList(Term));
term_RplacArgumentList(Term, term_ArgumentList(RplacTerm));
term_Free(RplacTerm);
}
}
else {
for (Arglist = term_ArgumentList(Term); !list_Empty(Arglist);
Arglist = list_Cdr(Arglist))
cont_ApplyBindingsModuloMatchingReverse(Context, list_Car(Arglist));
}
return Term;
}
BOOL cont_BindingsAreRenamingModuloMatching(const CONTEXT RenamingContext)
{
CONTEXT Context;
#ifdef CHECK
if (!cont_IsContextEmpty(RenamingContext)) {
misc_StartErrorReport();
misc_ErrorReport("\n In cont_BindingsAreRenamingModuloMatching:");
misc_ErrorReport(" Renaming context contains bindings.\n");
misc_FinishErrorReport();
}
#endif
cont_StartBinding();
Context = cont_LastBinding();
while (Context) {
if (!symbol_IsIndexVariable(cont_BindingSymbol(Context))) {
SYMBOL CodomainSymbol;
CodomainSymbol = term_TopSymbol(cont_BindingTerm(Context));
if (symbol_IsVariable(CodomainSymbol)) {
if (cont_VarIsRenamed(RenamingContext, CodomainSymbol)) {
cont_BackTrack();
return FALSE;
} else {
cont_CreateBinding(RenamingContext, CodomainSymbol, NULL, NULL);
cont_SetContextBindingRenaming(RenamingContext, CodomainSymbol, CodomainSymbol);
}
} else {
cont_BackTrack();
return FALSE;
}
}
Context = cont_BindingLink(Context);
}
cont_BackTrack();
return TRUE;
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * MISC FUNCTIONS * */
/* * * */
/* ********************************************************** */
/**************************************************************/
SYMBOL cont_TermMaxVar(CONTEXT Context, TERM Term)
/*********************************************************
INPUT: A context and a term.
RETURNS: The maximal variable in <Term> with respect to
the bindings in <Context>
********************************************************/
{
LIST scan;
SYMBOL result;
#ifdef CHECK
if (!term_IsTerm(Term)) {
misc_StartErrorReport();
misc_ErrorReport("\n In cont_TermMaxVar: Input term is corrupted.\n");
misc_FinishErrorReport();
}
#endif
Term = cont_Deref(&Context,Term);
result = symbol_Null();
if (term_IsStandardVariable(Term)) {
if (term_TopSymbol(Term) > result)
result = term_TopSymbol(Term);
} else {
for (scan = term_ArgumentList(Term); !list_Empty(scan); scan = list_Cdr(scan)) {
SYMBOL max = cont_TermMaxVar(Context, list_Car(scan));
if (max > result)
result = max;
}
}
return result;
}
NAT cont_TermSize(CONTEXT Context, TERM Term)
/*********************************************************
INPUT: A context and a term.
RETURNS: The number of symbols in <Term> with respect to
the bindings in <Context>
********************************************************/
{
NAT result;
LIST scan;
Term = cont_Deref(&Context, Term);
result = 1;
for (scan = term_ArgumentList(Term); !list_Empty(scan); scan = list_Cdr(scan))
result += cont_TermSize(Context, list_Car(scan));
return result;
}
BOOL cont_TermContainsSymbol(CONTEXT Context, TERM Term, SYMBOL Symbol)
/*********************************************************
INPUT: A context, a term and a symbol.
RETURNS: TRUE, if <Symbol> occurs in <Term> with respect to
the bindings in <Context>, FALSE otherwise.
********************************************************/
{
LIST scan;
Term = cont_Deref(&Context, Term);
if (symbol_Equal(term_TopSymbol(Term), Symbol))
return TRUE;
else
for (scan = term_ArgumentList(Term); !list_Empty(scan); scan = list_Cdr(scan)) {
if (cont_TermContainsSymbol(Context, list_Car(scan), Symbol))
return TRUE;
}
return FALSE;
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * OUTPUT * */
/* * * */
/* ********************************************************** */
/**************************************************************/
void cont_TermPrintPrefix(CONTEXT Context, TERM Term)
/**************************************************************
INPUT: A context and a term.
RETURNS: none.
SUMMARY: Prints the term modulo the context to stdout.
CAUTION: none.
***************************************************************/
{
Term = cont_Deref(&Context, Term);
symbol_Print(term_TopSymbol(Term));
if (term_IsComplex(Term)) {
LIST List;
putchar('(');
for (List = term_ArgumentList(Term); !list_Empty(List);
List = list_Cdr(List)) {
cont_TermPrintPrefix(Context, list_Car(List));
if (!list_Empty(list_Cdr(List)))
putchar(',');
}
putchar(')');
}
}