diff --git a/design_dump.cc b/design_dump.cc index 0abb2ed3f..c89d3158c 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1388,7 +1388,8 @@ void NetForLoop::dump(ostream&fd, unsigned ind) const fd << ""; fd << endl; statement_->dump(fd, ind+4); - step_statement_->dump(fd, ind+4); + if (step_statement_) + step_statement_->dump(fd, ind+4); } void NetFree::dump(ostream&o, unsigned ind) const diff --git a/elaborate.cc b/elaborate.cc index a98fbba76..dfd1fb7d2 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -5457,7 +5457,7 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, * - index variable (name1_) (optional) * - initial value (expr1_) (only if name1_ is present) * - condition expression (cond_) - * - step statement (step_) + * - step statement (step_) (optional) * - sub-statement (statement_) * * The rules that lead to the PForStatment look like: @@ -5526,9 +5526,12 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const // Now elaborate the for_step statement. I really should do // some error checking here to make sure the step statement // really does step the variable. - NetProc*step = step_->elaborate(des, scope); - if (!step) - error_flag = true; + NetProc*step = nullptr; + if (step_) { + step = step_->elaborate(des, scope); + if (!step) + error_flag = true; + } // Elaborate the condition expression. Try to evaluate it too, // in case it is a constant. This is an interesting case @@ -5544,10 +5547,10 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const // Error recovery - if we failed to elaborate any of the loop // expressions, give up now. Error counts where handled elsewhere. if (error_flag) { - delete initial_expr; - delete ce; - delete step; - delete sub; + if (initial_expr) delete initial_expr; + if (ce) delete ce; + if (step) delete step; + if (sub) delete sub; return 0; } diff --git a/net_proc.cc b/net_proc.cc index ffe8d82a7..f425560c5 100644 --- a/net_proc.cc +++ b/net_proc.cc @@ -212,7 +212,7 @@ void NetForLoop::wrap_up() // statement. This can happen for example with statments like this: // for ( ; ; ) ; // If the index_ and init_expr_ are present, then generate the - // inital assignment and push it into the sequential block + // inital assignment and push it into the sequential block. if (index_ || init_expr_) { top->set_line(*this); NetAssign_*lv = new NetAssign_(index_); @@ -225,7 +225,11 @@ void NetForLoop::wrap_up() internal_block->set_line(*this); if (statement_) internal_block->append(statement_); - internal_block->append(step_statement_); + + // The step statement is optional. If missing, it is assumed that + // the programmer has added it to the regular statement. Hopefully. + if (step_statement_) + internal_block->append(step_statement_); NetWhile*wloop = new NetWhile(condition_, internal_block); wloop->set_line(*this); diff --git a/parse.y b/parse.y index 14e563e59..6f278ac4a 100644 --- a/parse.y +++ b/parse.y @@ -675,7 +675,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector event_control %type statement statement_item statement_or_null %type compressed_statement -%type loop_statement for_step jump_statement +%type loop_statement for_step for_step_opt jump_statement %type concurrent_assertion_statement %type deferred_immediate_assertion_statement %type simple_immediate_assertion_statement @@ -1418,6 +1418,10 @@ for_step /* IEEE1800-2005: A.6.8 */ { $$ = $1; } ; +for_step_opt + : for_step { $$ = $1; } + | { $$ = nullptr; } + ; /* The function declaration rule matches the function declaration header, then pushes the function scope. This causes the @@ -1616,7 +1620,7 @@ lifetime_opt /* IEEE1800-2005: A.2.1.3 */ /* Loop statements are kinds of statements. */ loop_statement /* IEEE1800-2005: A.6.8 */ - : K_for '(' lpvalue '=' expression ';' expression ';' for_step ')' + : K_for '(' lpvalue '=' expression ';' expression ';' for_step_opt ')' statement_or_null { PForStatement*tmp = new PForStatement($3, $5, $7, $9, $11); FILE_NAME(tmp, @1); @@ -1624,7 +1628,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */ } // The initialization statement is optional. - | K_for '(' ';' expression ';' for_step ')' + | K_for '(' ';' expression ';' for_step_opt ')' statement_or_null { PForStatement*tmp = new PForStatement(nullptr, nullptr, $4, $6, $8); FILE_NAME(tmp, @1); @@ -1635,7 +1639,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */ // statement in a synthetic named block. We can name the block // after the variable that we are creating, that identifier is // safe in the controlling scope. - | K_for '(' K_var_opt data_type IDENTIFIER '=' expression ';' expression ';' for_step ')' + | K_for '(' K_var_opt data_type IDENTIFIER '=' expression ';' expression ';' for_step_opt ')' { static unsigned for_counter = 0; char for_block_name [64]; snprintf(for_block_name, sizeof for_block_name, "$ivl_for_loop%u", for_counter); @@ -1726,7 +1730,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */ yyerror(@1, "error: Error in for loop step assignment."); } - | K_for '(' lpvalue '=' expression ';' error ';' for_step ')' + | K_for '(' lpvalue '=' expression ';' error ';' for_step_opt ')' statement_or_null { $$ = 0; yyerror(@1, "error: Error in for loop condition expression."); diff --git a/pform_dump.cc b/pform_dump.cc index 627aa2bb3..b23d1e0fd 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1158,7 +1158,10 @@ void PForStatement::dump(ostream&out, unsigned ind) const else out << ""; out << "; )" << endl; - step_->dump(out, ind+6); + if (step_) + step_->dump(out, ind+6); + else + out << setw(ind+6) << "" << "" << endl; if (statement_) statement_->dump(out, ind+3); else diff --git a/synth2.cc b/synth2.cc index 251ab4a79..c90d739f2 100644 --- a/synth2.cc +++ b/synth2.cc @@ -1458,6 +1458,11 @@ bool NetForLoop::synth_async(Design*des, NetScope*scope, return false; } + if (!step_statement_) { + cerr << get_fileline() << ": sorry: Unable to synthesize for-loop without for_step statement." << endl; + return false; + } + ivl_assert(*this, index_ && init_expr_); if (debug_synth2) { cerr << get_fileline() << ": NetForLoop::synth_async: "