summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <pem@mysql.comhem.se>2004-08-17 20:20:58 +0200
committerunknown <pem@mysql.comhem.se>2004-08-17 20:20:58 +0200
commit9b5a6f7228850479abe0e4e2439dcf6b27a87136 (patch)
tree0a14fd07bbceeceb892fb762e8f9af5e74153b89
parentf43fe31e571bb5e127d5e0ca4ad6680a15104aa7 (diff)
downloadmariadb-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.result5
-rw-r--r--mysql-test/r/sp.result89
-rw-r--r--mysql-test/t/sp-error.test7
-rw-r--r--mysql-test/t/sp.test63
-rw-r--r--sql/lex.h2
-rw-r--r--sql/sp_head.cc33
-rw-r--r--sql/sp_head.h42
-rw-r--r--sql/sp_pcontext.cc82
-rw-r--r--sql/sp_pcontext.h51
-rw-r--r--sql/sql_yacc.yy147
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