Branch: Tag:

2001-01-10

2001-01-10 20:00:23 by Martin Stjernholm <mast@lysator.liu.se>

Implemented labeled breaks and continues. They follow the Java approach
closely.

Rev: src/docode.c:1.90
Rev: src/language.yacc:1.221

5:   \*/   /**/   #include "global.h" - RCSID("$Id: docode.c,v 1.89 2000/12/05 21:08:17 per Exp $"); + RCSID("$Id: docode.c,v 1.90 2001/01/10 20:00:23 mast Exp $");   #include "las.h"   #include "program.h"   #include "pike_types.h"
29:      static int do_docode2(node *n, INT16 flags);    - INT32 current_break=-1; - INT32 current_continue=-1; + struct statement_label_name + { +  struct statement_label_name *next; +  struct pike_string *str; +  unsigned INT16 line_number; + };    -  + struct statement_label + { +  struct statement_label *prev; +  struct statement_label_name *name; +  INT16 emit_break_label; +  INT32 break_label, continue_label; +  unsigned catch_depth; + }; + static struct statement_label *current_label = 0; +  + static unsigned catch_depth = 0; +  + #define PUSH_STATEMENT_LABEL do { \ +  struct statement_label new_label__; \ +  new_label__.prev = current_label; \ +  if (!current_label || current_label->break_label != -2) { \ +  /* Only cover the current label if it's in use by a statement. */ \ +  new_label__.name = 0; \ +  new_label__.break_label = new_label__.continue_label = -1; \ +  new_label__.catch_depth = catch_depth; \ +  current_label = &new_label__; \ +  } \ +  do +  + #define POP_STATEMENT_LABEL \ +  while (0); \ +  current_label = new_label__.prev; \ + } while (0) +    static INT32 current_switch_case;   static INT32 current_switch_default;   static INT32 current_switch_values_on_stack;
67:      static int lbl_cache[LBLCACHESIZE];    - int do_branch(INT32 lbl) + int do_branch(INT32 lbl, int catch_escapes)   {    if(lbl==-1)    {
94:    }       } +  while (catch_escapes--) +  emit0(F_ESCAPE_CATCH);    emit1(F_BRANCH, lbl);    return lbl;   }
166:    f=!!node_is_false(n);    if(t || f)    { -  if(t == iftrue) do_branch( label); +  if(t == iftrue) do_branch( label, 0);    return;    }    }
433:    tmp3=emit1(F_POP_N_ELEMS,0);       /* Else */ -  tmp2=do_branch(-1); +  tmp2=do_branch(-1, 0);    low_insert_label( DO_NOT_WARN((INT32)tmp1));       bdroppings=do_docode(CDDR(n), flags);
668:    case F_FOR:    {    INT32 *prev_switch_jumptable = current_switch_jumptable; -  INT32 break_save = current_break; -  INT32 continue_save = current_continue; +  PUSH_STATEMENT_LABEL {       current_switch_jumptable=0; -  current_break=alloc_label(); -  current_continue=alloc_label(); +  current_label->break_label=alloc_label(); +  current_label->continue_label=alloc_label();       if(CDR(n))    { -  do_jump_when_zero(CAR(n),current_break); +  do_jump_when_zero(CAR(n),current_label->break_label);    tmp2=ins_label(-1);    DO_CODE_BLOCK(CADR(n)); -  ins_label(current_continue); +  ins_label(current_label->continue_label);    DO_CODE_BLOCK(CDDR(n));    }else{    tmp2=ins_label(-1);    }    do_jump_when_non_zero(CAR(n), DO_NOT_WARN((INT32)tmp2)); -  ins_label(current_break); +  ins_label(current_label->break_label);       current_switch_jumptable = prev_switch_jumptable; -  current_break=break_save; -  current_continue=continue_save; +  } POP_STATEMENT_LABEL;    return 0;    }   
701:    {    node *arr;    INT32 *prev_switch_jumptable = current_switch_jumptable; -  INT32 break_save = current_break; -  INT32 continue_save = current_continue; +  PUSH_STATEMENT_LABEL {       current_switch_jumptable=0; -  current_break=alloc_label(); -  current_continue=alloc_label(); +  current_label->break_label=alloc_label(); +  current_label->continue_label=alloc_label();       arr=CAR(n);   
736: Inside #if defined(PIKE_DEBUG)
   if(d_flag)    emit0(F_MARK);   #endif -  tmp3=do_branch(-1); +  tmp3=do_branch(-1, 0);    tmp1=ins_label(-1);    DO_CODE_BLOCK(CDR(n)); -  ins_label(current_continue); +  ins_label(current_label->continue_label);    low_insert_label( DO_NOT_WARN((INT32)tmp3));    do_jump(n->token, DO_NOT_WARN((INT32)tmp1)); -  ins_label(current_break); +  ins_label(current_label->break_label);      #ifdef PIKE_DEBUG    if(d_flag)
750:   #endif       current_switch_jumptable = prev_switch_jumptable; -  current_break=break_save; -  current_continue=continue_save; +  } POP_STATEMENT_LABEL;    do_pop(4);    return 0;    }
762:    case F_DEC_LOOP:    {    INT32 *prev_switch_jumptable = current_switch_jumptable; -  INT32 break_save = current_break; -  INT32 continue_save = current_continue; +  PUSH_STATEMENT_LABEL {       current_switch_jumptable=0; -  current_break=alloc_label(); -  current_continue=alloc_label(); +  current_label->break_label=alloc_label(); +  current_label->continue_label=alloc_label();       tmp2=do_docode(CAR(n),0);   #ifdef PIKE_DEBUG
778: Inside #if defined(PIKE_DEBUG)
   if(d_flag)    emit0(F_MARK);   #endif -  tmp3=do_branch(-1); +  tmp3=do_branch(-1, 0);    tmp1=ins_label(-1);       DO_CODE_BLOCK(CDR(n)); -  ins_label(current_continue); +  ins_label(current_label->continue_label);    low_insert_label( DO_NOT_WARN((INT32)tmp3));    do_jump(n->token, DO_NOT_WARN((INT32)tmp1)); -  ins_label(current_break); +  ins_label(current_label->break_label);   #ifdef PIKE_DEBUG    if(d_flag)    emit0(F_POP_MARK);   #endif       current_switch_jumptable = prev_switch_jumptable; -  current_break=break_save; -  current_continue=continue_save; +  } POP_STATEMENT_LABEL;    do_pop(3);    return 0;    }
801:    case F_DO:    {    INT32 *prev_switch_jumptable = current_switch_jumptable; -  INT32 break_save = current_break; -  INT32 continue_save = current_continue; +  PUSH_STATEMENT_LABEL {       current_switch_jumptable=0; -  current_break=alloc_label(); -  current_continue=alloc_label(); +  current_label->break_label=alloc_label(); +  current_label->continue_label=alloc_label();       tmp2=ins_label(-1);    DO_CODE_BLOCK(CAR(n)); -  ins_label(current_continue); +  ins_label(current_label->continue_label);    do_jump_when_non_zero(CDR(n), DO_NOT_WARN((INT32)tmp2)); -  ins_label(current_break); +  ins_label(current_label->break_label);       current_switch_jumptable = prev_switch_jumptable; -  current_break=break_save; -  current_continue=continue_save; +  } POP_STATEMENT_LABEL;    return 0;    }   
965:    INT32 prev_switch_case = current_switch_case;    INT32 prev_switch_default = current_switch_default;    INT32 *prev_switch_jumptable = current_switch_jumptable; -  INT32 break_save = current_break; +     struct pike_string *prev_switch_type = current_switch_type;   #ifdef PIKE_DEBUG    struct svalue *save_sp=Pike_sp;   #endif -  +  PUSH_STATEMENT_LABEL {       if(do_docode(CAR(n),0)!=1)    fatal("Internal compiler error, time to panic\n");
978:    current_switch_type = mixed_type_string;    }    -  current_break=alloc_label(); +  current_label->break_label=alloc_label();       cases=count_cases(CDR(n));   
1060:    current_switch_values_on_stack = prev_switch_values_on_stack;    current_switch_type = prev_switch_type;    -  low_insert_label( current_break); +  low_insert_label( current_label->break_label);    -  current_break=break_save; +  } POP_STATEMENT_LABEL;   #ifdef PIKE_DEBUG    if(Pike_interpreter.recoveries && Pike_sp-Pike_interpreter.evaluator_stack < Pike_interpreter.recoveries->stack_pointer)    fatal("Stack error after F_SWITCH (underflow)\n");
1166:    return 0;       case F_BREAK: -  if(current_break == -1) +  case F_CONTINUE: +  if (CAR(n)) { +  struct pike_string *name = CAR(n)->u.sval.u.string; +  struct statement_label *label; +  struct statement_label_name *lbl_name; +  for (label = current_label; label; label = label->prev) +  for (lbl_name = label->name; lbl_name; lbl_name = lbl_name->next) +  if (lbl_name->str == name) +  goto label_found; +  my_yyerror("No surrounding statement labeled '%s'.", name->str); +  return 0; +  +  label_found: +  if (n->token == F_BREAK) { +  if (label->break_label < 0) label->emit_break_label = 1; +  label->break_label = +  do_branch(label->break_label, catch_depth - label->catch_depth); +  } +  else { +  if (label->continue_label < 0) +  my_yyerror("Cannot continue the non-loop statement on line %d.", +  lbl_name->line_number); +  else +  do_branch(label->continue_label, catch_depth - label->catch_depth); +  } +  } +  +  else +  if (n->token == F_BREAK) { +  if(!current_label || current_label->break_label < 0)    {    yyerror("Break outside loop or switch.");    }else{ -  do_branch( current_break); +  do_branch( current_label->break_label, +  catch_depth - current_label->catch_depth);    } -  +  } +  else { +  struct statement_label *label; +  for (label = current_label; label; label = label->prev) +  if (label->continue_label >= 0) { +  do_branch( label->continue_label, +  catch_depth - label->catch_depth);    return 0; -  +  } +  yyerror("Continue outside loop."); +  } +  return 0;    -  case F_CONTINUE: -  if(current_continue == -1) +  case F_NORMAL_STMT_LABEL: +  case F_CUSTOM_STMT_LABEL:    { -  yyerror("continue outside loop or switch."); -  }else{ -  do_branch( current_continue); +  PUSH_STATEMENT_LABEL { +  struct statement_label *label; +  struct statement_label_name name; +  name.str = CAR(n)->u.sval.u.string; +  name.line_number = n->line_number; +  +  for (label = current_label; label; label = label->prev) { +  struct statement_label_name *lbl_name; +  for (lbl_name = label->name; lbl_name; lbl_name = lbl_name->next) +  if (lbl_name->str == name.str) { +  INT32 save_line = lex.current_line; +  lex.current_line = name.line_number; +  my_yyerror("Duplicate nested labels, previous one on line %d.", +  lbl_name->line_number); +  lex.current_line = save_line; +  break;    } -  +  } +  +  name.next = current_label->name; +  current_label->name = &name; +  +  if (!name.next) { +  current_label->emit_break_label = 0; +  if (n->token == F_CUSTOM_STMT_LABEL) +  /* The statement we precede has custom label handling; leave +  * the statement_label "open" so the statement will use it +  * instead of covering it. */ +  current_label->break_label = -2; +  else +  current_label->break_label = -1; +  } +  DO_CODE_BLOCK(CDR(n)); +  if (!name.next && current_label->emit_break_label) +  low_insert_label(current_label->break_label); +  } POP_STATEMENT_LABEL;    return 0; -  +  }       case F_RETURN:    do_docode(CAR(n),0);
1196:       case F_CATCH:    { -  /* FIXME: Pike 7.0 compatibility? */ -  INT32 break_save = current_break; -  INT32 continue_save = current_continue; +  PUSH_STATEMENT_LABEL {    INT32 *prev_switch_jumptable = current_switch_jumptable;       current_switch_jumptable=0; -  current_break=alloc_label(); -  current_continue=alloc_label(); +  current_label->break_label=alloc_label(); +  if (TEST_COMPAT(7,0)) +  current_label->continue_label=alloc_label();    -  +  catch_depth++;    tmp1=do_jump(F_CATCH,-1);    DO_CODE_BLOCK(CAR(n)); -  ins_label(current_continue); -  ins_label(current_break); +  catch_depth--; +  +  if (TEST_COMPAT(7,0)) +  ins_label(current_label->continue_label); +  ins_label(current_label->break_label);    emit0(F_THROW_ZERO);    ins_label(DO_NOT_WARN((INT32)tmp1));    -  current_break=break_save; -  current_continue=continue_save; +     current_switch_jumptable = prev_switch_jumptable; -  +  } POP_STATEMENT_LABEL;    return 1;    }