Skip to content

Commit 44e0f2e

Browse files
authored
Merge pull request #205 from diffblue/verilog-parser-scopes
Verilog: typedef
2 parents cabf866 + 9898ca4 commit 44e0f2e

File tree

10 files changed

+199
-31
lines changed

10 files changed

+199
-31
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
typedef1.sv
3+
--bound 0
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module main;
2+
3+
typedef bit [31:0] some_word_type;
4+
typedef bit signed [31:0] some_signed_type;
5+
6+
some_word_type some_word;
7+
some_signed_type some_signed;
8+
9+
p0: assert property ($bits(some_word) == 32);
10+
11+
endmodule

regression/verilog/data-types/typedef1.desc renamed to regression/verilog/typedef/typedef2.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
CORE
2-
typedef1.sv
2+
typedef2.sv
33

44
^EXIT=10$
55
^SIGNAL=0$

src/verilog/parser.y

Lines changed: 74 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Author: Daniel Kroening, [email protected]
2828
#define mts(x, y) stack_expr(x).move_to_sub((irept &)stack_expr(y))
2929
#define swapop(x, y) stack_expr(x).operands().swap(stack_expr(y).operands())
3030
#define addswap(x, y, z) stack_expr(x).add(y).swap(stack_expr(z))
31+
#define push_scope(x) PARSER.push_scope(x)
32+
#define pop_scope() PARSER.pop_scope();
3133

3234
int yyveriloglex();
3335
extern char *yyverilogtext;
@@ -542,6 +544,7 @@ int yyverilogerror(const char *error)
542544
/* Others */
543545
%token TOK_ENDOFFILE
544546
%token TOK_NON_TYPE_IDENTIFIER
547+
%token TOK_TYPE_IDENTIFIER
545548
%token TOK_NUMBER // number, any base
546549
%token TOK_TIME_LITERAL // number followed by time unit
547550
%token TOK_QSTRING // quoted string
@@ -621,10 +624,20 @@ description:
621624
| config_declaration
622625
;
623626

627+
// This deviates from the IEEE 1800-2017 grammar
628+
// to allow the module scope to be opened.
629+
module_identifier_with_scope:
630+
module_identifier
631+
{
632+
$$ = $1;
633+
push_scope(stack_expr($1).id());
634+
}
635+
;
636+
624637
module_nonansi_header:
625638
attribute_instance_brace
626639
module_keyword
627-
module_identifier
640+
module_identifier_with_scope
628641
parameter_port_list_opt
629642
list_of_ports_opt ';'
630643
{
@@ -640,7 +653,7 @@ module_nonansi_header:
640653
module_ansi_header:
641654
attribute_instance_brace
642655
module_keyword
643-
module_identifier
656+
module_identifier_with_scope
644657
parameter_port_list_opt
645658
list_of_port_declarations ';'
646659
{
@@ -663,6 +676,9 @@ module_declaration:
663676
stack_expr($1).operands()[3],
664677
stack_expr($1).operands()[4],
665678
stack_expr($2));
679+
680+
// close the module scope
681+
pop_scope();
666682
}
667683
| module_ansi_header module_item_brace TOK_ENDMODULE module_identifier_opt
668684
{
@@ -673,6 +689,9 @@ module_declaration:
673689
stack_expr($1).operands()[3],
674690
stack_expr($1).operands()[4],
675691
stack_expr($2));
692+
693+
// close the module scope
694+
pop_scope();
676695
}
677696
| TOK_EXTERN module_nonansi_header
678697
/* ignored for now */
@@ -960,9 +979,15 @@ net_declaration:
960979
swapop($$, $6); }
961980
;
962981

982+
// Note that the identifier that is defined using the typedef may be
983+
// an existing type or non-type identifier.
963984
type_declaration:
964-
TOK_TYPEDEF data_type type_identifier ';'
965-
{ init($$, ID_decl);
985+
TOK_TYPEDEF data_type new_identifier ';'
986+
{ // add to the scope as a type name
987+
auto &name = PARSER.add_name(stack_expr($3).get(ID_identifier));
988+
name.is_type = true;
989+
990+
init($$, ID_decl);
966991
stack_expr($$).set(ID_class, ID_typedef);
967992
addswap($$, ID_type, $2);
968993
mto($$, $3);
@@ -1033,9 +1058,8 @@ data_type:
10331058
{ init($$, ID_chandle); }
10341059
| TOK_VIRTUAL interface_opt interface_identifier
10351060
{ init($$, "virtual_interface"); }
1036-
/*
1037-
| scope_opt type_identifier packed_dimension_brace
1038-
*/
1061+
| /*scope_opt*/ type_identifier packed_dimension_brace
1062+
{ $$ = $1; stack_expr($$).id(ID_typedef_type); }
10391063
| class_type
10401064
| TOK_EVENT
10411065
{ init($$, ID_event); }
@@ -1451,17 +1475,22 @@ struct_union:
14511475
// A.2.6 Function declarations
14521476

14531477
function_declaration:
1454-
TOK_FUNCTION automatic_opt signing_opt range_or_type_opt
1455-
function_identifier list_of_ports_opt ';'
1456-
function_item_declaration_brace statement TOK_ENDFUNCTION
1478+
TOK_FUNCTION
1479+
automatic_opt signing_opt range_or_type_opt
1480+
function_identifier
1481+
{ push_scope(stack_expr($1).get(ID_identifier)); }
1482+
list_of_ports_opt ';'
1483+
function_item_declaration_brace statement
1484+
TOK_ENDFUNCTION
14571485
{ init($$, ID_decl);
14581486
stack_expr($$).set(ID_class, ID_function);
14591487
addswap($$, ID_type, $4);
14601488
add_as_subtype(stack_type($4), stack_type($3));
14611489
addswap($$, ID_symbol, $5);
1462-
addswap($$, ID_ports, $6);
1463-
addswap($$, "declarations", $8);
1464-
addswap($$, ID_body, $9);
1490+
addswap($$, ID_ports, $7);
1491+
addswap($$, "declarations", $9);
1492+
addswap($$, ID_body, $10);
1493+
pop_scope();
14651494
}
14661495
;
14671496

@@ -1500,15 +1529,18 @@ function_item_declaration:
15001529
// A.2.7 Task declarations
15011530

15021531
task_declaration:
1503-
TOK_TASK task_identifier list_of_ports_opt ';'
1532+
TOK_TASK task_identifier
1533+
{ push_scope(stack_expr($2).get(ID_identifier)); }
1534+
list_of_ports_opt ';'
15041535
task_item_declaration_brace
15051536
statement_or_null TOK_ENDTASK
15061537
{ init($$, ID_decl);
15071538
stack_expr($$).set(ID_class, ID_task);
15081539
addswap($$, ID_symbol, $2);
1509-
addswap($$, ID_ports, $3);
1510-
addswap($$, "declarations", $5);
1511-
addswap($$, ID_body, $6);
1540+
addswap($$, ID_ports, $4);
1541+
addswap($$, "declarations", $6);
1542+
addswap($$, ID_body, $7);
1543+
pop_scope();
15121544
}
15131545
;
15141546

@@ -2351,11 +2383,14 @@ seq_block:
23512383
TOK_END
23522384
{ init($$, ID_block); swapop($$, $2); }
23532385
| TOK_BEGIN TOK_COLON block_identifier
2386+
{ push_scope(stack_expr($3).id()); }
23542387
statement_or_null_brace
23552388
TOK_END
23562389
{ init($$, ID_block);
2357-
swapop($$, $4);
2358-
addswap($$, ID_identifier, $3); }
2390+
swapop($$, $5);
2391+
addswap($$, ID_identifier, $3);
2392+
pop_scope();
2393+
}
23592394
;
23602395

23612396
block_item_declaration_brace:
@@ -2841,6 +2876,17 @@ attr_name: identifier
28412876
// System Verilog standard 1800-2017
28422877
// A.9.3 Identifiers
28432878

2879+
// An extension of the System Verilog grammar to allow defining new types
2880+
// using an existing type or non-type identifier.
2881+
new_identifier:
2882+
type_identifier
2883+
| non_type_identifier
2884+
;
2885+
2886+
non_type_identifier: TOK_NON_TYPE_IDENTIFIER
2887+
{ new_symbol($$, $1); }
2888+
;
2889+
28442890
block_identifier: TOK_NON_TYPE_IDENTIFIER;
28452891

28462892
genvar_identifier: identifier;
@@ -2869,7 +2915,14 @@ ps_covergroup_identifier:
28692915

28702916
memory_identifier: identifier;
28712917

2872-
type_identifier: identifier;
2918+
type_identifier: TOK_TYPE_IDENTIFIER
2919+
{
2920+
init($$, ID_typedef_type);
2921+
auto base_name = stack_expr($1).id();
2922+
stack_expr($$).set(ID_C_base_name, base_name);
2923+
stack_expr($$).set(ID_identifier, PARSER.current_scope->prefix+id2string(base_name));
2924+
}
2925+
;
28732926

28742927
parameter_identifier: TOK_NON_TYPE_IDENTIFIER;
28752928

@@ -2905,9 +2958,7 @@ hierarchical_identifier:
29052958

29062959
hierarchical_variable_identifier: hierarchical_identifier;
29072960

2908-
identifier: TOK_NON_TYPE_IDENTIFIER
2909-
{ new_symbol($$, $1); }
2910-
;
2961+
identifier: non_type_identifier;
29112962

29122963
property_identifier: TOK_NON_TYPE_IDENTIFIER;
29132964

src/verilog/scanner.l

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,12 @@ static void preprocessor()
6363

6464
#define IDENTIFIER(text) \
6565
{ newstack(yyveriloglval); \
66-
stack_expr(yyveriloglval).id(text); \
67-
return TOK_NON_TYPE_IDENTIFIER; \
66+
irep_idt irep_id = text; \
67+
stack_expr(yyveriloglval).id(irep_id); \
68+
auto name = PARSER.lookup(irep_id); \
69+
return name == nullptr ? TOK_NON_TYPE_IDENTIFIER : \
70+
name->is_type ? TOK_TYPE_IDENTIFIER : \
71+
TOK_NON_TYPE_IDENTIFIER; \
6872
}
6973
#define SYSTEM_VERILOG_KEYWORD(x) \
7074
{ if(PARSER.mode==verilog_parsert::SYSTEM_VERILOG) \

src/verilog/verilog_interfaces.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ void verilog_typecheckt::interface_module_decl(
528528
}
529529
}
530530
}
531-
531+
532532
forall_operands(it2, decl)
533533
{
534534
if(it2->id()==ID_symbol)

src/verilog/verilog_parser.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,32 @@ bool parse_verilog_file(const std::string &filename)
5252

5353
return verilog_parser.parse();
5454
}
55+
56+
/*******************************************************************\
57+
58+
Function: verilog_parsert::lookup
59+
60+
Inputs:
61+
62+
Outputs:
63+
64+
Purpose:
65+
66+
\*******************************************************************/
67+
68+
const verilog_parsert::scopet *verilog_parsert::lookup(irep_idt name) const
69+
{
70+
// we start from the current scope, and walk upwards to the root
71+
auto scope = current_scope;
72+
while(scope != nullptr)
73+
{
74+
auto name_it = scope->scope_map.find(name);
75+
if(name_it == scope->scope_map.end())
76+
scope = scope->parent;
77+
else
78+
return &name_it->second; // found it
79+
}
80+
81+
// not found, give up
82+
return nullptr;
83+
}

src/verilog/verilog_parser.h

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ Author: Daniel Kroening, [email protected]
99
#ifndef VERILOG_PARSER_H
1010
#define VERILOG_PARSER_H
1111

12-
#include <string>
13-
14-
#include <util/parser.h>
1512
#include <util/mp_arith.h>
13+
#include <util/optional.h>
14+
#include <util/parser.h>
1615

1716
#include "verilog_parse_tree.h"
1817

18+
#include <map>
19+
#include <string>
20+
1921
int yyverilogparse();
2022

2123
class verilog_parsert:public parsert
@@ -47,7 +49,56 @@ class verilog_parsert:public parsert
4749
{
4850
dummy_id=0;
4951
}
50-
52+
53+
// parser scopes and identifiers
54+
struct scopet
55+
{
56+
scopet() : parent(nullptr), prefix("Verilog::")
57+
{
58+
}
59+
explicit scopet(irep_idt name, scopet *_parent)
60+
: parent(_parent),
61+
prefix(id2string(_parent->prefix) + id2string(name) + ".")
62+
{
63+
}
64+
scopet *parent = nullptr;
65+
bool is_type = false;
66+
using scope_mapt = std::map<irep_idt, scopet>;
67+
scope_mapt scope_map;
68+
std::string prefix;
69+
};
70+
71+
scopet top_scope, *current_scope = &top_scope;
72+
73+
scopet &add_name(irep_idt name)
74+
{
75+
auto result =
76+
current_scope->scope_map.emplace(name, scopet{name, current_scope});
77+
return result.first->second;
78+
}
79+
80+
// Create the given sub-scope of the current scope.
81+
void push_scope(irep_idt name)
82+
{
83+
current_scope = &add_name(name);
84+
}
85+
86+
void pop_scope()
87+
{
88+
PRECONDITION(current_scope->parent != nullptr);
89+
current_scope = current_scope->parent;
90+
}
91+
92+
// Look up an identifier, starting from the current scope,
93+
// going upwards until found. Returns nullptr when not found.
94+
const scopet *lookup(irep_idt) const;
95+
96+
bool is_type(irep_idt name) const
97+
{
98+
auto scope_ptr = lookup(name);
99+
return scope_ptr == nullptr ? false : scope_ptr->is_type;
100+
}
101+
51102
unsigned dummy_id;
52103

53104
std::string get_dummy_id()

src/verilog/verilog_typecheck_type.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,21 @@ typet verilog_typecheck_exprt::convert_type(const typet &src)
5959
result.add_source_location() = std::move(source_location);
6060
return result;
6161
}
62+
else if(src.id() == ID_typedef_type)
63+
{
64+
// Look it up!
65+
const symbolt *symbol_ptr;
66+
67+
auto identifier = src.get(ID_identifier);
68+
69+
if(ns.lookup(identifier, symbol_ptr))
70+
throw errort().with_location(source_location)
71+
<< "type symbol " << identifier << " not found";
72+
73+
DATA_INVARIANT(symbol_ptr->is_type, "typedef symbols must be types");
74+
75+
return symbol_ptr->type;
76+
}
6277
else if(src.id() == ID_array)
6378
{
6479
const exprt &range=static_cast<const exprt &>(src.find(ID_range));

0 commit comments

Comments
 (0)