/* File: macro_xsb.h
** Author(s): Swift, Sagonas, Rao, Freire, Johnson
** Contact: xsb-contact@cs.sunysb.edu
**
** Copyright (C) The Research Foundation of SUNY, 1986, 1993-1998
**
** XSB is free software; you can redistribute it and/or modify it under the
** terms of the GNU Library General Public License as published by the Free
** Software Foundation; either version 2 of the License, or (at your option)
** any later version.
**
** XSB 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 Library General Public License for
** more details.
**
** You should have received a copy of the GNU Library General Public License
** along with XSB; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** $Id: macro_xsb.h,v 1.21 2002/10/04 20:42:01 lfcastro Exp $
**
*/
#ifndef __MACRO_XSB_H__
#define __MACRO_XSB_H__
#include "debug_xsb.h"
/*----------------------------------------------------------------------*/
/* typedef struct subgoal_frame *VariantSF; */
/*===========================================================================*/
/*
* Table Information Frame
* =======================
*
* Table Information Frames are created for each tabled predicate,
* allowing access to its calls and their associated answers.
*/
#include "table_status_defs.h"
typedef enum Tabled_Evaluation_Method {
VARIANT_TEM = VARIANT_EVAL_METHOD,
SUBSUMPTIVE_TEM = SUBSUMPTIVE_EVAL_METHOD
} TabledEvalMethod;
typedef struct Table_Info_Frame *TIFptr;
typedef struct Table_Info_Frame {
Psc psc_ptr; /* pointer to the PSC record of the subgoal */
TabledEvalMethod method; /* eval pred using variant or subsumption? */
BTNptr call_trie; /* pointer to the root of the call trie */
VariantSF subgoals; /* chain of predicate's subgoals */
TIFptr next_tif; /* pointer to next table info frame */
} TableInfoFrame;
#define TIF_PSC(pTIF) ( (pTIF)->psc_ptr )
#define TIF_EvalMethod(pTIF) ( (pTIF)->method )
#define TIF_CallTrie(pTIF) ( (pTIF)->call_trie )
#define TIF_Subgoals(pTIF) ( (pTIF)->subgoals )
#define TIF_NextTIF(pTIF) ( (pTIF)->next_tif )
#define IsVariantPredicate(pTIF) \
( TIF_EvalMethod(pTIF) == VARIANT_TEM )
#define IsSubsumptivePredicate(pTIF) \
( TIF_EvalMethod(pTIF) == SUBSUMPTIVE_TEM )
struct tif_list {
TIFptr first;
TIFptr last;
};
extern struct tif_list tif_list;
#define New_TIF(pTIF,pPSC) { \
pTIF = (TIFptr)mem_alloc(sizeof(TableInfoFrame)); \
if ( IsNULL(pTIF) ) \
xsb_abort("Ran out of memory in allocation of TableInfoFrame"); \
TIF_PSC(pTIF) = pPSC; \
TIF_EvalMethod(pTIF) = (TabledEvalMethod)flags[TABLING_METHOD]; \
TIF_CallTrie(pTIF) = NULL; \
TIF_Subgoals(pTIF) = NULL; \
TIF_NextTIF(pTIF) = NULL; \
if ( IsNonNULL(tif_list.last) ) \
TIF_NextTIF(tif_list.last) = pTIF; \
else \
tif_list.first = pTIF; \
tif_list.last = pTIF; \
}
/*===========================================================================*/
typedef struct ascc_edge *EPtr;
typedef struct completion_stack_frame *ComplStackFrame;
/*----------------------------------------------------------------------*/
/* Approximate Strongly Connected Component Edge Structure. */
/*----------------------------------------------------------------------*/
struct ascc_edge {
ComplStackFrame ascc_node_ptr;
EPtr next;
};
#define ASCC_EDGE_SIZE (sizeof(struct ascc_edge)/sizeof(CPtr))
#define edge_to_node(e) ((EPtr)(e))->ascc_node_ptr
#define next_edge(e) ((EPtr)(e))->next
/*----------------------------------------------------------------------*/
/* Completion Stack Structure (ASCC node structure). */
/* */
/* NOTE: Please make sure that fields "DG_edges" and "DGT_edges" are */
/* the last fields of the structure, and each time you modify */
/* this structure you also update the definition of the */
/* "compl_stk_frame_field" array defined in file debug.c */
/*----------------------------------------------------------------------*/
#define DELAYED -1
/*----------------------------------------------------------------------*/
struct completion_stack_frame {
VariantSF subgoal_ptr;
int level_num;
ALNptr del_ret_list; /* to reclaim deleted returns */
int visited;
#ifndef LOCAL_EVAL
EPtr DG_edges;
EPtr DGT_edges;
#endif
} ;
#define COMPLFRAMESIZE (sizeof(struct completion_stack_frame)/sizeof(CPtr))
#define compl_subgoal_ptr(b) ((ComplStackFrame)(b))->subgoal_ptr
#define compl_level(b) ((ComplStackFrame)(b))->level_num
#define compl_del_ret_list(b) ((ComplStackFrame)(b))->del_ret_list
#define compl_visited(b) ((ComplStackFrame)(b))->visited
#ifndef LOCAL_EVAL
#define compl_DG_edges(b) ((ComplStackFrame)(b))->DG_edges
#define compl_DGT_edges(b) ((ComplStackFrame)(b))->DGT_edges
#endif
#define prev_compl_frame(b) (((CPtr)(b))+COMPLFRAMESIZE)
#define next_compl_frame(b) (((CPtr)(b))-COMPLFRAMESIZE)
#define adjust_level(CS_FRAME) { \
int new_level = compl_level(CS_FRAME); \
if ( new_level < compl_level(openreg) ) { \
CPtr csf = CS_FRAME; \
while ( (compl_level(csf) >= new_level) && (csf >= openreg) ) { \
compl_level(csf) = new_level; \
csf = next_compl_frame(csf); \
} \
} \
}
/*
* The overflow test MUST be placed after the initialization of the
* ComplStackFrame in the current implementation. This is so that the
* corresponding subgoal which points to this frame can be found and its
* link can be updated if an expansion is required. This was the simplest
* solution to not leaving any dangling pointers to the old area.
*/
#define push_completion_frame_common(subgoal) \
level_num++; \
openreg -= COMPLFRAMESIZE; \
compl_subgoal_ptr(openreg) = subgoal; \
compl_level(openreg) = level_num; \
compl_del_ret_list(openreg) = NULL; \
compl_visited(openreg) = FALSE
#define push_completion_frame_batched(subgoal) \
compl_DG_edges(openreg) = compl_DGT_edges(openreg) = NULL
#ifdef LOCAL_EVAL
#define push_completion_frame(subgoal) \
push_completion_frame_common(subgoal); \
check_completion_stack_overflow
#else
#define push_completion_frame(subgoal) \
push_completion_frame_common(subgoal); \
push_completion_frame_batched(subgoal); \
check_completion_stack_overflow
#endif
#if (!defined(LOCAL_EVAL))
#define compact_completion_frame(cp_frame,cs_frame,subgoal) \
compl_subgoal_ptr(cp_frame) = subgoal; \
compl_level(cp_frame) = compl_level(cs_frame); \
compl_visited(cp_frame) = FALSE; \
compl_DG_edges(cp_frame) = compl_DGT_edges(cp_frame) = NULL; \
cp_frame = next_compl_frame(cp_frame)
#endif
/*----------------------------------------------------------------------*/
/* Subgoal (Call) Structure. */
/*----------------------------------------------------------------------*/
#include "slgdelay.h"
/*----------------------------------------------------------------------*/
enum SubgoalFrameType {
VARIANT_PRODUCER_SFT, SUBSUMPTIVE_PRODUCER_SFT, SUBSUMED_CONSUMER_SFT
};
/* Variant (Producer) Subgoal Frame
-------------------------------- */
typedef struct subgoal_frame {
byte sf_type; /* The type of subgoal frame */
byte is_complete; /* If producer, whether its answer set is complete */
byte is_reclaimed; /* Whether structs for supporting answer res from an
incomplete table have been reclaimed */
TIFptr tif_ptr; /* Table of which this call is a part */
BTNptr leaf_ptr; /* Handle for call in the CallTrie */
BTNptr ans_root_ptr; /* Root of the return trie */
ALNptr ans_list_ptr; /* Pointer to the list of returns in the ret trie */
ALNptr ans_list_tail; /* pointer to the tail of the answer list */
void *next_subgoal;
void *prev_subgoal;
CPtr cp_ptr; /* Pointer to the Generator CP */
CPtr asf_list_ptr; /* Pointer to list of (CP) active subgoal frames */
CPtr compl_stack_ptr; /* Pointer to subgoal's completion stack frame */
CPtr compl_suspens_ptr; /* SLGWAM: CP stack ptr */
PNDE nde_list; /* pointer to a list of negative DEs */
} variant_subgoal_frame;
#define subg_sf_type(b) ((VariantSF)(b))->sf_type
#define subg_is_complete(b) ((VariantSF)(b))->is_complete
#define subg_is_reclaimed(b) ((VariantSF)(b))->is_reclaimed
#define subg_prev_subgoal(b) ((VariantSF)(b))->prev_subgoal
#define subg_next_subgoal(b) ((VariantSF)(b))->next_subgoal
#define subg_tif_ptr(b) ((VariantSF)(b))->tif_ptr
#define subg_leaf_ptr(b) ((VariantSF)(b))->leaf_ptr
#define subg_ans_root_ptr(b) ((VariantSF)(b))->ans_root_ptr
#define subg_ans_list_ptr(b) ((VariantSF)(b))->ans_list_ptr
#define subg_ans_list_tail(b) ((VariantSF)(b))->ans_list_tail
#define subg_cp_ptr(b) ((VariantSF)(b))->cp_ptr
#define subg_asf_list_ptr(b) ((VariantSF)(b))->asf_list_ptr
/* use this for mark as completed == 0 */
#define subg_compl_stack_ptr(b) ((VariantSF)(b))->compl_stack_ptr
#define subg_compl_susp_ptr(b) ((VariantSF)(b))->compl_suspens_ptr
#define subg_nde_list(b) ((VariantSF)(b))->nde_list
/* Subsumptive Producer Subgoal Frame
---------------------------------- */
typedef struct SubsumedConsumerSubgoalFrame *SubConsSF;
typedef struct SubsumptiveProducerSubgoalFrame *SubProdSF;
typedef struct SubsumptiveProducerSubgoalFrame {
variant_subgoal_frame var_sf;
SubConsSF consumers; /* List of properly subsumed subgoals which
consume from a producer's answer set */
} subsumptive_producer_sf;
#define subg_consumers(SF) ((SubProdSF)(SF))->consumers
/* Subsumed Consumer Subgoal Frame
* -------------------------------
* Position of shared fields MUST correspond to that of variant_subgoal_frame.
*/
typedef struct SubsumedConsumerSubgoalFrame {
byte sf_type; /* The type of subgoal frame */
byte junk[2];
TIFptr tif_ptr; /* Table of which this call is a part */
BTNptr leaf_ptr; /* Handle for call in the CallTrie */
SubProdSF producer; /* The subgoal frame from whose answer set answers
are collected into the answer list */
ALNptr ans_list_ptr; /* Pointer to the list of returns in the ret trie */
ALNptr ans_list_tail; /* Pointer to the tail of the answer list */
TimeStamp ts; /* Time stamp to use during next answer ident */
SubConsSF consumers; /* Chain link for properly subsumed subgoals */
} subsumptive_consumer_sf;
#define conssf_producer(SF) ((SubConsSF)(SF))->producer
#define conssf_timestamp(SF) ((SubConsSF)(SF))->ts
#define conssf_consumers(SF) ((SubConsSF)(SF))->consumers
/* beginning of REAL answers in the answer list */
#define subg_answers(subg) ALN_Next(subg_ans_list_ptr(subg))
#define IsVariantSF(pSF) (subg_sf_type(pSF) == VARIANT_PRODUCER_SFT)
#define IsSubProdSF(pSF) (subg_sf_type(pSF) == SUBSUMPTIVE_PRODUCER_SFT)
#define IsSubConsSF(pSF) (subg_sf_type(pSF) == SUBSUMED_CONSUMER_SFT)
#define IsVariantProducer(pSF) IsVariantSF(pSF)
#define IsSubsumptiveProducer(pSF) IsSubProdSF(pSF)
#define IsProperlySubsumed(pSF) IsSubConsSF(pSF)
#define IsProducingSubgoal(pSF) \
( IsVariantProducer(pSF) || IsSubsumptiveProducer(pSF) )
#define ProducerSubsumesSubgoals(pSF) \
( IsSubsumptiveProducer(pSF) && IsNonNULL(subg_consumers(pSF)) )
/* Doubly-linked lists of Producer Subgoal Frames
* ----------------------------------------------
* Manipulating a doubly-linked list maintained through fields
* `prev' and `next'.
*/
#define subg_dll_add_sf(pSF,Chain,NewChain) { \
subg_prev_subgoal(pSF) = NULL; \
subg_next_subgoal(pSF) = Chain; \
if ( IsNonNULL(Chain) ) \
subg_prev_subgoal(Chain) = pSF; \
NewChain = (VariantSF)pSF; \
}
#define subg_dll_remove_sf(pSF,Chain,NewChain) { \
if ( IsNonNULL(subg_prev_subgoal(pSF)) ) { \
subg_next_subgoal(subg_prev_subgoal(pSF)) = subg_next_subgoal(pSF); \
NewChain = Chain; \
} \
else \
NewChain = (VariantSF)subg_next_subgoal(pSF); \
if ( IsNonNULL(subg_next_subgoal(pSF)) ) \
subg_prev_subgoal(subg_next_subgoal(pSF)) = subg_prev_subgoal(pSF); \
subg_prev_subgoal(pSF) = subg_next_subgoal(pSF) = NULL; \
}
extern ALNptr empty_return(void);
/* Appending to the Answer List of a SF
------------------------------------ */
#define SF_AppendNewAnswerList(pSF,pAnsList) { \
\
ALNptr pLast; \
\
pLast = pAnsList; \
while ( IsNonNULL(ALN_Next(pLast)) ) \
pLast = ALN_Next(pLast); \
SF_AppendToAnswerList(pSF,pAnsList,pLast); \
}
#define SF_AppendNewAnswer(pSF,pAns) SF_AppendToAnswerList(pSF,pAns,pAns)
#define SF_AppendToAnswerList(pSF,pHead,pTail) { \
if ( has_answers(pSF) ) \
/*
* Insert new answer at the end of the answer list.
*/ \
ALN_Next(subg_ans_list_tail(pSF)) = pHead; \
else \
/*
* The dummy answer list node is the only node currently in the list.
* It's pointed to by the head ptr, but the tail ptr is NULL.
*/ \
ALN_Next(subg_ans_list_ptr(pSF)) = pHead; \
subg_ans_list_tail(pSF) = pTail; \
}
/* Global Structure Management
--------------------------- */
#define SUBGOAL_FRAMES_PER_BLOCK 16
extern struct Structure_Manager smVarSF;
extern struct Structure_Manager smProdSF;
extern struct Structure_Manager smConsSF;
/* Subgoal Frame (De)Allocation
---------------------------- */
/*
* Allocates and initializes a subgoal frame for a producing subgoal.
* The TIP field is initialized, fields of the call trie leaf and this
* subgoal are set to point to one another, while the completion stack
* frame pointer is set to the next available location (frame) on the
* stack (but the space is not yet allocated from the stack). Also, an
* answer-list node is allocated for pointing to a dummy answer node and
* inserted into the answer list. Note that answer sets (answer tries,
* roots) are lazily created -- not until an answer is generated.
* Therefore this field may potentially be NULL, as it is initialized
* here. memset() is used so that the remaining fields are initialized
* to 0/NULL so, in some sense making this macro independent of the
* number of fields.
*/
#define NewProducerSF(SF,Leaf,TableInfo) { \
\
void *pNewSF; \
\
if ( IsVariantPredicate(TableInfo) ) { \
SM_AllocateStruct(smVarSF,pNewSF); \
pNewSF = memset(pNewSF,0,sizeof(variant_subgoal_frame)); \
subg_sf_type(pNewSF) = VARIANT_PRODUCER_SFT; \
} \
else { \
SM_AllocateStruct(smProdSF,pNewSF); \
pNewSF = memset(pNewSF,0,sizeof(subsumptive_producer_sf)); \
subg_sf_type(pNewSF) = SUBSUMPTIVE_PRODUCER_SFT; \
} \
subg_tif_ptr(pNewSF) = TableInfo; \
subg_dll_add_sf(pNewSF,TIF_Subgoals(TableInfo),TIF_Subgoals(TableInfo)); \
subg_leaf_ptr(pNewSF) = Leaf; \
CallTrieLeaf_SetSF(Leaf,pNewSF); \
subg_ans_list_ptr(pNewSF) = empty_return(); \
subg_compl_stack_ptr(pNewSF) = openreg - COMPLFRAMESIZE; \
SF = (VariantSF)pNewSF; \
}
#define FreeProducerSF(SF) { \
subg_dll_remove_sf(SF,TIF_Subgoals(subg_tif_ptr(SF)), \
TIF_Subgoals(subg_tif_ptr(SF))); \
if ( IsVariantSF(SF) ) \
SM_DeallocateStruct(smVarSF,SF) \
else \
SM_DeallocateStruct(smProdSF,SF) \
}
/*
* Allocates and initializes a subgoal frame for a consuming subgoal: a
* properly subsumed call consuming from an incomplete producer.
* Consuming subgoals are NOT inserted into the subgoal chain
* maintained by the TIF, but instead are maintained by the producer in
* a private linked list. Many fields of a consumer SF are left blank
* since it won't be used in the same way as those for producers. Its
* main purpose is to maintain the answer list and the call form. Just
* as for the producer, an answer-list node is allocated for pointing
* to a dummy answer node and inserted into the answer list.
*
* Finally, some housekeeping is needed to support lazy creation of the
* auxiliary structures in the producer's answer TST. If this is the
* first consumer for this producer, then create these auxiliary
* structures.
*/
void tstCreateTSIs(TSTNptr);
#define NewSubConsSF(SF,Leaf,TableInfo,Producer) { \
\
void *pNewSF; \
\
SM_AllocateStruct(smConsSF,pNewSF); \
pNewSF = memset(pNewSF,0,sizeof(subsumptive_consumer_sf)); \
subg_sf_type(pNewSF) = SUBSUMED_CONSUMER_SFT; \
subg_tif_ptr(pNewSF) = TableInfo; \
subg_leaf_ptr(pNewSF) = Leaf; \
CallTrieLeaf_SetSF(Leaf,pNewSF); \
conssf_producer(pNewSF) = (SubProdSF)Producer; \
if ( ! ProducerSubsumesSubgoals(Producer) ) \
tstCreateTSIs((TSTNptr)subg_ans_root_ptr(Producer)); \
subg_ans_list_ptr(pNewSF) = empty_return(); \
conssf_timestamp(pNewSF) = CONSUMER_SF_INITIAL_TS; \
conssf_consumers(pNewSF) = subg_consumers(Producer); \
subg_consumers(Producer) = (SubConsSF)pNewSF; \
SF = (VariantSF)pNewSF; \
}
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
#define set_min(a,b,c) if (b < c) a = b; else a = c
#define tab_level(SUBG_PTR) \
compl_level((subg_compl_stack_ptr(SUBG_PTR)))
#define next_tab_level(CSF_PTR) \
compl_level(prev_compl_frame(CSF_PTR))
#define is_leader(CSF_PTR) \
(next_tab_level(CSF_PTR) < compl_level(CSF_PTR))
/*----------------------------------------------------------------------*/
/* Codes for completed subgoals (assigned to subg_answers) */
/*----------------------------------------------------------------------*/
#define NO_ANSWERS (ALNptr)0
#define UNCOND_ANSWERS (ALNptr)1
#define COND_ANSWERS (ALNptr)2
/*----------------------------------------------------------------------*/
/* The following 2 macros are to be used for incomplete subgoals. */
/*----------------------------------------------------------------------*/
#define has_answers(SUBG_PTR) IsNonNULL(subg_answers(SUBG_PTR))
#define has_no_answers(SUBG_PTR) IsNULL(subg_answers(SUBG_PTR))
/*----------------------------------------------------------------------*/
/* The following 5 macros should be used only for completed subgoals. */
/*----------------------------------------------------------------------*/
/*
* These defs depend on when the root of an answer trie is created.
* Currently, this is when the first answer is added to the set. They
* are also dependent upon representation of the truth of ground goals.
* Currently, true subgoals have an ESCAPE node placed below the root,
* while false goals have no root nor leaves (since no answer was ever
* inserted, there was no opportunity to create a root).
*/
#define has_answer_code(SUBG_PTR) \
( IsNonNULL(subg_ans_root_ptr(SUBG_PTR)) && \
IsNonNULL(BTN_Child(subg_ans_root_ptr(SUBG_PTR))) )
#define subgoal_fails(SUBG_PTR) \
( ! has_answer_code(SUBG_PTR) )
/* should only be used on ground subgoals (is for escape node inspection) */
#define subgoal_unconditionally_succeeds(SUBG_PTR) \
( has_answer_code(SUBG_PTR) && \
is_unconditional_answer(BTN_Child(subg_ans_root_ptr(SUBG_PTR))) )
#define mark_subgoal_failed(SUBG_PTR) \
(subg_ans_root_ptr(SUBG_PTR) = NULL)
#define neg_simplif_possible(SUBG_PTR) \
((subgoal_fails(SUBG_PTR)) && (subg_nde_list(SUBG_PTR) != NULL))
/*----------------------------------------------------------------------*/
#define is_completed(SUBG_PTR) subg_is_complete(SUBG_PTR)
#define structs_are_reclaimed(SUBG_PTR) subg_is_reclaimed(SUBG_PTR)
#define mark_as_completed(SUBG_PTR) { \
subg_is_complete(SUBG_PTR) = TRUE; \
reclaim_del_ret_list(SUBG_PTR); \
}
#define subgoal_space_has_been_reclaimed(SUBG_PTR,CS_FRAME) \
(SUBG_PTR != compl_subgoal_ptr(CS_FRAME))
#define mark_delayed(csf1, csf2, susp) { \
compl_visited(csf1) = DELAYED; \
compl_visited(csf2) = DELAYED; \
/* do not put TRUE but some !0 value that GC can recognize as int tagged */\
csf_neg_loop(susp) = XSB_INT; \
}
/*----------------------------------------------------------------------*/
/* The following macro might be called more than once for some subgoal. */
/* So, please make sure that functions/macros that it calls are robust */
/* under repeated uses. - Kostis. */
/* A new Subgoal Frame flag prevents multiple calls. - Ernie */
/*----------------------------------------------------------------------*/
#define reclaim_incomplete_table_structs(SUBG_PTR) { \
if ( ! structs_are_reclaimed(SUBG_PTR) ) { \
table_complete_entry(SUBG_PTR); \
structs_are_reclaimed(SUBG_PTR) = TRUE; \
} \
}
/*----------------------------------------------------------------------*/
#ifdef DEMAND
#define Reset_Demand_Freeze_Registers \
bdfreg = bfreg; \
trdfreg = trfreg; \
hdfreg = hfreg; \
edfreg = efreg
#else
#define Reset_Demand_Freeze_Registers
#endif
#define reset_freeze_registers \
bfreg = (CPtr)(tcpstack.high) - CP_SIZE; \
trfreg = (CPtr *)(tcpstack.low); \
hfreg = (CPtr)(glstack.low); \
efreg = (CPtr)(glstack.high) - 1; \
level_num = xwammode = 0; \
root_address = ptcpreg = NULL; \
Reset_Demand_Freeze_Registers
#define adjust_freeze_registers(tcp) \
if (bfreg < tcp_bfreg(tcp)) { bfreg = tcp_bfreg(tcp); } \
if (trfreg > tcp_trfreg(tcp)) { trfreg = tcp_trfreg(tcp); }\
if (hfreg > tcp_hfreg(tcp)) { hfreg = tcp_hfreg(tcp); } \
if (efreg < tcp_efreg(tcp)) { efreg = tcp_efreg(tcp); }
#define reclaim_stacks(tcp) \
if (tcp == root_address) { \
reset_freeze_registers; \
/* xsb_dbgmsg("reset registers...."); */ \
} \
else { \
adjust_freeze_registers(tcp); \
/* xsb_dbgmsg(adjust registers...."); */ \
}
/*----------------------------------------------------------------------*/
#define pdlpush(cell) *(pdlreg) = cell; pdlreg--
#define pdlpop *(++pdlreg)
#define pdlempty (pdlreg == (CPtr)(pdl.high) - 1)
#define resetpdl \
if (pdlreg < (CPtr) pdl.low) \
xsb_exit("pdlreg grew too much"); \
else (pdlreg = (CPtr)(pdl.high) - 1)
#define remove_open_tables_loop(Endpoint) remove_open_tries(Endpoint)
#define remove_open_tables() remove_open_tries(COMPLSTACKBOTTOM)
/*----------------------------------------------------------------------*/
#define get_var_and_attv_nums(var_num, attv_num, tmp_int) \
var_num = tmp_int & 0xffff; \
attv_num = tmp_int >> 16
/*----------------------------------------------------------------------*/
#endif /* __MACRO_XSB_H__ */
syntax highlighted by Code2HTML, v. 0.9.1