/* File:      slginsts_xsb_i.h
** Author(s): Swift, Rao, Sagonas, Freire, Cui, 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: slginsts_xsb_i.h,v 1.27 2002/11/04 18:09:03 dwarren Exp $
** 
*/


/* special debug includes */
#include "debugs/debug_delay.h"


#define ARITY	op1	/* register Cell */
#define Yn	op2	/* register Cell */
#define LABEL	op3	/* CPtr */

/*-------------------------------------------------------------------------*/

/*
 *  Organization of Tabling Choice Points:
 *
 *             +-------------+
 *             |             |   LOW MEMORY
 *             |    Trail    |
 *             |             |
 *             |      |      |
 *             |      V      |
 *             |             |
 *             |             |
 *             |      ^      |
 *             |      |      |
 *             |             |
 *             |  CP Stack   |
 *             |             |
 *             |             |
 *             |=============|
 *             | Rest of CPF |--- Different for Generator and Consumer
 *             |-------------|_
 *             |   INT: m    | \
 *             |   Term-m    |  |
 *             |      .      |  |- Answer Template
 *             |      .      |  |
 *             |      .      |  |
 *             |   Term-1    |_/
 *             |=============|
 *             |      .      |
 *             |      .      |
 *             |      .      |    HIGH MEMORY
 *             +-------------+
 *
 *
 *  Answer Templates are stored in the Heap:
 *
 *             +-------------+
 *             |      .      |   LOW MEMORY
 *             |      .      |
 *             |      .      |
 *             |-------------|_
 *             |   Term-m    | \
 *             |      .      |  |
 *             |      .      |  |- Answer Template
 *             |      .      |  |
 *             |   Term-1    |  |
 *             |   INT: m    |_/
 *             |-------------|
 *             |             |
 *             |    Heap     |
 *             |             |
 *             |      |      |
 *             |      V      |
 *             |             |
 *             |             |
 *             |      ^      |
 *             |      |      |
 *             |             |
 *             |    Local    |
 *             |             |    HIGH MEMORY
 *             +-------------+
 */

/*-------------------------------------------------------------------------*/

/*
 *  Instruction format:
 *    1st word: opcode X X pred_arity
 *    2nd word: pred_first_clause_label
 *    3rd word: preds_TableInfo_record
 */

XSB_Start_Instr_Chained(tabletry,_tabletry)
XSB_Start_Instr(tabletrysingle,_tabletrysingle) 
  DefOps13
  /*
   *  Retrieve instruction arguments and test the system stacks for
   *  overflow.  The local PCreg, "lpcreg", is incremented to point to
   *  the instruction to be executed should this one fail.
   */
  byte this_instr = *lpcreg;
  byte *continuation;
  TabledCallInfo callInfo;
  CallLookupResults lookupResults;
  VariantSF producer_sf, consumer_sf;
  CPtr answer_template;
  int template_size, attv_num, tmp;

  xwammode = 1;
  CallInfo_Arguments(callInfo) = reg + 1;
  CallInfo_CallArity(callInfo) = get_xxa; 
  LABEL = (CPtr)((byte *) get_xxxl);  
  Op1(get_xxxxl);
  CallInfo_TableInfo(callInfo) = (TIFptr) get_xxxxl;
  ADVANCE_PC(size_xxxXX);

  check_tcpstack_overflow;
  CallInfo_VarVectorLoc(callInfo) = top_of_cpstack;

  if ( this_instr == tabletry ) {
    /* lpcreg was left pointing to the next clause, e.g. tableretry */
    continuation = lpcreg;
  }
  else 
    continuation = (pb) &check_complete_inst;

  check_glstack_overflow(MAX_ARITY,lpcreg,OVERFLOW_MARGIN);

  /*
   *  Perform a call-check/insert operation on the current call.  The
   *  subterms of this call which form the answer template are
   *  computed and pushed on top of the CP stack, along with its size
   *  (encoded as a Prolog INT) .  A pointer to this size, followed by
   *  the reverse template vector (as depicted above), is returned in
   *  CallLUR_VarVector(lookupResults).  Always (now) the answer
   *  template is pushed on the Heap rather than the CPS.  In that
   *  case, (heap - 1) points to the A.T. and
   *  CallLUR_VarVector(lookupResults) has the same value as
   *  CallInfo_VarVectorLoc(callInfo).
   */

  table_call_search(&callInfo,&lookupResults);

  producer_sf = CallLUR_Subsumer(lookupResults);
  answer_template = CallLUR_VarVector(lookupResults);

  if ( IsNULL(producer_sf) ) {

    /* New Producer
       ------------ */
    CPtr producer_cpf;
    NewProducerSF(producer_sf, CallLUR_Leaf(lookupResults),
		  CallInfo_TableInfo(callInfo));
    producer_cpf = answer_template;
    save_find_locx(ereg);
    save_registers(producer_cpf, CallInfo_CallArity(callInfo), rreg);
    SaveProducerCPF(producer_cpf, continuation, producer_sf,
		    CallInfo_CallArity(callInfo), (hreg - 1));
#ifdef SLG_GC
    tcp_prevtop(producer_cpf) = answer_template; 
    /* answer_template points to the previous top, since the A.T. proper
       is now always copied to the heap */
#endif
    push_completion_frame(producer_sf);
    ptcpreg = (CPtr)producer_sf;
    subg_cp_ptr(producer_sf) = breg = producer_cpf;
    delayreg = NULL;
    if (root_address == 0)
      root_address = breg;
    hbreg = hreg;
    lpcreg = (byte *) LABEL;	/* branch to program clause */
    XSB_Next_Instr();
  }

  else if ( is_completed(producer_sf) ) {

    /* Unify Call with Answer Trie
       --------------------------- */
    if (has_answer_code(producer_sf)) {
      int i;
      xsb_dbgmsg((LOG_DELAY, "++Returning answers from COMPLETED table: "));
      dbg_print_subgoal(LOG_DELAY, stddbg, producer_sf);
      xsb_dbgmsg((LOG_DELAY, "\n"));
      answer_template = hreg - 1; 

      tmp = int_val(cell(answer_template));
      get_var_and_attv_nums(template_size, attv_num, tmp);
      num_vars_in_var_regs = -1;

      /* Initialize var_regs[] as the attvs in the call. */
      if (attv_num > 0) {
	CPtr cptr;
	for (cptr = answer_template - 1;
	     cptr >= answer_template + template_size; cptr++) {
	  if (isattv(cell(cptr)))
	    var_regs[++num_vars_in_var_regs] = (CPtr) cell(cptr);
	}
	/* now num_vars_in_var_regs should be attv_num - 1 */
      }

      reg_arrayptr = reg_array-1;
      for (i = 0; i < template_size; i++) {
	pushreg(cell(answer_template-template_size+i));
      }
      delay_it = 1;
      lpcreg = (byte *)subg_ans_root_ptr(producer_sf);
      XSB_Next_Instr();
    }
    else {
      Fail1;
      XSB_Next_Instr();
    }
  }

  else if ( CallLUR_VariantFound(lookupResults) )

    /* Previously Seen Subsumed Call
       ----------------------------- */
    consumer_sf = CallTrieLeaf_GetSF(CallLUR_Leaf(lookupResults));

  else

    /* New Properly Subsumed Call
       -------------------------- */
    NewSubConsSF( consumer_sf, CallLUR_Leaf(lookupResults),
		   CallInfo_TableInfo(callInfo), producer_sf );

  /*
   * The call, represented by "consumer_sf", will consume from an
   * incomplete producer, represented by "producer_sf".
   */
  {
    CPtr consumer_cpf;
#ifdef SLG_GC
    CPtr prev_cptop;
#endif
    ALNptr answer_continuation;
    BTNptr first_answer;

    /* Create Consumer Choice Point
       ---------------------------- */
    adjust_level(subg_compl_stack_ptr(producer_sf));
    save_find_locx(ereg);

    consumer_cpf = answer_template;
#ifdef SLG_GC
    prev_cptop = consumer_cpf;
#endif

    answer_template = hreg-1;

    efreg = ebreg;
    if (trreg > trfreg) trfreg = trreg;
    if (hfreg < hreg) hfreg = hreg;
    SaveConsumerCPF( consumer_cpf, consumer_sf,
		     subg_asf_list_ptr(producer_sf), 
		     answer_template);
#ifdef SLG_GC
    nlcp_prevtop(consumer_cpf) = prev_cptop;
#endif
    subg_asf_list_ptr(producer_sf) = breg = bfreg = consumer_cpf;

    /* Consume First Answer or Suspend
       ------------------------------- */
    table_pending_answer( subg_ans_list_ptr(consumer_sf),
			  answer_continuation,
			  first_answer,
			  (SubConsSF)consumer_sf,
			  (SubProdSF)producer_sf,
			  answer_template,
			  TPA_NoOp,
			  TPA_NoOp );

    if ( IsNonNULL(answer_continuation) ) {
      int tmp;
      nlcp_trie_return(consumer_cpf) = answer_continuation; 
      hbreg = hreg;

      tmp = int_val(cell(answer_template));
      get_var_and_attv_nums(template_size, attv_num, tmp);
      answer_template--;

      table_consume_answer(first_answer,template_size,attv_num,answer_template,
			   CallInfo_TableInfo(callInfo));

      if (is_conditional_answer(first_answer)) {
	xsb_dbgmsg((LOG_DELAY,
		"! POSITIVELY DELAYING in lay active (delayreg = %p)\n",
		delayreg));
	xsb_dbgmsg((LOG_DELAY, "\n>>>> delay_positively in lay_down_active\n"));
	xsb_dbgmsg((LOG_DELAY, ">>>> subgoal = "));
	dbg_print_subgoal(LOG_DELAY, stddbg, producer_sf);
	xsb_dbgmsg((LOG_DELAY, "\n"));
	{
	  /*
	   * Similar to delay_positively() in retry_active, we also
	   * need to put the substitution factor of the answer,
	   * var_addr[], into a term ret/n and pass it to
	   * delay_positively().
	   */
	  if (num_heap_term_vars == 0) {
	    delay_positively(producer_sf, first_answer,
			     makestring(get_ret_string()));
	  }
	  else {
#ifndef IGNORE_DELAYVAR
	    int i;
	    CPtr temp_hreg = hreg;
	    new_heap_functor(hreg, get_ret_psc(num_heap_term_vars));
	    for (i = 0; i < num_heap_term_vars; i++)
	      cell(hreg++) = (Cell) var_addr[i];
	    delay_positively(producer_sf, first_answer, makecs(temp_hreg));
#else
	    delay_positively(producer_sf, first_answer,
			     makestring(get_ret_string()));
#endif /* IGNORE_DELAYVAR */
	  }
	}
      }
      lpcreg = cpreg;
    }
    else {
      breg = nlcp_prevbreg(consumer_cpf);
      Fail1;
    }
  }
XSB_End_Instr()

/*-------------------------------------------------------------------------*/

/*
 *  Instruction format:
 *    1st word: opcode X X X
 *
 *  Description:
 *    Returns to a consumer an answer if one is available, otherwise it
 *    suspends.  Answer consumption is effected by unifying the consumer's
 *    answer template with an answer.  This instruction is encountered only
 *    by backtracking into a consumer choice point frame, either as a
 *    result of WAM- style backtracking or having been resumed via a
 *    check-complete instruction.  The CPF field "nlcp-trie-return" points
 *    to the last answer consumed.  If none have yet been consumed, then it
 *    points to the dummy answer.
 */

XSB_Start_Instr(answer_return,_answer_return) 
  VariantSF consumer_sf;
  ALNptr answer_continuation;
  BTNptr next_answer;
  CPtr answer_template;
  int template_size, attv_num;

  /* Locate relevant answers
     ----------------------- */
  answer_continuation = ALN_Next(nlcp_trie_return(breg)); /* step to next answer */
  consumer_sf = (VariantSF)nlcp_subgoal_ptr(breg);
  answer_template = nlcp_template(breg);
  table_pending_answer( nlcp_trie_return(breg),
			answer_continuation,
			next_answer,
			(SubConsSF)consumer_sf,
			conssf_producer(consumer_sf),
			answer_template,
			switch_envs(breg),
			TPA_NoOp );

  if ( IsNonNULL(answer_continuation)) {
    int tmp;

    /* Restore Consumer's state
       ------------------------ */
    switch_envs(breg);
    ptcpreg = nlcp_ptcp(breg);
    delayreg = nlcp_pdreg(breg);
    restore_some_wamregs(breg, ereg);

    /* Consume the next answer
       ----------------------- */
    nlcp_trie_return(breg) = answer_continuation;   /* update */
    tmp = int_val(cell(answer_template));
    get_var_and_attv_nums(template_size, attv_num, tmp);
    answer_template--;

    table_consume_answer(next_answer,template_size,attv_num,answer_template,
			 subg_tif_ptr(consumer_sf));

    if (is_conditional_answer(next_answer)) {
      /*
       * After load_solution_trie(), the substitution factor of the
       * answer is left in array var_addr[], and its arity is in
       * num_heap_term_vars.  We have to put it into a term ret/n (on 
       * the heap) and pass it to delay_positively().
       */
      if (num_heap_term_vars == 0) {
	delay_positively(consumer_sf, next_answer,
			 makestring(get_ret_string()));
      }
      else {
#ifndef IGNORE_DELAYVAR
	int i;
	CPtr temp_hreg = hreg;
	new_heap_functor(hreg, get_ret_psc(num_heap_term_vars));
	for (i = 0; i < num_heap_term_vars; i++) {
	  cell(hreg++) = (Cell) var_addr[i];
	}
	delay_positively(consumer_sf, next_answer, makecs(temp_hreg));
#else
	delay_positively(consumer_sf, next_answer,
			 makestring(get_ret_string()));
#endif /* IGNORE_DELAYVAR */
      }
    }
    lpcreg = cpreg;
  }

  else {

    /* Suspend this Consumer
       --------------------- */
    breg = nlcp_prevbreg(breg); /* in semi-naive this execs next active */
    restore_trail_condition_registers(breg);
    if (hbreg >= hfreg) hreg = hbreg; else hreg = hfreg;
    Fail1;
  }
XSB_End_Instr()

/*-------------------------------------------------------------------------*/

/*
 *  Instruction format:
 *    1st word: opcode X pred_arity perm_var_index
 *
 *  Description:
 *    Last instruction in each clause of a tabled predicate.  The instruction
 *    (1) saves the answer substitution in the answer trie and (2)
 *    adds a cell to the end of the answer list pointing to the root
 *    of the new subtstitution. All the
 *    information necessary to perform this Answer Check/Insert operation
 *    is saved in the producer's choice point frame.  This CP is 
 *    reached through the subgoal frame, which is noted in the first
 *    environment variable of the tabled clause.
 * 
 *    In the case where we have added an unconditional ground answer
 *    we perform early completion for the subgoal.
 *
 *    Next, if we are executing Local Evaluation, we fail after adding
 *    the answer (and perhaps performing ec)  This is not always the
 *    optimal way, as we need fail only if the subgoal is potentially
 *    a leader.
 * 
 *    If we are not executing local evaluation, we take the forward
 *    condinuation (i.e. we'll proceed).  In his case a delay element
 *    must be added to the delay list or the root subgoal of the
 *    current subgoal before proceeding.
 */

XSB_Start_Instr(new_answer_dealloc,_new_answer_dealloc) 
  Def2ops
  CPtr producer_cpf, producer_csf, answer_template;
  int template_size, attv_num, tmp;
  VariantSF producer_sf;
  xsbBool isNewAnswer = FALSE;
  BTNptr answer_leaf;

  ARITY = get_xax;
  Yn = get_xxa; /* we want the # of the register, not a pointer to it */

  ADVANCE_PC(size_xxx);
  producer_sf = (VariantSF)cell(ereg-Yn);
  producer_cpf = subg_cp_ptr(producer_sf);

#ifdef DEBUG_DELAYVAR
  xsb_dbgmsg((LOG_DEBUG,">>>> New answer for %s subgoal: ",
	     (is_completed(producer_sf) ? "completed" : "incomplete")));
  fprintf(stddbg, ">>>> ");
  dbg_print_subgoal(LOG_DEBUG, stddbg, producer_sf);
  xsb_dbgmsg((LOG_DEBUG,">>>> has delayreg = %p", delayreg));
#endif

  producer_csf = subg_compl_stack_ptr(producer_sf);

  /* if the subgoal has been early completed and its space reclaimed
   * from the stacks, access to its relevant information (e.g. to its
   * substitution factor) in the stacks is not safe, so better not
   * try to add this answer; it is a redundant one anyway...
   */
  if ((subgoal_space_has_been_reclaimed(producer_sf,producer_csf)) ||
      (IsNonNULL(delayreg) && answer_is_junk(delayreg))) {
    Fail1;
    XSB_Next_Instr();
  }

  /* answer template is now in the heap for generators */
  answer_template = tcp_template(subg_cp_ptr(producer_sf));
  tmp = int_val(cell(answer_template));
  get_var_and_attv_nums(template_size, attv_num, tmp);
  answer_template--;

#ifdef DEBUG_DELAYVAR
  xsb_dbgmsg(LOG_DEBUG,">>>> ARITY = %d; Yn = %d", (int)ARITY, (int)Yn);
#endif

  xsb_dbgmsg((LOG_DELAY, "\t--> This answer for "));
  dbg_print_subgoal(LOG_DELAY, stddbg, producer_sf);
#ifdef DEBUG_VERBOSE
  if (LOG_DELAY <= cur_log_level) {
    if (delayreg != NULL) {
      fprintf(stddbg, " has delay list = ");
      print_delay_list(stddbg, delayreg);
    } else {
      fprintf(stddbg, " has no delay list");
    }
  }
#endif

#ifdef DEBUG_DELAYVAR
  fprintf(stddbg, "\n>>>> (before variant_answer_search) template_size = %d\n",
	  (int)template_size);
  {
    int i;
    for (i = 0; i < template_size; i++) {
      fprintf(stddbg, ">>>> answer_template[%d] = ", i);
      printterm(stddbg, (Cell)(answer_template - i), 25);
      fprintf(stddbg, "\n");
    }
  }
#endif

  answer_leaf = table_answer_search( producer_sf, template_size, attv_num,
				     answer_template, &isNewAnswer );

  if ( isNewAnswer ) {   /* go ahead -- look for more answers */
    delayreg = tcp_pdreg(producer_cpf);      /* restore delayreg of parent */
    if (is_conditional_answer(answer_leaf)) {	/* positive delay */
#ifndef LOCAL_EVAL
#ifdef DEBUG_DELAYVAR
      fprintf(stddbg, ">>>> delay_positively in new_answer_dealloc\n");
#endif
      /*
       * The new answer for this call is a conditional one, so add it
       * into the delay list for its root subgoal.  Notice that
       * delayreg has already been restored to the delayreg of parent.
       *
       * This is the new version of delay_positively().  Here,
       * ans_var_pos_reg is passed from variant_answer_search().  It is a
       * pointer to the heap where the substitution factor of the
       * answer was saved as a term ret/n (in variant_answer_search()).
       */
#ifndef IGNORE_DELAYVAR
      if (isinteger(cell(ans_var_pos_reg))) {
	delay_positively(producer_sf, answer_leaf,
			 makestring(get_ret_string()));
      }
      else 
	delay_positively(producer_sf, answer_leaf, makecs(ans_var_pos_reg));
#else
	delay_positively(producer_sf, answer_leaf,
			 makestring(get_ret_string()));
#endif /* IGNORE_DELAYVAR */
#endif /* ! LOCAL_EVAL */
    }
    else {
      if (template_size == 0) {
	/*
	 *  The table is for a ground call which we just proved true.
	 *  (We entered an ESCAPE Node, above, to note this fact in the
	 *  table.)  As we only need to do this once, we perform "early
	 *  completion" by ignoring the other clauses of the predicate
	 *  and setting the failure continuation (next_clause) field of
	 *  the CPF to a check_complete instr.
	 */
	perform_early_completion(producer_sf, producer_cpf);
#if defined(LOCAL_EVAL)
	breg = producer_cpf;
#endif
      }
    }
#ifdef LOCAL_EVAL
    Fail1;	/* and do not return answer to the generator */
#else
    ptcpreg = tcp_ptcp(producer_cpf);
    cpreg = *((byte **)ereg-1);
    ereg = *(CPtr *)ereg;
    lpcreg = cpreg; 
#endif
  }
  else     /* repeat answer -- ignore */
     Fail1;
XSB_End_Instr()

/*-------------------------------------------------------------------------*/

/*
 *  Instruction format:
 *    1st word: opcode X X pred_arity
 *    2nd word: pred_next_clause_label
 *
 *  Description:
 *    Store the predicate's arity in "op1", update the failure continuation
 *    to the instruction following this one, and set the program counter to
 *    the predicate's next code subblock to be executed, as pointed to by
 *    the second argument to this instruction.  Finally, restore the state
 *    at the point of choice and continue execution using the predicate's
 *    next code subblock.
 */

XSB_Start_Instr(tableretry,_tableretry)
  Def1op
  Op1(get_xxa);
  tcp_pcreg(breg) = lpcreg+sizeof(Cell)*2;
  lpcreg = *(pb *)(lpcreg+sizeof(Cell));
  restore_type = 0;
  TABLE_RESTORE_SUB
XSB_End_Instr()

/*-------------------------------------------------------------------------*/

/*
 *  Instruction format:
 *    1st word: opcode X X pred_arity
 *
 *  Description:
 *    Store the predicate's arity in "op1", update the failure continuation
 *    to a check_complete instruction, and set the program counter to the
 *    predicate's last code subblock to be executed, as pointed to by the
 *    second argument to this instruction.  Finally, restore the state at
 *    the point of choice and continue execution with this last code
 *    subblock.
 */

XSB_Start_Instr(tabletrust,_tabletrust)
  Def1op
  Op1(get_xxa);
  ADVANCE_PC(size_xxx);
  tcp_pcreg(breg) = (byte *) &check_complete_inst;
  lpcreg = *(pb *)lpcreg;
#if defined(LOCAL_EVAL)
  /* trail cond. registers should not be restored here for Local */
  restore_type = 0;
#else
  restore_type = 1;
#endif
  TABLE_RESTORE_SUB
XSB_End_Instr()
/*-------------------------------------------------------------------------*/

#include "complete_xsb_i.h"

/*-------------------------------------------------------------------------*/

XSB_Start_Instr(resume_compl_suspension,_resume_compl_suspension)
#ifdef DEBUG_DELAYVAR
      fprintf(stddbg, ">>>> resume_compl_suspension is called\n");
#endif
{
  if ((unsigned long) csf_pcreg(breg) == 
      (unsigned long) &resume_compl_suspension_inst) {
    CPtr csf = breg;
    
    /* Switches the environment to a frame of a subgoal that was	*/
    /* suspended on completion, and sets the continuation pointer.	*/
    check_glstack_overflow(MAX_ARITY,lpcreg,OVERFLOW_MARGIN);
    freeze_and_switch_envs(csf, COMPL_SUSP_CP_SIZE);
    ptcpreg = csf_ptcp(csf);
    neg_delay = (csf_neg_loop(csf) != FALSE);
    delayreg = csf_pdreg(csf);
    cpreg = csf_cpreg(csf); 
    ereg = csf_ereg(csf);
    ebreg = csf_ebreg(csf);
    hbreg = csf_hreg(csf);
    save_find_locx(ereg);
    hbreg = hreg;
    breg = csf_prevcsf(csf);
    lpcreg = cpreg;
  } else {
    CPtr csf = cs_compsuspptr(breg);
    /* Switches the environment to a frame of a subgoal that was	*/
    /* suspended on completion, and sets the continuation pointer.	*/
    check_glstack_overflow(MAX_ARITY,lpcreg,OVERFLOW_MARGIN);
    freeze_and_switch_envs(csf, COMPL_SUSP_CP_SIZE);
    ptcpreg = csf_ptcp(csf);
    neg_delay = (csf_neg_loop(csf) != FALSE);
    delayreg = csf_pdreg(csf);
    cpreg = csf_cpreg(csf); 
    ereg = csf_ereg(csf);
    ebreg = csf_ebreg(csf);
    hbreg = csf_hreg(csf);
    save_find_locx(ereg);
    hbreg = hreg;
    if (csf_prevcsf(csf) != NULL) {
      cs_compsuspptr(breg) = csf_prevcsf(csf);
    } else {
      breg = cs_prevbreg(breg);
    }
    lpcreg = cpreg;
  }
}
XSB_End_Instr()

/*----------------------------------------------------------------------*/



syntax highlighted by Code2HTML, v. 0.9.1