+ code_t*out = $$ = abc_nop($$);
+ breakjumpsto($$, $1, out);
+ continuejumpsto($$, $1, cont);
+
+ $$ = var_block($$);
+ PASS12 old_state();
+}
+
+DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
+ $$ = code_new();
+ code_t*loopstart = $$ = abc_label($$);
+ $$ = code_append($$, $3);
+ code_t*cont = $$ = abc_nop($$);
+ $$ = code_append($$, $6.c);
+ $$ = abc_iftrue($$, loopstart);
+ code_t*out = $$ = abc_nop($$);
+ breakjumpsto($$, $1, out);
+ continuejumpsto($$, $1, cont);
+
+ $$ = var_block($$);
+ PASS12 old_state();
+}
+
+BREAK : "break" %prec prec_none {
+ $$ = abc___break__(0, "");
+}
+BREAK : "break" T_IDENTIFIER {
+ $$ = abc___break__(0, $2);
+}
+CONTINUE : "continue" %prec prec_none {
+ $$ = abc___continue__(0, "");
+}
+CONTINUE : "continue" T_IDENTIFIER {
+ $$ = abc___continue__(0, $2);
+}
+
+MAYBE_CASE_LIST : {$$=0;}
+MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
+MAYBE_CASE_LIST : DEFAULT {$$=$1;}
+MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
+CASE_LIST: CASE {$$=$1;}
+CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
+
+CASE: "case" E ':' MAYBECODE {
+ $$ = abc_dup(0);
+ $$ = code_append($$, $2.c);
+ code_t*j = $$ = abc_ifne($$, 0);
+ $$ = code_append($$, $4);
+ if($$->opcode != OPCODE___BREAK__) {
+ $$ = abc___fallthrough__($$, "");
+ }
+ code_t*e = $$ = abc_nop($$);
+ j->branch = e;
+}
+DEFAULT: "default" ':' MAYBECODE {
+ $$ = $3;
+}
+SWITCH : T_SWITCH '(' {PASS12 new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
+ $$=$4.c;
+ $$ = code_append($$, $7);
+ code_t*out = $$ = abc_pop($$);
+ breakjumpsto($$, $1, out);
+
+ code_t*c = $$,*lastblock=0;
+ while(c) {
+ if(c->opcode == OPCODE_IFNE) {
+ if(!c->next) syntaxerror("internal error in fallthrough handling");
+ lastblock=c->next;
+ } else if(c->opcode == OPCODE___FALLTHROUGH__) {
+ if(lastblock) {
+ c->opcode = OPCODE_JUMP;
+ c->branch = lastblock;
+ } else {
+ /* fall through end of switch */
+ c->opcode = OPCODE_NOP;
+ }
+ }
+ c=c->prev;
+ }
+
+ $$ = var_block($$);
+ PASS12 old_state();
+}
+
+/* ------------ try / catch /finally ---------------- */
+
+CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();state->exception_name=$3;new_variable($3, $4, 0);}
+ '{' MAYBECODE '}' {
+ namespace_t name_ns = {ACCESS_PACKAGE, ""};
+ multiname_t name = {QNAME, &name_ns, 0, $3};
+
+ NEW(abc_exception_t, e)
+ e->exc_type = sig2mname($4);
+ e->var_name = multiname_clone(&name);
+ $$ = e;
+
+ code_t*c = 0;
+ int i = find_variable_safe(state, $3)->index;
+ e->target = c = abc_nop(0);
+ c = abc_setlocal(c, i);
+ c = code_append(c, $8);
+ c = abc_kill(c, i);
+
+ c = var_block(c);
+ PASS12 old_state();
+}
+FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
+ $4 = var_block($4);
+ if(!$4) {
+ $$=0;
+ } else {
+ NEW(abc_exception_t, e)
+ e->exc_type = 0; //all exceptions
+ e->var_name = 0; //no name
+ e->target = 0;
+ e->to = abc_nop(0);
+ e->to = code_append(e->to, $4);
+ $$ = e;
+ }
+ PASS12 old_state();
+}
+
+CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
+CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
+CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
+CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
+ $$ = $1;
+ $$.finally = 0;
+ if($2) {
+ list_append($$.l,$2);
+ $$.finally = $2->to;$2->to=0;
+ }
+}
+CATCH_FINALLY_LIST: FINALLY {
+ $$.l=list_new();
+ $$.finally = 0;
+ if($1) {
+ list_append($$.l,$1);
+ $$.finally = $1->to;$1->to=0;
+ }
+}
+
+TRY : "try" '{' {PASS12 new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
+ code_t*out = abc_nop(0);
+
+ code_t*start = abc_nop(0);
+ $$ = code_append(start, $4);
+ if(!is_break_or_jump($4)) {
+ $$ = abc_jump($$, out);
+ }
+ code_t*end = $$ = abc_nop($$);
+
+ int tmp;
+ if($6.finally)
+ tmp = new_variable("__finally__", 0, 0);
+
+ abc_exception_list_t*l = $6.l;
+ int count=0;
+ while(l) {
+ abc_exception_t*e = l->abc_exception;
+ if(e->var_name) {
+ $$ = code_append($$, e->target);
+ $$ = abc_jump($$, out);
+ } else {
+ parserassert((ptroff_t)$6.finally);
+ // finally block
+ e->target = $$ = abc_nop($$);
+ $$ = abc___rethrow__($$);
+ }
+
+ e->from = start;
+ e->to = end;
+
+ l = l->next;
+ }
+ $$ = code_append($$, out);
+
+ $$ = insert_finally($$, $6.finally, tmp);
+
+ list_concat(state->method->exceptions, $6.l);
+
+ $$ = var_block($$);
+ PASS12 old_state();
+}
+
+/* ------------ throw ------------------------------- */