/* l2xixstm.c  LTX2X interpreter statement executor routines    */
/*  Written by: Peter Wilson, CUA  pwilson@cme.nist.gov                */
/*  This code is partly based on algorithms presented by Ronald Mak in */
/*  "Writing Compilers & Interpreters", John Wiley & Sons, 1991        */

#include <stdio.h>
#include "l2xicmon.h"
#include "l2xierr.h"
#include "l2xiscan.h"
#include "l2xisymt.h"
#include "l2xiprse.h"
#include "l2xiidbg.h"
#include "l2xiexec.h"

/* GLOBALS */

BOOLEAN executed_return;           /* TRUE iff return statement executed */

/* EXTERNALS */

extern int level;
extern int exec_line_number;;
extern long exec_stmt_count;
 
extern ICT *code_segmentp;           /* code segment ptr */
extern ICT *statement_startp;        /* ptr to start of statement */
extern TOKEN_CODE ctoken;            /* token from code segment */

extern STACK_ITEM *stack;                  /* runtime stack */
extern STACK_ITEM_PTR tos;                 /* ptr to top of runtime stack */
extern STACK_ITEM_PTR stack_frame_basep;   /* ptr to stack fame base */

extern BOOLEAN stack_flag;

extern BOOLEAN is_value_undef();
extern STRING get_stacked_string();

/* MACROS */

/* is_undef(tp1)  TRUE iff type tp1 is undef */
#define is_undef(tp1) (tp1 == any_typep)


/***************************************************************************/
/* exec_statement()  Execute a statement by calling appropriate routine    */
/*      returns the token code of the statement                            */

TOKEN_CODE exec_statement()
{
  TOKEN_CODE stmt_tok;
  entry_debug("exec_statement (l2xixstm.c)");

  if (ctoken == STATEMENT_MARKER) {
    exec_line_number = get_statement_cmarker();
    ++exec_stmt_count;

    statement_startp = code_segmentp;
    trace_statement_execution();
    get_ctoken();
  }
  stmt_tok = ctoken;

  switch (ctoken) {
    case IDENTIFIER: {
      SYMTAB_NODE_PTR idp = get_symtab_cptr();

      if (idp->defn.key == PROC_DEFN ||
          idp->defn.key == FUNC_DEFN) exec_routine_call(idp);
      else exec_assignment_statement(idp);
      break;
    }
    case BEGIN: {
      exec_compound_statement();
      break;
    }
    case CASE: {
      exec_case_statement();
      break;
    }
    case IF: {
      exec_if_statement();
      break;
    }
    case REPEAT: {
      exec_grepeat_statement();
      break;
    }
    case SEMICOLON:
    case END:
    case ELSE:
    case UNTIL: {
      break;
    }
       /* extensions for EXPRESS and ltx2x */
    case XSKIP : {
      break;
    }
    case XESCAPE : {
      break;
    }
    case XRETURN : {
      exec_return_statement();
      exit_debug("exec_statement at XRETURN");
      return(stmt_tok);
    }
    case END_OF_STATEMENTS: {
      exit_debug("exec_statement at END_OF_STATEMENTS");
      return(stmt_tok);
    }
    case ENDCODE: {
      exit_debug("exec_statement at ENDCODE");
      return(stmt_tok);
    }
/*    case ENDCODE: {          added for ltx2x to stop execution */
/*      exit_debug("exec_statement"); 
*       return; 
*      break; 
*    }
*/
    default: {
      runtime_error(UNIMPLEMENTED_RUNTIME_FEATURE);
      break;
    }
  } /* end switch */

  while (ctoken == SEMICOLON) get_ctoken();

  exit_debug("exec_statement");
  return(stmt_tok);
}                                                   /* end exec_statement  */
/***************************************************************************/



/***************************************************************************/
/* exec_return_statement()    Execute a return statement                   */
/*    at entry, ctoken = RETURN                                            */
/*    at exit, ctoken is token after RETURN                                */

exec_return_statement()
{
  entry_debug("exec_return_statement");

  get_ctoken();
/*  if (ctoken == LPAREN) exec_expression(); */
  executed_return = TRUE;

  exit_debug("exec_return_statement");
  return;
}                                             /* end EXEC_RETURN_STATEMENT */
/***************************************************************************/



/***************************************************************************/
/* exec_assignment_statement(idp)  Execute an assignment statement         */
/*                                                                         */

exec_assignment_statement(idp)
SYMTAB_NODE_PTR idp;                /* target variable id */
{
  STACK_ITEM_PTR targetp;           /* ptr to assignment target */
  TYPE_STRUCT_PTR target_tp, base_target_tp, expr_tp;
  BOOLEAN data_area;

  entry_debug("exec_assignment_statement");
  data_area = FALSE;

  /* Assignment to function id: target is first item of appropriate stack frame */
  if (idp->defn.key == FUNC_DEFN) {
    STACK_ITEM_PTR hp;
    int delta;                     /* difference in levels */

    hp = (STACK_ITEM_PTR) stack_frame_basep;
    delta = level - idp->level - 1;
    while (delta-- > 0) {
      hp = (STACK_ITEM_PTR) get_static_link((ADDRESS) hp);
    }
    targetp = (STACK_ITEM_PTR) hp;
    target_tp = idp->typep;
    get_ctoken();
  }

  /* Assignment to variable: Routine exec_variable leaves target address */
  /*                         on top of stack */
  else {
    if ((idp->typep->form == ARRAY_FORM) || (idp->typep->form == ENTITY_FORM)) {
      data_area = TRUE;
      debug_print("data_area is TRUE\n");
    }
    target_tp = exec_variable(idp, TARGET_USE);
    targetp = (STACK_ITEM_PTR) get_address(tos);

    pop();         /* pop off the target address */
  }

  base_target_tp = base_type(target_tp);

  /* Routine exec-expression leaves expression value on top of stack */
  get_ctoken();
  expr_tp = exec_expression();
  
  if (stack_flag) {
    log_print("Assignment LHS: ");
    expression_type_debug(target_tp);
    log_print("Assignment RHS: ");
    expression_type_debug(expr_tp);
  }
  

  /* do the assignment */

  exec_the_assign(targetp, target_tp, expr_tp);

  trace_data_store(idp, idp->typep, targetp, target_tp);

  exit_debug("exec_assignment_statement");
  return;
}                                         /* end exec_assignment_statement */
/***************************************************************************/



/***************************************************************************/
/* exec_the_assign(targetp, target_tp, expr_tp)  Do the actual assignment  */
/*             targetp, target_tp are the target and its type;             */
/*             expr_tp is the RHS type with its value on top of the stack. */
/*     The current token is unchanged                                      */

exec_the_assign(targetp, target_tp, expr_tp)
STACK_ITEM_PTR targetp;                 /* ptr to LHS */
TYPE_STRUCT_PTR target_tp;              /* ptr to type of LHS */
TYPE_STRUCT_PTR expr_tp;                /* ptr to type of RHS */
{
  TYPE_STRUCT_PTR base_target_tp;      /* ptr to LHS base type */
  STACK_TYPE rhstype;                  /* type on top of the stack */
  int size;
  entry_debug("exec_the_assign");

  if (is_undef(expr_tp) || is_value_undef(tos)) {
    put_undef(targetp);
    pop();
    exit_debug("exec_the_assign at undef");
    return;
  }

  rhstype = get_stackval_type(tos);
  if (expr_tp->form == ARRAY_FORM) {    /* then RHS is an array (element?) */
    if (rhstype == STKADD) {
      copy_value(tos, get_address(tos));
    }
  }

  base_target_tp = base_type(target_tp);

  if ((target_tp == real_typep) && (base_type(expr_tp) == integer_typep)) {
    /* real := integer */
    put_real(targetp, (XPRSAREAL) get_integer(tos));
  }

  else if (target_tp == logical_typep) {
      /* logical := logical */
    put_logical(targetp, get_logical(tos));
  }

  else if (target_tp->form == STRING_FORM && expr_tp->form == STRING_FORM) {
       /* string := string */
     exec_string_assign((STACK_ITEM_PTR) targetp);
  }

  else if (target_tp->form == ARRAY_FORM) {
    if (base_type(expr_tp) == target_tp->info.array.elmt_typep) { /* array := el */
      copy_value(targetp, tos);
    }
    else {             /* assume array := array */
      ICT *ptr1 = (ICT *) targetp;
      ICT *ptr2 = get_address(tos);
      size = target_tp->size;
      while (size--) *ptr1++ = *ptr2++;
    }
  }

  else if (target_tp->form == ENTITY_FORM ) {
    /* entity := entity */
    ICT *ptr1 = (ICT *) targetp;
    ICT *ptr2 = get_address(tos);
    size = target_tp->size;
    while (size--) *ptr1++ = *ptr2++;
  }
  else if ((base_target_tp == integer_typep) ||
           (target_tp->form == ENUM_FORM)) {
    /* Range check assignment to integer or enumeration subrange */
    if ((target_tp->form == SUBRANGE_FORM) &&
        ((get_integer(tos) < target_tp->info.subrange.min) ||
         (get_integer(tos) > target_tp->info.subrange.max))) {
      runtime_error(VALUE_OUT_OF_RANGE);
    }

    /* integer := integer */
    /* enumeration := enumeration */
    put_integer(targetp, get_integer(tos));
  }

  else {
    /* real := real */
    put_real(targetp, get_real(tos));
  }

  pop();    /* pop expression value */

  exit_debug("exec_the_assign");
  return;
}                                                   /* end EXEC_THE_ASSIGN */
/***************************************************************************/



/***************************************************************************/
/* exec_string_assign    Execute string := string                          */
/*                                                                         */

exec_string_assign(targetp)
STACK_ITEM_PTR targetp;             /* the LHS */
{
  STRING rhs;                        /* the RHS */
  STRING lhs;
  int num;
  int maxchrs;
  entry_debug("exec_string_assign");

  rhs = get_stacked_string(tos);    /* top of stack points to the string */
  free(targetp->value.string);
  num = strlen(rhs);
  sprintf(dbuffer, "strlen(str) = %d, str = %s\n", num, rhs);
  debug_print(dbuffer);
  lhs = alloc_bytes(num+1);
  sprintf(dbuffer, "lhs = %d", lhs);
  debug_print(dbuffer);
  strcpy(lhs, rhs);
  sprintf(dbuffer, ", str = %s\n", lhs);
  debug_print(dbuffer);
  
  put_string(targetp, lhs);
/*  set_string(targetp, rhs); */

  exit_debug("exec_string_assign");
  return;
}                                                /* end EXEC_STRING_ASSIGN */
/***************************************************************************/



/***************************************************************************/
/* set_string(var_idp, str)    Attaches string str to variable             */

set_string(var_idp, str)
SYMTAB_NODE_PTR var_idp;           /* variable in the symbol table */
STRING str;                        /* the string */
{
  int num;
  int maxchrs = 527;
  TYPE_STRUCT_PTR strtyp;
  entry_debug("set_string (l2xixstm.c)");

  sprintf(dbuffer, "var_idp = %d\n", var_idp);
  debug_print(dbuffer);
  num = strlen(str);
  sprintf(dbuffer, "num = strlen(str) = %d\n", num);
  debug_print(dbuffer);
  debug_print(str);
  strtyp = var_idp->typep;
/*  maxchrs = var_idp->typep->info.string.max_length; */
/*  maxchrs = strtyp->info.string.max_length; */
  sprintf(dbuffer, "\nmaxchrs = %d\n", maxchrs);
  debug_print(dbuffer);
  if (num > maxchrs) {
    runtime_error(RUNTIME_STRING_TOO_LONG);
    free(var_idp->info);
    var_idp->info = alloc_bytes(maxchrs + 1);
    strncpy(var_idp->info, str, maxchrs);
    var_idp->info[maxchrs] = '\0';
    strtyp->info.string.length = maxchrs;
  }
  else {
/*    free(var_idp->info); */
    var_idp->info = alloc_bytes(num+1);
    strcpy(var_idp->info, str);
/*    strtyp->info.string.length = num; */
  }

  exit_debug("set_string");
}                                                        /* end SET_STRING */
/***************************************************************************/



/***************************************************************************/
/* exec_routine_call(rtn_idp)  Execute procedure or function call.         */
/* return pointer to the type structure                                    */

TYPE_STRUCT_PTR exec_routine_call(rtn_idp)
SYMTAB_NODE_PTR rtn_idp;                     /* routine id */
{
  TYPE_STRUCT_PTR exec_declared_routine_call();
  TYPE_STRUCT_PTR exec_standard_routine_call();
  entry_debug("exec_routine_call");

  if (rtn_idp->defn.info.routine.key == DECLARED) {
    exit_debug("exec_routine_call");
    return(exec_declared_routine_call(rtn_idp));
  }
  else {
    exit_debug("exec_routine_call");
    return(exec_standard_routine_call(rtn_idp));
  }

}                                                /* end exec_routine_call  */
/***************************************************************************/



/***************************************************************************/
/* exec_declared_routine_call(rtn_idp)  Execute a call to a declared       */
/*                                      function or procedure              */
/* return pointer to the type structure                                    */

TYPE_STRUCT_PTR exec_declared_routine_call(rtn_idp)
SYMTAB_NODE_PTR rtn_idp;                     /* routine id */
{
  int old_level = level;                        /* level of caller */
  int new_level = rtn_idp->level + 1;           /* level of callee */
  STACK_ITEM_PTR new_stack_frame_basep;
  STACK_ITEM_PTR hp;                   /* ptr to frame header */
  entry_debug("exec_declared_routine_call");

  /* set up stack frame of callee */
  new_stack_frame_basep = tos + 1;
  push_stack_frame_header(old_level, new_level);

  /* push parameter values onto the stack */
  get_ctoken();
  if (ctoken == LPAREN) {
    exec_actual_parms(rtn_idp);
    get_ctoken();   /* the token after the RPAREN */
  }

  /* set the return address in the new stack frame, and execute callee */
  level = new_level;
  stack_frame_basep = new_stack_frame_basep;
  hp = stack_frame_basep;
/*  put_address(hp->return_address, (code_segmentp - 1)); */
  put_return_address(hp, (code_segmentp - 1));
/*  execute(rtn_idp);      changed this call for EXPRESS */
  exec_algorithm(rtn_idp);

  /* return from callee */
  level = old_level;
  get_ctoken();    /* first token after return */

  exit_debug("exec_declared_routine_call");
  return(rtn_idp->defn.key == PROC_DEFN ? NULL : rtn_idp->typep);

}                                       /* end exec_declared_routine_call  */
/***************************************************************************/



/***************************************************************************/
/* exec_actual_parms(rtn_idp)  Push the values of the actual parameters    */
/*                             onto the stack                              */

exec_actual_parms(rtn_idp)
SYMTAB_NODE_PTR rtn_idp;           /* id of callee routine */
{
  SYMTAB_NODE_PTR formal_idp;           /* formal param id */
  TYPE_STRUCT_PTR formal_tp, actual_tp;
  entry_debug("exec_actual_parms");
  
  /* loop to execute actual params */
  for (formal_idp = rtn_idp->defn.info.routine.parms;
       formal_idp != NULL;
       formal_idp = formal_idp->next) {
    formal_tp = formal_idp->typep;
    get_ctoken();

    /* value parameter */
    if (formal_idp->defn.key == VALPARM_DEFN) {
      actual_tp = exec_expression();

      /* Range check for a subrange formal param */
      if (formal_tp->form == SUBRANGE_FORM) {
        TYPE_STRUCT_PTR base_formal_tp = base_type(formal_tp);
        XPRSAINT value;

        value = get_integer(tos);
        if ((value < formal_tp->info.subrange.min) ||
            (value > formal_tp->info.subrange.max)) {
          runtime_error(VALUE_OUT_OF_RANGE);
        }
      }
     
      else if ((formal_tp == real_typep) &&
               (base_type(actual_tp) == integer_typep)) {
        /* real formal := integer actual */
        put_real(tos, (XPRSAREAL) get_integer(tos));
      }
      
     if ((formal_tp->form == ARRAY_FORM) ||
         (formal_tp->form == ENTITY_FORM)) {
       /* formal param is array or entity. Make a copy */
        int size = formal_tp->size;
        ICT *ptr1 = alloc_array(ICT, size);
        ICT *ptr2 = get_address(tos);      /* ??????????????????? */
        ICT *save_ptr = ptr1;

        while (size--) *ptr1++ = *ptr2++;
        put_address(tos, save_ptr);
      }
    } /* end value param */

    /* a VAR parameter */
    else {
      SYMTAB_NODE_PTR idp = get_symtab_cptr();
      exec_variable(idp, VARPARM_USE);
    }

  } /* end for loop */

  exit_debug("exec_actual_parms");
}                                                /* end exec_actual_parms  */
/***************************************************************************/



/***************************************************************************/
/* exec_compound_statement()  Execute a compound statement                 */
/*                                                                         */

exec_compound_statement()
{
  entry_debug("exec_compound_statement");

  get_ctoken();
  while (ctoken != END) exec_statement();
  get_ctoken();

  exit_debug("exec_compound_statement");
  return;
}                                          /* end exec_compound_statement  */
/***************************************************************************/



/***************************************************************************/
/* exec_case_statement()  Execute a CASE statement                         */
/*                        CASE <expr> OF                                   */
/*                           <case-branch>                                 */
/*                        END                                              */

exec_case_statement()
{
  XPRSAINT case_expr_value;                 /* CASE expr value */
  XPRSAINT case_label_count;                /* CASE label count */
  XPRSAINT case_label_value;                /* CASE label value */
  ADDRESS branch_table_location;       /* branch table address */
  ADDRESS case_branch_location;        /* CASE branch address */
  TYPE_STRUCT_PTR case_expr_tp;        /* CASE expr type */
  BOOLEAN done = FALSE;
  BOOLEAN found_otherwise = FALSE;
  ADDRESS otherwise_location;
  entry_debug("exec_case_statement");

  get_ctoken();               /* token after CASE */
  branch_table_location = get_address_cmarker();

  /* evaluate the CASE expr */
  get_ctoken();
  case_expr_tp = exec_expression();
  case_expr_value = get_integer(tos);
  pop();         /* expression value */

  /* search the branch table for the expr value */
  code_segmentp = branch_table_location;
  get_ctoken();
  case_label_count = get_cinteger();
  while (!done && case_label_count--) {
    case_label_value = get_cinteger();
    case_branch_location = get_caddress();
    done = case_label_value == case_expr_value;
    if (case_label_value == XOTHERWISE) {
      found_otherwise = TRUE;
      otherwise_location = case_branch_location;
    }
  }

  /* if found, goto the appropriate CASE branch */
  if (case_label_count >= 0) {
    code_segmentp = case_branch_location;
    get_ctoken();
    exec_statement(); 
    

    code_segmentp = get_address_cmarker();
    get_ctoken();
  }
  else if (found_otherwise) {
    code_segmentp = otherwise_location;
    get_ctoken();
    exec_statement();

    code_segmentp = get_address_cmarker();
    get_ctoken();
  }
  else {
    runtime_error(INVALID_CASE_VALUE);
  }

  exit_debug("exec_case_statement");
  return;
}                                               /* end exec_case_statement */
/***************************************************************************/





/***************************************************************************/
/* exec_if_statement()  Execute an IF statement                            */
/*                      IF <expr> THEN <stmt> END_IF                       */
/*               or                                                        */
/*                      IF <expr> THEN <stmt> ELSE <stmt> END_IF           */

exec_if_statement()
{
  ADDRESS false_location;               /* address of false branch */
  BOOLEAN test;
  entry_debug("exec_if_statement");

  get_ctoken();               /* token after if */
  false_location = get_address_cmarker();

  /* evaluate the boolean expression */
  get_ctoken();
  exec_expression();
  test = get_logical(tos) == TRUE_REP;
  pop();                     /* boolean value */

  if (test) {    /* do the TRUE branch */
    get_ctoken();        /* token after THEN */
    while (ctoken != ELSE && ctoken != XEND_IF) exec_statement();
      if (ctoken == ELSE) {
        get_ctoken();
        code_segmentp = get_address_cmarker();
        get_ctoken();       /* token after false stmt */
    }
  }
  else {           /* do the ELSE branch if there is one */
    code_segmentp = false_location;
    get_ctoken();

    if (ctoken == ELSE ) {
      get_ctoken();
      get_address_cmarker();      /* skip the address marker */

      get_ctoken();
      while(ctoken != XEND_IF) exec_statement();
    }
  }
  get_ctoken(); /* after the END_IF */


  exit_debug("exec_if_statement");
  return;
}                                                 /* end exec_if_statement */
/***************************************************************************/



/***************************************************************************/
/* exec_grepeat_statement()  Execute an EXPRESS REPEAT statement           */
/*    REPEAT [ <inc_control> ] <while_control> <until_control>             */
/*           <stmt-list> END_REPEAT;                                       */
/*  at entry: ctoken is REPEAT                                             */
/*  at exit:  ctoken is after END_REPEAT;                                  */

exec_grepeat_statement()
{
  SYMTAB_NODE_PTR control_idp;            /* control var id */
  TYPE_STRUCT_PTR control_tp;             /* control var type */
  STACK_ITEM_PTR targetp;                 /* ptr to control target */
  ADDRESS loop_start_location;            /* address of start of loop */
  ADDRESS loop_end_location;              /* address of end of loop */
  ADDRESS until_start_location;
  ADDRESS to_start_location;
  ADDRESS while_start_location;
  ADDRESS statements_start_location;
  BOOLEAN loop_done = FALSE;
  BOOLEAN is_increment_control = FALSE;   /* TRUE iff there is an inc. control */
  int control_value;                      /* value of control var */
  int initial_value, final_value, delta_value;
  TOKEN_CODE stmt_tok;
  entry_debug("exec_grepeat_statement (l2xixstm.c)");

  /* the first time through */
  get_ctoken();                   /* code (address marker) token after REPEAT */
  loop_end_location = get_address_cmarker();
    sprintf(dbuffer, "loop_end_location = %d\n", loop_end_location);
    debug_print(dbuffer);
  get_ctoken();                   /* source token after REPEAT */

  if (ctoken == FOR) {            /* increment control */
    is_increment_control = TRUE;
    get_ctoken();                 /* IDENTIFIER for the variable */
     /* get address of control var's stack item */
    control_idp = get_symtab_cptr();
    control_tp = exec_variable(control_idp, TARGET_USE);
    targetp = (STACK_ITEM_PTR) get_address(tos);
    pop();                             /* pop control var's address */

    /* evaluate the initial expression */
    get_ctoken();
    exec_expression();
    initial_value = get_integer(tos);
    pop();                /* initial value */
    put_integer(targetp, initial_value);
    control_value = initial_value;

    /* evaluate the final expression */
    get_ctoken();                        
    to_start_location = code_segmentp -1;
      sprintf(dbuffer, "to_start_location = %d\n", to_start_location);
      debug_print(dbuffer);
    exec_expression();
    final_value = get_integer(tos);
    pop();                /* final value */

    /* get the increment */
    get_ctoken();
    exec_expression();
    delta_value = get_integer(tos);
    pop();                /* delta value */
      /* check the bound */
      if ((delta_value >= 0 && control_value > final_value) ||
          (delta_value < 0  && control_value < final_value)) {
        code_segmentp = loop_end_location;
        get_ctoken();
        loop_done = TRUE;
      }
      if (loop_done) {
        exit_debug("exec_grepeat_statement");
        return;
      }
  }
  
  /* check the WHILE condition */
  get_ctoken();                
  while_start_location = code_segmentp -1;   
      sprintf(dbuffer, "while_start_location = %d\n", while_start_location);
      debug_print(dbuffer);
  exec_expression();
  if (get_logical(tos) == FALSE_REP) {    /* finished */
    code_segmentp = loop_end_location;
    get_ctoken();
    loop_done = TRUE;
  }
  pop();                             /* the WHILE value */
  if (loop_done) {
    exit_debug("exec_grepeat_statement");
    return;
  }

  /* skip the UNTIL condition */
  get_ctoken();
  until_start_location = code_segmentp -1;
      sprintf(dbuffer, "until_start_location = %d\n", until_start_location);
      debug_print(dbuffer);
  while (ctoken != STATEMENT_MARKER) get_ctoken();
  statements_start_location = code_segmentp -1;
      sprintf(dbuffer, "statements_start_location = %d\n", statements_start_location);
      debug_print(dbuffer);

  /* do the statements */
  do {
    stmt_tok = exec_statement();
    if (stmt_tok == XSKIP) {
      code_segmentp = until_start_location;
      break;
    }
    else if (stmt_tok == XESCAPE) {
      code_segmentp = loop_end_location;
      get_ctoken();
      loop_done = TRUE;
      pop();
      exit_debug("exec_grepeat_statement");
      return;
    }
  }  while (ctoken != XEND_REPEAT);

  /* This finishes the first pass, do subsequent passes */
  do {
    /* check the UNTIL expression */
    code_segmentp = until_start_location;
    get_ctoken();
    exec_expression();
    if (get_logical(tos) == TRUE_REP) {    /* finished */
      code_segmentp = loop_end_location;
      get_ctoken();
      loop_done = TRUE;
    }
    pop();                                 /* the UNTIL value */
    if (loop_done) {
      exit_debug("exec_grepeat_statement");
      return;
    }

    /* increment control now */
    if (is_increment_control) {
      /* perform the increment */
      control_value = get_integer(targetp) + delta_value;
      put_integer(targetp, control_value);
      /* do the check */
      code_segmentp = to_start_location;
      get_ctoken();
      exec_expression();
      get_integer(tos);
      if ((delta_value >= 0 && control_value > final_value) ||
          (delta_value < 0  && control_value < final_value)) {
        code_segmentp = loop_end_location;
        get_ctoken();
        loop_done = TRUE;
      }
      pop();                     /* the to value */
      if (loop_done) {
        exit_debug("exec_grepeat_statement");
        return;
      }
    }
     
      /* check the WHILE */
    code_segmentp = while_start_location;
    get_ctoken();
    exec_expression();
    if (get_logical(tos) == FALSE_REP) {
      code_segmentp = loop_end_location;
      get_ctoken();
      loop_done = TRUE;
    }
    pop();                                 /* the WHILE value */
    if (loop_done) {
      exit_debug("exec_grepeat_statement");
      return;
    }

    /* and now back to executing the statements */
    code_segmentp = statements_start_location;
    get_ctoken(); 
    do {
      exec_statement();
    } while (ctoken != XEND_REPEAT);
    /* start again checking the UNTIL condition */
    code_segmentp = until_start_location;
  }   while(TRUE);


  exit_debug("exec_grepeat_statement");
  return;

}                                            /* end EXEC_GREPEAT_STATEMENT */
/***************************************************************************/