/* $Id: trail.h 566 2006-11-06 17:20:50Z clerger $ * Copyright (C) 1996, 2002, 2004, 2006 Eric de la Clergerie * ------------------------------------------------------------ * * Trail -- Implementation of the layer and trail stacks * * ------------------------------------------------------------ * Description * Variable bindings are accessed through two stacks * * Layer stack for bindings in DyALog objects * * Trail stack for recent bindings created by unification * or subsumption. * * The trail stack is also used to store local and layer trail points * to undo bindings * * Parameters * LSTACK_SIZE : size of the layer stack * TRAIL_SIZE : size of the trail stack * ------------------------------------------------------------ */ #ifndef TRAIL_READ #define TRAIL_READ typedef struct layer_undo_box *layer_undo_t; typedef struct overwrite_box *overwrite_t; /********************************************************************** * Control : Environment and Backtrack **********************************************************************/ typedef struct environment_box *environment_t; typedef struct choice_box *choice_t; typedef void (*continuation_t)(); #define R_CP ((continuation_t) REG(I_CP)) #define R_E ((environment_t) REG(I_E)) #define R_B ((choice_t) REG(I_B)) #define R_BC ((choice_t) REG(I_BC)) #define R_P ((continuation_t) REG(I_P)) #define R_MIN_LAYER ((fkey_t) REG(I_MIN_LAYER)) #define LVALUE_R_CP (LVALUE_REG(I_CP)) #define LVALUE_R_E (LVALUE_REG(I_E)) #define LVALUE_R_B (LVALUE_REG(I_B)) #define LVALUE_R_BC (LVALUE_REG(I_BC)) #define LVALUE_R_P (LVALUE_REG(I_P)) #define LVALUE_R_MIN_LAYER (LVALUE_REG(I_MIN_LAYER)) /********************************************************************** * For the Common Generalizer Operation **********************************************************************/ typedef struct cgbinding_box *cgbinding_t; /********************************************************************** * For the Indexation Operations **********************************************************************/ typedef struct indexation_box *indexation_t; typedef void *SubsTree; /********************************************************************** * For Keeping Info about Variable Display **********************************************************************/ typedef struct display_box *display_t; /*********************************************************************** * For the Collect and Collapse passes ***********************************************************************/ typedef struct collect_list *collect_t; /* pointer to a list of collected variables */ typedef struct collapse_box *collapse_t; /* pointer to a collapse box */ typedef struct rename_box *rename_t; /* pointer to a rename box */ typedef struct unbind_box *unbind_t; /* pointer to an unbind box */ typedef struct binding_box *binding_t; #define FOLVAR_HI_SHIFT 5 #define FOLVAR_LO_MASK ((1 >> FOLVAR_HI_SHIFT) - 1) #define FOLVAR_HI(X) (FOLVAR_INDEX(X) >> FOLVAR_HI_SHIFT) #define FOLVAR_LO_INDEX(X) (1 << (FOLVAR_INDEX(X) & FOLVAR_LO_MASK)) #define COLLAPSE_MARK_ENTERED( _layer ) \ if (! (_layer)->collapse) \ { (_layer)->collapse = TRAIL_COLLAPSE(_layer);} #define TAG_LOCAL_EXITED 1 #define TAG_LAYER_EXITED 2 #define COLLAPSE_MARK_EXITED(_layer) \ ((_layer)->collapse->exited |= TAG_LOCAL_EXITED ) #define COLLAPSE_LOCAL_EXITED_P( _collapse ) \ ( (_collapse)->exited & TAG_LOCAL_EXITED ) #define COLLAPSE_MARK_LAYER_EXITED( _layer ) \ ((_layer)->collapse->exited |= TAG_LAYER_EXITED ) #define COLLAPSE_LAYER_EXITED_P( _collapse ) \ ( (_collapse)->exited & TAG_LAYER_EXITED ) /*********************************************************************** * Sbinding (Layer bindings) ***********************************************************************/ typedef struct sbinding { fol_t bindee; long bindee_shift; } *sbind_t; #define SBINDING_SIZE (sizeof( struct sbinding)) #define SBINDING_MAKE( _v , _k) \ ({ sbind_t sbind = (sbind_t) GC_MALLOC( SBINDING_SIZE ); \ sbind->bindee = _v; \ sbind->bindee_shift = _k; \ sbind; }) #define SBINDING_K(k,b) \ (k = ( b->bindee_shift == 1 ) \ ? (fkey_t) 0 \ : (k + (b->bindee_shift >> LSTACK_ALIGN_SHIFT))) /*********************************************************************** * Layer stack (for layer bindings) ***********************************************************************/ typedef struct layer { vca_t vca; long collect0; /* collect X_k with HI(X) == 0 */ collect_t collect_list; /* collect other X_k within a sorted list */ collapse_t collapse; /* a pointer to a collapse box in the trail stack */ } __attribute__ ((aligned (16))) *fkey_t; extern struct layer lstack[]; #define LSTACK_BASE ( (fkey_t) &lstack[0] ) #define LSTACK_INDEX( p ) ( (long) (p - LSTACK_BASE )) #define LSTACK_POINTER( i ) ( (fkey_t) (LSTACK_BASE + i)) #define LSTACK_TOP ( (fkey_t) REG(I_LAYER) ) #define LVALUE_LSTACK_TOP ( LVALUE_REG(I_LAYER) ) #define LSTACK_VCA( i ) ( lstack[i].vca ) #define KEY_TO_BINT( p ) ( BINT( LSTACK_INDEX( p )) ) #define BINT_TO_KEY( i ) ( LSTACK_POINTER( CINT( i )) ) #define LSTACK_PUSH(_top_,_layer) \ ( assert( ((fkey_t) _top_) < lstack + LSTACK_SIZE), \ ((fkey_t)_top_)->collect0 = 0, \ ((fkey_t)_top_)->collect_list = (collect_t) 0, \ ((fkey_t)_top_)->collapse = (void *) 0, \ ((fkey_t)_top_)->vca = _layer, \ _top_ = ((fkey_t) _top_) + 1 \ ) #define LSTACK_ALIGN_SHIFT 4 /* the value depends on the asked aligment on layers */ #define LSTACK_ALIGN( k ) ( (long)(k) << LSTACK_ALIGN_SHIFT ) #define LSTACK_POP( _top ) ( LVALUE_LSTACK_TOP = REG_VALUE(_top) ) #define LAYER_ONCE_DEREF( X, k ) ( vca_ref( k->vca , FOLVAR_INDEX( FOL_DEREF_VAR(X)))) /* Standard Layer Binding */ #define LAYER_REBIND( _vca, X, k, t, l) \ ({long s = FOL_GROUNDP(t) ? 1 : LSTACK_ALIGN(l-k); \ sbind_t bind = SBINDING_MAKE( t, s ); \ vca_set( _vca, FOLVAR_INDEX( X ), (entry_t) bind ); \ }) #define LAYER_UNBIND( X, k ) (vca_reset( LSTACK_VCA( k ), FOLVAR_INDEX( X ))) #define LAYER_MERGE(k , l) (LSTACK_VCA( k ) = vca_merge( LSTACK_VCA( k ), LSTACK_VCA( l ))) #define LAYER_LENGTH( k ) (VCA_SAFE_LENGTH( LSTACK_VCA( k ) )) #define LSTACK_PUSH_VOID (LSTACK_PUSH(LVALUE_LSTACK_TOP,(vca_t) 0), LSTACK_TOP - 1) /*********************************************************************** * Trail stack of local bindings (and trail points) ***********************************************************************/ typedef enum { CHOICE=0, INDEXATION, LAYER, OVERWRITE, UBIND, SBIND, CGBIND, ENVIRONMENT, COLLAPSE, UNBIND, RENAME, MASK, COLLECT, DISPLAY, FORWARD, UPWARD, HASH_SCAN, REGISTERS, BLOCK } boxtype; // typedef void * TrailWord; // typedef WamWord TrailWord; typedef union trailbox { boxtype type; /* to access directly the trailbox type */ struct layer_undo_box { boxtype type; /* type = LAYER */ fkey_t top; /* top of layer stack */ } layer_undo; struct binding_box { boxtype type; /* type = UBIND or SBIND or MASK */ fkey_t binder_key; /* search is done on this key => first position */ fol_t bindee; /* the binding */ fkey_t bindee_key; binding_t next; /* following binding for binder */ binding_t *back; /* ptr on binder's previous binding next field */ fol_t binder; /* information about the binder (could be removed) */ binding_t keep; /* next binding to keep (Collapse Pass) */ } binding; struct cgbinding_box { boxtype type; /* type = GBIND */ fol_t binder; fkey_t k_binder; fol_t left; fkey_t k_left; fol_t right; fkey_t k_right; cgbinding_t next; } cgbinding; struct collapse_box { boxtype type; /* type = COLLAPSE */ fkey_t layer; Bool exited; fkey_t block_start; unsigned long shift; /* new position after collapse */ rename_t rename_list; collapse_t next; vca_t new; /* new vca */ } collapse; struct unbind_box { boxtype type; /* type = UNBIND */ fol_t Y; /* Y_l target of at least one renaming */ fkey_t l; rename_t rename_list; /* list of X_k renamed into Y_l */ unbind_t next; } unbind; struct rename_box { boxtype type; /* type = RENAME */ fol_t X; /* => X_k renamed */ fkey_t k; rename_t next; } rename; struct indexation_box { boxtype type; /* type = INDEXATION (not yet used) */ SubsTree father; /* father of the current node in the Subst. tree */ SubsTree son; /* next node to visit in the Subst. tree */ fkey_t top; /* the top layer BEFORE load env. in the layer stack */ indexation_t back; /* link with previous index box */ } indexation; struct overwrite_box { boxtype type; /* type = OVERWRITE (not yet used) */ fkey_t key; /* The overwriten layer */ vca_t vca; /* and its previous vca value */ } overwrite; struct collect_list { boxtype type; /* type = COLLECT */ unsigned long index; unsigned long collect; collect_t next; } collect; struct environment_box { boxtype type; /* type = ENVIRONMENT */ continuation_t cp; fkey_t top; TrailWord *trail; fkey_t min_layer; environment_t prev; tabobj_t trans; fkey_t trans_key; tabobj_t item; fkey_t item_key; long n; } environment; struct choice_box { boxtype type; /* type = CHOICE */ fkey_t top; /* LSTACK_TOP copy */ TrailWord *trail; /* TRAIL top */ fkey_t min_layer; continuation_t alt; continuation_t cp; environment_t e; choice_t prev; choice_t bc; tabobj_t trans; fkey_t trans_key; tabobj_t item; fkey_t item_key; long n; } choice; struct display_box { boxtype type; /* type = DISPLAY */ fol_t var; fkey_t key; int status; /* 0=single occ var, >0 = multi * occ var */ char * name; /* varname to be displayed if non empty*/ display_t next; } display; struct registers_box { boxtype type; /* type = REGISTERS */ tabobj_t item; fkey_t k_item; fol_t item_comp; } registers; } *bind_t; extern TrailWord trail[]; #define TRAIL_BASE ( (TrailWord *) &trail[NB_REGISTERS] ) #define C_TRAIL_TOP ( (TrailWord *) REG(I_TRAIL) ) #define C_TRAIL_COLLAPSE ( (collapse_t )(trail[I_COLLAPSE] )) #define C_TRAIL_BINDING ( (binding_t )(trail[I_BINDING] )) #define C_TRAIL_UNBIND ( (unbind_t )(trail[I_UNBIND] )) #define C_TRAIL_CGBINDING ( (cgbinding_t)(trail[I_CGBINDING] ) ) #define C_TRAIL_DISPLAY ( (display_t )(trail[I_DISPLAY] )) #define LVALUE_TRAIL_BASE ( &trail[NB_REGISTERS] ) #define LVALUE_C_TRAIL_TOP ( LVALUE_REG(I_TRAIL) ) #define LVALUE_C_TRAIL_COLLAPSE ( trail[I_COLLAPSE] ) #define LVALUE_C_TRAIL_BINDING ( trail[I_BINDING] ) #define LVALUE_C_TRAIL_UNBIND ( trail[I_UNBIND] ) #define LVALUE_C_TRAIL_CGBINDING ( trail[I_CGBINDING] ) #define LVALUE_C_TRAIL_DISPLAY ( trail[I_DISPLAY] ) #define PUSH_TRAIL_BOX(_type,_box) \ _type _box = (_type) (C_TRAIL_TOP+1); \ LVALUE_C_TRAIL_TOP = REG_VALUE((TrailWord *) (_box+1)); \ *C_TRAIL_TOP = (TrailWord) _box; \ assert( C_TRAIL_TOP < trail + (TRAIL_SIZE)); #define PUSH_TRAIL_VAR_BOX(_type,_box,_n) \ _type _box = (_type) (C_TRAIL_TOP+1); \ LVALUE_C_TRAIL_TOP = REG_VALUE((TrailWord *) (_box+1) + _n); \ *C_TRAIL_TOP = (TrailWord) _box; \ assert( C_TRAIL_TOP < trail + (TRAIL_SIZE)); #define PUSH_TRAIL_BLOCK(_n) \ ({ \ TrailWord *box=C_TRAIL_TOP+1; \ *(boxtype *)box=BLOCK; \ LVALUE_C_TRAIL_TOP= REG_VALUE(box+(_n/4)+1); \ *C_TRAIL_TOP=(TrailWord)box; \ assert( C_TRAIL_TOP < trail + (TRAIL_SIZE)); \ box+1; \ }) #define POP_TRAIL_BOX(_top) \ ({ \ bind_t box = (bind_t) (*(TrailWord *)_top); \ _top=((TrailWord *) (*(TrailWord *)_top))-1; \ box; \ }) #define TRAIL_TYPE(_top) (((bind_t) (*_top))->type) /*********************************************************************** * Control stack (use boxtype as trail stack) ***********************************************************************/ extern TrailWord c_ctl[]; #define CTL_BASE ( (TrailWord *) c_ctl ) #define C_CTL_TOP ( (TrailWord *) REG(I_CTL) ) #define LVALUE_CTL_BASE ( c_ctl ) #define LVALUE_C_CTL_TOP ( LVALUE_REG(I_CTL) ) #define PUSH_CTL_VAR_BOX(_type,_box,_n) \ _type _box = (_type) (C_CTL_TOP+1); \ LVALUE_C_CTL_TOP = REG_VALUE((TrailWord *) (_box+1) + _n); \ *C_CTL_TOP = (TrailWord) _box; \ assert( C_CTL_TOP < c_ctl + (CTL_SIZE)); #define POP_CTL_BOX(_top) \ ({ \ bind_t box = (bind_t) (*_top); \ _top=((TrailWord *) (*_top))-1; \ box; \ }) /*********************************************************************** * Prototypes ***********************************************************************/ typedef enum { _fail_bind_ = 0, _local_bind_ , _layer_bind_ } bindtype; /* Dereferencing */ extern binding_t once_u_deref ( const fol_t , const fkey_t ); extern binding_t once_s_deref ( const fol_t , const fkey_t ); extern binding_t once_l_deref ( const fol_t , fkey_t ); extern binding_t once_ul_deref ( const fol_t , fkey_t ); extern binding_t closure_ul_deref( fol_t , fkey_t ); extern Bool loop_deref ( fol_t , fkey_t ); /* Trailing & Untrailing */ extern void collapse_insert( collapse_t *, collapse_t ); extern void untrail_layer(); /* Collecting & Collapsing */ extern void wrapped_collect(fol_t, fkey_t); extern obj_t collapse( fol_t, fkey_t); /* Term Operations */ extern Bool sfol_occur(fol_t, fkey_t, fol_t, fkey_t); extern Bool sfol_unify(fol_t, fkey_t, fol_t, fkey_t); extern Bool sfol_subsume(fol_t, fkey_t, fol_t, fkey_t); extern Bool sfol_alt_subsume(fol_t, fkey_t, fol_t, fkey_t); extern Bool sfol_identical(fol_t, fkey_t, fol_t, fkey_t); extern void sfol_unif_bind(fol_t, fkey_t, fol_t, fkey_t); extern unsigned long sfol_weight(fol_t, fkey_t); extern fol_t sfol_copy(fol_t, fkey_t); /********************************************************************** * LAYER entries * Materialize the start of a new environement in the layer stack * (implicitely starts also a new environement in the trail stack) **********************************************************************/ #define TSO( _pos ) ((_pos)->layer_undo) inline static void TRAIL_LAYER() { PUSH_TRAIL_BOX(layer_undo_t,box); box->type = LAYER; box->top = LSTACK_TOP; } inline static void UNTRAIL_LAYER( layer_undo_t box ) { LSTACK_POP( box->top ); } /********************************************************************** * UBIND and SBIND and MASK entries * Materialize a local unification or subsumption or mask binding * * - UBIND : Local Unification Binding * - SBIND : Local Subsumption Binding * - MASK : Mask a local binding **********************************************************************/ #define TRAIL_UBIND( X, k, t, l) \ ({ \ fol_t _x = FOL_DEREF_VAR(X); \ binding_t * _b = (binding_t *) &FOLVAR_UNIF_REF( _x ) ; \ TRAIL_BIND( UBIND, _x, k, t, l,_b); \ }) #define TRAIL_SBIND( X, k, t, l) \ ({ \ fol_t _x = FOL_DEREF_VAR(X); \ TRAIL_BIND( SBIND, _x, k, t, l, (binding_t *)&FOLVAR_SUB_REF( _x ) ) ; \ }) #define TSB( _pos ) ((_pos)->binding) inline static binding_t TRAIL_BIND( boxtype _type, fol_t X, fkey_t k, fol_t t, fkey_t l, binding_t *_b) { PUSH_TRAIL_BOX(binding_t,box); box->type= _type; box->binder=X; box->binder_key=k; box->bindee=t; box->bindee_key= (FOL_GROUNDP(t)) ? (fkey_t) 0 : l; if (k < R_MIN_LAYER) { LVALUE_R_MIN_LAYER=REG_VALUE(k); } box->keep = (binding_t) 0; for (; *_b && (*_b)->binder_key > k ; _b = &((*_b)->next) ); box->next = *_b; *_b = (binding_t) box; box->back = _b; return box; } inline static void UNTRAIL_BIND_OR_MASK(binding_t box) { *(box->back) = box->next; } /********************************************************************** * GBIND entries * Materialize a binding done when searching a common generalization **********************************************************************/ #define TSCG( _pos ) ( (_pos)->cgbinding ) inline static cgbinding_t TRAIL_CGBIND( fol_t X, fkey_t k, fol_t _left, fkey_t _k_left, fol_t _right, fkey_t _k_right ) { PUSH_TRAIL_BOX(cgbinding_t,box); box->type = CGBIND; box->binder = X; box->k_binder = k; box->left = _left; box->k_left = _k_left; box->right = _right; box->k_right = _k_right; box->next = C_TRAIL_CGBINDING; LVALUE_C_TRAIL_CGBINDING = REG_VALUE(box); return box; } inline static void UNTRAIL_CGBIND( cgbinding_t box ) { LVALUE_C_TRAIL_CGBINDING = REG_VALUE(box->next); } /********************************************************************** * COLLAPSE entries * Materialize an entered layer during the collapse pass **********************************************************************/ #define TSC( _pos ) ( (_pos)->collapse ) inline static collapse_t TRAIL_COLLAPSE( fkey_t _layer ) { PUSH_TRAIL_BOX(collapse_t,box); box->type = COLLAPSE; box->layer = _layer; box->exited = 0; box->shift = 0; box->new = (vca_t) 0; box->rename_list = (rename_t) 0; collapse_insert( (collapse_t *) &LVALUE_C_TRAIL_COLLAPSE, box ); return box; } inline static void UNTRAIL_COLLAPSE(collapse_t box) { box->layer->collect0 = 0; box->layer->collect_list = (collect_t) 0; box->layer->collapse = (collapse_t) 0; box->new = (vca_t) 0; box->layer = (fkey_t) 0; } /********************************************************************** * UNBIND entries * Materialize a variable Y_l target of a renaming during * the collapse pass **********************************************************************/ #define TSU( _pos ) ( (_pos)->unbind ) inline static void TRAIL_UNBIND(fol_t _Y, fkey_t _l, unbind_t *_next) { PUSH_TRAIL_BOX(unbind_t,box); box->type = UNBIND; box->Y = _Y; box->l = _l; box->rename_list = (rename_t) 0; box->next = *_next; *_next = box; } /********************************************************************** * RENAME entries * Materialize a renamed variable X_k during the collapse pass **********************************************************************/ #define TSR( _pos ) ( (_pos)->rename ) inline static void TRAIL_RENAME(fol_t X, fkey_t k, rename_t *from) { PUSH_TRAIL_BOX(rename_t,box); box->type = RENAME; box->X = X; box->k = k; box->next = *from; *from = box; } /********************************************************************** * INDEXATION entries (not yet used) * Materialize a binding done when searching a candidate **********************************************************************/ #define TSI( _pos ) ( (_pos)->indexation ) inline static void TRAIL_INDEXATION(SubsTree _father, SubsTree _son, indexation_t _back) { PUSH_TRAIL_BOX(indexation_t,box); box->type = INDEXATION; box->father = _father; box->son = _son; box->top = LSTACK_TOP; box->back = _back; } #define UNTRAIL_INDEXATION( _box_ ) /********************************************************************** * OVERWRITE entries (not yet used) * Materialize an overwriten layer **********************************************************************/ #define TSW( _pos ) ( (_pos)->overwrite ) inline static void TRAIL_OVERWRITE(fkey_t _key) { PUSH_TRAIL_BOX(overwrite_t,box); box->type = OVERWRITE; box->key = (_key); box->vca = (_key)->vca; } inline static void UNTRAIL_OVERWRITE(overwrite_t box) { box->key->vca = box->vca; } /********************************************************************** * COLLECT entries * Materialize a collect list **********************************************************************/ #define TSCL( _pos ) ( (_pos)->collect ) inline static collect_t TRAIL_COLLECT(unsigned long _index, unsigned long _val, collect_t _next) { PUSH_TRAIL_BOX(collect_t,box); box->type = COLLECT; box->index = _index; box->next = _next; box->collect = _val; return box; } /********************************************************************** * ENVIRONEMENT entries * Materialize a new environement (with essentialy a continuation) **********************************************************************/ /* Moved to rt.h */ /********************************************************************** * CHOICE entries * Materialize a choice point **********************************************************************/ /* Moved to rt.h */ /********************************************************************** * DISPLAY entries * Materialize a display list **********************************************************************/ #define TSDI( _pos ) ( (_pos)->display ) inline static display_t TRAIL_DISPLAY(fol_t _var, fkey_t _key) { PUSH_TRAIL_BOX(display_t,box); box->type = DISPLAY; box->var = _var; box->key = _key; box->status = 0; box->name = (char *) 0; box->next = C_TRAIL_DISPLAY; LVALUE_C_TRAIL_DISPLAY = REG_VALUE(box); if (_key < R_MIN_LAYER) { LVALUE_R_MIN_LAYER=REG_VALUE(_key); } return box; } inline static void UNTRAIL_DISPLAY(display_t box) { LVALUE_C_TRAIL_DISPLAY = REG_VALUE(box->next); } /********************************************************************** * REGISTERS entries * Save additional registers (item-related registers) **********************************************************************/ /* Moved to rt.h */ /********************************************************************** * tagging local and layer bindings **********************************************************************/ #define LAYER_MASK 1 #define TAG_LAYER_BINDING( b ) ((binding_t) (((unsigned long)b) + LAYER_MASK )) #define UNTAG_LAYER_BINDING( b ) ((sbind_t) (((unsigned long)b) - LAYER_MASK )) #define LAYER_BINDING_P( b ) (((unsigned long) b) & LAYER_MASK) /*********************************************************************** * The calls to the different dereferencers * (we must be able to modify the input variables) ***********************************************************************/ #define ASM_LOAD(X,k) \ { \ LVALUE_REG( I_DEREF_A ) = REG_VALUE(X); \ LVALUE_REG( I_DEREF_K ) = REG_VALUE(k); \ } #define ASM_UNLOAD(X,k) \ { \ X = (fol_t) REG( I_DEREF_A ); \ k = (fkey_t) REG( I_DEREF_K ); \ } #define WRAP_DEREF( __deref, X, k) \ ({ binding_t __value = (binding_t) __deref(X,k); \ if ((Bool)__value) ASM_UNLOAD(X,k); \ __value; }) #define ONCE_U_DEREF( X, k) WRAP_DEREF( once_u_deref, X, k ) #define ONCE_S_DEREF( X, k) WRAP_DEREF( once_s_deref, X, k ) #define ONCE_L_DEREF( X, k) WRAP_DEREF( once_l_deref, X, k ) #define ONCE_UL_DEREF( X, k) WRAP_DEREF( once_ul_deref, X, k ) #define CLOSURE_UL_DEREF(X,k) WRAP_DEREF( closure_ul_deref, X, k) #define LOOP_DEREF(X,k) WRAP_DEREF( loop_deref, X,k ) extern fkey_t load_layer_archive(const unsigned long, obj_t); #define Collapse_Unwrap( o, k_o, k, env ) \ ({ obj_t _k_env = collapse(o,k_o); \ k = NULLP( _k_env ) ? 0 : CINT(CAR( _k_env )); \ env = NULLP( _k_env ) ? BNIL : CDR( _k_env); \ }) #endif /* TRAIL_READ */