% SystemVerilog Grammar This file contains a destilled version of the SystemVerilog grammar, which, as it is layed out in the standard, is a mixture of both syntax and semantics. # EXPRESSION primary primary assignment_operator expression => operator_assignment unary_operator primary "tagged" member_identifier [expression] => tagged_union_expression ("++"|"--") expression => inc_or_dec_expression expression binary_operator expression expression "inside" "{" open_range_list "}" => inside_expression expression "matches" pattern => cond_predicate expression "&&&" expression_or_cond_pattern => cond_predicate expression "?" expression ":" expression => conditional_expression expression ("++"|"--") => inc_or_dec_expression expression "." identifier expression "." "super" expression "::" identifier expression "[" range_expression "]" expression "(" [list_of_arguments] ")" => function_subroutine_call # PRIMARY "this" "super" "$" "null" "$root" "$unit" primary_literal "{" "}" => empty_queue "(" expression ")" "(" expression ":" expression ":" expression ")" => mintypmax_expression "{" expression {"," expression} "}" => concatenation "{" expression "{" expression {"," expression} "}" "}" => multiple_concatenation "{" ("<<"|">>") [slice_size] stream_concatenation "}" => streaming_concatenation ## Ignored casting_type "'" "(" expression ")" => cast assignment_pattern_expression_type assignment_pattern => assignment_pattern_expression # RANGE EXPRESSION expression expression ":" expression => range expression ("+:"|"-:") expression => indexed_range # LIST OF PORTS According to the standard, the formal syntax for both ANSI and non-ANSI module ports is as follows: // header module_nonansi_header := {attribute_instance} module_keyword [lifetime] module_identifier {package_import_declaration} [parameter_port_list] list_of_ports ";" module_ansi_header := {attribute_instance} module_keyword [lifetime] module_identifier {package_import_declaration} [parameter_port_list] [list_of_port_declarations] ";" // non-ANSI style list_of_ports := "(" port {"," port} ")" port := [port_expression] := "." port_identifier "(" [port_expression] ")" port_expression := port_reference := "{" port_reference {"," port_reference} "}" port_reference := port_identifier constant_select // ANSI style list_of_port_declarations := "(" [{attribute_instance} ansi_port_declaration {"," {attribute_instance} ansi_port_declaration}] ")" ansi_port_declaration := [net_port_header | interface_port_header] port_identifier {unpacked_dimension} ["=" constant_expression] := [variable_port_header] port_identifier {variable_dimension} ["=" constant_expression] := [port_direction] "." port_identifier "(" [expression] ")" net_port_header := [port_direction] net_port_type variable_port_header := [port_direction] variable_port_type interface_port_header := interface_identifier ["." modport_identifier] := "interface" ["." modport_identifier] port_direction := "input" | "output" | "inout" | "ref" net_port_type := [net_type] data_type_or_implicit variable_port_type := data_type := "var" data_type_or_implicit To maintain sanity, the ANSI and non-ANSI variants shall be collapsed into one, and the verification that a list of declarations is provided in the ANSI case shall be performed at a later stage, once the AST has been built. module_header := {attribute_instance} module_keyword [lifetime] module_identifier {package_import_declaration} [parameter_port_list] [list_of_ports] ";" list_of_ports := "(" [{attribute_instance} port {"," {attribute_instance} port}] ")" port := [port_expression] := [net_port_header | interface_port_header] port_identifier {unpacked_dimension} ["=" constant_expression] := [variable_port_header] port_identifier {variable_dimension} ["=" constant_expression] := [port_direction] "." port_identifier "(" [expression] ")" port_expression := port_reference := "{" port_reference {"," port_reference} "}" port_reference := port_identifier constant_select net_port_header := [port_direction] net_port_type variable_port_header := [port_direction] variable_port_type interface_port_header := interface_identifier ["." modport_identifier] := "interface" ["." modport_identifier] port_direction := "input" | "output" | "inout" | "ref" net_port_type := [net_type] data_type_or_implicit variable_port_type := data_type := "var" data_type_or_implicit Removing all sorts of semantics from the port syntax, postponing verification interpretation to when the AST has been built, we arrive at the following syntax. Also, support for attribute instances shall be dropped for now. module_header := module_keyword [lifetime] module_identifier {package_import_declaration} [parameter_port_list] [list_of_ports] ";" list_of_ports := "(" [port {"," port}] ")" port := "{" port_reference {"," port_reference} "}" := [port_direction] [port_header] port_identifier {"[" range_expression "]"} ["=" constant_expression] := [port_direction] "." port_identifier "(" [expression] ")" port_reference := port_identifier {"[" range_expression "]"} port_header := [net_type | "var"] data_type_or_implicit := (interface_identifier | "interface") ["." modport_identifier] -> interface_port_header port_direction := "input" | "output" | "inout" | "ref" net_type := "supply0" | "supply1" | "tri" | "triand" | "trior" | "trireg" | "tri0" | "tri1" | "uwire" | "wire" | "wand" | "wor" port_with_first_class_types := "{" expression {"," expression} "}" := [port_direction] expression expression "=" expression /* careful about precedence */ := [port_direction] "." identifier "(" [expression] ")"