Make the for_step of for loops optional

In IEEE Std 1800-2017 A.6.8: the for_step part of the for loop
is optional. If missing, it is assumed that the programmer known
what they are doing.
This commit is contained in:
Stephen Williams 2022-12-11 16:39:53 -08:00
parent bb779112c7
commit 5b9ceee062
6 changed files with 37 additions and 17 deletions

View File

@ -1388,7 +1388,8 @@ void NetForLoop::dump(ostream&fd, unsigned ind) const
fd << "<nil>";
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

View File

@ -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;
}

View File

@ -212,7 +212,7 @@ void NetForLoop::wrap_up()
// statement. This can happen for example with statments like this:
// for ( ; <condition> ; <step> ) <statement> ;
// 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);

14
parse.y
View File

@ -675,7 +675,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <event_statement> event_control
%type <statement> statement statement_item statement_or_null
%type <statement> compressed_statement
%type <statement> loop_statement for_step jump_statement
%type <statement> loop_statement for_step for_step_opt jump_statement
%type <statement> concurrent_assertion_statement
%type <statement> deferred_immediate_assertion_statement
%type <statement> 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.");

View File

@ -1158,7 +1158,10 @@ void PForStatement::dump(ostream&out, unsigned ind) const
else
out << "<no-cond>";
out << "; <for_step>)" << endl;
step_->dump(out, ind+6);
if (step_)
step_->dump(out, ind+6);
else
out << setw(ind+6) << "" << "<no for_step statement>" << endl;
if (statement_)
statement_->dump(out, ind+3);
else

View File

@ -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: "