Commit 77b671f5 authored by pem@mysql.com's avatar pem@mysql.com

Moved create/find/drop functions to a separate files (sp.cc,sp.h).

Fixed backpatching of forward jumps.
Implemented LOOP, WHILE, REPEAT (temporarily known as SPREPEAT).

Known bug: Expression evaluation still not quite ok (e.g. "x > 0"),
which is why IF and CASE is not yet implemented.
parent f0137bcd
...@@ -58,7 +58,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ ...@@ -58,7 +58,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
log_event.h mini_client.h sql_repl.h slave.h \ log_event.h mini_client.h sql_repl.h slave.h \
stacktrace.h sql_sort.h sql_cache.h set_var.h \ stacktrace.h sql_sort.h sql_cache.h set_var.h \
spatial.h gstream.h sp_head.h sp_pcontext.h \ spatial.h gstream.h sp_head.h sp_pcontext.h \
sp_rcontext.h sp_rcontext.h sp.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc \ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
...@@ -87,7 +87,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ ...@@ -87,7 +87,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
mini_client.cc mini_client_errors.c \ mini_client.cc mini_client_errors.c \
stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\ stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\
gstream.cc spatial.cc sql_help.cc \ gstream.cc spatial.cc sql_help.cc \
sp_head.cc sp_pcontext.cc sp_head.cc sp_pcontext.cc sp.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS) gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
......
...@@ -126,6 +126,11 @@ public: ...@@ -126,6 +126,11 @@ public:
return m_offset; return m_offset;
} }
virtual Item_result result_type() const
{
return this_const_item()->result_type();
}
// Abstract methods inherited from Item. Just defer the call to // Abstract methods inherited from Item. Just defer the call to
// the item in the frame // the item in the frame
inline enum Type type() const inline enum Type type() const
......
...@@ -317,10 +317,10 @@ static SYMBOL symbols[] = { ...@@ -317,10 +317,10 @@ static SYMBOL symbols[] = {
{ "REPAIR", SYM(REPAIR),0,0}, { "REPAIR", SYM(REPAIR),0,0},
{ "REPLACE", SYM(REPLACE),0,0}, { "REPLACE", SYM(REPLACE),0,0},
{ "REPLICATION", SYM(REPLICATION),0,0}, { "REPLICATION", SYM(REPLICATION),0,0},
{ "SPREPEAT", SYM(SPREPEAT_SYM),0,0}, /* QQ Temp. until conflict solved */
{ "REPEATABLE", SYM(REPEATABLE_SYM),0,0}, { "REPEATABLE", SYM(REPEATABLE_SYM),0,0},
{ "REQUIRE", SYM(REQUIRE_SYM),0,0}, { "REQUIRE", SYM(REQUIRE_SYM),0,0},
{ "RESET", SYM(RESET_SYM),0,0}, { "RESET", SYM(RESET_SYM),0,0},
{ "UNTIL", SYM(UNTIL_SYM),0,0},
{ "USER_RESOURCES", SYM(RESOURCES),0,0}, { "USER_RESOURCES", SYM(RESOURCES),0,0},
{ "RESTORE", SYM(RESTORE_SYM),0,0}, { "RESTORE", SYM(RESTORE_SYM),0,0},
{ "RESTRICT", SYM(RESTRICT),0,0}, { "RESTRICT", SYM(RESTRICT),0,0},
...@@ -351,7 +351,7 @@ static SYMBOL symbols[] = { ...@@ -351,7 +351,7 @@ static SYMBOL symbols[] = {
{ "SONAME", SYM(UDF_SONAME_SYM),0,0}, { "SONAME", SYM(UDF_SONAME_SYM),0,0},
{ "SPATIAL", SYM(SPATIAL_SYM),0,0}, { "SPATIAL", SYM(SPATIAL_SYM),0,0},
{ "SPECIFIC", SYM(SPECIFIC_SYM),0,0}, { "SPECIFIC", SYM(SPECIFIC_SYM),0,0},
{ "SPSET", SYM(SPSET_SYM),0,0}, { "SPSET", SYM(SPSET_SYM),0,0}, /* Temp. until SET parsing solved. */
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0}, { "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0}, { "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
{ "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0}, { "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
...@@ -392,6 +392,7 @@ static SYMBOL symbols[] = { ...@@ -392,6 +392,7 @@ static SYMBOL symbols[] = {
{ "UNIQUE", SYM(UNIQUE_SYM),0,0}, { "UNIQUE", SYM(UNIQUE_SYM),0,0},
{ "UNLOCK", SYM(UNLOCK_SYM),0,0}, { "UNLOCK", SYM(UNLOCK_SYM),0,0},
{ "UNSIGNED", SYM(UNSIGNED),0,0}, { "UNSIGNED", SYM(UNSIGNED),0,0},
{ "UNTIL", SYM(UNTIL_SYM),0,0},
{ "USE", SYM(USE_SYM),0,0}, { "USE", SYM(USE_SYM),0,0},
{ "USE_FRM", SYM(USE_FRM),0,0}, { "USE_FRM", SYM(USE_FRM),0,0},
{ "USING", SYM(USING),0,0}, { "USING", SYM(USING),0,0},
......
/* Copyright (C) 2002 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysql_priv.h"
#include "sp.h"
#include "sp_head.h"
// Finds the SP 'name'. Currently this always reads from the database
// and prepares (parse) it, but in the future it will first look in
// the in-memory cache for SPs. (And store newly prepared SPs there of
// course.)
sp_head *
sp_find(THD *thd, Item_string *iname)
{
extern int yyparse(void *thd);
LEX *tmplex;
TABLE *table;
TABLE_LIST tables;
const char *defstr;
String *name;
sp_head *sp = NULL;
name = iname->const_string();
memset(&tables, 0, sizeof(tables));
tables.db= (char*)"mysql";
tables.real_name= tables.alias= (char*)"proc";
if (! (table= open_ltable(thd, &tables, TL_READ)))
return NULL;
if (table->file->index_read_idx(table->record[0], 0,
(byte*)name->c_ptr(), name->length(),
HA_READ_KEY_EXACT))
goto done;
if ((defstr= get_field(&thd->mem_root, table, 1)) == NULL)
goto done;
// QQ Set up our own mem_root here???
tmplex= lex_start(thd, (uchar*)defstr, strlen(defstr));
if (yyparse(thd) || thd->fatal_error || tmplex->sphead == NULL)
goto done; // Error
else
sp = tmplex->sphead;
done:
if (table)
close_thread_tables(thd);
return sp;
}
int
sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen)
{
int ret= 0;
TABLE *table;
TABLE_LIST tables;
memset(&tables, 0, sizeof(tables));
tables.db= (char*)"mysql";
tables.real_name= tables.alias= (char*)"proc";
/* Allow creation of procedures even if we can't open proc table */
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
{
ret= -1;
goto done;
}
restore_record(table, 2); // Get default values for fields
table->field[0]->store(name, namelen, default_charset_info);
table->field[1]->store(def, deflen, default_charset_info);
ret= table->file->write_row(table->record[0]);
done:
close_thread_tables(thd);
return ret;
}
int
sp_drop(THD *thd, char *name, uint namelen)
{
TABLE *table;
TABLE_LIST tables;
tables.db= (char *)"mysql";
tables.real_name= tables.alias= (char *)"proc";
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
goto err;
if (! table->file->index_read_idx(table->record[0], 0,
(byte *)name, namelen,
HA_READ_KEY_EXACT))
{
int error;
if ((error= table->file->delete_row(table->record[0])))
table->file->print_error(error, MYF(0));
}
close_thread_tables(thd);
return 0;
err:
close_thread_tables(thd);
return -1;
}
/* -*- C++ -*- */
/* Copyright (C) 2002 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _SP_H_
#define _SP_H_
//
// Finds a stored procedure given its name. Returns NULL if not found.
//
sp_head *
sp_find(THD *thd, Item_string *name);
int
sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen);
int
sp_drop(THD *thd, char *name, uint namelen);
#endif /* _SP_H_ */
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "mysql_priv.h" #include "mysql_priv.h"
#include "sp_head.h" #include "sp_head.h"
#include "sp.h"
#include "sp_pcontext.h" #include "sp_pcontext.h"
#include "sp_rcontext.h" #include "sp_rcontext.h"
...@@ -31,9 +32,7 @@ eval_func_item(Item *it, enum enum_field_types type) ...@@ -31,9 +32,7 @@ eval_func_item(Item *it, enum enum_field_types type)
{ {
it= it->this_item(); it= it->this_item();
/* QQ Which way do we do this? Or is there some even better way? */ /* QQ How do we do this? Is there some better way? */
#if 1
/* QQ Obey the declared type of the variable */
switch (type) switch (type)
{ {
case MYSQL_TYPE_TINY: case MYSQL_TYPE_TINY:
...@@ -77,30 +76,7 @@ eval_func_item(Item *it, enum enum_field_types type) ...@@ -77,30 +76,7 @@ eval_func_item(Item *it, enum enum_field_types type)
/* QQ Don't know what to do with the rest. */ /* QQ Don't know what to do with the rest. */
break; break;
} }
#else
/* QQ This looks simpler, but is wrong? It disregards the variable's type. */
switch (it->result_type())
{
case REAL_RESULT:
it= new Item_real(it->val());
break;
case INT_RESULT:
it= new Item_int(it->val_int());
break;
case STRING_RESULT:
{
char buffer[MAX_FIELD_WIDTH];
String tmp(buffer, sizeof(buffer), default_charset_info);
(void)it->val_str(&tmp);
it= new Item_string(buffer, sizeof(buffer), default_charset_info);
break;
}
default:
/* QQ Don't know what to do with the rest. */
break;
}
#endif
return it; return it;
} }
...@@ -113,6 +89,7 @@ sp_head::sp_head(LEX_STRING *name, LEX *lex) ...@@ -113,6 +89,7 @@ sp_head::sp_head(LEX_STRING *name, LEX *lex)
m_defstr= new Item_string(dstr, lex->end_of_query - lex->buf, m_defstr= new Item_string(dstr, lex->end_of_query - lex->buf,
default_charset_info); default_charset_info);
my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8); my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
m_backpatch.empty();
} }
int int
...@@ -144,7 +121,7 @@ sp_head::execute(THD *thd) ...@@ -144,7 +121,7 @@ sp_head::execute(THD *thd)
Item *it = li++; // Skip first one, it's the procedure name Item *it = li++; // Skip first one, it's the procedure name
nctx = new sp_rcontext(csize); nctx = new sp_rcontext(csize);
// QQ: No error checking whatsoever right now // QQ: No error checking whatsoever right now. Should do type checking?
for (i = 0 ; (it= li++) && i < params ; i++) for (i = 0 ; (it= li++) && i < params ; i++)
{ {
sp_pvar_t *pvar = pctx->find_pvar(i); sp_pvar_t *pvar = pctx->find_pvar(i);
...@@ -168,7 +145,7 @@ sp_head::execute(THD *thd) ...@@ -168,7 +145,7 @@ sp_head::execute(THD *thd)
// The rest of the frame are local variables which are all IN. // The rest of the frame are local variables which are all IN.
// QQ We haven't found any hint of what the value is when unassigned, // QQ We haven't found any hint of what the value is when unassigned,
// so we set it to NULL for now. It's an error to refer to an // so we set it to NULL for now. It's an error to refer to an
// unassigned variable (which should be detected by the parser). // unassigned variable anyway (which should be detected by the parser).
for (; i < csize ; i++) for (; i < csize ; i++)
nctx->push_item(NULL); nctx->push_item(NULL);
thd->spcont= nctx; thd->spcont= nctx;
...@@ -212,6 +189,7 @@ sp_head::execute(THD *thd) ...@@ -212,6 +189,7 @@ sp_head::execute(THD *thd)
} }
// Reset lex during parsing, before we parse a sub statement.
void void
sp_head::reset_lex(THD *thd) sp_head::reset_lex(THD *thd)
{ {
...@@ -244,6 +222,7 @@ sp_head::reset_lex(THD *thd) ...@@ -244,6 +222,7 @@ sp_head::reset_lex(THD *thd)
thd->lex.auxilliary_table_list.empty(); thd->lex.auxilliary_table_list.empty();
} }
// Restore lex during parsing, after we have parsed a sub statement.
void void
sp_head::restore_lex(THD *thd) sp_head::restore_lex(THD *thd)
{ {
...@@ -255,123 +234,25 @@ sp_head::restore_lex(THD *thd) ...@@ -255,123 +234,25 @@ sp_head::restore_lex(THD *thd)
} }
void void
sp_head::push_backpatch(uint ip) sp_head::push_backpatch(sp_instr *i)
{ {
(void)m_backpatch.push_front(&ip); (void)m_backpatch.push_front(i);
} }
void void
sp_head::backpatch(uint dest) sp_head::backpatch()
{
while (! m_backpatch.is_empty())
{
uint *ip= m_backpatch.pop();
sp_instr_jump *i= static_cast<sp_instr_jump *>(get_instr(*ip));
i->set_destination(dest);
}
}
// ------------------------------------------------------------------
// Finds the SP 'name'. Currently this always reads from the database
// and prepares (parse) it, but in the future it will first look in
// the in-memory cache for SPs. (And store newly prepared SPs there of
// course.)
sp_head *
sp_find(THD *thd, Item_string *iname)
{ {
extern int yyparse(void *thd); sp_instr *ip;
LEX *tmplex; uint dest= instructions();
TABLE *table; List_iterator_fast<sp_instr> li(m_backpatch);
TABLE_LIST tables;
const char *defstr;
String *name;
sp_head *sp = NULL;
name = iname->const_string();
memset(&tables, 0, sizeof(tables));
tables.db= (char*)"mysql";
tables.real_name= tables.alias= (char*)"proc";
if (! (table= open_ltable(thd, &tables, TL_READ)))
return NULL;
if (table->file->index_read_idx(table->record[0], 0,
(byte*)name->c_ptr(), name->length(),
HA_READ_KEY_EXACT))
goto done;
if ((defstr= get_field(&thd->mem_root, table, 1)) == NULL)
goto done;
// QQ Set up our own mem_root here???
tmplex= lex_start(thd, (uchar*)defstr, strlen(defstr));
if (yyparse(thd) || thd->fatal_error || tmplex->sphead == NULL)
goto done; // Error
else
sp = tmplex->sphead;
done:
if (table)
close_thread_tables(thd);
return sp;
}
int while ((ip= li++))
sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen)
{
int ret= 0;
TABLE *table;
TABLE_LIST tables;
memset(&tables, 0, sizeof(tables));
tables.db= (char*)"mysql";
tables.real_name= tables.alias= (char*)"proc";
/* Allow creation of procedures even if we can't open proc table */
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
{ {
ret= -1; sp_instr_jump *i= static_cast<sp_instr_jump *>(ip);
goto done;
}
restore_record(table, 2); // Get default values for fields
table->field[0]->store(name, namelen, default_charset_info); i->set_destination(dest);
table->field[1]->store(def, deflen, default_charset_info);
ret= table->file->write_row(table->record[0]);
done:
close_thread_tables(thd);
return ret;
}
int
sp_drop(THD *thd, char *name, uint namelen)
{
TABLE *table;
TABLE_LIST tables;
tables.db= (char *)"mysql";
tables.real_name= tables.alias= (char *)"proc";
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
goto err;
if (! table->file->index_read_idx(table->record[0], 0,
(byte *)name, namelen,
HA_READ_KEY_EXACT))
{
int error;
if ((error= table->file->delete_row(table->record[0])))
table->file->print_error(error, MYF(0));
} }
close_thread_tables(thd); m_backpatch.empty();
return 0;
err:
close_thread_tables(thd);
return -1;
} }
...@@ -412,7 +293,6 @@ sp_instr_set::execute(THD *thd, uint *nextp) ...@@ -412,7 +293,6 @@ sp_instr_set::execute(THD *thd, uint *nextp)
// //
// sp_instr_jump_if // sp_instr_jump_if
// //
int int
sp_instr_jump_if::execute(THD *thd, uint *nextp) sp_instr_jump_if::execute(THD *thd, uint *nextp)
{ {
...@@ -428,7 +308,6 @@ sp_instr_jump_if::execute(THD *thd, uint *nextp) ...@@ -428,7 +308,6 @@ sp_instr_jump_if::execute(THD *thd, uint *nextp)
// //
// sp_instr_jump_if_not // sp_instr_jump_if_not
// //
int int
sp_instr_jump_if_not::execute(THD *thd, uint *nextp) sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{ {
......
...@@ -73,10 +73,10 @@ public: ...@@ -73,10 +73,10 @@ public:
restore_lex(THD *thd); restore_lex(THD *thd);
void void
push_backpatch(uint ip); push_backpatch(sp_instr *i);
void void
backpatch(uint dest); backpatch();
private: private:
...@@ -85,7 +85,7 @@ private: ...@@ -85,7 +85,7 @@ private:
LEX *m_mylex; // My own lex LEX *m_mylex; // My own lex
LEX m_lex; // Temp. store for the other lex LEX m_lex; // Temp. store for the other lex
DYNAMIC_ARRAY m_instr; // The "instructions" DYNAMIC_ARRAY m_instr; // The "instructions"
List<uint> m_backpatch; // Instructions needing backpaching List<sp_instr> m_backpatch; // Instructions needing backpaching
inline sp_instr * inline sp_instr *
get_instr(uint i) get_instr(uint i)
...@@ -99,20 +99,6 @@ private: ...@@ -99,20 +99,6 @@ private:
}; // class sp_head : public Sql_alloc }; // class sp_head : public Sql_alloc
//
// Find a stored procedure given its name. Returns NULL if not
// found.
//
sp_head *
sp_find(THD *thd, Item_string *name);
int
sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen);
int
sp_drop(THD *thd, char *name, uint namelen);
// //
// "Instructions"... // "Instructions"...
// //
...@@ -243,7 +229,7 @@ public: ...@@ -243,7 +229,7 @@ public:
m_dest= dest; m_dest= dest;
} }
private: protected:
int m_dest; // Where we will go int m_dest; // Where we will go
...@@ -272,7 +258,6 @@ public: ...@@ -272,7 +258,6 @@ public:
private: private:
int m_dest; // Where we will go
Item *m_expr; // The condition Item *m_expr; // The condition
}; // class sp_instr_jump_if : public sp_instr_jump }; // class sp_instr_jump_if : public sp_instr_jump
...@@ -300,7 +285,6 @@ public: ...@@ -300,7 +285,6 @@ public:
private: private:
int m_dest; // Where we will go
Item *m_expr; // The condition Item *m_expr; // The condition
}; // class sp_instr_jump_if_not : public sp_instr_jump }; // class sp_instr_jump_if_not : public sp_instr_jump
......
...@@ -125,6 +125,12 @@ class sp_pcontext : public Sql_alloc ...@@ -125,6 +125,12 @@ class sp_pcontext : public Sql_alloc
sp_label_t * sp_label_t *
find_label(char *name); find_label(char *name);
inline sp_label_t *
last_label()
{
return m_label.head();
}
inline void inline void
pop_label() pop_label()
{ {
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#endif #endif
#include "sp_head.h" #include "sp_head.h"
#include "sp.h"
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
/* /*
......
...@@ -531,6 +531,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -531,6 +531,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token ITERATE_SYM %token ITERATE_SYM
%token LEAVE_SYM %token LEAVE_SYM
%token LOOP_SYM %token LOOP_SYM
/* QQ This is temporary, until the REPEAT conflict is solved. */
%token SPREPEAT_SYM
%token UNTIL_SYM %token UNTIL_SYM
%token WHILE_SYM %token WHILE_SYM
%token ASENSITIVE_SYM %token ASENSITIVE_SYM
...@@ -1053,8 +1055,10 @@ sp_proc_stmt: ...@@ -1053,8 +1055,10 @@ sp_proc_stmt:
} }
sp_unlabeled_control sp_unlabeled_control
{ {
/* QQ backpatch here */ LEX *lex= Lex;
Lex->spcont->pop_label();
lex->spcont->pop_label();
lex->sphead->backpatch();
} }
| LEAVE_SYM IDENT | LEAVE_SYM IDENT
{ {
...@@ -1068,10 +1072,9 @@ sp_proc_stmt: ...@@ -1068,10 +1072,9 @@ sp_proc_stmt:
} }
else else
{ {
uint ip= lex->sphead->instructions(); sp_instr_jump *i= new sp_instr_jump(lex->sphead->instructions());
sp_instr_jump *i= new sp_instr_jump(ip, 0);
lex->sphead->push_backpatch(ip); lex->sphead->push_backpatch(i); /* Jumping forward */
lex->sphead->add_instr(i); lex->sphead->add_instr(i);
} }
} }
...@@ -1088,7 +1091,7 @@ sp_proc_stmt: ...@@ -1088,7 +1091,7 @@ sp_proc_stmt:
else else
{ {
uint ip= lex->sphead->instructions(); uint ip= lex->sphead->instructions();
sp_instr_jump *i= new sp_instr_jump(ip, lab->ip); sp_instr_jump *i= new sp_instr_jump(ip, lab->ip); /* Jump back */
lex->sphead->add_instr(i); lex->sphead->add_instr(i);
} }
...@@ -1148,29 +1151,59 @@ sp_labeled_control: ...@@ -1148,29 +1151,59 @@ sp_labeled_control:
} }
else else
{ {
/* QQ backpatch here */
lex->spcont->pop_label(); lex->spcont->pop_label();
lex->sphead->backpatch();
} }
} }
; ;
sp_unlabeled_control: sp_unlabeled_control:
begin BEGIN_SYM
sp_decls sp_decls
sp_proc_stmts sp_proc_stmts
END END
{ { /* QQ This is just a dummy for grouping declarations and statements
together. No [[NOT] ATOMIC] yet, and we need to figure out how
make it coexist with the existing BEGIN COMMIT/ROLLBACK. */
Lex->spcont->pop($2); Lex->spcont->pop($2);
} }
| LOOP_SYM | LOOP_SYM
sp_proc_stmts sp_proc_stmts END LOOP_SYM
END LOOP_SYM {
LEX *lex= Lex;
uint ip= lex->sphead->instructions();
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
sp_instr_jump *i = new sp_instr_jump(ip, lab->ip);
lex->sphead->add_instr(i);
}
| WHILE_SYM expr DO_SYM | WHILE_SYM expr DO_SYM
sp_proc_stmts {
END WHILE_SYM LEX *lex= Lex;
| FUNC_ARG2 /* "REPEAT" actually... */ uint ip= lex->sphead->instructions();
sp_proc_stmts sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $2);
UNTIL_SYM expr END FUNC_ARG2
lex->sphead->push_backpatch(i); /* Jumping forward */
lex->sphead->add_instr(i);
}
sp_proc_stmts END WHILE_SYM
{
LEX *lex= Lex;
uint ip= lex->sphead->instructions();
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
sp_instr_jump *i = new sp_instr_jump(ip, lab->ip);
lex->sphead->add_instr(i);
}
| SPREPEAT_SYM sp_proc_stmts UNTIL_SYM expr END SPREPEAT_SYM
{ /* ^^ QQ temp. until conflict solved ^^ */
LEX *lex= Lex;
uint ip= lex->sphead->instructions();
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $4, lab->ip);
lex->sphead->add_instr(i);
}
; ;
create2: create2:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment