Factor procedural block parsing

The sequential and parallel block grammar duplicates scope setup and teardown,
statement transfer, and closing label handling.

Move the common logic into `pform_start_block()` and
`pform_finish_block()`. This keeps the grammar actions focused on their
syntax-specific checks and makes both block forms use the same scope and
statement ownership paths without changing the accepted syntax.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2026-07-18 11:19:37 -07:00
parent 11af9fb3b3
commit dcc8e93d7e
1 changed files with 49 additions and 40 deletions

89
parse.y
View File

@ -594,6 +594,48 @@ static void procedural_item_list_add_declaration(const YYLTYPE&loc,
procedural_item_list_add_ports(list, ports); procedural_item_list_add_ports(list, ports);
} }
static PBlock *pform_start_block(const YYLTYPE&loc, const char *name,
PBlock::BL_TYPE block_type)
{
auto block = pform_push_block_scope(loc, name, block_type);
current_block_stack.push(block);
return block;
}
static PBlock *pform_finish_block(const YYLTYPE&block_loc,
const YYLTYPE&end_loc, const char *type,
char *raw_name, char *end_label,
PBlock::BL_TYPE block_type,
procedural_item_list_t *raw_items)
{
std::unique_ptr<char[]> name_ptr(raw_name);
std::unique_ptr<procedural_item_list_t> items(raw_items);
const char *name = name_ptr.get();
bool keep_scope = name || items->has_decls;
pform_pop_block_scope(keep_scope);
assert(! current_block_stack.empty());
auto block = current_block_stack.top();
current_block_stack.pop();
if (keep_scope) {
if (block_type != PBlock::BL_SEQ)
block->set_join_type(block_type);
} else {
delete block;
block = new PBlock(block_type);
FILE_NAME(block, block_loc);
}
if (items->statements)
block->set_statement(*items->statements);
check_end_label(end_loc, type, name, end_label);
return block;
}
static void port_declaration_context_init(void) static void port_declaration_context_init(void)
{ {
port_declaration_context.port_type = NetNet::PINOUT; port_declaration_context.port_type = NetNet::PINOUT;
@ -7315,28 +7357,13 @@ statement_item /* This is roughly statement_item in the LRM */
/* In SystemVerilog an unnamed block can contain variable declarations. */ /* In SystemVerilog an unnamed block can contain variable declarations. */
| K_begin label_opt | K_begin label_opt
{ PBlock*tmp = pform_push_block_scope(@1, $2, PBlock::BL_SEQ); { pform_start_block(@1, $2, PBlock::BL_SEQ); }
current_block_stack.push(tmp);
}
block_item_or_statement_list_opt K_end label_opt block_item_or_statement_list_opt K_end label_opt
{ std::unique_ptr<procedural_item_list_t> items($4); { if (!$2 && $4->has_decls) {
if (!$2 && items->has_decls) {
pform_block_decls_requires_sv(); pform_block_decls_requires_sv();
} }
bool keep_scope = $2 || items->has_decls; $$ = pform_finish_block(@1, @6, "block", $2, $6,
pform_pop_block_scope(keep_scope); PBlock::BL_SEQ, $4);
assert(! current_block_stack.empty());
auto tmp = current_block_stack.top();
current_block_stack.pop();
if (!keep_scope) {
delete tmp;
tmp = new PBlock(PBlock::BL_SEQ);
FILE_NAME(tmp, @1);
}
if (items->statements) tmp->set_statement(*items->statements);
check_end_label(@6, "block", $2, $6);
delete[]$2;
$$ = tmp;
} }
/* fork-join blocks are very similar to begin-end blocks. In fact, /* fork-join blocks are very similar to begin-end blocks. In fact,
@ -7346,30 +7373,12 @@ statement_item /* This is roughly statement_item in the LRM */
/* In SystemVerilog an unnamed block can contain variable declarations. */ /* In SystemVerilog an unnamed block can contain variable declarations. */
| K_fork label_opt | K_fork label_opt
{ PBlock*tmp = pform_push_block_scope(@1, $2, PBlock::BL_PAR); { pform_start_block(@1, $2, PBlock::BL_PAR); }
current_block_stack.push(tmp);
}
block_item_or_statement_list_opt join_keyword label_opt block_item_or_statement_list_opt join_keyword label_opt
{ std::unique_ptr<procedural_item_list_t> items($4); { if (!$2 && $4->has_decls) {
if (!$2 && items->has_decls) {
pform_requires_sv(@4, "Variable declaration in unnamed block"); pform_requires_sv(@4, "Variable declaration in unnamed block");
} }
bool keep_scope = $2 || items->has_decls; $$ = pform_finish_block(@1, @6, "fork", $2, $6, $5, $4);
pform_pop_block_scope(keep_scope);
assert(! current_block_stack.empty());
auto tmp = current_block_stack.top();
current_block_stack.pop();
if (keep_scope) {
tmp->set_join_type($5);
} else {
delete tmp;
tmp = new PBlock($5);
FILE_NAME(tmp, @1);
}
if (items->statements) tmp->set_statement(*items->statements);
check_end_label(@6, "fork", $2, $6);
delete[]$2;
$$ = tmp;
} }
| K_disable hierarchy_identifier ';' | K_disable hierarchy_identifier ';'