Parsing of SystemVerilog-2012 ANSI-style port declarations.
Here's the basic grammar:
list_of_port_declarations ::= '(' [ {attribute_instance} ansi_port_declaration { ',' {attribute_instance} ansi_port_declaration } ] ')' ansi_port_declaration ::= [ net_port_header | interface_port_header ] identifier {unpacked_dimension} [ '=' expression ] | [ variable_port_header ] identifier {variable_dimension} [ '=' expression ] | [ port_direction ] '.' identifier '(' [expression] ')' net_port_header ::= [port_direction] net_port_type interface_port_header ::= identifier [ '.' identifier ] | 'interface' [ '.' identifier ] variable_port_header ::= [port_direction] variable_port_type port_direction ::= 'input' | 'output' | 'inout' | 'ref'
There are also some footnotes. Section 23.2.2.2 imposes various semantic restrictions, e.g.,: a ref port shall be a variable type and an inout port shall not be; it shall be illegal to initialize a port that is not a variable output port or to specify a default value for a port that is not an input port.
Section 23.2.2.3 also gives a LOT of subtle rules regarding how the directions/kinds get inherited across the list of port declarations, etc. See sv-ansi-port-interpretation.
We have decided to NOT yet implement the third kind of
ansi_port_declaration ::= [ port_direction ] '.' identifier '(' [expression] ')'
If we do want to come back and implement this some day, we will need to figure out a way to reconcile the lack of port declarations for the wires in the expression. That is, back in the Verilog-2005 days, we could expect that a port such as:
module mymod (.foo( {a, b} ), ...)
Would be followed up with port declarations for A and B. However, these new SystemVerilog ANSI-style declarations don't seem to have any such corresponding port declarations. It would likely take a bit of work to get transforms like argresolve, replicate, and toe, to cope with this.
Anyway, this simplification means we're only going to try to support:
ansi_port_declaration ::= [ net_port_header | interface_port_header ] identifier {unpacked_dimension} [ '=' expression ] | [ variable_port_header ] identifier {variable_dimension} [ '=' expression ]
Furthermore, we'll not support default expressions yet (we don't support them on non-ANSI ports yet, either) and since we don't really have any support for fancy dimensions, what we'll really try to implement is just:
ansi_port_declaration ::= net_port_header identifier {unpacked_dimension} | variable_port_header identifier {variable_dimension} | interface_port_header identifier {unpacked_dimension} net_port_header ::= [port_direction] net_port_type variable_port_header ::= [port_direction] variable_port_type interface_port_header ::= identifier [ '.' identifier ] | 'interface' [ '.' identifier ]
The tricky part of this is dealing with port types. See parse-port-types for notes about how we distinguish between