diff options
author | unknown <pem@mysql.comhem.se> | 2004-08-17 20:20:58 +0200 |
---|---|---|
committer | unknown <pem@mysql.comhem.se> | 2004-08-17 20:20:58 +0200 |
commit | 9b5a6f7228850479abe0e4e2439dcf6b27a87136 (patch) | |
tree | 0a14fd07bbceeceb892fb762e8f9af5e74153b89 | |
parent | f43fe31e571bb5e127d5e0ca4ad6680a15104aa7 (diff) | |
download | mariadb-git-9b5a6f7228850479abe0e4e2439dcf6b27a87136.tar.gz |
WL#2002: Implement stored procedure GOTO.
Mostly done, it works, but the temporary LABEL syntax still to be fixed.
mysql-test/r/sp-error.result:
New test case for WL#2002 (GOTO).
mysql-test/r/sp.result:
New test case for WL#2002 (GOTO).
(Also corrected another test)
mysql-test/t/sp-error.test:
New test case for WL#2002 (GOTO).
mysql-test/t/sp.test:
New test case for WL#2002 (GOTO).
(Also corrected another test)
sql/lex.h:
New symbol GOTO.
Also a temporary symbol LABEL, which hopefully will go away soon.
sql/sp_head.cc:
Fixed backpatching to cope with free GOTO labels an hpop and cpop instructions.
Also optimized away pointless jump instructions.
sql/sp_head.h:
Fixed backpatching to cope with free GOTO labels an hpop and cpop instructions.
We now sometimes generate hpop/cpop 0 instructions but the optimizer removes them.
sql/sp_pcontext.cc:
Added free GOTO labels, and support for coping with jumps out of blocks
with handlers or cursors.
sql/sp_pcontext.h:
Added free GOTO labels, and support for coping with jumps out of blocks
with handlers or cursors.
sql/sql_yacc.yy:
Added GOTO and LABEL, and adjusted backpatching accordingly. Also fixed LEAVE
out of blocks. The LABEL syntax will go away soon, hopefully.
-rw-r--r-- | mysql-test/r/sp-error.result | 5 | ||||
-rw-r--r-- | mysql-test/r/sp.result | 89 | ||||
-rw-r--r-- | mysql-test/t/sp-error.test | 7 | ||||
-rw-r--r-- | mysql-test/t/sp.test | 63 | ||||
-rw-r--r-- | sql/lex.h | 2 | ||||
-rw-r--r-- | sql/sp_head.cc | 33 | ||||
-rw-r--r-- | sql/sp_head.h | 42 | ||||
-rw-r--r-- | sql/sp_pcontext.cc | 82 | ||||
-rw-r--r-- | sql/sp_pcontext.h | 51 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 147 |
10 files changed, 482 insertions, 39 deletions
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 02aaa646646..14e2090579b 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -63,6 +63,11 @@ iterate foo; end| ERROR 42000: ITERATE with no matching label: foo create procedure foo() +begin +goto foo; +end| +ERROR 42000: GOTO with no matching label: foo +create procedure foo() foo: loop foo: loop set @x=2; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index a7f6d2a1b2f..9b2e16e3fe9 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -398,6 +398,87 @@ id data i 3 delete from t1| drop procedure i| +create procedure j() +begin +declare y int; +label a; +select * from t1; +select count(*) into y from t1; +if y > 2 then +goto b; +end if; +insert into t1 values ("j", y); +goto a; +label b; +end| +call j()| +id data +id data +j 0 +id data +j 0 +j 1 +id data +j 0 +j 1 +j 2 +drop procedure j| +create procedure k(a int) +begin +declare x int default 0; +declare continue handler for sqlstate '42S98' set x = 1; +label a; +select * from t1; +b: +while x < 2 do +begin +declare continue handler for sqlstate '42S99' set x = 2; +if a = 0 then +set x = x + 1; +iterate b; +elseif a = 1 then +leave b; +elseif a = 2 then +set a = 1; +goto a; +end if; +end; +end while b; +select * from t1; +end| +call k(0)| +id data +j 0 +j 1 +j 2 +id data +j 0 +j 1 +j 2 +call k(1)| +id data +j 0 +j 1 +j 2 +id data +j 0 +j 1 +j 2 +call k(2)| +id data +j 0 +j 1 +j 2 +id data +j 0 +j 1 +j 2 +id data +j 0 +j 1 +j 2 +drop procedure k| +delete from t1| insert into t1 values ("foo", 3), ("bar", 19)| insert into t2 values ("x", 9, 4.1), ("y", -1, 19.2), ("z", 3, 2.2)| create procedure sel1() @@ -1487,7 +1568,7 @@ Grants for root@localhost GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 22185 +master-bin.000001 22451 Database Table In_use Name_locked Privilege Context Comment Alter Tables To alter the table @@ -1541,7 +1622,7 @@ Grants for root@localhost GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 22185 +master-bin.000001 22451 Database Table In_use Name_locked Privilege Context Comment Alter Tables To alter the table @@ -1580,10 +1661,10 @@ show processlist; end| call bug4902_2()| Id User Host db Command Time State Info -# root localhost test Query 0 NULL call bug4902_2() +# root localhost test Query # NULL call bug4902_2() call bug4902_2()| Id User Host db Command Time State Info -# root localhost test Query 0 NULL call bug4902_2() +# root localhost test Query # NULL call bug4902_2() drop procedure bug4902_2| drop table if exists t3| create procedure bug4904() diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index ecba664dfca..2c2dd10c676 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -82,7 +82,7 @@ drop procedure if exists foo| --error 1304 show create procedure foo| -# LEAVE/ITERATE with no match +# LEAVE/ITERATE/GOTO with no match --error 1307 create procedure foo() foo: loop @@ -98,6 +98,11 @@ create procedure foo() foo: begin iterate foo; end| +--error 1307 +create procedure foo() +begin + goto foo; +end| # Redefining label --error 1308 diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 3913afed735..265223fd930 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -468,6 +468,65 @@ delete from t1| drop procedure i| +# The non-standard GOTO, for compatibility +# +# QQQ The "label" syntax is temporary. +# QQQ This is no nearly enough, more tests are needed +# +create procedure j() +begin + declare y int; + +label a; + select * from t1; + select count(*) into y from t1; + if y > 2 then + goto b; + end if; + insert into t1 values ("j", y); + goto a; +label b; +end| + +call j()| + +drop procedure j| + +# With dummy handlers, just to test restore of contexts with jumps +create procedure k(a int) +begin + declare x int default 0; + declare continue handler for sqlstate '42S98' set x = 1; + +label a; + select * from t1; +b: + while x < 2 do + begin + declare continue handler for sqlstate '42S99' set x = 2; + + if a = 0 then + set x = x + 1; + iterate b; + elseif a = 1 then + leave b; + elseif a = 2 then + set a = 1; + goto a; + end if; + end; + end while b; + + select * from t1; +end| + +call k(0)| +call k(1)| +call k(2)| + +drop procedure k| +delete from t1| + # SELECT with one of more result set sent back to the clinet insert into t1 values ("foo", 3), ("bar", 19)| insert into t2 values ("x", 9, 4.1), ("y", -1, 19.2), ("z", 3, 2.2)| @@ -1725,9 +1784,9 @@ create procedure bug4902_2() begin show processlist; end| ---replace_column 1 # +--replace_column 1 # 6 # call bug4902_2()| ---replace_column 1 # +--replace_column 1 # 6 # call bug4902_2()| drop procedure bug4902_2| diff --git a/sql/lex.h b/sql/lex.h index 023c4752720..957aa3159e7 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -209,6 +209,7 @@ static SYMBOL symbols[] = { { "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION)}, { "GET_FORMAT", SYM(GET_FORMAT)}, { "GLOBAL", SYM(GLOBAL_SYM)}, + { "GOTO", SYM(GOTO_SYM)}, { "GRANT", SYM(GRANT)}, { "GRANTS", SYM(GRANTS)}, { "GROUP", SYM(GROUP)}, @@ -256,6 +257,7 @@ static SYMBOL symbols[] = { { "KEY", SYM(KEY_SYM)}, { "KEYS", SYM(KEYS)}, { "KILL", SYM(KILL_SYM)}, + { "LABEL", SYM(LABEL_SYM)}, { "LANGUAGE", SYM(LANGUAGE_SYM)}, { "LAST", SYM(LAST_SYM)}, { "LEADING", SYM(LEADING)}, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 6ba72215e39..bc6251903c2 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -846,12 +846,36 @@ sp_head::backpatch(sp_label_t *lab) List_iterator_fast<bp_t> li(m_backpatch); while ((bp= li++)) - if (bp->lab == lab) + { + if (bp->lab == lab || + (bp->lab->type == SP_LAB_REF && + my_strcasecmp(system_charset_info, bp->lab->name, lab->name) == 0)) { - sp_instr_jump *i= static_cast<sp_instr_jump *>(bp->instr); + sp_scope_t sdiff; - i->set_destination(dest); + if (bp->lab->type == SP_LAB_REF) + bp->lab= lab; + m_pcont->diff_scopes(0, &sdiff); + bp->instr->backpatch(dest, sdiff.hndlrs, sdiff.curs); } + } +} + +int +sp_head::check_backpatch(THD *thd) +{ + bp_t *bp; + List_iterator_fast<bp_t> li(m_backpatch); + + while ((bp= li++)) + { + if (bp->lab->type == SP_LAB_REF) + { + net_printf(thd, ER_SP_LILABEL_MISMATCH, "GOTO", bp->lab->name); + return -1; + } + } + return 0; } void @@ -1199,8 +1223,9 @@ sp_instr_jump::print(String *str) uint sp_instr_jump::opt_mark(sp_head *sp) { - marked= 1; m_dest= opt_shortcut_jump(sp); + if (m_dest != m_ip+1) /* Jumping to following instruction? */ + marked= 1; m_optdest= sp->get_instr(m_dest); return m_dest; } diff --git a/sql/sp_head.h b/sql/sp_head.h index 0b33c6b2142..39a74366ccb 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -182,6 +182,13 @@ public: void backpatch(struct sp_label *); + // Check that no unresolved references exist. + // If none found, 0 is returned, otherwise errors have been issued + // and -1 is returned. + // This is called by the parser at the end of a create procedure/function. + int + check_backpatch(THD *thd); + char *name(uint *lenp = 0) const { if (lenp) @@ -272,7 +279,7 @@ public: virtual void print(String *str) = 0; - virtual void set_destination(uint dest) + virtual void backpatch(uint dest, uint hpop, uint cpop) {} virtual uint opt_mark(sp_head *sp) @@ -394,8 +401,7 @@ public: virtual void opt_move(uint dst, List<sp_instr> *ibp); - virtual void - set_destination(uint dest) + virtual void backpatch(uint dest, uint hpop, uint cpop) { if (m_dest == 0) // Don't reset m_dest= dest; @@ -575,6 +581,21 @@ public: virtual void print(String *str); + virtual void backpatch(uint dest, uint hpop, uint cpop) + { + if (hpop > m_count) + m_count= 0; + else + m_count-= hpop; + } + + virtual uint opt_mark(sp_head *sp) + { + if (m_count) + marked= 1; + return m_ip+1; + } + private: uint m_count; @@ -655,6 +676,21 @@ public: virtual void print(String *str); + virtual void backpatch(uint dest, uint hpop, uint cpop) + { + if (cpop > m_count) + m_count= 0; + else + m_count-= cpop; + } + + virtual uint opt_mark(sp_head *sp) + { + if (m_count) + marked= 1; + return m_ip+1; + } + private: uint m_count; diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index 03333a2da72..6f999531e58 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -27,12 +27,14 @@ #include "sp_head.h" sp_pcontext::sp_pcontext() - : Sql_alloc(), m_params(0), m_framesize(0), m_handlers(0), m_cursmax(0) + : Sql_alloc(), m_params(0), m_framesize(0), m_handlers(0), m_cursmax(0), + m_hndlrlev(0) { VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8)); VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8)); VOID(my_init_dynamic_array(&m_cursor, sizeof(LEX_STRING), 16, 8)); VOID(my_init_dynamic_array(&m_scopes, sizeof(sp_scope_t), 16, 8)); + VOID(my_init_dynamic_array(&m_glabel, sizeof(sp_label_t *), 16, 8)); m_label.empty(); } @@ -43,6 +45,7 @@ sp_pcontext::destroy() delete_dynamic(&m_cond); delete_dynamic(&m_cursor); delete_dynamic(&m_scopes); + delete_dynamic(&m_glabel); m_label.empty(); } @@ -53,14 +56,46 @@ sp_pcontext::push_scope() s.vars= m_pvar.elements; s.conds= m_cond.elements; + s.hndlrs= m_hndlrlev; s.curs= m_cursor.elements; + s.glab= m_glabel.elements; insert_dynamic(&m_scopes, (gptr)&s); } void -sp_pcontext::pop_scope() +sp_pcontext::pop_scope(sp_scope_t *sp) { - (void)pop_dynamic(&m_scopes); + byte *p= pop_dynamic(&m_scopes); + + if (sp && p) + memcpy(sp, p, sizeof(sp_scope_t)); +} + +void +sp_pcontext::diff_scopes(uint sold, sp_scope_t *diffs) +{ + uint snew= m_scopes.elements; + sp_scope_t scope; + + diffs->vars= diffs->conds= diffs->hndlrs= diffs->curs= diffs->glab= 0; + while (snew-- > sold) + { + get_dynamic(&m_scopes, (gptr)&scope, snew); + diffs->vars+= scope.vars; + diffs->conds+= scope.conds; + diffs->hndlrs+= scope.hndlrs; + diffs->curs+= scope.curs; + diffs->glab+= scope.glab; + } + if (sold) + { + get_dynamic(&m_scopes, (gptr)&scope, sold-1); + diffs->vars-= scope.vars; + diffs->conds-= scope.conds; + diffs->hndlrs-= scope.hndlrs; + diffs->curs-= scope.curs; + diffs->glab-= scope.glab; + } } @@ -132,7 +167,8 @@ sp_pcontext::push_label(char *name, uint ip) { lab->name= name; lab->ip= ip; - lab->isbegin= FALSE; + lab->type= SP_LAB_GOTO; + lab->scopes= 0; m_label.push_front(lab); } return lab; @@ -245,3 +281,41 @@ sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped) } return FALSE; } + +sp_label_t * +sp_pcontext::push_glabel(char *name, uint ip) +{ + sp_label_t *lab = (sp_label_t *)sql_alloc(sizeof(sp_label_t)); + + if (lab) + { + lab->name= name; + lab->ip= ip; + lab->type= SP_LAB_GOTO; + lab->scopes= 0; + insert_dynamic(&m_glabel, (gptr)&lab); + } + return lab; +} + +sp_label_t * +sp_pcontext::find_glabel(char *name) +{ + uint i= m_glabel.elements; + + while (i--) + { + sp_label_t *lab; + + get_dynamic(&m_glabel, (gptr)&lab, i); + if (my_strcasecmp(system_charset_info, name, lab->name) == 0) + return lab; + } + return NULL; +} + +void +sp_pcontext::pop_glabel(uint count) +{ + (void)pop_dynamic(&m_glabel); +} diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index a82cefa2e42..e3bdc41779a 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -39,11 +39,18 @@ typedef struct sp_pvar Item *dflt; } sp_pvar_t; + +#define SP_LAB_REF 0 // Unresolved reference (for goto) +#define SP_LAB_GOTO 1 // Free goto label +#define SP_LAB_BEGIN 2 // Label at BEGIN +#define SP_LAB_ITER 3 // Label at iteration control + typedef struct sp_label { char *name; uint ip; // Instruction index - my_bool isbegin; // For ITERATE error checking + int type; // begin/iter or ref/free + uint scopes; // No. of scopes at label } sp_label_t; typedef struct sp_cond_type @@ -61,7 +68,7 @@ typedef struct sp_cond typedef struct sp_scope { - uint vars, conds, curs; + uint vars, conds, hndlrs, curs, glab; } sp_scope_t; class sp_pcontext : public Sql_alloc @@ -82,7 +89,18 @@ class sp_pcontext : public Sql_alloc push_scope(); void - pop_scope(); + pop_scope(sp_scope_t *sp = 0); + + uint + scopes() + { + return m_scopes.elements; + } + + // Sets '*diffs' to the differences between current scope index snew and sold + void + diff_scopes(uint sold, sp_scope_t *diffs); + // // Parameters and variables @@ -223,6 +241,18 @@ class sp_pcontext : public Sql_alloc return m_handlers; } + inline void + push_handlers(uint count) + { + m_hndlrlev+= count; + } + + inline void + pop_handlers(uint count) + { + m_hndlrlev-= count; + } + // // Cursors // @@ -246,17 +276,32 @@ class sp_pcontext : public Sql_alloc return m_cursmax; } + // + // GOTO labels + // + + sp_label_t * + push_glabel(char *name, uint ip); + + sp_label_t * + find_glabel(char *name); + + void + pop_glabel(uint count); + private: uint m_params; // The number of parameters uint m_framesize; // The maximum framesize uint m_handlers; // The total number of handlers uint m_cursmax; // The maximum number of cursors + uint m_hndlrlev; // Current number of active handlers DYNAMIC_ARRAY m_pvar; // Parameters/variables DYNAMIC_ARRAY m_cond; // Conditions DYNAMIC_ARRAY m_cursor; // Cursors DYNAMIC_ARRAY m_scopes; // For error checking + DYNAMIC_ARRAY m_glabel; // Goto labels List<sp_label_t> m_label; // The label list diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 751125c9fe8..498fb1b7fcf 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -611,6 +611,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CURSOR_SYM %token ELSEIF_SYM %token ITERATE_SYM +%token GOTO_SYM +%token LABEL_SYM %token LEAVE_SYM %token LOOP_SYM %token REPEAT_SYM @@ -1180,13 +1182,16 @@ create: sp_proc_stmt { LEX *lex= Lex; + sp_head *sp= lex->sphead; - lex->sphead->init_strings(YYTHD, lex, $3); + if (sp->check_backpatch(YYTHD)) + YYABORT; + sp->init_strings(YYTHD, lex, $3); lex->sql_command= SQLCOM_CREATE_PROCEDURE; /* Restore flag if it was cleared above */ - if (lex->sphead->m_old_cmq) + if (sp->m_old_cmq) YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; - lex->sphead->restore_thd_mem_root(YYTHD); + sp->restore_thd_mem_root(YYTHD); } | CREATE or_replace algorithm VIEW_SYM table_ident { @@ -1286,6 +1291,8 @@ create_function_tail: LEX *lex= Lex; sp_head *sp= lex->sphead; + if (sp->check_backpatch(YYTHD)) + YYABORT; lex->sql_command= SQLCOM_CREATE_SPFUNCTION; sp->init_strings(YYTHD, lex, lex->spname); /* Restore flag if it was cleared above */ @@ -1816,7 +1823,8 @@ sp_proc_stmt: { LEX *lex= Lex; sp_head *sp = lex->sphead; - sp_label_t *lab= lex->spcont->find_label($2.str); + sp_pcontext *ctx= lex->spcont; + sp_label_t *lab= ctx->find_label($2.str); if (! lab) { @@ -1825,8 +1833,20 @@ sp_proc_stmt: } else { - sp_instr_jump *i= new sp_instr_jump(sp->instructions()); - + uint ip= sp->instructions(); + sp_scope_t sdiff; + sp_instr_jump *i; + sp_instr_hpop *ih; + sp_instr_cpop *ic; + + ctx->diff_scopes(0, &sdiff); + ih= new sp_instr_hpop(ip++, sdiff.hndlrs); + sp->push_backpatch(ih, lab); + sp->add_instr(ih); + ic= new sp_instr_cpop(ip++, sdiff.curs); + sp->push_backpatch(ic, lab); + sp->add_instr(ic); + i= new sp_instr_jump(ip); sp->push_backpatch(i, lab); /* Jumping forward */ sp->add_instr(i); } @@ -1834,19 +1854,101 @@ sp_proc_stmt: | ITERATE_SYM IDENT { LEX *lex= Lex; - sp_label_t *lab= lex->spcont->find_label($2.str); + sp_head *sp= lex->sphead; + sp_pcontext *ctx= lex->spcont; + sp_label_t *lab= ctx->find_label($2.str); - if (! lab || lab->isbegin) + if (! lab || lab->type != SP_LAB_ITER) { net_printf(YYTHD, ER_SP_LILABEL_MISMATCH, "ITERATE", $2.str); YYABORT; } else { - uint ip= lex->sphead->instructions(); - sp_instr_jump *i= new sp_instr_jump(ip, lab->ip); /* Jump back */ + sp_instr_jump *i; + uint ip= sp->instructions(); + sp_scope_t sdiff; + + ctx->diff_scopes(lab->scopes, &sdiff); + if (sdiff.hndlrs) + sp->add_instr(new sp_instr_hpop(ip++, sdiff.hndlrs)); + if (sdiff.curs) + sp->add_instr(new sp_instr_cpop(ip++, sdiff.curs)); + i= new sp_instr_jump(ip, lab->ip); /* Jump back */ + sp->add_instr(i); + } + } + | LABEL_SYM IDENT + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + sp_pcontext *ctx= lex->spcont; + sp_label_t *lab= ctx->find_label($2.str); - lex->sphead->add_instr(i); + if (! lab) + lab= ctx->find_glabel($2.str); + if (lab) + { + net_printf(YYTHD, ER_SP_LABEL_REDEFINE, $2.str); + YYABORT; + } + else + { + lab= ctx->push_glabel($2.str, sp->instructions()); + lab->type= SP_LAB_GOTO; + lab->scopes= ctx->scopes(); + sp->backpatch(lab); + } + } + | GOTO_SYM IDENT + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + sp_pcontext *ctx= lex->spcont; + uint ip= lex->sphead->instructions(); + sp_label_t *lab= ctx->find_label($2.str); + sp_scope_t sdiff; + sp_instr_jump *i; + sp_instr_hpop *ih; + sp_instr_cpop *ic; + + if (! lab) + lab= ctx->find_glabel($2.str); + + if (! lab) + { + lab= (sp_label_t *)YYTHD->alloc(sizeof(sp_label_t)); + lab->name= $2.str; + lab->ip= 0; + lab->type= SP_LAB_REF; + lab->scopes= 0; + + ctx->diff_scopes(0, &sdiff); + ih= new sp_instr_hpop(ip++, sdiff.hndlrs); + sp->push_backpatch(ih, lab); + sp->add_instr(ih); + ic= new sp_instr_cpop(ip++, sdiff.curs); + sp->add_instr(ic); + sp->push_backpatch(ic, lab); + i= new sp_instr_jump(ip); + sp->push_backpatch(i, lab); /* Jumping forward */ + sp->add_instr(i); + } + else + { + ctx->diff_scopes(lab->scopes, &sdiff); + if (sdiff.hndlrs) + { + ih= new sp_instr_hpop(ip++, sdiff.hndlrs); + sp->add_instr(ih); + } + if (sdiff.curs) + { + ic= new sp_instr_cpop(ip++, sdiff.curs); + sp->add_instr(ic); + } + i= new sp_instr_jump(ip, lab->ip); /* Jump back */ + sp->add_instr(i); } } | OPEN_SYM ident @@ -2041,7 +2143,8 @@ sp_labeled_control: IDENT ':' { LEX *lex= Lex; - sp_label_t *lab= lex->spcont->find_label($1.str); + sp_pcontext *ctx= lex->spcont; + sp_label_t *lab= ctx->find_label($1.str); if (lab) { @@ -2050,8 +2153,10 @@ sp_labeled_control: } else { - lex->spcont->push_label($1.str, - lex->sphead->instructions()); + lab= lex->spcont->push_label($1.str, + lex->sphead->instructions()); + lab->type= SP_LAB_ITER; + lab->scopes= ctx->scopes(); } } sp_unlabeled_control sp_opt_label @@ -2088,27 +2193,33 @@ sp_unlabeled_control: LEX *lex= Lex; sp_label_t *lab= lex->spcont->last_label(); - lab->isbegin= TRUE; + lab->type= SP_LAB_BEGIN; /* Scope duplicate checking */ lex->spcont->push_scope(); } sp_decls + { + Lex->spcont->push_handlers($3.hndlrs); + } sp_proc_stmts END { LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; + sp_scope_t scope; - sp->backpatch(ctx->last_label()); /* We always has a label */ + sp->backpatch(ctx->last_label()); /* We always have a label */ ctx->pop_pvar($3.vars); ctx->pop_cond($3.conds); + ctx->pop_handlers($3.hndlrs); ctx->pop_cursor($3.curs); if ($3.hndlrs) - sp->add_instr(new sp_instr_hpop(sp->instructions(),$3.hndlrs)); + sp->add_instr(new sp_instr_hpop(sp->instructions(), $3.hndlrs)); if ($3.curs) sp->add_instr(new sp_instr_cpop(sp->instructions(), $3.curs)); - ctx->pop_scope(); + ctx->pop_scope(&scope); + ctx->pop_glabel(scope.glab); } | LOOP_SYM sp_proc_stmts END LOOP_SYM |