| /* Copyright 2017-2020 The Verible Authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| %code requires{ |
| #include "common/parser/parser_param.h" |
| } |
| |
| %{ |
| /** |
| verilog.y |
| yacc/bison LR(1) grammar for SystemVerilog. |
| |
| The syntax tree constructed by the semantic actions in this file are |
| fragile and subject to change without notice. |
| Functionality that relies directly on this structure should be isolated under |
| //verilog/CST/... (concrete syntax tree) and unit-tested accordingly. |
| **/ |
| |
| #include "common/parser/bison_parser_common.h" |
| #include "common/text/tree_utils.h" |
| #include "common/util/casts.h" |
| #include "common/util/logging.h" |
| #include "verilog/CST/declaration.h" |
| #include "verilog/CST/DPI.h" |
| #include "verilog/CST/expression.h" |
| #include "verilog/CST/functions.h" |
| #include "verilog/CST/module.h" |
| #include "verilog/CST/parameters.h" |
| #include "verilog/CST/port.h" |
| #include "verilog/CST/verilog_nonterminals.h" |
| #include "verilog/CST/verilog_treebuilder_utils.h" |
| |
| /*** |
| * Verilog Language Standard (IEEE 1364-2005): |
| * http://ieeexplore.ieee.org/xpl/mostRecentIssue.jsp?punumber=10779 |
| * |
| * System Verilog (IEEE 1800-2017): |
| * https://standards.ieee.org/standard/1800-2017.html |
| * This is the Language Reference Manual, or LRM. |
| * |
| * Verilog-AMS: |
| * http://www.accellera.org/images/downloads/standards/v-ams/VAMS-LRM-2-4.pdf |
| * |
| * System Verilog Assertions: |
| * http://www.eecs.umich.edu/courses/eecs578/eecs578.f15/miniprojects/SVAproject/manuals/SVA_manual.pdf |
| * http://vlsi.pro/sva-sequences-other-operators/ |
| **/ |
| |
| |
| namespace verilog { |
| |
| using verible::ParserParam; |
| using verible::MakeNode; |
| using verible::MakeTaggedNode; |
| using verible::ExtendNode; |
| using verible::ForwardChildren; |
| using verible::SetChild; |
| using verible::SymbolCastToNode; |
| using verible::SymbolPtr; |
| using verible::SyntaxTreeNode; |
| using verible::down_cast; |
| |
| using N = NodeEnum; |
| |
| constexpr std::nullptr_t qualifier_placeholder = nullptr; |
| constexpr std::nullptr_t expression_placeholder = nullptr; |
| |
| |
| using std::move; |
| |
| static std::nullptr_t Recover() { |
| // TODO(fangism): return a useful ErrorNode or ErrorToken, using the |
| // most recent recovered error token in the ParserParam. |
| return nullptr; |
| } |
| |
| // Transforms: |
| // (sublist, separator), item -> sublist +separator +item |
| // TODO(fangism): if generally useful, factor into concrete_syntax_tree.h |
| static SymbolPtr ExtendFirstSublist(SymbolPtr& pair, SymbolPtr item) { |
| // pair node is a 2-tuple (sublist, separator), |
| // where sublist is a SyntaxTreeNode. |
| auto& pair_node = down_cast<SyntaxTreeNode&>(*pair); |
| auto& sublist = pair_node[0]; |
| auto& separator = pair_node[1]; |
| return ExtendNode(sublist, separator, item); |
| } |
| |
| // Transforms: |
| // (..., sublist), item -> (..., sublist +item) |
| static SymbolPtr ExtendLastSublist(SymbolPtr& list, SymbolPtr& item) { |
| auto& list_node = down_cast<SyntaxTreeNode&>(*list); |
| auto& last_sublist = down_cast<SyntaxTreeNode&>( |
| *list_node.mutable_children().back()); |
| last_sublist.Append(move(item)); |
| return move(list); |
| } |
| |
| // Transforms: |
| // ((..., sublist), separator), item -> (..., sublist +separator +item) |
| static SymbolPtr ExtendLastSublistWithSeparator( |
| SymbolPtr& pair, SymbolPtr& item) { |
| auto& pair_node = down_cast<SyntaxTreeNode&>(*pair); |
| auto& list = pair_node[0]; |
| auto& separator = pair_node[1]; |
| /* Extend the last sublist. */ |
| auto& list_node = down_cast<SyntaxTreeNode&>(*list); |
| auto& sublist_node = down_cast<SyntaxTreeNode&>( |
| *list_node.mutable_children().back()); |
| sublist_node.Append(move(separator), move(item)); |
| return move(list); |
| } |
| |
| // (Below): These helper forwarding functions help ensure consistent structure, |
| // and check that the correct number of arguments are passed: |
| |
| static SymbolPtr MakePackedDimensionsNode(SymbolPtr& arg) { |
| return MakeTaggedNode(N::kPackedDimensions, arg); |
| } |
| |
| static SymbolPtr MakeUnpackedDimensionsNode(SymbolPtr& arg) { |
| return MakeTaggedNode(N::kUnpackedDimensions, arg); |
| } |
| |
| %} |
| |
| %debug |
| %verbose |
| %expect 0 |
| %define api.pure |
| %param { ::verible::ParserParam* param } |
| /* TODO(fangism): this prefix name should point to an adaptation of yylex */ |
| %define api.prefix {verilog_} |
| %define api.value.type {::verible::SymbolPtr} |
| |
| // LINT.IfChange |
| %token PP_Identifier |
| %token PP_include "`include" |
| %token PP_define "`define" |
| %token PP_define_body "<<`define-tokens>>" |
| %token PP_ifdef "`ifdef" |
| %token PP_ifndef "`ifndef" |
| /* `if doesn't exist for Verilog */ |
| %token PP_else "`else" |
| %token PP_elsif "`elsif" |
| %token PP_endif "`endif" |
| %token PP_undef "`undef" |
| %token PP_default_text "<<default-text>>" |
| %token PP_TOKEN_CONCAT "``" |
| |
| %token DR_timescale "`timescale" |
| %token DR_resetall "`resetall" |
| %token DR_celldefine "`celldefine" |
| %token DR_endcelldefine "`endcelldefine" |
| %token DR_unconnected_drive "`unconnected_drive" |
| %token DR_nounconnected_drive "`nounconnected_drive" |
| %token DR_default_nettype "`default_nettype" |
| %token DR_suppress_faults "`suppress_faults" |
| %token DR_nosuppress_faults "`nosuppress_faults" |
| %token DR_enable_portfaults "`enable_portfaults" |
| %token DR_disable_portfaults "`disable_portfaults" |
| %token DR_delay_mode_distributed "`delay_mode_distributed" |
| %token DR_delay_mode_path "`delay_mode_path" |
| %token DR_delay_mode_unit "`delay_mode_unit" |
| %token DR_delay_mode_zero "`delay_mode_zero" |
| %token DR_default_decay_time "`default_decay_time" |
| %token DR_default_trireg_strength "`default_trireg_strength" |
| %token DR_pragma "`pragma" |
| %token DR_uselib "`uselib" |
| %token DR_begin_keywords "`begin_keywords" |
| %token DR_end_keywords "`end_keywords" |
| %token DR_protect "`protect" |
| %token DR_endprotect "`endprotect" |
| |
| |
| /** |
| The grammar in the SystemVerilog LRM is written in terms of type-specific |
| identifiers, like module_identifier and class_identifier, however, |
| without preprocessing, we cannot know the type of an identifier that |
| is not locally defined, so the grammar here uses only generic identifiers. |
| **/ |
| |
| // gen_tokenizer annotations existed in the original verilog.y grammar |
| // which was a way to generate a syntax highlighter. |
| // TODO(fangism): Remove these if they are not useful. |
| |
| // gen_tokenizer start IDENTIFIER |
| %token SymbolIdentifier // encapsulates all of the above |
| %token EscapedIdentifier // starts with \ and ends with whitespace |
| %token SystemTFIdentifier // $identifier |
| %token MacroIdentifier // `identifier |
| %token MacroCallId |
| %token MacroIdItem |
| %token MacroNumericWidth |
| // gen_tokenizer stop |
| |
| // gen_tokenizer start NUMERIC_LITERAL |
| %token TK_DecNumber // DEC_NUMBER |
| %token TK_RealTime // REALTIME |
| %token TK_TimeLiteral // TIME_LITERAL |
| %token TK_DecBase |
| %token TK_DecDigits |
| %token TK_XZDigits |
| %token TK_BinBase |
| %token TK_BinDigits |
| %token TK_OctBase |
| %token TK_OctDigits |
| %token TK_HexBase |
| %token TK_HexDigits |
| %token TK_UnBasedNumber // UNBASED_NUMBER |
| // gen_tokenizer stop |
| |
| // gen_tokenizer start STRING_LITERAL |
| %token TK_StringLiteral // STRING |
| %token TK_EvalStringLiteral // STRING |
| // gen_tokenizer stop |
| |
| // gen_tokenizer start KEYWORD |
| /* The base tokens from 1364-1995. */ |
| %token TK_1step "1step" |
| %token TK_always "always" |
| %token TK_and "and" |
| %token TK_assign "assign" |
| %token TK_begin "begin" |
| %token TK_buf "buf" |
| %token TK_bufif0 "bufif0" |
| %token TK_bufif1 "bufif1" |
| %token TK_case "case" |
| %token TK_casex "casex" |
| %token TK_casez "casez" |
| %token TK_cmos "cmos" |
| %token TK_deassign "deassign" |
| %token TK_default "default" |
| %token TK_defparam "defparam" |
| %token TK_disable "disable" |
| %token TK_edge "edge" |
| %token TK_else "else" |
| %token TK_end "end" |
| %token TK_endcase "endcase" |
| %token TK_endfunction "endfunction" |
| %token TK_endmodule "endmodule" |
| %token TK_endprimitive "endprimitive" |
| %token TK_endspecify "endspecify" |
| %token TK_endtable "endtable" |
| %token TK_endtask "endtask" |
| %token TK_event "event" |
| %token TK_for "for" |
| %token TK_force "force" |
| %token TK_forever "forever" |
| %token TK_fork "fork" |
| %token TK_function "function" |
| %token TK_highz0 "highz0" |
| %token TK_highz1 "highz1" |
| %token TK_if "if" |
| %token TK_ifnone "ifnone" |
| %token TK_initial "initial" |
| %token TK_inout "inout" |
| %token TK_input "input" |
| %token TK_integer "integer" |
| %token TK_join "join" |
| %token TK_large "large" |
| %token TK_macromodule "macromodule" |
| %token TK_medium "medium" |
| %token TK_module "module" |
| %token TK_nand "nand" |
| %token TK_negedge "negedge" |
| %token TK_nmos "nmos" |
| %token TK_nor "nor" |
| %token TK_not "not" |
| %token TK_notif0 "notif0" |
| %token TK_notif1 "notif1" |
| %token TK_or "or" |
| %token TK_option "option" |
| %token TK_output "output" |
| %token TK_parameter "parameter" |
| %token TK_pmos "pmos" |
| %token TK_posedge "posedge" |
| %token TK_primitive "primitive" |
| %token TK_pull0 "pull0" |
| %token TK_pull1 "pull1" |
| %token TK_pulldown "pulldown" |
| %token TK_pullup "pullup" |
| %token TK_rcmos "rcmos" |
| %token TK_real "real" |
| %token TK_realtime "realtime" |
| %token TK_reg "reg" |
| %token TK_release "release" |
| %token TK_repeat "repeat" |
| %token TK_rnmos "rnmos" |
| %token TK_rpmos "rpmos" |
| %token TK_rtran "rtran" |
| %token TK_rtranif0 "rtranif0" |
| %token TK_rtranif1 "rtranif1" |
| %token TK_sample "sample" |
| %token TK_scalared "scalared" |
| %token TK_small "small" |
| %token TK_specify "specify" |
| %token TK_specparam "specparam" |
| %token TK_strong0 "strong0" |
| %token TK_strong1 "strong1" |
| %token TK_supply0 "supply0" |
| %token TK_supply1 "supply1" |
| %token TK_table "table" |
| %token TK_task "task" |
| %token TK_time "time" |
| %token TK_tran "tran" |
| %token TK_tranif0 "tranif0" |
| %token TK_tranif1 "tranif1" |
| %token TK_tri "tri" |
| %token TK_tri0 "tri0" |
| %token TK_tri1 "tri1" |
| %token TK_triand "triand" |
| %token TK_trior "trior" |
| %token TK_trireg "trireg" |
| %token TK_type_option "type_option" |
| %token TK_vectored "vectored" |
| %token TK_wait "wait" |
| %token TK_wand "wand" |
| %token TK_weak0 "weak0" |
| %token TK_weak1 "weak1" |
| %token TK_while "while" |
| %token TK_wire "wire" |
| %token TK_wor "wor" |
| %token TK_xnor "xnor" |
| %token TK_xor "xor" |
| %token TK_Shold "$hold" |
| %token TK_Snochange "$nochange" |
| %token TK_Speriod "$period" |
| %token TK_Srecovery "$recovery" |
| %token TK_Ssetup "$setup" |
| %token TK_Ssetuphold "$setuphold" |
| %token TK_Sskew "$skew" |
| %token TK_Swidth "$width" |
| /* Icarus specific tokens. */ |
| %token TKK_attribute "$attribute" |
| %token TK_bool "bool" |
| /* The new tokens from 1364-2001. */ |
| %token TK_automatic "automatic" |
| %token TK_endgenerate "endgenerate" |
| %token TK_generate "generate" |
| %token TK_genvar "genvar" |
| %token TK_localparam "localparam" |
| %token TK_noshowcancelled "noshowcancelled" |
| %token TK_pulsestyle_onevent "pulsestyle_onevent" |
| %token TK_pulsestyle_ondetect "pulsestyle_ondetect" |
| %token TK_showcancelled "showcancelled" |
| %token TK_signed "signed" |
| %token TK_unsigned "unsigned" |
| %token TK_Sfullskew "$fullskew" |
| %token TK_Srecrem "$recrem" |
| %token TK_Sremoval "$removal" |
| %token TK_Stimeskew "$timeskew" |
| /* The 1364-2001 configuration tokens. */ |
| %token TK_cell "cell" |
| %token TK_config "config" |
| %token TK_design "design" |
| %token TK_endconfig "endconfig" |
| %token TK_incdir "incdir" |
| %token TK_include "include" |
| %token TK_instance "instance" |
| %token TK_liblist "liblist" |
| %token TK_library "library" |
| %token TK_use "use" |
| /* The new tokens from 1364-2005. */ |
| %token TK_wone "wone" |
| %token TK_uwire "uwire" |
| /* The new tokens from 1800-2005. */ |
| %token TK_alias "alias" |
| %token TK_always_comb "always_comb" |
| %token TK_always_ff "always_ff" |
| %token TK_always_latch "always_latch" |
| %token TK_assert "assert" |
| %token TK_assume "assume" |
| %token TK_before "before" |
| %token TK_bind "bind" |
| %token TK_bins "bins" |
| %token TK_binsof "binsof" |
| %token TK_bit "bit" |
| %token TK_break "break" |
| %token TK_byte "byte" |
| %token TK_chandle "chandle" |
| %token TK_class "class" |
| %token TK_clocking "clocking" |
| %token TK_const "const" |
| %token TK_constraint "constraint" |
| %token TK_context "context" |
| %token TK_continue "continue" |
| %token TK_cover "cover" |
| %token TK_covergroup "covergroup" |
| %token TK_coverpoint "coverpoint" |
| %token TK_cross "cross" |
| %token TK_dist "dist" |
| %token TK_do "do" |
| %token TK_endclass "endclass" |
| %token TK_endclocking "endclocking" |
| %token TK_endgroup "endgroup" |
| %token TK_endinterface "endinterface" |
| %token TK_endpackage "endpackage" |
| %token TK_endprogram "endprogram" |
| %token TK_endproperty "endproperty" |
| %token TK_endsequence "endsequence" |
| %token TK_enum "enum" |
| %token TK_expect "expect" |
| %token TK_export "export" |
| %token TK_extends "extends" |
| %token TK_extern "extern" |
| %token TK_final "final" |
| %token TK_first_match "first_match" |
| %token TK_foreach "foreach" |
| %token TK_forkjoin "forkjoin" |
| %token TK_iff "iff" |
| %token TK_ignore_bins "ignore_bins" |
| %token TK_illegal_bins "illegal_bins" |
| %token TK_import "import" |
| %token TK_inside "inside" |
| %token TK_int "int" |
| %token TK_interface "interface" |
| %token TK_intersect "intersect" |
| %token TK_join_any "join_any" |
| %token TK_join_none "join_none" |
| %token TK_local "local" |
| %token TK_local_SCOPE "local::" |
| %token TK_logic "logic" |
| %token TK_longint "longint" |
| %token TK_matches "matches" |
| %token TK_modport "modport" |
| %token TK_new "new" |
| %token TK_null "null" |
| %token TK_package "package" |
| %token TK_packed "packed" |
| %token TK_priority "priority" |
| %token TK_program "program" |
| %token TK_property "property" |
| %token TK_protected "protected" |
| %token TK_pure "pure" |
| %token TK_rand "rand" |
| %token TK_randc "randc" |
| %token TK_randcase "randcase" |
| %token TK_randsequence "randsequence" |
| %token TK_randomize "randomize" |
| %token TK_ref "ref" |
| %token TK_return "return" |
| %token TK_Sroot "$root" |
| %token TK_sequence "sequence" |
| %token TK_shortint "shortint" |
| %token TK_shortreal "shortreal" |
| %token TK_solve "solve" |
| %token TK_static "static" |
| %token TK_string "string" |
| %token TK_struct "struct" |
| %token TK_super "super" |
| %token TK_tagged "tagged" |
| %token TK_this "this" |
| %token TK_throughout "throughout" |
| %token TK_timeprecision "timeprecision" |
| %token TK_timeunit "timeunit" |
| %token TK_timescale_unit "(timescale_unit)" |
| %token TK_type "type" |
| %token TK_typedef "typedef" |
| %token TK_union "union" |
| %token TK_unique "unique" |
| %token TK_unique_index "unique_index" |
| %token TK_Sunit "$unit" |
| %token TK_var "var" |
| %token TK_virtual "virtual" |
| %token TK_void "void" |
| %token TK_wait_order "wait_order" |
| %token TK_wildcard "wildcard" |
| %token TK_with "with" |
| %token TK_with__covergroup "with(covergroup)" |
| %token TK_within "within" |
| /* Fake tokens that are passed once we have an initial token. */ |
| %token TK_timeprecision_check "timeprecision_check" |
| /* The new tokens from 1800-2009. */ |
| %token TK_timeunit_check "timeunit_check" |
| %token TK_accept_on "accept_on" |
| %token TK_checker "checker" |
| %token TK_endchecker "endchecker" |
| %token TK_eventually "eventually" |
| %token TK_global "global" |
| %token TK_implies "implies" |
| %token TK_let "let" |
| %token TK_nexttime "nexttime" |
| %token TK_reject_on "reject_on" |
| %token TK_restrict "restrict" |
| %token TK_s_always "s_always" |
| %token TK_s_eventually "s_eventually" |
| %token TK_s_nexttime "s_nexttime" |
| %token TK_s_until "s_until" |
| %token TK_s_until_with "s_until_with" |
| %token TK_strong "strong" |
| %token TK_sync_accept_on "sync_accept_on" |
| %token TK_sync_reject_on "sync_reject_on" |
| %token TK_unique0 "unique0" |
| %token TK_until "until" |
| %token TK_until_with "until_with" |
| %token TK_untyped "untyped" |
| %token TK_weak "weak" |
| /* The new tokens from 1800-2012. */ |
| %token TK_implements "implements" |
| %token TK_interconnect "interconnect" |
| %token TK_nettype "nettype" |
| %token TK_soft "soft" |
| /* The new tokens for Verilog-AMS 2.3. */ |
| %token TK_above "above" |
| %token TK_abs "abs" |
| %token TK_absdelay "absdelay" |
| %token TK_abstol "abstol" |
| %token TK_access "access" |
| %token TK_acos "acos" |
| %token TK_acosh "acosh" |
| %token TK_ac_stim "ac_stim" |
| %token TK_aliasparam "aliasparam" |
| %token TK_analog "analog" |
| %token TK_analysis "analysis" |
| %token TK_asin "asin" |
| %token TK_asinh "asinh" |
| %token TK_atan "atan" |
| %token TK_atan2 "atan2" |
| %token TK_atanh "atanh" |
| %token TK_branch "branch" |
| %token TK_ceil "ceil" |
| %token TK_connect "connect" |
| %token TK_connectmodule "connectmodule" |
| %token TK_connectrules "connectrules" |
| %token TK_continuous "continuous" |
| %token TK_cos "cos" |
| %token TK_cosh "cosh" |
| %token TK_ddt "ddt" |
| %token TK_ddt_nature "ddt_nature" |
| %token TK_ddx "ddx" |
| %token TK_discipline "discipline" |
| %token TK_discrete "discrete" |
| %token TK_domain "domain" |
| %token TK_driver_update "driver_update" |
| %token TK_endconnectrules "endconnectrules" |
| %token TK_enddiscipline "enddiscipline" |
| %token TK_endnature "endnature" |
| %token TK_endparamset "endparamset" |
| %token TK_exclude "exclude" |
| %token TK_exp "exp" |
| %token TK_final_step "final_step" |
| %token TK_flicker_noise "flicker_noise" |
| %token TK_floor "floor" |
| %token TK_flow "flow" |
| %token TK_from "from" |
| %token TK_ground "ground" |
| %token TK_hypot "hypot" |
| %token TK_idt "idt" |
| %token TK_idtmod "idtmod" |
| %token TK_idt_nature "idt_nature" |
| %token TK_inf "inf" |
| %token TK_infinite "infinite" /* `default_decay_time argument */ |
| %token TK_initial_step "initial_step" |
| %token TK_laplace_nd "laplace_nd" |
| %token TK_laplace_np "laplace_np" |
| %token TK_laplace_zd "laplace_zd" |
| %token TK_laplace_zp "laplace_zp" |
| %token TK_last_crossing "last_crossing" |
| %token TK_limexp "limexp" |
| %token TK_ln "ln" |
| %token TK_log "log" |
| %token TK_max "max" |
| %token TK_merged "merged" |
| %token TK_min "min" |
| %token TK_nature "nature" |
| %token TK_net_resolution "net_resolution" |
| %token TK_noise_table "noise_table" |
| %token TK_paramset "paramset" |
| %token TK_potential "potential" |
| %token TK_pow "pow" |
| %token TK_resolveto "resolveto" |
| %token TK_sin "sin" |
| %token TK_sinh "sinh" |
| %token TK_slew "slew" |
| %token TK_split "split" |
| %token TK_sqrt "sqrt" |
| %token TK_tan "tan" |
| %token TK_tanh "tanh" |
| %token TK_timer "timer" |
| %token TK_transition "transition" |
| %token TK_units "units" |
| %token TK_white_noise "white_noise" |
| %token TK_wreal "wreal" |
| %token TK_zi_nd "zi_nd" |
| %token TK_zi_np "zi_np" |
| %token TK_zi_zd "zi_zd" |
| %token TK_zi_zp "zi_zp" |
| |
| // built-in methods |
| %token TK_find "find" |
| %token TK_find_index "find_index" |
| %token TK_find_first "find_first" |
| %token TK_find_first_index "find_first_index" |
| %token TK_find_last "find_last" |
| %token TK_find_last_index "find_last_index" |
| |
| %token TK_sort "sort" |
| %token TK_rsort "rsort" |
| %token TK_reverse "reverse" |
| %token TK_shuffle "shuffle" |
| |
| %token TK_sum "sum" |
| %token TK_product "product" |
| // gen_tokenizer stop |
| |
| // operator tokens |
| %token TK_PLUS_EQ "+=" |
| %token TK_MINUS_EQ "-=" |
| %token TK_MUL_EQ "*=" |
| %token TK_DIV_EQ "/=" |
| %token TK_MOD_EQ "%=" |
| |
| %token TK_AND_EQ "&=" |
| %token TK_OR_EQ "|=" |
| %token TK_XOR_EQ "^=" |
| |
| %token TK_INCR "++" |
| %token TK_DECR "--" |
| // TODO(b/63595640): Disambiguate between use as less-equal, |
| // nonblocking_assignment, and clocking_drive. |
| %token TK_LE "<=" |
| %token TK_GE ">=" |
| %token TK_EG "=>" |
| %token TK_EQ "==" |
| %token TK_WILDCARD_EQ "==?" |
| %token TK_NE "!=" |
| %token TK_WILDCARD_NE "!=?" |
| %token TK_CEQ "===" |
| %token TK_CNE "!==" |
| %token TK_LP "'{" |
| %token TK_LS "<<" |
| // or "<<<" |
| %token TK_RS ">>" |
| %token TK_RSS ">>>" |
| %token TK_SG "*>" |
| %token TK_CONTRIBUTE "<+" |
| %token TK_PO_POS "+:" |
| %token TK_PO_NEG "-:" |
| %token TK_POW "**" |
| %token TK_PSTAR "(*" |
| %token TK_STARP "*)" |
| %token TK_DOTSTAR ".*" |
| %token TK_LOR "||" |
| %token TK_LAND "&&" |
| %token TK_TAND "&&&" |
| %token TK_NAND "~&" |
| %token TK_NOR "~|" |
| %token TK_NXOR "~^" |
| // or "^~" |
| %token TK_LOGEQUIV "<->" |
| |
| %token TK_NONBLOCKING_TRIGGER "->>" |
| %token _TK_RARROW "->" |
| // _TK_RARROW is disambiguated into one of the following symbols |
| // (see verilog_lexical_context.cc): |
| %token TK_TRIGGER "->(trigger)" |
| %token TK_LOGICAL_IMPLIES "->(logical-implies)" |
| %token TK_CONSTRAINT_IMPLIES "->(constraint-implies)" |
| |
| %token TK_SCOPE_RES "::" |
| %token TK_COLON_EQ ":=" |
| %token TK_COLON_DIV ":/" |
| %token TK_POUNDPOUND "##" |
| %token TK_edge_descriptor |
| %token TK_LBSTARRB "[*]" |
| %token TK_LBPLUSRB "[+]" |
| %token TK_LBSTAR "[*" |
| %token TK_LBEQ "[=" |
| %token TK_LBRARROW "[->" |
| %token TK_PIPEARROW "|->" |
| %token TK_PIPEARROW2 "|=>" |
| %token TK_POUNDMINUSPOUND "#-#" |
| %token TK_POUNDEQPOUND "#=#" |
| %token TK_ATAT "@@" |
| |
| %token MacroArg |
| %token MacroCallCloseToEndLine |
| |
| /* These token types exist for the lexer, but are not used in this parser. */ |
| // The ∗ escaping is needed here because Bison 3.5.91+ puts the string |
| // literal in a block comment in the generated parser, and the "*/" in the |
| // literal causes the block comment to end prematurely and causes a syntax |
| // error. Note that this literal does not affect the grammar in any way. |
| %token TK_COMMENT_BLOCK "/∗comment∗/" |
| %token TK_EOL_COMMENT "// end of line comment" |
| %token TK_SPACE "<<space>>" /* includes tabs */ |
| %token TK_NEWLINE "<<\\n>>" |
| %token TK_LINE_CONT "<<\\line-cont>>" |
| %token TK_ATTRIBUTE "(*attribute*)" |
| |
| /* most likely a lexical error */ |
| %token TK_OTHER |
| // LINT.ThenChange(../formatting/verilog_token.cc) |
| |
| /* A glorified ';' specialized to mark the end of an |
| assertion_variable_declaration list inside the |
| body of a property_declaration (which ends with a property_spec) |
| or a sequence_declaration (which ends with a sequence_expr). |
| This re-enumeration is set by a contextualizing pass between the |
| lexer and parser. |
| */ |
| %token SemicolonEndOfAssertionVariableDeclarations ";(after-assertion-variable-decls)" |
| |
| // right-associative modify-assignment operators |
| %right TK_PLUS_EQ |
| %right TK_MINUS_EQ |
| %right TK_MUL_EQ |
| %right TK_DIV_EQ |
| %right TK_MOD_EQ |
| %right TK_AND_EQ |
| %right TK_OR_EQ |
| %right TK_XOR_EQ |
| %right TK_LS_EQ |
| %right TK_RS_EQ |
| %right TK_RSS_EQ |
| %right '?' |
| %right ':' |
| %right TK_inside |
| %right TK_LOGICAL_IMPLIES |
| %right TK_LOGEQUIV |
| /* left-associative operators */ |
| %left TK_LOR |
| %left TK_LAND |
| %left '|' |
| %left '^' TK_NXOR TK_NOR |
| %left '&' TK_NAND |
| %left TK_EQ TK_NE TK_CEQ TK_CNE |
| %left TK_WILDCARD_EQ TK_WILDCARD_NE |
| %left TK_GE TK_LE '<' '>' |
| %left TK_LS TK_RS TK_RSS |
| %left '+' '-' |
| %left '*' '/' '%' |
| %left TK_POW |
| /** |
| %left UNARY_PREC |
| **/ |
| |
| /* to resolve dangling else ambiguity. */ |
| /* alternatively, rewrite using matched/unmatched-if */ |
| %nonassoc less_than_TK_else |
| %nonassoc TK_else |
| /* to resolve exclude (... ambiguity */ |
| %nonassoc '(' |
| %nonassoc TK_exclude |
| |
| /* root of syntax tree: */ |
| %start source_text |
| |
| %% |
| |
| source_text |
| : description_list |
| { param->SetRoot(move($1)); } |
| | /* empty */ |
| { param->SetRoot(MakeNode()); } |
| ; |
| GenericIdentifier |
| // TODO(fangism): re-tag these to look like GenericIdentifier |
| : SymbolIdentifier |
| { $$ = move($1); } |
| | EscapedIdentifier |
| { $$ = move($1); } |
| | MacroIdentifier |
| { $$ = move($1); } |
| | KeywordIdentifier |
| { $$ = move($1); } |
| /* Treat built-in function identifiers as plain identifiers. */ |
| | unary_builtin_function |
| { $$ = move($1); } |
| | binary_builtin_function |
| { $$ = move($1); } |
| ; |
| |
| KeywordIdentifier |
| /* The following are keywords in certain dialects of Verilog. |
| * For now, allow these to be used as identifiers until we actually find |
| * examples that use the dialects, and will require additional context. |
| */ |
| /* Verilog-AMS: */ |
| : TK_branch |
| { $$ = move($1); } |
| | TK_access |
| { $$ = move($1); } |
| | TK_exclude |
| { $$ = move($1); } |
| | TK_flow |
| { $$ = move($1); } |
| | TK_from |
| { $$ = move($1); } |
| | TK_ground |
| { $$ = move($1); } |
| | TK_connect |
| { $$ = move($1); } |
| /* Verilog-A derivative operators */ |
| | TK_ddx |
| { $$ = move($1); } |
| | TK_ddt |
| { $$ = move($1); } |
| | TK_idt |
| { $$ = move($1); } |
| | TK_idtmod |
| { $$ = move($1); } |
| /* Verilog-AMS connect keywords: */ |
| | TK_split |
| { $$ = move($1); } |
| | TK_merged |
| { $$ = move($1); } |
| /* Verilog-AMS event statements: */ |
| | TK_timer |
| { $$ = move($1); } |
| /* | TK_cross is used in SystemVerilog covergroups */ |
| | TK_above |
| { $$ = move($1); } |
| | TK_discrete |
| { $$ = move($1); } |
| | TK_initial_step |
| { $$ = move($1); } |
| | TK_final_step |
| { $$ = move($1); } |
| /* TK_sample is in SystemVerilog coverage_event */ |
| | TK_sample |
| { $$ = move($1); } |
| /* TODO(fangism): 'bool' is not a SystemVerilog keyword, but we may |
| * still want to discourage it (style-guide). */ |
| | TK_bool |
| { $$ = move($1); } |
| ; |
| |
| /* TODO(fangism): phase this out: |
| * Separate into preprocessor_balanced_* and preprocessor_action. |
| * Require uses of preprocess control flow to be balanced. |
| */ |
| preprocessor_directive |
| : preprocessor_control_flow |
| { $$ = move($1); } |
| | preprocessor_action |
| { $$ = move($1); } |
| ; |
| |
| preprocessor_if_header |
| : PP_ifdef PP_Identifier |
| { $$ = MakeTaggedNode(N::kPreprocessorIfdefClause, $1, $2); } |
| /* consumer of $$ is expected to ExtendNode */ |
| | PP_ifndef PP_Identifier |
| { $$ = MakeTaggedNode(N::kPreprocessorIfndefClause, $1, $2); } |
| /* consumer of $$ is expected to ExtendNode */ |
| /* | PP_if expression '\n' */ /* doesn't exist for Verilog */ |
| ; |
| |
| preprocessor_elsif_header |
| : PP_elsif PP_Identifier |
| { $$ = MakeTaggedNode(N::kPreprocessorElsifClause, $1, $2); } |
| /* consumer of $$ is expected to ExtendNode */ |
| /* `elsif is interpreted as else-if-macro-is-defined, |
| * not the traditional expression predicate that follows else-if. |
| */ |
| ; |
| |
| /* TODO(fangism): Phase this out. |
| * Require uses of preprocess control flow to be balanced. |
| */ |
| preprocessor_control_flow |
| : preprocessor_if_header |
| { $$ = move($1); } |
| | preprocessor_elsif_header |
| { $$ = move($1); } |
| | PP_else |
| { $$ = move($1); } |
| | PP_endif |
| { $$ = move($1); } |
| ; |
| |
| preprocessor_action |
| : PP_undef PP_Identifier |
| { $$ = MakeTaggedNode(N::kPreprocessorUndef, $1, $2); } |
| | PP_include preprocess_include_argument |
| { $$ = MakeTaggedNode(N::kPreprocessorInclude, $1, $2); } |
| /* The body of a `define macro can be any unstructured sequence of tokens, |
| * which this parser just accumulates in an un-lexer manner. |
| * Verilog preprocessing even supports `defines in the bodies of `defines! |
| */ |
| | PP_define PP_Identifier PP_define_body |
| { $$ = MakeTaggedNode(N::kPreprocessorDefine, $1, $2, $3); } |
| /* $3 is unlexed text, and may even be empty. */ |
| | PP_define PP_Identifier '(' macro_formals_list_opt ')' PP_define_body |
| { $$ = MakeTaggedNode(N::kPreprocessorDefine, $1, $2, MakeParenGroup($3, $4, $5), $6); } |
| /* $6 is unlexed text, and may even be empty. */ |
| ; |
| |
| macro_formals_list_opt |
| : macro_formals_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$.reset(); } |
| ; |
| macro_formals_list |
| : macro_formals_list ',' macro_formal_parameter |
| { $$ = ExtendNode($1, $2, $3); } |
| | macro_formal_parameter |
| { $$ = MakeTaggedNode(N::kMacroFormalParameterList, $1); } |
| ; |
| macro_formal_parameter |
| : PP_Identifier |
| { $$ = MakeTaggedNode(N::kMacroFormalArg, $1); } |
| | PP_Identifier '=' PP_default_text |
| { $$ = MakeTaggedNode(N::kMacroFormalArg, $1, $2, $3); } |
| /* $3 is unlexed text */ |
| ; |
| |
| preprocess_include_argument |
| : string_literal |
| { $$ = move($1); } |
| | MacroIdentifier |
| { $$ = move($1); } |
| | MacroGenericItem |
| { $$ = move($1); } |
| | MacroCall |
| { $$ = move($1); } |
| ; |
| |
| MacroGenericItem |
| : MacroCallItem |
| { $$ = move($1); } |
| | MacroIdItem |
| { $$ = MakeTaggedNode(N::kMacroGenericItem, $1); } |
| ; |
| MacroCallItem |
| /* suitable for use as list items */ |
| : MacroCallId '(' macro_args_opt MacroCallCloseToEndLine |
| { $$ = MakeTaggedNode(N::kMacroCall, $1, MakeParenGroup($2, $3, $4)); } |
| ; |
| MacroCall |
| /* suitable for use in expressions */ |
| : MacroCallId '(' macro_args_opt ')' |
| { $$ = MakeTaggedNode(N::kMacroCall, $1, MakeParenGroup($2, $3, $4)); } |
| ; |
| macro_args_opt |
| : macro_args_opt ',' macro_arg_opt |
| { $$ = ExtendNode($1, $2, $3); } |
| | macro_arg_opt |
| { $$ = MakeTaggedNode(N::kMacroArgList, $1);} |
| ; |
| macro_arg_opt |
| : MacroArg |
| /* un-lexed text */ |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| procedural_assertion_statement |
| : concurrent_assertion_statement |
| { $$ = move($1); } |
| | immediate_assertion_statement |
| { $$ = move($1); } |
| /* TODO(fangism): |
| | checker_instantiation |
| */ |
| ; |
| |
| assertion_item |
| : concurrent_assertion_item |
| { $$ = move($1); } |
| | deferred_immediate_assertion_item |
| { $$ = move($1); } |
| ; |
| assignment_pattern |
| : TK_LP expression_list_proper '}' |
| { $$ = MakeTaggedNode(N::kAssignmentPattern, $1, $2, $3); } |
| | TK_LP structure_or_array_pattern_expression_list '}' |
| { $$ = MakeTaggedNode(N::kAssignmentPattern, $1, $2, $3); } |
| | TK_LP expression '{' expression_list_proper '}' '}' |
| { $$ = MakeTaggedNode(N::kAssignmentPattern, $1, $2, MakeBraceGroup($3, $4, $5), $6); } |
| /* replication construct: $2 must be a constant expression */ |
| | TK_LP '}' |
| { $$ = MakeTaggedNode(N::kAssignmentPattern, $1, $2); } |
| ; |
| |
| structure_or_array_pattern_expression_list |
| : structure_or_array_pattern_expression_list ',' structure_or_array_pattern_expression |
| { $$ = ExtendNode($1, $2, $3); } |
| | structure_or_array_pattern_expression |
| { $$ = MakeNode($1); } |
| ; |
| structure_or_array_pattern_expression |
| : structure_or_array_pattern_key ':' expression |
| { $$ = MakeTaggedNode(N::kPatternExpression, $1, $2, $3); } |
| ; |
| structure_or_array_pattern_key |
| /* structure_pattern_key : member_identifier | assignment_pattern_key |
| * array_pattern_key : constant_expression | assignment_pattern_key |
| * assignment_pattern_key : simple_type | TK_default |
| */ |
| : expression |
| { $$ = move($1); } |
| /* $1 should be a constant expression or GenericIdentifier (member). */ |
| | simple_type |
| { $$ = move($1); } |
| | TK_default |
| { $$ = move($1); } |
| ; |
| simple_type |
| : integer_atom_type |
| { $$ = move($1); } |
| | integer_vector_type |
| { $$ = move($1); } |
| /* TODO(fangism): support package scope or class scope type here: |
| | qualified_id |
| */ |
| ; |
| |
| block_identifier_opt |
| : unqualified_id ':' |
| { $$ = MakeTaggedNode(N::kBlockIdentifier, $1, $2); } |
| /* $1 should be a GenericIdentifier, no parameter_value */ |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| interface_class_declaration |
| : TK_interface TK_class GenericIdentifier |
| module_parameter_port_list_opt |
| declaration_extends_list_opt ';' /* multiple base interfaces allowed */ |
| interface_class_item_list_opt |
| TK_endclass label_opt |
| { $$ = MakeTaggedNode(N::kInterfaceClassDeclaration, $1, $2, $3, $4, $5, $6, $7, $8, $9); } |
| ; |
| declaration_extends_list_opt |
| : declaration_extends_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| declaration_extends_list |
| : TK_extends class_id |
| { $$ = MakeTaggedNode(N::kDeclarationExtendsList, $1, $2); } |
| | declaration_extends_list ',' class_id |
| { $$ = ExtendNode($1, $2, $3); } |
| ; |
| implements_interface_list_opt |
| : implements_interface_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| implements_interface_list |
| : implements_interface_list ',' class_id |
| { $$ = ExtendNode($1, $2, $3); } |
| | TK_implements class_id |
| { $$ = MakeTaggedNode(N::kImplementsList, $1, $2); } |
| ; |
| |
| interface_class_item_list_opt |
| : interface_class_item_list |
| { $$ = move($1); } |
| | /* empty */ |
| ; |
| interface_class_item_list |
| : interface_class_item_list interface_class_item |
| { $$ = ExtendNode($1, $2); } |
| | interface_class_item |
| { $$ = MakeTaggedNode(N::kInterfaceClassItemList, $1); } |
| ; |
| interface_class_item |
| : type_declaration |
| { $$ = move($1); } |
| | any_param_declaration |
| { $$ = move($1); } |
| | interface_class_method |
| { $$ = move($1); } |
| | ';' |
| { $$ = move($1); } |
| ; |
| interface_class_method |
| : TK_pure TK_virtual method_prototype ';' |
| { $$ = MakeTaggedNode(N::kInterfaceClassMethod, $1, $2, $3, $4); } |
| ; |
| |
| method_prototype |
| : task_prototype |
| { $$ = move($1); } |
| | function_prototype |
| { $$ = move($1); } |
| ; |
| |
| class_declaration |
| : TK_virtual_opt TK_class lifetime_opt GenericIdentifier |
| module_parameter_port_list_opt |
| class_declaration_extends_opt /* only one base type allowed */ |
| implements_interface_list_opt ';' |
| class_items_opt TK_endclass |
| label_opt |
| { $$ = MakeTaggedNode(N::kClassDeclaration, |
| MakeTaggedNode(N::kClassHeader, |
| $1, $2, $3, $4, $5, $6, $7, $8), |
| $9, $10, $11); } |
| ; |
| class_constraint |
| : constraint_prototype |
| { $$ = move($1); } |
| | constraint_declaration |
| { $$ = move($1); } |
| ; |
| class_declaration_extends_opt |
| : TK_extends class_id |
| { $$ = MakeTaggedNode(N::kExtendsList, $1, $2); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| unqualified_id |
| : GenericIdentifier parameter_value_opt |
| { $$ = MakeTaggedNode(N::kUnqualifiedId, $1, $2); } |
| /* If the root identifier is a package, it should not have parameters. */ |
| /* TODO(fangism): parameter_value_opt is too permissive here, |
| should only allow parenthesized parameter lists following '#'. */ |
| /* Normally, a type reference does not declare a new symbol, however, this rule |
| * is used in an overloaded way as an implicitly typed declaration in: |
| * type_identifier_or_implicit_basic_followed_by_id_and_dimensions_opt |
| * type_identifier_or_implicit_basic_followed_by_id |
| */ |
| ; |
| qualified_id |
| /* This also serves as a scoped class member identifier, which is useful for |
| * out-of-line method (function/task) definitions. |
| * For the purposes of emitting code blocks, we take only the final |
| * identifier in the hierarchy (here, $3). |
| * Once we migrate to a full AST, we can resolve the complete class scopes of |
| * hierarchical identifiers. |
| */ |
| : qualified_id TK_SCOPE_RES unqualified_id |
| { $$ = ExtendNode($1, $2, $3); } |
| | unqualified_id TK_SCOPE_RES unqualified_id |
| { $$ = MakeTaggedNode(N::kQualifiedId, $1, $2, $3); } |
| | TK_Sunit TK_SCOPE_RES unqualified_id |
| /* $unit refers to a package scope, but can never appear alone. */ |
| { $$ = MakeTaggedNode(N::kQualifiedId, $1, $2, $3); } |
| | qualified_id TK_SCOPE_RES TK_new |
| { $$ = ExtendNode($1, $2, $3); } |
| | unqualified_id TK_SCOPE_RES TK_new |
| { $$ = MakeTaggedNode(N::kQualifiedId, $1, $2, $3); } |
| /* Allow class_name::new to refer to out-of-line constructor. */ |
| ; |
| class_id |
| : qualified_id |
| { $$ = move($1); } |
| | unqualified_id |
| { $$ = move($1); } |
| ; |
| class_items_opt |
| : class_items |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = MakeTaggedNode(N::kClassItems);} |
| ; |
| class_items |
| : class_items class_item |
| { $$ = ExtendNode($1, $2); } |
| | class_item |
| { $$ = MakeTaggedNode(N::kClassItems, $1);} |
| ; |
| |
| class_constructor_prototype |
| : TK_function TK_new tf_port_list_paren_opt |
| { $$ = MakeTaggedNode(N::kClassConstructorPrototype, $1, $2, $3); } |
| /* users of this rule may append a trailing ';' to this node |
| * TODO(fangism): move the ';' into this rule |
| */ |
| ; |
| |
| class_constructor |
| : class_constructor_prototype ';' |
| /* merged: function_item_list_opt statement_or_null_list_opt */ |
| tf_item_or_statement_or_null_list_opt |
| TK_endfunction endnew_opt |
| { $$ = MakeTaggedNode(N::kClassConstructor, qualifier_placeholder, |
| ExtendNode($1, $2), $3, $4, $5); } |
| /* TODO(fangism) Probably want to include the qualifier_placeholder |
| * in the prototype/header as well. Reshape this. */ |
| ; |
| |
| /* TODO(fangism): should some of these function declarations be METHODs? |
| * lexer will need to keep track of in_class (level) |
| * and function_declaration will need to use it. |
| **/ |
| class_item |
| /* The keyword 'virtual' is overloaded both as a method qualifier and as |
| * a keyword to start an interface data type. |
| * To avoid conflict, we expand method_qualifier_list_opt and property_qualifier_opt |
| * by the first item, to discern those that start with 'virtual' and those that do not. |
| */ |
| /* originally: method_qualifier_list_opt class_constructor */ |
| : method_property_qualifier_list_not_starting_with_virtual class_constructor |
| { SetChild($2, 0, $1); |
| $$ = move($2); } |
| | class_constructor |
| { $$ = move($1); } |
| | TK_virtual method_qualifier_list_opt class_constructor |
| { SetChild($3, 0, MakeTaggedNode(N::kQualifierList, $1, ForwardChildren($2))); |
| $$ = move($3); } |
| |
| /* originally: property_qualifier_list_opt data_type list_of_variable_decl_assignments ';' */ |
| /* or: property_qualifier_list_opt data_declaration */ |
| | method_property_qualifier_list_not_starting_with_virtual |
| const_opt var_opt data_type list_of_variable_decl_assignments ';' |
| { $$ = MakeDataDeclaration( |
| ExtendNode($1, $2, $3), |
| MakeInstantiationBase( |
| MakeTaggedNode(N::kInstantiationType, $4), |
| $5), |
| $6); } |
| | data_type list_of_variable_decl_assignments ';' |
| { $$ = MakeDataDeclaration( |
| qualifier_placeholder, |
| MakeInstantiationBase( |
| MakeTaggedNode(N::kInstantiationType, $1), |
| $2), |
| $3); } |
| | TK_const class_item_qualifier_list_opt data_type list_of_variable_decl_assignments ';' |
| { $$ = MakeDataDeclaration( |
| MakeTaggedNode(N::kQualifierList, $1, ForwardChildren($2)), |
| MakeInstantiationBase( |
| MakeTaggedNode(N::kInstantiationType, $3), |
| $4), |
| $5); } |
| | interface_data_declaration |
| { $$ = move($1); } |
| |
| | package_import_declaration |
| { $$ = move($1); } |
| /* In the LRM, package_import_declaration is covered by data_declaration. */ |
| |
| /* originally: method_qualifier_list_opt task_or_function_declaration */ |
| /* should qualifier be attached to function/task declaration? */ |
| | method_property_qualifier_list_not_starting_with_virtual task_declaration |
| { SetChild(SymbolCastToNode(*$2)[0] /* kTaskHeader */, 0, $1); |
| $$ = move($2); } |
| | task_declaration |
| { $$ = move($1); } |
| | TK_virtual method_qualifier_list_opt task_declaration |
| { SetChild(SymbolCastToNode(*$3)[0] /* kTaskHeader */, 0, |
| MakeTaggedNode(N::kQualifierList, $1, ForwardChildren($2))); |
| $$ = move($3); } |
| /* TODO(fangism): Method qualifiers should be grouped together into one list, |
| * rather than being split between virtual and method_qualifier list. |
| */ |
| | method_property_qualifier_list_not_starting_with_virtual function_declaration |
| { SetChild(SymbolCastToNode(*$2)[0] /* kFunctionHeader */, 0, $1); |
| $$ = move($2); } |
| | function_declaration |
| { $$ = move($1); } |
| | TK_virtual method_qualifier_list_opt function_declaration |
| { SetChild(SymbolCastToNode(*$3)[0] /* kFunctionHeader */, 0, |
| MakeTaggedNode(N::kQualifierList, $1, ForwardChildren($2))); |
| $$ = move($3); } |
| /* pure virtual method prototypes: */ |
| | TK_pure TK_virtual class_item_qualifier_list_opt method_prototype ';' |
| { $$ = MakeTaggedNode(N::kForwardDeclaration, |
| MakeTaggedNode(N::kQualifierList, $1, $2, ForwardChildren($3)), |
| ExtendNode($4, $5)); } |
| /* forward declarations (excludes definition body): */ |
| | TK_extern method_qualifier_list_opt method_prototype ';' |
| { $$ = MakeTaggedNode(N::kForwardDeclaration, |
| MakeTaggedNode(N::kQualifierList, $1, ForwardChildren($2)), |
| ExtendNode($3, $4)); } |
| | TK_extern method_qualifier_list_opt class_constructor_prototype ';' |
| { $$ = MakeTaggedNode(N::kForwardDeclaration, |
| MakeTaggedNode(N::kQualifierList, $1, ForwardChildren($2)), |
| ExtendNode($3, $4)); } |
| | class_declaration |
| { $$ = move($1); } |
| | interface_class_declaration |
| { $$ = move($1); } |
| | class_constraint |
| { $$ = move($1); } |
| | type_declaration |
| { $$ = move($1); } |
| | any_param_declaration |
| { $$ = move($1); } |
| | covergroup_declaration |
| { $$ = move($1); } |
| | ';' |
| { $$ = MakeTaggedNode(N::kNullDeclaration, $1); } |
| | error ';' |
| { yyerrok; $$ = Recover(); } |
| | macro_call_or_item |
| { $$ = move($1); } |
| | preprocessor_balanced_class_items |
| { $$ = move($1); } |
| | preprocessor_action |
| { $$ = move($1); } |
| ; |
| |
| interface_data_declaration |
| : interface_type list_of_variable_decl_assignments ';' |
| { $$ = MakeDataDeclaration( |
| qualifier_placeholder, |
| MakeInstantiationBase( |
| MakeTaggedNode(N::kInstantiationType, $1), |
| $2), |
| $3); } |
| /* interface instantiation: virtual type_if inst_if */ |
| ; |
| |
| preprocessor_balanced_class_items |
| : preprocessor_if_header class_items_opt |
| preprocessor_elsif_class_items_opt |
| preprocessor_else_class_item_opt |
| PP_endif |
| { $$ = MakeTaggedNode(N::kPreprocessorBalancedClassItems, |
| ExtendNode($1, $2), ForwardChildren($3), $4, $5); |
| } |
| ; |
| preprocessor_elsif_class_items_opt |
| : preprocessor_elsif_class_items |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_elsif_class_items |
| : preprocessor_elsif_class_items preprocessor_elsif_class_item |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_elsif_class_item |
| { $$ = MakeNode($1); } /* Don't bother tagging; node will be flattened. */ |
| ; |
| preprocessor_elsif_class_item |
| : preprocessor_elsif_header class_items_opt |
| { $$ = ExtendNode($1, $2); } |
| ; |
| preprocessor_else_class_item_opt |
| : preprocessor_else_class_item |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_else_class_item |
| : PP_else class_items_opt |
| { $$ = MakeTaggedNode(N::kPreprocessorElseClause, $1, $2); } |
| ; |
| |
| macro_call_or_item |
| : MacroGenericItem |
| { $$ = move($1); } |
| /* lone macro on its own line */ |
| | MacroCall ';' |
| { $$ = ExtendNode($1, $2); } |
| ; |
| |
| class_item_qualifier |
| : TK_static |
| { $$ = move($1); } |
| | TK_protected |
| { $$ = move($1); } |
| | TK_local |
| { $$ = move($1); } |
| ; |
| class_item_qualifier_list_opt |
| : class_item_qualifier_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| class_item_qualifier_list |
| : class_item_qualifier_list class_item_qualifier |
| { $$ = ExtendNode($1, $2); } |
| | class_item_qualifier |
| { $$ = MakeTaggedNode(N::kQualifierList, $1); } |
| ; |
| class_new |
| : TK_new '(' argument_list_opt ')' |
| { $$ = MakeTaggedNode(N::kClassNew, $1, MakeParenGroup($2, $3, $4)); } |
| | TK_new reference |
| { $$ = MakeTaggedNode(N::kClassNew, $1, $2); } |
| /* The LRM actually permits any expression at $2. */ |
| | TK_new |
| { $$ = MakeTaggedNode(N::kClassNew, $1); } |
| /* TODO(fangism): |
| | class_id TK_SCOPE_RES TK_new '(' argument_list_opt ')' |
| */ |
| ; |
| |
| /* action_block is a very strange nonterminal in SystemVerilog: |
| * it consists of the statement body of the assert/assume clause, |
| * followed by an optional else-clause. |
| * To make this more consistent with conditional constructs, |
| * this node will be dismantled by the consumer and reshaped, |
| * so that an assert-clause will resemble an if-clause, etc. |
| */ |
| action_block |
| : statement_or_null |
| %prec less_than_TK_else |
| { $$ = MakeTaggedNode(N::kActionBlock, $1, nullptr); } |
| | statement_or_null TK_else statement_or_null |
| { $$ = MakeTaggedNode(N::kActionBlock, $1, |
| MakeTaggedNode(N::kElseClause, $2, MakeTaggedNode(N::kElseBody, $3))); } |
| |
| /* original grammar rule: |
| * statement TK_else statement_or_null |
| * but relaxed to look like the unmatched-if case so the %prec directive |
| * can resolve the S/R conflict. |
| */ |
| | TK_else statement_or_null |
| { $$ = MakeTaggedNode(N::kActionBlock, nullptr, |
| MakeTaggedNode(N::kElseClause, $1, MakeTaggedNode(N::kElseBody, $2))); } |
| ; |
| concurrent_assertion_item |
| : block_identifier_opt concurrent_assertion_statement |
| { $$ = MakeTaggedNode(N::kAssertionItem, $1, $2); } |
| /* TODO(fangism): |
| | checker_instantiation |
| */ |
| ; |
| concurrent_assertion_statement |
| /* all end with ';' or '}' */ |
| : assert_property_statement |
| { $$ = move($1); } |
| | assume_property_statement |
| { $$ = move($1); } |
| | cover_property_statement |
| { $$ = move($1); } |
| | cover_sequence_statement |
| { $$ = move($1); } |
| | restrict_property_statement |
| { $$ = move($1); } |
| ; |
| assert_property_statement |
| : TK_assert TK_property '(' property_spec ')' action_block |
| { auto& node = SymbolCastToNode(*$6); |
| $$ = MakeTaggedNode( |
| N::kAssertPropertyStatement, |
| MakeTaggedNode( /* like an if-clause */ |
| N::kAssertPropertyClause, |
| MakeTaggedNode( /* like an if-header */ |
| N::kAssertPropertyHeader, |
| $1, $2, MakeParenGroup($3, $4, $5)), |
| MakeTaggedNode(N::kAssertPropertyBody, node[0])), |
| node[1] /* else-clause */); |
| } |
| ; |
| assume_property_statement |
| : TK_assume TK_property '(' property_spec ')' action_block |
| { auto& node = SymbolCastToNode(*$6); |
| $$ = MakeTaggedNode( |
| N::kAssumePropertyStatement, |
| MakeTaggedNode( /* like an if-clause */ |
| N::kAssumePropertyClause, |
| MakeTaggedNode( /* like an if-header */ |
| N::kAssumePropertyHeader, |
| $1, $2, MakeParenGroup($3, $4, $5)), |
| MakeTaggedNode(N::kAssumePropertyBody, node[0])), |
| node[1] /* else-clause */); |
| } |
| ; |
| cover_property_statement |
| : TK_cover TK_property '(' property_spec ')' statement_or_null |
| /* shaped like kIfClause */ |
| { $$ = MakeTaggedNode(N::kCoverPropertyStatement, |
| MakeTaggedNode(N::kCoverPropertyHeader, |
| $1, $2, MakeParenGroup($3, $4, $5)), |
| MakeTaggedNode(N::kCoverPropertyBody, $6)); } |
| ; |
| expect_property_statement |
| : TK_expect '(' property_spec ')' action_block |
| { auto& node = SymbolCastToNode(*$5); |
| $$ = MakeTaggedNode( |
| N::kExpectPropertyStatement, |
| MakeTaggedNode( /* like an if-clause */ |
| N::kExpectPropertyClause, |
| MakeTaggedNode( /* like an if-header */ |
| N::kExpectPropertyHeader, |
| $1, MakeParenGroup($2, $3, $4)), |
| MakeTaggedNode(N::kExpectPropertyBody, node[0])), |
| node[1] /* else-clause */); |
| } |
| ; |
| cover_sequence_statement |
| : TK_cover TK_sequence '(' sequence_spec ')' statement_or_null |
| /* shaped like kIfClause */ |
| { $$ = MakeTaggedNode(N::kCoverSequenceStatement, |
| MakeTaggedNode(N::kCoverSequenceHeader, |
| $1, $2, MakeParenGroup($3, $4, $5)), |
| MakeTaggedNode(N::kCoverSequenceBody, $6)); } |
| |
| ; |
| restrict_property_statement |
| : TK_restrict TK_property '(' property_spec ')' ';' |
| { $$ = MakeTaggedNode(N::kRestrictPropertyStatement, |
| $1, $2, MakeParenGroup($3, $4, $5), $6); } |
| ; |
| |
| deferred_immediate_assertion_item |
| : block_identifier_opt deferred_immediate_assertion_statement |
| { $$ = MakeTaggedNode(N::kAssertionItem, $1, $2); } |
| ; |
| immediate_assertion_statement |
| : simple_immediate_assertion_statement |
| { $$ = move($1); } |
| | deferred_immediate_assertion_statement |
| { $$ = move($1); } |
| ; |
| simple_immediate_assertion_statement |
| : TK_assert '(' expression ')' action_block |
| /* shaped similarly to kConditionalStatement */ |
| { auto& node = SymbolCastToNode(*$5); |
| $$ = MakeTaggedNode( |
| N::kAssertionStatement, |
| MakeTaggedNode( /* like an if-clause */ |
| N::kAssertionClause, |
| MakeTaggedNode( /* like an if-header */ |
| N::kAssertionHeader, |
| $1, nullptr, MakeParenGroup($2, $3, $4)), |
| MakeTaggedNode(N::kAssertionBody, node[0])), |
| node[1] /* else-clause */); |
| } |
| | TK_assume '(' expression ')' action_block |
| /* shaped similarly to kConditionalStatement */ |
| { auto& node = SymbolCastToNode(*$5); |
| $$ = MakeTaggedNode( |
| N::kAssumeStatement, |
| MakeTaggedNode( /* like an if-clause */ |
| N::kAssumeClause, |
| MakeTaggedNode( /* like an if-header */ |
| N::kAssumeHeader, |
| $1, nullptr, MakeParenGroup($2, $3, $4)), |
| MakeTaggedNode(N::kAssumeBody, node[0])), |
| node[1] /* else-clause */); |
| } |
| | TK_cover '(' expression ')' statement_or_null |
| /* shaped similarly to kIfClause, doesn't have an else-clause */ |
| { $$ = MakeTaggedNode(N::kCoverStatement, |
| MakeTaggedNode(N::kCoverHeader, |
| $1, nullptr, |
| MakeParenGroup($2, $3, $4)), |
| MakeTaggedNode(N::kCoverBody, $5)); } |
| ; |
| deferred_immediate_assertion_statement |
| : TK_assert final_or_zero '(' expression ')' action_block |
| /* shaped similarly to kConditionalStatement */ |
| { auto& node = SymbolCastToNode(*$6); |
| $$ = MakeTaggedNode( |
| N::kAssertionStatement, |
| MakeTaggedNode( /* like an if-clause */ |
| N::kAssertionClause, |
| MakeTaggedNode( /* like an if-header */ |
| N::kAssertionHeader, |
| $1, $2, MakeParenGroup($3, $4, $5)), |
| MakeTaggedNode(N::kAssertionBody, node[0])), |
| node[1] /* else-clause */); |
| } |
| | TK_assume final_or_zero '(' expression ')' action_block |
| /* shaped similarly to kConditionalStatement */ |
| { auto& node = SymbolCastToNode(*$6); |
| $$ = MakeTaggedNode( |
| N::kAssumeStatement, |
| MakeTaggedNode( /* like an if-clause */ |
| N::kAssumeClause, |
| MakeTaggedNode( /* like an if-header */ |
| N::kAssumeHeader, |
| $1, $2, MakeParenGroup($3, $4, $5)), |
| MakeTaggedNode(N::kAssumeBody, node[0])), |
| node[1] /* else-clause */); |
| } |
| | TK_cover final_or_zero '(' expression ')' statement_or_null |
| /* shaped similarly to kIfClause, doesn't have an else-clause */ |
| { $$ = MakeTaggedNode(N::kCoverStatement, |
| MakeTaggedNode(N::kCoverHeader, |
| $1, $2, |
| MakeParenGroup($3, $4, $5)), |
| MakeTaggedNode(N::kCoverBody, $6)); } |
| ; |
| final_or_zero |
| : TK_final |
| { $$ = move($1); } |
| | '#' TK_DecNumber |
| { $$ = MakeTaggedNode(N::kPoundZero, $1, $2); } |
| /* $2 must be 0 */ |
| ; |
| |
| constraint_block |
| : '{' constraint_block_item_list_opt '}' |
| { $$ = MakeBraceGroup($1, $2, $3); } |
| ; |
| constraint_block_item |
| : constraint_expression_no_preprocessor |
| { $$ = move($1); } |
| /* The TK_solve rule has been moved into constraint_expression |
| * to support an extension. |
| */ |
| | preprocessor_balanced_constraint_block_item |
| /* This also covers preprocessor_balanced_constraint_expressions. */ |
| { $$ = move($1); } |
| ; |
| constraint_primary_list |
| : constraint_primary_list ',' constraint_primary |
| { $$ = ExtendNode($1, $2, $3); } |
| | constraint_primary |
| { $$ = MakeTaggedNode(N::kConstraintPrimaryList, $1); } |
| ; |
| constraint_block_item_list |
| : constraint_block_item_list constraint_block_item |
| { $$ = ExtendNode($1, $2); } |
| | constraint_block_item |
| { $$ = MakeTaggedNode(N::kConstraintBlockItemList, $1); } |
| ; |
| constraint_block_item_list_opt |
| : constraint_block_item_list |
| { $$ = move($1); } |
| | /* empty */ |
| /* create empty list */ |
| { $$ = MakeTaggedNode(N::kConstraintBlockItemList); } |
| ; |
| preprocessor_balanced_constraint_block_item |
| : preprocessor_if_header constraint_block_item_list_opt |
| preprocessor_elsif_constraint_block_items_opt |
| preprocessor_else_constraint_block_item_opt |
| PP_endif |
| { $$ = MakeTaggedNode(N::kPreprocessorBalancedConstraintBlockItem, |
| ExtendNode($1, $2), ForwardChildren($3), $4, $5); |
| } |
| ; |
| preprocessor_elsif_constraint_block_items_opt |
| : preprocessor_elsif_constraint_block_items |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_elsif_constraint_block_items |
| : preprocessor_elsif_constraint_block_items preprocessor_elsif_constraint_block_item |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_elsif_constraint_block_item |
| { $$ = MakeNode($1); } /* Don't bother tagging; node will be flattened. */ |
| ; |
| preprocessor_elsif_constraint_block_item |
| : preprocessor_elsif_header constraint_block_item_list_opt |
| { $$ = ExtendNode($1, $2); } |
| ; |
| preprocessor_else_constraint_block_item_opt |
| : preprocessor_else_constraint_block_item |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_else_constraint_block_item |
| : PP_else constraint_block_item_list_opt |
| { $$ = MakeTaggedNode(N::kPreprocessorElseClause, $1, $2); } |
| ; |
| |
| constraint_declaration_package_item |
| /* Like constraint_declaration, but excludes qualifiers |
| * and allows the declared identifier to be scope-qualified. |
| */ |
| : TK_constraint class_id constraint_block |
| { $$ = MakeTaggedNode(N::kConstraintDeclaration, nullptr, $1, $2, $3); } |
| |
| /* $2 is allowed to be scope-qualified for out-of-line definitions */ |
| ; |
| constraint_declaration |
| : TK_static_opt TK_constraint GenericIdentifier constraint_block |
| { $$ = MakeTaggedNode(N::kConstraintDeclaration, $1, $2, $3, $4); } |
| ; |
| constraint_expression_no_preprocessor |
| /* Ends with ';' or '}' */ |
| : TK_soft expression_or_dist ';' |
| { $$ = MakeTaggedNode(N::kConstraintExpression, $1, $2, $3);} |
| | expression_or_dist ';' |
| { $$ = MakeTaggedNode(N::kConstraintExpression, $1, $2);} |
| | expression TK_CONSTRAINT_IMPLIES constraint_set |
| { $$ = MakeTaggedNode(N::kConstraintExpression, $1, $2, $3);} |
| | TK_if '(' expression ')' constraint_set |
| %prec less_than_TK_else |
| { $$ = MakeTaggedNode(N::kConstraintExpression, $1, MakeParenGroup($2, $3, $4), $5);} |
| | TK_if '(' expression ')' constraint_set TK_else constraint_set |
| { $$ = MakeTaggedNode(N::kConstraintExpression, $1, MakeParenGroup($2, $3, $4), $5, $6, $7);} |
| | TK_foreach '(' reference ')' constraint_set |
| { $$ = MakeTaggedNode(N::kConstraintExpression, $1, MakeParenGroup($2, $3, $4), $5);} |
| /* TODO(fangism): $3 must end with the form: '[' loop_variables ']' |
| * where loop_variables is a list of loop variable identifiers. |
| * See note in variable_dimension nonterminal. |
| */ |
| | uniqueness_constraint ';' |
| { $$ = MakeTaggedNode(N::kConstraintExpression, $1, $2);} |
| | TK_disable TK_soft constraint_primary ';' |
| { $$ = MakeTaggedNode(N::kConstraintExpression, $1, $2, $3, $4);} |
| | TK_solve constraint_primary_list TK_before constraint_primary_list ';' |
| { $$ = MakeTaggedNode(N::kConstraintExpression, $1, $2, $3, $4, $5);} |
| /* solve within as a constraint_set items is an extension to the LRM |
| * to allow solve statements inside foreach. |
| */ |
| ; |
| constraint_expression |
| /* Factored out this rule because constraint_block_item covers |
| constraint_expression, so excluding preprocessor-balancing from |
| constraint_expression will avoid R/R conflicts. |
| */ |
| : constraint_expression_no_preprocessor |
| { $$ = move($1); } |
| | preprocessor_balanced_constraint_expressions |
| { $$ = move($1); } |
| ; |
| constraint_primary |
| : reference |
| { $$ = move($1); } |
| /* covers: |
| * reference '[' part_select_range ']' |
| * where part_select_range |
| * : constant_range |
| * | indexed_range |
| * ; |
| * both of which are covered in variable_dimension. |
| */ |
| ; |
| uniqueness_constraint |
| : TK_unique '{' open_range_list '}' |
| { $$ = MakeTaggedNode(N::kUniquenessConstraint, $1, MakeBraceGroup($2, $3, $4)); } |
| ; |
| constraint_expression_list |
| : constraint_expression_list constraint_expression |
| { $$ = ExtendNode($1, $2); } |
| | constraint_expression |
| { $$ = MakeTaggedNode(N::kConstraintExpressionList, $1); } |
| ; |
| constraint_expression_list_opt |
| : constraint_expression_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| preprocessor_balanced_constraint_expressions |
| : preprocessor_if_header constraint_expression_list_opt |
| preprocessor_elsif_constraint_expressions_opt |
| preprocessor_else_constraint_expression_opt |
| PP_endif |
| { $$ = MakeTaggedNode(N::kPreprocessorBalancedConstraintExpressions, |
| ExtendNode($1, $2), ForwardChildren($3), $4, $5); |
| } |
| ; |
| preprocessor_elsif_constraint_expressions_opt |
| : preprocessor_elsif_constraint_expressions |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_elsif_constraint_expressions |
| : preprocessor_elsif_constraint_expressions preprocessor_elsif_constraint_expression |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_elsif_constraint_expression |
| { $$ = MakeNode($1); } |
| ; |
| preprocessor_elsif_constraint_expression |
| : preprocessor_elsif_header constraint_expression_list_opt |
| { $$ = ExtendNode($1, $2); } |
| ; |
| preprocessor_else_constraint_expression_opt |
| : preprocessor_else_constraint_expression |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_else_constraint_expression |
| : PP_else constraint_expression_list_opt |
| { $$ = MakeTaggedNode(N::kPreprocessorElseClause, $1, $2); } |
| ; |
| |
| constraint_prototype |
| : TK_static_opt TK_constraint GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kConstraintPrototype, $1, $2, $3, $4); } |
| ; |
| constraint_set |
| : constraint_expression |
| { $$ = move($1); } |
| | '{' constraint_expression_list '}' |
| /* TODO(fangism): $2 should be optional, but empty {} is covered by |
| expr_primary_braces in constraint_expression, and S/R conflicts. */ |
| { $$ = MakeBraceGroup($1, $2, $3); } |
| ; |
| const_opt |
| : TK_const |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| var_opt |
| : TK_var |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| data_declaration_base |
| /* very similar to struct_union_member and block_item_decl */ |
| : data_type_or_implicit_basic_followed_by_id_and_dimensions_opt |
| trailing_decl_assignment_opt ',' list_of_variable_decl_assignments ';' |
| { /* re-shape subtree to pass onto MakeDataDeclaration */ |
| auto& node = SymbolCastToNode(*$1); |
| $$ = MakeNode( |
| MakeInstantiationBase( |
| MakeTaggedNode(N::kInstantiationType, node[0]), /* data type */ |
| /* declaration assignment list is similar to instantiation list */ |
| MakeTaggedNode(N::kVariableDeclarationAssignmentList, |
| MakeTaggedNode( |
| N::kVariableDeclarationAssignment, |
| node[1], /* id */ |
| node[2], /* unpacked dimensions */ |
| $2), |
| $3, /* ',' */ |
| ForwardChildren($4))), |
| $5); |
| } |
| | data_type_or_implicit_basic_followed_by_id_and_dimensions_opt |
| trailing_decl_assignment_opt ';' |
| { /* re-shape subtree to pass onto MakeDataDeclaration */ |
| auto& node = SymbolCastToNode(*$1); |
| $$ = MakeNode( |
| MakeInstantiationBase( |
| MakeTaggedNode(N::kInstantiationType, node[0]), /* data type */ |
| /* declaration assignment list is similar to instantiation list */ |
| MakeTaggedNode(N::kVariableDeclarationAssignmentList, |
| MakeTaggedNode( |
| N::kVariableDeclarationAssignment, |
| node[1], /* id */ |
| node[2], /* unpacked dimensions */ |
| $2))), |
| $3); |
| } |
| ; |
| data_declaration_modifiers_opt |
| : const_opt var_opt lifetime_opt |
| { $$ = MakeTaggedNode(N::kQualifierList, $1, $2, $3); } |
| ; |
| data_declaration |
| : data_declaration_modifiers_opt data_declaration_base |
| { auto& node = SymbolCastToNode(*$2); |
| $$ = MakeDataDeclaration($1, node[0], node[1]); |
| } |
| /* In the LRM, data_declaration also includes: |
| * type_declaration |
| * package_import_declaration |
| * net_type_declaration |
| * but we choose to keep those separate in this grammar. |
| */ |
| ; |
| |
| data_type_primitive |
| : data_type_primitive_scalar decl_dimensions_opt |
| /* $2 is packed dimensions */ |
| { $$ = ExtendNode($1, MakePackedDimensionsNode($2)); } |
| ; |
| data_type_primitive_scalar |
| : integer_vector_type signed_unsigned_opt |
| { $$ = MakeTaggedNode(N::kDataTypePrimitive, $1, $2); } |
| | non_integer_type |
| { $$ = MakeTaggedNode(N::kDataTypePrimitive, $1); } |
| | struct_data_type |
| { $$ = MakeTaggedNode(N::kDataTypePrimitive, $1); } |
| | enum_data_type |
| { $$ = MakeTaggedNode(N::kDataTypePrimitive, $1); } |
| | integer_atom_type signed_unsigned_opt |
| { $$ = MakeTaggedNode(N::kDataTypePrimitive, $1, $2); } |
| | TK_chandle |
| { $$ = MakeTaggedNode(N::kDataTypePrimitive, $1); } |
| | TK_string |
| { $$ = MakeTaggedNode(N::kDataTypePrimitive, $1); } |
| | TK_event |
| { $$ = MakeTaggedNode(N::kDataTypePrimitive, $1); } |
| ; |
| |
| /* trailing optional decl_dimensions moved to rule: data_type */ |
| /* resolves conflict on: ID . '[' (sized-type or index expression?) */ |
| data_type_base |
| : data_type_primitive |
| { $$ = move($1); } |
| /* hierarchy_identifier starting w/ GenericIdentifier |
| * is source of major conflict, so we factor the rest out. |
| **/ |
| | reference_or_call |
| { $$ = move($1); } |
| /* covers class_id : qualified_id | unqualified_id |
| * can already contain type parameters (parameter_value_opt) |
| * TODO(fangism): calls are not permitted in type reference, but it was |
| * written permissively to avoid R/R conflicts against expressions. |
| */ |
| /* merged into: reference |
| | GenericIdentifier decl_dimensions_opt |
| | scope_prefix GenericIdentifier |
| | scope_prefix_opt GenericIdentifier |
| | class_id |
| */ |
| /* interface_type is also considered a 'data_type' in the language, |
| * but it is handled specially in class_item, to avoid a conflict on |
| * the 'virtual' keyword. |
| */ |
| | type_reference |
| { $$ = move($1); } |
| ; |
| |
| type_reference |
| : TK_type '(' expression ')' |
| { $$ = MakeTaggedNode(N::kTypeReference, $1, MakeParenGroup($2, $3, $4)); } |
| /* TODO(fangism): some data types are not covered |
| | TK_type '(' data_type ')' |
| */ |
| ; |
| |
| /* pulled decl_dimensions_opt outside of data_type to other rules */ |
| data_type |
| : data_type_base /* decl_dimensions_opt */ |
| { $$ = move($1); } |
| ; |
| |
| interface_type |
| : TK_virtual interface_opt GenericIdentifier parameter_value_opt |
| { $$ = MakeTaggedNode(N::kInterfaceType, $1, $2, $3, $4); } |
| /* $3 is the interface_identifier */ |
| | TK_virtual interface_opt GenericIdentifier parameter_value_opt |
| '.' member_name |
| { $$ = MakeTaggedNode(N::kInterfaceType, $1, $2, $3, $4, $5, $6); } |
| |
| /* $5 is the modport_identifier (optional) */ |
| ; |
| interface_opt |
| : TK_interface |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| delay3_or_drive_opt |
| : delay3 |
| { $$ = move($1); } |
| | drive_strength |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| /* support interface.modport as a type */ |
| scope_or_if_res |
| : TK_SCOPE_RES |
| { $$ = move($1); } |
| | '.' |
| { $$ = move($1); } |
| ; |
| |
| /* Re-worked grammar to eliminate conflict on type identifier, |
| * which is a consequence of implicit types in declarations. |
| * Unable to parse: "ID . ID" without further lookahead past second ID, |
| * so rules were rewritten to *group* the declared ID along with |
| * its preceding (possibly implicit) type. |
| * The *last* identifier is the one being declared, so return it in $$. |
| * For outline generation, don't care about type, so it is dropped. |
| * Delay and drive specifiers occur in net_declarations. |
| */ |
| type_identifier_or_implicit_followed_by_id_and_dimensions_opt |
| // : class_id GenericIdentifier { $$ = move($2); } |
| // : GenericIdentifier delay3_or_drive_opt GenericIdentifier { $$ = move($3); } |
| : GenericIdentifier delay3 decl_dimensions_opt |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, $1, $2, |
| MakePackedDimensionsNode($3)), |
| $4, MakeUnpackedDimensionsNode($5)); } |
| | GenericIdentifier drive_strength decl_dimensions_opt |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, $1, $2, |
| MakePackedDimensionsNode($3)), |
| $4, MakeUnpackedDimensionsNode($5)); } |
| | GenericIdentifier decl_dimensions_opt |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, $1, nullptr, |
| MakePackedDimensionsNode($2)), |
| $3, MakeUnpackedDimensionsNode($4)); } |
| | GenericIdentifier scope_or_if_res GenericIdentifier |
| delay3_or_drive_opt decl_dimensions_opt |
| GenericIdentifier decl_dimensions_opt |
| /* TODO(fangism): separate scope_or_if_res into different node tags cases, |
| * one for TK_SCOPE (qualified_id), one for '.' (interface port). |
| */ |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, |
| MakeTaggedNode(N::kInterfacePortHeader, |
| $1, $2, $3), |
| $4, |
| MakePackedDimensionsNode($5)), |
| $6, MakeUnpackedDimensionsNode($7)); } |
| // | delay3_or_drive_opt GenericIdentifier { $$ = move($2); } |
| | /* implicit type */ /* decl_dimensions_opt */ |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, nullptr, nullptr, |
| MakeTaggedNode(N::kPackedDimensions, |
| nullptr)), |
| $1, MakeUnpackedDimensionsNode($2)); } |
| | /* implicit type */ delay3 decl_dimensions_opt |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, nullptr, $1, |
| MakePackedDimensionsNode($2)), |
| $3, MakeUnpackedDimensionsNode($4)); } |
| | /* implicit type */ drive_strength decl_dimensions_opt |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, nullptr, $1, |
| MakePackedDimensionsNode($2)), |
| $3, MakeUnpackedDimensionsNode($4)); } |
| ; |
| |
| /* with optional decl_dimensions before and after */ |
| /* All declared GenericIdentifiers are wrapped in kUnqualifiedId to make their |
| * shape more consistent with MakeTypeIdDimensionsTuple. |
| */ |
| type_identifier_followed_by_id |
| : unqualified_id decl_dimensions_opt GenericIdentifier |
| { $$ = MakeTypeIdTuple( |
| MakeTaggedNode(N::kDataType, $1, |
| MakePackedDimensionsNode($2)), |
| MakeTaggedNode(N::kUnqualifiedId, $3)); } |
| /* $1 is type */ |
| | qualified_id decl_dimensions_opt GenericIdentifier |
| { $$ = MakeTypeIdTuple( |
| MakeTaggedNode(N::kDataType, $1, |
| MakePackedDimensionsNode($2)), |
| MakeTaggedNode(N::kUnqualifiedId, $3)); } |
| /* The following are 'interface_port_header' from the LRM: */ |
| | unqualified_id '.' member_name decl_dimensions_opt GenericIdentifier |
| { $$ = MakeTypeIdTuple( |
| MakeTaggedNode(N::kDataType, |
| MakeTaggedNode(N::kInterfacePortHeader, |
| $1, $2, $3), |
| MakePackedDimensionsNode($4)), |
| MakeTaggedNode(N::kUnqualifiedId, $5)); } |
| /* $1..$3 is interface modport */ |
| | TK_interface '.' member_name GenericIdentifier |
| { $$ = MakeTypeIdTuple( |
| MakeTaggedNode(N::kDataType, |
| MakeTaggedNode(N::kInterfacePortHeader, |
| $1, $2, $3), nullptr), |
| MakeTaggedNode(N::kUnqualifiedId, $4)); } |
| | TK_interface GenericIdentifier |
| { $$ = MakeTypeIdTuple( |
| MakeTaggedNode(N::kDataType, |
| MakeTaggedNode(N::kInterfacePortHeader, |
| $1), nullptr), |
| MakeTaggedNode(N::kUnqualifiedId, $2)); } |
| ; |
| |
| |
| /* Return type and declaration name: */ |
| /* no delay3 or drive_strength, for data_declaration */ |
| type_identifier_or_implicit_basic_followed_by_id |
| // TODO(jeremycs): standardize this family of rules |
| : unqualified_id GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, |
| MakeTaggedNode(N::kDataType, $1), $2); } |
| /* $1 is type */ |
| | qualified_id GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, |
| MakeTaggedNode(N::kDataType, $1), $2); } |
| /* $1 is type */ |
| | /* implicit type */ unqualified_id |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, |
| MakeTaggedNode(N::kDataType, nullptr), $1); } |
| /* This rule really wants to be (implicit type): |
| * GenericIdentifier |
| * but to resolve a conflict due to insufficient lookahead, it is "upgraded" |
| * to a more inclusive nonterminal. |
| * TODO(fangism): verify that this is GenericIdentifier without parameters. |
| */ |
| /* The following are 'interface_port_header' from the LRM: */ |
| | unqualified_id '.' member_name GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, |
| MakeTaggedNode(N::kDataType, |
| MakeTaggedNode(N::kInterfacePortHeader, |
| $1, $2, $3)), |
| $4); } |
| /* $1..$3 is interface.modport */ |
| | TK_interface '.' member_name GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, |
| MakeTaggedNode(N::kDataType, |
| MakeTaggedNode(N::kInterfacePortHeader, |
| $1, $2, $3)), |
| $4); } |
| | TK_interface GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, |
| MakeTaggedNode(N::kDataType, |
| MakeTaggedNode(N::kInterfacePortHeader, |
| $1)), |
| $2); } |
| ; |
| |
| /* data_type or class_id followed by declared name, optional array size |
| * The declared name can be scope-qualified for out-of-line definitions. |
| * Here, the last 'class_id' covers scope-qualified names. |
| */ |
| type_identifier_or_implicit_basic_followed_by_id_and_dimensions_opt |
| : qualified_id decl_dimensions_opt |
| class_id decl_dimensions_opt |
| { $$ = MakeTypeIdDimensionsTuple( |
| MakeTaggedNode(N::kDataType, $1, |
| MakePackedDimensionsNode($2)), |
| $3, MakeUnpackedDimensionsNode($4)); } |
| /* $1 is type */ |
| | unqualified_id decl_dimensions_opt |
| class_id decl_dimensions_opt |
| { $$ = MakeTypeIdDimensionsTuple( |
| MakeTaggedNode(N::kDataType, $1, |
| MakePackedDimensionsNode($2)), |
| $3, MakeUnpackedDimensionsNode($4)); } |
| | unqualified_id '.' member_name decl_dimensions_opt |
| class_id decl_dimensions_opt |
| /* This looks like reference_or_call */ |
| { $$ = MakeTypeIdDimensionsTuple( |
| MakeTaggedNode(N::kDataType, |
| MakeTaggedNode(N::kInterfacePortHeader, |
| $1, $2, $3), |
| MakePackedDimensionsNode($4)), |
| $5, MakeUnpackedDimensionsNode($6)); } |
| /* $1..$3 is interface.modport */ |
| | /* implicit type */ unqualified_id decl_dimensions_opt |
| { $$ = MakeTypeIdDimensionsTuple( |
| MakeTaggedNode(N::kDataType, nullptr, nullptr), |
| $1, MakeUnpackedDimensionsNode($2)); } |
| | /* implicit type */ qualified_id decl_dimensions_opt |
| { $$ = MakeTypeIdDimensionsTuple( |
| MakeTaggedNode(N::kDataType, nullptr, nullptr), |
| $1, MakeUnpackedDimensionsNode($2)); } |
| /* This rule really wants to be (implicit type): |
| * GenericIdentifier decl_dimensions_opt |
| * However, since (GenericIdentifier decl_dimensions_opt) is |
| * ambiguously an implicit-typed declaration and a return type, there is |
| * insufficient symbol lookahead to resolve the difference. |
| * Thus, GenericIdentifier is "upgraded" to a construct that captures |
| * GenericIdentifier without conflict, here, unqualified_id. |
| * This permits invalid constructs, so syntax should be enforced in a |
| * separate pass. |
| */ |
| ; |
| |
| data_type_or_implicit |
| : decl_dimensions delay3_or_drive_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, nullptr, |
| MakePackedDimensionsNode($1)), |
| $2, nullptr, nullptr); } |
| | signing decl_dimensions_opt delay3_or_drive_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, $1, |
| MakePackedDimensionsNode($2)), |
| $3, nullptr, nullptr); } |
| | GenericIdentifier decl_dimensions_opt delay3_or_drive_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, $1, |
| MakePackedDimensionsNode($2)), |
| $3, nullptr, nullptr); } |
| | GenericIdentifier TK_SCOPE_RES GenericIdentifier decl_dimensions_opt delay3_or_drive_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode( |
| N::kDataType, |
| MakeTaggedNode(N::kQualifiedId, $1, $2, $3), |
| MakePackedDimensionsNode($4)), |
| $5, nullptr, nullptr); } |
| /* want to use just 'class_id' to cover all qualified and unqualified types, |
| * including parameterized types, but encounter grammar conflicts |
| */ |
| ; |
| |
| /* For declaring net_type or function_declaration return type, followed by declared name */ |
| data_type_or_implicit_followed_by_id_and_dimensions_opt |
| : data_type_primitive GenericIdentifier decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, $1, nullptr), |
| nullptr /* delay3_or_drive_opt */, |
| $2, MakeUnpackedDimensionsNode($3)); } |
| /* $1 is type, including optional packed dimensions */ |
| /* allows optional delay3 or drive_strength: */ |
| | type_identifier_or_implicit_followed_by_id_and_dimensions_opt |
| { $$ = move($1); } |
| | signing decl_dimensions_opt delay3_or_drive_opt |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, $1, |
| MakePackedDimensionsNode($2)), |
| $3, $4, |
| MakeUnpackedDimensionsNode($5)); } |
| | decl_dimensions delay3_or_drive_opt GenericIdentifier decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, nullptr, |
| MakePackedDimensionsNode($1)), |
| $2, $3, |
| MakeUnpackedDimensionsNode($4)); } |
| | TK_void GenericIdentifier decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitIdDimensions, |
| MakeTaggedNode(N::kDataType, $1, nullptr), |
| nullptr /* delay3_or_drive_opt */, $2, |
| MakeUnpackedDimensionsNode($3)); } |
| ; |
| |
| data_type_or_implicit_basic_followed_by_id |
| // TODO(jeremycs): standardize this family of rules |
| : data_type_primitive GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, |
| MakeTaggedNode(N::kDataType, $1), $2); } |
| /* forbids optional delay3 or drive_strength: */ |
| | type_identifier_or_implicit_basic_followed_by_id |
| { $$ = move($1); } |
| | signing decl_dimensions_opt GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, |
| MakeTaggedNode(N::kDataType, $1, |
| MakePackedDimensionsNode($2)), |
| $3); } |
| | decl_dimensions GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, |
| MakeTaggedNode(N::kDataType, nullptr, |
| MakePackedDimensionsNode($1)), |
| $2); } |
| | TK_void GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, |
| MakeTaggedNode(N::kDataType, $1), $2); } |
| ; |
| |
| /** |
| * For general port declarations: (tf_port_item, port_declaration_noattr) |
| * This rule was introduced as a combination of: |
| * TYPE DIM ID DIM |
| * TYPE DIM ID |
| * TYPE ID |
| * DIM ID DIM |
| * DIM ID |
| * ID |
| * where TYPE can be an ID. |
| * |
| * ID can now be a scope-qualified name (here, class_name), |
| * to support out-of-line definitions. |
| **/ |
| data_type_or_implicit_basic_followed_by_id_and_dimensions_opt |
| : data_type_primitive class_id decl_dimensions_opt |
| { $$ = MakeTypeIdDimensionsTuple( |
| MakeTaggedNode(N::kDataType, $1, |
| nullptr /* packed dimensions */), |
| $2, MakeUnpackedDimensionsNode($3)); } |
| /* forbids optional delay3 or drive_strength: */ |
| | type_identifier_or_implicit_basic_followed_by_id_and_dimensions_opt |
| { $$ = move($1); } |
| | signing decl_dimensions_opt class_id decl_dimensions_opt |
| { $$ = MakeTypeIdDimensionsTuple( |
| MakeTaggedNode(N::kDataType, $1, |
| MakePackedDimensionsNode($2)), |
| $3, MakeUnpackedDimensionsNode($4)); } |
| | decl_dimensions class_id decl_dimensions_opt |
| { $$ = MakeTypeIdDimensionsTuple( |
| MakeTaggedNode(N::kDataType, nullptr, |
| MakePackedDimensionsNode($1)), |
| $2, MakeUnpackedDimensionsNode($3)); } |
| | TK_void class_id decl_dimensions_opt |
| { $$ = MakeTypeIdDimensionsTuple( |
| MakeTaggedNode(N::kDataType, $1, nullptr), |
| $2, MakeUnpackedDimensionsNode($3)); } |
| ; |
| |
| description |
| : module_or_interface_declaration |
| { $$ = move($1); } |
| | udp_primitive |
| { $$ = move($1); } |
| | config_declaration |
| { $$ = move($1); } |
| | nature_declaration |
| { $$ = move($1); } |
| | package_declaration |
| { $$ = move($1); } |
| | discipline_declaration |
| { $$ = move($1); } |
| | package_item_no_pp |
| { $$ = move($1); } |
| | TKK_attribute '(' GenericIdentifier ',' |
| TK_StringLiteral ',' TK_StringLiteral ')' |
| { $$ = MakeTaggedNode(N::kAttribute, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7), |
| $8)); } |
| | bind_directive |
| { $$ = move($1); } |
| | preprocessor_balanced_description_items |
| { $$ = move($1); } |
| | preprocessor_action |
| { $$ = move($1); } |
| ; |
| description_list_opt |
| : description_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| description_list |
| : description |
| { $$ = MakeTaggedNode(N::kDescriptionList, $1); } |
| | description_list description |
| { $$ = ExtendNode($1, $2); } |
| ; |
| preprocessor_balanced_description_items |
| : preprocessor_if_header description_list_opt |
| preprocessor_elsif_description_items_opt |
| preprocessor_else_description_item_opt |
| PP_endif |
| { $$ = MakeTaggedNode(N::kPreprocessorBalancedDescriptionItems, |
| ExtendNode($1, $2), ForwardChildren($3), $4, $5); |
| } |
| ; |
| preprocessor_elsif_description_items_opt |
| : preprocessor_elsif_description_items |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_elsif_description_items |
| : preprocessor_elsif_description_items preprocessor_elsif_description_item |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_elsif_description_item |
| { $$ = MakeNode($1); } /* Don't bother tagging; node will be flattened. */ |
| ; |
| preprocessor_elsif_description_item |
| : preprocessor_elsif_header description_list_opt |
| { $$ = ExtendNode($1, $2); } |
| ; |
| preprocessor_else_description_item_opt |
| : preprocessor_else_description_item |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_else_description_item |
| : PP_else description_list_opt |
| { $$ = MakeTaggedNode(N::kPreprocessorElseClause, $1, $2); } |
| ; |
| endnew_opt |
| : ':' TK_new |
| { $$ = MakeTaggedNode(N::kEndNew, $1, $2); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| dynamic_array_new |
| : TK_new '[' expression ']' |
| { $$ = MakeTaggedNode(N::kDynamicArrayNew, $1, |
| MakeBracketGroup($2, $3, $4), nullptr); } |
| | TK_new '[' expression ']' '(' expression ')' |
| { $$ = MakeTaggedNode(N::kDynamicArrayNew, $1, |
| MakeBracketGroup($2, $3, $4), |
| MakeParenGroup($5, $6, $7)); } |
| |
| ; |
| for_step_opt |
| : for_step |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| for_step |
| : for_step ',' assignment_statement |
| { $$ = ExtendNode($1, $2, $3); } |
| | assignment_statement |
| { $$ = MakeTaggedNode(N::kForStepList, $1); } |
| ; |
| /* LRM: this is named for_step_assignment */ |
| assignment_statement |
| : assignment_statement_no_expr |
| { $$ = move($1); } |
| | inc_or_dec_expression |
| { $$ = move($1); } |
| /* TODO(b/150645241): function_subroutine_call */ |
| ; |
| assignment_statement_no_expr |
| : lpvalue '=' expression |
| { $$ = MakeTaggedNode(N::kNetVariableAssignment, $1, $2, $3); } |
| | assign_modify_statement |
| { $$ = move($1); } |
| ; |
| |
| function_prototype |
| /* TODO(fangism): can this be structured like FunctionHeader? */ |
| /* users of this rule may append a trailing ';' */ |
| : TK_function lifetime_opt |
| /* data_type_or_implicit_or_void GenericIdentifier */ |
| data_type_or_implicit_basic_followed_by_id_and_dimensions_opt |
| tf_port_list_paren_opt |
| { $$ = MakeTaggedNode(N::kFunctionPrototype, |
| qualifier_placeholder, $1, $2, $3, $4); } |
| /* Without port list, is suitable for export declarations. */ |
| ; |
| |
| function_return_type_and_id |
| : data_type_or_implicit_basic_followed_by_id_and_dimensions_opt |
| /* $1 should not have unpacked dimensions */ |
| { $$ = RepackReturnTypeId(move($1)); } |
| | interface_type class_id |
| { $$ = RepackReturnTypeId(MakeTypeIdDimensionsTuple( |
| MakeTaggedNode(N::kDataType, $1, nullptr), $2, nullptr)); } |
| ; |
| |
| function_declaration |
| /* This covers both in-line declarations and out-of-line class method |
| * declarations. |
| */ |
| : TK_function lifetime_opt |
| function_return_type_and_id '(' tf_port_list_opt ')' ';' |
| /* block_item_decls_opt statement_or_null_list_opt */ |
| block_item_or_statement_or_null_list_opt |
| TK_endfunction endfunction_label_opt |
| { $$ = MakeFunctionDeclaration(qualifier_placeholder, $1, $2, |
| ForwardChildren($3), // expand type id pair |
| MakeParenGroup($4, $5, $6), |
| $7, nullptr, $8, $9, $10); } |
| | TK_function lifetime_opt |
| function_return_type_and_id ';' |
| function_item_list |
| statement_or_null_list_opt |
| TK_endfunction endfunction_label_opt |
| { $$ = MakeFunctionDeclaration(qualifier_placeholder, $1, $2, |
| ForwardChildren($3), // expand type id pair |
| nullptr, $4, $5, $6, $7, $8); } |
| | TK_function lifetime_opt |
| function_return_type_and_id ';' |
| /* empty function_item_list */ |
| statement_or_null_list_opt |
| TK_endfunction endfunction_label_opt |
| { $$ = MakeFunctionDeclaration(qualifier_placeholder, $1, $2, |
| ForwardChildren($3), // expand type id pair |
| nullptr, $4, nullptr, $5, $6, $7); } |
| ; |
| |
| endfunction_label_opt |
| : label_opt |
| { $$ = $1 ? MakeTaggedNode(N::kFunctionEndlabel, ForwardChildren($1)) |
| : nullptr; } |
| | ':' TK_new |
| /* for constructors */ |
| { $$ = MakeTaggedNode(N::kFunctionEndlabel, $1, $2); } |
| ; |
| implicit_class_handle |
| : TK_this |
| { $$ = move($1); } |
| | TK_super |
| { $$ = move($1); } |
| ; |
| |
| /* TODO(jeremycs): Fill this out */ |
| inc_or_dec_expression |
| : TK_INCR lpvalue /* %prec UNARY_PREC */ |
| { $$ = MakeTaggedNode(N::kIncrementDecrementExpression, $1, $2); } |
| | lpvalue TK_INCR /* %prec UNARY_PREC */ |
| { $$ = MakeTaggedNode(N::kIncrementDecrementExpression, $1, $2); } |
| | TK_DECR lpvalue /* %prec UNARY_PREC */ |
| { $$ = MakeTaggedNode(N::kIncrementDecrementExpression, $1, $2); } |
| | lpvalue TK_DECR /* %prec UNARY_PREC */ |
| { $$ = MakeTaggedNode(N::kIncrementDecrementExpression, $1, $2); } |
| ; |
| integer_atom_type |
| : TK_byte |
| { $$ = move($1); } |
| | TK_shortint |
| { $$ = move($1); } |
| | TK_int |
| { $$ = move($1); } |
| | TK_longint |
| { $$ = move($1); } |
| | TK_integer |
| { $$ = move($1); } |
| | TK_time |
| { $$ = move($1); } |
| ; |
| integer_vector_type |
| : TK_reg |
| { $$ = move($1); } |
| | TK_bit |
| { $$ = move($1); } |
| | TK_logic |
| { $$ = move($1); } |
| ; |
| join_keyword |
| : TK_join |
| { $$ = move($1); } |
| | TK_join_none |
| { $$ = move($1); } |
| | TK_join_any |
| { $$ = move($1); } |
| ; |
| jump_statement |
| : TK_break ';' |
| { $$ = MakeTaggedNode(N::kJumpStatement, $1, $2); } |
| | TK_continue ';' |
| { $$ = MakeTaggedNode(N::kJumpStatement, $1, $2); } |
| | TK_return ';' |
| { $$ = MakeTaggedNode(N::kJumpStatement, $1, nullptr, $2); } |
| | TK_return expression ';' |
| { $$ = MakeTaggedNode(N::kJumpStatement, $1, $2, $3); } |
| ; |
| loop_statement |
| : TK_for '(' for_initialization_opt ';' expression_opt ';' for_step_opt ')' |
| statement_or_null |
| { $$ = MakeTaggedNode(N::kForLoopStatement, |
| MakeTaggedNode(N::kLoopHeader, $1, |
| MakeParenGroup($2, |
| MakeTaggedNode(N::kForSpec, |
| $3, $4, |
| MakeTaggedNode(N::kForCondition, $5), |
| $6, $7), |
| $8)), |
| $9); } |
| | TK_forever statement_or_null |
| { $$ = MakeTaggedNode(N::kForeverLoopStatement, $1, $2); } |
| | repeat_control statement_or_null |
| { $$ = MakeTaggedNode(N::kRepeatLoopStatement, $1, $2); } |
| | TK_while '(' expression ')' statement_or_null |
| { $$ = MakeTaggedNode(N::kWhileLoopStatement, $1, $2, $3, $4, $5); } |
| | TK_do statement_or_null TK_while '(' expression ')' ';' |
| { $$ = MakeTaggedNode(N::kDoWhileLoopStatement, $1, $2, $3, $4, $5, $6, $7); } |
| | TK_foreach '(' reference ')' statement_or_null |
| { $$ = MakeTaggedNode(N::kForeachLoopStatement, $1, $2, $3, $4, $5); } |
| /* TODO(fangism): $3 must end with the form: '[' loop_variables ']' . |
| * where loop_variables is a list of loop variable identifiers. |
| * See note in variable_dimension nonterminal. |
| */ |
| ; |
| for_initialization_opt |
| : for_initialization |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| for_initialization |
| : for_initialization ',' for_init_decl_or_assign |
| { $$ = ExtendNode($1, $2, $3); } |
| | for_init_decl_or_assign |
| { $$ = MakeTaggedNode(N::kForInitializationList, $1); } |
| ; |
| for_init_decl_or_assign |
| : lpvalue '=' expression |
| { $$ = MakeTaggedNode(N::kForInitialization, nullptr, nullptr, $1, $2, $3); } |
| | data_type GenericIdentifier '=' expression |
| { $$ = MakeTaggedNode(N::kForInitialization, nullptr, $1, $2, $3, $4); } |
| | TK_var data_type GenericIdentifier '=' expression |
| { $$ = MakeTaggedNode(N::kForInitialization, $1, $2, $3, $4, $5); } |
| ; |
| |
| /* TODO(fangism): collect list of fields/variables to report. */ |
| list_of_variable_decl_assignments |
| : variable_decl_assignment |
| { $$ = MakeTaggedNode(N::kVariableDeclarationAssignmentList, $1); } |
| | list_of_variable_decl_assignments ',' variable_decl_assignment |
| { $$ = ExtendNode($1, $2, $3); } |
| ; |
| variable_decl_assignment |
| /* similar to gate_instance_or_register_variable */ |
| : GenericIdentifier decl_dimensions_opt trailing_decl_assignment_opt |
| { $$ = MakeTaggedNode(N::kVariableDeclarationAssignment, $1, |
| MakeUnpackedDimensionsNode($2), $3); } |
| /* TODO(fangism): $2 must start with unsized dimensions '[' ']' |
| * for dynamic_array_new. |
| */ |
| /* TODO(fangism): Arrays should not be assigned to a singular rvalue. */ |
| ; |
| trailing_decl_assignment_opt |
| : trailing_decl_assignment |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| trailing_decl_assignment |
| /* similar to trailing_assign */ |
| : '=' dynamic_array_new |
| { $$ = MakeTaggedNode(N::kTrailingAssign, $1, $2); } |
| | '=' expression |
| { $$ = MakeTaggedNode(N::kTrailingAssign, $1, $2); } |
| | '=' class_new |
| { $$ = MakeTaggedNode(N::kTrailingAssign, $1, $2); } |
| /* TODO(fangism): allow [ class_id "::" ] class scope before 'new' */ |
| ; |
| method_qualifier_list_opt |
| : method_qualifier_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| method_qualifier_list |
| : method_qualifier_list method_qualifier |
| { $$ = ExtendNode($1, $2); } |
| | method_qualifier |
| { $$ = MakeTaggedNode(N::kQualifierList, $1); } |
| ; |
| method_property_qualifier_list_not_starting_with_virtual |
| : method_property_qualifier_list_not_starting_with_virtual |
| method_property_qualifier |
| { $$ = ExtendNode($1, $2); } |
| | property_qualifier /* excludes TK_virtual */ |
| { $$ = MakeTaggedNode(N::kQualifierList, $1); } |
| ; |
| method_qualifier |
| : TK_virtual |
| { $$ = move($1); } |
| | TK_pure TK_virtual |
| { $$ = move($1); } |
| | class_item_qualifier |
| { $$ = move($1); } |
| ; |
| method_property_qualifier |
| /* grammatic simplification: unify method_qualifier with property qualifier */ |
| : TK_virtual |
| { $$ = move($1); } |
| | class_item_qualifier |
| { $$ = move($1); } |
| | random_qualifier |
| { $$ = move($1); } |
| ; |
| |
| modport_declaration |
| : TK_modport modport_item_list ';' |
| { $$ = MakeTaggedNode(N::kModportDeclaration, $1, $2, $3); } |
| ; |
| modport_item_list |
| : modport_item |
| { $$ = MakeTaggedNode(N::kModportItemList, $1); } |
| | modport_item_list ',' modport_item |
| { $$ = ExtendNode($1, $2, $3); } |
| ; |
| modport_item |
| : GenericIdentifier '(' modport_ports_list ')' |
| { $$ = MakeTaggedNode(N::kModportItem, $1, MakeParenGroup($2, $3, $4)); } |
| ; |
| modport_ports_list |
| /* This is a list of modport_ports_declaration, whose rule would normally |
| be written as (from LRM): |
| |
| modport_ports_list |
| : modport_ports_list ',' modport_ports_declaration |
| | modport_ports_declaration |
| ; |
| modport_ports_declaration |
| : modport_clocking_declaration |
| | modport_simple_ports_declaration |
| | modport_tf_ports_declaration |
| ; |
| // each of these could be prefixed with 'attribute_list_opt' |
| |
| This set of rules is implemented in a state machine fashion to |
| eliminate the S/R conflict on ',' which acts as two types of separators: |
| separating declarations of the same type, and declarations of different |
| types. By writing explicit rules about the context before the separator, |
| we effectively give this a two-token lookahead. |
| |
| The tree structure returned is a (two-level) list-of-lists, where |
| the inner list can cover multiple identifier declarations. |
| */ |
| : modport_simple_ports_declaration_last |
| { $$ = move($1); } |
| | modport_tf_ports_declaration_last |
| { $$ = move($1); } |
| | modport_clocking_declaration_last |
| { $$ = move($1); } |
| ; |
| |
| dpi_spec_string |
| : TK_StringLiteral |
| { $$ = move($1); } |
| /* TODO(fangism): Verify this is "DPI-C" or "DPI". */ |
| ; |
| dpi_import_property_opt |
| : dpi_import_property |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| dpi_import_property |
| : TK_context |
| { $$ = move($1); } |
| /* suitable for task_prototype and function_prototype */ |
| | TK_pure |
| { $$ = move($1); } |
| /* suitable for only function_prototype */ |
| ; |
| |
| dpi_import_export |
| : dpi_import_item |
| { $$ = move($1); } |
| | dpi_export_item |
| { $$ = move($1); } |
| ; |
| dpi_export_item |
| /* The following rules are expanded from: |
| * TK_export dpi_spec_string { GenericIdentifier '=' }_opt modport_tf_port ';' |
| */ |
| : TK_export dpi_spec_string GenericIdentifier '=' modport_tf_port ';' |
| { $$ = MakeTaggedNode(N::kDPIExportItem, $1, $2, $3, $4, $5, $6); } |
| | TK_export dpi_spec_string modport_tf_port ';' |
| { $$ = MakeTaggedNode(N::kDPIExportItem, $1, $2, nullptr, nullptr, $3, $4); } |
| ; |
| import_export |
| : TK_export |
| { $$ = move($1); } |
| | TK_import |
| { $$ = move($1); } |
| ; |
| dpi_import_item |
| /* The following rules are expanded from: |
| * TK_import dpi_spec_string dpi_import_property_opt |
| * { GenericIdentifier '=' }_opt method_prototype ';' |
| */ |
| : TK_import dpi_spec_string dpi_import_property_opt |
| GenericIdentifier '=' method_prototype ';' |
| { $$ = MakeDPIImport($1, $2, $3, $4, $5, $6, $7); } |
| | TK_import dpi_spec_string dpi_import_property_opt method_prototype ';' |
| { $$ = MakeDPIImport($1, $2, $3, nullptr, nullptr, $4, $5); } |
| ; |
| |
| modport_ports_declaration_trailing_comma |
| : modport_simple_ports_declaration_trailing_comma |
| { $$ = move($1); } |
| | modport_tf_ports_declaration_trailing_comma |
| { $$ = move($1); } |
| | modport_clocking_declaration_trailing_comma |
| { $$ = move($1); } |
| ; |
| modport_simple_ports_declaration_trailing_comma |
| : modport_simple_ports_declaration_last ',' |
| /* At this point, we don't know whether the comma is followed by |
| a keyword or another continued declaration. Return a 2-tuple. */ |
| { $$ = MakeNode($1, $2); } |
| ; |
| modport_tf_ports_declaration_trailing_comma |
| : modport_tf_ports_declaration_last ',' |
| { $$ = MakeNode($1, $2); } /* Return a 2-tuple. */ |
| ; |
| modport_clocking_declaration_trailing_comma |
| : modport_clocking_declaration_last ',' |
| { $$ = MakeNode($1, $2); } /* Return a 2-tuple. */ |
| ; |
| modport_tf_ports_declaration_begin |
| : import_export |
| { $$ = MakeTaggedNode(N::kModportPortList, |
| MakeTaggedNode(N::kModportTFPortsDeclaration, $1)); } |
| | modport_ports_declaration_trailing_comma import_export |
| { $$ = ExtendFirstSublist( |
| $1, MakeTaggedNode(N::kModportTFPortsDeclaration, $2)); |
| } |
| ; |
| modport_tf_ports_declaration_last |
| : modport_tf_ports_declaration_begin modport_tf_port |
| { $$ = ExtendLastSublist($1, $2); } |
| | modport_tf_ports_declaration_trailing_comma modport_tf_port |
| { $$ = ExtendLastSublistWithSeparator($1, $2); } |
| ; |
| modport_clocking_declaration_begin |
| : TK_clocking |
| { $$ = MakeTaggedNode( |
| N::kModportPortList, |
| MakeTaggedNode(N::kModportClockingPortsDeclaration, $1)); } |
| | modport_ports_declaration_trailing_comma TK_clocking |
| { $$ = ExtendFirstSublist( |
| $1, MakeTaggedNode(N::kModportClockingPortsDeclaration, $2)); |
| } |
| ; |
| modport_clocking_declaration_last |
| : modport_clocking_declaration_begin GenericIdentifier |
| { $$ = ExtendLastSublist($1, $2); } |
| /* clocking declarations only take a single identifier (not a list), |
| thus the following rule is disabled: |
| | modport_clocking_declaration_trailing_comma GenericIdentifier |
| */ |
| ; |
| modport_simple_ports_declaration_begin |
| : port_direction |
| { $$ = MakeTaggedNode( |
| N::kModportPortList, |
| MakeTaggedNode(N::kModportSimplePortsDeclaration, $1)); } |
| | modport_ports_declaration_trailing_comma port_direction |
| { $$ = ExtendFirstSublist( |
| $1, MakeTaggedNode(N::kModportSimplePortsDeclaration, $2)); |
| } |
| ; |
| modport_simple_ports_declaration_last |
| : modport_simple_ports_declaration_begin modport_simple_port |
| { $$ = ExtendLastSublist($1, $2); } |
| | modport_simple_ports_declaration_trailing_comma modport_simple_port |
| { $$ = ExtendLastSublistWithSeparator($1, $2); } |
| ; |
| |
| modport_simple_port |
| : '.' member_name '(' expression ')' |
| { $$ = MakeTaggedNode(N::kModportSimplePort, $1, $2, |
| MakeParenGroup($3, $4, $5)); } |
| /* TODO(fangism): use distinct enums for these two cases */ |
| | GenericIdentifier |
| { $$ = MakeTaggedNode(N::kModportSimplePort, $1); } |
| ; |
| modport_tf_port |
| : task_prototype |
| { $$ = move($1); } |
| | function_prototype |
| { $$ = move($1); } |
| | GenericIdentifier |
| { $$ = move($1); } |
| ; |
| non_integer_type |
| : TK_real |
| { $$ = move($1); } |
| | TK_realtime |
| { $$ = move($1); } |
| | TK_shortreal |
| { $$ = move($1); } |
| ; |
| |
| macro_digits |
| : MacroCall |
| { $$ = move($1); } |
| | MacroIdentifier |
| { $$ = move($1); } |
| ; |
| based_number |
| : dec_based_number |
| { $$ = move($1); } |
| | bin_based_number |
| { $$ = move($1); } |
| | oct_based_number |
| { $$ = move($1); } |
| | hex_based_number |
| { $$ = move($1); } |
| ; |
| dec_based_number |
| : TK_DecBase TK_DecDigits |
| { $$ = MakeTaggedNode(N::kBaseDigits, $1, $2); } |
| | TK_DecBase TK_XZDigits |
| { $$ = MakeTaggedNode(N::kBaseDigits, $1, $2); } |
| | TK_DecBase macro_digits |
| { $$ = MakeTaggedNode(N::kBaseDigits, $1, $2); } |
| ; |
| bin_based_number |
| : TK_BinBase TK_BinDigits |
| { $$ = MakeTaggedNode(N::kBaseDigits, $1, $2); } |
| | TK_BinBase macro_digits |
| { $$ = MakeTaggedNode(N::kBaseDigits, $1, $2); } |
| ; |
| oct_based_number |
| : TK_OctBase TK_OctDigits |
| { $$ = MakeTaggedNode(N::kBaseDigits, $1, $2); } |
| | TK_OctBase macro_digits |
| { $$ = MakeTaggedNode(N::kBaseDigits, $1, $2); } |
| ; |
| hex_based_number |
| : TK_HexBase TK_HexDigits |
| { $$ = MakeTaggedNode(N::kBaseDigits, $1, $2); } |
| | TK_HexBase macro_digits |
| { $$ = MakeTaggedNode(N::kBaseDigits, $1, $2); } |
| ; |
| number |
| : based_number |
| { $$ = MakeTaggedNode(N::kNumber, $1); } |
| | TK_DecNumber |
| { $$ = MakeTaggedNode(N::kNumber, $1); } |
| | constant_dec_number based_number |
| { $$ = MakeTaggedNode(N::kNumber, $1, $2); } |
| | TK_UnBasedNumber |
| { $$ = MakeTaggedNode(N::kNumber, $1); } |
| | constant_dec_number TK_UnBasedNumber |
| { $$ = MakeTaggedNode(N::kNumber, $1, $2); } |
| ; |
| /* allow `macro where one might expect a constant number */ |
| constant_dec_number |
| : TK_DecNumber |
| { $$ = move($1); } |
| | MacroNumericWidth |
| { $$ = move($1); } |
| ; |
| open_range_list |
| : open_range_list ',' value_range |
| { $$ = ExtendNode($1, $2, $3); } |
| | value_range |
| { $$ = MakeTaggedNode(N::kOpenRangeList, $1); } |
| ; |
| package_declaration |
| : TK_package lifetime_opt GenericIdentifier ';' |
| package_item_list_opt |
| TK_endpackage label_opt |
| { $$ = MakeTaggedNode(N::kPackageDeclaration, $1, $2, $3, $4, $5, $6, $7); } |
| ; |
| module_package_import_list_opt |
| : package_import_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| package_import_list |
| : package_import_declaration |
| { $$ = MakeTaggedNode(N::kPackageImportList, $1); } |
| | package_import_list package_import_declaration |
| { $$ = ExtendNode($1, $2); } |
| ; |
| package_import_declaration |
| : TK_import package_import_item_list ';' |
| { $$ = MakeTaggedNode(N::kPackageImportDeclaration, $1, $2, $3); } |
| ; |
| package_export_declaration |
| : TK_export '*' TK_SCOPE_RES '*' ';' |
| { $$ = MakeTaggedNode(N::kPackageExportDeclaration, $1, |
| MakeTaggedNode(N::kPackageImportItem, |
| MakeTaggedNode(N::kScopePrefix, $2, $3), |
| $4), |
| $5); |
| } |
| | TK_export package_import_item_list ';' |
| { $$ = MakeTaggedNode(N::kPackageExportDeclaration, $1, $2, $3); } |
| ; |
| package_import_item |
| : scope_prefix GenericIdentifier |
| { $$ = MakeTaggedNode(N::kPackageImportItem, $1, $2); } |
| | scope_prefix '*' |
| { $$ = MakeTaggedNode(N::kPackageImportItem, $1, $2); } |
| /** |
| : GenericIdentifier TK_SCOPE_RES GenericIdentifier |
| | GenericIdentifier TK_SCOPE_RES '*' |
| **/ |
| ; |
| package_import_item_list |
| : package_import_item_list ',' package_import_item |
| { $$ = ExtendNode($1, $2, $3); } |
| | package_import_item |
| { $$ = MakeTaggedNode(N::kPackageImportItemList, $1); } |
| ; |
| package_item |
| : package_item_no_pp |
| { $$ = move($1); } |
| | preprocessor_balanced_package_items |
| { $$ = move($1); } |
| | preprocessor_action |
| { $$ = move($1); } |
| ; |
| package_item_no_pp |
| : package_or_generate_item_declaration |
| { $$ = move($1); } |
| | timeunits_declaration |
| { $$ = move($1); } |
| | type_declaration |
| { $$ = move($1); } |
| | data_declaration |
| { $$ = move($1); } |
| | interface_data_declaration |
| { $$ = move($1); } |
| | clocking_declaration |
| { $$ = move($1); } |
| | let_declaration |
| { $$ = move($1); } |
| | constraint_declaration_package_item |
| { $$ = move($1); } |
| | package_import_declaration |
| { $$ = move($1); } |
| | package_export_declaration |
| { $$ = move($1); } |
| | timescale_directive |
| { $$ = move($1); } |
| | misc_directive |
| { $$ = move($1); } |
| | module_item_directive |
| { $$ = move($1); } |
| | macro_call_or_item |
| { $$ = move($1); } |
| | error ';' /* error in data or type declaration */ |
| { yyerrok; $$ = Recover(); } |
| /** |
| * Allow subset of module_items at the top-level to be able to |
| * parse files that are `included within module bodies. |
| * Tracked as b/36417019. |
| **/ |
| | any_param_declaration |
| { $$ = move($1); } |
| | /* attribute_list_opt */ TK_initial statement_item |
| { $$ = MakeTaggedNode(N::kInitialStatement, $1, $2); } |
| ; |
| preprocessor_balanced_package_items |
| : preprocessor_if_header package_item_list_opt |
| preprocessor_elsif_package_items_opt |
| preprocessor_else_package_item_opt |
| PP_endif |
| { $$ = MakeTaggedNode(N::kPreprocessorBalancedPackageItems, |
| ExtendNode($1, $2), ForwardChildren($3), $4, $5); |
| } |
| ; |
| preprocessor_elsif_package_items_opt |
| : preprocessor_elsif_package_items |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_elsif_package_items |
| : preprocessor_elsif_package_items preprocessor_elsif_package_item |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_elsif_package_item |
| { $$ = MakeNode($1); } /* Don't bother tagging; node will be flattened. */ |
| ; |
| preprocessor_elsif_package_item |
| : preprocessor_elsif_header package_item_list_opt |
| { $$ = ExtendNode($1, $2); } |
| ; |
| preprocessor_else_package_item_opt |
| : preprocessor_else_package_item |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_else_package_item |
| : PP_else package_item_list_opt |
| { $$ = MakeTaggedNode(N::kPreprocessorElseClause, $1, $2); } |
| ; |
| package_item_list |
| : package_item_list package_item |
| { $$ = ExtendNode($1, $2); } |
| | package_item |
| { $$ = MakeTaggedNode(N::kPackageItemList, $1); } |
| ; |
| package_item_list_opt |
| : package_item_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| misc_directive |
| /* These directives may appear in top/package scope. */ |
| : DR_resetall |
| { $$ = move($1); } |
| | DR_celldefine |
| { $$ = move($1); } |
| | DR_endcelldefine |
| { $$ = move($1); } |
| | DR_unconnected_drive pull01 |
| { $$ = MakeTaggedNode(N::kTopLevelDirective, $1, $2); } |
| | DR_nounconnected_drive |
| { $$ = move($1); } |
| | DR_default_nettype net_type_or_none |
| { $$ = MakeTaggedNode(N::kTopLevelDirective, $1, $2); } |
| | DR_suppress_faults |
| { $$ = move($1); } |
| | DR_nosuppress_faults |
| { $$ = move($1); } |
| | DR_enable_portfaults |
| { $$ = move($1); } |
| | DR_disable_portfaults |
| { $$ = move($1); } |
| | DR_delay_mode_distributed |
| { $$ = move($1); } |
| | DR_delay_mode_path |
| { $$ = move($1); } |
| | DR_delay_mode_unit |
| { $$ = move($1); } |
| | DR_delay_mode_zero |
| { $$ = move($1); } |
| | DR_default_decay_time decay_value_simple |
| { $$ = MakeTaggedNode(N::kTopLevelDirective, $1, $2); } |
| /* $2 can be real or integer time */ |
| | DR_default_trireg_strength TK_DecNumber |
| { $$ = MakeTaggedNode(N::kTopLevelDirective, $1, $2); } |
| /* $2 is integer in [0,250] */ |
| | DR_pragma |
| { $$ = move($1); } |
| | DR_uselib |
| { $$ = move($1); } |
| | DR_begin_keywords TK_StringLiteral |
| { $$ = MakeTaggedNode(N::kTopLevelDirective, $1, $2); } |
| /* $2 should name a standard, e.g. "1800-2012" or "1364-2005" */ |
| | DR_end_keywords |
| { $$ = move($1); } |
| ; |
| net_type_or_none |
| : net_type |
| { $$ = move($1); } |
| | GenericIdentifier |
| { $$ = move($1); } |
| /* $1 should be 'none', which is not a keyword. */ |
| ; |
| module_item_directive |
| /* These directives may appear within a module. */ |
| : DR_protect |
| { $$ = move($1); } |
| | DR_endprotect |
| { $$ = move($1); } |
| ; |
| port_direction |
| : dir |
| { $$ = move($1); } |
| | TK_ref |
| { $$ = move($1); } |
| ; |
| tf_port_direction |
| : port_direction |
| { $$ = move($1); } |
| | TK_const TK_ref |
| { $$ = MakeTaggedNode(N::kConstRef, $1, $2); } |
| ; |
| tf_port_direction_opt |
| : tf_port_direction |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| property_qualifier |
| : class_item_qualifier |
| { $$ = move($1); } |
| | random_qualifier |
| { $$ = move($1); } |
| ; |
| property_spec |
| : event_control_opt property_spec_disable_iff_opt property_expr |
| { $$ = MakeTaggedNode(N::kPropertySpec, $1, $2, $3); } |
| ; |
| sequence_spec |
| : event_control_opt property_spec_disable_iff_opt sequence_expr |
| { $$ = MakeTaggedNode(N::kSequenceSpec, $1, $2, $3); } |
| ; |
| property_spec_disable_iff |
| : TK_disable TK_iff '(' expression_or_dist ')' |
| { $$ = MakeTaggedNode(N::kPropertySpecDisableIff, |
| $1, $2, MakeParenGroup($3, $4, $5)); } |
| ; |
| property_spec_disable_iff_opt |
| : property_spec_disable_iff |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| random_qualifier_opt |
| : random_qualifier |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| random_qualifier |
| : TK_rand |
| { $$ = move($1); } |
| | TK_randc |
| { $$ = move($1); } |
| ; |
| |
| signing |
| : TK_signed |
| { $$ = move($1); } |
| | TK_unsigned |
| { $$ = move($1); } |
| ; |
| statement |
| : /* attribute_list_opt */ statement_item |
| { $$ = move($1); } |
| | unqualified_id ':' /* attribute_list_opt */ statement_item |
| { $$ = MakeTaggedNode(N::kLabeledStatement, $1, $2, $3); } |
| /* $1 should be a GenericIdentifier, but unqualified_id avoids conflict. */ |
| ; |
| statement_or_null |
| : statement |
| { $$ = move($1); } |
| | /* attribute_list_opt */ ';' |
| { $$ = MakeTaggedNode(N::kNullStatement, $1); } |
| ; |
| block_item_or_statement_or_null |
| : block_item_decl |
| { $$ = move($1); } |
| | statement_or_null |
| { $$ = move($1); } |
| ; |
| block_item_or_statement_or_null_list |
| : block_item_or_statement_or_null_list block_item_or_statement_or_null |
| { $$ = ExtendNode($1, $2); } |
| | block_item_or_statement_or_null |
| { $$ = MakeTaggedNode(N::kBlockItemStatementList, $1); } |
| ; |
| block_item_or_statement_or_null_list_opt |
| : block_item_or_statement_or_null_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = MakeTaggedNode(N::kBlockItemStatementList); } |
| ; |
| stream_expression |
| : expression |
| { $$ = move($1); } |
| /* TODO(fangism): |
| | expression TK_with select_variable_dimension |
| */ |
| ; |
| stream_expression_list |
| : stream_expression_list ',' stream_expression |
| { $$ = ExtendNode($1, $2, $3); } |
| | stream_expression |
| { $$ = MakeTaggedNode(N::kStreamExpressionList, $1); } |
| ; |
| stream_operator |
| : TK_LS |
| { $$ = move($1); } |
| | TK_RS |
| { $$ = move($1); } |
| ; |
| streaming_concatenation |
| : '{' stream_operator slice_size_opt '{' stream_expression_list '}' '}' |
| { $$ = MakeTaggedNode(N::kStreamingConcatenation, $1, $2, $3, |
| MakeTaggedNode(N::kConcatenationExpression, $4, $5, $6), $7); } |
| /* accommodate macro call as operand of stream_operator */ |
| | '{' stream_operator slice_size MacroCall '}' |
| { $$ = MakeTaggedNode(N::kStreamingConcatenation, $1, $2, $3, $4, $5); } |
| | '{' stream_operator slice_size MacroIdentifier '}' |
| { $$ = MakeTaggedNode(N::kStreamingConcatenation, $1, $2, $3, $4, $5); } |
| | '{' stream_operator MacroCall '}' |
| { $$ = MakeTaggedNode(N::kStreamingConcatenation, $1, $2, nullptr, $3, $4); } |
| | '{' stream_operator MacroIdentifier '}' |
| { $$ = MakeTaggedNode(N::kStreamingConcatenation, $1, $2, nullptr, $3, $4); } |
| ; |
| slice_size_opt |
| : slice_size |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| slice_size |
| /* similar to parameter_expr */ |
| /* original slice_size: |
| : expression // must be constant |
| | data_type |
| * However, to avoid conflict with the '{' that follows, we really want |
| * any-expression-that-doesn't-start-with-{. |
| * A close compromise is expr_primary without expr_primary_braces. |
| */ |
| : expr_primary_no_groups |
| { $$ = move($1); } |
| | expr_primary_parens |
| { $$ = move($1); } |
| | reference_or_call |
| { $$ = move($1); } |
| | data_type_primitive |
| { $$ = move($1); } |
| /* non-primitive data-types already covered by reference_or_call */ |
| ; |
| task_prototype |
| : TK_task lifetime_opt GenericIdentifier tf_port_list_paren_opt |
| /* users of this rule may append a trailing ';' */ |
| { $$ = MakeTaggedNode(N::kTaskPrototype, qualifier_placeholder, |
| $1, $2, $3, $4); } |
| |
| ; |
| task_declaration |
| : TK_task lifetime_opt task_declaration_id tf_port_list_paren_opt ';' |
| /** replaced with unified list to eliminate conflict |
| task_item_list_opt statement_or_null_list_opt |
| **/ |
| tf_item_or_statement_or_null_list_opt |
| TK_endtask label_opt |
| { $$ = MakeTaggedNode(N::kTaskDeclaration, |
| MakeTaggedNode(N::kTaskHeader, qualifier_placeholder, |
| $1, $2, $3, $4, $5), |
| $6, $7, $8); } |
| /* The declared name, $3, can be scope-qualified, |
| * which is covered by class_id. |
| */ |
| /** merged above |
| | TK_task lifetime_opt task_declaration_id |
| '(' tf_port_list_opt ')' ';' |
| block_item_decls_opt |
| statement_or_null_list_opt |
| TK_endtask |
| label_opt |
| **/ |
| ; |
| task_declaration_id |
| : GenericIdentifier scope_or_if_res GenericIdentifier |
| { $$ = MakeTaggedNode(N::kQualifiedId, |
| MakeTaggedNode(N::kUnqualifiedId, $1), $2, |
| MakeTaggedNode(N::kUnqualifiedId, $3)); } |
| | GenericIdentifier |
| { $$ = MakeTaggedNode(N::kUnqualifiedId, $1); } |
| ; |
| tf_port_declaration |
| /* tf_port_direction signed_unsigned_opt |
| * class_id_opt decl_dimensions_opt |
| * list_of_tf_variable_identifiers ';' |
| */ |
| /* Expanded to avoid GenericIdentifier conflict on implicit type: */ |
| : tf_port_direction signed_unsigned_opt |
| qualified_id decl_dimensions_opt |
| list_of_tf_variable_identifiers ';' |
| { $$ = MakeTaggedNode(N::kTFPortDeclaration, $1, |
| MakeTaggedNode(N::kDataType, |
| MakeTaggedNode(N::kDataTypePrimitive, |
| $2, $3), |
| MakePackedDimensionsNode($4)), |
| $5, $6); } |
| | tf_port_direction signed_unsigned_opt |
| unqualified_id decl_dimensions_opt |
| list_of_tf_variable_identifiers ';' |
| { $$ = MakeTaggedNode(N::kTFPortDeclaration, $1, |
| MakeTaggedNode(N::kDataType, |
| MakeTaggedNode(N::kDataTypePrimitive, $2, $3), |
| MakePackedDimensionsNode($4)), |
| $5, $6); } |
| | tf_port_direction signed_unsigned_opt decl_dimensions |
| list_of_tf_variable_identifiers ';' |
| { $$ = MakeTaggedNode(N::kTFPortDeclaration, $1, |
| MakeTaggedNode(N::kDataType, |
| MakeTaggedNode(N::kDataTypePrimitive, $2, nullptr), |
| MakePackedDimensionsNode($3)), |
| $4, $5); } |
| | tf_port_direction signed_unsigned_opt |
| list_of_tf_variable_identifiers ';' |
| { $$ = MakeTaggedNode(N::kTFPortDeclaration, $1, |
| MakeTaggedNode(N::kDataType, |
| MakeTaggedNode(N::kDataTypePrimitive, $2), |
| nullptr), |
| $3, $4); } |
| | tf_port_direction data_type_primitive |
| list_of_tf_variable_identifiers ';' |
| { $$ = MakeTaggedNode(N::kTFPortDeclaration, $1, |
| MakeTaggedNode(N::kDataType, $2, nullptr), |
| $3, $4); } |
| ; |
| list_of_tf_variable_identifiers |
| : list_of_tf_variable_identifiers ',' tf_variable_identifier |
| { $$ = ExtendNode($1, $2, $3); } |
| | tf_variable_identifier_first |
| { $$ = MakeTaggedNode(N::kTFVariableIdentifierList, $1); } |
| ; |
| tf_variable_identifier_first |
| /* This rule is a workaround to resolve a S/R conflict from implicit types. */ |
| : unqualified_id decl_dimensions_opt trailing_assign_opt |
| { $$ = MakeTaggedNode(N::kTFVariableIdentifier, $1, $2, $3); } |
| /* TODO(fangism): Verify that $1 doesn't actually have any parameters. */ |
| ; |
| tf_variable_identifier |
| : GenericIdentifier decl_dimensions_opt trailing_assign_opt |
| { $$ = MakeTaggedNode(N::kTFVariableIdentifier, $1, $2, $3); } |
| ; |
| tf_port_item |
| : tf_port_direction_opt data_type_or_implicit_basic_followed_by_id_and_dimensions_opt |
| tf_port_item_expr_opt |
| { $$ = MakeTaskFunctionPortItem($1, $2, $3); } |
| | tf_port_direction_opt interface_type GenericIdentifier decl_dimensions_opt |
| tf_port_item_expr_opt |
| { $$ = MakeTaskFunctionPortItem($1, |
| MakeTypeIdDimensionsTuple( |
| MakeTaggedNode(N::kDataType, $2, nullptr), |
| $3, MakeUnpackedDimensionsNode($4)), |
| $5); } |
| ; |
| tf_port_item_expr_opt |
| : '=' expression |
| { $$ = MakeTaggedNode(N::kTrailingAssign, $1, $2); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| tf_port_list |
| : tf_port_list_item_last |
| { $$ = move($1); } |
| | tf_port_list_preprocessor_last |
| { $$ = move($1); } |
| ; |
| tf_port_list_trailing_comma |
| : tf_port_list ',' |
| { $$ = ExtendNode($1, $2); } |
| ; |
| tf_port_list_item_last |
| : tf_port_list_trailing_comma tf_port_item |
| { $$ = ExtendNode($1, $2); } |
| | tf_port_list_preprocessor_last tf_port_item |
| { $$ = ExtendNode($1, $2); } |
| | tf_port_item |
| { $$ = MakeTaggedNode(N::kPortList, $1); } |
| ; |
| tf_port_list_preprocessor_last |
| : tf_port_list preprocessor_directive |
| { $$ = ExtendNode($1, $2); } |
| | tf_port_list_trailing_comma preprocessor_directive |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_directive |
| { $$ = MakeTaggedNode(N::kPortList, $1); } |
| ; |
| |
| timescale_directive |
| : DR_timescale time_literal '/' time_literal |
| { $$ = MakeTaggedNode(N::kTimescaleDirective, $1, $2, $3, $4); } |
| | DR_timescale MacroGenericItem |
| { $$ = MakeTaggedNode(N::kTimescaleDirective, $1, $2); } |
| ; |
| time_literal |
| : TK_TimeLiteral |
| { $$ = MakeTaggedNode(N::kTimeLiteral, $1); } |
| | TK_DecNumber TK_timescale_unit |
| { $$ = MakeTaggedNode(N::kTimeLiteral, $1, $2); } |
| ; |
| timeunits_declaration |
| : TK_timeunit TK_TimeLiteral ';' |
| { $$ = MakeTaggedNode(N::kTimeunitsDeclaration, $1, $2, $3); } |
| | TK_timeunit TK_TimeLiteral '/' TK_TimeLiteral ';' |
| { $$ = MakeTaggedNode(N::kTimeunitsDeclaration, $1, $2, $3, $4, $5); } |
| | TK_timeprecision TK_TimeLiteral ';' |
| { $$ = MakeTaggedNode(N::kTimeunitsDeclaration, $1, $2, $3); } |
| /* Originated from iverilog parser, but mo mention of them in the LRM: */ |
| | TK_timeunit_check TK_TimeLiteral ';' |
| { $$ = MakeTaggedNode(N::kTimeunitsDeclaration, $1, $2, $3); } |
| | TK_timeunit_check TK_TimeLiteral '/' TK_TimeLiteral ';' |
| { $$ = MakeTaggedNode(N::kTimeunitsDeclaration, $1, $2, $3, $4, $5); } |
| | TK_timeprecision_check TK_TimeLiteral ';' |
| { $$ = MakeTaggedNode(N::kTimeunitsDeclaration, $1, $2, $3); } |
| ; |
| value_range |
| : expression |
| { $$ = move($1); } |
| | '[' expression ':' expression ']' |
| { $$ = MakeTaggedNode(N::kValueRange, $1, $2, $3, $4, $5); } |
| /* half-open ranges are only legal in certain contexts */ |
| ; |
| |
| select_variable_dimension |
| /* used by references and element selection */ |
| : '[' expression ':' expression ']' |
| { $$ = MakeTaggedNode(N::kSelectVariableDimension, $1, $2, $3, $4, $5); } |
| | '[' expression_or_null_list_opt ']' |
| { $$ = MakeTaggedNode(N::kSelectVariableDimension, $1, $2, $3); } |
| /* indexed_range: */ |
| | '[' expression TK_PO_POS expression ']' |
| { $$ = MakeTaggedNode(N::kSelectVariableDimension, $1, $2, $3, $4, $5); } |
| | '[' expression TK_PO_NEG expression ']' |
| { $$ = MakeTaggedNode(N::kSelectVariableDimension, $1, $2, $3, $4, $5); } |
| ; |
| |
| decl_variable_dimension |
| /* used in declaration contexts */ |
| : '[' expression ':' expression ']' |
| { $$ = MakeTaggedNode(N::kDimensionRange, $1, $2, $3, $4, $5); } |
| | '[' expression_or_null_list_opt ']' |
| { $$ = MakeTaggedNode(N::kDimensionScalar, $1, $2, $3); } |
| /* This covers the common form of: '[' expression ']' . |
| * When this is used as '[' loop_variables ']' in the foreach context, |
| * each item should be GenericIdentifier, referring to a loop variable, |
| * or blank. |
| * This also covers '[' ']' empty brackets, which is an unsized_dimension |
| * for dynamic array allocations. |
| * "+:" and "-:" are slice operators, and $4 should be constant expressions. |
| */ |
| | '[' expression TK_PO_POS expression ']' |
| { $$ = MakeTaggedNode(N::kDimensionSlice, $1, $2, $3, $4, $5); } |
| | '[' expression TK_PO_NEG expression ']' |
| { $$ = MakeTaggedNode(N::kDimensionSlice, $1, $2, $3, $4, $5); } |
| /* queue dimension, covered by above: */ |
| /* simplification: |
| * added the following to look like index_extension (only for hierarchy_identifier) |
| */ |
| /* associative dimension: */ |
| | '[' data_type_primitive ']' |
| { $$ = MakeTaggedNode(N::kDimensionAssociativeType, $1, $2, $3 ); } |
| /* non-primitive data_type are covered by expression */ |
| | lb_star_rb |
| { $$ = move($1); } |
| ; |
| |
| lb_star_rb |
| /* The following are accepted as '[*]' for associative array declarations: */ |
| : '[' '*' ']' |
| { $$ = MakeTaggedNode(N::kDimensionAssociativeIntegral, $1, $2, $3); } |
| | TK_LBSTARRB |
| { $$ = MakeTaggedNode(N::kDimensionAssociativeIntegral, $1); } |
| | TK_LBSTAR ']' |
| { $$ = MakeTaggedNode(N::kDimensionAssociativeIntegral, $1, $2); } |
| ; |
| |
| /** ignore attributes for now, treat them as comments in lexer |
| attribute_list_opt |
| : attribute_instance_list |
| | // empty |
| ; |
| attribute_instance_list |
| : TK_PSTAR TK_STARP |
| | TK_PSTAR attribute_list TK_STARP |
| | attribute_instance_list TK_PSTAR TK_STARP |
| | attribute_instance_list TK_PSTAR attribute_list TK_STARP |
| ; |
| attribute_list |
| : attribute_list ',' attribute |
| | attribute |
| ; |
| attribute |
| : GenericIdentifier '=' expression |
| | GenericIdentifier |
| ; |
| **/ |
| any_param_declaration |
| // TODO(fangism): restructure trailing assign lists |
| /** grouped id with type to allow ranged decl without conflict |
| * | TK_parameter param_type parameter_assign_list ';' |
| * | TK_localparam param_type localparam_assign_list ';' |
| */ |
| : TK_parameter param_type_followed_by_id_and_dimensions_opt |
| trailing_assign ',' parameter_assign_list ';' |
| { $$ = MakeTaggedNode(N::kParamDeclaration, $1, $2, $3, $4, $5, $6); } |
| | TK_parameter param_type_followed_by_id_and_dimensions_opt |
| trailing_assign ';' |
| { $$ = MakeTaggedNode(N::kParamDeclaration, $1, $2, $3, $4); } |
| | TK_localparam param_type_followed_by_id_and_dimensions_opt |
| trailing_assign ',' localparam_assign_list ';' |
| { $$ = MakeTaggedNode(N::kParamDeclaration, $1, $2, $3, $4, $5, $6); } |
| | TK_localparam param_type_followed_by_id_and_dimensions_opt |
| trailing_assign ';' |
| { $$ = MakeTaggedNode(N::kParamDeclaration, $1, $2, $3, $4); } |
| /* The next rules are type parameter declarations: */ |
| | TK_parameter TK_type type_assignment_list ';' |
| { $$ = MakeTaggedNode(N::kParamDeclaration, $1, $2, $3, $4); } |
| | TK_localparam TK_type type_assignment_list ';' |
| { $$ = MakeTaggedNode(N::kParamDeclaration, $1, $2, $3, $4); } |
| ; |
| |
| instantiation_type |
| : data_type |
| { $$ = MakeTaggedNode(N::kInstantiationType, $1); } |
| | interface_type |
| { $$ = MakeTaggedNode(N::kInstantiationType, $1); } |
| ; |
| |
| instantiation_base |
| : instantiation_type gate_instance_or_register_variable_list |
| { $$ = MakeInstantiationBase($1, $2); } |
| ; |
| |
| data_declaration_or_module_instantiation |
| /* data_declaration: */ |
| /* expanded from: |
| * const_opt var_opt lifetime_opt |
| * [ data_type | interface_type ] gate_instance_or_register_variable_list ';' |
| * to avoid S/R conflict. |
| */ |
| : instantiation_base ';' |
| { $$ = MakeDataDeclaration(qualifier_placeholder, $1, $2); } |
| | lifetime const_opt instantiation_base ';' |
| { $$ = MakeDataDeclaration( |
| MakeTaggedNode(N::kQualifierList, $1, $2), $3, $4); } |
| /* const_opt was added here to support "static const" (vs. "const static") |
| * which is not explicitly permitted by the LRM grammar, but is interpreted |
| * by some vendors as intended to be permitted. |
| */ |
| | TK_var lifetime_opt instantiation_base ';' |
| { $$ = MakeDataDeclaration( |
| MakeTaggedNode(N::kQualifierList, $1, $2), $3, $4); } |
| | TK_const var_opt lifetime_opt instantiation_base ';' |
| { $$ = MakeDataDeclaration( |
| MakeTaggedNode(N::kQualifierList, $1, $2, $3), |
| $4, $5); } |
| /* Using data_declaration_modifiers_opt causes S/R conflict. */ |
| ; |
| |
| block_item_decl |
| : data_declaration_or_module_instantiation |
| { $$ = move($1); } |
| /* temporarily removed |
| | TK_reg data_type register_variable_list ';' |
| */ |
| | package_import_declaration |
| { $$ = move($1); } |
| | any_param_declaration |
| { $$ = move($1); } |
| | type_declaration |
| { $$ = move($1); } |
| | let_declaration |
| { $$ = move($1); } |
| ; |
| /** no longer needed |
| block_item_decls |
| : block_item_decl |
| | block_item_decls block_item_decl |
| ; |
| block_item_decls_opt |
| : block_item_decls |
| | // empty |
| ; |
| **/ |
| type_declaration |
| : TK_typedef data_type GenericIdentifier decl_dimensions_opt ';' |
| { $$ = MakeTaggedNode(N::kTypeDeclaration, $1, $2, nullptr, $3, $4, $5); } |
| | TK_typedef TK_class GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kTypeDeclaration, $1, $2, nullptr, $3, $4, nullptr); } |
| | TK_typedef TK_interface TK_class GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kTypeDeclaration, $1, $2, $3, $4, $5); } |
| | TK_typedef interface_type GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kTypeDeclaration, $1, $2, nullptr, $3, $4, nullptr); } |
| /* TODO: Figure out how to make the braced members list optional |
| to make these more robust */ |
| | TK_typedef TK_enum GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kTypeDeclaration, $1, |
| MakeTaggedNode(N::kDataTypePrimitive, |
| MakeTaggedNode(N::kEnumType, |
| $2, nullptr, nullptr)), |
| nullptr, $3, $4, nullptr); } |
| | TK_typedef TK_struct GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kTypeDeclaration, $1, |
| MakeTaggedNode(N::kDataTypePrimitive, |
| MakeTaggedNode(N::kStructType, |
| $2, nullptr, nullptr)), |
| nullptr, $3, $4, nullptr); } |
| | TK_typedef TK_union GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kTypeDeclaration, $1, |
| MakeTaggedNode(N::kDataTypePrimitive, |
| MakeTaggedNode(N::kUnionType, |
| $2, nullptr, nullptr)), |
| nullptr, $3, $4, nullptr); } |
| | TK_typedef GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kTypeDeclaration, $1, nullptr, nullptr, $2, $3, nullptr); } |
| ; |
| /* enums only become named via typedef */ |
| enum_data_type |
| : TK_enum '{' enum_name_list '}' |
| { $$ = MakeTaggedNode(N::kEnumType, $1, nullptr, MakeBraceGroup($2, $3, $4)); } |
| | TK_enum data_type '{' enum_name_list '}' |
| { $$ = MakeTaggedNode(N::kEnumType, $1, $2, MakeBraceGroup($3, $4, $5)); } |
| ; |
| enum_name_list |
| : enum_name_list_preprocessor_last |
| { $$ = move($1); } |
| | enum_name_list_item_last |
| { $$ = move($1); } |
| ; |
| enum_name_list_trailing_comma |
| : enum_name_list ',' |
| { $$ = ExtendNode($1, $2); } |
| ; |
| enum_name_list_preprocessor_last |
| : enum_name_list preprocessor_directive |
| { $$ = ExtendNode($1, $2); } |
| | enum_name_list_trailing_comma preprocessor_directive |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_directive |
| { $$ = MakeTaggedNode(N::kEnumNameList, $1); } |
| ; |
| enum_name_list_item_last |
| : enum_name_list_trailing_comma enum_name |
| { $$ = ExtendNode($1, $2); } |
| | enum_name_list_preprocessor_last enum_name |
| { $$ = ExtendNode($1, $2); } |
| | enum_name |
| { $$ = MakeTaggedNode(N::kEnumNameList, $1); } |
| ; |
| |
| pos_neg_number |
| : number |
| { $$ = move($1); } |
| | '-' number |
| { $$ = MakeTaggedNode(N::kNumber, $1, ForwardChildren($2)); } |
| ; |
| enum_name |
| : GenericIdentifier |
| { $$ = MakeTaggedNode(N::kEnumName, $1); } |
| | GenericIdentifier '[' pos_neg_number ']' |
| { $$ = MakeTaggedNode(N::kEnumName, $1, MakeBracketGroup($2, $3, $4)); } |
| | GenericIdentifier '[' pos_neg_number ':' pos_neg_number ']' |
| { $$ = MakeTaggedNode(N::kEnumName, $1, MakeBracketGroup($2, MakeNode($3, $4, $5), $6)); } |
| | GenericIdentifier '=' expression |
| { $$ = MakeTaggedNode(N::kEnumName, $1, MakeTaggedNode(N::kTrailingAssign, $2, $3)); } |
| | GenericIdentifier '[' pos_neg_number ']' '=' expression |
| { $$ = MakeTaggedNode(N::kEnumName, $1, MakeBracketGroup($2, $3, $4), |
| MakeTaggedNode(N::kTrailingAssign, $5, $6)); } |
| | GenericIdentifier '[' pos_neg_number ':' pos_neg_number ']' '=' expression |
| { $$ = MakeTaggedNode(N::kEnumName, $1, MakeBracketGroup($2, MakeNode($3, $4, $5), $6), |
| MakeTaggedNode(N::kTrailingAssign, $7, $8)); } |
| ; |
| /* structs only become named via typedef */ |
| struct_data_type |
| : TK_struct packed_signing_opt '{' struct_union_member_list '}' |
| { $$ = MakeTaggedNode(N::kStructType, $1, $2, MakeBraceGroup($3, $4, $5)); } |
| | TK_union TK_tagged_opt packed_signing_opt '{' struct_union_member_list '}' |
| { $$ = MakeTaggedNode(N::kUnionType, $1, $2, $3, |
| MakeBraceGroup($4, $5, $6)); } |
| ; |
| packed_signing_opt |
| : TK_packed signed_unsigned_opt |
| { $$ = MakeTaggedNode(N::kPackedSigning, $1, $2); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| struct_union_member_list |
| : struct_union_member_list struct_union_member |
| { $$ = ExtendNode($1, $2); } |
| | struct_union_member |
| { $$ = MakeTaggedNode(N::kStructUnionMemberList, $1); } |
| ; |
| struct_union_member |
| /* very similar to data_declaration */ |
| : /* attribute_list_opt */ |
| random_qualifier_opt |
| data_type_or_implicit_followed_by_id_and_dimensions_opt trailing_assign_opt ';' |
| { $$ = MakeTaggedNode(N::kStructUnionMember, $1, $2, $3, $4); } |
| | random_qualifier_opt |
| data_type_or_implicit_followed_by_id_and_dimensions_opt trailing_assign_opt ',' |
| list_of_variable_decl_assignments ';' |
| { $$ = MakeTaggedNode(N::kStructUnionMember, $1, $2, $3, $4, $5, $6); } |
| | preprocessor_directive |
| { $$ = move($1); } |
| ; |
| |
| case_item |
| : expression_list_proper ':' statement_or_null |
| { $$ = MakeTaggedNode(N::kCaseItem, $1, $2, $3); } |
| | TK_default ':' statement_or_null |
| { $$ = MakeTaggedNode(N::kDefaultItem, $1, $2, $3); } |
| | TK_default statement_or_null |
| { $$ = MakeTaggedNode(N::kDefaultItem, $1, nullptr, $2); } |
| | preprocessor_directive |
| { $$ = MakeTaggedNode(N::kCaseItem, $1); } |
| /** |
| | error ':' statement_or_null |
| **/ |
| ; |
| case_inside_item |
| : open_range_list ':' statement_or_null |
| { $$ = MakeTaggedNode(N::kCaseInsideItem, $1, $2, $3); } |
| | TK_default ':' statement_or_null |
| { $$ = MakeTaggedNode(N::kCaseInsideItem, $1, $2, $3); } |
| | TK_default statement_or_null |
| { $$ = MakeTaggedNode(N::kCaseInsideItem, $1, $2); } |
| | preprocessor_directive |
| { $$ = MakeTaggedNode(N::kCaseInsideItem, $1); } |
| ; |
| case_pattern_item |
| : pattern TK_TAND expression ':' statement_or_null |
| { $$ = MakeTaggedNode(N::kCasePatternItem, $1, $2, $3, $4, $5); } |
| | pattern ':' statement_or_null |
| { $$ = MakeTaggedNode(N::kCasePatternItem, $1, $2, $3); } |
| | TK_default ':' statement_or_null |
| { $$ = MakeTaggedNode(N::kCasePatternItem, $1, $2, $3); } |
| | TK_default statement_or_null |
| { $$ = MakeTaggedNode(N::kCasePatternItem, $1, $2); } |
| | preprocessor_directive |
| { $$ = MakeTaggedNode(N::kCasePatternItem, $1); } |
| ; |
| case_items |
| : case_items case_item |
| { $$ = ExtendNode($1, $2); } |
| | case_item |
| { $$ = MakeTaggedNode(N::kCaseItemList, $1); } |
| ; |
| case_inside_items |
| : case_inside_items case_inside_item |
| { $$ = ExtendNode($1, $2); } |
| | case_inside_item |
| { $$ = MakeTaggedNode(N::kCaseInsideItemList, $1); } |
| ; |
| case_pattern_items |
| : case_pattern_items case_pattern_item |
| { $$ = ExtendNode($1, $2); } |
| | case_pattern_item |
| { $$ = MakeTaggedNode(N::kCasePatternItemList, $1); } |
| |
| ; |
| charge_strength |
| : '(' TK_small ')' |
| { $$ = MakeParenGroup($1, $2, $3); } |
| | '(' TK_medium ')' |
| { $$ = MakeParenGroup($1, $2, $3); } |
| | '(' TK_large ')' |
| { $$ = MakeParenGroup($1, $2, $3); } |
| ; |
| charge_strength_opt |
| : charge_strength |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| defparam_assign |
| : reference '=' expression |
| { $$ = MakeTaggedNode(N::kDefParamAssignment, $1, $2, $3); } |
| ; |
| defparam_assign_list |
| : defparam_assign |
| { $$ = MakeTaggedNode(N::kDefParamAssignmentList, nullptr, $1); } |
| /* TODO(fangism): The following doesn't seem valid, so remove it. */ |
| | decl_dimensions defparam_assign |
| { $$ = MakeTaggedNode(N::kDefParamAssignmentList, |
| MakeUnpackedDimensionsNode($1), |
| $2); } |
| | defparam_assign_list ',' defparam_assign |
| { $$ = ExtendNode($1, $2, $3); } |
| ; |
| delay1 |
| : '#' delay_value_simple |
| { $$ = MakeTaggedNode(N::kDelay, $1, $2); } |
| | '#' '(' delay_value ')' |
| { $$ = MakeTaggedNode(N::kDelay, $1, MakeParenGroup($2, $3, $4)); } |
| ; |
| delay3 |
| : '#' delay_value_simple |
| { $$ = MakeTaggedNode(N::kDelay, $1, $2); } |
| | '#' '(' delay_value ')' |
| { $$ = MakeTaggedNode(N::kDelay, $1, MakeParenGroup($2, $3, $4)); } |
| | '#' '(' delay_value ',' delay_value ')' |
| { $$ = MakeTaggedNode(N::kDelay, $1, MakeParenGroup($2, MakeNode($3, $4, $5), $6)); } |
| | '#' '(' delay_value ',' delay_value ',' delay_value ')' |
| { $$ = MakeTaggedNode(N::kDelay, $1, MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7), $8)); } |
| ; |
| delay3_opt |
| : delay3 |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| delay_value_list |
| : delay_value |
| { $$ = MakeTaggedNode(N::kDelayValueList, $1); } |
| | delay_value_list ',' delay_value |
| { $$ = ExtendNode($1, $2, $3); } |
| ; |
| delay_value |
| : expression |
| { $$ = move($1); } |
| | expression ':' expression ':' expression |
| // TODO(jeremycs): change this structure to reflect mintypmax |
| { $$ = MakeTaggedNode(N::kMinTypMaxList, $1, $2, $3, $4, $5); } |
| ; |
| delay_value_simple |
| : TK_DecNumber |
| { $$ = MakeTaggedNode(N::kDelayValue, $1); } |
| | TK_RealTime |
| { $$ = MakeTaggedNode(N::kDelayValue, $1); } |
| | delay_identifier |
| { $$ = move($1); } |
| /* $1 is a package-scope identifier in LRM, but some tools |
| * also permit a general hierarchical reference. |
| */ |
| | TK_TimeLiteral |
| { $$ = MakeTaggedNode(N::kDelayValue, $1); } |
| | TK_1step |
| { $$ = MakeTaggedNode(N::kDelayValue, $1); } |
| ; |
| delay_identifier |
| : delay_identifier '.' GenericIdentifier |
| { $$ = ExtendNode($1, $2, $3); } |
| | delay_scope |
| { $$ = move($1); } |
| ; |
| delay_scope |
| : delay_scope TK_SCOPE_RES GenericIdentifier |
| { $$ = ExtendNode($1, $2, $3); } |
| | GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDelayValue, $1); } |
| ; |
| decay_value_simple |
| : TK_DecNumber |
| { $$ = move($1); } |
| | TK_RealTime |
| { $$ = move($1); } |
| | TK_TimeLiteral |
| { $$ = move($1); } |
| | TK_infinite |
| { $$ = move($1); } |
| ; |
| |
| optional_semicolon |
| : ';' |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| discipline_declaration |
| : TK_discipline GenericIdentifier optional_semicolon |
| discipline_items_opt TK_enddiscipline |
| { $$ = MakeTaggedNode(N::kDisciplineDeclaration, $1, $2, $3, $4, $5); } |
| ; |
| discipline_items_opt |
| : discipline_items |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| discipline_items |
| : discipline_items discipline_item |
| { $$ = ExtendNode($1, $2); } |
| | discipline_item |
| { $$ = MakeTaggedNode(N::kDisciplineItemList, $1); } |
| ; |
| discipline_item |
| /* discipline_domain_bindings: */ |
| : TK_domain TK_discrete ';' |
| { $$ = MakeTaggedNode(N::kDisciplineDomainBinding, $1, $2, $3); } |
| | TK_domain TK_continuous ';' |
| { $$ = MakeTaggedNode(N::kDisciplineDomainBinding, $1, $2, $3); } |
| /* nature_bindings: potential_or_flow nature_identifier ';' */ |
| | TK_potential GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kDisciplinePotential, $1, $2, $3); } |
| | TK_flow GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kDisciplineFlow, $1, $2, $3); } |
| /* TODO(fangism): nature_attribute_override */ |
| ; |
| nature_declaration |
| : TK_nature GenericIdentifier optional_semicolon |
| nature_items |
| TK_endnature |
| ; |
| nature_items |
| : nature_items nature_item |
| | nature_item |
| ; |
| nature_item |
| : TK_units '=' TK_StringLiteral ';' |
| | TK_abstol '=' expression ';' |
| | TK_access '=' GenericIdentifier ';' |
| | TK_idt_nature '=' GenericIdentifier ';' |
| | TK_ddt_nature '=' GenericIdentifier ';' |
| ; |
| |
| config_declaration |
| : TK_config GenericIdentifier ';' |
| design_statement |
| list_of_config_rule_statements_opt |
| TK_endconfig label_opt |
| { $$ = MakeTaggedNode(N::kConfigDeclaration, $1, $2, $3, $4, $5, $6, $7); } |
| ; |
| design_statement |
| : TK_design lib_cell_identifiers_opt ';' |
| { $$ = MakeTaggedNode(N::kDesignStatement, $1, $2, $3); } |
| ; |
| lib_cell_identifiers_opt |
| : lib_cell_identifiers |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| lib_cell_identifiers |
| : lib_cell_identifiers lib_cell_id |
| { $$ = ExtendNode($1, $2); } |
| | lib_cell_id |
| { $$ = MakeTaggedNode(N::kDesignStatementItems, $1); } |
| ; |
| list_of_config_rule_statements_opt |
| : list_of_config_rule_statements |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| list_of_config_rule_statements |
| : list_of_config_rule_statements config_rule_statement |
| { $$ = ExtendNode($1, $2); } |
| | config_rule_statement |
| { $$ = MakeTaggedNode(N::kConfigRuleStatementList, $1); } |
| ; |
| config_rule_statement |
| : TK_default liblist_clause ';' |
| { $$ = MakeTaggedNode(N::kConfigRuleStatement, $1, $2, $3); } |
| | inst_clause liblist_clause ';' |
| { $$ = MakeTaggedNode(N::kConfigRuleStatement, $1, $2, $3); } |
| | inst_clause use_clause ';' |
| { $$ = MakeTaggedNode(N::kConfigRuleStatement, $1, $2, $3); } |
| | cell_clause liblist_clause ';' |
| { $$ = MakeTaggedNode(N::kConfigRuleStatement, $1, $2, $3); } |
| | cell_clause use_clause ';' |
| { $$ = MakeTaggedNode(N::kConfigRuleStatement, $1, $2, $3); } |
| | preprocessor_balanced_config_rule_statements |
| { $$ = move($1); } |
| ; |
| inst_clause |
| : TK_instance reference |
| /* $2:reference is instance name */ |
| { $$ = MakeTaggedNode(N::kInstClause, $1, $2); } |
| ; |
| cell_clause |
| : TK_cell lib_cell_id |
| { $$ = MakeTaggedNode(N::kCellClause, $1, $2); } |
| ; |
| liblist_clause |
| : TK_liblist list_of_libraries_opt |
| { $$ = MakeTaggedNode(N::kLiblistClause, $1, $2); } |
| ; |
| use_clause |
| : TK_use lib_cell_id opt_config |
| { $$ = MakeTaggedNode(N::kUseClause, $1, $2, nullptr, ForwardChildren($3)); } |
| /* TODO(b/124600414): This has a S/R conflict because ('.' ID) is in both parts. |
| Why is there no separator between these in the official grammar?? |
| | TK_use lib_cell_id named_parameter_assignment_list opt_config |
| { $$ = MakeTaggedNode(N::kUseClause, $1, $2, $3, ForwardChildren($3)); } |
| */ |
| | TK_use named_parameter_assignment_list opt_config |
| { $$ = MakeTaggedNode(N::kUseClause, $1, nullptr, $2, ForwardChildren($3)); } |
| ; |
| |
| preprocessor_balanced_config_rule_statements |
| : preprocessor_if_header list_of_config_rule_statements_opt |
| preprocessor_elsif_config_rule_statements_opt |
| preprocessor_else_config_rule_statement_opt |
| PP_endif |
| { $$ = MakeTaggedNode(N::kPreprocessorBalancedConfigRuleStatements, |
| ExtendNode($1, $2), ForwardChildren($3), $4, $5); |
| } |
| ; |
| preprocessor_elsif_config_rule_statements_opt |
| : preprocessor_elsif_config_rule_statements |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_elsif_config_rule_statements |
| : preprocessor_elsif_config_rule_statements |
| preprocessor_elsif_config_rule_statement |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_elsif_config_rule_statement |
| { $$ = MakeNode($1); } /* Don't bother tagging; node will be flattened. */ |
| ; |
| preprocessor_elsif_config_rule_statement |
| : preprocessor_elsif_header list_of_config_rule_statements_opt |
| { $$ = ExtendNode($1, $2); } |
| ; |
| preprocessor_else_config_rule_statement_opt |
| : preprocessor_else_config_rule_statement |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_else_config_rule_statement |
| : PP_else list_of_config_rule_statements_opt |
| { $$ = MakeTaggedNode(N::kPreprocessorElseClause, $1, $2); } |
| ; |
| |
| named_parameter_assignment_list |
| : named_parameter_assignment_list ',' named_parameter_assignment |
| { $$ = ExtendNode($1, $2, $3); } |
| | named_parameter_assignment |
| { $$ = MakeTaggedNode(N::kActualParameterByNameList, $1); } |
| ; |
| named_parameter_assignment |
| /* subset of: parameter_value_byname */ |
| : '.' member_name '(' parameter_expr ')' |
| { $$ = MakeTaggedNode(N::kParamByName, $1, $2, MakeParenGroup($3, $4, $5)); } |
| | '.' member_name '(' ')' |
| { $$ = MakeTaggedNode(N::kParamByName, $1, $2, MakeParenGroup($3, nullptr, $4)); } |
| ; |
| opt_config |
| : ':' TK_config |
| { $$ = MakeNode($1, $2); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| lib_cell_id |
| : GenericIdentifier |
| /* cell_id */ |
| { $$ = MakeTaggedNode(N::kCellIdentifier, nullptr, nullptr, $1); } |
| | GenericIdentifier '.' GenericIdentifier |
| /* library_id . cell_id */ |
| { $$ = MakeTaggedNode(N::kCellIdentifier, $1, $2, $3); } |
| ; |
| list_of_libraries_opt |
| : list_of_libraries |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| list_of_libraries |
| : list_of_libraries GenericIdentifier |
| { $$ = ExtendNode($1, $2); } |
| | GenericIdentifier |
| { $$ = MakeTaggedNode(N::kIdentifierList, $1); } |
| /* could also give this own node type like kLibraryList */ |
| ; |
| |
| drive_strength |
| : '(' dr_strength0 ',' dr_strength1 ')' |
| | '(' dr_strength1 ',' dr_strength0 ')' |
| | '(' dr_strength0 ',' TK_highz1 ')' |
| | '(' dr_strength1 ',' TK_highz0 ')' |
| | '(' TK_highz1 ',' dr_strength0 ')' |
| | '(' TK_highz0 ',' dr_strength1 ')' |
| ; |
| drive_strength_opt |
| : drive_strength |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| dr_strength0 |
| : TK_supply0 |
| { $$ = move($1); } |
| | TK_strong0 |
| { $$ = move($1); } |
| | TK_pull0 |
| { $$ = move($1); } |
| | TK_weak0 |
| { $$ = move($1); } |
| ; |
| dr_strength1 |
| : TK_supply1 |
| { $$ = move($1); } |
| | TK_strong1 |
| { $$ = move($1); } |
| | TK_pull1 |
| { $$ = move($1); } |
| | TK_weak1 |
| { $$ = move($1); } |
| ; |
| pull01 |
| : TK_pull0 |
| { $$ = move($1); } |
| | TK_pull1 |
| { $$ = move($1); } |
| ; |
| event_control |
| : '@' hierarchy_event_identifier |
| { $$ = MakeTaggedNode(N::kEventControl, $1, $2);} |
| | '@' '(' event_expression_list ')' |
| { $$ = MakeTaggedNode(N::kEventControl, $1, MakeParenGroup($2, $3, $4));} |
| | '@' '(' '*' ')' |
| { $$ = MakeTaggedNode(N::kEventControl, $1, MakeParenGroup($2, $3, $4));} |
| | '@' '*' |
| { $$ = MakeTaggedNode(N::kEventControl, $1, $2);} |
| /* same as @ (*), which the lexer returns as just '*' */ |
| ; |
| event_control_opt |
| : event_control |
| { $$ = move($1); } |
| | /*empty*/ |
| { $$ = nullptr; } |
| ; |
| event_expression_list |
| : event_expression |
| { $$ = MakeTaggedNode(N::kEventExpressionList, $1); } |
| | event_expression_list TK_or event_expression |
| { $$ = ExtendNode($1, $2, $3); } |
| | event_expression_list ',' event_expression |
| { $$ = ExtendNode($1, $2, $3); } |
| ; |
| event_expression |
| : edge_operator expression |
| { $$ = MakeTaggedNode(N::kEventExpression, $1, $2); } |
| | expression |
| { $$ = MakeTaggedNode(N::kEventExpression, $1); } |
| | edge_operator expression TK_iff expression |
| { $$ = MakeTaggedNode(N::kEventExpression, $1, $2, $3, $4); } |
| | expression TK_iff expression |
| { $$ = MakeTaggedNode(N::kEventExpression, $1, $2, $3); } |
| ; |
| branch_probe_expression |
| : GenericIdentifier '(' GenericIdentifier ',' GenericIdentifier ')' |
| { $$ = MakeTaggedNode(N::kBranchProbeExpression, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5), $6)); } |
| | GenericIdentifier '(' GenericIdentifier ')' |
| { $$ = MakeTaggedNode(N::kBranchProbeExpression, $1, |
| MakeParenGroup($2, $3, $4)); } |
| ; |
| |
| pattern_opt |
| : pattern |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| pattern |
| : '.' member_name |
| { $$ = MakeTaggedNode(N::kPattern, $1, $2); } |
| | TK_DOTSTAR |
| { $$ = MakeTaggedNode(N::kPattern, $1); } |
| | expr_primary_no_groups |
| { $$ = MakeTaggedNode(N::kPattern, $1); } |
| /* $1 must be a constant expression */ |
| | TK_tagged GenericIdentifier pattern_opt |
| // TODO(jeremycs): consider flattening here |
| { $$ = MakeTaggedNode(N::kPattern, $1, $2, $3); } |
| | TK_LP pattern_list '}' |
| { $$ = MakeTaggedNode(N::kPattern, $1, $2, $3); } |
| | TK_LP member_pattern_list '}' |
| { $$ = MakeTaggedNode(N::kPattern, $1, $2, $3); } |
| ; |
| pattern_list |
| : pattern_list ',' pattern |
| { $$ = ExtendNode($1, $2, $3); } |
| | pattern |
| { $$ = MakeTaggedNode(N::kPatternList, $1); } |
| ; |
| member_pattern |
| : GenericIdentifier ':' pattern |
| { $$ = MakeTaggedNode(N::kMemberPattern, $1, $2, $3); } |
| ; |
| member_pattern_list |
| : member_pattern_list ',' member_pattern |
| { $$ = ExtendNode($1, $2, $3); } |
| | member_pattern |
| { $$ = MakeTaggedNode(N::kMemberPatternList, $1); } |
| ; |
| |
| expression |
| : equiv_impl_expr |
| { $$ = MakeTaggedNode(N::kExpression, $1);} |
| ; |
| |
| equiv_impl_expr |
| : cond_expr |
| { $$ = move($1); } |
| | cond_expr TK_LOGICAL_IMPLIES equiv_impl_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | cond_expr TK_LOGEQUIV equiv_impl_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| |
| /* lowest precedence expression */ |
| cond_expr |
| : logor_expr |
| { $$ = move($1); } |
| | logor_expr '?' expression ':' cond_expr |
| { $$ = MakeTaggedNode(N::kTernaryExpression, $1, $2, $3, $4, $5); } |
| // | cond_expr '?' cond_expr ':' cond_expr |
| // | cond_expr '?' logor_expr ':' logor_expr |
| /* |
| | expression '?' expression ':' expression |
| */ |
| ; |
| |
| inc_or_dec_or_primary_expr |
| : postfix_expression |
| { $$ = move($1); } |
| | inc_or_dec_expression |
| { $$ = move($1); } |
| ; |
| |
| unary_expr |
| : unary_prefix_expr |
| { $$ = move($1); } |
| ; |
| |
| unary_prefix_expr |
| : inc_or_dec_or_primary_expr |
| { $$ = move($1); } |
| /* the following section's expr_primary-s were prefixed with attribute_list_opt */ |
| | unary_op unary_prefix_expr |
| { $$ = MakeTaggedNode(N::kUnaryPrefixExpression, $1, $2); } |
| ; |
| |
| unary_op |
| : '+' |
| { $$ = move($1); } |
| | '-' |
| { $$ = move($1); } |
| | '~' |
| { $$ = move($1); } |
| | '&' |
| { $$ = move($1); } |
| | '!' |
| { $$ = move($1); } |
| | '|' |
| { $$ = move($1); } |
| | '^' |
| { $$ = move($1); } |
| | TK_NAND |
| { $$ = move($1); } |
| | TK_NOR |
| { $$ = move($1); } |
| | TK_NXOR |
| { $$ = move($1); } |
| ; |
| |
| pow_expr |
| : unary_expr |
| { $$ = move($1); } |
| | pow_expr TK_POW unary_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| |
| mul_expr |
| : pow_expr |
| { $$ = move($1); } |
| | mul_expr '*' pow_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | mul_expr '/' pow_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | mul_expr '%' pow_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| |
| add_expr |
| : mul_expr |
| { $$ = move($1); } |
| | add_expr '+' mul_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | add_expr '-' mul_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| |
| shift_expr |
| : add_expr |
| { $$ = move($1); } |
| | shift_expr TK_LS add_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | shift_expr TK_RS add_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | shift_expr TK_RSS add_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| |
| comp_expr |
| : shift_expr |
| { $$ = move($1); } |
| | comp_expr '<' shift_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | comp_expr '>' shift_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | comp_expr TK_LE shift_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | comp_expr TK_GE shift_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | comp_expr TK_inside '{' open_range_list '}' |
| { //auto group = MakeBraceGroup($3, $4, $5); |
| $$ = MakeBinaryExpression($1, $2, MakeBraceGroup($3, $4, $5)); } |
| /* inside_expression is for set membership */ |
| | comp_expr TK_inside reference |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| /* This rule is an extension of the LRM rules supported by some vendors. */ |
| /* TODO(fangism): dist expression has same precedence as this group */ |
| ; |
| |
| logeq_expr |
| : comp_expr |
| { $$ = move($1); } |
| | logeq_expr TK_EQ comp_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | logeq_expr TK_NE comp_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | logeq_expr TK_WILDCARD_EQ comp_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | logeq_expr TK_WILDCARD_NE comp_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| |
| ; |
| |
| caseeq_expr |
| : logeq_expr |
| { $$ = move($1); } |
| | caseeq_expr TK_CEQ logeq_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | caseeq_expr TK_CNE logeq_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| |
| bitand_expr |
| : caseeq_expr |
| { $$ = move($1); } |
| | bitand_expr '&' caseeq_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | bitand_expr TK_NAND caseeq_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| |
| xor_expr |
| : bitand_expr |
| { $$ = move($1); } |
| | xor_expr '^' bitand_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | xor_expr TK_NXOR bitand_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| |
| bitor_expr |
| : xor_expr |
| { $$ = move($1); } |
| | bitor_expr '|' xor_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | bitor_expr TK_NOR xor_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| |
| with_exprs_suffix |
| : with_exprs_suffix with_covergroup_expression_in_parens |
| { $$ = MakeTaggedNode(N::kWithGroup, $1, $2); } |
| | bitor_expr |
| { $$ = move($1); } |
| ; |
| |
| matches_expr |
| : with_exprs_suffix |
| { $$ = move($1); } |
| /* matches_integer_covergroup_expr is a form of select_expression */ |
| | matches_expr TK_matches with_exprs_suffix |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| |
| /* $3 should be expression? */ |
| ; |
| |
| logand_expr |
| : matches_expr |
| { $$ = move($1); } |
| | logand_expr TK_LAND bitor_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| |
| /* lowest precedence binary expression */ |
| logor_expr |
| : logand_expr |
| { $$ = move($1); } |
| | logor_expr TK_LOR logand_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| |
| expr_mintypmax |
| /* The typical min-typ-max for is expression ':' expression ':' expression. |
| * However, we extend this to support other special forms that appear |
| * inside parentheses without conflict. |
| * The precedence chosen for these list delimiters is arbitrary. |
| * See trans_list (in comments). |
| */ |
| : expr_mintypmax_trans_set |
| { $$ = move($1); } |
| ; |
| expr_mintypmax_trans_set |
| /* TODO(jeremycs): reconsider decision to flatten here*/ |
| /* TK_EG is the separator in trans_set */ |
| : expr_mintypmax_trans_set TK_EG expr_mintypmax_generalized |
| { $$ = ExtendNode($1, $2, ForwardChildren($3)); } |
| | expr_mintypmax_generalized |
| { $$ = IsExpression($1) ? move($1) |
| : MakeTaggedNode(N::kMinTypMaxList, ForwardChildren($1)); } |
| ; |
| expr_mintypmax_generalized |
| /* covers original expr_mintypmax : expression ':' expression ':' expression |
| * When this is expected, verify that this has 3 items in the 'list'. |
| */ |
| : expr_mintypmax_generalized ':' property_expr_or_assignment_list |
| { $$ = ExtendNode($1, $2, ForwardChildren($3)); } |
| | property_expr_or_assignment_list /* ','-separated */ |
| { $$ = IsExpression($1) ? move($1) |
| : MakeTaggedNode(N::kMinTypMaxList, ForwardChildren($1)); } |
| /* for trans_list, each of these can be an open_range_list, |
| * for all other contexts, these should be single value_range. |
| */ |
| ; |
| property_expr_or_assignment_list |
| /* covers open_range_list */ |
| : property_expr_or_assignment_list ',' property_expr_or_assignment |
| { $$ = ExtendNode($1, $2, $3); } |
| | property_expr_or_assignment |
| { $$ = IsExpression($1) ? move($1) |
| : MakeTaggedNode(N::kMinTypMaxList, $1); } |
| ; |
| property_expr_or_assignment |
| : property_expr |
| { $$ = move($1); } |
| /* covers sequence_repetition_expr |
| * : expression_or_dist boolean_abbrev_opt |
| * covers trans_range_list |
| * : open_range_list boolean_abbrev_opt |
| * though only the last item should be suffixed, and its boolean_abbrev_opt |
| * should be hoisted to become a suffix of the whole open_range_list. |
| */ |
| /* covers simple expression, including inc_or_dec_expression (assignment) */ |
| /* covers sequence_match_item: subroutine_call */ |
| | '[' expression ':' expression ']' |
| { $$ = MakeTaggedNode(N::kValueRange, $1, $2, $3, $4, $5); } |
| /* covers value_range */ |
| | assignment_statement_no_expr |
| { $$ = move($1); } |
| /* covers sequence_match_item: assignment_statement */ |
| ; |
| |
| argument_list_opt |
| : any_argument_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| any_argument_list |
| : any_argument_list_trailing_comma |
| { $$ = move($1); } |
| | any_argument_list_preprocessor_last |
| { $$ = move($1); } |
| | any_argument_list_item_last |
| { $$ = move($1); } |
| ; |
| any_argument_list_trailing_comma |
| : any_argument_list ',' |
| { $$ = ExtendNode($1, $2); } |
| | ',' |
| { $$ = MakeTaggedNode(N::kArgumentList, $1); } |
| ; |
| any_argument_list_item_last |
| /* TODO(fangism): positional arguments must appear before named arguments, |
| * except inside odd uses of preprocessing directives. |
| */ |
| : any_argument |
| { $$ = MakeTaggedNode(N::kArgumentList, $1); } |
| /* comma separating arguments is required, |
| * except after preprocessor directive |
| */ |
| | any_argument_list_trailing_comma any_argument |
| { $$ = ExtendNode($1, $2); } |
| | any_argument_list_preprocessor_last any_argument |
| { $$ = ExtendNode($1, $2); } |
| ; |
| any_argument_list_preprocessor_last |
| : preprocessor_directive |
| { $$ = MakeTaggedNode(N::kArgumentList, $1); } |
| /* comma separating preprocessor_directive is optional */ |
| | any_argument_list preprocessor_directive |
| { $$ = ExtendNode($1, $2); } |
| ; |
| any_argument |
| /* similar to parameter_expr */ |
| : expression /* positional argument */ |
| { $$ = move($1); } |
| | data_type_primitive |
| { $$ = move($1); } |
| | event_control |
| { $$ = move($1); } |
| /* Special functions like $past() take an event_control argument. */ |
| | parameter_value_byname /* named argument */ |
| { $$ = move($1); } |
| ; |
| |
| expression_or_null_list_opt |
| : expression_or_null_list_opt ',' expression_opt |
| { $$ = ExtendNode($1, $2, $3); } |
| | expression_opt |
| { $$ = MakeTaggedNode(N::kExpressionList, $1); } |
| ; |
| |
| expression_opt |
| : expression |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| expression_list_proper |
| : expression_list_proper ',' expression |
| { $$ = ExtendNode($1, $2, $3); } |
| | expression |
| { $$ = MakeTaggedNode(N::kExpressionList, $1); } |
| ; |
| |
| scope_prefix |
| : GenericIdentifier TK_SCOPE_RES |
| { $$ = MakeTaggedNode(N::kScopePrefix, $1, $2); } |
| | TK_Sunit TK_SCOPE_RES |
| { $$ = MakeTaggedNode(N::kScopePrefix, $1, $2); } |
| ; |
| |
| postfix_expression |
| : reference_or_call |
| { $$ = move($1); } |
| | expr_primary |
| { $$ = move($1); } |
| ; |
| |
| reference_or_call |
| : local_root |
| { $$ = MakeTaggedNode(N::kReferenceCallBase, |
| MakeTaggedNode(N::kReference, $1)); } |
| /* base of reference, including GenericIdentifier */ |
| | local_root '(' argument_list_opt ')' |
| { $$ = MakeTaggedNode(N::kReferenceCallBase, |
| MakeTaggedNode(N::kFunctionCall, $1, MakeParenGroup($2, $3, $4))); } |
| /* subroutine call */ |
| | reference_or_call hierarchy_or_call_extension |
| { $$ = ExtendNode($1, $2); } |
| /* . member */ |
| /* or method call */ |
| | reference_or_call select_variable_dimension |
| { $$ = ExtendNode($1, $2); } |
| /* [ range ] */ |
| ; |
| |
| reference |
| /* Replaces former "scoped_hierarchy_identifier" */ |
| : local_root |
| { $$ = MakeTaggedNode(N::kReference, $1); } |
| /* base of reference, including GenericIdentifier */ |
| | reference hierarchy_extension |
| { $$ = ExtendNode($1, $2); } |
| /* . member */ |
| | reference select_variable_dimension |
| { $$ = ExtendNode($1, $2); } |
| /* [ range ] */ |
| ; |
| |
| /* highest precedence expressions */ |
| expr_primary |
| /* split up as such to make it easier to work around conflicts */ |
| : expr_primary_no_groups |
| { $$ = move($1); } |
| |
| // | '(' expr_mintypmax ')' |
| // { $$ = MakeParenGroup($1, $2, $3); } |
| | expr_primary_parens |
| { $$ = move($1); } |
| | expr_primary_braces |
| { $$ = move($1); } |
| | assignment_pattern |
| { $$ = move($1); } |
| ; |
| expr_primary_parens |
| : '(' expr_mintypmax ')' |
| { $$ = MakeParenGroup($1, $2, $3); } |
| ; |
| expr_primary_braces |
| : '{' '}' |
| { $$ = MakeTaggedNode(N::kExpression, |
| MakeTaggedNode(N::kConcatenationExpression, $1, nullptr, $2)); } |
| | '{' value_range '{' expression_list_proper '}' '}' |
| { $$ = MakeTaggedNode(N::kExpression, $1, $2, MakeTaggedNode(N::kConcatenationExpression, $3, $4, $5), $6); } |
| /* repeat concatenation: $2 should be an expression, not a range */ |
| | range_list_in_braces |
| /* Reshape to use kConcatenationExpression instead of kBraceGroup */ |
| { auto& node = SymbolCastToNode(*$1); |
| $$ = MakeTaggedNode(N::kExpression, |
| MakeTaggedNode(N::kConcatenationExpression, |
| node[0], |
| node[1], |
| node[2])); } |
| | streaming_concatenation |
| { $$ = MakeTaggedNode(N::kExpression, $1); } |
| |
| ; |
| range_list_in_braces |
| : '{' open_range_list '}' |
| { $$ = MakeBraceGroup($1, $2, $3); } |
| /* for SystemVerilog covergroups, open_range_list serves as covergroup_range_list. */ |
| /* list of ranges also covers list of expressions, so to eliminate R/R conflict |
| * we've removed expression_list_proper: |
| | '{' expression_list_proper '}' |
| */ |
| ; |
| |
| /* TODO(jeremycs): unclear how much of this structure is actually needed */ |
| type_or_id_root |
| : class_id |
| { $$ = move($1); } |
| | implicit_class_handle |
| { $$ = move($1); } |
| ; |
| local_root |
| : TK_local_SCOPE type_or_id_root |
| { $$ = MakeTaggedNode(N::kLocalRoot, $1, $2); } |
| /* 'local' is a legal class_qualifier in the scope of an |
| * inline constraint block. |
| */ |
| | TK_Sroot '.' type_or_id_root |
| { $$ = MakeTaggedNode(N::kLocalRoot, $1, $2, $3); } |
| | type_or_id_root |
| { $$ = MakeTaggedNode(N::kLocalRoot, $1); } |
| /* The following is now covered by allowing '.' class_id in |
| * hierarchy_extension. |
| * implicit_class_handle '.' class_id |
| */ |
| | MacroCall |
| { $$ = move($1); } |
| |
| ; |
| |
| string_literal |
| : TK_StringLiteral |
| { $$ = move($1); } |
| | TK_EvalStringLiteral |
| { $$ = move($1); } |
| ; |
| |
| expr_primary_no_groups |
| : number |
| { $$ = move($1); } |
| | TK_RealTime |
| { $$ = move($1); } |
| // allow time literals in delay1 expressions, |
| // e.g. #(10ps) or #(N *5ps) |
| | TK_TimeLiteral |
| { $$ = move($1); } |
| | string_literal |
| { $$ = move($1); } |
| | cast |
| { $$ = move($1); } |
| | randomize_call |
| { $$ = move($1); } |
| | select_condition /* for covergroups */ |
| { $$ = move($1); } |
| | '$' |
| { $$ = move($1); } |
| /* '$' is used to index into queues */ |
| | TK_null |
| { $$ = move($1); } |
| | system_tf_call |
| { $$ = move($1); } |
| | type_reference |
| { $$ = move($1); } |
| | MacroGenericItem |
| { $$ = move($1); } |
| /* This is useful for when there is an expression or reference |
| * on its own line, at the end of an argument list. |
| */ |
| ; |
| cast |
| : casting_type '\'' '(' expression ')' |
| { $$ = MakeTaggedNode(N::kCast, $1, $2, MakeParenGroup($3, $4, $5)); } |
| ; |
| casting_type |
| : TK_DecNumber |
| { $$ = move($1); } |
| /* TODO(fangism): This should be a constant_primary. */ |
| | expr_primary_parens |
| { $$ = move($1); } |
| | system_tf_call |
| { $$ = move($1); } |
| /* for constant functions like $bits and $clog2 */ |
| | data_type_base |
| { $$ = move($1); } |
| /* $1 should be limited to 'simple_type', according to the LRM. */ |
| | signing |
| { $$ = move($1); } |
| | TK_const |
| { $$ = move($1); } |
| /* covered by data_type_base: |
| | TK_string |
| */ |
| ; |
| randomize_call |
| : TK_randomize /* attribute_list_opt */ |
| identifier_list_in_parens_opt |
| with_constraint_block_opt |
| { $$ = MakeTaggedNode(N::kRandomizeFunctionCall, $1, $2, $3); } |
| /* Another form of randomize_call is as a member function, like foo.randomize(). |
| * This is covered by reference_or_call. |
| */ |
| ; |
| identifier_list_in_parens_opt |
| : '(' identifier_list ')' |
| { $$ = MakeParenGroup($1, $2, $3); } |
| /* variable identifier list */ |
| | '(' TK_null ')' |
| { $$ = MakeParenGroup($1, $2, $3); } |
| | '(' ')' |
| { $$ = MakeParenGroup($1, nullptr, $2); } |
| | /* empty */ |
| ; |
| identifier_list |
| /* LRM:18.7 says list elements should be simple variable identifiers, |
| * but it seems that some tools allow indexed references. |
| */ |
| : identifier_list ',' reference |
| { $$ = ExtendNode($1, $2, $3); } |
| | reference |
| { $$ = MakeTaggedNode(N::kIdentifierList, $1); } |
| ; |
| with_constraint_block_opt |
| : with_constraint_block |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| with_constraint_block |
| : TK_with identifier_list_in_parens_opt constraint_block |
| { $$ = MakeTaggedNode(N::kWithConstraints, $1, $2, $3); } |
| ; |
| |
| unary_builtin_function |
| : TK_acos |
| { $$ = move($1); } |
| | TK_acosh |
| { $$ = move($1); } |
| | TK_asin |
| { $$ = move($1); } |
| | TK_asinh |
| { $$ = move($1); } |
| | TK_atan |
| { $$ = move($1); } |
| | TK_atanh |
| { $$ = move($1); } |
| | TK_ceil |
| { $$ = move($1); } |
| | TK_cos |
| { $$ = move($1); } |
| | TK_cosh |
| { $$ = move($1); } |
| | TK_exp |
| { $$ = move($1); } |
| | TK_floor |
| { $$ = move($1); } |
| | TK_ln |
| { $$ = move($1); } |
| | TK_log |
| { $$ = move($1); } |
| | TK_sin |
| { $$ = move($1); } |
| | TK_sinh |
| { $$ = move($1); } |
| | TK_sqrt |
| { $$ = move($1); } |
| | TK_tan |
| { $$ = move($1); } |
| | TK_tanh |
| { $$ = move($1); } |
| | TK_abs |
| { $$ = move($1); } |
| ; |
| binary_builtin_function |
| : TK_atan2 |
| { $$ = move($1); } |
| | TK_hypot |
| { $$ = move($1); } |
| | TK_pow |
| { $$ = move($1); } |
| /* In SystemVerilog these are built-in array-locator methods. |
| | TK_max |
| | TK_min |
| */ |
| ; |
| |
| /** |
| function_item_list_opt |
| : function_item_list |
| | // empty |
| ; |
| **/ |
| function_item_list |
| : function_item |
| { $$ = MakeTaggedNode(N::kFunctionItemList, $1); } |
| | function_item_list function_item |
| { $$ = ExtendNode($1, $2); } |
| ; |
| function_item |
| : tf_port_declaration |
| { $$ = move($1); } |
| | block_item_decl |
| { $$ = move($1); } |
| ; |
| |
| /* primitive_gate_instance covers the following gate_instantiation constructs |
| * from the LRM: |
| * cmos_switch_instance |
| * enable_gate_instance |
| * mos_switch_instance |
| * n_input_gate_instance |
| * n_output_gate_instance |
| * pass_switch_instance |
| * pass_enable_switch_instance |
| * pull_gate_instance |
| * The number of arguments for each of these instances is not checked here. |
| */ |
| primitive_gate_instance |
| : GenericIdentifier decl_dimensions_opt '(' any_port_list_opt ')' |
| /* $1, $2 := name_of_instance |
| : instance_identifier { unpacked_dimension } |
| */ |
| { $$ = MakeTaggedNode(N::kPrimitiveGateInstance, $1, |
| MakeUnpackedDimensionsNode($2), |
| MakeParenGroup($3, $4, $5)); } |
| /* anonymous instance */ |
| | '(' any_port_list_opt ')' |
| { $$ = MakeTaggedNode(N::kPrimitiveGateInstance, nullptr, nullptr, MakeParenGroup($1, $2, $3)); } |
| | GenericIdentifier decl_dimensions |
| { $$ = MakeTaggedNode(N::kPrimitiveGateInstance, $1, |
| MakeUnpackedDimensionsNode($2), |
| nullptr); } |
| ; |
| primitive_gate_instance_list |
| : primitive_gate_instance_list ',' primitive_gate_instance |
| { $$ = ExtendNode($1, $2, $3); } |
| | primitive_gate_instance |
| { $$ = MakeTaggedNode(N::kPrimitiveGateInstanceList, $1); } |
| ; |
| |
| // more permissive to eliminate S/R conflict |
| // TODO(fangism): Reject the unpacked dimensions in these constructs. |
| gate_instance_or_register_variable |
| /* similar to variable_decl_assignment */ |
| : GenericIdentifier decl_dimensions_opt trailing_decl_assignment_opt |
| { $$ = MakeTaggedNode(N::kRegisterVariable, $1, |
| MakeUnpackedDimensionsNode($2), $3); } |
| | GenericIdentifier decl_dimensions_opt '(' any_port_list_opt ')' |
| { $$ = MakeTaggedNode(N::kGateInstance, $1, |
| MakeUnpackedDimensionsNode($2), |
| MakeParenGroup($3, $4, $5)); } |
| | MacroCall |
| /* covers MacroCallId '(' ... ')' as an instance */ |
| /* TODO(fangism): restructure this like a kGateInstance */ |
| { $$ = move($1); } |
| /* TODO(fangism): arrays should not be declared with port connections */ |
| /* TODO(b/36706412): support anonymous instances */ |
| // | '(' any_port_list_opt ')' |
| ; |
| gate_instance_or_register_variable_list |
| : gate_instance_or_register_variable_list ',' gate_instance_or_register_variable |
| { $$ = ExtendNode($1, $2, $3); } |
| | gate_instance_or_register_variable |
| { $$ = MakeTaggedNode(N::kGateInstanceRegisterVariableList, $1); } |
| ; |
| |
| gatetype |
| : TK_and |
| { $$ = move($1); } |
| | TK_nand |
| { $$ = move($1); } |
| | TK_or |
| { $$ = move($1); } |
| | TK_nor |
| { $$ = move($1); } |
| | TK_xor |
| { $$ = move($1); } |
| | TK_xnor |
| { $$ = move($1); } |
| | TK_buf |
| { $$ = move($1); } |
| | TK_bufif0 |
| { $$ = move($1); } |
| | TK_bufif1 |
| { $$ = move($1); } |
| | TK_not |
| { $$ = move($1); } |
| | TK_notif0 |
| { $$ = move($1); } |
| | TK_notif1 |
| { $$ = move($1); } |
| ; |
| switchtype |
| : TK_nmos |
| | TK_rnmos |
| | TK_pmos |
| | TK_rpmos |
| | TK_cmos |
| | TK_rcmos |
| | TK_tran |
| | TK_rtran |
| | TK_tranif0 |
| | TK_tranif1 |
| | TK_rtranif0 |
| | TK_rtranif1 |
| ; |
| |
| |
| hierarchy_extension |
| : '.' class_id |
| { $$ = MakeTaggedNode(N::kHierarchyExtension, $1, $2); } |
| /* TODO(fangism): Most of the time, $2 should be a GenericIdentifier; |
| * a qualified class_id should only be permitted when preceded by |
| * implicit_class_handle. |
| * (This happens to resemble C++-syntax: obj.foo::bar .) |
| */ |
| | '.' MacroCall |
| { $$ = MakeTaggedNode(N::kMacroCallExtension, $1, $2);} |
| ; |
| hierarchy_or_call_extension |
| : '.' class_id |
| { $$ = MakeTaggedNode(N::kHierarchyExtension, $1, $2); } |
| | '.' class_id '(' argument_list_opt ')' |
| { $$ = MakeTaggedNode(N::kMethodCallExtension, $1, $2, MakeParenGroup($3, $4, $5)); } |
| | '.' MacroCall |
| { $$ = MakeTaggedNode(N::kMacroCallExtension, $1, $2); } |
| /* Special functions like 'new' and 'randomize' should only ever appear |
| * at end of any hierarchical reference. |
| */ |
| | '.' TK_new |
| { $$ = MakeTaggedNode(N::kNewCall, $1, $2); } |
| | '.' TK_new '(' argument_list_opt ')' |
| { $$ = MakeTaggedNode(N::kNewCall, $1, $2, MakeParenGroup($3, $4, $5)); } |
| | '.' TK_randomize '(' argument_list_opt ')' with_constraint_block_opt |
| { $$ = MakeTaggedNode(N::kRandomizeMethodCallExtension, $1, |
| $2, |
| MakeParenGroup($3, $4, $5), $6); } |
| |
| /* Extra layers are created here to make the call to randomize appear as |
| * any other arbitrary function call. |
| */ |
| | '.' TK_randomize with_constraint_block_opt |
| { $$ = MakeTaggedNode(N::kRandomizeMethodCallExtension, $1, |
| $2, |
| nullptr, $3); } |
| /* member function form of randomize_call */ |
| | '.' builtin_array_method '(' argument_list_opt ')' |
| array_method_with_predicate_opt |
| { $$ = MakeTaggedNode(N::kBuiltinArrayMethodCallExtension, $1, $2, MakeParenGroup($3, $4, $5), $6); } |
| | '.' builtin_array_method |
| array_method_with_predicate_opt |
| { $$ = MakeTaggedNode(N::kBuiltinArrayMethodCallExtension, $1, $2, $3); } |
| ; |
| /** this was merged into variable_dimension: (eliminate conflict on '[' ) |
| index_extension |
| : '[' expression ']' |
| | '[' expression ':' expression ']' |
| | '[' expression TK_PO_POS expression ']' |
| | '[' expression TK_PO_NEG expression ']' |
| ; |
| **/ |
| builtin_array_method |
| : array_locator_method |
| { $$ = move($1); } |
| | array_ordering_method |
| { $$ = move($1); } |
| | array_reduction_method |
| { $$ = move($1); } |
| ; |
| array_locator_method |
| /* built-in method calls */ |
| : TK_find |
| { $$ = move($1); } |
| | TK_find_index |
| { $$ = move($1); } |
| | TK_find_first |
| { $$ = move($1); } |
| | TK_find_first_index |
| { $$ = move($1); } |
| | TK_find_last |
| { $$ = move($1); } |
| | TK_find_last_index |
| { $$ = move($1); } |
| | TK_unique |
| { $$ = move($1); } |
| | TK_unique_index |
| { $$ = move($1); } |
| | TK_min |
| { $$ = move($1); } |
| | TK_max |
| { $$ = move($1); } |
| ; |
| array_ordering_method |
| : TK_sort |
| { $$ = move($1); } |
| | TK_rsort |
| { $$ = move($1); } |
| | TK_reverse |
| { $$ = move($1); } |
| | TK_shuffle |
| { $$ = move($1); } |
| ; |
| array_reduction_method |
| : TK_sum |
| { $$ = move($1); } |
| | TK_product |
| { $$ = move($1); } |
| | TK_and |
| { $$ = move($1); } |
| | TK_or |
| { $$ = move($1); } |
| | TK_xor |
| { $$ = move($1); } |
| ; |
| array_method_with_predicate_opt |
| : TK_with '(' expression ')' |
| { $$ = MakeTaggedNode(N::kArrayWithPredicate, $1, MakeParenGroup($2, $3, $4)); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| hierarchy_event_identifier |
| : hierarchy_event_identifier '.' hierarchy_segment |
| { $$ = ExtendNode($1, $2, $3); } |
| | hierarchy_segment |
| { $$ = MakeTaggedNode(N::kHierarchySegmentList, $1); } |
| ; |
| hierarchy_segment |
| : GenericIdentifier select_dimensions_opt |
| { $$ = MakeTaggedNode(N::kHierarchySegment, $1, $2); } |
| ; |
| |
| list_of_identifiers |
| : GenericIdentifier |
| { $$ = MakeTaggedNode(N::kIdentifierList, $1); } |
| | list_of_identifiers ',' GenericIdentifier |
| { $$ = ExtendNode($1, $2, $3); } |
| ; |
| list_of_identifiers_unpacked_dimensions |
| : list_of_identifiers_unpacked_dimensions ',' identifier_optional_unpacked_dimensions |
| { $$ = ExtendNode($1, $2, $3); } |
| | identifier_optional_unpacked_dimensions |
| { $$ = MakeTaggedNode(N::kIdentifierUnpackedDimensionsList, $1); } |
| ; |
| identifier_optional_unpacked_dimensions |
| : GenericIdentifier decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kIdentifierUnpackedDimensions, $1, |
| MakeUnpackedDimensionsNode($2)); } |
| ; |
| list_of_module_item_identifiers |
| /* Workaround for grammatic conflict on implicitly typed port declarations: |
| * Allow first item in list to reduce to an unqualified_id. |
| * Subsequent items should be GenericIdentifiers. |
| */ |
| : list_of_module_item_identifiers ',' identifier_optional_unpacked_dimensions |
| { $$ = ExtendNode($1, $2, $3); } |
| | unqualified_id decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kIdentifierList, |
| MakeTaggedNode(N::kIdentifierUnpackedDimensions, $1, |
| MakeTaggedNode(N::kUnpackedDimensions, |
| $2))); } |
| /* TODO(fangism): Verify $1 is a bare GenericIdentifer, no parameters. */ |
| ; |
| list_of_port_identifiers |
| /* TODO(fangism): This probably needs decl_dimensions_opt after identifiers. */ |
| : GenericIdentifier |
| { $$ = MakeTaggedNode(N::kPortIdentifierList, |
| MakeTaggedNode(N::kPortIdentifier, $1)); } |
| | GenericIdentifier '=' expression |
| /* port identifier with '=' default value */ |
| { $$ = MakeTaggedNode(N::kPortIdentifierList, |
| MakeTaggedNode(N::kPortIdentifier, $1, $2, $3)); } |
| | list_of_port_identifiers ',' GenericIdentifier |
| { $$ = ExtendNode($1, $2, MakeTaggedNode(N::kPortIdentifier, $3)); } |
| | list_of_port_identifiers ',' GenericIdentifier '=' expression |
| /* port identifier with '=' default value */ |
| { $$ = ExtendNode($1, $2, MakeTaggedNode(N::kPortIdentifier, $3, $4, $5)); } |
| ; |
| |
| identifier_opt |
| : GenericIdentifier |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| /* Inside preprocesor conditionals only, allow trailing comma */ |
| preprocessor_list_of_ports_or_port_declarations_opt |
| : list_of_ports_or_port_declarations_opt |
| { $$ = move($1); } |
| | list_of_ports_or_port_declarations_trailing_comma |
| { $$ = move($1); } |
| ; |
| list_of_ports_or_port_declarations_opt |
| : list_of_ports_or_port_declarations |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = MakeTaggedNode(N::kPortDeclarationList); } |
| ; |
| list_of_ports_or_port_declarations |
| /* This serves as list_of_ports or list_of_port_declarations. |
| * The LRM grammar does not permit mixing the two styles of lists (ANSI and |
| * non-ANSI), but combining them was necessary to accommodate preprocessing |
| * directives without ambiguity. |
| */ |
| : list_of_ports_or_port_declarations_preprocessor_last |
| { $$ = move($1); } |
| | list_of_ports_or_port_declarations_item_last |
| { $$ = move($1); } |
| ; |
| list_of_ports_or_port_declarations_preprocessor_last |
| : list_of_ports_or_port_declarations |
| preprocessor_balanced_port_declarations |
| { $$ = ExtendNode($1, $2); } |
| | list_of_ports_or_port_declarations_trailing_comma |
| preprocessor_balanced_port_declarations |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_balanced_port_declarations |
| { $$ = MakeTaggedNode(N::kPortDeclarationList, $1); } |
| ; |
| list_of_ports_or_port_declarations_item_last |
| : list_of_ports_or_port_declarations_preprocessor_last port_or_port_declaration |
| { $$ = ExtendNode($1, $2); } |
| | list_of_ports_or_port_declarations_trailing_comma port_or_port_declaration |
| { $$ = ExtendNode($1, $2); } |
| | port_or_port_declaration |
| { $$ = MakeTaggedNode(N::kPortDeclarationList, $1); } |
| ; |
| list_of_ports_or_port_declarations_trailing_comma |
| : list_of_ports_or_port_declarations ',' |
| { $$ = ExtendNode($1, $2); } |
| ; |
| port_or_port_declaration |
| : port |
| { $$ = move($1); } |
| | port_declaration |
| { $$ = move($1); } |
| /** The following has been incorporated into the 'port' rule: |
| | GenericIdentifier trailing_assign_opt |
| **/ |
| ; |
| |
| preprocessor_balanced_port_declarations |
| : preprocessor_if_header preprocessor_list_of_ports_or_port_declarations_opt |
| preprocessor_elsif_port_declarations_opt |
| preprocessor_else_port_declarations_opt |
| PP_endif |
| { $$ = MakeTaggedNode(N::kPreprocessorBalancedPortDeclarations, |
| ExtendNode($1, $2), ForwardChildren($3), $4, $5); |
| } |
| | MacroGenericItem |
| { $$ = move($1); } |
| | preprocessor_action |
| { $$ = move($1); } |
| ; |
| preprocessor_elsif_port_declarations_opt |
| : preprocessor_elsif_port_declarations |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_elsif_port_declarations |
| : preprocessor_elsif_port_declarations preprocessor_elsif_port_declaration |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_elsif_port_declaration |
| { $$ = MakeNode($1); } /* Don't bother tagging; node will be flattened. */ |
| ; |
| preprocessor_elsif_port_declaration |
| : preprocessor_elsif_header preprocessor_list_of_ports_or_port_declarations_opt |
| { $$ = ExtendNode($1, $2); } |
| ; |
| preprocessor_else_port_declarations_opt |
| : preprocessor_else_port_declarations |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_else_port_declarations |
| : PP_else preprocessor_list_of_ports_or_port_declarations_opt |
| { $$ = MakeTaggedNode(N::kPreprocessorElseClause, $1, $2); } |
| ; |
| |
| /** list_of_port_or_port_declarations combines the following rules: |
| list_of_ports |
| : port_opt |
| | list_of_ports ',' port_opt |
| ; |
| |
| list_of_port_declarations |
| : list_of_port_declarations ',' port_declaration |
| | list_of_port_declarations ',' GenericIdentifier trailing_assign_opt |
| | port_declaration |
| ; |
| **/ |
| |
| dir |
| : TK_input |
| { $$ = move($1); } |
| | TK_output |
| { $$ = move($1); } |
| | TK_inout |
| { $$ = move($1); } |
| ; |
| |
| port_declaration |
| : /* attribute_list_opt */ port_declaration_noattr |
| { $$ = move($1); } |
| ; |
| port_declaration_noattr |
| /* should consist of: |
| * inout_declaration |
| * input_declaration |
| * output_declaration |
| * ref_declaration |
| * interface_port_declaration |
| */ |
| // TODO(jeremycs): make this look more like type_identifier_followed_by_ ... rules |
| /* originally: data_type_or_implicit, but restricted to resolve conflict */ |
| // : dir var_or_net_type_opt data_type_or_implicit GenericIdentifier decl_dimensions_opt |
| // | dir var_or_net_type_opt data_type_or_implicit GenericIdentifier '=' expression |
| // |
| // NodekPortDeclaration will have children in the following format: |
| // dir, var_or_net_type_opt, data_type (includes packed dimensions), id, |
| // unpacked dimensions, trailing_assign_opt |
| // |
| : port_direction var_or_net_type_opt |
| data_type_or_implicit_basic_followed_by_id_and_dimensions_opt |
| trailing_assign_opt |
| { $$ = MakeTaggedNode(N::kPortDeclaration, $1, $2, ForwardChildren($3), $4); } |
| // TODO(fangism): inout's cannot have variable port types, |
| // so this needs to be enforced in CST validation. |
| | net_type data_type_or_implicit_basic_followed_by_id_and_dimensions_opt |
| trailing_assign_opt |
| { $$ = MakeTaggedNode(N::kPortDeclaration, nullptr, $1, |
| ForwardChildren($2), $3); } |
| | port_direction TK_wreal GenericIdentifier trailing_assign_opt |
| { $$ = MakeTaggedNode(N::kPortDeclaration, $1, nullptr, $2, $3, nullptr, $4); } |
| | data_type_primitive GenericIdentifier decl_dimensions_opt trailing_assign_opt |
| { $$ = MakeTaggedNode(N::kPortDeclaration, nullptr, nullptr, |
| // just expand without ForwardChildren: |
| // MakeTypeIdDimensionsTuple( |
| MakeTaggedNode(N::kDataType, $1, |
| nullptr /* packed dimensions */), |
| MakeTaggedNode(N::kUnqualifiedId, $2), |
| MakeUnpackedDimensionsNode($3) |
| // ) |
| , // |
| $4); } |
| /* user-defined types: including interface_port_declaration */ |
| | type_identifier_followed_by_id decl_dimensions_opt trailing_assign_opt |
| { $$ = MakeTaggedNode(N::kPortDeclaration, nullptr, nullptr, ForwardChildren($1), |
| MakeUnpackedDimensionsNode($2), $3); } |
| ; |
| var_or_net_type_opt |
| : net_type |
| { $$ = move($1); } |
| | TK_var |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| signed_unsigned_opt |
| : signing |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| lpvalue |
| /* intended to cover 'net_lvalue' and 'variable_lvalue' in LRM */ |
| : reference_or_call |
| { $$ = MakeTaggedNode(N::kLPValue, $1); } |
| /* Unless functions can return by reference, calls should not be permitted |
| * in lvalues. Written this way to avoid R/R conflict against expressions. |
| * TODO(fangism): Reject any () calls in $1. |
| */ |
| | range_list_in_braces |
| { $$ = MakeTaggedNode(N::kLPValue, $1); } |
| /* TODO(fangism): For lpvalue, verify that $1 is of the form |
| * '{' expression_list_proper '}' and that each item in the list is an lvalue. |
| */ |
| | assignment_pattern |
| /* for 'assignment_pattern_net_lvalue' |
| * and 'assignment_pattern_variable_lvalue'. |
| * TODO(fangism): verify that elements are lpvalue (not just any expr). |
| */ |
| { $$ = MakeTaggedNode(N::kLPValue, $1); } |
| | streaming_concatenation |
| { $$ = MakeTaggedNode(N::kLPValue, $1); } |
| ; |
| |
| cont_assign |
| : lpvalue '=' expression |
| { $$ = MakeTaggedNode(N::kNetVariableAssignment, $1, $2, $3); } |
| |
| // FIXME: allow just lpvalue to permit just reference for MacroCall |
| ; |
| cont_assign_list |
| : cont_assign_list ',' cont_assign |
| { $$ = ExtendNode($1, $2, $3); } |
| | cont_assign |
| { $$ = MakeTaggedNode(N::kAssignmentList, $1); } |
| ; |
| |
| symbol_or_label |
| : GenericIdentifier |
| { $$ = move($1); } |
| | MacroIdItem |
| { $$ = move($1); } |
| ; |
| |
| module_or_interface_declaration |
| /* combined module and interface declarations because they are so similar */ |
| : /* attribute_list_opt */ |
| module_start lifetime_opt symbol_or_label |
| module_package_import_list_opt |
| module_parameter_port_list_opt |
| module_port_list_opt |
| module_attribute_foreign_opt ';' |
| /* local_timeunit_prec_decl_opt */ /* merged into module_item */ |
| module_item_list_opt |
| module_end |
| label_opt |
| { const auto node_enum = DeclarationKeywordToNodeEnum(*$1); |
| $$ = MakeTaggedNode(node_enum, |
| MakeModuleHeader($1, $2, $3, $4, $5, $6, $7, $8), |
| $9, $10, $11); } |
| /* TODO(fangism): check that module_start and module_end match */ |
| /* TODO(fangism): extern {module,interface,program} declarations, ANSI and non-ANSI */ |
| ; |
| |
| module_start |
| : TK_module |
| { $$ = move($1); } |
| | TK_macromodule |
| { $$ = move($1); } |
| | TK_program |
| { $$ = move($1); } |
| | TK_interface |
| { $$ = move($1); } |
| ; |
| |
| module_end |
| : TK_endmodule |
| { $$ = move($1); } |
| | TK_endprogram |
| { $$ = move($1); } |
| | TK_endinterface |
| { $$ = move($1); } |
| ; |
| label_opt |
| : ':' symbol_or_label |
| { $$ = MakeTaggedNode(N::kLabel, $1, $2); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| module_attribute_foreign |
| : TK_PSTAR GenericIdentifier TK_integer GenericIdentifier '=' TK_StringLiteral ';' TK_STARP |
| { $$ = MakeTaggedNode(N::kModuleAttributeForeign, $1, $2, $3, $4, $5, $6, $7, $8); } |
| ; |
| module_attribute_foreign_opt |
| : module_attribute_foreign |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| module_port_list_opt |
| : '(' list_of_ports_or_port_declarations_opt ')' |
| { $$ = MakeParenGroup($1, $2, $3); } |
| /** replaces these rules: |
| | '(' list_of_ports ')' |
| | '(' list_of_port_declarations ')' |
| **/ |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| module_parameter_port_list_opt |
| : '#' '(' module_parameter_port_list ')' |
| { $$ = MakeTaggedNode(N::kFormalParameterListDeclaration, $1, MakeParenGroup($2, $3, $4)); } |
| | '#' '(' ')' |
| { $$ = MakeTaggedNode(N::kFormalParameterListDeclaration, $1, |
| MakeParenGroup($2, MakeTaggedNode(N::kFormalParameterList), $3)); |
| } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| parameter_opt |
| : TK_parameter |
| { $$ = move($1); } |
| | TK_localparam |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| module_parameter_port |
| /* : parameter_opt param_type_opt parameter_assign */ |
| : parameter_opt param_type_followed_by_id_and_dimensions_opt |
| trailing_assign_opt |
| { $$ = MakeTaggedNode(N::kParamDeclaration, $1, $2, $3); } |
| /* TODO(fangism): Verify that $2 should not have trailing dimensions (in this context). */ |
| | parameter_opt TK_type type_assignment |
| { $$ = MakeTaggedNode(N::kParamDeclaration, $1, $2, $3); } |
| /* type parameter: |
| * The EBNF permits a type_assignment_list, however, since both |
| * type_assignment_list and module_parameter_port_list are comma-separated, |
| * 1-token lookahead is insufficient to decide S/R on ',', thus we limit |
| * each type parameter declaration to one assignment. |
| * TODO(fangism): Refactor grammar to better allow comma-separated |
| * parameter multi-declarations. |
| */ |
| /* The keyword 'parameter' is optional in formal parameter lists (such as |
| * ANSI-style header declarations), but it is good for readability. |
| */ |
| ; |
| |
| type_assignment_list |
| : type_assignment_list ',' type_assignment |
| { $$ = ExtendNode($1, $2, $3); } |
| | type_assignment |
| { $$ = MakeTaggedNode(N::kTypeAssignmentList, $1); } |
| ; |
| type_assignment |
| : GenericIdentifier '=' parameter_expr |
| { $$ = MakeTaggedNode(N::kTypeAssignment, $1, $2, $3); } |
| /* $3 covers all types, including interface types and user-defined types */ |
| | GenericIdentifier |
| { $$ = MakeTaggedNode(N::kTypeAssignment, $1, nullptr, nullptr); } |
| |
| ; |
| |
| module_parameter_port_list |
| /* expanded to allow preprocessing directives like `ifdef */ |
| : module_parameter_port_list_item_last |
| { $$ = move($1); } |
| | module_parameter_port_list_preprocessor_last |
| { $$ = move($1); } |
| ; |
| module_parameter_port_list_trailing_comma |
| : module_parameter_port_list ',' |
| { $$ = ExtendNode($1, $2); } |
| ; |
| module_parameter_port_list_preprocessor_last |
| : module_parameter_port_list preprocessor_directive |
| { $$ = ExtendNode($1, $2); } |
| | module_parameter_port_list_trailing_comma preprocessor_directive |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_directive |
| { $$ = MakeTaggedNode(N::kFormalParameterList, $1); } |
| ; |
| module_parameter_port_list_item_last |
| /* default value is mandatory */ |
| : module_parameter_port_list_trailing_comma module_parameter_port |
| { $$ = ExtendNode($1, $2); } |
| | module_parameter_port_list_preprocessor_last module_parameter_port |
| { $$ = ExtendNode($1, $2); } |
| | module_parameter_port |
| { $$ = MakeTaggedNode(N::kFormalParameterList, $1); } |
| ; |
| |
| net_declaration |
| : net_type net_variable_or_decl_assigns ';' |
| { $$ = MakeTaggedNode(N::kNetDeclaration, $1, nullptr, $2, $3); } |
| | net_type data_type_or_implicit net_variable_or_decl_assigns ';' |
| { $$ = MakeTaggedNode(N::kNetDeclaration, $1, $2, $3, $4); } |
| /* TODO(fangism): support drive_strength and charge_strength */ |
| // : net_type data_type_or_implicit delay3_opt net_variable_list ';' |
| // : net_type data_type_or_implicit delay3 net_variable_list ';' |
| // : net_type data_type_or_implicit_followed_by_id |
| // | net_type data_type_or_implicit delay3_opt net_decl_assigns ';' |
| // | net_type data_type_or_implicit delay3 net_decl_assigns ';' |
| // | net_type data_type_or_implicit_followed_by_id |
| // trailing_assign_opt ';' |
| // | net_type data_type_or_implicit_followed_by_id |
| // trailing_assign_opt ',' net_decl_assigns ';' |
| // | net_type data_type_or_implicit drive_strength net_decl_assigns ';' |
| | TK_trireg charge_strength_opt decl_dimensions_opt delay3_opt list_of_identifiers ';' |
| { $$ = MakeTaggedNode(N::kNetDeclaration, $1, $2, |
| MakePackedDimensionsNode($3), |
| $4, $5, $6); } |
| /* TODO(fangism): net_type_identifer [ delay_control ] list_of_net_decl_assignments */ |
| /* TODO(fangism): TK_interconnect ... */ |
| ; |
| |
| module_port_declaration |
| // TODO(fangism): add more structure here, e.g. kDataType. |
| /* In the LRM, this is ansi_port_declaration. |
| * Any of these could be prefixed with attribute_list_opt. |
| */ |
| : TK_wreal delay3_opt net_variable_or_decl_assigns ';' |
| { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1, $2, $3, $4); } |
| | port_direction TK_wreal list_of_identifiers_unpacked_dimensions ';' |
| { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1, $2, $3, $4); } |
| // | TK_wreal delay3 net_variable_list ';' |
| // | TK_wreal net_variable_list ';' |
| // | TK_wreal net_decl_assigns ';' |
| | port_direction signed_unsigned_opt qualified_id decl_dimensions_opt |
| list_of_identifiers_unpacked_dimensions ';' |
| { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1, $2, $3, |
| MakePackedDimensionsNode($4), |
| $5, $6); } |
| | port_direction signed_unsigned_opt unqualified_id decl_dimensions_opt |
| list_of_identifiers_unpacked_dimensions ';' |
| { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1, $2, $3, |
| MakePackedDimensionsNode($4), |
| $5, $6); } |
| | port_direction signed_unsigned_opt decl_dimensions delay3_opt |
| list_of_identifiers_unpacked_dimensions ';' |
| { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1, $2, |
| MakePackedDimensionsNode($3), $4, |
| $5, $6);} |
| /* implicit type */ |
| | port_direction signed_unsigned_opt delay3 |
| list_of_identifiers_unpacked_dimensions ';' |
| { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1, $2, $3, $4, $5); } |
| /* implicit type */ |
| | port_direction signed_unsigned_opt list_of_module_item_identifiers ';' |
| { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1, $2, $3, $4);} |
| /* implicit type */ |
| | port_direction port_net_type signed_unsigned_opt decl_dimensions_opt |
| list_of_identifiers_unpacked_dimensions ';' |
| { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1, $2, $3, |
| MakePackedDimensionsNode($4), |
| $5, $6); } |
| | dir var_type signed_unsigned_opt decl_dimensions_opt |
| list_of_port_identifiers ';' |
| { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1, $2, $3, |
| MakePackedDimensionsNode($4), |
| $5, $6); } |
| ; |
| |
| parameter_override |
| : TK_defparam defparam_assign_list ';' |
| { $$ = MakeTaggedNode(N::kParameterOverride, $1, $2, $3); } |
| ; |
| |
| gate_instantiation |
| // TODO(jeremycs): possibly introduce structure here |
| : /* attribute_list_opt */ gatetype primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, $2, $3); } |
| | /* attribute_list_opt */ gatetype delay3 primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, $2, $3, $4); } |
| | /* attribute_list_opt */ gatetype drive_strength primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, $2, $3, $4); } |
| | /* attribute_list_opt */ gatetype drive_strength delay3 primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, $2, $3, $4, $5); } |
| | /* attribute_list_opt */ switchtype primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, $2, $3); } |
| | /* attribute_list_opt */ switchtype delay3 primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, $2, $3, $4); } |
| | TK_pullup primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, $2, $3); } |
| | TK_pulldown primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, $2, $3); } |
| | TK_pullup '(' dr_strength1 ')' primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, |
| MakeParenGroup($2, $3, $4), $5, $6); } |
| | TK_pullup '(' dr_strength1 ',' dr_strength0 ')' primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5), $6), $7, $8); } |
| | TK_pullup '(' dr_strength0 ',' dr_strength1 ')' primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5), $6), $7, $8); } |
| | TK_pulldown '(' dr_strength0 ')' primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, |
| MakeParenGroup($2, $3, $4), $5, $6); } |
| | TK_pulldown '(' dr_strength1 ',' dr_strength0 ')' primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5), $6), $7, $8); } |
| | TK_pulldown '(' dr_strength0 ',' dr_strength1 ')' primitive_gate_instance_list ';' |
| { $$ = MakeTaggedNode(N::kGateInstantiation, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5), $6), $7, $8); } |
| ; |
| |
| specify_block |
| : TK_specify specify_item_list_opt TK_endspecify |
| { $$ = MakeTaggedNode(N::kSpecifyBlock, $1, $2, $3); } |
| ; |
| |
| specparam_declaration |
| : /* attribute_list_opt */ TK_specparam specparam_decl ';' |
| { $$ = MakeTaggedNode(N::kSpecParamDeclaration, $1, $2, $3); } |
| ; |
| |
| generate_region |
| : TK_generate generate_item_list_opt TK_endgenerate |
| { $$ = MakeTaggedNode(N::kGenerateRegion, $1, $2, $3); } |
| ; |
| |
| continuous_assign |
| : TK_assign drive_strength_opt delay3_opt cont_assign_list ';' |
| { $$ = MakeTaggedNode(N::kContinuousAssignmentStatement, $1, $2, $3, $4, $5); } |
| /* Allowed the following because they have been observed in practice: */ |
| | TK_assign drive_strength_opt delay3_opt macro_call_or_item |
| { $$ = MakeTaggedNode(N::kContinuousAssignmentStatement, $1, $2, $3, $4, nullptr); } |
| /* TODO(fangism): shape kContinuousAssignmentStatement consistently */ |
| ; |
| |
| net_alias_assign_lvalue_list |
| : net_alias_assign_lvalue_list '=' lpvalue |
| { $$ = ExtendNode($1, $2, $3); } |
| | lpvalue '=' lpvalue |
| { $$ = MakeTaggedNode(N::kNetAliasLvalueList, $1, $2, $3); } |
| ; |
| |
| net_alias |
| : TK_alias net_alias_assign_lvalue_list ';' |
| { $$ = MakeTaggedNode(N::kNetAlias, $1, $2, $3); } |
| ; |
| |
| loop_generate_construct |
| : TK_for '(' genvar_opt GenericIdentifier '=' expression ';' |
| expression_opt ';' for_step_opt ')' |
| generate_item |
| { $$ = MakeTaggedNode( |
| N::kLoopGenerateConstruct, |
| MakeTaggedNode( |
| N::kLoopHeader, $1, |
| MakeParenGroup($2, |
| MakeTaggedNode(N::kForSpec, |
| MakeTaggedNode(N::kForInitialization, $3, nullptr, $4, $5, $6), |
| $7, |
| MakeTaggedNode(N::kForCondition, $8), |
| $9, $10), |
| $11)), |
| $12); } |
| /* for_step permits any assignment operation */ |
| ; |
| |
| conditional_generate_construct |
| : generate_if generate_item TK_else generate_item |
| { $$ = MakeTaggedNode(N::kConditionalGenerateConstruct, |
| MakeTaggedNode(N::kGenerateIfClause, |
| MakeTaggedNode(N::kGenerateIfHeader, $1), |
| MakeTaggedNode(N::kGenerateIfBody, $2)), |
| MakeTaggedNode(N::kGenerateElseClause, |
| $3, |
| MakeTaggedNode(N::kGenerateElseBody, $4))); } |
| | generate_if generate_item %prec less_than_TK_else |
| { $$ = MakeTaggedNode(N::kConditionalGenerateConstruct, |
| MakeTaggedNode(N::kGenerateIfClause, |
| MakeTaggedNode(N::kGenerateIfHeader, $1), |
| MakeTaggedNode(N::kGenerateIfBody, $2)), |
| nullptr); } |
| | TK_case '(' expression ')' generate_case_items TK_endcase |
| { $$ = MakeTaggedNode(N::kCaseGenerateConstruct, $1, |
| MakeParenGroup($2, $3, $4), $5, $6); } |
| ; |
| |
| always_construct |
| : /* attribute_list_opt */ always_any statement |
| { $$ = MakeTaggedNode(N::kAlwaysStatement, $1, $2); } |
| ; |
| |
| initial_construct |
| : /* attribute_list_opt */ TK_initial statement |
| { $$ = MakeTaggedNode(N::kInitialStatement, $1, $2); } |
| ; |
| |
| final_construct |
| : /* attribute_list_opt */ TK_final statement |
| { $$ = MakeTaggedNode(N::kFinalStatement, $1, $2); } |
| ; |
| |
| analog_construct |
| : /* attribute_list_opt */ TK_analog analog_statement |
| { $$ = MakeTaggedNode(N::kAnalogStatement, $1, ForwardChildren($2)); } |
| ; |
| |
| module_common_item |
| : module_or_generate_item_declaration |
| { $$ = move($1); } |
| | always_construct |
| { $$ = move($1); } |
| | initial_construct |
| { $$ = move($1); } |
| | final_construct |
| { $$ = move($1); } |
| | analog_construct |
| /* Verilog-AMS*/ |
| { $$ = move($1); } |
| | assertion_item |
| { $$ = move($1); } |
| | bind_directive |
| { $$ = move($1); } |
| | continuous_assign |
| { $$ = move($1); } |
| | net_alias |
| { $$ = move($1); } |
| | loop_generate_construct |
| { $$ = move($1); } |
| | conditional_generate_construct |
| { $$ = move($1); } |
| | system_tf_call ';' |
| { $$ = ExtendNode($1, $2); } |
| /* covers elaboration_system_task */ |
| ; |
| |
| genvar_declaration |
| : TK_genvar list_of_identifiers ';' |
| { $$ = MakeTaggedNode(N::kGenvarDeclaration, $1, $2, $3); } |
| ; |
| |
| module_or_generate_item_declaration |
| // TODO(jeremycs): fill this out |
| : package_or_generate_item_declaration |
| { $$ = move($1); } |
| | clocking_declaration |
| { $$ = move($1); } |
| | TK_default TK_clocking GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kDefaultClockingStatement, $1, $2, $3, $4); } |
| | TK_default TK_disable TK_iff expression_or_dist ';' |
| { $$ = MakeTaggedNode(N::kDefaultDisableStatement, $1, $2, $3, $4, $5); } |
| | genvar_declaration |
| { $$ = move($1); } |
| ; |
| |
| package_or_generate_item_declaration |
| : class_declaration |
| { $$ = move($1); } |
| | interface_class_declaration |
| { $$ = move($1); } |
| | net_declaration |
| { $$ = move($1); } |
| | task_declaration |
| { $$ = move($1); } |
| | function_declaration |
| { $$ = move($1); } |
| | covergroup_declaration |
| { $$ = move($1); } |
| | assertion_item_declaration |
| { $$ = move($1); } |
| | modport_declaration |
| { $$ = move($1); } |
| | specparam_declaration |
| { $$ = move($1); } |
| /* TODO(fangism): checker_declaration */ |
| | dpi_import_export |
| { $$ = move($1); } |
| | ';' |
| { $$ = MakeTaggedNode(N::kNullItem, $1); } |
| ; |
| |
| module_or_generate_item |
| : parameter_override |
| { $$ = move($1); } |
| | gate_instantiation |
| { $$ = move($1); } |
| /* TODO(fangism): udp_instantiation */ |
| | /* attribute_list_opt */ block_item_decl |
| { $$ = move($1); } |
| /* includes module_instantiation, and most other instantiations */ |
| | module_common_item |
| { $$ = move($1); } |
| ; |
| |
| module_item |
| : module_port_declaration |
| { $$ = move($1); } |
| | non_port_module_item |
| { $$ = move($1); } |
| | module_block |
| { $$ = move($1); } |
| | macro_call_or_item |
| { $$ = move($1); } |
| | preprocessor_balanced_module_items |
| { $$ = move($1); } |
| | preprocessor_action |
| { $$ = move($1); } |
| | module_item_directive |
| { $$ = move($1); } |
| | error ';' |
| { yyerrok; $$ = Recover(); } |
| ; |
| |
| module_block |
| /* This construct is not LRM-valid, but is popularly supported among other |
| * tools, so we decided to legalize the syntax while flagging it as a |
| * lint error. |
| */ |
| : begin module_item_list_opt end |
| { $$ = MakeTaggedNode(N::kModuleBlock, $1, $2, $3); } |
| ; |
| preprocessor_balanced_module_items |
| : preprocessor_if_header module_item_list_opt |
| preprocessor_elsif_module_items_opt |
| preprocessor_else_module_item_opt |
| PP_endif |
| { $$ = MakeTaggedNode(N::kPreprocessorBalancedModuleItems, |
| ExtendNode($1, $2), ForwardChildren($3), $4, $5); |
| } |
| ; |
| preprocessor_elsif_module_items_opt |
| : preprocessor_elsif_module_items |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_elsif_module_items |
| : preprocessor_elsif_module_items preprocessor_elsif_module_item |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_elsif_module_item |
| { $$ = MakeNode($1); } /* Don't bother tagging; node will be flattened. */ |
| ; |
| preprocessor_elsif_module_item |
| : preprocessor_elsif_header module_item_list_opt |
| { $$ = ExtendNode($1, $2); } |
| ; |
| preprocessor_else_module_item_opt |
| : preprocessor_else_module_item |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_else_module_item |
| : PP_else module_item_list_opt |
| { $$ = MakeTaggedNode(N::kPreprocessorElseClause, $1, $2); } |
| ; |
| |
| non_port_module_item |
| : generate_region |
| { $$ = move($1); } |
| | module_or_generate_item |
| { $$ = move($1); } |
| | specify_block |
| { $$ = move($1); } |
| | timeunits_declaration |
| { $$ = move($1); } |
| | module_or_interface_declaration |
| { $$ = move($1); } |
| | TKK_attribute '(' GenericIdentifier ',' TK_StringLiteral ',' TK_StringLiteral ')' ';' |
| { $$ = MakeTaggedNode(N::kAttribute, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7), |
| $8), $9); } |
| ; |
| |
| always_any |
| : TK_always |
| { $$ = move($1); } |
| | TK_always_ff |
| { $$ = move($1); } |
| | TK_always_comb |
| { $$ = move($1); } |
| | TK_always_latch |
| { $$ = move($1); } |
| ; |
| generate_if |
| : TK_if '(' expression ')' |
| { $$ = MakeTaggedNode(N::kGenerateIf, $1, MakeParenGroup($2, $3, $4)); } |
| ; |
| generate_case_items |
| : generate_case_items generate_case_item |
| { $$ = ExtendNode($1, $2); } |
| | generate_case_item |
| { $$ = MakeTaggedNode(N::kGenerateCaseItemList, $1); } |
| ; |
| generate_case_item |
| : expression_list_proper ':' generate_item |
| { $$ = MakeTaggedNode(N::kGenerateCaseItem, $1, $2, $3); } |
| | TK_default ':' generate_item |
| { $$ = MakeTaggedNode(N::kGenerateDefaultItem, $1, $2, $3); } |
| ; |
| |
| generate_item |
| : module_or_generate_item |
| { $$ = move($1); } |
| /* |
| | interface_or_generate_item |
| | checker_or_generate_item |
| */ |
| | generate_block |
| { $$ = move($1); } |
| | macro_call_or_item |
| { $$ = move($1); } |
| | preprocessor_balanced_generate_items |
| { $$ = move($1); } |
| | preprocessor_action |
| { $$ = move($1); } |
| | error ';' |
| { yyerrok; $$ = Recover(); } |
| ; |
| preprocessor_balanced_generate_items |
| : preprocessor_if_header generate_item_list_opt |
| preprocessor_elsif_generate_items_opt |
| preprocessor_else_generate_item_opt |
| PP_endif |
| { $$ = MakeTaggedNode(N::kPreprocessorBalancedGenerateItems, |
| ExtendNode($1, $2), ForwardChildren($3), $4, $5); |
| } |
| ; |
| preprocessor_elsif_generate_items_opt |
| : preprocessor_elsif_generate_items |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_elsif_generate_items |
| : preprocessor_elsif_generate_items preprocessor_elsif_generate_item |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_elsif_generate_item |
| { $$ = MakeNode($1); } /* Don't bother tagging; node will be flattened. */ |
| ; |
| preprocessor_elsif_generate_item |
| : preprocessor_elsif_header generate_item_list_opt |
| { $$ = ExtendNode($1, $2); } |
| ; |
| preprocessor_else_generate_item_opt |
| : preprocessor_else_generate_item |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_else_generate_item |
| : PP_else generate_item_list_opt |
| { $$ = MakeTaggedNode(N::kPreprocessorElseClause, $1, $2); } |
| ; |
| |
| begin |
| : TK_begin label_opt |
| { $$ = MakeTaggedNode(N::kBegin, $1, $2); } |
| ; |
| |
| end |
| : TK_end label_opt |
| { $$ = MakeTaggedNode(N::kEnd, $1, $2); } |
| ; |
| |
| /* The LRM swaps the roles of generate_item and generate_block, but block as |
| * an subset of item (not the reverse) is more conventional in other languages. |
| */ |
| generate_block |
| : begin generate_item_list_opt end |
| { $$ = MakeTaggedNode(N::kGenerateBlock, $1, $2, $3); } |
| /* begin : label is more common and is the preferred style. */ |
| | unqualified_id ':' TK_begin generate_item_list_opt end |
| { $$ = MakeTaggedNode(N::kGenerateBlock, |
| MakeTaggedNode(N::kBegin, |
| MakeTaggedNode(N::kLabel, $1, $2), |
| $3), |
| $4, $5); } |
| /* $1 should be a GenericIdentifier, without parameter_value */ |
| /* Legal syntax, but the style-linter should reject this. */ |
| ; |
| |
| generate_item_list |
| : generate_item_list generate_item |
| { $$ = ExtendNode($1, $2); } |
| | generate_item |
| { $$ = MakeTaggedNode(N::kGenerateItemList, $1); } |
| ; |
| |
| generate_item_list_opt |
| : generate_item_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = MakeTaggedNode(N::kGenerateItemList); } |
| ; |
| |
| module_item_list |
| : module_item_list module_item |
| { $$ = ExtendNode($1, $2); } |
| | module_item |
| { $$ = MakeTaggedNode(N::kModuleItemList, $1); } |
| ; |
| module_item_list_opt |
| : module_item_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = MakeTaggedNode(N::kModuleItemList); } |
| ; |
| genvar_opt |
| : TK_genvar |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| net_decl_assign |
| : GenericIdentifier '=' expression |
| { $$ = MakeTaggedNode(N::kNetDeclarationAssignment, $1, $2, $3); } |
| ; |
| /** |
| net_decl_assigns |
| : net_decl_assigns ',' net_decl_assign |
| | net_decl_assign |
| ; |
| **/ |
| net_variable_or_decl_assign |
| : net_variable |
| { $$ = move($1); } |
| | net_decl_assign |
| { $$ = move($1); } |
| ; |
| net_variable_or_decl_assigns |
| : net_variable_or_decl_assigns ',' net_variable_or_decl_assign |
| { $$ = ExtendNode($1, $2, $3); } |
| | net_variable_or_decl_assign |
| { $$ = MakeTaggedNode(N::kNetVariableDeclarationAssign, $1); } |
| ; |
| |
| bit_logic |
| : TK_logic |
| { $$ = move($1); } |
| | TK_bit |
| { $$ = move($1); } |
| ; |
| bit_logic_opt |
| : bit_logic |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| port_net_type |
| : net_type |
| { $$ = move($1); } |
| | TK_logic |
| { $$ = move($1); } |
| ; |
| net_type |
| : TK_wire |
| { $$ = move($1); } |
| | TK_tri |
| { $$ = move($1); } |
| | TK_tri1 |
| { $$ = move($1); } |
| | TK_supply0 |
| { $$ = move($1); } |
| | TK_wand |
| { $$ = move($1); } |
| | TK_triand |
| { $$ = move($1); } |
| | TK_tri0 |
| { $$ = move($1); } |
| | TK_supply1 |
| { $$ = move($1); } |
| | TK_wor |
| { $$ = move($1); } |
| | TK_trior |
| { $$ = move($1); } |
| | TK_wone |
| { $$ = move($1); } |
| | TK_uwire |
| { $$ = move($1); } |
| ; |
| var_type |
| : TK_reg |
| ; |
| |
| /** |
| param_type |
| : bit_logic_opt signed_unsigned_opt decl_dimensions_opt |
| // includes implicit type |
| | integer_atom_type |
| | non_integer_type |
| ; |
| **/ |
| |
| /* this rule introduced to allow: |
| * localparam RANGE ID RANGE |
| * allow decl_dimensions_opt in between |
| **/ |
| param_type_followed_by_id_and_dimensions_opt |
| // : bit_logic_opt signed_unsigned_opt decl_dimensions_opt GenericIdentifier decl_dimensions_opt |
| /* apparently, there are user-defined parameter types */ |
| /* TODO(fangism): enforce more structure here, e.g. kDataType */ |
| : bit_logic_opt signed_unsigned_opt qualified_id decl_dimensions_opt |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeParamTypeDeclaration(MakeTypeInfoNode($1, $2, $3), |
| MakePackedDimensionsNode($4), |
| $5, |
| MakeUnpackedDimensionsNode($6)); } |
| | bit_logic_opt signed_unsigned_opt unqualified_id decl_dimensions_opt |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeParamTypeDeclaration(MakeTypeInfoNode($1, $2, $3), |
| MakePackedDimensionsNode($4), |
| $5, |
| MakeUnpackedDimensionsNode($6)); } |
| | bit_logic_opt signed_unsigned_opt unqualified_id decl_dimensions_opt |
| { $$ = MakeParamTypeDeclaration(MakeTypeInfoNode($1, $2, nullptr), |
| /* no packed dimensions */ nullptr, |
| /* parameter id, not type */ $3, |
| MakeUnpackedDimensionsNode($4)); } |
| /* implicit type. Declared identifier upgraded to unqualified_id to avoid conflict. */ |
| /* TODO(fangism): Verify that $3 is only a GenericIdentifier, without parameters. */ |
| | bit_logic_opt signed_unsigned_opt decl_dimensions |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeParamTypeDeclaration(MakeTypeInfoNode($1, $2, nullptr), |
| MakePackedDimensionsNode($3), |
| $4, |
| MakeUnpackedDimensionsNode($5)); } |
| | integer_atom_type signed_unsigned_opt decl_dimensions_opt |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeParamTypeDeclaration(MakeTypeInfoNode($1, $2, nullptr), |
| MakePackedDimensionsNode($3), |
| $4, |
| MakeUnpackedDimensionsNode($5)); } |
| | non_integer_type decl_dimensions_opt |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeParamTypeDeclaration(MakeTypeInfoNode($1, nullptr, nullptr), |
| MakePackedDimensionsNode($2), |
| $3, |
| MakeUnpackedDimensionsNode($4)); } |
| | TK_reg decl_dimensions_opt |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeParamTypeDeclaration(MakeTypeInfoNode($1, nullptr, nullptr), |
| MakePackedDimensionsNode($2), |
| $3, |
| MakeUnpackedDimensionsNode($4)); } |
| | TK_string decl_dimensions_opt |
| GenericIdentifier decl_dimensions_opt |
| { $$ = MakeParamTypeDeclaration(MakeTypeInfoNode($1, nullptr, nullptr), |
| MakePackedDimensionsNode($2), |
| $3, |
| MakeUnpackedDimensionsNode($4)); } |
| /* TODO(fangism): see if this can be simplified to: |
| * data_type_or_implicit_basic_followed_by_id_and_dimensions_opt |
| */ |
| ; |
| parameter_assign_list |
| : parameter_assign |
| { $$ = MakeTaggedNode(N::kParameterAssignList, $1); } |
| | parameter_assign_list ',' parameter_assign |
| { $$ = ExtendNode($1, $2, $3); } |
| ; |
| localparam_assign_list |
| : localparam_assign |
| { $$ = MakeTaggedNode(N::kParameterAssignList, $1); } |
| | localparam_assign_list ',' localparam_assign |
| { $$ = ExtendNode($1, $2, $3); } |
| ; |
| parameter_assign |
| : GenericIdentifier '=' expression parameter_value_ranges_opt |
| { $$ = MakeTaggedNode(N::kParameterAssign, $1, $2, $3); } |
| ; |
| localparam_assign |
| : GenericIdentifier '=' expression |
| { $$ = MakeTaggedNode(N::kParameterAssign, $1, $2, $3); } |
| ; |
| /** |
| * Normally localparam assign do not take parameter_value_ranges_opt, |
| * whereas param assigns can, but we simplify the grammar by merging these. |
| **/ |
| trailing_assign |
| /* similar to trailing_decl_assignment */ |
| : '=' parameter_expr parameter_value_ranges_opt |
| { $$ = MakeTaggedNode(N::kTrailingAssign, $1, $2, $3); } |
| ; |
| trailing_assign_opt |
| : trailing_assign |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| parameter_value_ranges_opt |
| : parameter_value_ranges |
| | /* empty */ |
| ; |
| parameter_value_ranges |
| : parameter_value_ranges parameter_value_range |
| | parameter_value_range |
| ; |
| parameter_value_range |
| : from_exclude '[' value_range_expression ':' value_range_expression ']' |
| | from_exclude '[' value_range_expression ':' value_range_expression ')' |
| | from_exclude '(' value_range_expression ':' value_range_expression ']' |
| | from_exclude '(' value_range_expression ':' value_range_expression ')' |
| | TK_exclude expression |
| ; |
| value_range_expression |
| : expression |
| /* Verilog-AMS supports +/- inf in ranges. */ |
| | TK_inf |
| | '+' TK_inf |
| | '-' TK_inf |
| ; |
| from_exclude |
| : TK_from |
| | TK_exclude |
| ; |
| parameter_value_opt |
| : parameters |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| parameters |
| : '#' '(' parameter_expr_list ')' |
| { $$ = MakeTaggedNode(N::kActualParameterList, $1, MakeParenGroup($2, $3, $4)); } |
| | '#' '(' parameter_value_byname_list ')' |
| { $$ = MakeTaggedNode(N::kActualParameterList, $1, MakeParenGroup($2, $3, $4)); } |
| /* TODO(fangism): allow preprocessor_directives in parameter_expr_list |
| * by combining with parameter_value_byname_list. |
| */ |
| | '#' '(' ')' |
| { $$ = MakeTaggedNode(N::kActualParameterList, $1, MakeParenGroup($2, nullptr, $3)); } |
| | '#' TK_DecNumber |
| { $$ = MakeTaggedNode(N::kActualParameterList, $1, $2); } |
| | '#' TK_RealTime |
| { $$ = MakeTaggedNode(N::kActualParameterList, $1, $2); } |
| ; |
| parameter_expr_list |
| /* positional arguments */ |
| : parameter_expr_list ',' parameter_expr |
| { $$ = ExtendNode($1, $2, $3); } |
| | parameter_expr |
| { $$ = MakeTaggedNode(N::kActualParameterPositionalList, $1); } |
| ; |
| parameter_value_byname |
| : '.' member_name '(' parameter_expr ')' |
| { $$ = MakeTaggedNode(N::kParamByName, $1, $2, MakeParenGroup($3, $4, $5)); } |
| | '.' member_name '(' ')' |
| { $$ = MakeTaggedNode(N::kParamByName, $1, $2, MakeParenGroup($3, nullptr, $4)); } |
| | '.' member_name |
| { $$ = MakeTaggedNode(N::kParamByName, $1, $2, nullptr); } |
| ; |
| parameter_value_byname_list |
| /* named arguments */ |
| : parameter_value_byname_list_item_last |
| { $$ = move($1); } |
| | parameter_value_byname_list_preprocessor_last |
| { $$ = move($1); } |
| | parameter_value_byname_list_trailing_comma |
| { $$ = move($1); } |
| ; |
| parameter_value_byname_list_trailing_comma |
| : parameter_value_byname_list ',' |
| { $$ = ExtendNode($1, $2); } |
| | ',' |
| { $$ = MakeTaggedNode(N::kActualParameterByNameList, $1); } |
| ; |
| parameter_value_byname_list_preprocessor_last |
| : parameter_value_byname_list preprocessor_directive |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_directive |
| { $$ = MakeTaggedNode(N::kActualParameterByNameList, $1); } |
| ; |
| parameter_value_byname_list_item_last |
| : parameter_value_byname |
| { $$ = MakeTaggedNode(N::kActualParameterByNameList, $1); } |
| | parameter_value_byname_list_trailing_comma parameter_value_byname |
| { $$ = ExtendNode($1, $2); } |
| | parameter_value_byname_list_preprocessor_last parameter_value_byname |
| { $$ = ExtendNode($1, $2); } |
| ; |
| |
| parameter_expr |
| /* similar to any_argument */ |
| : expression |
| { $$ = move($1); } |
| | data_type_primitive |
| { $$ = move($1); } |
| /* Spec grammar allows any data_type, but all user-defined types can look like |
| * expressions as qualified or unqualified identifiers. So limiting this |
| * rule to only primitive types eliminates conflict. |
| * Types may come from expression, but that can only be determined by symbol |
| * table lookup. |
| */ |
| | interface_type |
| { $$ = move($1); } |
| ; |
| |
| /* non-ANSI port declarations are covered in the LRM 23.2.2.1 */ |
| port |
| : port_expression trailing_assign_opt |
| /* when using a trailing_assign, port_expression should be a port_reference */ |
| { $$ = MakeTaggedNode(N::kPort, $1, $2); } |
| | '.' member_name '(' port_expression_opt ')' |
| { $$ = MakeTaggedNode(N::kPort, $1, $2, MakeParenGroup($3, $4, $5)); } |
| ; |
| any_port_list_opt |
| : any_port_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| any_port_list |
| : any_port_list_item_last |
| { $$ = move($1); } |
| | any_port_list_preprocessor_last |
| { $$ = move($1); } |
| | any_port_list_trailing_comma |
| { $$ = move($1); } |
| /* TODO(b/36237582): accept a macro item here |
| | any_port_list_trailing_macro_item |
| { $$ = move($1); } |
| ; |
| */ |
| any_port_list_trailing_comma |
| : any_port_list ',' |
| { $$ = ExtendNode($1, $2); } |
| | ',' |
| { $$ = MakeTaggedNode(N::kPortActualList, $1); } |
| ; |
| /* TODO(b/36237582): accept a macro item here |
| The difficulty around this lies with the reduction path from |
| MacroGenericItem -> expr_primary_no_groups -> expression. |
| Allowing MacroGenericItem here will hit R/R conflicts. |
| Ideally, what we want to express is that commas are optional following |
| MacroGenericItems. If we made commas optional entirely, it would be |
| too permissive w.r.t. actual LRM grammar, and would push the responsibility |
| to CST validation. |
| any_port_list_trailing_macro_item |
| : any_port_list MacroGenericItem |
| { $$ = ExtendNode($1, $2); } |
| | MacroGenericItem |
| { $$ = MakeTaggedNode(N::kPortActualList, $1); } |
| ; |
| */ |
| any_port_list_item_last |
| : any_port_list_trailing_comma any_port |
| { $$ = ExtendNode($1, $2); } |
| | any_port_list_preprocessor_last any_port |
| { $$ = ExtendNode($1, $2); } |
| | any_port |
| { $$ = MakeTaggedNode(N::kPortActualList, $1); } |
| ; |
| any_port_list_preprocessor_last |
| : any_port_list preprocessor_directive |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_directive |
| { $$ = MakeTaggedNode(N::kPortActualList, $1); } |
| ; |
| any_port |
| : port_named |
| { $$ = move($1); } |
| | expression |
| /* Note: expr_primary_no_groups already covers MacroGenericItem */ |
| { $$ = MakeTaggedNode(N::kActualPositionalPort, move($1)); } |
| ; |
| port_named |
| : '.' member_name '(' expression ')' |
| { $$ = MakeTaggedNode(N::kActualNamedPort, $1, $2, MakeParenGroup($3, $4, $5)); } |
| | '.' member_name '(' ')' |
| { $$ = MakeTaggedNode(N::kActualNamedPort, $1, $2, MakeParenGroup($3, nullptr, $4)); } |
| | '.' member_name |
| { $$ = MakeTaggedNode(N::kActualNamedPort, $1, $2, nullptr); } |
| | TK_DOTSTAR |
| { $$ = move($1); } |
| ; |
| |
| member_name |
| : GenericIdentifier |
| { $$ = move($1); } |
| | builtin_array_method |
| { $$ = move($1); } |
| ; |
| |
| port_expression_opt |
| : port_expression |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| port_expression |
| : port_reference |
| { $$ = move($1); } |
| | '{' port_reference_list '}' |
| { $$ = MakeBraceGroup($1, $2, $3); } |
| ; |
| |
| port_reference |
| : unqualified_id decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kPortReference, $1, $2); } |
| /* These 'unqualified_id' should all be GenericIdentifier, but were |
| * promoted to ease S/R conflict resolution vs. general class_ids in |
| * port declarations. |
| * TODO(fangism): Verify that $1 is a bare GenericIdentifier. |
| * TODO(fangism): Verify that $2 is a constant_select (select_dimensions). |
| */ |
| ; |
| port_reference_list |
| : port_reference |
| { $$ = MakeTaggedNode(N::kPortReferenceList, $1); } |
| | port_reference_list ',' port_reference |
| { $$ = ExtendNode($1, $2, $3); } |
| ; |
| select_dimensions_opt |
| : select_dimensions |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| select_dimensions |
| : select_variable_dimension |
| { $$ = MakeTaggedNode(N::kSelectVariableDimension, $1); } |
| | select_dimensions select_variable_dimension |
| { $$ = ExtendNode($1, $2); } |
| ; |
| |
| /* Depending on context, these could be either packed or unpacked dimensions. |
| * The caller of these rules should annotate as such. |
| */ |
| decl_dimensions_opt |
| : decl_dimensions |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| decl_dimensions |
| : decl_variable_dimension |
| { $$ = MakeTaggedNode(N::kDeclarationDimensions, $1); } |
| | decl_dimensions decl_variable_dimension |
| { $$ = ExtendNode($1, $2); } |
| ; |
| |
| /** merged into: gate_instance_or_register_variable_list |
| register_variable |
| : GenericIdentifier decl_dimensions_opt |
| | GenericIdentifier decl_dimensions_opt '=' expression |
| ; |
| register_variable_list |
| : register_variable |
| | register_variable_list ',' register_variable |
| ; |
| **/ |
| net_variable |
| : GenericIdentifier decl_dimensions_opt |
| { $$ = MakeTaggedNode(N::kNetVariable, $1, |
| MakeUnpackedDimensionsNode($2)); } |
| ; |
| /** merged into net_variable_or_decl_assigns: |
| net_variable_list |
| : net_variable |
| | net_variable_list ',' net_variable |
| ; |
| **/ |
| specify_item |
| : TK_specparam specparam_decl ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, $2, $3); } |
| | specify_simple_path_decl ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, $2); } |
| | specify_edge_path_decl ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, $2); } |
| | TK_if '(' expression ')' specify_simple_path_decl ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, $3, $4), $5, $6); } |
| | TK_if '(' expression ')' specify_edge_path_decl ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, $3, $4), $5, $6); } |
| | TK_ifnone specify_simple_path_decl ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, $2, $3); } |
| | TK_ifnone specify_edge_path_decl ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, $2, $3); } |
| | TK_Sfullskew '(' spec_reference_event ',' spec_reference_event |
| ',' delay_value ',' delay_value spec_notifier_opt ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7, $8, $9, $10), $11), |
| $12);} |
| | TK_Snochange '(' spec_reference_event ',' spec_reference_event |
| ',' delay_value ',' delay_value spec_notifier_opt ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7, $8, $9, $10), $11), |
| $12);} |
| | TK_Srecrem '(' spec_reference_event ',' spec_reference_event |
| ',' delay_value ',' delay_value spec_notifier_opt ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7, $8, $9, $10), $11), |
| $12);} |
| | TK_Ssetuphold '(' spec_reference_event ',' spec_reference_event |
| ',' delay_value ',' delay_value spec_notifier_opt ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7, $8, $9, $10), $11), |
| $12);} |
| |
| | TK_Speriod '(' spec_reference_event ',' delay_value spec_notifier_opt ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6), $7), |
| $8);} |
| | TK_Swidth '(' spec_reference_event ',' delay_value ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5), $6), |
| $7);} |
| | TK_Shold '(' spec_reference_event ',' spec_reference_event |
| ',' delay_value spec_notifier_opt ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $7, $8), $9), |
| $10);} |
| | TK_Srecovery '(' spec_reference_event ',' spec_reference_event |
| ',' delay_value spec_notifier_opt ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7, $8), $9), |
| $10); } |
| | TK_Sremoval '(' spec_reference_event ',' spec_reference_event |
| ',' delay_value spec_notifier_opt ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7, $8), $9), |
| $10); } |
| | TK_Ssetup '(' spec_reference_event ',' spec_reference_event |
| ',' delay_value spec_notifier_opt ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7, $8), $9), |
| $10); } |
| | TK_Sskew '(' spec_reference_event ',' spec_reference_event |
| ',' delay_value spec_notifier_opt ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7, $8), $9), |
| $10); } |
| | TK_Stimeskew '(' spec_reference_event ',' spec_reference_event |
| ',' delay_value spec_notifier_opt ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7, $8), $9), |
| $10); } |
| | TK_Swidth '(' spec_reference_event ',' delay_value |
| ',' expression spec_notifier_opt ')' ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, |
| MakeParenGroup($2, MakeNode($3, $4, $5, $6, $7, $8), $9), |
| $10); } |
| |
| | TK_pulsestyle_onevent specify_path_identifiers ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, $2, $3); } |
| | TK_pulsestyle_ondetect specify_path_identifiers ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, $2, $3); } |
| | TK_showcancelled specify_path_identifiers ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, $2, $3); } |
| | TK_noshowcancelled specify_path_identifiers ';' |
| { $$ = MakeTaggedNode(N::kSpecifyItem, $1, $2, $3); } |
| | preprocessor_directive |
| { $$ = move($1); } |
| ; |
| specify_item_list |
| : specify_item |
| { $$ = MakeTaggedNode(N::kSpecifyItemList, $1); } |
| | specify_item_list specify_item |
| { $$ = ExtendNode($1, $2); } |
| ; |
| specify_item_list_opt |
| : /* empty */ |
| { $$ = MakeTaggedNode(N::kSpecifyItemList); } |
| | specify_item_list |
| { $$ = move($1); } |
| ; |
| specify_edge_path_decl |
| : specify_edge_path '=' '(' delay_value_list ')' |
| { $$ = MakeTaggedNode(N::kSpecifyPathDeclaration, $1, $2, MakeParenGroup($3, $4, $5)); } |
| | specify_edge_path '=' delay_value_simple |
| { $$ = MakeTaggedNode(N::kSpecifyPathDeclaration, $1, $2, $3); } |
| ; |
| edge_operator |
| : TK_posedge |
| { $$ = move($1); } |
| | TK_negedge |
| { $$ = move($1); } |
| | TK_edge |
| { $$ = move($1); } |
| ; |
| specify_edge_path |
| : '(' specify_path_identifiers spec_polarity |
| TK_EG '(' specify_path_identifiers polarity_operator expression ')' ')' |
| { $$ = MakeTaggedNode(N::kSpecifyEdgePath, $1, $2, $3, $4, |
| MakeParenGroup($5, MakeNode($6, $7, $8), $9), $10); } |
| | '(' specify_path_identifiers spec_polarity |
| TK_SG '(' specify_path_identifiers polarity_operator expression ')' ')' |
| { $$ = MakeTaggedNode(N::kSpecifyEdgePath, $1, $2, $3, $4, |
| MakeParenGroup($5, MakeNode($6, $7, $8), $9), $10); } |
| | '(' edge_operator specify_path_identifiers spec_polarity |
| TK_EG '(' specify_path_identifiers polarity_operator expression ')' ')' |
| { $$ = MakeTaggedNode(N::kSpecifyEdgePath, $1, $2, $3, $4, $5, |
| MakeParenGroup($6, MakeNode($7, $8, $9), $10), $11); } |
| | '(' edge_operator specify_path_identifiers spec_polarity |
| TK_SG '(' specify_path_identifiers polarity_operator expression ')' ')' |
| { $$ = MakeTaggedNode(N::kSpecifyEdgePath, $1, $2, $3, $4, $5, |
| MakeParenGroup($6, MakeNode($7, $8, $9), $10), $11); } |
| ; |
| polarity_operator |
| : TK_PO_POS |
| { $$ = move($1); } |
| | TK_PO_NEG |
| { $$ = move($1); } |
| | ':' |
| { $$ = move($1); } |
| ; |
| specify_simple_path_decl |
| : specify_simple_path '=' '(' delay_value_list ')' |
| { $$ = MakeTaggedNode(N::kSpecifyPathDeclaration, $1, $2, MakeParenGroup($3, $4, $5)); } |
| | specify_simple_path '=' delay_value_simple |
| { $$ = MakeTaggedNode(N::kSpecifyPathDeclaration, $1, $2, $3); } |
| /** |
| | specify_simple_path '=' '(' error ')' |
| **/ |
| ; |
| specify_simple_path |
| : '(' specify_path_identifiers spec_polarity |
| TK_EG specify_path_identifiers ')' |
| { $$ = MakeTaggedNode(N::kSpecifySimplePath, $1, $2, $3, $4, $5, $6); } |
| | '(' specify_path_identifiers spec_polarity |
| TK_SG specify_path_identifiers ')' |
| { $$ = MakeTaggedNode(N::kSpecifySimplePath, $1, $2, $3, $4, $5, $6); } |
| /** |
| | '(' error ')' |
| **/ |
| ; |
| specify_path_identifiers |
| : GenericIdentifier |
| { $$ = MakeTaggedNode(N::kSpecifyPathIdentifier, $1); } |
| | GenericIdentifier '[' expr_primary ']' |
| { $$ = MakeTaggedNode(N::kSpecifyPathIdentifier, $1, MakeBracketGroup($2, $3, $4)); } |
| | specify_path_identifiers ',' GenericIdentifier |
| { $$ = ExtendNode($1, $2, $3); } |
| | specify_path_identifiers ',' GenericIdentifier '[' expr_primary ']' |
| { $$ = ExtendNode($1, $2, $3, MakeBracketGroup($4, $5, $6)); } |
| ; |
| specparam |
| /* all expressions should have constant value */ |
| : GenericIdentifier '=' expression |
| { $$ = MakeTaggedNode(N::kSpecParam, $1, $2, $3); } |
| | GenericIdentifier '=' expression ':' expression ':' expression |
| { $$ = MakeTaggedNode(N::kSpecParam, $1, $2, MakeTaggedNode(N::kMinTypMaxList, |
| $3, $4, $5, $6, $7)); } |
| /* TODO(fangism): support pulse_control_specparam. |
| | GenericIdentifier '=' '(' expression ',' expression ')' |
| */ |
| ; |
| specparam_list |
| : specparam |
| { $$ = MakeTaggedNode(N::kSpecParamList, $1); } |
| | specparam_list ',' specparam |
| { $$ = ExtendNode($1, $2); } |
| ; |
| specparam_decl |
| : specparam_list |
| { $$ = move($1); } |
| | decl_dimensions specparam_list |
| { $$ = MakeTaggedNode(N::kSpecParamDeclaration, |
| MakePackedDimensionsNode($1), $2); } |
| ; |
| spec_polarity |
| : '+' |
| { $$ = move($1); } |
| | '-' |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| spec_reference_event |
| /* also known as: timing_check_event */ |
| : edge_operator specify_terminal_descriptor |
| { $$ = MakeTaggedNode(N::kSpecifyReferenceEvent, $1, $2);} |
| | edge_operator specify_terminal_descriptor TK_TAND expression |
| { $$ = MakeTaggedNode(N::kSpecifyReferenceEvent, $1, $2, $3, $4);} |
| /* $4 should be a timing_check_condition */ |
| | TK_edge '[' edge_descriptor_list ']' specify_terminal_descriptor |
| { $$ = MakeTaggedNode(N::kSpecifyReferenceEvent, $1, MakeBracketGroup($2, $3, $4), |
| $5); } |
| | TK_edge '[' edge_descriptor_list ']' specify_terminal_descriptor TK_TAND expression |
| { $$ = MakeTaggedNode(N::kSpecifyReferenceEvent, $1, MakeBracketGroup($2, $3, $4), |
| $5, $6, $7); } |
| | specify_terminal_descriptor TK_TAND expression |
| { $$ = MakeTaggedNode(N::kSpecifyReferenceEvent, $1, $2, $3);} |
| | specify_terminal_descriptor |
| { $$ = MakeTaggedNode(N::kSpecifyReferenceEvent, $1);} |
| ; |
| edge_descriptor_list |
| : edge_descriptor_list ',' TK_edge_descriptor |
| { $$ = ExtendNode($1, $2, $3); } |
| | TK_edge_descriptor |
| { $$ = MakeTaggedNode(N::kEdgeDescriptorList, $1); } |
| ; |
| specify_terminal_descriptor |
| : reference |
| { $$ = move($1); } |
| ; |
| spec_notifier_opt |
| : spec_notifier |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| spec_notifier |
| : ',' |
| { $$ = MakeTaggedNode(N::kSpecifyNotifier, $1); } |
| | ',' reference |
| { $$ = MakeTaggedNode(N::kSpecifyNotifier, $1, $2); } |
| | spec_notifier ',' |
| { $$ = ExtendNode($1, $2); } |
| | spec_notifier ',' reference |
| { $$ = ExtendNode($1, $2, $3); } |
| | GenericIdentifier |
| { $$ = MakeTaggedNode(N::kSpecifyNotifier, $1); } |
| ; |
| |
| |
| case_any |
| : TK_case |
| { $$ = move($1); } |
| | TK_casex |
| { $$ = move($1); } |
| | TK_casez |
| { $$ = move($1); } |
| ; |
| |
| blocking_assignment |
| /* TODO(fangism): structure kBlockingAssignmentStatement consistently */ |
| : lpvalue '=' delay_or_event_control expression ';' |
| { $$ = MakeTaggedNode(N::kBlockingAssignmentStatement, $1, $2, $3, $4, $5); } |
| | lpvalue '=' dynamic_array_new ';' |
| { $$ = MakeTaggedNode(N::kBlockingAssignmentStatement, $1, $2, $3, $4); } |
| | lpvalue '=' class_new ';' |
| { $$ = MakeTaggedNode(N::kBlockingAssignmentStatement, $1, $2, $3, $4); } |
| ; |
| |
| nonblocking_assignment |
| /* TODO(fangism): structure kNonblockingAssignmentStatement consistently */ |
| : lpvalue TK_LE delay_or_event_control_opt expression ';' |
| { $$ = MakeTaggedNode(N::kNonblockingAssignmentStatement, $1, $2, $3, $4, $5); } |
| /* This rule overlaps with clocking_drive. */ |
| ; |
| clocking_drive_only |
| : lpvalue TK_LE cycle_delay expression ';' |
| { $$ = MakeTaggedNode(N::kNonblockingAssignmentStatement, $1, $2, $3, $4, $5); } |
| ; |
| |
| procedural_continuous_assignment |
| : TK_assign lpvalue '=' expression ';' |
| { $$ = MakeTaggedNode(N::kProceduralContinuousAssignmentStatement, $1, |
| MakeTaggedNode(N::kNetVariableAssignment, $2, $3, $4), |
| $5); } |
| | TK_assign macro_call_or_item |
| { $$ = MakeTaggedNode(N::kProceduralContinuousAssignmentStatement, $1, $2); } |
| /* allowed because this has been observed in practice */ |
| | TK_deassign lpvalue ';' |
| { $$ = MakeTaggedNode(N::kProceduralContinuousDeassignmentStatement, $1, $2, $3); } |
| | TK_force lpvalue '=' expression ';' |
| { $$ = MakeTaggedNode(N::kProceduralContinuousForceStatement, $1, |
| MakeTaggedNode(N::kNetVariableAssignment, $2, $3, $4), |
| $5); } |
| | TK_release lpvalue ';' |
| { $$ = MakeTaggedNode(N::kProceduralContinuousReleaseStatement, $1, $2, $3); } |
| ; |
| |
| case_statement |
| /* TODO(jeremycs): maybe add structure */ |
| /* includes randcase_statement */ |
| : unique_priority_opt case_any '(' expression ')' case_items TK_endcase |
| { $$ = MakeTaggedNode(N::kCaseStatement, $1, $2, MakeParenGroup($3, $4, $5), $6, $7);} |
| | unique_priority_opt case_any '(' expression ')' TK_matches |
| case_pattern_items TK_endcase |
| { $$ = MakeTaggedNode(N::kCaseStatement, $1, $2, MakeParenGroup($3, $4, $5), $6, $7, $8);} |
| | unique_priority_opt case_any '(' expression ')' TK_inside |
| case_inside_items TK_endcase |
| { $$ = MakeTaggedNode(N::kCaseStatement, $1, $2, MakeParenGroup($3, $4, $5), $6, $7, $8);} |
| /* $2 should only be TK_case, but case_any avoids S/R conflict. */ |
| | unique_priority_opt TK_randcase case_items TK_endcase |
| { $$ = MakeTaggedNode(N::kRandCaseStatement, $1, $2, $3, $4);} |
| /** |
| | TK_case '(' expression ')' case_items TK_endcase |
| | TK_casex '(' expression ')' case_items TK_endcase |
| | TK_casez '(' expression ')' case_items TK_endcase |
| **/ |
| ; |
| |
| conditional_statement |
| : unique_priority_opt TK_if '(' expression ')' statement_or_null |
| %prec less_than_TK_else |
| { $$ = MakeTaggedNode(N::kConditionalStatement, |
| MakeTaggedNode(N::kIfClause, |
| MakeTaggedNode(N::kIfHeader, $1, $2, MakeParenGroup($3, $4, $5)), |
| MakeTaggedNode(N::kIfBody, $6)));} |
| | unique_priority_opt TK_if '(' expression ')' statement_or_null |
| TK_else statement_or_null |
| { $$ = MakeTaggedNode(N::kConditionalStatement, |
| MakeTaggedNode(N::kIfClause, |
| MakeTaggedNode(N::kIfHeader, $1, $2, MakeParenGroup($3, $4, $5)), |
| MakeTaggedNode(N::kIfBody, $6)), |
| MakeTaggedNode(N::kElseClause, $7, MakeTaggedNode(N::kElseBody, $8)));} |
| ; |
| |
| event_trigger |
| : TK_TRIGGER reference ';' |
| { $$ = MakeTaggedNode(N::kBlockingEventTriggerStatement, $1, $2, $3); } |
| | TK_NONBLOCKING_TRIGGER delay_or_event_control_opt reference ';' |
| { $$ = MakeTaggedNode(N::kNonblockingEventTriggerStatement, |
| $1, $2, $3, $4); } |
| ; |
| |
| repeat_control |
| : TK_repeat '(' expression ')' |
| { $$ = MakeTaggedNode(N::kRepeatControl, $1, MakeParenGroup($2, $3, $4)); } |
| ; |
| |
| delay_or_event_control |
| : delay1 |
| { $$ = move($1); } |
| | event_control |
| { $$ = move($1); } |
| | repeat_control event_control |
| { $$ = MakeTaggedNode(N::kRepeatEventControl, $1, $2); } |
| ; |
| |
| delay_or_event_control_opt |
| : delay_or_event_control |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| par_block |
| : TK_fork label_opt |
| /* merged: block_item_decls_opt statement_or_null_list_opt */ |
| block_item_or_statement_or_null_list_opt |
| join_keyword label_opt |
| /* TODO(fangism): pair ($1,$2) and ($4,$5) together, like kBegin,kEnd */ |
| { $$ = MakeTaggedNode(N::kParBlock, $1, $2, $3, $4, $5); } |
| ; |
| |
| procedural_timing_control_statement |
| : delay1 statement_or_null |
| { $$ = MakeTaggedNode(N::kProceduralTimingControlStatement, $1, $2); } |
| | event_control statement_or_null |
| { $$ = MakeTaggedNode(N::kProceduralTimingControlStatement, $1, $2); } |
| | cycle_delay statement_or_null |
| { $$ = MakeTaggedNode(N::kProceduralTimingControlStatement, $1, $2); } |
| ; |
| |
| seq_block |
| : begin block_item_or_statement_or_null_list_opt end |
| /* merged: block_item_decls_opt statement_or_null_list_opt */ |
| { $$ = MakeTaggedNode(N::kSeqBlock, $1, $2, $3); } |
| ; |
| |
| wait_statement |
| : TK_wait '(' expression ')' statement_or_null |
| /* shaped similarly to kIfClause */ |
| { $$ = MakeTaggedNode(N::kWaitStatement, |
| MakeTaggedNode(N::kWaitHeader, |
| $1, MakeParenGroup($2, $3, $4)), |
| MakeTaggedNode(N::kWaitBody, $5));} |
| | TK_wait TK_fork ';' |
| { $$ = MakeTaggedNode(N::kWaitForkStatement, $1, $2, $3);} |
| /* TODO(b/144972702): wait_order ... */ |
| ; |
| |
| statement_item |
| /* TODO(fangism): Some of these may not be valid for both tasks and functions. */ |
| : blocking_assignment |
| { $$ = move($1); } |
| | nonblocking_assignment |
| { $$ = move($1); } |
| | procedural_continuous_assignment |
| { $$ = move($1); } |
| | case_statement |
| { $$ = move($1); } |
| /* covers randcase_statement */ |
| | conditional_statement |
| { $$ = move($1); } |
| | assignment_statement ';' |
| { $$ = ExtendNode($1, $2); } |
| /* includes inc_or_dec_expression */ |
| /* TODO(fangism): expand this from for_step_assignment */ |
| | disable_statement |
| { $$ = move($1); } |
| | event_trigger |
| { $$ = move($1); } |
| | loop_statement |
| { $$ = move($1); } |
| | jump_statement |
| { $$ = move($1); } |
| | par_block |
| { $$ = move($1); } |
| | procedural_timing_control_statement |
| { $$ = move($1); } |
| | seq_block |
| { $$ = move($1); } |
| | wait_statement |
| { $$ = move($1); } |
| | procedural_assertion_statement |
| { $$ = move($1); } |
| | expect_property_statement |
| { $$ = move($1); } |
| | clocking_drive_only |
| { $$ = move($1); } |
| | randsequence_statement |
| { $$ = move($1); } |
| | subroutine_call ';' |
| { $$ = MakeTaggedNode(N::kStatement, $1, $2); } |
| /* covered by reference_or_call rule: |
| | scoped_hierarchy_identifier '(' argument_list_opt ')' ';' |
| | scoped_hierarchy_identifier ';' |
| | implicit_class_handle '.' TK_new '(' argument_list_opt ')' ';' |
| */ |
| | randomize_call ';' |
| { $$ = MakeTaggedNode(N::kStatement, $1, $2); } |
| // seen in the wild: |
| | TK_void '\'' '(' expression ')' ';' |
| { $$ = MakeTaggedNode(N::kStatement, MakeTaggedNode(N::kVoidcast, $1, $2, MakeParenGroup($3, $4, $5), $6)); } |
| | error ';' |
| { yyerrok; $$ = Recover(); } |
| | MacroGenericItem /* statement that does not end with ; */ |
| { $$ = move($1); } |
| /* reference_or_call already covers: MacroCall ';' */ |
| /* preprocessor_directive has been split into the following: */ |
| | preprocessor_balanced_statements |
| { $$ = move($1); } |
| | preprocessor_action |
| { $$ = move($1); } |
| ; |
| |
| preprocessor_balanced_statements |
| : preprocessor_if_header block_item_or_statement_or_null_list_opt |
| preprocessor_elsif_statements_opt |
| preprocessor_else_statement_opt |
| PP_endif |
| { $$ = MakeTaggedNode(N::kPreprocessorBalancedStatements, |
| ExtendNode($1, $2), ForwardChildren($3), $4, $5); |
| } |
| ; |
| preprocessor_elsif_statements_opt |
| : preprocessor_elsif_statements |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_elsif_statements |
| : preprocessor_elsif_statements preprocessor_elsif_statement |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_elsif_statement |
| { $$ = MakeNode($1); } /* Don't bother tagging; node will be flattened. */ |
| ; |
| preprocessor_elsif_statement |
| : preprocessor_elsif_header block_item_or_statement_or_null_list_opt |
| { $$ = ExtendNode($1, $2); } |
| ; |
| preprocessor_else_statement_opt |
| : preprocessor_else_statement |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_else_statement |
| : PP_else block_item_or_statement_or_null_list_opt |
| { $$ = MakeTaggedNode(N::kPreprocessorElseClause, $1, $2); } |
| ; |
| |
| disable_statement |
| : TK_disable reference ';' |
| { $$ = MakeTaggedNode(N::kDisableStatement, $1, $2, $3); } |
| | TK_disable TK_fork ';' |
| { $$ = MakeTaggedNode(N::kDisableStatement, $1, $2, $3); } |
| ; |
| assign_modify_statement |
| : lpvalue TK_PLUS_EQ expression |
| { $$ = MakeTaggedNode(N::kAssignModifyStatement, $1, $2, $3); } |
| | lpvalue TK_MINUS_EQ expression |
| { $$ = MakeTaggedNode(N::kAssignModifyStatement, $1, $2, $3); } |
| | lpvalue TK_MUL_EQ expression |
| { $$ = MakeTaggedNode(N::kAssignModifyStatement, $1, $2, $3); } |
| | lpvalue TK_DIV_EQ expression |
| { $$ = MakeTaggedNode(N::kAssignModifyStatement, $1, $2, $3); } |
| | lpvalue TK_MOD_EQ expression |
| { $$ = MakeTaggedNode(N::kAssignModifyStatement, $1, $2, $3); } |
| | lpvalue TK_AND_EQ expression |
| { $$ = MakeTaggedNode(N::kAssignModifyStatement, $1, $2, $3); } |
| | lpvalue TK_OR_EQ expression |
| { $$ = MakeTaggedNode(N::kAssignModifyStatement, $1, $2, $3); } |
| | lpvalue TK_XOR_EQ expression |
| { $$ = MakeTaggedNode(N::kAssignModifyStatement, $1, $2, $3); } |
| | lpvalue TK_LS_EQ expression |
| { $$ = MakeTaggedNode(N::kAssignModifyStatement, $1, $2, $3); } |
| | lpvalue TK_RS_EQ expression |
| { $$ = MakeTaggedNode(N::kAssignModifyStatement, $1, $2, $3); } |
| | lpvalue TK_RSS_EQ expression |
| { $$ = MakeTaggedNode(N::kAssignModifyStatement, $1, $2, $3); } |
| ; |
| unique_priority_opt |
| : TK_unique |
| { $$ = move($1); } |
| | TK_unique0 |
| { $$ = move($1); } |
| | TK_priority |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| statement_or_null_list_opt |
| : statement_or_null_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = MakeTaggedNode(N::kStatementList); } |
| ; |
| statement_or_null_list |
| : statement_or_null_list statement_or_null |
| { $$ = ExtendNode($1, $2); } |
| | statement_or_null |
| { $$ = MakeTaggedNode(N::kStatementList, $1); } |
| ; |
| analog_statement |
| : branch_probe_expression TK_CONTRIBUTE expression ';' |
| { $$ = MakeTaggedNode(N::kAnalogStatement, $1, $2, $3, $4); } |
| ; |
| /* same as function_item */ |
| task_item |
| : block_item_decl |
| { $$ = move($1); } |
| | tf_port_declaration |
| { $$ = move($1); } |
| ; |
| /** merged with into tf_item_or_statement_or_null_list |
| task_item_list |
| : task_item_list task_item |
| | task_item |
| ; |
| task_item_list_opt |
| : task_item_list |
| | // empty |
| ; |
| **/ |
| /* introduced to simplify grammar, reduce conflicts */ |
| tf_item_or_statement_or_null |
| : task_item |
| { $$ = move($1); } |
| | statement_or_null |
| { $$ = move($1); } |
| ; |
| tf_item_or_statement_or_null_list |
| /* TODO(jeremycs): unclear if this should have its own enum */ |
| : tf_item_or_statement_or_null |
| { $$ = MakeTaggedNode(N::kStatementList, $1); } |
| | tf_item_or_statement_or_null_list tf_item_or_statement_or_null |
| { $$ = ExtendNode($1, $2); } |
| ; |
| tf_item_or_statement_or_null_list_opt |
| : tf_item_or_statement_or_null_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = MakeTaggedNode(N::kStatementList); } |
| ; |
| |
| tf_port_list_paren_opt |
| : '(' tf_port_list_opt ')' |
| { $$ = MakeParenGroup($1, $2, $3); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| tf_port_list_opt |
| : tf_port_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| |
| ; |
| udp_body |
| : TK_table udp_entry_list TK_endtable |
| { $$ = MakeTaggedNode(N::kUdpBody, $1, $2, $3); } |
| | TK_table TK_endtable |
| { $$ = MakeTaggedNode(N::kUdpBody, $1, nullptr, $2); } |
| /** |
| | TK_table error TK_endtable |
| **/ |
| ; |
| udp_entry_list |
| : udp_comb_entry_list |
| { $$ = move($1); } |
| | udp_sequ_entry_list |
| { $$ = move($1); } |
| | udp_unknown_list |
| { $$ = move($1); } |
| ; |
| udp_unknown_list |
| : udp_unknown_list preprocessor_directive |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_directive |
| { $$ = MakeTaggedNode(N::kUdpEntryList, $1); } |
| ; |
| udp_comb_entry |
| : udp_input_list ':' udp_output_sym ';' |
| { $$ = MakeTaggedNode(N::kUdpCombEntry, $1, $2, $3, $4); } |
| ; |
| udp_comb_entry_list |
| : udp_comb_entry |
| { $$ = MakeTaggedNode(N::kUdpEntryList, $1); } |
| | udp_comb_entry_list udp_comb_entry |
| { $$ = ExtendNode($1, $2); } |
| | udp_comb_entry_list preprocessor_directive |
| { $$ = ExtendNode($1, $2); } |
| | udp_unknown_list udp_comb_entry |
| { $$ = ExtendNode($1, $2); } |
| ; |
| udp_sequ_entry_list |
| : udp_sequ_entry |
| { $$ = MakeTaggedNode(N::kUdpEntryList, $1); } |
| | udp_sequ_entry_list udp_sequ_entry |
| { $$ = ExtendNode($1, $2); } |
| | udp_sequ_entry_list preprocessor_directive |
| { $$ = ExtendNode($1, $2); } |
| | udp_unknown_list udp_sequ_entry |
| { $$ = ExtendNode($1, $2); } |
| ; |
| udp_sequ_entry |
| : udp_input_list ':' udp_input_sym ':' udp_output_sym ';' |
| { $$ = MakeTaggedNode(N::kUdpSequenceEntry, $1, $2, $3, $4, $5, $6); } |
| ; |
| udp_initial |
| : TK_initial GenericIdentifier '=' number ';' |
| { $$ = MakeTaggedNode(N::kUdpInitial, $1, $2, $3, $4, $5); } |
| ; |
| udp_init_opt |
| : udp_initial |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| udp_input_list |
| : udp_input_sym |
| { $$ = MakeTaggedNode(N::kUdpInputList, $1); } |
| | udp_input_list udp_input_sym |
| { $$ = ExtendNode($1, $2); } |
| ; |
| udp_input_sym |
| : '0' |
| { $$ = move($1); } |
| | '1' |
| { $$ = move($1); } |
| | 'x' |
| { $$ = move($1); } |
| | '?' |
| { $$ = move($1); } |
| | 'b' |
| { $$ = move($1); } |
| | '*' |
| { $$ = move($1); } |
| | '%' |
| { $$ = move($1); } |
| | 'f' |
| { $$ = move($1); } |
| | 'F' |
| { $$ = move($1); } |
| | 'l' |
| { $$ = move($1); } |
| | 'h' |
| { $$ = move($1); } |
| | 'B' |
| { $$ = move($1); } |
| | 'r' |
| { $$ = move($1); } |
| | 'R' |
| { $$ = move($1); } |
| | 'M' |
| { $$ = move($1); } |
| | 'n' |
| { $$ = move($1); } |
| | 'N' |
| { $$ = move($1); } |
| | 'p' |
| { $$ = move($1); } |
| | 'P' |
| { $$ = move($1); } |
| | 'Q' |
| { $$ = move($1); } |
| | 'q' |
| { $$ = move($1); } |
| | '_' |
| { $$ = move($1); } |
| | '+' |
| { $$ = move($1); } |
| | TK_DecNumber |
| { $$ = move($1); } |
| ; |
| udp_output_sym |
| : '0' |
| { $$ = move($1); } |
| | '1' |
| { $$ = move($1); } |
| | 'x' |
| { $$ = move($1); } |
| | '-' |
| { $$ = move($1); } |
| | TK_DecNumber |
| { $$ = move($1); } |
| ; |
| udp_port_decl |
| : TK_input list_of_identifiers ';' |
| { $$ = MakeTaggedNode(N::kUdpPortDeclaration, nullptr, $1, $2, $3); } |
| | TK_output GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kUdpPortDeclaration, nullptr, $1, $2, $3); } |
| | TK_reg GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kUdpPortDeclaration, $1, nullptr, $2, $3); } |
| | TK_reg TK_output GenericIdentifier ';' |
| { $$ = MakeTaggedNode(N::kUdpPortDeclaration, $1, $2, $3, $4); } |
| ; |
| udp_port_decls |
| : udp_port_decl |
| { $$ = MakeTaggedNode(N::kUdpPortDeclarationList, $1); } |
| | udp_port_decls udp_port_decl |
| { $$ = ExtendNode($1, $2); } |
| ; |
| udp_port_list |
| : GenericIdentifier |
| { $$ = MakeTaggedNode(N::kUdpPortList, $1); } |
| | udp_port_list ',' GenericIdentifier |
| { $$ = ExtendNode($1, $2, $3); } |
| ; |
| udp_initial_expr_opt |
| : '=' expression |
| { $$ = MakeTaggedNode(N::kTrailingAssign, $1, $2); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| udp_input_declaration_list |
| : TK_input GenericIdentifier |
| { $$ = MakeTaggedNode(N::kUdpInputDeclarationList, $1, $2); } |
| | udp_input_declaration_list ',' TK_input GenericIdentifier |
| { $$ = ExtendNode($1, $2, $3, $4); } |
| ; |
| udp_primitive |
| : TK_primitive GenericIdentifier '(' udp_port_list ')' ';' |
| udp_port_decls |
| udp_init_opt |
| udp_body |
| TK_endprimitive label_opt |
| { $$ = MakeTaggedNode(N::kUdpPrimitive, $1, $2, MakeParenGroup($3, $4, $5), $6, |
| $7, $8, $9, $10, $11); } |
| | TK_primitive GenericIdentifier |
| '(' TK_output TK_reg_opt GenericIdentifier udp_initial_expr_opt ',' |
| udp_input_declaration_list ')' ';' |
| udp_body |
| TK_endprimitive label_opt |
| { $$ = MakeTaggedNode(N::kUdpPrimitive, $1, $2, |
| MakeParenGroup($3, MakeNode($4, $5, $6, $7, $8, $9), $10), |
| $11, $12, $13, $14); } |
| ; |
| lifetime |
| : TK_automatic |
| { $$ = move($1); } |
| | TK_static |
| { $$ = move($1); } |
| ; |
| lifetime_opt |
| : lifetime |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| TK_reg_opt |
| : TK_reg |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| TK_static_opt |
| : TK_static |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| TK_tagged_opt |
| : TK_tagged |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| TK_virtual_opt |
| : TK_virtual |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| bind_directive |
| : TK_bind reference ':' bind_target_instance_list bind_instantiation ';' |
| { $$ = MakeTaggedNode(N::kBindDirective, $1, $2, $3, $4, $5, $6); } |
| /* $2 is target scope (module or interface), |
| * and should be GenericIdentifier. |
| */ |
| | TK_bind reference bind_instantiation ';' |
| { $$ = MakeTaggedNode(N::kBindDirective, $1, $2, nullptr, nullptr, $3, $4); } |
| /* if $2 is target scope (module or interface), |
| * then $2 should be a GenericIdentifier, |
| * if $2 is a bind_target_scope, then it may be hierarchical. |
| */ |
| ; |
| bind_target_instance_list |
| : bind_target_instance_list ',' bind_target_instance |
| { $$ = ExtendNode($1, $2, $3); } |
| | bind_target_instance |
| { $$ = MakeTaggedNode(N::kBindTargetInstanceList, $1); } |
| ; |
| bind_target_instance |
| : reference |
| { $$ = move($1); } |
| /* Any bit selections in []'s must be constant expressions. */ |
| ; |
| bind_instantiation |
| /* similar to block_item_decl instantiation */ |
| : class_id gate_instance_or_register_variable_list |
| { $$ = MakeTaggedNode(N::kBindTargetInstance, $1, $2); } |
| /* covers: program, module, interface, checker instantiation */ |
| ; |
| |
| clocking_declaration |
| /* TODO(b/19573356): Introduce CodeBlock::CLOCKING. */ |
| : TK_default TK_clocking identifier_opt event_control ';' |
| clocking_item_list_opt |
| TK_endclocking label_opt |
| { $$ = MakeTaggedNode(N::kClockingDeclaration, $1, $2, $3, $4, $5, $6, $7, $8); } |
| /* $4 event_control should be @identifier or @(event_expr) */ |
| | TK_clocking identifier_opt event_control ';' |
| clocking_item_list_opt |
| TK_endclocking label_opt |
| { $$ = MakeTaggedNode(N::kClockingDeclaration, nullptr, $1, $2, $3, $4, $5, $6, $7); } |
| /* $4 event_control should be @identifier or @(event_expr) */ |
| | TK_global TK_clocking identifier_opt event_control ';' |
| TK_endclocking label_opt |
| { $$ = MakeTaggedNode(N::kClockingDeclaration, $1, $2, $3, $4, $5, $6, nullptr, $7); } |
| ; |
| clocking_item_list_opt |
| : clocking_item_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| clocking_item_list |
| : clocking_item_list clocking_item |
| { $$ = ExtendNode($1, $2); } |
| | clocking_item |
| { $$ = MakeTaggedNode(N::kClockingItemList, $1); } |
| ; |
| clocking_item |
| : TK_default default_skew ';' |
| { $$ = MakeTaggedNode(N::kClockingItem, $1, $2, $3); } |
| | clocking_direction list_of_clocking_decl_assign ';' |
| { $$ = MakeTaggedNode(N::kClockingItem, $1, $2, $3); } |
| | /* attribute_list_opt */ assertion_item_declaration |
| { $$ = move($1); } |
| | let_declaration |
| { $$ = move($1); } |
| ; |
| default_skew |
| : TK_input clocking_skew |
| { $$ = MakeTaggedNode(N::kDefaultSkew, $1, $2);} |
| | TK_input clocking_skew TK_output clocking_skew |
| { $$ = MakeTaggedNode(N::kDefaultSkew, $1, $2, $3, $4);} |
| | TK_output clocking_skew |
| { $$ = MakeTaggedNode(N::kDefaultSkew, $1, $2);} |
| ; |
| clocking_skew_opt |
| : clocking_skew |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| clocking_skew |
| : edge_operator delay3_opt |
| { $$ = MakeTaggedNode(N::kClockingSkew, $1, $2);} |
| | delay3 |
| { $$ = MakeTaggedNode(N::kClockingSkew, $1);} |
| ; |
| clocking_direction |
| : TK_input clocking_skew_opt |
| { $$ = MakeTaggedNode(N::kClockingDirection, $1, $2); } |
| | TK_input clocking_skew_opt TK_output clocking_skew_opt |
| { $$ = MakeTaggedNode(N::kClockingDirection, $1, $2, $3, $4); } |
| | TK_output clocking_skew_opt |
| { $$ = MakeTaggedNode(N::kClockingDirection, $1, $2); } |
| | TK_inout |
| { $$ = MakeTaggedNode(N::kClockingDirection, $1); } |
| ; |
| list_of_clocking_decl_assign |
| : list_of_clocking_decl_assign ',' clocking_decl_assign |
| { $$ = ExtendNode($1, $2, $3); } |
| | clocking_decl_assign |
| { $$ = MakeTaggedNode(N::kClockingAssignList, $1); } |
| ; |
| clocking_decl_assign |
| : GenericIdentifier trailing_assign_opt |
| { $$ = MakeTaggedNode(N::kClockingAssign, $1, $2); } |
| /* $1 is signal_identifier */ |
| ; |
| |
| assertion_item_declaration |
| : property_declaration |
| { $$ = move($1); } |
| | sequence_declaration |
| { $$ = move($1); } |
| /* moved to other rules to avoid R/R conflict |
| | let_declaration |
| */ |
| ; |
| |
| let_declaration |
| : TK_let GenericIdentifier let_port_list_in_parens_opt '=' expression ';' |
| { $$ = MakeTaggedNode(N::kLetDeclaration, $1, $2, $3, $4, $5, $6); } |
| ; |
| let_port_list_in_parens_opt |
| : '(' let_port_list ')' |
| { $$ = MakeParenGroup($1, $2, $3); } |
| | '(' ')' |
| { $$ = MakeParenGroup($1, nullptr, $2); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| let_port_list |
| : let_port_list ',' let_port_item |
| { $$ = ExtendNode($1, $2, $3); } |
| | let_port_item |
| { $$ = MakeTaggedNode(N::kLetPortList, $1); } |
| ; |
| let_port_item |
| : let_formal_type_followed_by_id decl_dimensions_opt |
| /* $2 is not limited to being an unpacked dimension */ |
| { $$ = MakeTaggedNode(N::kLetPortItem, ForwardChildren($1), $2); } |
| | let_formal_type_followed_by_id decl_dimensions_opt '=' expression |
| { $$ = MakeTaggedNode(N::kLetPortItem, ForwardChildren($1), $2, $3, $4); } |
| ; |
| let_formal_type_followed_by_id |
| /* similar to property_formal_type_followed_by_id */ |
| : data_type_or_implicit_basic_followed_by_id |
| { $$ = move($1); } |
| | TK_untyped GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, $1, $2); } |
| ; |
| |
| sequence_declaration |
| : TK_sequence GenericIdentifier |
| sequence_port_list_in_parens_opt ';' |
| assertion_variable_declaration_list |
| SemicolonEndOfAssertionVariableDeclarations |
| sequence_expr optional_semicolon |
| TK_endsequence label_opt |
| { $$ = MakeTaggedNode(N::kSequenceDeclaration, |
| $1, $2, $3, $4, ExtendNode($5, $6), |
| MakeTaggedNode(N::kSequenceDeclarationFinalExpr, $7, $8), |
| $9, $10); } |
| | TK_sequence GenericIdentifier |
| sequence_port_list_in_parens_opt |
| SemicolonEndOfAssertionVariableDeclarations |
| sequence_expr optional_semicolon |
| TK_endsequence label_opt |
| { $$ = MakeTaggedNode(N::kSequenceDeclaration, |
| $1, $2, $3, $4, nullptr, |
| MakeTaggedNode(N::kSequenceDeclarationFinalExpr, $5, $6), |
| $7, $8); } |
| ; |
| |
| sequence_port_list_in_parens_opt |
| : '(' sequence_port_list_opt ')' |
| { $$ = MakeParenGroup($1, $2, $3); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| sequence_port_list_opt |
| : sequence_port_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| sequence_port_list |
| : sequence_port_list ',' sequence_port_item |
| { $$ = ExtendNode($1, $2, $3); } |
| | sequence_port_item |
| { $$ = MakeTaggedNode(N::kSequencePortList, $1); } |
| ; |
| sequence_port_item |
| : /* attribute_list_opt */ |
| local_sequence_lvar_port_direction_opt |
| sequence_port_type_followed_by_id decl_dimensions_opt trailing_assign_opt |
| /* $3 is not limited to being an unpacked dimension */ |
| { $$ = MakeTaggedNode(N::kSequencePortItem, $1, $2, $3, $4); } |
| ; |
| local_sequence_lvar_port_direction_opt |
| : TK_local dir |
| { $$ = MakeNode($1, $2); } |
| | TK_local |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| sequence_port_type_followed_by_id |
| /* similar to property_formal_type_followed_by_id */ |
| : data_type_or_implicit_basic_followed_by_id |
| { $$ = move($1); } |
| | TK_sequence GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, $1, $2); } |
| | TK_untyped GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, $1, $2); } |
| ; |
| |
| property_declaration |
| : TK_property GenericIdentifier property_port_list_in_parens_opt ';' |
| assertion_variable_declaration_list |
| SemicolonEndOfAssertionVariableDeclarations |
| property_spec optional_semicolon |
| TK_endproperty label_opt |
| { $$ = MakeTaggedNode(N::kPropertyDeclaration, |
| $1, $2, $3, $4, ExtendNode($5, $6), |
| ExtendNode($7, $8), $9, $10); } |
| | TK_property GenericIdentifier property_port_list_in_parens_opt |
| SemicolonEndOfAssertionVariableDeclarations |
| property_spec optional_semicolon |
| TK_endproperty label_opt |
| { $$ = MakeTaggedNode(N::kPropertyDeclaration, |
| $1, $2, $3, $4, nullptr, |
| ExtendNode($5, $6), $7, $8); } |
| ; |
| property_port_list_in_parens_opt |
| : '(' property_port_list ')' |
| { $$ = MakeParenGroup($1, $2, $3); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| property_port_list |
| : property_port_list ',' property_port_item |
| { $$ = ExtendNode($1, $2, $3); } |
| | property_port_item |
| { $$ = MakeTaggedNode(N::kPropertyPortList, $1); } |
| ; |
| property_port_item |
| : /* attribute_list_opt */ |
| property_port_modifiers_opt |
| property_formal_type_followed_by_id |
| /* equivalent to: property_formal_type GenericIdentifier, |
| * but written as such to allow for implicit types without conflict. |
| */ |
| decl_dimensions_opt |
| property_actual_arg_opt |
| /* $3 is not limited to being an unpacked dimension */ |
| { $$ = MakeTaggedNode(N::kPropertyPortItem, $1, $2, $3, $4); } |
| ; |
| property_port_modifiers_opt |
| : TK_local TK_input |
| { $$ = MakeTaggedNode(N::kPropertyPortModifierList, $1, $2); } |
| | TK_local |
| { $$ = MakeTaggedNode(N::kPropertyPortModifierList, $1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| property_formal_type_followed_by_id |
| /* similar to sequence_port_type_followed_by_id */ |
| : data_type_or_implicit_basic_followed_by_id |
| { $$ = move($1); } |
| | TK_sequence GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, $1, $2); } |
| | TK_untyped GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, $1, $2); } |
| | TK_property GenericIdentifier |
| { $$ = MakeTaggedNode(N::kDataTypeImplicitBasicId, $1, $2); } |
| ; |
| property_actual_arg_opt |
| : '=' property_actual_arg |
| { $$ = MakeTaggedNode(N::kTrailingAssign, $1, $2); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| assertion_variable_declaration_list |
| : assertion_variable_declaration_list ';' assertion_variable_declaration |
| { $$ = ExtendNode($1, $2, $3); } |
| | assertion_variable_declaration |
| { $$ = MakeTaggedNode(N::kAssertionVariableDeclarationList, $1); } |
| ; |
| assertion_variable_declaration |
| : var_opt data_type_or_implicit_basic_followed_by_id_and_dimensions_opt |
| trailing_assign_opt |
| { $$ = MakeTaggedNode(N::kAssertionVariableDeclaration, $1, $2, $3); } |
| | var_opt data_type_or_implicit_basic_followed_by_id_and_dimensions_opt |
| trailing_assign_opt ',' net_variable_or_decl_assigns |
| { $$ = MakeTaggedNode(N::kAssertionVariableDeclaration, $1, $2, $3, $4, $5); } |
| // TODO(fangism): re-pack $3 |
| ; |
| |
| property_actual_arg |
| /* Both event_expression and sequence_expr cover plain expression, so |
| * to avoid conflict, we expand event_expression without the lone expression rule. |
| */ |
| : edge_operator expression |
| { $$ = MakeTaggedNode(N::kPropertyActualArg, $1, $2); } |
| /* from event_expression */ |
| | property_expr |
| { $$ = MakeTaggedNode(N::kPropertyActualArg, $1); } |
| ; |
| |
| |
| /* sequence expression operator precedence (high-to-low): |
| * repetition [*] [=] [->] |
| * delay ## |
| * throughout |
| * within |
| * intersect |
| * and |
| * or |
| * |
| * property expression operator precedence (high-to-low): |
| * not |
| * and |
| * or |
| * if-else |
| * |-> |=> (implication) |
| */ |
| /* |
| * The language spec contains rules (same with TK_or): |
| * property_expr : property_expr TK_and property_expr |
| * property_expr : sequence_expr |
| * sequence_expr : sequence_expr TK_and_sequence_expr |
| * Thus, without context, property_expr and sequence_expr become entangled. |
| */ |
| property_expr |
| : sequence_expr |
| { $$ = move($1); } |
| ; |
| sequence_expr |
| /* merged with property_expr */ |
| : property_implication_expr |
| { $$ = move($1); } |
| ; |
| |
| property_prefix_expr |
| // TODO(fangism): distinguish different property_prefix_exprs |
| : TK_accept_on '(' expression_or_dist ')' property_prefix_expr |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, MakeParenGroup($2, $3, $4), $5); } |
| | TK_reject_on '(' expression_or_dist ')' property_prefix_expr |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, MakeParenGroup($2, $3, $4), $5); } |
| | TK_sync_accept_on '(' expression_or_dist ')' property_prefix_expr |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, MakeParenGroup($2, $3, $4), $5); } |
| | TK_sync_reject_on '(' expression_or_dist ')' property_prefix_expr |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, MakeParenGroup($2, $3, $4), $5); } |
| |
| /* TODO(fangism): |
| // like sequence_instance, this looks like a function/subroutine call. |
| | property_instance |
| */ |
| /* temporal_property_expr: */ |
| | TK_nexttime property_prefix_expr |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, nullptr, $2); } |
| | TK_nexttime '[' expression ']' property_prefix_expr |
| /* $3 is a constant_expression */ |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, |
| MakeTaggedNode(N::kPropertyExpressionIndex, $2, $3, $4), |
| $5); } |
| | TK_s_nexttime property_prefix_expr |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, nullptr, $2); } |
| | TK_s_nexttime '[' expression ']' property_prefix_expr |
| /* $3 is a constant_expression */ |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, |
| MakeTaggedNode(N::kPropertyExpressionIndex, $2, $3, $4), |
| $5); } |
| | TK_always property_prefix_expr |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, nullptr, $2); } |
| | TK_always '[' cycle_range ']' property_prefix_expr |
| /* $3 is a cycle_delay_const_range_expression */ |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, |
| MakeTaggedNode(N::kCycleDelayConstRange, $2, $3, $4), |
| $5); } |
| | TK_s_always '[' cycle_range ']' property_prefix_expr |
| /* $3 should be a constant_range */ |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, |
| MakeTaggedNode(N::kCycleDelayConstRange, $2, $3, $4), |
| $5); } |
| | TK_s_eventually property_prefix_expr |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, nullptr, $2); } |
| | TK_eventually '[' cycle_range ']' property_prefix_expr |
| /* $3 should be a constant_range */ |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, |
| MakeTaggedNode(N::kCycleDelayConstRange, $2, $3, $4), |
| $5); } |
| | TK_s_eventually '[' cycle_range ']' property_prefix_expr |
| /* $3 should be a cycle_delay_const_range_expression */ |
| { $$ = MakeTaggedNode(N::kPropertyPrefixExpression, $1, |
| MakeTaggedNode(N::kCycleDelayConstRange, $2, $3, $4), |
| $5); } |
| | property_if_else_expr |
| { $$ = move($1); } |
| ; |
| |
| property_if_else_expr |
| : TK_if '(' expression_or_dist ')' property_prefix_expr |
| TK_else property_prefix_expr |
| { $$ = MakeTaggedNode(N::kPropertyIfElse, $1, |
| MakeParenGroup($2, $3, $4), $5, $6, $7); } |
| | TK_if '(' expression_or_dist ')' property_prefix_expr |
| %prec less_than_TK_else |
| { $$ = MakeTaggedNode(N::kPropertyIfElse, $1, MakeParenGroup($2, $3, $4), $5); } |
| | simple_sequence_expr |
| { $$ = move($1); } |
| ; |
| |
| simple_sequence_expr |
| // TODO: distinguish different sequence expressions' tags |
| /* cannot have trailing if */ |
| : TK_first_match '(' sequence_expr_match_item_list ')' |
| { $$ = MakeTaggedNode(N::kPropertySimpleSequenceExpression, $1, |
| MakeParenGroup($2, $3, $4)); } |
| /* TODO(fangism): Resolve conflict on sequence_instance. |
| * sequence_instance looks like function/subroutine call, |
| * already covered by expression. |
| | sequence_instance sequence_abbrev_opt |
| */ |
| | property_case_statement |
| { $$ = move($1); } |
| | TK_strong '(' sequence_expr ')' |
| { $$ = MakeTaggedNode(N::kPropertySimpleSequenceExpression, $1, |
| MakeParenGroup($2, $3, $4)); } |
| | TK_weak '(' sequence_expr ')' |
| { $$ = MakeTaggedNode(N::kPropertySimpleSequenceExpression, $1, |
| MakeParenGroup($2, $3, $4)); } |
| | sequence_or_expr |
| { $$ = move($1); } |
| ; |
| |
| property_case_statement |
| : TK_case '(' expression_or_dist ')' |
| property_case_item_list optional_semicolon |
| TK_endcase |
| { $$ = MakeTaggedNode(N::kPropertyCaseStatement, $1, MakeParenGroup($2, $3, $4), |
| $5, $6, $7); } |
| ; |
| property_case_item_list |
| : property_case_item_list ';' property_case_item |
| { $$ = ExtendNode($1, $2, $3); } |
| | property_case_item |
| { $$ = MakeTaggedNode(N::kPropertyCaseItemList, $1); } |
| ; |
| /* Language spec allows semicolons to be optional following each property_case_item, |
| * but without a required separator, the grammar becomes unparseable. |
| * We still allow the last semicolon to be optional. |
| */ |
| property_case_item |
| : expression_or_dist_list ':' property_expr |
| { $$ = MakeTaggedNode(N::kPropertyCaseItem, $1, $2, $3); } |
| | TK_default ':' property_expr |
| { $$ = MakeTaggedNode(N::kPropertyDefaultItem, $1, $2, $3); } |
| | TK_default property_expr |
| { $$ = MakeTaggedNode(N::kPropertyDefaultItem, $1, $2); } |
| ; |
| expression_or_dist_list |
| : expression_or_dist_list ',' expression_or_dist |
| { $$ = ExtendNode($1, $2, $3); } |
| | expression_or_dist |
| { $$ = MakeTaggedNode(N::kExpressionDistributionList, $1); } |
| ; |
| |
| property_implication_expr |
| : property_implication_expr property_operator property_prefix_expr |
| { $$ = ExtendNode($1, $2, $3); } |
| | property_prefix_expr |
| { $$ = IsExpression($1) ? move($1) |
| : MakeTaggedNode(N::kPropertyImplicationList, $1); } |
| ; |
| |
| property_operator |
| /* TODO(fangism): order these operators by precedence. */ |
| /* Could not find good reference about precedence of followed-by operators. */ |
| : implication_operator |
| { $$ = move($1); } |
| | until_operator |
| { $$ = move($1); } |
| | followed_by_operator |
| { $$ = move($1); } |
| ; |
| implication_operator |
| : TK_PIPEARROW |
| { $$ = move($1); } |
| | TK_PIPEARROW2 |
| { $$ = move($1); } |
| | TK_implies |
| { $$ = move($1); } |
| | TK_iff |
| { $$ = move($1); } |
| ; |
| until_operator |
| : TK_until |
| { $$ = move($1); } |
| | TK_until_with |
| { $$ = move($1); } |
| | TK_s_until |
| { $$ = move($1); } |
| | TK_s_until_with |
| { $$ = move($1); } |
| ; |
| followed_by_operator |
| : TK_POUNDEQPOUND |
| { $$ = move($1); } |
| | TK_POUNDMINUSPOUND |
| { $$ = move($1); } |
| ; |
| |
| |
| system_tf_call |
| /* This also covers constant_function_subroutine_call. */ |
| : SystemTFIdentifier '(' argument_list_opt ')' |
| { $$ = MakeTaggedNode(N::kSystemTFCall, $1, MakeParenGroup($2, $3, $4)); } |
| | SystemTFIdentifier |
| { $$ = MakeTaggedNode(N::kSystemTFCall, $1); } |
| /* Some system tasks can be 'called' without ()-arguments. */ |
| ; |
| |
| sequence_match_item_list |
| : sequence_match_item_list ',' sequence_match_item |
| { $$ = ExtendNode($1, $2, $3); } |
| | sequence_match_item |
| { $$ = MakeTaggedNode(N::kSequenceMatchItemList, $1); } |
| |
| ; |
| sequence_expr_match_item_list |
| : property_expr ',' sequence_match_item_list |
| { $$ = MakeTaggedNode(N::kSequenceMatchItemList, $1, $2, |
| ForwardChildren($3)); } |
| | property_expr |
| { $$ = MakeTaggedNode(N::kSequenceMatchItemList, $1); } |
| ; |
| sequence_match_item |
| : assignment_statement |
| { $$ = move($1); } |
| | subroutine_call |
| { $$ = move($1); } |
| ; |
| subroutine_call |
| : reference_or_call |
| { $$ = move($1); } |
| | system_tf_call |
| { $$ = move($1); } |
| ; |
| |
| // TODO(jeremycs): unclear if flattening is correct approach here |
| sequence_or_expr |
| : sequence_or_expr TK_or sequence_and_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | sequence_and_expr |
| { $$ = IsExpression($1) ? move($1) : move($1); } |
| ; |
| sequence_and_expr |
| : sequence_and_expr TK_and sequence_unary_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| | sequence_unary_expr |
| { $$ = IsExpression($1) ? move($1) : move($1); } |
| sequence_unary_expr |
| : sequence_intersect_expr |
| { $$ = IsExpression($1) ? move($1) : move($1); } |
| | TK_not sequence_intersect_expr |
| { $$ = MakeTaggedNode(N::kUnaryPrefixExpression, $1, $2); } |
| /* only for property_expr */ |
| ; |
| sequence_intersect_expr |
| : sequence_within_expr |
| { $$ = IsExpression($1) ? move($1) : move($1); } |
| | sequence_intersect_expr TK_intersect sequence_within_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| sequence_within_expr |
| : sequence_throughout_expr |
| { $$ = IsExpression($1) ? move($1) : move($1); } |
| | sequence_within_expr TK_within sequence_throughout_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| sequence_throughout_expr |
| : sequence_delay_range_expr |
| { $$ = IsExpression($1) ? move($1) : move($1); } |
| | sequence_throughout_expr TK_throughout sequence_delay_range_expr |
| { $$ = MakeBinaryExpression($1, $2, $3); } |
| ; |
| |
| sequence_delay_range_expr |
| : sequence_delay_repetition_list |
| { $$ = IsExpression($1) ? move($1) : move($1); } |
| | cycle_delay_range sequence_delay_repetition_list |
| { $$ = MakeTaggedNode(N::kSequenceDelayRange, $1, $2); } |
| ; |
| sequence_delay_repetition_list |
| : sequence_delay_repetition_list cycle_delay_range sequence_expr_primary |
| { $$ = MakeTaggedNode(N::kSequenceDelayRepetition, $1, $2, $3); } |
| | sequence_expr_primary |
| { $$ = IsExpression($1) ? move($1) : move($1); } |
| ; |
| |
| cycle_delay |
| : TK_POUNDPOUND TK_DecNumber |
| { $$ = MakeTaggedNode(N::kCycleDelay, $1, $2); } |
| | TK_POUNDPOUND GenericIdentifier |
| { $$ = MakeTaggedNode(N::kCycleDelay, $1, $2); } |
| | TK_POUNDPOUND '(' expression ')' |
| { $$ = MakeTaggedNode(N::kCycleDelay, $1, MakeParenGroup($2, $3, $4)); } |
| ; |
| |
| cycle_delay_range |
| : TK_POUNDPOUND '[' cycle_range ']' |
| { $$ = MakeTaggedNode(N::kCycleDelayRange, $1, MakeBracketGroup($2, $3, $4)); } |
| | TK_POUNDPOUND TK_LBSTARRB |
| { $$ = MakeTaggedNode(N::kCycleDelayRange, $1, $2); } |
| /* but not lb_star_rb */ |
| | TK_POUNDPOUND TK_LBPLUSRB |
| { $$ = MakeTaggedNode(N::kCycleDelayRange, $1, $2); } |
| | TK_POUNDPOUND '(' expression ')' |
| { $$ = MakeTaggedNode(N::kCycleDelayRange, $1, MakeParenGroup($2, $3, $4)); } |
| /* $2 expression should be constant. */ |
| | TK_POUNDPOUND GenericIdentifier |
| { $$ = MakeTaggedNode(N::kCycleDelayRange, $1, $2); } |
| | TK_POUNDPOUND TK_DecNumber |
| { $$ = MakeTaggedNode(N::kCycleDelayRange, $1, $2); } |
| ; |
| cycle_range_or_expr |
| /* this covers repeat_range */ |
| : cycle_range |
| { $$ = move($1); } |
| | expression |
| { $$ = move($1); } |
| ; |
| cycle_range |
| /* For constant expressions, $3 can be '$'. */ |
| : expression ':' expression |
| { $$ = MakeTaggedNode(N::kCycleRange, $1, $2, $3); } |
| ; |
| dist_opt |
| : TK_dist '{' dist_list '}' |
| { $$ = MakeTaggedNode(N::kDistribution, expression_placeholder, |
| $1, MakeBraceGroup($2, $3, $4)); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| dist_list |
| : dist_item |
| { $$ = MakeTaggedNode(N::kDistributionItemList, $1); } |
| | dist_list ',' dist_item |
| { $$ = ExtendNode($1, $2, $3); } |
| ; |
| dist_item |
| : value_range dist_weight |
| { $$ = MakeTaggedNode(N::kDistributionItem, $1, ForwardChildren($2)); } |
| | value_range |
| { $$ = MakeTaggedNode(N::kDistributionItem, $1, nullptr, nullptr); } |
| ; |
| dist_weight |
| : TK_COLON_EQ expression |
| { $$ = MakeNode($1, $2); } |
| | TK_COLON_DIV expression |
| { $$ = MakeNode($1, $2); } |
| ; |
| /** |
| sequence_instance |
| // looks like a function call |
| : reference_or_call |
| ; |
| sequence_arguments_list_opt |
| : '(' sequence_arguments_list ')' |
| | '(' ')' |
| | // empty |
| ; |
| sequence_arguments_list |
| : sequence_arguments_list ',' sequence_actual_arg_any |
| | sequence_actual_arg_any |
| ; |
| // TODO(fangism): Positional arguments must appear before named arguments. |
| sequence_actual_arg_any |
| : sequence_actual_arg |
| // positional argument |
| | '.' member_name '(' sequence_actual_arg ')' |
| // named argument |
| ; |
| sequence_actual_arg |
| // identical to property_actual_arg |
| : event_expression |
| | sequence_expr |
| ; |
| **/ |
| |
| sequence_expr_primary |
| // TODO(fangism): Combine these into a single conflict-free ruleset. |
| : sequence_repetition_expr |
| { $$ = move($1); } |
| /* |
| | sequence_expr_match_primary |
| * is now 'covered' by sequence_repetition_expr, see explanation under |
| * the sequence_repetition_expr nonterminal. |
| */ |
| ; |
| /* |
| sequence_expr_match_primary |
| : '(' sequence_expr_match_item_list ')' sequence_abbrev_opt |
| ; |
| */ |
| sequence_repetition_expr |
| /* Highest precedence sequence_expr. */ |
| : expression_or_dist boolean_abbrev_opt |
| { $$ = ($2 == nullptr) ? move($1) : |
| MakeTaggedNode(N::kSequenceRepetitionExpression, |
| $1, $2); } |
| /* This covers a simple expression. |
| * |
| * More importantly, this also covers sequence_expr_match_primary without conflict: |
| * expression_or_dist :: expr_primary_parens :: '(' expr_mintypmax ')' |
| * :: '(' sequence_expr_match_item_list ')' |
| * expr_mintypmax :: property_expr_or_assignment_list |
| * property_expr_or_assignment :: property_expr (start of sequence_expr_match_item_list) |
| * :: subroutine_call (of sequence_match_item) |
| * property_expr_or_assignment :: sequence_match_item :: assignment_statement |
| * boolean_abbrev_opt :: sequence_abbrev_opt |
| */ |
| ; |
| expression_or_dist |
| : expression dist_opt |
| { |
| // If dist_opt is nullptr, then we can just forward expression |
| // without introducing another layer |
| if ($2 == nullptr) { |
| $$ = move($1); |
| } else { |
| SetChild($2, 0, $1); |
| $$ = move($2); |
| } |
| } |
| ; |
| |
| /* covered by boolean_abbrev_opt |
| sequence_abbrev_opt |
| : consecutive_repetition |
| | // empty |
| ; |
| */ |
| boolean_abbrev_opt |
| /* This covers repeat_range_opt. */ |
| : boolean_abbrev |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| boolean_abbrev |
| /* similar to repeat_range */ |
| : consecutive_repetition |
| { $$ = move($1); } |
| | nonconsecutive_repetition |
| { $$ = move($1); } |
| | goto_repetition |
| { $$ = move($1); } |
| ; |
| consecutive_repetition |
| : TK_LBSTAR cycle_range_or_expr ']' |
| { $$ = MakeTaggedNode(N::kConsecutiveRepetition, $1, $2, $3); } |
| | TK_LBSTARRB |
| { $$ = MakeTaggedNode(N::kConsecutiveRepetition, $1); } |
| /* but not lb_star_rb */ |
| | TK_LBPLUSRB |
| { $$ = MakeTaggedNode(N::kConsecutiveRepetition, $1); } |
| ; |
| nonconsecutive_repetition |
| : TK_LBEQ cycle_range_or_expr ']' |
| { $$ = MakeTaggedNode(N::kNonconsecutiveRepetition, $1, $2, $3); } |
| ; |
| goto_repetition |
| : TK_LBRARROW cycle_range_or_expr ']' |
| { $$ = MakeTaggedNode(N::kGotoRepetition, $1, $2, $3); } |
| ; |
| |
| covergroup_declaration |
| : TK_covergroup GenericIdentifier tf_port_list_paren_opt coverage_event_opt ';' |
| coverage_spec_or_option_list_opt |
| TK_endgroup label_opt |
| { $$ = MakeTaggedNode(N::kCovergroupDeclaration, |
| MakeTaggedNode(N::kCovergroupHeader, |
| $1, $2, $3, $4, $5), |
| $6, $7, $8); } |
| ; |
| |
| coverage_spec_or_option_list_opt |
| : coverage_spec_or_option_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| coverage_spec_or_option_list |
| : coverage_spec_or_option_list coverage_spec_or_option |
| { $$ = ExtendNode($1, $2); } |
| | coverage_spec_or_option |
| { $$ = MakeTaggedNode(N::kCoverageSpecOptionList, $1); } |
| ; |
| coverage_spec_or_option |
| : /* attribute_list_opt */ coverage_spec /* no ';' here */ |
| { $$ = move($1); } |
| | /* attribute_list_opt */ coverage_option ';' |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_directive |
| { $$ = move($1); } |
| | macro_call_or_item |
| { $$ = move($1); } |
| ; |
| coverage_option |
| : TK_option '.' GenericIdentifier '=' expression |
| { $$ = MakeTaggedNode(N::kCoverageOption, $1, $2, $3, $4, $5); } |
| | TK_type_option '.' GenericIdentifier '=' expression |
| { $$ = MakeTaggedNode(N::kCoverageOption, $1, $2, $3, $4, $5); } |
| ; |
| coverage_spec |
| : cover_point |
| { $$ = move($1); } |
| /* already ends with '}' or ';' */ |
| | cover_cross |
| { $$ = move($1); } |
| /* already ends with '}' or ';' */ |
| ; |
| coverage_event_opt |
| : coverage_event |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| coverage_event |
| : event_control |
| { $$ = move($1); } |
| | TK_with__covergroup TK_function TK_sample '(' tf_port_list_opt ')' |
| { $$ = MakeTaggedNode(N::kCoverageEvent, $1, $2, $3, MakeParenGroup($4, $5, $6)); } |
| | TK_ATAT '(' block_event_expression ')' |
| { $$ = MakeTaggedNode(N::kCoverageEvent, $1 , MakeParenGroup($2, $3, $4)); } |
| ; |
| block_event_expression |
| : block_event_or_expr |
| { $$ = move($1); } |
| ; |
| block_event_or_expr |
| : block_event_or_expr TK_or block_event_expr_primary |
| { $$ = ExtendNode($1, $2, $3); } |
| | block_event_expr_primary |
| { $$ = MakeTaggedNode(N::kCoverageBlockEventOrList, $1); } |
| ; |
| block_event_expr_primary |
| : TK_begin reference |
| { $$ = MakeTaggedNode(N::kCoverageBlockEventExpression, $1, $2); } |
| | TK_end reference |
| { $$ = MakeTaggedNode(N::kCoverageBlockEventExpression, $1, $2); } |
| ; |
| |
| cover_cross |
| /* optional leading label is painful to disambiguate */ |
| : data_type_or_implicit_basic_followed_by_id ':' |
| TK_cross cross_item_list iff_expr_opt cross_body |
| { $$ = MakeTaggedNode(N::kCoverCross, $1, $2, $3, $4, $5, $6); } |
| /* $1 should be GenericIdentifier, make sure it has nothing else. |
| * promoted as such to ease S/R conflict resolution. |
| */ |
| | TK_cross cross_item_list iff_expr_opt cross_body |
| { $$ = MakeTaggedNode(N::kCoverCross, $1, $2, $3, $4); } |
| ; |
| cross_body |
| : '{' cross_body_item_list_opt '}' |
| { $$ = MakeBraceGroup($1, $2, $3); } |
| | ';' |
| { $$ = move($1); } |
| ; |
| cross_body_item_list_opt |
| : cross_body_item_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| cross_body_item_list |
| : cross_body_item_list cross_body_item |
| { $$ = ExtendNode($1, $2); } |
| | cross_body_item |
| { $$ = MakeTaggedNode(N::kCrossBodyItemList, $1); } |
| ; |
| cross_item_list |
| : cross_item_list ',' cross_item |
| { $$ = ExtendNode($1, $2, $3); } |
| | cross_item ',' cross_item |
| { $$ = MakeTaggedNode(N::kCrossItemList, $1, $2, $3); } |
| /* cross_item_list must contain 2 or more items. */ |
| ; |
| cross_body_item |
| : function_declaration |
| { $$ = move($1); } |
| | /* attribute_list_opt */ bins_selection ';' |
| { $$ = ExtendNode($1, $2); } |
| | /* attribute_list_opt */ coverage_option ';' |
| { $$ = ExtendNode($1, $2); } |
| ; |
| cross_item |
| : reference |
| { $$ = move($1); } |
| /* refers to a cover_point_identifier or variable_identifier */ |
| /* NOTE: The LRM only allows a simple GenericIdentifier here, |
| * so a general hierarchical reference may be a vendor extension. |
| */ |
| ; |
| cover_point |
| : data_type_or_implicit_basic_followed_by_id ':' TK_coverpoint |
| /* $1 is optional label (GenericIdentifier) */ |
| property_expr |
| /* expression iff_expr_opt (covered by property_expr) */ |
| bins_or_options_list_opt |
| { $$ = MakeTaggedNode(N::kCoverPoint, $1, $2, $3, $4, $5); } |
| /* must end with '}' or ';' */ |
| | TK_coverpoint |
| property_expr |
| /* expression iff_expr_opt (covered by property_expr) */ |
| bins_or_options_list_opt |
| { $$ = MakeTaggedNode(N::kCoverPoint, nullptr, nullptr, $1, $2, $3); } |
| ; |
| iff_expr_opt |
| : TK_iff '(' expression ')' |
| { $$ = MakeTaggedNode(N::kIffExpression, $1, MakeParenGroup($2, $3, $4)); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| bins_or_options_list_opt |
| : '{' bins_or_options_list '}' |
| { $$ = MakeBraceGroup($1, $2, $3); } |
| |
| /* Some copies of EBNF spec (sigasi.com) misprints non-literal braces. |
| * Code samples confirm that these are in fact required literal braces. |
| */ |
| | ';' |
| { $$ = move($1); } |
| ; |
| bins_or_options_list |
| : bins_or_options_list bins_or_options |
| { $$ = ExtendNode($1, $2); } |
| | bins_or_options |
| { $$ = MakeTaggedNode(N::kBinOptionList, $1); } |
| ; |
| bins_or_options |
| : /* attribute_list_opt */ coverage_option ';' |
| { $$ = ExtendNode($1, $2); } |
| | /* attribute_list_opt */ coverage_bin ';' |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_balanced_bins_or_options_list |
| { $$ = move($1); } |
| | macro_call_or_item |
| { $$ = move($1); } |
| ; |
| |
| bins_or_options_list_opt_pp |
| : bins_or_options_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_balanced_bins_or_options_list |
| : preprocessor_if_header bins_or_options_list_opt_pp |
| preprocessor_elsif_bins_or_options_list_opt |
| preprocessor_else_bins_or_options_opt |
| PP_endif |
| { $$ = MakeTaggedNode(N::kPreprocessorBalancedBinsOrOptions, |
| ExtendNode($1, $2), ForwardChildren($3), $4, $5); |
| } |
| ; |
| preprocessor_elsif_bins_or_options_list_opt |
| : preprocessor_elsif_bins_or_options_list |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_elsif_bins_or_options_list |
| : preprocessor_elsif_bins_or_options_list preprocessor_elsif_bins_or_options |
| { $$ = ExtendNode($1, $2); } |
| | preprocessor_elsif_bins_or_options |
| { $$ = MakeNode($1); } /* Don't bother tagging; node will be flattened. */ |
| ; |
| preprocessor_elsif_bins_or_options |
| : preprocessor_elsif_header bins_or_options_list_opt_pp |
| { $$ = ExtendNode($1, $2); } |
| ; |
| preprocessor_else_bins_or_options_opt |
| : preprocessor_else_bins_or_options |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| preprocessor_else_bins_or_options |
| : PP_else bins_or_options_list_opt_pp |
| { $$ = MakeTaggedNode(N::kPreprocessorElseClause, $1, $2); } |
| ; |
| |
| coverage_bin |
| /* This is a simplified approximation that may permit some illegal combinations. */ |
| : wildcard_opt bins_keyword GenericIdentifier covergroup_expression_bracketed_opt '=' |
| coverage_bin_rhs iff_expr_opt |
| { $$ = MakeTaggedNode(N::kCoverageBin, $1, $2, $3, $4, $5, $6, $7); } |
| ; |
| coverage_bin_rhs |
| : set_covergroup_expression_or_covergroup_range_list_or_trans_list |
| { $$ = move($1); } |
| | TK_default |
| { $$ = move($1); } |
| | TK_default TK_sequence |
| { $$ = MakeNode($1, $2); } |
| ; |
| wildcard_opt |
| : TK_wildcard |
| { $$ = move($1); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| bins_keyword |
| : TK_bins |
| { $$ = move($1); } |
| | TK_illegal_bins |
| { $$ = move($1); } |
| | TK_ignore_bins |
| { $$ = move($1); } |
| ; |
| covergroup_expression_bracketed_opt |
| : '[' expression ']' |
| { $$ = MakeBracketGroup($1, $2, $3); } |
| | '[' ']' |
| { $$ = MakeBracketGroup($1, nullptr, $2); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| set_covergroup_expression_or_covergroup_range_list_or_trans_list |
| /* This has been grouped together in a permissive manner to mitigate conflicts. */ |
| : expression_list_proper /* comma-separated list of expressions */ |
| { $$ = move($1); } |
| /* set_covergroup_expression is covergroup_expression is expression. |
| * |
| * covers cover_point_identifier with: |
| * expression_list_proper :: expression :: GenericIdentifier |
| * |
| * covers '{' covergroup_range_list '}', which is '{' open_range_list '}': |
| * expression_list_proper :: expression :: expr_primary_braces |
| * :: '{' open_range_list '}' |
| * |
| * covers trans_list (commented below): |
| * expression_list_proper :: trans_list |
| * trans_item :: expression :: expr_primary_parens :: '(' expr_mintypmax ')' |
| * expr_mintypmax :: expr_mintypmax_trans_set :: expr_mintypmax_generalized |
| * open_range_list :: value_range |
| | trans_list |
| */ |
| ; |
| /** retained for reference |
| trans_list |
| : trans_list ',' trans_item |
| | trans_item |
| ; |
| trans_item |
| : '(' trans_set ')' |
| ; |
| trans_set |
| : trans_set TK_EG trans_range_list |
| | trans_range_list |
| ; |
| trans_range_list |
| : open_range_list repeat_range_opt |
| // $1 same as covergroup_range_list |
| ; |
| repeat_range_opt |
| // covered by to boolean_abbrev_opt |
| // repeat_range is covered by cycle_range_or_expr |
| : TK_LBSTAR cycle_range_or_expr ']' |
| | TK_LBRARROW cycle_range_or_expr ']' |
| | TK_LBEQ cycle_range_or_expr ']' |
| | // empty |
| ; |
| repeat_range |
| : value_range |
| ; |
| */ |
| bins_selection |
| : bins_keyword GenericIdentifier '=' select_expression /* iff_expr_opt */ |
| { $$ = MakeTaggedNode(N::kBinsSelection, $1, $2, $3, $4); } |
| /* select_expression as property_expr covers trailing iff_expr_opt */ |
| ; |
| select_expression |
| : property_expr |
| { $$ = move($1); } |
| /* from EBNF: |
| : select_condition |
| | ! select_condition |
| | select_expression && select_expression |
| | select_expression || select_expression |
| | ( select_expression ) |
| | select_expression with ( with_covergroup_expression ) [ matches integer_covergroup_expression ] |
| | cross_identifier |
| | cross_set_expression [ matches integer_covergroup_expression ] |
| */ |
| ; |
| |
| select_condition |
| /* primary select expression */ |
| : TK_binsof '(' bins_expression ')' |
| { $$ = MakeTaggedNode(N::kSelectCondition, $1, MakeParenGroup($2, $3, $4)); } |
| /* optional trailing TK_intersect range_list_in_braces is covered by |
| * select_expression using property_expr, which contains the |
| * TK_intersect operator. |
| | TK_binsof '(' bins_expression ')' TK_intersect range_list_in_braces |
| * where range_list_in_braces covers covergroup_range_list. |
| */ |
| ; |
| bins_expression |
| : reference |
| { $$ = move($1); } |
| ; |
| with_covergroup_expression_in_parens |
| : TK_with__covergroup '(' with_covergroup_expression ')' |
| // TODO(fangism): optionally trailing 'matches': |
| // TK_matches integer_covergroup_expression |
| ; |
| with_covergroup_expression |
| : expression |
| ; |
| /* |
| integer_covergroup_expression |
| : expression |
| ; |
| cross_set_expression |
| : expression |
| ; |
| */ |
| |
| /******** LRM: A.6.12 randsequence ********/ |
| randsequence_statement |
| : TK_randsequence '(' identifier_opt ')' production_list TK_endsequence |
| { $$ = MakeTaggedNode(N::kRandSequenceStatement, |
| $1, MakeParenGroup($2, $3, $4), $5, $6); } |
| ; |
| |
| production_list |
| : production_list production |
| { $$ = ExtendNode($1, $2); } |
| | production |
| { $$ = MakeTaggedNode(N::kProductionList, $1); } |
| ; |
| |
| production |
| : data_type_or_void_with_id tf_port_list_paren_opt ':' rs_rule_list ';' |
| { $$ = MakeTaggedNode(N::kProduction, $1, $2, $3, $4, $5); } |
| ; |
| |
| data_type_or_void_with_id |
| : data_type_or_implicit_basic_followed_by_id_and_dimensions_opt |
| /* simplify: this is too general, no need for dimensions */ |
| { $$ = move($1); } |
| ; |
| |
| rs_rule_list |
| : rs_rule_list '|' rs_rule |
| { $$ = ExtendNode($1, $2, $3); } |
| | rs_rule |
| { $$ = MakeTaggedNode(N::kRandSequenceRuleList, $1); } |
| ; |
| |
| rs_rule |
| : rs_production_list_or_rand_join |
| { $$ = MakeTaggedNode(N::kRandSequenceRule, $1); } |
| | rs_production_list_or_rand_join TK_COLON_EQ weight_specification |
| { $$ = MakeTaggedNode(N::kRandSequenceRule, $1, $2, $3); } |
| | rs_production_list_or_rand_join TK_COLON_EQ weight_specification rs_code_block |
| { $$ = MakeTaggedNode(N::kRandSequenceRule, $1, $2, $3, $4); } |
| ; |
| |
| rs_production_list_or_rand_join |
| : rs_production_list |
| { $$ = move($1); } |
| | TK_rand TK_join expression_in_parens_opt production_items_list |
| { $$ = MakeTaggedNode(N::kRandJoin, $1, $2, $3, $4); } |
| ; |
| |
| expression_in_parens_opt |
| : '(' expression ')' |
| { $$ = MakeParenGroup($1, $2, $3); } |
| | /* empty */ |
| { $$ = nullptr; } |
| ; |
| |
| rs_production_list |
| : rs_production_list rs_prod |
| { $$ = ExtendNode($1, $2); } |
| | rs_prod |
| { $$ = MakeTaggedNode(N::kRandSequenceProductionList, $1); } |
| ; |
| |
| weight_specification |
| : number |
| /* $1 must be integral */ |
| { $$ = MakeTaggedNode(N::kWeightSpecification, $1); } |
| | GenericIdentifier |
| { $$ = MakeTaggedNode(N::kWeightSpecification, $1); } |
| | '(' expression ')' |
| { $$ = MakeTaggedNode(N::kWeightSpecification, $1, $2, $3); } |
| ; |
| |
| rs_code_block |
| : '{' block_item_or_statement_or_null_list_opt '}' |
| /* block_item_decls_opt statement_or_null_list_opt */ |
| { $$ = MakeBraceGroup($1, $2, $3); } |
| ; |
| |
| production_items_list |
| : production_items_list production_item |
| { $$ = ExtendNode($1, $2); } |
| | production_item production_item |
| /* at least two elements required */ |
| { $$ = MakeTaggedNode(N::kProductionItemsList, $1, $2); } |
| ; |
| |
| rs_prod |
| : production_item |
| { $$ = move($1); } |
| | rs_code_block |
| { $$ = move($1); } |
| | rs_if_else |
| { $$ = move($1); } |
| | rs_repeat |
| { $$ = move($1); } |
| | rs_case |
| { $$ = move($1); } |
| ; |
| |
| production_item |
| : GenericIdentifier '(' any_port_list ')' |
| { $$ = MakeTaggedNode(N::kProductionItem, $1, MakeParenGroup($2, $3, $4)); } |
| | GenericIdentifier |
| { $$ = MakeTaggedNode(N::kProductionItem, $1); } |
| ; |
| |
| rs_if_else |
| : TK_if '(' expression ')' production_item TK_else production_item |
| { $$ = MakeTaggedNode(N::kRandSequenceConditional, |
| $1, MakeParenGroup($2, $3, $4), $5, $6, $7); } |
| | TK_if '(' expression ')' production_item |
| { $$ = MakeTaggedNode(N::kRandSequenceConditional, |
| $1, MakeParenGroup($2, $3, $4), $5); } |
| ; |
| |
| rs_repeat |
| : repeat_control production_item |
| { $$ = MakeTaggedNode(N::kRandSequenceLoop, $1, $2); } |
| ; |
| |
| rs_case |
| : TK_case '(' expression ')' rs_case_item_list TK_endcase |
| { $$ = MakeTaggedNode(N::kRandSequenceCase, |
| $1, MakeParenGroup($2, $3, $4), $5, $6); } |
| ; |
| |
| rs_case_item_list |
| : rs_case_item_list rs_case_item |
| { $$ = ExtendNode($1, $2); } |
| | rs_case_item |
| { $$ = MakeTaggedNode(N::kRandSequenceCaseItemList, $1); } |
| ; |
| |
| rs_case_item |
| : case_item_expression_list ':' production_item ';' |
| { $$ = MakeTaggedNode(N::kRandSequenceCaseItem, $1, $2, $3, $4); } |
| | TK_default ':' production_item ';' |
| { $$ = MakeTaggedNode(N::kRandSequenceDefaultItem, $1, $2, $3, $4); } |
| | TK_default production_item ';' |
| { $$ = MakeTaggedNode(N::kRandSequenceDefaultItem, $1, nullptr, $2, $3); } |
| ; |
| |
| case_item_expression_list |
| : case_item_expression_list ',' case_item_expression |
| { $$ = ExtendNode($1, $2, $3); } |
| | case_item_expression |
| { $$ = MakeTaggedNode(N::kExpressionList, $1); } |
| ; |
| |
| case_item_expression |
| : expression |
| { $$ = move($1); } |
| ; |
| |
| %% |
| |
| // Ensure type consistency with StateStack in parser_param.h |
| static_assert(std::is_same<yytype_int16, verible::bison_state_int_type>::value, |
| "Update bison_state_int_type in parser_param.h to match yy.tab.cc."); |
| |
| // Expose the token names for diagnostic messages. |
| const char* verilog_symbol_name(size_t symbol_enum) { |
| // This (static) table contains YYNTOKENS token names, |
| // followed by YYNNTS nonterminal symbol names. |
| const int yytoken = YYTRANSLATE(symbol_enum); |
| CHECK(yytoken <= YYNTOKENS + YYNNTS); |
| return yytname[yytoken]; |
| } |
| |
| } // namespace verilog |