diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index 0d39af0d82..211a4c5841 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -677,6 +677,18 @@ DmlNode* ContinueLeaveNode::parse(thread_db* /*tdbb*/, MemoryPool& pool, Compile ContinueLeaveNode* ContinueLeaveNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { + const char* cmd = blrOp == blr_continue_loop ? "CONTINUE" : "BREAK/LEAVE"; + + if (!dsqlScratch->loopLevel) + { + ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << + // Token unknown + Arg::Gds(isc_token_err) << + Arg::Gds(isc_random) << cmd); + } + + dsqlLabel = PASS1_label(dsqlScratch, true, dsqlLabel); + return this; } @@ -687,6 +699,8 @@ void ContinueLeaveNode::print(string& text, Array& /*nodes*/) const void ContinueLeaveNode::genBlr(DsqlCompilerScratch* dsqlScratch) { + dsqlScratch->appendUChar(blrOp); + dsqlScratch->appendUChar((int)(IPTR) dsqlLabel->nod_arg[Dsql::e_label_number]); } const StmtNode* ContinueLeaveNode::execute(thread_db* /*tdbb*/, jrd_req* request, ExeState* /*exeState*/) const @@ -2087,7 +2101,7 @@ StmtNode* ExecStatementNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) if (dsqlInnerStmt) { ++dsqlScratch->loopLevel; - node->dsqlLabel = PASS1_label2(dsqlScratch, NULL, dsqlLabel); + node->dsqlLabel = PASS1_label(dsqlScratch, false, dsqlLabel); node->dsqlInnerStmt = PASS1_statement(dsqlScratch, dsqlInnerStmt); --dsqlScratch->loopLevel; dsqlScratch->labels.pop(); @@ -3389,7 +3403,7 @@ StmtNode* ForNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) // CVC: Let's add the ability to BREAK the for_select same as the while, // but only if the command is FOR SELECT, otherwise we have singular SELECT dsqlScratch->loopLevel++; - node->dsqlLabel = PASS1_label2(dsqlScratch, NULL, dsqlLabel); + node->dsqlLabel = PASS1_label(dsqlScratch, false, dsqlLabel); node->dsqlAction = PASS1_statement(dsqlScratch, dsqlAction); dsqlScratch->loopLevel--; dsqlScratch->labels.pop(); diff --git a/src/dsql/StmtNodes.h b/src/dsql/StmtNodes.h index a772f2919d..0d5ad0bccb 100644 --- a/src/dsql/StmtNodes.h +++ b/src/dsql/StmtNodes.h @@ -138,7 +138,8 @@ public: explicit ContinueLeaveNode(MemoryPool& pool, UCHAR aBlrOp) : TypedNode(pool), blrOp(aBlrOp), - labelNumber(0) + labelNumber(0), + dsqlLabel(NULL) { fb_assert(blrOp == blr_continue_loop || blrOp == blr_leave); } @@ -165,6 +166,7 @@ public: public: UCHAR blrOp; USHORT labelNumber; + dsql_nod* dsqlLabel; }; diff --git a/src/dsql/gen.cpp b/src/dsql/gen.cpp index 1eb57cc261..3f44d6ccea 100644 --- a/src/dsql/gen.cpp +++ b/src/dsql/gen.cpp @@ -668,16 +668,6 @@ void GEN_statement( DsqlCompilerScratch* dsqlScratch, dsql_nod* node) GEN_statement(dsqlScratch, node->nod_arg[e_err_action]); return; - case nod_breakleave: - dsqlScratch->appendUChar(blr_leave); - dsqlScratch->appendUChar((int)(IPTR) node->nod_arg[e_breakleave_label]->nod_arg[e_label_number]); - return; - - case nod_continue: - dsqlScratch->appendUChar(blr_continue_loop); - dsqlScratch->appendUChar((int)(IPTR) node->nod_arg[e_continue_label]->nod_arg[e_label_number]); - return; - case nod_start_savepoint: dsqlScratch->appendUChar(blr_start_savepoint); return; diff --git a/src/dsql/node.h b/src/dsql/node.h index a7986fb26c..a1dbe30bb3 100644 --- a/src/dsql/node.h +++ b/src/dsql/node.h @@ -165,7 +165,6 @@ enum nod_t nod_mod_field_name, nod_mod_field_type, nod_mod_field_pos, - nod_breakleave, nod_udf_param, // there should be a way to signal a param by descriptor! nod_searched_case, // searched CASE function nod_simple_case, // simple CASE function @@ -202,7 +201,6 @@ enum nod_t nod_package_name, nod_package_obj, nod_mod_field_null_flag, - nod_continue, nod_func_obj, nod_function_name }; @@ -529,10 +527,6 @@ enum node_args { e_mod_fld_pos_new_position, e_mod_fld_pos_count, - // CVC: blr_leave used to emulate break - e_breakleave_label = 0, // nod_breakleave - e_breakleave_count, - e_udf_param_field = 0, e_udf_param_type, // Basically, by_reference or by_descriptor e_udf_param_count, @@ -591,10 +585,7 @@ enum node_args { e_mod_fld_null_flag_field = 0, // nod_mod_field_null_flag e_mod_fld_null_flag_value, - e_mod_fld_null_flag_count, - - e_continue_label = 0, // nod_continue - e_continue_count + e_mod_fld_null_flag_count }; } // namespace diff --git a/src/dsql/parse.y b/src/dsql/parse.y index c053a43b43..703bbee48c 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -2596,22 +2596,27 @@ label_opt : symbol_label_name ':' { $$ = NULL; } ; -breakleave : KW_BREAK - { $$ = make_node (nod_breakleave, (int) e_breakleave_count, NULL); } - | LEAVE - { $$ = make_node (nod_breakleave, (int) e_breakleave_count, NULL); } - | LEAVE symbol_label_name - { $$ = make_node (nod_breakleave, (int) e_breakleave_count, - make_node (nod_label, (int) e_label_count, $2, NULL)); } - ; +breakleave + : KW_BREAK + { $$ = makeClassNode(newNode(blr_leave)); } + | LEAVE + { $$ = makeClassNode(newNode(blr_leave)); } + | LEAVE symbol_label_name + { + ContinueLeaveNode* node = newNode(blr_leave); + node->dsqlLabel = make_node(nod_label, (int) e_label_count, $2, NULL); + $$ = makeClassNode(node); + } + ; continue : CONTINUE - { $$ = make_node(nod_continue, (int) e_continue_count, NULL); } + { $$ = makeClassNode(newNode(blr_continue_loop)); } | CONTINUE symbol_label_name { - $$ = make_node(nod_continue, (int) e_continue_count, - make_node(nod_label, (int) e_label_count, $2, NULL)); + ContinueLeaveNode* node = newNode(blr_continue_loop); + node->dsqlLabel = make_node(nod_label, (int) e_label_count, $2, NULL); + $$ = makeClassNode(node); } ; diff --git a/src/dsql/pass1.cpp b/src/dsql/pass1.cpp index 233296b186..7e8634cf10 100644 --- a/src/dsql/pass1.cpp +++ b/src/dsql/pass1.cpp @@ -1275,28 +1275,6 @@ dsql_nod* PASS1_statement(DsqlCompilerScratch* dsqlScratch, dsql_nod* input) node->nod_arg[e_err_action] = PASS1_statement(dsqlScratch, input->nod_arg[e_err_action]); return node; - case nod_breakleave: - if (!dsqlScratch->loopLevel) - { - ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << - // Token unknown - Arg::Gds(isc_token_err) << - Arg::Gds(isc_random) << Arg::Str("BREAK/LEAVE")); - } - input->nod_arg[e_breakleave_label] = PASS1_label(dsqlScratch, input); - return input; - - case nod_continue: - if (!dsqlScratch->loopLevel) - { - ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << - // Token unknown - Arg::Gds(isc_token_err) << - Arg::Gds(isc_random) << Arg::Str("CONTINUE")); - } - input->nod_arg[e_continue_label] = PASS1_label(dsqlScratch, input); - return input; - case nod_select: { node = PASS1_rse(dsqlScratch, input->nod_arg[e_select_expr], input->nod_arg[e_select_lock]); @@ -1339,7 +1317,7 @@ dsql_nod* PASS1_statement(DsqlCompilerScratch* dsqlScratch, dsql_nod* input) // CVC: loop numbers should be incremented before analyzing the body // to preserve nesting <==> increasing level number dsqlScratch->loopLevel++; - node->nod_arg[e_while_label] = PASS1_label(dsqlScratch, input); + node->nod_arg[e_while_label] = PASS1_label(dsqlScratch, false, input->nod_arg[e_while_label]); node->nod_arg[e_while_action] = PASS1_statement(dsqlScratch, input->nod_arg[e_while_action]); dsqlScratch->loopLevel--; dsqlScratch->labels.pop(); @@ -3853,39 +3831,9 @@ static dsql_nod* pass1_insert( DsqlCompilerScratch* dsqlScratch, dsql_nod* input // Process loop interruption. -dsql_nod* PASS1_label(DsqlCompilerScratch* dsqlScratch, dsql_nod* input) +dsql_nod* PASS1_label(DsqlCompilerScratch* dsqlScratch, bool breakContinue, dsql_nod* label) { DEV_BLKCHK(dsqlScratch, dsql_type_req); - DEV_BLKCHK(input, dsql_type_nod); - - dsql_nod* label = NULL; - - // retrieve a label - - switch (input->nod_type) - { - case nod_breakleave: - label = input->nod_arg[e_breakleave_label]; - break; - case nod_continue: - label = input->nod_arg[e_continue_label]; - break; - case nod_while: - label = input->nod_arg[e_while_label]; - break; - default: - fb_assert(false); - } - - return PASS1_label2(dsqlScratch, input, label); -} - - -// Process loop interruption. -dsql_nod* PASS1_label2(DsqlCompilerScratch* dsqlScratch, dsql_nod* input, dsql_nod* label) -{ - DEV_BLKCHK(dsqlScratch, dsql_type_req); - DEV_BLKCHK(input, dsql_type_nod); DEV_BLKCHK(label, dsql_type_nod); // look for a label, if specified @@ -3916,7 +3864,8 @@ dsql_nod* PASS1_label2(DsqlCompilerScratch* dsqlScratch, dsql_nod* input, dsql_n } USHORT number = 0; - if (input && (input->nod_type == nod_breakleave || input->nod_type == nod_continue)) + + if (breakContinue) { if (position > 0) { @@ -7778,14 +7727,6 @@ void DSQL_pretty(const dsql_nod* node, int column) verb = "end_backup"; break; - case nod_breakleave: - verb = "breakleave"; - break; - - case nod_continue: - verb = "continue"; - break; - case nod_while: verb = "while"; break; diff --git a/src/dsql/pass1_proto.h b/src/dsql/pass1_proto.h index ed677b0d29..5dddc4d042 100644 --- a/src/dsql/pass1_proto.h +++ b/src/dsql/pass1_proto.h @@ -35,8 +35,7 @@ Jrd::dsql_nod* PASS1_compose(Jrd::dsql_nod*, Jrd::dsql_nod*, UCHAR); Jrd::dsql_nod* PASS1_cursor_name(Jrd::DsqlCompilerScratch*, const Firebird::MetaName&, USHORT, bool); void PASS1_expand_select_node(Jrd::DsqlCompilerScratch*, Jrd::dsql_nod*, Jrd::DsqlNodStack&, bool); void PASS1_field_unknown(const TEXT*, const TEXT*, const Jrd::dsql_nod*); -Jrd::dsql_nod* PASS1_label(Jrd::DsqlCompilerScratch*, Jrd::dsql_nod*); -Jrd::dsql_nod* PASS1_label2(Jrd::DsqlCompilerScratch*, Jrd::dsql_nod*, Jrd::dsql_nod*); +Jrd::dsql_nod* PASS1_label(Jrd::DsqlCompilerScratch*, bool, Jrd::dsql_nod*); Jrd::dsql_nod* PASS1_lookup_alias(Jrd::DsqlCompilerScratch*, const Jrd::dsql_str*, Jrd::dsql_nod*, bool); Jrd::dsql_ctx* PASS1_make_context(Jrd::DsqlCompilerScratch* statement, const Jrd::dsql_nod* relation_node); Jrd::dsql_nod* PASS1_node(Jrd::DsqlCompilerScratch*, Jrd::dsql_nod*);