// -*- C++ -*- //************************************************************************* // DESCRIPTION: Verilog-Perl bison parser // // This file is part of Verilog-Perl. // // Author: Wilson Snyder // // Code available from: http://www.veripool.org/systemperl // //************************************************************************* // // Copyright 2001-2019 by Wilson Snyder. This program is free software; // you can redistribute it and/or modify it under the terms of either the GNU // Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //************************************************************************* %{ #include #include #include #include #include #include #include #include #include #include #include #include "VParse.h" #include "VParseGrammar.h" #define YYERROR_VERBOSE 1 #define YYINITDEPTH 5000 // Large as the stack won't grow, since YYSTYPE_IS_TRIVIAL isn't defined #define YYMAXDEPTH 5000 // See VParseGrammar.h for the C++ interface to this parser // Include that instead of VParseBison.h //************************************************************************* #define GRAMMARP VParseGrammar::staticGrammarp() #define PARSEP VParseGrammar::staticParsep() #define NEWSTRING(text) (string((text))) #define SPACED(a,b) ((a)+(((a)=="" || (b)=="")?"":" ")+(b)) #define VARRESET_LIST(decl) { GRAMMARP->pinNum(1); VARRESET(); VARDECL(decl); } // Start of pinlist #define VARRESET_NONLIST(decl) { GRAMMARP->pinNum(0); VARRESET(); VARDECL(decl); } // Not in a pinlist #define VARRESET() { VARDECL(""); VARIO(""); VARNET(""); VARDTYPE(""); } // Start of one variable decl // VARDECL("") indicates inside a port list or IO list and we shouldn't declare the variable #define VARDECL(type) { GRAMMARP->m_varDecl = (type); } // genvar, parameter, localparam #define VARIO(type) { GRAMMARP->m_varIO = (type); } // input, output, inout, ref, const ref #define VARNET(type) { GRAMMARP->m_varNet = (type); } // supply*,wire,tri #define VARDTYPE(type) { GRAMMARP->m_varDType = (type); } // "signed", "int", etc #define PINNUMINC() { GRAMMARP->pinNumInc(); } #define INSTPREP(cellmod,cellparam,withinInst) { GRAMMARP->pinNum(1); GRAMMARP->m_cellMod=(cellmod); GRAMMARP->m_cellParam=(cellparam); GRAMMARP->m_withinInst = 1; } #define INSTDONE() { GRAMMARP->m_withinInst = 0; } enum net_idx {NI_NETNAME = 0, NI_MSB, NI_LSB}; static void VARDONE(VFileLine* fl, const string& name, const string& array, const string& value) { if (GRAMMARP->m_varIO!="" && GRAMMARP->m_varDecl=="") GRAMMARP->m_varDecl="port"; if (GRAMMARP->m_varDecl!="") { PARSEP->varCb(fl, GRAMMARP->m_varDecl, name, PARSEP->symObjofUpward(), GRAMMARP->m_varNet, GRAMMARP->m_varDType, array, value); } if (GRAMMARP->m_varIO!="" || GRAMMARP->pinNum()) { PARSEP->portCb(fl, name, PARSEP->symObjofUpward(), GRAMMARP->m_varIO, GRAMMARP->m_varDType, array, GRAMMARP->pinNum()); } if (GRAMMARP->m_varDType == "type") { PARSEP->syms().replaceInsert(VAstType::TYPE,name); } } static void VARDONETYPEDEF(VFileLine* fl, const string& name, const string& type, const string& array) { VARRESET(); VARDECL("typedef"); VARDTYPE(type); VARDONE(fl,name,array,""); // TYPE shouldn't override a more specific node type, as often is forward reference PARSEP->syms().replaceInsert(VAstType::TYPE,name); } static void parse_net_constants(VFileLine* fl, VParseHashElem nets[][3]) { VParseHashElem (*net)[3] = &nets[0]; VParseHashElem* nhp = net[0]; std::deque::iterator it = GRAMMARP->m_portStack.begin(); while (it != GRAMMARP->m_portStack.end()) { // Default net name is simply the complete token const char* netnamep = it->m_name.c_str(); size_t delim = it->m_name.find_first_of("'"); if (it->m_name[0] != '\\' && it->m_msb.empty() && delim != string::npos && it->m_name[delim] == '\'') { // Handle sized integer constants (e.g., 7'b0) specifically but ignore replications (e.g., {4{w}}) if (delim != 0 && netnamep[0] != '{') { // Handle the first part that indicates the width for sized constants (guaranteed to be a decimal) char* endp; errno = 0; long l = strtol(netnamep, &endp, 10); if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX || l <= 0) { fl->error((string)"Unexpected length in size of integer constant: \""+netnamep+"\"."); return; } // Skip whitespace while (endp < netnamep + delim && isspace(*endp)) { endp++; } if (endp != netnamep + delim) { fl->error((string)"Could not convert size of integer constant: \""+netnamep+"\"."); return; } int count = l; // Skip characters up to the delimiter ' to determine new netnamep netnamep += delim; // Test for legal base specifiers: // d, D, h, H, o, O , b, or B for the decimal, hexadecimal, octal, and binary bases, respectively char base = netnamep[1]; // 's' indicates a signed constant, is followed by the actual base; currently ignored if (base == 's' || base == 'S') { base = netnamep[2]; } if (strchr("dDhHoObB", base) == NULL) { fl->error((string)"Base specifier \""+base+"\" is not valid in integer constant \""+it->m_name.c_str()+"\"."); return; } // These assignments could be prettified with C++11 nhp[NI_MSB].keyp = "msb"; nhp[NI_MSB].val_type = VParseHashElem::ELEM_INT; nhp[NI_MSB].val_int = count - 1; nhp[NI_LSB].keyp = "lsb"; nhp[NI_LSB].val_type = VParseHashElem::ELEM_INT; nhp[NI_LSB].val_int = 0; } else { // fl->error increases the error count which would create regressions for no good reasons. // There is no ->warn or similar though but we could print, e.g., to stderr in these cases //fl->error((string)"Neither unsized integer constant nor replications are not fully supported in nets (\""+netnamep+"\")."); //fprintf(stderr, "Neither unsized integer constant nor replications are not fully supported in nets (\"%s\").\n", netnamep); } } else { // Ordinary net names might have a range attached or not. // If it does then parse its bounds into proper integers. const char *msbstr = it->m_msb.c_str(); if (msbstr[0] != '\0') { { // Parse NI_MSB char* endp; errno = 0; long l = strtol(msbstr, &endp, 10); // Test for range within int, and proper parsing if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX || l < 0 || (endp && l == 0 && errno == ERANGE)) { fl->error((string)"Unexpected length in msb specification of \""+netnamep+"\" (endp="+endp+", errno="+strerror(errno)+")."); return; } nhp[NI_MSB].keyp = "msb"; nhp[NI_MSB].val_type = VParseHashElem::ELEM_INT; nhp[NI_MSB].val_int = (int)l; } { // Parse NI_LSB char* endp; errno = 0; long l = strtol(it->m_lsb.c_str(), &endp, 10); if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX || l < 0 || (endp && l == 0 && errno == ERANGE)) { fl->error((string)"Unexpected length in lsb specification of \""+netnamep+"\"."); return; } nhp[NI_LSB].keyp = "lsb"; nhp[NI_LSB].val_type = VParseHashElem::ELEM_INT; nhp[NI_LSB].val_int = (int)l; } } else { nhp[NI_MSB].keyp = NULL; nhp[NI_LSB].keyp = NULL; } } nhp[NI_NETNAME].keyp = "netname"; nhp[NI_NETNAME].val_type = VParseHashElem::ELEM_STR; nhp[NI_NETNAME].val_str = netnamep; *it++; nhp += 3; // We operate on three elements in each iteration } } static void PINDONE(VFileLine* fl, const string& name, const string& expr) { if (GRAMMARP->m_cellParam) { // Stack them until we create the instance itself GRAMMARP->m_pinStack.push_back(VParseGPin(fl, name, expr, GRAMMARP->pinNum())); } else { PARSEP->pinCb(fl, name, expr, GRAMMARP->pinNum()); if (PARSEP->usePinSelects()) { if (GRAMMARP->m_portStack.empty()) { string netname; if (GRAMMARP->m_portNextNetName.empty()) { netname = expr; } else { netname = GRAMMARP->m_portNextNetName; } size_t elem_cnt = GRAMMARP->m_portNextNetMsb.empty() ? 1 : 3; VParseHashElem nets[elem_cnt]; // These assignments could be prettified with C++11 nets[NI_NETNAME].keyp = "netname"; nets[NI_NETNAME].val_type = VParseHashElem::ELEM_STR; nets[NI_NETNAME].val_str = netname; if (elem_cnt > 1) { nets[NI_MSB].keyp = "msb"; nets[NI_MSB].val_type = VParseHashElem::ELEM_STR; nets[NI_MSB].val_str = GRAMMARP->m_portNextNetMsb; nets[NI_LSB].keyp = "lsb"; nets[NI_LSB].val_type = VParseHashElem::ELEM_STR; nets[NI_LSB].val_str = GRAMMARP->m_portNextNetLsb; } PARSEP->pinselectsCb(fl, name, 1, elem_cnt, &nets[0], GRAMMARP->pinNum()); } else { // Connection with multiple pins was parsed completely. // There might be one net left in the pipe... if (GRAMMARP->m_portNextNetValid) { GRAMMARP->m_portStack.push_front(VParseNet(GRAMMARP->m_portNextNetName, GRAMMARP->m_portNextNetMsb, GRAMMARP->m_portNextNetLsb)); } unsigned int arraycnt = GRAMMARP->m_portStack.size(); VParseHashElem nets[arraycnt][3]; parse_net_constants(fl, nets); PARSEP->pinselectsCb(fl, name, arraycnt, 3, &nets[0][0], GRAMMARP->pinNum()); } // Clear all pin-related fields GRAMMARP->m_portNextNetValid = false; GRAMMARP->m_portNextNetName.clear(); GRAMMARP->m_portStack.clear(); GRAMMARP->m_portNextNetMsb.clear(); GRAMMARP->m_portNextNetLsb.clear(); } } } static void PINPARAMS() { // Throw out all the "pins" we found before we could do instanceCb while (!GRAMMARP->m_pinStack.empty()) { VParseGPin& pinr = GRAMMARP->m_pinStack.front(); PARSEP->parampinCb(pinr.m_fl, pinr.m_name, pinr.m_conn, pinr.m_number); GRAMMARP->m_pinStack.pop_front(); } GRAMMARP->m_withinPin = true; } static void PORTNET(VFileLine* fl, const string& name) { if (!GRAMMARP->m_withinInst) { return; } GRAMMARP->m_portNextNetValid = true; GRAMMARP->m_portNextNetName = name; GRAMMARP->m_portNextNetMsb.clear(); GRAMMARP->m_portNextNetLsb.clear(); } static void PORTRANGE(const string& msb, const string& lsb) { if (!GRAMMARP->m_withinInst) { return; } GRAMMARP->m_portNextNetMsb = msb; GRAMMARP->m_portNextNetLsb = lsb; } static void PIN_CONCAT_APPEND(const string& expr) { if (!GRAMMARP->m_withinPin) { return; } if (!GRAMMARP->m_portNextNetValid) { // Only while not within a valid net term the expression is part // of a replication constant. If that's detected ignore the // previous expression (that is actually just the contained // concatenation) in favor of the full replication expression. if (expr[0] == '{') { if (expr.find_first_of("{", 1) != string::npos) { // fprintf(stderr, "%d: ignoring \"%s\" in favor of \"%s\".\n", __LINE__, GRAMMARP->m_portStack.front().m_name.c_str(), expr.c_str()); GRAMMARP->m_portStack.pop_front(); GRAMMARP->m_portStack.push_front(VParseNet(expr)); } } else { GRAMMARP->m_portStack.push_front(VParseNet(expr)); } } else { GRAMMARP->m_portStack.push_front(VParseNet(GRAMMARP->m_portNextNetName, GRAMMARP->m_portNextNetMsb, GRAMMARP->m_portNextNetLsb)); } GRAMMARP->m_portNextNetValid = false; } /* Yacc */ static int VParseBisonlex(VParseBisonYYSType* yylvalp) { return PARSEP->lexToBison(yylvalp); } static void VParseBisonerror(const char *s) { VParseGrammar::bisonError(s); } static void ERRSVKWD(VFileLine* fileline, const string& tokname) { static int toldonce = 0; fileline->error((string)"Unexpected \""+tokname+"\": \""+tokname+"\" is a SystemVerilog keyword misused as an identifier."); if (!toldonce++) fileline->error("Modify the Verilog-2001 code to avoid SV keywords, or use `begin_keywords or --language."); } static void NEED_S09(VFileLine*, const string&) { //Let lint tools worry about it //fileline->error((string)"Advanced feature: \""+tokname+"\" is a 1800-2009 construct, but used under --language 1800-2005 or earlier."); } %} BISONPRE_VERSION(0.0, 2.999, %pure_parser) BISONPRE_VERSION(3.0, %pure-parser) BISONPRE_VERSION(0.0, 2.999, %token_table) BISONPRE_VERSION(3.0, %token-table) BISONPRE_VERSION(2.4, 2.999, %define lr.keep_unreachable_states) BISONPRE_VERSION(3.0, %define lr.keep-unreachable-state) // When writing Bison patterns we use yTOKEN instead of "token", // so Bison will error out on unknown "token"s. // Generic lexer tokens, for example a number // IEEE: real_number %token yaFLOATNUM "FLOATING-POINT NUMBER" // IEEE: identifier, class_identifier, class_variable_identifier, // covergroup_variable_identifier, dynamic_array_variable_identifier, // enum_identifier, interface_identifier, interface_instance_identifier, // package_identifier, type_identifier, variable_identifier, %token yaID__ETC "IDENTIFIER" %token yaID__LEX "IDENTIFIER-in-lex" %token yaID__aPACKAGE "PACKAGE-IDENTIFIER" %token yaID__aTYPE "TYPE-IDENTIFIER" // aCOVERGROUP is same as aTYPE // Can't predecode aFUNCTION, can declare after use // Can't predecode aINTERFACE, can declare after use // Can't predecode aTASK, can declare after use // IEEE: integral_number %token yaINTNUM "INTEGER NUMBER" // IEEE: time_literal + time_unit %token yaTIMENUM "TIME NUMBER" // IEEE: string_literal %token yaSTRING "STRING" %token yaSTRING__IGNORE "STRING-ignored" // Used when expr:string not allowed %token yaTIMINGSPEC "TIMING SPEC ELEMENT" %token ygenGATE "GATE keyword" %token ygenCONFIGKEYWORD "CONFIG keyword (cell/use/design/etc)" %token ygenOPERATOR "OPERATOR" %token ygenSTRENGTH "STRENGTH keyword (strong1/etc)" %token ygenSYSCALL "SYSCALL" %token '!' %token '#' %token '%' %token '&' %token '(' %token ')' %token '*' %token '+' %token ',' %token '-' %token '.' %token '/' %token ':' %token ';' %token '<' %token '=' %token '>' %token '?' %token '@' %token '[' %token ']' %token '^' %token '{' %token '|' %token '}' %token '~' // Specific keywords // yKEYWORD means match "keyword" // Other cases are yXX_KEYWORD where XX makes it unique, // for example yP_ for punctuation based operators. // Double underscores "yX__Y" means token X followed by Y, // and "yX__ETC" means X folled by everything but Y(s). %token yACCEPT_ON "accept_on" %token yALIAS "alias" %token yALWAYS "always" %token yAND "and" %token yASSERT "assert" %token yASSIGN "assign" %token yASSUME "assume" %token yAUTOMATIC "automatic" %token yBEFORE "before" %token yBEGIN "begin" %token yBIND "bind" %token yBINS "bins" %token yBINSOF "binsof" %token yBIT "bit" %token yBREAK "break" %token yBUF "buf" %token yBYTE "byte" %token yCASE "case" %token yCASEX "casex" %token yCASEZ "casez" %token yCHANDLE "chandle" %token yCHECKER "checker" %token yCLASS "class" %token yCLOCK "clock" %token yCLOCKING "clocking" %token yCONSTRAINT "constraint" %token yCONST__ETC "const" %token yCONST__LEX "const-in-lex" %token yCONST__LOCAL "const-then-local" %token yCONST__REF "const-then-ref" %token yCONTEXT "context" %token yCONTINUE "continue" %token yCOVER "cover" %token yCOVERGROUP "covergroup" %token yCOVERPOINT "coverpoint" %token yCROSS "cross" %token yDEASSIGN "deassign" %token yDEFAULT "default" %token yDEFPARAM "defparam" %token yDISABLE "disable" %token yDIST "dist" %token yDO "do" %token yEDGE "edge" %token yELSE "else" %token yEND "end" %token yENDCASE "endcase" %token yENDCHECKER "endchecker" %token yENDCLASS "endclass" %token yENDCLOCKING "endclocking" %token yENDFUNCTION "endfunction" %token yENDGENERATE "endgenerate" %token yENDGROUP "endgroup" %token yENDINTERFACE "endinterface" %token yENDMODULE "endmodule" %token yENDPACKAGE "endpackage" %token yENDPROGRAM "endprogram" %token yENDPROPERTY "endproperty" %token yENDSEQUENCE "endsequence" %token yENDSPECIFY "endspecify" %token yENDTABLE "endtable" %token yENDTASK "endtask" %token yENUM "enum" %token yEVENT "event" %token yEVENTUALLY "eventually" %token yEXPECT "expect" %token yEXPORT "export" %token yEXTENDS "extends" %token yEXTERN "extern" %token yFINAL "final" %token yFIRST_MATCH "first_match" %token yFOR "for" %token yFORCE "force" %token yFOREACH "foreach" %token yFOREVER "forever" %token yFORK "fork" %token yFORKJOIN "forkjoin" %token yFUNCTION__ETC "function" %token yFUNCTION__LEX "function-in-lex" %token yFUNCTION__aPUREV "function-is-pure-virtual" %token yGENERATE "generate" %token yGENVAR "genvar" %token yGLOBAL__CLOCKING "global-then-clocking" %token yGLOBAL__LEX "global-in-lex" %token yIF "if" %token yIFF "iff" %token yIGNORE_BINS "ignore_bins" %token yILLEGAL_BINS "illegal_bins" %token yIMPLEMENTS "implements" %token yIMPLIES "implies" %token yIMPORT "import" %token yINITIAL "initial" %token yINOUT "inout" %token yINPUT "input" %token yINSIDE "inside" %token yINT "int" %token yINTEGER "integer" %token yINTERCONNECT "interconnect" %token yINTERFACE "interface" %token yINTERSECT "intersect" %token yJOIN "join" %token yLET "let" %token yLOCALPARAM "localparam" %token yLOCAL__COLONCOLON "local-then-::" %token yLOCAL__ETC "local" %token yLOCAL__LEX "local-in-lex" %token yLOGIC "logic" %token yLONGINT "longint" %token yMATCHES "matches" %token yMODPORT "modport" %token yMODULE "module" %token yNAND "nand" %token yNEGEDGE "negedge" %token yNETTYPE "nettype" %token yNEW__ETC "new" %token yNEW__LEX "new-in-lex" %token yNEW__PAREN "new-then-paren" %token yNEXTTIME "nexttime" %token yNOR "nor" %token yNOT "not" %token yNULL "null" %token yOR "or" %token yOUTPUT "output" %token yPACKAGE "package" %token yPACKED "packed" %token yPARAMETER "parameter" %token yPOSEDGE "posedge" %token yPRIORITY "priority" %token yPROGRAM "program" %token yPROPERTY "property" %token yPROTECTED "protected" %token yPURE "pure" %token yRAND "rand" %token yRANDC "randc" %token yRANDCASE "randcase" %token yRANDSEQUENCE "randsequence" %token yREAL "real" %token yREALTIME "realtime" %token yREF "ref" %token yREG "reg" %token yREJECT_ON "reject_on" %token yRELEASE "release" %token yREPEAT "repeat" %token yRESTRICT "restrict" %token yRETURN "return" %token ySCALARED "scalared" %token ySEQUENCE "sequence" %token ySHORTINT "shortint" %token ySHORTREAL "shortreal" %token ySIGNED "signed" %token ySOFT "soft" %token ySOLVE "solve" %token ySPECIFY "specify" %token ySPECPARAM "specparam" %token ySTATIC__CONSTRAINT "static-then-constraint" %token ySTATIC__ETC "static" %token ySTATIC__LEX "static-in-lex" %token ySTRING "string" %token ySTRONG "strong" %token ySTRUCT "struct" %token ySUPER "super" %token ySUPPLY0 "supply0" %token ySUPPLY1 "supply1" %token ySYNC_ACCEPT_ON "sync_accept_on" %token ySYNC_REJECT_ON "sync_reject_on" %token yS_ALWAYS "s_always" %token yS_EVENTUALLY "s_eventually" %token yS_NEXTTIME "s_nexttime" %token yS_UNTIL "s_until" %token yS_UNTIL_WITH "s_until_with" %token yTABLE "table" %token yTAGGED "tagged" %token yTASK__ETC "task" %token yTASK__LEX "task-in-lex" %token yTASK__aPUREV "task-is-pure-virtual" %token yTHIS "this" %token yTHROUGHOUT "throughout" %token yTIME "time" %token yTIMEPRECISION "timeprecision" %token yTIMEUNIT "timeunit" %token yTRI "tri" %token yTRI0 "tri0" %token yTRI1 "tri1" %token yTRIAND "triand" %token yTRIOR "trior" %token yTRIREG "trireg" %token yTYPE "type" %token yTYPEDEF "typedef" %token yUNION "union" %token yUNIQUE "unique" %token yUNIQUE0 "unique0" %token yUNSIGNED "unsigned" %token yUNTIL "until" %token yUNTIL_WITH "until_with" %token yUNTYPED "untyped" %token yVAR "var" %token yVECTORED "vectored" %token yVIRTUAL__CLASS "virtual-then-class" %token yVIRTUAL__ETC "virtual" %token yVIRTUAL__INTERFACE "virtual-then-interface" %token yVIRTUAL__LEX "virtual-in-lex" %token yVIRTUAL__anyID "virtual-then-identifier" %token yVOID "void" %token yWAIT "wait" %token yWAIT_ORDER "wait_order" %token yWAND "wand" %token yWEAK "weak" %token yWHILE "while" %token yWILDCARD "wildcard" %token yWIRE "wire" %token yWITHIN "within" %token yWITH__BRA "with-then-[" %token yWITH__CUR "with-then-{" %token yWITH__ETC "with" %token yWITH__LEX "with-in-lex" %token yWITH__PAREN "with-then-(" %token yWOR "wor" %token yXNOR "xnor" %token yXOR "xor" %token yD_ERROR "$error" %token yD_FATAL "$fatal" %token yD_INFO "$info" %token yD_ROOT "$root" %token yD_UNIT "$unit" %token yD_WARNING "$warning" %token yP_TICK "'" %token yP_TICKBRA "'{" %token yP_OROR "||" %token yP_ANDAND "&&" %token yP_NOR "~|" %token yP_XNOR "^~" %token yP_NAND "~&" %token yP_EQUAL "==" %token yP_NOTEQUAL "!=" %token yP_CASEEQUAL "===" %token yP_CASENOTEQUAL "!==" %token yP_WILDEQUAL "==?" %token yP_WILDNOTEQUAL "!=?" %token yP_GTE ">=" %token yP_LTE "<=" %token yP_LTE__IGNORE "<=-ignored" // Used when expr:<= means assignment %token yP_SLEFT "<<" %token yP_SRIGHT ">>" %token yP_SSRIGHT ">>>" %token yP_POW "**" %token yP_PAR__IGNORE "(-ignored" // Used when sequence_expr:expr:( is ignored %token yP_PAR__STRENGTH "(-for-strength" %token yP_LTMINUSGT "<->" %token yP_PLUSCOLON "+:" %token yP_MINUSCOLON "-:" %token yP_MINUSGT "->" %token yP_MINUSGTGT "->>" %token yP_EQGT "=>" %token yP_ASTGT "*>" %token yP_ANDANDAND "&&&" %token yP_POUNDPOUND "##" %token yP_POUNDMINUSPD "#-#" %token yP_POUNDEQPD "#=#" %token yP_DOTSTAR ".*" %token yP_ATAT "@@" %token yP_COLONCOLON "::" %token yP_COLONEQ ":=" %token yP_COLONDIV ":/" %token yP_ORMINUSGT "|->" %token yP_OREQGT "|=>" %token yP_BRASTAR "[*" %token yP_BRAEQ "[=" %token yP_BRAMINUSGT "[->" %token yP_BRAPLUSKET "[+]" %token yP_PLUSPLUS "++" %token yP_MINUSMINUS "--" %token yP_PLUSEQ "+=" %token yP_MINUSEQ "-=" %token yP_TIMESEQ "*=" %token yP_DIVEQ "/=" %token yP_MODEQ "%=" %token yP_ANDEQ "&=" %token yP_OREQ "|=" %token yP_XOREQ "^=" %token yP_SLEFTEQ "<<=" %token yP_SRIGHTEQ ">>=" %token yP_SSRIGHTEQ ">>>=" // '( is not a operator, as "' (" is legal //******************** // Verilog op precedence %token prUNARYARITH %token prREDUCTION %token prNEGATION %token prEVENTBEGIN %token prTAGGED // These prevent other conflicts %left yP_ANDANDAND %left yMATCHES %left prTAGGED %left prSEQ_CLOCKING // Lowest precedence // These are in IEEE 17.7.1 %nonassoc yALWAYS yS_ALWAYS yEVENTUALLY yS_EVENTUALLY yACCEPT_ON yREJECT_ON ySYNC_ACCEPT_ON ySYNC_REJECT_ON %right yP_ORMINUSGT yP_OREQGT yP_POUNDMINUSPD yP_POUNDEQPD %right yUNTIL yS_UNTIL yUNTIL_WITH yS_UNTIL_WITH yIMPLIES %right yIFF %left yOR %left yAND %nonassoc yNOT yNEXTTIME yS_NEXTTIME %left yINTERSECT %left yWITHIN %right yTHROUGHOUT %left prPOUNDPOUND_MULTI %left yP_POUNDPOUND %left yP_BRASTAR yP_BRAEQ yP_BRAMINUSGT yP_BRAPLUSKET // Not specified, but needed higher than yOR, lower than normal non-pexpr expressions %left yPOSEDGE yNEGEDGE yEDGE %left '{' '}' //%nonassoc '=' yP_PLUSEQ yP_MINUSEQ yP_TIMESEQ yP_DIVEQ yP_MODEQ yP_ANDEQ yP_OREQ yP_XOREQ yP_SLEFTEQ yP_SRIGHTEQ yP_SSRIGHTEQ yP_COLONEQ yP_COLONDIV yP_LTE %right yP_MINUSGT yP_LTMINUSGT %right '?' ':' %left yP_OROR %left yP_ANDAND %left '|' yP_NOR %left '^' yP_XNOR %left '&' yP_NAND %left yP_EQUAL yP_NOTEQUAL yP_CASEEQUAL yP_CASENOTEQUAL yP_WILDEQUAL yP_WILDNOTEQUAL %left '>' '<' yP_GTE yP_LTE yP_LTE__IGNORE yINSIDE yDIST %left yP_SLEFT yP_SRIGHT yP_SSRIGHT %left '+' '-' %left '*' '/' '%' %left yP_POW %left prUNARYARITH yP_MINUSMINUS yP_PLUSPLUS prREDUCTION prNEGATION %left '.' // Not in IEEE, but need to avoid conflicts; TICK should bind tightly just lower than COLONCOLON %left yP_TICK //%left '(' ')' '[' ']' yP_COLONCOLON '.' %nonassoc prLOWER_THAN_ELSE %nonassoc yELSE //BISONPRE_TYPES // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion %start source_text %% //********************************************************************** // Feedback to the Lexer // Note we read a parenthesis ahead, so this may not change the lexer at the right point. statePushVlg: // For PSL lexing, escape current state into Verilog state /* empty */ { } ; statePop: // Return to previous lexing state /* empty */ { } ; //********************************************************************** // Files source_text: // ==IEEE: source_text /* empty */ { } // // timeunits_declaration moved into description:package_item | descriptionList { } ; descriptionList: // IEEE: part of source_text description { } | descriptionList description { } ; description: // ==IEEE: description module_declaration { } // // udp_declaration moved into module_declaration | interface_declaration { } | program_declaration { } | package_declaration { } | package_item { } | bind_directive { } // unsupported // IEEE: config_declaration | error { } ; timeunits_declaration: // ==IEEE: timeunits_declaration yTIMEUNIT yaTIMENUM ';' { } | yTIMEUNIT yaTIMENUM '/' yaTIMENUM ';' { NEED_S09($1,"timeunit /"); } | yTIMEPRECISION yaTIMENUM ';' { } ; //********************************************************************** // Packages package_declaration: // ==IEEE: package_declaration packageFront package_itemListE yENDPACKAGE endLabelE { PARSEP->endpackageCb($3,$3); PARSEP->symPopScope(VAstType::PACKAGE); } ; packageFront: // // Lifetime is 1800-2009 yPACKAGE lifetimeE idAny ';' { PARSEP->symPushNew(VAstType::PACKAGE, $3); PARSEP->packageCb($1,$1, $3); } ; package_itemListE: // IEEE: [{ package_item }] /* empty */ { } | package_itemList { } ; package_itemList: // IEEE: { package_item } package_item { } | package_itemList package_item { } ; package_item: // ==IEEE: package_item package_or_generate_item_declaration { } | anonymous_program { } | package_export_declaration { } | timeunits_declaration { } ; package_or_generate_item_declaration: // ==IEEE: package_or_generate_item_declaration net_declaration { } | data_declaration { } | task_declaration { } | function_declaration { } | checker_declaration { } | dpi_import_export { } | extern_constraint_declaration { } | class_declaration { } // // class_constructor_declaration is part of function_declaration | local_parameter_declaration ';' { } | parameter_declaration ';' { } | covergroup_declaration { } | overload_declaration { } | assertion_item_declaration { } | ';' { } ; package_import_declarationList: package_import_declaration { } | package_import_declarationList package_import_declaration { } ; package_import_declaration: // ==IEEE: package_import_declaration yIMPORT package_import_itemList ';' { } ; package_import_itemList: package_import_item { } | package_import_itemList ',' package_import_item { } ; package_import_item: // ==IEEE: package_import_item yaID__aPACKAGE yP_COLONCOLON package_import_itemObj { PARSEP->syms().import($1,$1,$3); PARSEP->importCb($1,$1,$3); } ; package_import_itemObj: // IEEE: part of package_import_item idAny { $$=$1; $$=$1; } | '*' { $$=$1; $$=$1; } ; package_export_declaration: // IEEE: package_export_declaration yEXPORT '*' yP_COLONCOLON '*' ';' { } | yEXPORT package_import_itemList ';' { } ; //********************************************************************** // Module headers module_declaration: // ==IEEE: module_declaration // // timeunits_declaration instead in module_item // // IEEE: module_nonansi_header + module_ansi_header modFront importsAndParametersE portsStarE ';' module_itemListE yENDMODULE endLabelE { PARSEP->endmoduleCb($6,$6); PARSEP->symPopScope(VAstType::MODULE); } // | yEXTERN modFront importsAndParametersE portsStarE ';' { PARSEP->symPopScope(VAstType::MODULE); } ; modFront: // // General note: all *Front functions must call symPushNew before // // any formal arguments, as the arguments must land in the new scope. yMODULE lifetimeE idAny { PARSEP->symPushNew(VAstType::MODULE, $3); PARSEP->moduleCb($1,$1,$3,false,PARSEP->inCellDefine()); } ; importsAndParametersE: // IEEE: common part of module_declaration, interface_declaration, program_declaration // // { package_import_declaration } [ parameter_port_list ] parameter_port_listE { } | package_import_declarationList parameter_port_listE { } ; parameter_value_assignmentE: // IEEE: [ parameter_value_assignment ] /* empty */ { } | '#' '(' cellpinList ')' { } // // Side effect of combining *_instantiations | '#' delay_value { } ; parameter_port_listE: // IEEE: parameter_port_list + empty == parameter_value_assignment /* empty */ { } | '#' '(' ')' { } // // IEEE: '#' '(' list_of_param_assignments { ',' parameter_port_declaration } ')' // // IEEE: '#' '(' parameter_port_declaration { ',' parameter_port_declaration } ')' // // Can't just do that as "," conflicts with between vars and between stmts, so // // split into pre-comma and post-comma parts | '#' '(' {VARRESET_LIST("parameter");} paramPortDeclOrArgList ')' { VARRESET_NONLIST(""); } // // Note legal to start with "a=b" with no parameter statement ; paramPortDeclOrArgList: // IEEE: list_of_param_assignments + { parameter_port_declaration } paramPortDeclOrArg { } | paramPortDeclOrArgList ',' paramPortDeclOrArg { } ; paramPortDeclOrArg: // IEEE: param_assignment + parameter_port_declaration // // We combine the two as we can't tell which follows a comma param_assignment { } | parameter_port_declarationFront param_assignment { } ; portsStarE: // IEEE: .* + list_of_ports + list_of_port_declarations + empty /* empty */ { } // // .* expanded from module_declaration // // '(' ')' handled by list_of_ports:portE | '(' yP_DOTSTAR ')' { } | '(' {VARRESET_LIST("");} list_of_portsE ')' { VARRESET_NONLIST(""); } ; list_of_portsE: // IEEE: list_of_ports + list_of_port_declarations portE { } | list_of_portsE ',' portE { } ; portE: // ==IEEE: [ port ] // // Though not type for interfaces, we factor out the port direction and type // // so we can simply handle it in one place // // // IEEE: interface_port_header port_identifier { unpacked_dimension } // // Expanded interface_port_header // // We use instantCb here because the non-port form looks just like a module instantiation /* empty */ { } | portDirNetE id/*interface*/ idAny/*port*/ variable_dimensionListE sigAttrListE { VARDTYPE($2); VARIO("interface"); VARDONE($2, $3, $4, ""); PINNUMINC(); PARSEP->instantCb($2, $2, $3, $4); PARSEP->endcellCb($2,""); } | portDirNetE yINTERFACE idAny/*port*/ variable_dimensionListE sigAttrListE { VARDTYPE($2); VARIO("interface"); VARDONE($2, $3, $4, ""); PINNUMINC(); } | portDirNetE id/*interface*/ '.' idAny/*modport*/ idAny/*port*/ variable_dimensionListE sigAttrListE { VARDTYPE($2+"."+$4); VARIO("interface"); VARDONE($2, $5, $6, ""); PINNUMINC(); PARSEP->instantCb($2, $2, $5, $6); PARSEP->endcellCb($2,""); } | portDirNetE yINTERFACE '.' idAny/*modport*/ idAny/*port*/ variable_dimensionListE sigAttrListE { VARDTYPE($2+"."+$4); VARIO("interface"); VARDONE($2, $5, $6, ""); PINNUMINC(); } // // // IEEE: ansi_port_declaration, with [port_direction] removed // // IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension } [ '=' constant_expression ] // // IEEE: [ net_port_header | variable_port_header ] '.' port_identifier '(' [ expression ] ')' // // IEEE: [ variable_port_header ] port_identifier { variable_dimension } [ '=' constant_expression ] // // Substitute net_port_header = [ port_direction ] net_port_type // // Substitute variable_port_header = [ port_direction ] variable_port_type // // Substitute net_port_type = [ net_type ] data_type_or_implicit // // Substitute variable_port_type = var_data_type // // [ [ port_direction ] net_port_type | interface_port_header ] port_identifier { unpacked_dimension } // // [ [ port_direction ] var_data_type ] port_identifier variable_dimensionListE [ '=' constant_expression ] // // [ [ port_direction ] net_port_type | [ port_direction ] var_data_type ] '.' port_identifier '(' [ expression ] ')' // // // Remove optional '[...] id' is in portAssignment // // Remove optional '[port_direction]' is in port // // net_port_type | interface_port_header port_identifier { unpacked_dimension } // // net_port_type | interface_port_header port_identifier { unpacked_dimension } // // var_data_type port_identifier variable_dimensionListE [ '=' constExpr ] // // net_port_type | [ port_direction ] var_data_type '.' port_identifier '(' [ expr ] ')' // // Expand implicit_type // // // IEEE-2012: Since a net_type_identifier is a data_type, it falls into // // the rules here without change. // // // variable_dimensionListE instead of rangeListE to avoid conflicts // // // Note implicit rules looks just line declaring additional followon port // // No VARDECL("port") for implicit, as we don't want to declare variables for them | portDirNetE var_data_type '.' portSig '(' portAssignExprE ')' sigAttrListE { VARDTYPE($2); VARDONE($4, $4, "", ""); PINNUMINC(); } | portDirNetE signing '.' portSig '(' portAssignExprE ')' sigAttrListE { VARDTYPE($2); VARDONE($4, $4, "", ""); PINNUMINC(); } | portDirNetE signingE variable_dimensionList '.' portSig '(' portAssignExprE ')' sigAttrListE { VARDTYPE(SPACED($2,$3)); VARDONE($5, $5, "", ""); PINNUMINC(); } | portDirNetE yINTERCONNECT signingE variable_dimensionListE '.' portSig '(' portAssignExprE ')' sigAttrListE { VARDTYPE(SPACED(SPACED($2,$3),$4)); VARDONE($6, $6, "", ""); PINNUMINC(); } | portDirNetE /*implicit*/ '.' portSig '(' portAssignExprE ')' sigAttrListE { /*VARDTYPE-same*/ VARDONE($3, $3, "", ""); PINNUMINC(); } // | portDirNetE var_data_type portSig variable_dimensionListE sigAttrListE { VARDTYPE($2); VARDONE($3, $3, $4, ""); PINNUMINC(); } | portDirNetE signing portSig variable_dimensionListE sigAttrListE { VARDTYPE($2); VARDONE($3, $3, $4, ""); PINNUMINC(); } | portDirNetE signingE variable_dimensionList portSig variable_dimensionListE sigAttrListE { VARDTYPE(SPACED($2,$3)); VARDONE($4, $4, $5, ""); PINNUMINC(); } | portDirNetE yINTERCONNECT signingE variable_dimensionList portSig variable_dimensionListE sigAttrListE { VARDTYPE(SPACED(SPACED($2,$3),$4)); VARDONE($5, $5, $6, ""); PINNUMINC(); } | portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE { /*VARDTYPE-same*/ VARDONE($2, $2, $3, ""); PINNUMINC(); } // | portDirNetE var_data_type portSig variable_dimensionListE sigAttrListE '=' constExpr { VARDTYPE($2); VARDONE($3, $3, $4, $7); PINNUMINC(); } | portDirNetE signing portSig variable_dimensionListE sigAttrListE '=' constExpr { VARDTYPE($2); VARDONE($3, $3, $4, $7); PINNUMINC(); } | portDirNetE signingE variable_dimensionList portSig variable_dimensionListE sigAttrListE '=' constExpr { VARDTYPE(SPACED($2,$3)); VARDONE($4, $4, $5, $8); PINNUMINC(); } | portDirNetE yINTERCONNECT signingE variable_dimensionList portSig variable_dimensionListE sigAttrListE '=' constExpr { VARDTYPE(SPACED(SPACED($2,$3),$4)); VARDONE($5, $5, $6, $9); PINNUMINC(); } | portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE '=' constExpr { /*VARDTYPE-same*/ VARDONE($2, $2, $3, $6); PINNUMINC(); } // | '{' list_of_portsE '}' { } ; portDirNetE: // IEEE: part of port, optional net type and/or direction /* empty */ { } // // Per spec, if direction given default the nettype. // // The higher level rule may override this VARDTYPE with one later in the parse. | port_direction { VARDTYPE(""/*default_nettype*/); } | port_direction net_type { VARDTYPE(""/*default_nettype*/); } // net_type calls VARNET | net_type { } // net_type calls VARNET ; port_declNetE: // IEEE: part of port_declaration, optional net type /* empty */ { } | net_type { } // net_type calls VARNET ; portAssignExprE: // IEEE: part of port, optional expression /* empty */ { } | expr { } ; portSig: id/*port*/ { $$=$1; $$=$1; } | idSVKwd { $$=$1; $$=$1; } ; //********************************************************************** // Interface headers interface_declaration: // IEEE: interface_declaration + interface_nonansi_header + interface_ansi_header: // // timeunits_delcarationE is instead in interface_item intFront importsAndParametersE portsStarE ';' interface_itemListE yENDINTERFACE endLabelE { PARSEP->endinterfaceCb($6, $6); PARSEP->symPopScope(VAstType::INTERFACE); } | yEXTERN intFront importsAndParametersE portsStarE ';' { } ; intFront: yINTERFACE lifetimeE idAny/*new_interface*/ { PARSEP->symPushNew(VAstType::INTERFACE,$3); PARSEP->interfaceCb($1,$1,$3); } ; interface_itemListE: /* empty */ { } | interface_itemList { } ; interface_itemList: interface_item { } | interface_itemList interface_item { } ; interface_item: // IEEE: interface_item + non_port_interface_item port_declaration ';' { } // // IEEE: non_port_interface_item | generate_region { } | interface_or_generate_item { } | program_declaration { } // // IEEE 1800-2017: modport_item // // See instead old 2012 position in interface_or_generate_item | interface_declaration { } | timeunits_declaration { } // // See note in interface_or_generate item | module_common_item { } ; interface_or_generate_item: // ==IEEE: interface_or_generate_item // // module_common_item in interface_item, as otherwise duplicated // // with module_or_generate_item:module_common_item // // IEEE 1800-2017 removes modport_declaration here // // but for 2012 compatibility we retain it modport_declaration { } | extern_tf_declaration { } ; //********************************************************************** // Program headers anonymous_program: // ==IEEE: anonymous_program // // See the spec - this doesn't change the scope, items still go up "top" yPROGRAM ';' anonymous_program_itemListE yENDPROGRAM { } ; anonymous_program_itemListE: // IEEE: { anonymous_program_item } /* empty */ { } | anonymous_program_itemList { } ; anonymous_program_itemList: // IEEE: { anonymous_program_item } anonymous_program_item { } | anonymous_program_itemList anonymous_program_item { } ; anonymous_program_item: // ==IEEE: anonymous_program_item task_declaration { } | function_declaration { } | class_declaration { } | covergroup_declaration { } // // class_constructor_declaration is part of function_declaration | ';' { } ; program_declaration: // IEEE: program_declaration + program_nonansi_header + program_ansi_header: // // timeunits_delcarationE is instead in program_item pgmFront importsAndParametersE portsStarE ';' program_itemListE yENDPROGRAM endLabelE { PARSEP->endprogramCb($6,$6); PARSEP->symPopScope(VAstType::PROGRAM); } | yEXTERN pgmFront importsAndParametersE portsStarE ';' { PARSEP->symPopScope(VAstType::PROGRAM); } ; pgmFront: yPROGRAM lifetimeE idAny/*new_program*/ { PARSEP->symPushNew(VAstType::PROGRAM,$3); PARSEP->programCb($1,$1, $3); } ; program_itemListE: // ==IEEE: [{ program_item }] /* empty */ { } | program_itemList { } ; program_itemList: // ==IEEE: { program_item } program_item { } | program_itemList program_item { } ; program_item: // ==IEEE: program_item port_declaration ';' { } | non_port_program_item { } ; non_port_program_item: // ==IEEE: non_port_program_item continuous_assign { } | module_or_generate_item_declaration { } | initial_construct { } | final_construct { } | concurrent_assertion_item { } | timeunits_declaration { } | program_generate_item { } ; program_generate_item: // ==IEEE: program_generate_item loop_generate_construct { } | conditional_generate_construct { } | generate_region { } | elaboration_system_task { } ; extern_tf_declaration: // ==IEEE: extern_tf_declaration yEXTERN task_prototype ';' { } | yEXTERN function_prototype ';' { } | yEXTERN yFORKJOIN task_prototype ';' { } ; modport_declaration: // ==IEEE: modport_declaration yMODPORT modport_itemList ';' { } ; modport_itemList: // IEEE: part of modport_declaration modport_item { } | modport_itemList ',' modport_item { } ; modport_item: // ==IEEE: modport_item modport_idFront '(' {VARRESET_LIST("");} modportPortsDeclList ')' { VARRESET_NONLIST(""); PARSEP->endmodportCb($1, "endmodport"); PARSEP->symPopScope(VAstType::MODPORT); } ; modport_idFront: id/*new-modport*/ { PARSEP->symPushNew(VAstType::MODPORT,$1); PARSEP->modportCb($1,"modport",$1); } ; modportPortsDeclList: modportPortsDecl { } | modportPortsDeclList ',' modportPortsDecl { } ; // IEEE: modport_ports_declaration + modport_simple_ports_declaration // + (modport_tf_ports_declaration+import_export) + modport_clocking_declaration // We've expanded the lists each take to instead just have standalone ID ports. // We track the type as with the V2k series of defines, then create as each ID is seen. modportPortsDecl: // // IEEE: modport_simple_ports_declaration port_direction modportSimplePort { } // // IEEE: modport_clocking_declaration | yCLOCKING idAny/*clocking_identifier*/ { } | yIMPORT modport_tf_port { } | yEXPORT modport_tf_port { } // Continuations of above after a comma. // // IEEE: modport_simple_ports_declaration | modportSimplePort { } ; modportSimplePort: // IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier // // Note 'init' field is used to say what to connect to id { VARDONE($1,$1,"",$1); PINNUMINC(); } | '.' idAny '(' ')' { VARDONE($1,$2,"",""); PINNUMINC(); } | '.' idAny '(' expr ')' { VARDONE($1,$2,"",$4); PINNUMINC(); } ; modport_tf_port: // ==IEEE: modport_tf_port id/*tf_identifier*/ { } | method_prototype { } ; //************************************************ // Variable Declarations genvar_declaration: // ==IEEE: genvar_declaration yGENVAR list_of_genvar_identifiers ';' { } ; list_of_genvar_identifiers: // IEEE: list_of_genvar_identifiers (for declaration) genvar_identifierDecl { } | list_of_genvar_identifiers ',' genvar_identifierDecl { } ; genvar_identifierDecl: // IEEE: genvar_identifier (for declaration) id/*new-genvar_identifier*/ sigAttrListE { VARRESET_NONLIST("genvar"); VARDONE($1, $1, "", ""); } ; local_parameter_declaration: // IEEE: local_parameter_declaration // // See notes in parameter_declaration local_parameter_declarationFront list_of_param_assignments { } ; parameter_declaration: // IEEE: parameter_declaration // // IEEE: yPARAMETER yTYPE list_of_type_assignments ';' // // Instead of list_of_type_assignments // // we use list_of_param_assignments because for port handling // // it already must accept types, so simpler to have code only one place parameter_declarationFront list_of_param_assignments { } ; local_parameter_declarationFront: // IEEE: local_parameter_declaration w/o assignment varLParamReset implicit_typeE { VARRESET(); VARDECL("localparam"); VARDTYPE($2); } | varLParamReset data_type { VARRESET(); VARDECL("localparam"); VARDTYPE($2); } | varLParamReset yTYPE { VARRESET(); VARDECL("localparam"); VARDTYPE($2); } ; parameter_declarationFront: // IEEE: parameter_declaration w/o assignment varGParamReset implicit_typeE { VARRESET(); VARDECL("parameter"); VARDTYPE($2); } | varGParamReset data_type { VARRESET(); VARDECL("parameter"); VARDTYPE($2); } | varGParamReset yTYPE { VARRESET(); VARDECL("parameter"); VARDTYPE($2); } ; parameter_port_declarationFront: // IEEE: parameter_port_declaration w/o assignment // // IEEE: parameter_declaration (minus assignment) parameter_declarationFront { } | local_parameter_declarationFront { /*NEED_S09(CURLINE(),"port localparams");*/ } // | data_type { VARDTYPE($1); } | yTYPE { VARDTYPE($1); } ; net_declaration: // IEEE: net_declaration - excluding implict net_declarationFront netSigList ';' { } ; net_declarationFront: // IEEE: beginning of net_declaration net_declRESET net_type strengthSpecE net_scalaredE net_dataType { VARDTYPE(SPACED($4,$5)); } | net_declRESET yINTERCONNECT signingE rangeListE { VARNET($2); VARDTYPE(SPACED($3,$4)); } ; net_declRESET: /* empty */ { VARRESET_NONLIST("net"); } ; net_scalaredE: /* empty */ { $$=""; } | ySCALARED { $$=$1; $$=$1; } | yVECTORED { $$=$1; $$=$1; } ; net_dataType: // // If there's a SV data type there shouldn't be a delay on this wire // // Otherwise #(...) can't be determined to be a delay or parameters // // Submit this as a footnote to the committee var_data_type { $$=$1; $$=$1; } | signingE rangeList delayE { $$=$1; $$=SPACED($1,$2); } | signing delayE { $$=$1; $$=$1; } | /*implicit*/ delayE { $$=$1; $$=""; } ; net_type: // ==IEEE: net_type ySUPPLY0 { VARNET($1); } | ySUPPLY1 { VARNET($1); } | yTRI { VARNET($1); } | yTRI0 { VARNET($1); } | yTRI1 { VARNET($1); } | yTRIAND { VARNET($1); } | yTRIOR { VARNET($1); } | yTRIREG { VARNET($1); } | yWAND { VARNET($1); } | yWIRE { VARNET($1); } | yWOR { VARNET($1); } ; varGParamReset: yPARAMETER { VARRESET_NONLIST($1); } ; varLParamReset: yLOCALPARAM { VARRESET_NONLIST($1); } ; port_direction: // ==IEEE: port_direction + tf_port_direction // // IEEE 19.8 just "input" FIRST forces type to wire - we'll ignore that here yINPUT { VARIO($1); } | yOUTPUT { VARIO($1); } | yINOUT { VARIO($1); } | yREF { VARIO($1); } | yCONST__REF yREF { VARIO($1); } ; port_directionReset: // IEEE: port_direction that starts a port_declaraiton // // Used only for declarations outside the port list yINPUT { VARRESET_NONLIST(""); VARIO($1); } | yOUTPUT { VARRESET_NONLIST(""); VARIO($1); } | yINOUT { VARRESET_NONLIST(""); VARIO($1); } | yREF { VARRESET_NONLIST(""); VARIO($1); } | yCONST__REF yREF { VARRESET_NONLIST(""); VARIO($1); } ; port_declaration: // ==IEEE: port_declaration // // Used inside block; followed by ';' // // SIMILAR to tf_port_declaration // // // IEEE: inout_declaration // // IEEE: input_declaration // // IEEE: output_declaration // // IEEE: ref_declaration port_directionReset port_declNetE var_data_type { VARDTYPE($3); } list_of_variable_decl_assignments { } | port_directionReset port_declNetE signingE rangeList { VARDTYPE(SPACED($3,$4)); } list_of_variable_decl_assignments { } | port_directionReset port_declNetE signing { VARDTYPE($3); } list_of_variable_decl_assignments { } | port_directionReset port_declNetE /*implicit*/ { VARDTYPE("");/*default_nettype*/} list_of_variable_decl_assignments { } // // IEEE: interface_declaration // // Looks just like variable declaration unless has a period // // See etcInst ; tf_port_declaration: // ==IEEE: tf_port_declaration // // Used inside function; followed by ';' // // SIMILAR to port_declaration // port_directionReset var_data_type { VARDTYPE($2); } list_of_tf_variable_identifiers ';' { } | port_directionReset implicit_typeE { VARDTYPE($2); } list_of_tf_variable_identifiers ';' { } ; integer_atom_type: // ==IEEE: integer_atom_type yBYTE { $$=$1; $$=$1; } | ySHORTINT { $$=$1; $$=$1; } | yINT { $$=$1; $$=$1; } | yLONGINT { $$=$1; $$=$1; } | yINTEGER { $$=$1; $$=$1; } | yTIME { $$=$1; $$=$1; } ; integer_vector_type: // ==IEEE: integer_atom_type yBIT { $$=$1; $$=$1; } | yLOGIC { $$=$1; $$=$1; } | yREG { $$=$1; $$=$1; } ; non_integer_type: // ==IEEE: non_integer_type ySHORTREAL { $$=$1; $$=$1; } | yREAL { $$=$1; $$=$1; } | yREALTIME { $$=$1; $$=$1; } ; signingE: // IEEE: signing - plus empty /*empty*/ { $$=""; } | signing { $$=$1; $$=$1; } ; signing: // ==IEEE: signing ySIGNED { $$=$1; $$=$1; } | yUNSIGNED { $$=$1; $$=$1; } ; //************************************************ // Data Types casting_type: // IEEE: casting_type simple_type { $$=$1; $$=$1; } // // IEEE: constant_primary // // In expr:cast this is expanded to just "expr" // // // IEEE: signing | ySIGNED { $$=$1; $$=$1; } | yUNSIGNED { $$=$1; $$=$1; } | ySTRING { $$=$1; $$=$1; } | yCONST__ETC/*then `*/ { $$=$1; $$=$1; } ; simple_type: // ==IEEE: simple_type // // IEEE: integer_type integer_atom_type { $$=$1; $$=$1; } | integer_vector_type { $$=$1; $$=$1; } | non_integer_type { $$=$1; $$=$1; } // // IEEE: ps_type_identifier // // IEEE: ps_parameter_identifier (presumably a PARAMETER TYPE) | package_scopeIdFollowsE yaID__aTYPE { $$=$1; $$=$1+$2; } // // { generate_block_identifer ... } '.' // // Need to determine if generate_block_identifier can be lex-detected ; data_typeVar: // IEEE: data_type + virtual_interface_declaration data_type { $$=$1; $$=$1; } // // IEEE-2009: virtual_interface_declaration // // IEEE-2012: part of data_type | yVIRTUAL__INTERFACE yINTERFACE id/*interface*/ parameter_value_assignmentE '.' id/*modport*/ { $$=$1; $$=SPACED($1,SPACED($2,$3)); } | yVIRTUAL__anyID id/*interface*/ parameter_value_assignmentE '.' id/*modport*/ { $$=$1; $$=SPACED($1,$2); } ; data_type: // ==IEEE: data_type, excluding class_type etc references integer_vector_type signingE rangeListE { $$=$1; $$=SPACED($1,SPACED($2,$3)); } | integer_atom_type signingE { $$=$1; $$=SPACED($1,$2); } | non_integer_type { $$=$1; $$=$1; } | ySTRUCT packedSigningE '{' { PARSEP->symPushNewAnon(VAstType::STRUCT); } /*cont*/ struct_union_memberList '}' packed_dimensionListE { $$=$1; $$=$1; PARSEP->symPopScope(VAstType::STRUCT); } | yUNION taggedE packedSigningE '{' { PARSEP->symPushNewAnon(VAstType::UNION); } /*cont*/ struct_union_memberList '}' packed_dimensionListE { $$=$1; $$=$1; PARSEP->symPopScope(VAstType::UNION); } | enumDecl { $$=$1; $$=$1; } | ySTRING { $$=$1; $$=$1; } | yCHANDLE { $$=$1; $$=$1; } // // Rules overlap virtual_interface_declaration // // Parameters here are SV2009 // // IEEE has ['.' modport] but that will conflict with port // // declarations which decode '.' modport themselves, so // // instead see data_typeVar | yVIRTUAL__INTERFACE yINTERFACE id/*interface*/ parameter_value_assignmentE { $$=$1; $$=SPACED($1,SPACED($2,$3)); } | yVIRTUAL__anyID id/*interface*/ parameter_value_assignmentE { $$=$1; $$=SPACED($1,$2); } // // // IEEE: [ class_scope | package_scope ] type_identifier { packed_dimension } // // See data_type // // IEEE: class_type // // See data_type | yEVENT { $$=$1; $$=$1; } | type_reference { $$=$1; $$=$1; } // //---------------------- // // REFERENCES // // // IEEE: [ class_scope | package_scope ] type_identifier { packed_dimension } // // IEEE: class_type // // IEEE: ps_covergroup_identifier // // Don't distinguish between types and classes so all these combined | package_scopeIdFollowsE class_typeOneList packed_dimensionListE { $$=$1; $$=$1+$2+$3; } ; // IEEE: struct_union - not needed, expanded in data_type data_type_or_void: // ==IEEE: data_type_or_void data_type { $$=$1; $$=$1; } | yVOID { $$=$1; $$=$1; } ; var_data_type: // ==IEEE: var_data_type data_type { $$=$1; $$=$1; } | yVAR data_type { $$=$1; $$=$1; } | yVAR implicit_typeE { $$=$1; $$=$1; } ; type_reference: // ==IEEE: type_reference yTYPE '(' exprOrDataType ')' { $$=$1; $$="type("+$3+")"; } ; struct_union_memberList: // IEEE: { struct_union_member } struct_union_member { } | struct_union_memberList struct_union_member { } ; struct_union_member: // ==IEEE: struct_union_member random_qualifierE data_type_or_void { VARRESET_NONLIST("member"); VARDTYPE(SPACED($1,$2)); } /*cont*/ list_of_variable_decl_assignments ';' { } ; list_of_variable_decl_assignments: // ==IEEE: list_of_variable_decl_assignments variable_decl_assignment { } | list_of_variable_decl_assignments ',' variable_decl_assignment { } ; variable_decl_assignment: // ==IEEE: variable_decl_assignment id variable_dimensionListE sigAttrListE { VARDONE($1, $1, $2, ""); } | id variable_dimensionListE sigAttrListE '=' variable_declExpr { VARDONE($1, $1, $2, $5); } | idSVKwd { } // // // IEEE: "dynamic_array_variable_identifier '[' ']' [ '=' dynamic_array_new ]" // // Matches above with variable_dimensionE = "[]" // // IEEE: "class_variable_identifier [ '=' class_new ]" // // variable_dimensionE must be empty // // Pushed into variable_declExpr:dynamic_array_new // // // IEEE: "[ covergroup_variable_identifier ] '=' class_new // // Pushed into variable_declExpr:class_new | '=' class_new { } ; list_of_tf_variable_identifiers: // ==IEEE: list_of_tf_variable_identifiers tf_variable_identifier { } | list_of_tf_variable_identifiers ',' tf_variable_identifier { } ; tf_variable_identifier: // IEEE: part of list_of_tf_variable_identifiers id variable_dimensionListE sigAttrListE { VARDONE($1, $1, $2, ""); } | id variable_dimensionListE sigAttrListE '=' expr { VARDONE($1, $1, $2, $5); } ; variable_declExpr: // IEEE: part of variable_decl_assignment - rhs of expr expr { $$=$1; $$=$1; } | dynamic_array_new { $$=$1; $$=$1; } | class_new { $$=$1; $$=$1; } ; variable_dimensionListE: // IEEE: variable_dimension + empty /*empty*/ { $$=""; } | variable_dimensionList { $$=$1; $$=$1; } ; variable_dimensionList: // IEEE: variable_dimension + empty variable_dimension { $$=$1; $$=$1; } | variable_dimensionList variable_dimension { $$=$1; $$=$1+$2; } ; variable_dimension: // ==IEEE: variable_dimension // // IEEE: unsized_dimension '[' ']' { $$=$1; $$=""; } // // IEEE: unpacked_dimension | anyrange { $$=$1; $$=$1; } | '[' constExpr ']' { $$=$1; $$="["+$2+"]"; } // // IEEE: associative_dimension | '[' data_type ']' { $$=$1; $$="["+$2+"]"; } | yP_BRASTAR ']' { $$=$1; $$="[*]"; } | '[' '*' ']' { $$=$1; $$="[*]"; } // // IEEE: queue_dimension // // '[' '$' ']' -- $ is part of expr // // '[' '$' ':' expr ']' -- anyrange:expr:$ ; random_qualifierE: // IEEE: random_qualifier + empty /*empty*/ { $$=""; } | random_qualifier { $$=$1; $$=$1; } ; random_qualifier: // ==IEEE: random_qualifier yRAND { $$=$1; $$=$1; } | yRANDC { $$=$1; $$=$1; } ; taggedE: /*empty*/ { } | yTAGGED { } ; packedSigningE: /*empty*/ { } | yPACKED signingE { } ; //************************************************ // enum // IEEE: part of data_type enumDecl: yENUM enum_base_typeE '{' enum_nameList '}' rangeListE { $$=$2; } ; enum_base_typeE: // IEEE: enum_base_type /* empty */ { $$="enum"; } // // Not in spec, but obviously "enum [1:0]" should work // // implicit_type expanded, without empty | signingE rangeList { $$=$1; $$=$1+$2; } | signing { $$=$1; $$=$1; } // | integer_atom_type signingE { $$=$1; $$=SPACED($1,$2); } | integer_vector_type signingE regrangeE { $$=$1; $$=SPACED($1,SPACED($2,$3)); } // // below can be idAny or yaID__aTYPE // // IEEE requires a type, though no shift conflict if idAny | idAny regrangeE { $$=$1; $$=SPACED($1,$2); } ; enum_nameList: enum_name_declaration { } | enum_nameList ',' enum_name_declaration { } ; enum_name_declaration: // ==IEEE: enum_name_declaration idAny/*enum_identifier*/ enumNameRangeE enumNameStartE { } ; enumNameRangeE: // IEEE: second part of enum_name_declaration /* empty */ { } | '[' intnumAsConst ']' { } | '[' intnumAsConst ':' intnumAsConst ']' { } ; enumNameStartE: // IEEE: third part of enum_name_declaration /* empty */ { } | '=' constExpr { } ; intnumAsConst: yaINTNUM { } ; //************************************************ // Typedef data_declaration: // ==IEEE: data_declaration // // VARRESET can't be called here - conflicts data_declarationVar { } | type_declaration { } | package_import_declaration { } // // IEEE 2005: virtual_interface_declaration // // IEEE 2009 removed this // // "yVIRTUAL yID yID" looks just like a data_declaration // // Therefore the virtual_interface_declaration term isn't used // // 1800-2009: | net_type_declaration { } ; class_property: // ==IEEE: class_property, which is {property_qualifier} data_declaration memberQualResetListE data_declarationVarClass { } | memberQualResetListE type_declaration { } | memberQualResetListE package_import_declaration { } // // IEEE: virtual_interface_declaration // // "yVIRTUAL yID yID" looks just like a data_declaration // // Therefore the virtual_interface_declaration term isn't used ; data_declarationVar: // IEEE: part of data_declaration // // The first declaration has complications between assuming what's the type vs ID declaring data_declarationVarFront list_of_variable_decl_assignments ';' { } ; data_declarationVarClass: // IEEE: part of data_declaration (for class_property) // // The first declaration has complications between assuming what's the type vs ID declaring data_declarationVarFrontClass list_of_variable_decl_assignments ';' { } ; data_declarationVarFront: // IEEE: part of data_declaration // // implicit_type expanded into /*empty*/ or "signingE rangeList" constE yVAR lifetimeE data_type { VARRESET(); VARDECL("var"); VARDTYPE(SPACED($1,$4)); } | constE yVAR lifetimeE { VARRESET(); VARDECL("var"); VARDTYPE($1); } | constE yVAR lifetimeE signingE rangeList { VARRESET(); VARDECL("var"); VARDTYPE(SPACED($1,SPACED($4,$5))); } // // // Expanded: "constE lifetimeE data_type" | /**/ data_typeVar { VARRESET(); VARDECL("var"); VARDTYPE($1); } | /**/ lifetime data_typeVar { VARRESET(); VARDECL("var"); VARDTYPE($2); } | yCONST__ETC lifetimeE data_typeVar { VARRESET(); VARDECL("var"); VARDTYPE(SPACED($1,$3)); } // // = class_new is in variable_decl_assignment // // // IEEE: virtual_interface_declaration // // data_type includes VIRTUAL_INTERFACE, so added to data_typeVar ; data_declarationVarFrontClass: // IEEE: part of data_declaration (for class_property) // // VARRESET called before this rule // // yCONST is removed, added to memberQual rules // // implicit_type expanded into /*empty*/ or "signingE rangeList" yVAR lifetimeE data_type { VARDECL("var"); VARDTYPE(SPACED(GRAMMARP->m_varDType,$3)); } | yVAR lifetimeE { VARDECL("var"); VARDTYPE(GRAMMARP->m_varDType); } | yVAR lifetimeE signingE rangeList { VARDECL("var"); VARDTYPE(SPACED(GRAMMARP->m_varDType,SPACED($3,$4))); } // // // Expanded: "constE lifetimeE data_type" | /**/ data_typeVar { VARDECL("var"); VARDTYPE(SPACED(GRAMMARP->m_varDType,$1)); } // // lifetime is removed, added to memberQual rules to avoid conflict // // yCONST is removed, added to memberQual rules to avoid conflict // // = class_new is in variable_decl_assignment ; net_type_declaration: // IEEE: net_type_declaration yNETTYPE data_type idAny/*net_type_identifier*/ ';' { PARSEP->syms().replaceInsert(VAstType::TYPE, $3); } // // package_scope part of data_type | yNETTYPE data_type idAny yWITH__ETC package_scopeIdFollowsE id/*tf_identifier*/ ';' { PARSEP->syms().replaceInsert(VAstType::TYPE, $3); } | yNETTYPE package_scopeIdFollowsE id/*net_type_identifier*/ idAny/*net_type_identifier*/ ';' { PARSEP->syms().replaceInsert(VAstType::TYPE, $4); } ; constE: // IEEE: part of data_declaration /* empty */ { $$ = ""; } | yCONST__ETC { $$ = $1; } ; implicit_typeE: // IEEE: part of *data_type_or_implicit // // Also expanded in data_declaration /* empty */ { $$ = ""; } | signingE rangeList { $$ = SPACED($1,$2); } | signing { $$ = $1; } ; assertion_variable_declaration: // IEEE: assertion_variable_declaration // // IEEE: var_data_type expanded var_data_type list_of_variable_decl_assignments ';' { } ; type_declaration: // ==IEEE: type_declaration // // Use idAny, as we can redeclare a typedef on an existing typedef yTYPEDEF data_type idAny variable_dimensionListE ';' { VARDONETYPEDEF($1,$3,$2,$4); } | yTYPEDEF id/*interface*/ bit_selectE '.' idAny/*type*/ idAny/*type*/ ';' { VARDONETYPEDEF($1,$6,$2+$3+"."+$5,""); } // // Combines into above "data_type id" rule | yTYPEDEF id ';' { VARDONETYPEDEF($1,$2,"",""); } | yTYPEDEF yENUM idAny ';' { PARSEP->syms().replaceInsert(VAstType::ENUM, $3); } | yTYPEDEF ySTRUCT idAny ';' { PARSEP->syms().replaceInsert(VAstType::STRUCT, $3); } | yTYPEDEF yUNION idAny ';' { PARSEP->syms().replaceInsert(VAstType::UNION, $3); } | yTYPEDEF yCLASS idAny ';' { PARSEP->syms().replaceInsert(VAstType::CLASS, $3); } | yTYPEDEF yINTERFACE yCLASS idAny ';' { PARSEP->syms().replaceInsert(VAstType::CLASS, $3); } ; //************************************************ // Module Items module_itemListE: // IEEE: Part of module_declaration /* empty */ { } | module_itemList { } ; module_itemList: // IEEE: Part of module_declaration module_item { } | module_itemList module_item { } ; module_item: // ==IEEE: module_item port_declaration ';' { } | non_port_module_item { } ; non_port_module_item: // ==IEEE: non_port_module_item generate_region { } | module_or_generate_item { } | specify_block { } | specparam_declaration { } | program_declaration { } | module_declaration { } | interface_declaration { } | timeunits_declaration { } ; module_or_generate_item: // ==IEEE: module_or_generate_item // // IEEE: parameter_override yDEFPARAM list_of_defparam_assignments ';' { } // // IEEE: gate_instantiation + udp_instantiation + module_instantiation // // not here, see etcInst in module_common_item // // We joined udp & module definitions, so this goes here | combinational_body { } // // This module_common_item shared with interface_or_generate_item:module_common_item | module_common_item { } ; module_common_item: // ==IEEE: module_common_item module_or_generate_item_declaration { } // // IEEE: interface_instantiation // // + IEEE: program_instantiation // // + module_instantiation from module_or_generate_item | etcInst { } | assertion_item { } | bind_directive { } | continuous_assign { } // // IEEE: net_alias | yALIAS variable_lvalue aliasEqList ';' { } | initial_construct { } | final_construct { } // // IEEE: always_construct | yALWAYS stmtBlock { } | loop_generate_construct { } | conditional_generate_construct { } | elaboration_system_task { } // | error ';' { } ; continuous_assign: // IEEE: continuous_assign yASSIGN strengthSpecE delayE assignList ';' { } ; initial_construct: // IEEE: initial_construct yINITIAL stmtBlock { } ; final_construct: // IEEE: final_construct yFINAL stmtBlock { } ; module_or_generate_item_declaration: // ==IEEE: module_or_generate_item_declaration package_or_generate_item_declaration { } | genvar_declaration { } | clocking_declaration { } | yDEFAULT yCLOCKING idAny/*new-clocking_identifier*/ ';' { } | yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';' { } ; aliasEqList: // IEEE: part of net_alias '=' variable_lvalue { } | aliasEqList '=' variable_lvalue { } ; bind_directive: // ==IEEE: bind_directive + bind_target_scope // // ';' - Note IEEE grammar is wrong, includes extra ';' - it's already in module_instantiation // // We merged the rules - id may be a bind_target_instance or module_identifier or interface_identifier yBIND bind_target_instance bind_instantiation { } | yBIND bind_target_instance ':' bind_target_instance_list bind_instantiation { } ; bind_target_instance_list: // ==IEEE: bind_target_instance_list bind_target_instance { } | bind_target_instance_list ',' bind_target_instance { } ; bind_target_instance: // ==IEEE: bind_target_instance hierarchical_identifierBit { } ; bind_instantiation: // ==IEEE: bind_instantiation // // IEEE: program_instantiation // // IEEE: + module_instantiation // // IEEE: + interface_instantiation etcInst { } ; //************************************************ // Generates // // Way down in generate_item is speced a difference between module, // interface and checker generates. modules and interfaces are almost // identical (minus DEFPARAMs) so we overlap them. Checkers are too // different, so we copy all rules for checkers. generate_region: // ==IEEE: generate_region yGENERATE ~c~genItemList yENDGENERATE { } | yGENERATE yENDGENERATE { } ; c_generate_region: // IEEE: generate_region (for checkers) BISONPRE_COPY(generate_region,{s/~c~/c_/g}) // {copied} ; generate_block: // IEEE: generate_block // // Either a single item, or a begin-end block ~c~generate_item { } | ~c~genItemBegin { } ; c_generate_block: // IEEE: generate_block (for checkers) BISONPRE_COPY(generate_block,{s/~c~/c_/g}) // {copied} ; genItemBegin: // IEEE: part of generate_block yBEGIN ~c~genItemList yEND { } | yBEGIN yEND { } | id ':' yBEGIN ~c~genItemList yEND endLabelE { } | id ':' yBEGIN yEND endLabelE { } | yBEGIN ':' idAny ~c~genItemList yEND endLabelE { } | yBEGIN ':' idAny yEND endLabelE { } ; c_genItemBegin: // IEEE: part of generate_block (for checkers) BISONPRE_COPY(genItemBegin,{s/~c~/c_/g}) // {copied} ; genItemOrBegin: // Not in IEEE, but our begin isn't under generate_item ~c~generate_item { } | ~c~genItemBegin { } ; c_genItemOrBegin: // (for checkers) BISONPRE_COPY(genItemOrBegin,{s/~c~/c_/g}) // {copied} ; genItemList: ~c~genItemOrBegin { } | ~c~genItemList ~c~genItemOrBegin { } ; c_genItemList: // (for checkers) BISONPRE_COPY(genItemList,{s/~c~/c_/g}) // {copied} ; generate_item: // IEEE: module_or_interface_or_generate_item // // Only legal when in a generate under a module (or interface under a module) module_or_generate_item { } // // Only legal when in a generate under an interface | interface_or_generate_item { } // // IEEE: checker_or_generate_item // // Only legal when in a generate under a checker // // so below in c_generate_item ; c_generate_item: // IEEE: generate_item (for checkers) checker_or_generate_item { } ; conditional_generate_construct: // ==IEEE: conditional_generate_construct // // IEEE: case_generate_construct yCASE '(' expr ')' yENDCASE { } | yCASE '(' expr ')' ~c~case_generate_itemList yENDCASE { } // // IEEE: if_generate_construct | yIF '(' expr ')' ~c~generate_block %prec prLOWER_THAN_ELSE { } | yIF '(' expr ')' ~c~generate_block yELSE ~c~generate_block { } ; c_conditional_generate_construct: // IEEE: conditional_generate_construct (for checkers) BISONPRE_COPY(conditional_generate_construct,{s/~c~/c_/g}) // {copied} ; loop_generate_construct: // ==IEEE: loop_generate_construct yFOR '(' genvar_initialization ';' expr ';' genvar_iteration ')' ~c~generate_block { } ; c_loop_generate_construct: // IEEE: loop_generate_construct (for checkers) BISONPRE_COPY(loop_generate_construct,{s/~c~/c_/g}) // {copied} ; genvar_initialization: // ==IEEE: genvar_initalization id '=' constExpr { } | yGENVAR genvar_identifierDecl '=' constExpr { } ; genvar_iteration: // ==IEEE: genvar_iteration // // IEEE: assignment_operator plus IDs | id '=' expr { } | id yP_PLUSEQ expr { } | id yP_MINUSEQ expr { } | id yP_TIMESEQ expr { } | id yP_DIVEQ expr { } | id yP_MODEQ expr { } | id yP_ANDEQ expr { } | id yP_OREQ expr { } | id yP_XOREQ expr { } | id yP_SLEFTEQ expr { } | id yP_SRIGHTEQ expr { } | id yP_SSRIGHTEQ expr { } // // inc_or_dec_operator | yP_PLUSPLUS id { } | yP_MINUSMINUS id { } | id yP_PLUSPLUS { } | id yP_MINUSMINUS { } ; case_generate_itemList: // IEEE: { case_generate_item } ~c~case_generate_item { } | ~c~case_generate_itemList ~c~case_generate_item { } ; c_case_generate_itemList: // IEEE: { case_generate_item } (for checkers) BISONPRE_COPY(case_generate_itemList,{s/~c~/c_/g}) // {copied} ; case_generate_item: // ==IEEE: case_generate_item caseCondList ':' ~c~generate_block { } | yDEFAULT ':' ~c~generate_block { } | yDEFAULT ~c~generate_block { } ; c_case_generate_item: // IEEE: case_generate_item (for checkers) BISONPRE_COPY(case_generate_item,{s/~c~/c_/g}) // {copied} ; //************************************************ // Assignments and register declarations assignList: assignOne { } | assignList ',' assignOne { } ; assignOne: variable_lvalue '=' expr { PARSEP->contassignCb($2,"assign",$1,$3); } ; delay_or_event_controlE: // IEEE: delay_or_event_control plus empty /* empty */ { } | delay_control { } /* ignored */ | event_control { } /* ignored */ | yREPEAT '(' expr ')' event_control { } /* ignored */ ; delayE: /* empty */ { } | delay_control { } /* ignored */ ; delay_control: // ==IEEE: delay_control '#' delay_value { } /* ignored */ | '#' '(' minTypMax ')' { } /* ignored */ | '#' '(' minTypMax ',' minTypMax ')' { } /* ignored */ | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' { } /* ignored */ ; delay_value: // ==IEEE:delay_value // // IEEE: ps_identifier ps_id_etc { } | yaINTNUM { } | yaFLOATNUM { } | yaTIMENUM { } ; delayExpr: expr { } ; minTypMax: // IEEE: mintypmax_expression and constant_mintypmax_expression delayExpr { } | delayExpr ':' delayExpr ':' delayExpr { } ; netSigList: // IEEE: list_of_port_identifiers netSig { } | netSigList ',' netSig { } ; netSig: // IEEE: net_decl_assignment - one element from list_of_port_identifiers netId sigAttrListE { VARDONE($1, $1, "", ""); } | netId sigAttrListE '=' expr { VARDONE($1, $1, "", $4); } | netId variable_dimensionList sigAttrListE { VARDONE($1, $1, $2, ""); } ; netId: id/*new-net*/ { $$=$1; $$=$1; } | idSVKwd { $$=$1; $$=$1; } ; sigAttrListE: /* empty */ { } ; rangeListE: // IEEE: [{packed_dimension}] /* empty */ { $$=""; } | rangeList { $$=$1; $$ = $1; } ; rangeList: // IEEE: {packed_dimension} anyrange { $$=$1; $$ = $1; } | rangeList anyrange { $$=$1; $$ = $1+$2; } ; regrangeE: /* empty */ { $$=""; } | anyrange { $$=$1; $$=$1; } ; bit_selectE: // IEEE: constant_bit_select (IEEE included empty) /* empty */ { $$ = ""; } | '[' constExpr ']' { $$=$1; $$ = "["+$2+"]"; } ; // IEEE: select // Merged into more general idArray anyrange: '[' constExpr ':' constExpr ']' { $$=$1; $$ = "["+$2+":"+$4+"]"; } ; packed_dimensionListE: // IEEE: [{ packed_dimension }] /* empty */ { $$=""; } | packed_dimensionList { $$=$1; $$=$1; } ; packed_dimensionList: // IEEE: { packed_dimension } packed_dimension { $$=$1; $$=$1; } | packed_dimensionList packed_dimension { $$=$1; $$=$1+$2; } ; packed_dimension: // ==IEEE: packed_dimension anyrange { $$=$1; $$=$1; } | '[' ']' { $$="[]"; } ; //************************************************ // Parameters param_assignment: // ==IEEE: param_assignment // // IEEE: constant_param_expression // // param_expression: '$' is in expr id/*new-parameter*/ variable_dimensionListE sigAttrListE '=' exprOrDataTypeOrMinTypMax { $$=$1; VARDONE($1, $1, $2, $5); } // // only legal in port list; throws error if not set | id/*new-parameter*/ variable_dimensionListE sigAttrListE { $$=$1; VARDONE($1, $1, $2, ""); NEED_S09($1,"optional parameter defaults"); } ; list_of_param_assignments: // ==IEEE: list_of_param_assignments param_assignment { } | list_of_param_assignments ',' param_assignment { } ; list_of_defparam_assignments: // ==IEEE: list_of_defparam_assignments defparam_assignment { } | list_of_defparam_assignments ',' defparam_assignment { } ; defparam_assignment: // ==IEEE: defparam_assignment hierarchical_identifier/*parameter*/ '=' expr { PARSEP->defparamCb($2,"defparam",$1,$3); } ; //************************************************ // Instances // We don't know identifier types, so this matches all module,udp,etc instantiation // module_id [#(params)] name (pins) [, name ...] ; // module_instantiation // gate (strong0) [#(delay)] [name] (pins) [, (pins)...] ; // gate_instantiation // program_id [#(params}] name ; // program_instantiation // interface_id [#(params}] name ; // interface_instantiation // checker_id name (pins) ; // checker_instantiation etcInst: // IEEE: module_instantiation + gate_instantiation + udp_instantiation instName { INSTPREP($1,1,0); } strengthSpecE parameter_value_assignmentE { INSTPREP($1,0,1); } instnameList ';' { INSTDONE(); } // // IEEE: interface_identifier' .' modport_identifier list_of_interface_identifiers | instName { INSTPREP($1,1,0); } '.' id {INSTPREP($1,0,0);} mpInstnameList ';' { INSTDONE(); } ; instName: gateKwd { $$=$1; $$=$1; } // // id is-a: interface_identifier // // or program_identifier // // or udp_identifier // // or module_identifier | id { $$=$1; $$=$1; } ; mpInstnameList: // Similar to instnameList, but for modport instantiations which have no parenthesis mpInstnameParen { } | mpInstnameList ',' mpInstnameParen { } ; mpInstnameParen: // Similar to instnameParen, but for modport instantiations which have no parenthesis mpInstname { PARSEP->endcellCb($1,""); } ; mpInstname: // Similar to instname, but for modport instantiations which have no parenthesis // // id is-a: interface_port_identifier (interface.modport) id instRangeE { PARSEP->instantCb($1, GRAMMARP->m_cellMod, $1, $2); } ; instnameList: instnameParen { } | instnameList ',' instnameParen { } ; instnameParen: instname cellpinList ')' { PARSEP->endcellCb($3,""); } ; instname: // // id is-a: hierarchical_instance (interface) // // or instance_identifier (module) // // or instance_identifier (program) // // or udp_instance (udp) id instRangeE '(' { PARSEP->instantCb($1, GRAMMARP->m_cellMod, $1, $2); PINPARAMS(); } | instRangeE '(' { PARSEP->instantCb($2, GRAMMARP->m_cellMod, "", $1); PINPARAMS(); } // UDP ; instRangeE: /* empty */ { $$ = ""; } | '[' constExpr ']' { $$=$1; $$ = "["+$2+"]"; } | '[' constExpr ':' constExpr ']' { $$=$1; $$ = "["+$2+":"+$4+"]"; } ; cellpinList: { VARRESET_LIST(""); } cellpinItList { VARRESET_NONLIST(""); GRAMMARP->m_withinPin = false; } ; cellpinItList: // IEEE: list_of_port_connections + list_of_parameter_assignmente { GRAMMARP->m_portNextNetName.clear(); } cellpinItemE { } | cellpinItList ',' cellpinItemE { } ; cellpinItemE: // IEEE: named_port_connection + named_parameter_assignment + empty /* empty: ',,' is legal */ { PINNUMINC(); } /*PINDONE(yylval.fl,"",""); <- No, as then () implies a pin*/ | yP_DOTSTAR { PINDONE($1,"*","*");PINNUMINC(); } | '.' idSVKwd { PINDONE($1,$2,$2); PINNUMINC(); } | '.' idAny { PINDONE($1,$2,$2); PINNUMINC(); } | '.' idAny '(' ')' { PINDONE($1,$2,""); PINNUMINC(); } // // mintypmax is expanded here, as it might be a UDP or gate primitive // // For checkers, this needs to not just expr, but include events + properties | '.' idAny '(' pev_expr ')' { PINDONE($1,$2,$4); PINNUMINC(); } | '.' idAny '(' pev_expr ':' expr ')' { PINDONE($1,$2,$4); PINNUMINC(); } | '.' idAny '(' pev_expr ':' expr ':' expr ')' { PINDONE($1,$2,$4); PINNUMINC(); } // // For parameters | '.' idAny '(' data_type ')' { PINDONE($1,$2,$4); PINNUMINC(); } // // For parameters | data_type { PINDONE($1,"",$1); PINNUMINC(); } // | expr { PINDONE($1,"",$1); PINNUMINC(); } | expr ':' expr { PINDONE($1,"",$1); PINNUMINC(); } | expr ':' expr ':' expr { PINDONE($1,"",$1); PINNUMINC(); } ; //************************************************ // EventControl lists event_control: // ==IEEE: event_control '@' '(' event_expression ')' { } | '@' '*' { } | '@' '(' '*' ')' { } // // IEEE: hierarchical_event_identifier | '@' idClassSel/*event_id or ps_or_hierarchical_sequence_identifier*/ { } // // IEEE: ps_or_hierarchical_sequence_identifier // // sequence_instance without parens matches idClassSel above. // // Ambiguity: "'@' sequence (-for-sequence" versus expr:delay_or_event_controlE "'@' id (-for-expr // // For now we avoid this, as it's very unlikely someone would mix // // 1995 delay with a sequence with parameters. // // Alternatively split this out of event_control, and delay_or_event_controlE // // and anywhere delay_or_event_controlE is called allow two expressions ; event_expression: // IEEE: event_expression - split over several // // ',' rules aren't valid in port lists - ev_expr is there. // // Also eliminates left recursion to appease conflicts ev_expr { } | event_expression ',' ev_expr %prec yOR { } /* Verilog 2001 */ ; senitemEdge: // IEEE: part of event_expression // // Also called by pev_expr yPOSEDGE expr { $$=$1; $$=$1+" "+$2; } | yPOSEDGE expr yIFF expr { $$=$1; $$=$1+" "+$2+" iff "+$4; } | yNEGEDGE expr { $$=$1; $$=$1+" "+$2; } | yNEGEDGE expr yIFF expr { $$=$1; $$=$1+" "+$2+" iff "+$4; } | yEDGE expr { $$=$1; $$=$1+" "+$2; NEED_S09($1,"edge"); } | yEDGE expr yIFF expr { $$=$1; $$=$1+" "+$2+" iff "+$4; NEED_S09($1,"edge"); } ; //************************************************ // Statements stmtBlock: // IEEE: statement + seq_block + par_block stmt { } ; seq_block: // ==IEEE: seq_block // // IEEE doesn't allow declarations in unnamed blocks, but several simulators do. seq_blockFront blockDeclStmtList yEND endLabelE { PARSEP->symPopScope(VAstType::BLOCK); } | seq_blockFront /**/ yEND endLabelE { PARSEP->symPopScope(VAstType::BLOCK); } ; par_block: // ==IEEE: par_block par_blockFront blockDeclStmtList yJOIN endLabelE { PARSEP->symPopScope(VAstType::FORK); } | par_blockFront /**/ yJOIN endLabelE { PARSEP->symPopScope(VAstType::FORK); } ; seq_blockFront: // IEEE: part of seq_block yBEGIN { PARSEP->symPushNewAnon(VAstType::BLOCK); } | yBEGIN ':' idAny/*new-block_identifier*/ { PARSEP->symPushNew(VAstType::BLOCK,$1); } ; par_blockFront: // IEEE: part of par_block yFORK { PARSEP->symPushNewAnon(VAstType::FORK); } | yFORK ':' idAny/*new-block_identifier*/ { PARSEP->symPushNew(VAstType::FORK,$1); } ; blockDeclStmtList: // IEEE: { block_item_declaration } { statement or null } // // The spec seems to suggest a empty declaration isn't ok, but most simulators take it block_item_declarationList { } | block_item_declarationList stmtList { } | stmtList { } ; block_item_declarationList: // IEEE: [ block_item_declaration ] block_item_declaration { } | block_item_declarationList block_item_declaration { } ; block_item_declaration: // ==IEEE: block_item_declaration data_declaration { } | local_parameter_declaration ';' { } | parameter_declaration ';' { } | overload_declaration { } | let_declaration { } ; stmtList: stmtBlock { } | stmtList stmtBlock { } ; stmt: // IEEE: statement_or_null == function_statement_or_null statement_item { } | id/*block_identifier*/ ':' statement_item { } /*S05 block creation rule*/ // // from _or_null | ';' { } ; statement_item: // IEEE: statement_item // // IEEE: operator_assignment foperator_assignment ';' { } // // // IEEE: blocking_assignment // // 1800-2009 restricts LHS of assignment to new to not have a range // // This is ignored to avoid conflicts | fexprLvalue '=' class_new ';' { } | fexprLvalue '=' dynamic_array_new ';' { } // // // IEEE: nonblocking_assignment | fexprLvalue yP_LTE delay_or_event_controlE expr ';' { } // // // IEEE: procedural_continuous_assignment | yASSIGN expr '=' delay_or_event_controlE expr ';' { } | yDEASSIGN variable_lvalue ';' { } | yFORCE expr '=' expr ';' { } | yRELEASE variable_lvalue ';' { } // // // IEEE: case_statement | unique_priorityE caseStart caseAttrE case_itemListE yENDCASE { } | unique_priorityE caseStart caseAttrE yMATCHES case_patternListE yENDCASE { } | unique_priorityE caseStart caseAttrE yINSIDE case_insideListE yENDCASE { } // // // IEEE: conditional_statement | unique_priorityE yIF '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { } | unique_priorityE yIF '(' expr ')' stmtBlock yELSE stmtBlock { } // | finc_or_dec_expression ';' { } // // IEEE: inc_or_dec_expression // // Below under expr // // // IEEE: subroutine_call_statement | yVOID yP_TICK '(' function_subroutine_callNoMethod ')' ';' { } | yVOID yP_TICK '(' expr '.' function_subroutine_callNoMethod ')' ';' { } // // Expr included here to resolve our not knowing what is a method call // // Expr here must result in a subroutine_call | task_subroutine_callNoMethod ';' { } | fexpr '.' array_methodNoRoot ';' { } | fexpr '.' task_subroutine_callNoMethod ';' { } | fexprScope ';' { } // // Not here in IEEE; from class_constructor_declaration // // Because we've joined class_constructor_declaration into generic functions // // Way over-permissive; // // IEEE: [ ySUPER '.' yNEW [ '(' list_of_arguments ')' ] ';' ] | fexpr '.' class_new ';' { } // // // IEEE: disable_statement | yDISABLE hierarchical_identifier/*task_or_block*/ ';' { } | yDISABLE yFORK ';' { } // // IEEE: event_trigger | yP_MINUSGT hierarchical_identifier/*event*/ ';' { } | yP_MINUSGTGT delay_or_event_controlE hierarchical_identifier/*event*/ ';' { } // // IEEE: loop_statement | yFOREVER stmtBlock { } | yREPEAT '(' expr ')' stmtBlock { } | yWHILE '(' expr ')' stmtBlock { } // // for's first ';' is in for_initalization | yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock { } | yFOR '(' for_initialization ';' for_stepE ')' stmtBlock { } | yDO stmtBlock yWHILE '(' expr ')' ';' { } // // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009 | yFOREACH '(' idClassForeach/*array_id[loop_variables]*/ ')' stmt { } // // // IEEE: jump_statement | yRETURN ';' { } | yRETURN expr ';' { } | yBREAK ';' { } | yCONTINUE ';' { } // | par_block { } // // IEEE: procedural_timing_control_statement + procedural_timing_control | delay_control stmtBlock { } | event_control stmtBlock { } | cycle_delay stmtBlock { } // | seq_block { } // // // IEEE: wait_statement | yWAIT '(' expr ')' stmtBlock { } | yWAIT yFORK ';' { } | yWAIT_ORDER '(' hierarchical_identifierList ')' action_block { } // // // IEEE: procedural_assertion_statement | procedural_assertion_statement { } // // // IEEE: clocking_drive ';' // // clockvar_expression made to fexprLvalue to prevent reduce conflict // // Note LTE in this context is highest precedence, so first on left wins | fexprLvalue yP_LTE cycle_delay expr ';' { } // | randsequence_statement { } // // // IEEE: randcase_statement | yRANDCASE case_itemList yENDCASE { } // | expect_property_statement { } // | error ';' { } ; operator_assignment: // IEEE: operator_assignment ~f~exprLvalue '=' delay_or_event_controlE expr { } | ~f~exprLvalue yP_PLUSEQ expr { } | ~f~exprLvalue yP_MINUSEQ expr { } | ~f~exprLvalue yP_TIMESEQ expr { } | ~f~exprLvalue yP_DIVEQ expr { } | ~f~exprLvalue yP_MODEQ expr { } | ~f~exprLvalue yP_ANDEQ expr { } | ~f~exprLvalue yP_OREQ expr { } | ~f~exprLvalue yP_XOREQ expr { } | ~f~exprLvalue yP_SLEFTEQ expr { } | ~f~exprLvalue yP_SRIGHTEQ expr { } | ~f~exprLvalue yP_SSRIGHTEQ expr { } ; foperator_assignment: // IEEE: operator_assignment (for first part of expression) BISONPRE_COPY(operator_assignment,{s/~f~/f/g}) // {copied} ; inc_or_dec_expression: // ==IEEE: inc_or_dec_expression // // Need fexprScope instead of variable_lvalue to prevent conflict ~l~exprScope yP_PLUSPLUS { $$=$1; $$ = $1+$2; } | ~l~exprScope yP_MINUSMINUS { $$=$1; $$ = $1+$2; } // // Need expr instead of variable_lvalue to prevent conflict | yP_PLUSPLUS expr { $$=$1; $$ = $1+$2; } | yP_MINUSMINUS expr { $$=$1; $$ = $1+$2; } ; finc_or_dec_expression: // IEEE: inc_or_dec_expression (for first part of expression) BISONPRE_COPY(inc_or_dec_expression,{s/~l~/f/g}) // {copied} ; sinc_or_dec_expression: // IEEE: inc_or_dec_expression (for sequence_expression) BISONPRE_COPY(inc_or_dec_expression,{s/~l~/s/g}) // {copied} ; pinc_or_dec_expression: // IEEE: inc_or_dec_expression (for property_expression) BISONPRE_COPY(inc_or_dec_expression,{s/~l~/p/g}) // {copied} ; ev_inc_or_dec_expression: // IEEE: inc_or_dec_expression (for ev_expr) BISONPRE_COPY(inc_or_dec_expression,{s/~l~/ev_/g}) // {copied} ; pev_inc_or_dec_expression: // IEEE: inc_or_dec_expression (for pev_expr) BISONPRE_COPY(inc_or_dec_expression,{s/~l~/pev_/g}) // {copied} ; class_new: // ==IEEE: class_new // // Special precence so (...) doesn't match expr yNEW__ETC { $$=$1; $$ = $1; } | yNEW__ETC expr { $$=$1; $$ = $1+" "+$2; } // // Grammer abiguity; we assume "new (x)" the () are a argument, not expr | yNEW__PAREN '(' list_of_argumentsE ')' { $$=$1; $$ = $1+"("+$3+")"; } ; dynamic_array_new: // ==IEEE: dynamic_array_new yNEW__ETC '[' expr ']' { $$=$1; $$=$1+"["+$3+"]"; } | yNEW__ETC '[' expr ']' '(' expr ')' { $$=$1; $$=$1+"["+$3+"]("+$6+")"; } ; //************************************************ // Case/If unique_priorityE: // IEEE: unique_priority + empty /*empty*/ { } | yPRIORITY { } | yUNIQUE { } | yUNIQUE0 { NEED_S09($1, "unique0"); } ; action_block: // ==IEEE: action_block stmt %prec prLOWER_THAN_ELSE { } | stmt yELSE stmt { } | yELSE stmt { } ; caseStart: // IEEE: part of case_statement yCASE '(' expr ')' { } | yCASEX '(' expr ')' { } | yCASEZ '(' expr ')' { } ; caseAttrE: /*empty*/ { } ; case_patternListE: // IEEE: case_pattern_item // &&& is part of expr so aliases to case_itemList case_itemListE { } ; case_itemListE: // IEEE: [ { case_item } ] /* empty */ { } | case_itemList { } ; case_insideListE: // IEEE: [ { case_inside_item } ] /* empty */ { } | case_inside_itemList { } ; case_itemList: // IEEE: { case_item + ... } caseCondList ':' stmtBlock { } | yDEFAULT ':' stmtBlock { } | yDEFAULT stmtBlock { } | case_itemList caseCondList ':' stmtBlock { } | case_itemList yDEFAULT stmtBlock { } | case_itemList yDEFAULT ':' stmtBlock { } ; case_inside_itemList: // IEEE: { case_inside_item + open_range_list ... } open_range_list ':' stmtBlock { } | yDEFAULT ':' stmtBlock { } | yDEFAULT stmtBlock { } | case_inside_itemList open_range_list ':' stmtBlock { } | case_inside_itemList yDEFAULT stmtBlock { } | case_inside_itemList yDEFAULT ':' stmtBlock { } ; open_range_list: // ==IEEE: open_range_list + open_value_range open_value_range { } | open_range_list ',' open_value_range { } ; open_value_range: // ==IEEE: open_value_range value_range { } ; value_range: // ==IEEE: value_range expr { } | '[' expr ':' expr ']' { } ; covergroup_value_range: // ==IEEE-2012: covergroup_value_range cgexpr { } | '[' cgexpr ':' cgexpr ']' { } ; caseCondList: // IEEE: part of case_item expr { } | caseCondList ',' expr { } ; patternNoExpr: // IEEE: pattern **Excluding Expr* '.' id/*variable*/ { $$=$1; $$="."+$2; } | yP_DOTSTAR { $$=$1; $$=".*"; } // // IEEE: "expr" excluded; expand in callers // // "yTAGGED id [expr]" Already part of expr | yTAGGED id/*member_identifier*/ patternNoExpr { $$=$1; $$=" tagged "+$2+" "+$3; } // // "yP_TICKBRA patternList '}'" part of expr under assignment_pattern ; patternList: // IEEE: part of pattern patternOne { $$=$1; $$=$1; } | patternList ',' patternOne { $$=$1; $$=$1+","+$3; } ; patternOne: // IEEE: part of pattern expr { $$=$1; $$=$1; } | expr '{' argsExprList '}' { $$=$1; $$=$1; } | patternNoExpr { $$=$1; $$=$1; } ; patternMemberList: // IEEE: part of pattern and assignment_pattern patternKey ':' expr { $$=$1; $$=$1+" : "+$2; } | patternKey ':' patternNoExpr { $$=$1; $$=$1+" : "+$2; } | patternMemberList ',' patternKey ':' expr { $$=$1; $$=$1+","+$3+":"+$4; } | patternMemberList ',' patternKey ':' patternNoExpr { $$=$1; $$=$1+","+$3+":"+$4; } ; patternKey: // IEEE: merge structure_pattern_key, array_pattern_key, assignment_pattern_key // // IEEE: structure_pattern_key // // id/*member*/ is part of constExpr below constExpr { $$=$1; $$=$1; } // // IEEE: assignment_pattern_key | yDEFAULT { $$=$1; $$=$1; } | simple_type { $$=$1; $$=$1; } // // simple_type reference looks like constExpr ; assignment_pattern: // ==IEEE: assignment_pattern // This doesn't match the text of the spec. I think a : is missing, or example code needed // yP_TICKBRA constExpr exprList '}' { $$="'{"+$2+" "+$3"}"; } // // "'{ const_expression }" is same as patternList with one entry // // From patternNoExpr // // also IEEE: "''{' expression { ',' expression } '}'" // // matches since patternList includes expr yP_TICKBRA patternList '}' { $$=$1; $$="'{"+$2+"}"; } // // From patternNoExpr // // also IEEE "''{' structure_pattern_key ':' ... // // also IEEE "''{' array_pattern_key ':' ... | yP_TICKBRA patternMemberList '}' { $$=$1; $$="'{"+$2+"}"; } // // IEEE: Not in grammar, but in VMM | yP_TICKBRA '}' { $$=$1; $$="'{}"; } ; // "datatype id = x {, id = x }" | "yaId = x {, id=x}" is legal for_initialization: // ==IEEE: for_initialization + for_variable_declaration + extra terminating ";" // // IEEE: for_variable_declaration for_initializationItemList ';' { } // // IEEE: 1800-2017 empty initialization | ';' { } ; for_initializationItemList: // IEEE: [for_variable_declaration...] for_initializationItem { } | for_initializationItemList ',' for_initializationItem { } ; for_initializationItem: // IEEE: variable_assignment + for_variable_declaration // // IEEE: for_variable_declaration data_type idAny/*new*/ '=' expr { VARDTYPE($1); } // // IEEE-2012: | yVAR data_type idAny/*new*/ '=' expr { VARDTYPE($1); } // // IEEE: variable_assignment | variable_lvalue '=' expr { } ; for_stepE: // IEEE: for_step + empty /* empty */ { } | for_step { } ; for_step: // IEEE: for_step for_step_assignment { } | for_step ',' for_step_assignment { } ; for_step_assignment: // ==IEEE: for_step_assignment operator_assignment { } // | inc_or_dec_expression { } // // IEEE: subroutine_call | function_subroutine_callNoMethod { } // // method_call:array_method requires a '.' | expr '.' array_methodNoRoot { } | exprScope { } ; loop_variables: // ==IEEE: loop_variables id { $$=$1; $$=$1; } | loop_variables ',' id { $$=$1; $$=$1+","+$3; } ; //************************************************ // Functions/tasks funcRef: // IEEE: part of tf_call // // package_scope/hierarchical_... is part of expr, so just need ID // // making-a id-is-a // // ----------------- ------------------ // // tf_call tf_identifier expr (list_of_arguments) // // method_call(post .) function_identifier expr (list_of_arguments) // // property_instance property_identifier property_actual_arg // // sequence_instance sequence_identifier sequence_actual_arg // // let_expression let_identifier let_actual_arg // id '(' pev_list_of_argumentsE ')' { $$=$1; $$=$1+"("+$3+")"; } | package_scopeIdFollows id '(' pev_list_of_argumentsE ')' { $$=$2; $$=$1+$2+"("+$4+")"; } | class_scope_id '(' pev_list_of_argumentsE ')' { $$=$1; $$=$1+"("+$3+")"; } ; task_subroutine_callNoMethod: // function_subroutine_callNoMethod (as task) // // IEEE: tf_call funcRef { $$=$1; $$=$1; } | funcRef yWITH__PAREN '(' expr ')' { $$=$1; $$=$1+" "+$2+$3+$4+$5; } | system_t_call { $$=$1; $$=$1; } // // IEEE: method_call requires a "." so is in expr // // IEEE: ['std::'] not needed, as normal std package resolution will find it // // IEEE: randomize_call // // We implement randomize as a normal funcRef, since randomize isn't a keyword // // Note yNULL is already part of expressions, so they come for free | funcRef yWITH__CUR constraint_block { $$=$1; $$=$1+" with..."; } ; function_subroutine_callNoMethod: // IEEE: function_subroutine_call (as function) // // IEEE: tf_call funcRef { $$=$1; $$=$1; } | funcRef yWITH__PAREN '(' expr ')' { $$=$1; $$=$1+" "+$2+$3+$4+$5; } | system_f_call { $$=$1; $$=$1; } // // IEEE: method_call requires a "." so is in expr // // IEEE: ['std::'] not needed, as normal std package resolution will find it // // IEEE: randomize_call // // We implement randomize as a normal funcRef, since randomize isn't a keyword // // Note yNULL is already part of expressions, so they come for free | funcRef yWITH__CUR constraint_block { $$=$1; $$=$1+" with..."; } ; system_t_call: // IEEE: system_tf_call (as task) system_f_call { $$=$1; $$ = $1; } ; system_f_call: // IEEE: system_tf_call (as func) ygenSYSCALL parenE { $$=$1; $$ = $1; } // // Allow list of data_type to support "x,,,y" | ygenSYSCALL '(' exprOrDataTypeList ')' { $$=$1; $$ = $1+"("+$3+")"; } // // Standard doesn't explicity list system calls // // But these match elaboration calls in 1800-2009 | yD_FATAL parenE { $$=$1; $$ = $1; } | yD_FATAL '(' exprOrDataTypeList ')' { $$=$1; $$ = $1+"("+$3+")"; } | yD_ERROR parenE { $$=$1; $$ = $1; } | yD_ERROR '(' exprOrDataTypeList ')' { $$=$1; $$ = $1+"("+$3+")"; } | yD_WARNING parenE { $$=$1; $$ = $1; } | yD_WARNING '(' exprOrDataTypeList ')' { $$=$1; $$ = $1+"("+$3+")"; } | yD_INFO parenE { $$=$1; $$ = $1; } | yD_INFO '(' exprOrDataTypeList ')' { $$=$1; $$ = $1+"("+$3+")"; } ; elaboration_system_task: // IEEE: elaboration_system_task (1800-2009) // // $fatal first argument is exit number, must be constant yD_FATAL parenE ';' { $$=$1; $$ = $1; NEED_S09($1,"elaboration system tasks"); } | yD_FATAL '(' exprOrDataTypeList ')' ';' { $$=$1; $$ = $1+"("+$3+")"; NEED_S09($1,"elaboration system tasks"); } | yD_ERROR parenE ';' { $$=$1; $$ = $1; NEED_S09($1,"elaboration system tasks"); } | yD_ERROR '(' exprOrDataTypeList ')' ';' { $$=$1; $$ = $1+"("+$3+")"; NEED_S09($1,"elaboration system tasks"); } | yD_WARNING parenE ';' { $$=$1; $$ = $1; NEED_S09($1,"elaboration system tasks"); } | yD_WARNING '(' exprOrDataTypeList ')' ';' {$$=$1; $$ = $1+"("+$3+")"; NEED_S09($1,"elaboration system tasks"); } | yD_INFO parenE ';' { $$=$1; $$ = $1; NEED_S09($1,"elaboration system tasks"); } | yD_INFO '(' exprOrDataTypeList ')' ';' { $$=$1; $$ = $1+"("+$3+")"; NEED_S09($1,"elaboration system tasks"); } ; property_actual_arg: // ==IEEE: property_actual_arg // // IEEE: property_expr // // IEEE: sequence_actual_arg pev_expr { $$=$1; $$=$1; } // // IEEE: sequence_expr // // property_expr already includes sequence_expr ; task: yTASK__ETC { $$=$1; } | yTASK__aPUREV { $$=$1; } ; task_declaration: // IEEE: task_declaration yTASK__ETC lifetimeE taskId tfGuts yENDTASK endLabelE { PARSEP->endtaskfuncCb($5,$5); PARSEP->symPopScope(VAstType::TASK); } | yTASK__aPUREV lifetimeE taskId tfGutsPureV { PARSEP->endtaskfuncCb($1,"endtask"); PARSEP->symPopScope(VAstType::TASK); } ; task_prototype: // ==IEEE: task_prototype // // IEEE: has '(' tf_port_list ')' // // However the () should be optional for OVA task taskId '(' tf_port_listE ')' { PARSEP->symPopScope(VAstType::TASK); PARSEP->endtaskfuncCb($1,"endtask"); } | task taskId { PARSEP->symPopScope(VAstType::TASK); PARSEP->endtaskfuncCb($1,"endtask"); } ; function: yFUNCTION__ETC { $$=$1; } | yFUNCTION__aPUREV { $$=$1; } ; function_declaration: // IEEE: function_declaration + function_body_declaration yFUNCTION__ETC lifetimeE funcId tfGuts yENDFUNCTION endLabelE { PARSEP->endtaskfuncCb($5,$5); PARSEP->symPopScope(VAstType::FUNCTION); } | yFUNCTION__ETC lifetimeE funcIdNew tfGuts yENDFUNCTION endLabelE { PARSEP->endtaskfuncCb($5,$5); PARSEP->symPopScope(VAstType::FUNCTION); } | yFUNCTION__aPUREV lifetimeE funcId tfGutsPureV { PARSEP->endtaskfuncCb($1,"endfunction"); PARSEP->symPopScope(VAstType::FUNCTION); } | yFUNCTION__aPUREV lifetimeE funcIdNew tfGutsPureV { PARSEP->endtaskfuncCb($1,"endfunction"); PARSEP->symPopScope(VAstType::FUNCTION); } ; function_prototype: // IEEE: function_prototype // // IEEE: has '(' tf_port_list ')' // // However the () should be optional for OVA function funcId '(' tf_port_listE ')' { PARSEP->symPopScope(VAstType::FUNCTION); PARSEP->endtaskfuncCb($1,"endfunction"); } | function funcId { PARSEP->symPopScope(VAstType::FUNCTION); PARSEP->endtaskfuncCb($1,"endfunction"); } ; class_constructor_prototype: // ==IEEE: class_constructor_prototype function funcIdNew '(' tf_port_listE ')' ';' { PARSEP->symPopScope(VAstType::FUNCTION); PARSEP->endtaskfuncCb($1,"endfunction"); } | function funcIdNew ';' { PARSEP->symPopScope(VAstType::FUNCTION); PARSEP->endtaskfuncCb($1,"endfunction"); } ; method_prototype: task_prototype { } | function_prototype { } ; lifetimeE: // IEEE: [lifetime] /* empty */ { } | lifetime { } ; lifetime: // ==IEEE: lifetime // // Note lifetime used by members is instead under memberQual ySTATIC__ETC { } | yAUTOMATIC { } ; taskId: tfIdScoped { PARSEP->symPushNewUnder(VAstType::TASK, $1, $1); PARSEP->taskCb($1,"task",$1); } ; funcId: // IEEE: function_data_type_or_implicit + part of function_body_declaration // // IEEE: function_data_type_or_implicit must be expanded here to prevent conflict // // function_data_type expanded here to prevent conflicts with implicit_type:empty vs data_type:ID /**/ tfIdScoped { PARSEP->symPushNewUnder(VAstType::FUNCTION, $1, $1); PARSEP->functionCb($1,"function",$1,""); } | signingE rangeList tfIdScoped { PARSEP->symPushNewUnder(VAstType::FUNCTION, $3, $3); PARSEP->functionCb($3,"function",$3,SPACED($1,$2)); } | signing tfIdScoped { PARSEP->symPushNewUnder(VAstType::FUNCTION, $2, $2); PARSEP->functionCb($2,"function",$2,$1); } | yVOID tfIdScoped { PARSEP->symPushNewUnder(VAstType::FUNCTION, $2, $2); PARSEP->functionCb($2,"function",$2,$1); } | data_type tfIdScoped { PARSEP->symPushNewUnder(VAstType::FUNCTION, $2, $2); PARSEP->functionCb($2,"function",$2,$1); } ; funcIdNew: // IEEE: from class_constructor_declaration yNEW__ETC { PARSEP->symPushNewUnder(VAstType::FUNCTION, "new", NULL); PARSEP->functionCb($1,"function","new",""); } | yNEW__PAREN { PARSEP->symPushNewUnder(VAstType::FUNCTION, "new", NULL); PARSEP->functionCb($1,"function","new",""); } | class_scopeWithoutId yNEW__PAREN { PARSEP->symPushNewUnder(VAstType::FUNCTION, "new", $1); PARSEP->functionCb($2,"function","new",""); } ; tfIdScoped: // IEEE: part of function_body_declaration/task_body_declaration // // IEEE: [ interface_identifier '.' | class_scope ] function_identifier id { $$=$1; $$=NULL; $$ = $1; } | id/*interface_identifier*/ '.' id { $$=$1; $$=NULL; $$ = $1+"."+$2; } | class_scope_id { $$=$1; $$=$1; $$ = $1; } ; tfGuts: '(' tf_port_listE ')' ';' tfBodyE { } | ';' tfBodyE { } ; tfGutsPureV: '(' tf_port_listE ')' ';' { } | ';' { } ; tfBodyE: // IEEE: part of function_body_declaration/task_body_declaration /* empty */ { } | tf_item_declarationList { } | tf_item_declarationList stmtList { } | stmtList { } ; function_data_type: // IEEE: function_data_type yVOID { $$ = $1; } | data_type { $$ = $1; } ; tf_item_declarationList: tf_item_declaration { } | tf_item_declarationList tf_item_declaration { } ; tf_item_declaration: // ==IEEE: tf_item_declaration block_item_declaration { } | tf_port_declaration { } ; tf_port_listE: // IEEE: tf_port_list + empty // // Empty covered by tf_port_item { VARRESET_LIST(""); VARIO("input"); } tf_port_listList { VARRESET_NONLIST(""); } ; tf_port_listList: // IEEE: part of tf_port_list tf_port_item { } | tf_port_listList ',' tf_port_item { } ; tf_port_item: // ==IEEE: tf_port_item // // We split tf_port_item into the type and assignment as don't know what follows a comma /* empty */ { PINNUMINC(); } // For example a ",," port | tf_port_itemFront tf_port_itemAssignment { PINNUMINC(); } | tf_port_itemAssignment { PINNUMINC(); } ; tf_port_itemFront: // IEEE: part of tf_port_item, which has the data type data_type { VARDTYPE($1); } | signingE rangeList { VARDTYPE(SPACED($1,$2)); } | signing { VARDTYPE($1); } | yVAR data_type { VARDTYPE($2); } | yVAR implicit_typeE { VARDTYPE($2); } // | tf_port_itemDir /*implicit*/ { VARDTYPE(""); /*default_nettype-see spec*/ } | tf_port_itemDir data_type { VARDTYPE($2); } | tf_port_itemDir signingE rangeList { VARDTYPE(SPACED($2,$3)); } | tf_port_itemDir signing { VARDTYPE($2); } | tf_port_itemDir yVAR data_type { VARDTYPE($3); } | tf_port_itemDir yVAR implicit_typeE { VARDTYPE($3); } ; tf_port_itemDir: // IEEE: part of tf_port_item, direction port_direction { } // port_direction sets VARIO ; tf_port_itemAssignment: // IEEE: part of tf_port_item, which has assignment id variable_dimensionListE sigAttrListE { VARDONE($1, $1, $2, ""); } | id variable_dimensionListE sigAttrListE '=' expr { VARDONE($1, $1, $2, $5); } ; parenE: /* empty */ { } | '(' ')' { } ; // method_call: // ==IEEE: method_call + method_call_body // // IEEE: method_call_root '.' method_identifier [ '(' list_of_arguments ')' ] // // "method_call_root '.' method_identifier" looks just like "expr '.' id" // // "method_call_root '.' method_identifier (...)" looks just like "expr '.' tf_call" // // IEEE: built_in_method_call // // method_call_root not needed, part of expr resolution // // What's left is below array_methodNoRoot array_methodNoRoot: // ==IEEE: built_in_method_call without root // // method_call_root not needed, part of expr resolution array_method_nameNoId method_callWithE { $$=$1; $$=$1+$2; } | array_method_nameNoId '(' list_of_argumentsE ')' method_callWithE { $$=$1; $$=$1+$2+$3+$4+$5; } // // "method_call_root '.' randomize_call" matches function_subroutine_call:randomize_call ; method_callWithE: // // Code duplicated elsewhere /* empty */ { $$=""; } | yWITH__PAREN '(' expr ')' { $$=$1; $$=$1+$2+$3+$4; } ; array_method_nameNoId: // IEEE: array_method_name minus method_identifier yUNIQUE { $$=$1; $$=$1; } | yAND { $$=$1; $$=$1; } | yOR { $$=$1; $$=$1; } | yXOR { $$=$1; $$=$1; } ; dpi_import_export: // ==IEEE: dpi_import_export yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE function_prototype ';' { } | yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE task_prototype ';' { } | yEXPORT yaSTRING dpi_importLabelE function idAny ';' { } | yEXPORT yaSTRING dpi_importLabelE task idAny ';' { } ; dpi_importLabelE: // IEEE: part of dpi_import_export /* empty */ { } | idAny/*c_identifier*/ '=' { } ; dpi_tf_import_propertyE: // IEEE: [ dpi_function_import_property + dpi_task_import_property ] /* empty */ { } | yCONTEXT { } | yPURE { } ; overload_declaration: // ==IEEE: overload_declaration // // OLD: Overloads deprecated in IEEE 1800-2017 yBIND overload_operator function data_type idAny/*new-function_identifier*/ '(' overload_proto_formals ')' ';' { } ; overload_operator: // ==IEEE: overload_operator "+" { $$="+"; } | yP_PLUSPLUS { $$="++"; } | "-" { $$="-"; } | yP_MINUSMINUS { $$="--"; } | "*" { $$="*"; } | yP_POW { $$="**"; } | "/" { $$="/"; } | "%" { $$="%"; } | yP_EQUAL { $$="=="; } | yP_NOTEQUAL { $$="!="; } | "<" { $$="<"; } | yP_LTE { $$="<="; } | ">" { $$=">"; } | yP_GTE { $$=">="; } | "=" { $$="="; } ; overload_proto_formals: // ==IEEE: overload_proto_formals data_type { } | overload_proto_formals ',' data_type { } ; //************************************************ // Expressions // // ~l~ means this is the (l)eft hand side of any operator // it will get replaced by "", "f" or "s"equence // ~r~ means this is a (r)ight hand later expansion in the same statement, // not under parenthesis for <= disambiguation // it will get replaced by "", or "f" // ~p~ means this is a (p)arenthetized expression // it will get replaced by "", or "s"equence constExpr: expr { $$=$1; $$ = $1; } ; expr: // IEEE: part of expression/constant_expression/primary // *SEE BELOW* // IEEE: primary/constant_primary // // // IEEE: unary_operator primary '+' ~r~expr %prec prUNARYARITH { $$=$1; $$ = $1+$2; } | '-' ~r~expr %prec prUNARYARITH { $$=$1; $$ = $1+$2; } | '!' ~r~expr %prec prNEGATION { $$=$1; $$ = $1+$2; } | '&' ~r~expr %prec prREDUCTION { $$=$1; $$ = $1+$2; } | '~' ~r~expr %prec prNEGATION { $$=$1; $$ = $1+$2; } | '|' ~r~expr %prec prREDUCTION { $$=$1; $$ = $1+$2; } | '^' ~r~expr %prec prREDUCTION { $$=$1; $$ = $1+$2; } | yP_NAND ~r~expr %prec prREDUCTION { $$=$1; $$ = $1+$2; } | yP_NOR ~r~expr %prec prREDUCTION { $$=$1; $$ = $1+$2; } | yP_XNOR ~r~expr %prec prREDUCTION { $$=$1; $$ = $1+$2; } // // // IEEE: inc_or_dec_expression | ~l~inc_or_dec_expression { $$=$1; $$ = $1; } // // // IEEE: '(' operator_assignment ')' // // Need exprScope of variable_lvalue to prevent conflict | '(' ~p~exprScope '=' expr ')' { $$=$1; $$ = "("+$2+$3+$4+")"; } | '(' ~p~exprScope yP_PLUSEQ expr ')' { $$=$1; $$ = "("+$2+$3+$4+")"; } | '(' ~p~exprScope yP_MINUSEQ expr ')' { $$=$1; $$ = "("+$2+$3+$4+")"; } | '(' ~p~exprScope yP_TIMESEQ expr ')' { $$=$1; $$ = "("+$2+$3+$4+")"; } | '(' ~p~exprScope yP_DIVEQ expr ')' { $$=$1; $$ = "("+$2+$3+$4+")"; } | '(' ~p~exprScope yP_MODEQ expr ')' { $$=$1; $$ = "("+$2+$3+$4+")"; } | '(' ~p~exprScope yP_ANDEQ expr ')' { $$=$1; $$ = "("+$2+$3+$4+")"; } | '(' ~p~exprScope yP_OREQ expr ')' { $$=$1; $$ = "("+$2+$3+$4+")"; } | '(' ~p~exprScope yP_XOREQ expr ')' { $$=$1; $$ = "("+$2+$3+$4+")"; } | '(' ~p~exprScope yP_SLEFTEQ expr ')' { $$=$1; $$ = "("+$2+$3+$4+")"; } | '(' ~p~exprScope yP_SRIGHTEQ expr ')' { $$=$1; $$ = "("+$2+$3+$4+")"; } | '(' ~p~exprScope yP_SSRIGHTEQ expr ')' { $$=$1; $$ = "("+$2+$3+$4+")"; } // // // IEEE: expression binary_operator expression | ~l~expr '+' ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr '-' ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr '*' ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr '/' ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr '%' ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_EQUAL ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_NOTEQUAL ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_CASEEQUAL ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_CASENOTEQUAL ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_WILDEQUAL ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_WILDNOTEQUAL ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_ANDAND ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_OROR ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_POW ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr '<' ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr '>' ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_GTE ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr '&' ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr '|' ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr '^' ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_XNOR ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_NOR ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_NAND ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_SLEFT ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_SRIGHT ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_SSRIGHT ~r~expr { $$=$1; $$ = $1+$2+$3; } | ~l~expr yP_LTMINUSGT ~r~expr { $$=$1; $$ = $1+$2+$3; } // // // IEEE: expr yP_MINUSGT expr (1800-2009) // // Conflicts with constraint_expression:"expr yP_MINUSGT constraint_set" // // To duplicating expr for constraints, just allow the more general form // // Later Ast processing must ignore constraint terms where inappropriate | ~l~expr yP_MINUSGT constraint_set { $$=$1; $$ = $1+$2+$3; } // // // <= is special, as we need to disambiguate it with <= assignment // // We copy all of expr to fexpr and rename this token to a fake one. | ~l~expr yP_LTE~f__IGNORE~ ~r~expr { $$=$1; $$ = $1+$2+$3; } // // // IEEE: conditional_expression | ~l~expr '?' ~r~expr ':' ~r~expr { $$=$1; $$ = $1+"?"+$3+":"+$5; } // // // IEEE: inside_expression | ~l~expr yINSIDE '{' open_range_list '}' { $$=$1; $$ = $1+" inside {"+$3+"}"; } // // // IEEE: tagged_union_expression | yTAGGED id/*member*/ %prec prTAGGED { $$=$1; $$ = " tagged "+$1; } | yTAGGED id/*member*/ %prec prTAGGED expr { $$=$1; $$ = " tagged "+$1+" "+$2; } // //======================// IEEE: primary/constant_primary // // // IEEE: primary_literal (minus string, which is handled specially) | yaINTNUM { $$=$1; $$ = $1; } | yaFLOATNUM { $$=$1; $$ = $1; } | yaTIMENUM { $$=$1; $$ = $1; } | strAsInt~noStr__IGNORE~ { $$=$1; $$ = $1; } // // // IEEE: "... hierarchical_identifier select" see below // // // IEEE: empty_queue (IEEE 1800-2017 empty_unpacked_array_concatenation) | '{' '}' // // // IEEE: concatenation/constant_concatenation // // Part of exprOkLvalue below // // // IEEE: multiple_concatenation/constant_multiple_concatenation | '{' constExpr '{' cateList '}' '}' { $$=$1; $$ = "{"+$2+"{"+$4+"}}"; } // // IEEE: multiple_concatenation/constant_multiple_concatenation+ range_expression (1800-2009) | '{' constExpr '{' cateList '}' '}' '[' expr ']' { $$=$1; $$ = "{"+$2+"{"+$4+"}}["+$8+"]"; NEED_S09($6,"{}[]"); } | '{' constExpr '{' cateList '}' '}' '[' expr ':' expr ']' { $$=$1; $$ = "{"+$2+"{"+$4+"}}["+$8+$9+$10+"]"; NEED_S09($6,"{}[]"); } | '{' constExpr '{' cateList '}' '}' '[' expr yP_PLUSCOLON expr ']' { $$=$1; $$ = "{"+$2+"{"+$4+"}}["+$8+$9+$10+"]"; NEED_S09($6,"{}[]"); } | '{' constExpr '{' cateList '}' '}' '[' expr yP_MINUSCOLON expr ']' { $$=$1; $$ = "{"+$2+"{"+$4+"}}["+$8+$9+$10+"]"; NEED_S09($6,"{}[]"); } // | function_subroutine_callNoMethod { $$ = $1; } // // method_call | ~l~expr '.' function_subroutine_callNoMethod { $$=$1; $$=$1+"."+$3; } // // method_call:array_method requires a '.' | ~l~expr '.' array_methodNoRoot { $$=$1; $$ = $1+"."+$3; } // // // IEEE: let_expression // // see funcRef // // // IEEE: '(' mintypmax_expression ')' | ~noPar__IGNORE~'(' expr ')' { $$=$1; $$ = "("+$2+")"; } | ~noPar__IGNORE~'(' expr ':' expr ':' expr ')' { $$=$1; $$ = "("+$2+":"+$4+":"+$5+")"; } // // PSL rule | '_' '(' statePushVlg expr statePop ')' { $$=$1; $$ = "_("+$4+")"; } // Arbitrary Verilog inside PSL // // // IEEE: cast/constant_cast | casting_type yP_TICK '(' expr ')' { $$=$1; $$ = $1+"'("+$4+")"; } // // Spec only allows primary with addition of a type reference // // We'll be more general, and later assert LHS was a type. | ~l~expr yP_TICK '(' expr ')' { $$=$1; $$ = $1+"'("+$4+")"; } // // // IEEE: assignment_pattern_expression // // IEEE: streaming_concatenation // // See exprOkLvalue // // // IEEE: sequence_method_call // // Indistinguishable from function_subroutine_call:method_call // | '$' { $$=$1; $$ = "$"; } | yNULL { $$=$1; $$ = $1; } // // IEEE: yTHIS // // See exprScope // //---------------------- // // // Part of expr that may also be used as lvalue | ~l~exprOkLvalue { $$=$1; $$ = $1; } // //---------------------- // // // IEEE: cond_predicate - here to avoid reduce problems // // Note expr includes cond_pattern | ~l~expr yP_ANDANDAND ~r~expr { $$=$1; $$ = $1 + "&&&" + $3; } // // // IEEE: cond_pattern - here to avoid reduce problems // // "expr yMATCHES pattern" // // IEEE: pattern - expanded here to avoid conflicts | ~l~expr yMATCHES patternNoExpr { $$=$1; $$ = $1 + " matches " + $3; } | ~l~expr yMATCHES ~r~expr { $$=$1; $$ = $1 + " matches " + $3; } // // // IEEE: expression_or_dist - here to avoid reduce problems // // "expr yDIST '{' dist_list '}'" | ~l~expr yDIST '{' dist_list '}' { $$=$1; $$ = $1 + " dist " + $3+"..."+$5; } ; fexpr: // For use as first part of statement (disambiguates <=) BISONPRE_COPY(expr,{s/~l~/f/g; s/~r~/f/g; s/~f__IGNORE~/__IGNORE/g;}) // {copied} ; ev_expr: // IEEE: event_expression // // for yOR/, see event_expression // // // IEEE: [ edge_identifier ] expression [ yIFF expression ] // // expr alone see below senitemEdge { } | ev_expr yIFF expr { } // // // IEEE: sequence_instance [ yIFF expression ] // // seq_inst is in expr, so matches senitem rule above // // // IEEE: event_expression yOR event_expression | ev_expr yOR ev_expr { } // // IEEE: event_expression ',' event_expression // // See real event_expression rule // //--------------------- // // IEEE: expr | BISONPRE_COPY(expr,{s/~l~/ev_/g; s/~r~/ev_/g; s/~p~/ev_/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g;}) // {copied} // // // IEEE: '(' event_expression ')' // // expr:'(' x ')' conflicts with event_expression:'(' event_expression ')' // // so we use a special expression class | '(' event_expression ')' { $$=$1; $$ = "(...)"; } // // IEEE: From normal expr: '(' expr ':' expr ':' expr ')' // // But must avoid conflict | '(' event_expression ':' expr ':' expr ')' { $$=$1; $$ = "(...)"; } ; //sexpr: See elsewhere //pexpr: See elsewhere exprOkLvalue: // expression that's also OK to use as a variable_lvalue ~l~exprScope { $$=$1; $$ = $1; } // // IEEE: concatenation/constant_concatenation | '{' cateList '}' { $$=$1; $$ = "{"+$2+"}"; } // // IEEE: concatenation/constant_concatenation+ constant_range_expression (1800-2009) | '{' cateList '}' '[' expr ']' { $$=$1; $$ = "{"+$2+"}["+$5+"]"; NEED_S09($4,"{}[]"); } | '{' cateList '}' '[' expr ':' expr ']' { $$=$1; $$ = "{"+$2+"}["+$5+$6+$7+"]"; NEED_S09($4,"{}[]"); } | '{' cateList '}' '[' expr yP_PLUSCOLON expr ']' { $$=$1; $$ = "{"+$2+"}["+$5+$6+$7+"]"; NEED_S09($4,"{}[]"); } | '{' cateList '}' '[' expr yP_MINUSCOLON expr ']' { $$=$1; $$ = "{"+$2+"}["+$5+$6+$7+"]"; NEED_S09($4,"{}[]"); } // // IEEE: assignment_pattern_expression // // IEEE: [ assignment_pattern_expression_type ] == [ ps_type_id /ps_paremeter_id/data_type] // // We allow more here than the spec requires | ~l~exprScope assignment_pattern { $$=$1; $$=$1+$2; } | data_type assignment_pattern { $$=$1; $$=$1+$2; } | assignment_pattern { $$=$1; $$=$1; } // | streaming_concatenation { $$=$1; $$ = $1; } ; fexprOkLvalue: // exprOkLValue, For use as first part of statement (disambiguates <=) BISONPRE_COPY(exprOkLvalue,{s/~l~/f/g}) // {copied} ; sexprOkLvalue: // exprOkLValue, For use by sequence_expr BISONPRE_COPY(exprOkLvalue,{s/~l~/s/g}) // {copied} ; pexprOkLvalue: // exprOkLValue, For use by property_expr BISONPRE_COPY(exprOkLvalue,{s/~l~/p/g}) // {copied} ; ev_exprOkLvalue: // exprOkLValue, For use by ev_expr BISONPRE_COPY(exprOkLvalue,{s/~l~/ev_/g}) // {copied} ; pev_exprOkLvalue: // exprOkLValue, For use by ev_expr BISONPRE_COPY(exprOkLvalue,{s/~l~/pev_/g}) // {copied} ; exprLvalue: // expression that should be a variable_lvalue ~f~exprOkLvalue { $$=$1; $$ = $1; } ; fexprLvalue: // For use as first part of statement (disambiguates <=) BISONPRE_COPY(exprLvalue,{s/~f~/f/g}) // {copied} ; exprScope: // scope and variable for use to inside an expression // // Here we've split method_call_root | implicit_class_handle | class_scope | package_scope // // from the object being called and let expr's "." deal with resolving it. // // (note method_call_root was simplified to require a primary in 1800-2009) // // // IEEE: [ implicit_class_handle . | class_scope | package_scope ] hierarchical_identifier select // // Or method_call_body without parenthesis // // See also varRefClassBit, which is the non-expr version of most of this yTHIS { $$=$1; $$ = $1; } | idArrayed { $$=$1; $$ = $1; } | package_scopeIdFollows idArrayed { $$=$1; $$ = $1+$2; } | class_scopeIdFollows idArrayed { $$=$1; $$ = $1+$2; } | ~l~expr '.' idArrayed { $$=$1; $$ = $1+"."+$3; PORTNET($1, $$); } // // expr below must be a "yTHIS" | ~l~expr '.' ySUPER { $$=$1; $$ = $1+"."+$3; } // // Part of implicit_class_handle | ySUPER { $$=$1; $$ = $1; } ; fexprScope: // exprScope, For use as first part of statement (disambiguates <=) BISONPRE_COPY(exprScope,{s/~l~/f/g}) // {copied} ; sexprScope: // exprScope, For use by sequence_expr BISONPRE_COPY(exprScope,{s/~l~/s/g}) // {copied} ; pexprScope: // exprScope, For use by property_expr BISONPRE_COPY(exprScope,{s/~l~/p/g}) // {copied} ; ev_exprScope: // exprScope, For use by ev_expr BISONPRE_COPY(exprScope,{s/~l~/ev_/g}) // {copied} ; pev_exprScope: // exprScope, For use by ev_expr BISONPRE_COPY(exprScope,{s/~l~/pev_/g}) // {copied} ; // Generic expressions exprOrDataType: // expr | data_type: combined to prevent conflicts expr { $$=$1; $$ = $1; } // // data_type includes id that overlaps expr, so special flavor | data_type { $$=$1; $$ = $1; } // // not in spec, but needed for $past(sig,1,,@(posedge clk)) | event_control { $$ = "event_control"; } ; exprOrDataTypeOrMinTypMax: // exprOrDataType or mintypmax_expression expr { $$=$1; $$ = $1; } | expr ':' expr ':' expr { $$=$1; $$ = $1+$2+$3+$4+$5; } // // data_type includes id that overlaps expr, so special flavor | data_type { $$=$1; $$ = $1; } // // not in spec, but needed for $past(sig,1,,@(posedge clk)) | event_control { $$ = "event_control"; } ; cateList: // // Not just 'expr' to prevent conflict via stream_concOrExprOrType stream_expression { $$=$1; $$ = $1; PIN_CONCAT_APPEND($1); } | cateList ',' stream_expression { $$=$1; $$ = $1+","+$3; PIN_CONCAT_APPEND($3); } ; exprOrDataTypeList: exprOrDataType { $$=$1; $$ = $1; } | exprOrDataTypeList ',' exprOrDataType { $$=$1; $$ = $1+","+$3; } | exprOrDataTypeList ',' { $$=$1; $$ = $1+","; } // Verilog::Parser only: ,, is ok ; list_of_argumentsE: // IEEE: [list_of_arguments] // // See comments under funcRef argsDottedList { $$=$1; $$=$1; } | argsExprListE { $$=$1; $$=$1; } | argsExprListE ',' argsDottedList { $$=$1; $$=$1+","+$3; } ; pev_list_of_argumentsE: // IEEE: [list_of_arguments] - pev_expr at bottom // // See comments under funcRef pev_argsDottedList { $$=$1; $$=$1; } | pev_argsExprListE { $$=$1; $$=$1; } | pev_argsExprListE ',' pev_argsDottedList { $$=$1; $$=$1+","+$3; } ; argsExprList: // IEEE: part of list_of_arguments (used where ,, isn't legal) expr { $$=$1; $$ = $1; } | argsExprList ',' expr { $$=$1; $$ = $1+","+$3; } ; argsExprListE: // IEEE: part of list_of_arguments argsExprOneE { $$=$1; $$ = $1; } | argsExprListE ',' argsExprOneE { $$=$1; $$ = $1+","+$3; } ; pev_argsExprListE: // IEEE: part of list_of_arguments - pev_expr at bottom pev_argsExprOneE { $$=$1; $$ = $1; } | pev_argsExprListE ',' pev_argsExprOneE { $$=$1; $$ = $1+","+$3; } ; argsExprOneE: // IEEE: part of list_of_arguments /*empty*/ { $$ = ""; } // ,, is legal in list_of_arguments | expr { $$=$1; $$ = $1; } ; pev_argsExprOneE: // IEEE: part of list_of_arguments - pev_expr at bottom /*empty*/ { $$ = ""; } // ,, is legal in list_of_arguments | pev_expr { $$=$1; $$ = $1; } ; argsDottedList: // IEEE: part of list_of_arguments argsDotted { $$=$1; $$=$1; } | argsDottedList ',' argsDotted { $$=$1; $$=$1+","+$3; } ; pev_argsDottedList: // IEEE: part of list_of_arguments - pev_expr at bottom pev_argsDotted { $$=$1; $$=$1; } | pev_argsDottedList ',' pev_argsDotted { $$=$1; $$=$1+","+$3; } ; argsDotted: // IEEE: part of list_of_arguments '.' idAny '(' ')' { $$=$1; $$=$1+$2+$3+$4; } | '.' idAny '(' expr ')' { $$=$1; $$=$1+$2+$3+$4+$5; } ; pev_argsDotted: // IEEE: part of list_of_arguments - pev_expr at bottom '.' idAny '(' ')' { $$=$1; $$=$1+$2+$3+$4; } | '.' idAny '(' pev_expr ')' { $$=$1; $$=$1+$2+$3+$4+$5; } ; streaming_concatenation: // ==IEEE: streaming_concatenation // // Need to disambiguate {<< expr-{ ... expr-} stream_concat } // // From {<< stream-{ ... stream-} } // // Likewise simple_type's idScoped from constExpr's idScope // // Thus we allow always any two operations. Sorry // // IEEE: "'{' yP_SL/R stream_concatenation '}'" // // IEEE: "'{' yP_SL/R simple_type stream_concatenation '}'" // // IEEE: "'{' yP_SL/R constExpr stream_concatenation '}'" '{' yP_SLEFT stream_concOrExprOrType '}' { $$=$1; $$="{<<"+$3+"}"; } | '{' yP_SRIGHT stream_concOrExprOrType '}' { $$=$1; $$="{>>"+$3+"}"; } | '{' yP_SLEFT stream_concOrExprOrType stream_concatenation '}' { $$=$1; $$="{<<"+$3+" "+$4+"}"; } | '{' yP_SRIGHT stream_concOrExprOrType stream_concatenation '}' { $$=$1; $$="{>>"+$3+" "+$4+"}"; } ; stream_concOrExprOrType: // IEEE: stream_concatenation | slice_size:simple_type | slice_size:constExpr cateList { $$=$1; $$=$1; } | simple_type { $$=$1; $$=$1; } // // stream_concatenation found via cateList:stream_expr:'{-normal-concat' // // simple_typeRef found via cateList:stream_expr:expr:id // // constant_expression found via cateList:stream_expr:expr ; stream_concatenation: // ==IEEE: stream_concatenation '{' stream_expressionList '}' { $$=$1; $$="{"+$2+"}"; } ; stream_expressionList: // IEEE: part of stream_concatenation stream_expression { $$=$1; $$=$1; } | stream_expressionList ',' stream_expression { $$=$1; $$=$1+","+$3; } ; stream_expression: // ==IEEE: stream_expression // // IEEE: array_range_expression expanded below expr { $$=$1; $$=$1; } | expr yWITH__BRA '[' expr ']' { $$=$1; $$=$1; } | expr yWITH__BRA '[' expr ':' expr ']' { $$=$1; $$=$1; } | expr yWITH__BRA '[' expr yP_PLUSCOLON expr ']' { $$=$1; $$=$1; } | expr yWITH__BRA '[' expr yP_MINUSCOLON expr ']' { $$=$1; $$=$1; } ; //************************************************ // Gate declarations // We can't tell between UDPs and modules as they aren't declared yet. // For simplicity, assume everything is a module, perhaps nameless, // and deal with it later. // IEEE: cmos_switchtype + enable_gatetype + mos_switchtype // + n_input_gatetype + n_output_gatetype + pass_en_switchtype // + pass_switchtype gateKwd: ygenGATE { $$=$1; INSTPREP($1,0,0); } | yAND { $$=$1; INSTPREP($1,0,0); } | yBUF { $$=$1; INSTPREP($1,0,0); } | yNAND { $$=$1; INSTPREP($1,0,0); } | yNOR { $$=$1; INSTPREP($1,0,0); } | yNOT { $$=$1; INSTPREP($1,0,0); } | yOR { $$=$1; INSTPREP($1,0,0); } | yXNOR { $$=$1; INSTPREP($1,0,0); } | yXOR { $$=$1; INSTPREP($1,0,0); } ; // This list is also hardcoded in VParseLex.l strength: // IEEE: strength0+strength1 - plus HIGHZ/SMALL/MEDIUM/LARGE ygenSTRENGTH { } | ySUPPLY0 { } | ySUPPLY1 { } ; strengthSpecE: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty /* empty */ { } | strengthSpec { } ; strengthSpec: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty yP_PAR__STRENGTH strength ')' { } | yP_PAR__STRENGTH strength ',' strength ')' { } ; //************************************************ // Tables combinational_body: // IEEE: combinational_body + sequential_body yTABLE tableJunkList yENDTABLE { } ; tableJunkList: tableJunk { } /* ignored */ | tableJunkList tableJunk { } /* ignored */ ; tableJunk: BISONPRE_NOT(yTABLE,yENDTABLE) { } | yTABLE tableJunk yENDTABLE { } | error {} ; //************************************************ // Specify specify_block: // ==IEEE: specify_block ySPECIFY specifyJunkList yENDSPECIFY { } | ySPECIFY yENDSPECIFY { } ; specifyJunkList: specifyJunk { } /* ignored */ | specifyJunkList specifyJunk { } /* ignored */ ; specifyJunk: BISONPRE_NOT(ySPECIFY,yENDSPECIFY) { } | ySPECIFY specifyJunk yENDSPECIFY { } | error {} ; specparam_declaration: // ==IEEE: specparam_declaration ySPECPARAM junkToSemiList ';' { } ; junkToSemiList: junkToSemi { } /* ignored */ | junkToSemiList junkToSemi { } /* ignored */ ; junkToSemi: BISONPRE_NOT(';',yENDSPECIFY,yENDMODULE) { } | error {} ; //************************************************ // IDs id: yaID__ETC { $$=$1; $$=$1; } ; idAny: // Any kind of identifier yaID__aPACKAGE { $$=$1; $$=$1; } | yaID__aTYPE { $$=$1; $$=$1; } | yaID__ETC { $$=$1; $$=$1; } ; idSVKwd: // Warn about non-forward compatible Verilog 2001 code // // yBIT, yBYTE won't work here as causes conflicts yDO { $$=$1; $$=$1; ERRSVKWD($1,$$); } | yFINAL { $$=$1; $$=$1; ERRSVKWD($1,$$); } ; variable_lvalue: // IEEE: variable_lvalue or net_lvalue // // Note many variable_lvalue's must use exprOkLvalue when arbitrary expressions may also exist idClassSel { $$=$1; $$ = $1; } | '{' variable_lvalueConcList '}' { $$=$1; $$ = $1+$2+$3; } // // IEEE: [ assignment_pattern_expression_type ] assignment_pattern_variable_lvalue // // We allow more assignment_pattern_expression_types then strictly required | data_type yP_TICKBRA variable_lvalueList '}' { $$=$1; $$ = $1+" "+$2+$3+$4; } | idClassSel yP_TICKBRA variable_lvalueList '}' { $$=$1; $$ = $1+" "+$2+$3+$4; } | /**/ yP_TICKBRA variable_lvalueList '}' { $$=$1; $$ = $1+$2+$3; } | streaming_concatenation { $$=$1; $$ = $1; } ; variable_lvalueConcList: // IEEE: part of variable_lvalue: '{' variable_lvalue { ',' variable_lvalue } '}' variable_lvalue { $$=$1; $$ = $1; } | variable_lvalueConcList ',' variable_lvalue { $$=$1; $$ = $1+","+$3; } ; variable_lvalueList: // IEEE: part of variable_lvalue: variable_lvalue { ',' variable_lvalue } variable_lvalue { $$=$1; $$ = $1; } | variable_lvalueList ',' variable_lvalue { $$=$1; $$ = $1+","+$3; } ; idClassSel: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable idDotted { $$=$1; $$ = $1; } // // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select | yTHIS '.' idDotted { $$=$1; $$ = "this."+$3; } | ySUPER '.' idDotted { $$=$1; $$ = "super."+$3; } | yTHIS '.' ySUPER '.' idDotted { $$=$1; $$ = "this.super."+$3; } // // Expanded: package_scope idDotted | class_scopeIdFollows idDotted { $$=$1; $$ = $1+$2; } | package_scopeIdFollows idDotted { $$=$1; $$ = $1+$2; } ; idClassForeach: // Misc Ref to dotted, and/or arrayed, no bit range for foreach statement // // We can't just use the more general idClassSel // // because ,'s are allowed in the []'s idDottedForeach { $$=$1; $$ = $1; } // // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select | yTHIS '.' idDottedForeach { $$=$1; $$ = "this."+$3; } | ySUPER '.' idDottedForeach { $$=$1; $$ = "super."+$3; } | yTHIS '.' ySUPER '.' idDottedForeach { $$=$1; $$ = "this.super."+$3; } // // Expanded: package_scope idDotted | class_scopeIdFollows idDottedForeach { $$=$1; $$ = $1+$2; } | package_scopeIdFollows idDottedForeach { $$=$1; $$ = $1+$2; } ; hierarchical_identifierList: // IEEE: part of wait_statement hierarchical_identifier { } | hierarchical_identifierList ',' hierarchical_identifier { } ; hierarchical_identifierBit: // IEEE: "hierarchical_identifier bit_select" // // Not in grammar but "this." believed legal here idClassSel { } ; hierarchical_identifier: // IEEE: hierarchical_identifier, including extra bit_select // // +hierarchical_parameter_identifier // // Not in grammar but "this." believed legal here idClassSel { $$=$1; $$ = $1; } ; idDotted: yD_ROOT '.' idDottedMore { $$=$1; $$ = $1+"."+$3; } | idDottedMore { $$=$1; $$ = $1; } ; idDottedForeach: yD_ROOT '.' idDottedForeachMore { $$=$1; $$ = $1+"."+$3; } | idDottedForeachMore { $$=$1; $$ = $1; } ; idDottedMore: idArrayed { $$=$1; $$ = $1; } | idDottedMore '.' idArrayed { $$=$1; $$ = $1+"."+$3; } ; idDottedForeachMore: idForeach { $$=$1; $$ = $1; } | idDottedForeachMore '.' idForeach { $$=$1; $$ = $1+"."+$3; } ; // Single component of dotted path, maybe [#]. // Due to lookahead constraints, we can't know if [:] or [+:] are valid (last dotted part), // we'll assume so and cleanup later. // id below includes: // enum_identifier idArrayed: // IEEE: id + select id { $$=$1; $$ = $1; PORTNET($1, $1);} // // IEEE: part_select_range/constant_part_select_range | idArrayed '[' expr ']' { $$=$1; $$ = $1+"["+$3+"]"; PORTRANGE($3, $3);} | idArrayed '[' constExpr ':' constExpr ']' { $$=$1; $$ = $1+"["+$3+":"+$5+"]"; PORTRANGE($3, $5);} // // IEEE: indexed_range/constant_indexed_range | idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$=$1; $$ = $1+"["+$3+"+:"+$5+"]"; } | idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$=$1; $$ = $1+"["+$3+"-:"+$5+"]"; } ; idForeach: // IEEE: id + select + [loop_variables] // // Merge of foreach and idArrayed to prevent conflict id { $$=$1; $$ = $1; } // // IEEE: part_select_range/constant_part_select_range | idForeach '[' expr ']' { $$=$1; $$ = $1+"["+$3+"]"; } | idForeach '[' constExpr ':' constExpr ']' { $$=$1; $$ = $1+"["+$3+":"+$5+"]"; } // // IEEE: indexed_range/constant_indexed_range | idForeach '[' expr yP_PLUSCOLON constExpr ']' { $$=$1; $$ = $1+"["+$3+"+:"+$5+"]"; } | idForeach '[' expr yP_MINUSCOLON constExpr ']' { $$=$1; $$ = $1+"["+$3+"-:"+$5+"]"; } // // IEEE: part of foreach: [ loop_variables ] | idForeach '[' expr ',' loop_variables ']' { $$=$1; $$ = $1+"["+$3+","+$5+"]"; } ; strAsInt: yaSTRING { $$=$1; $$ = $1; } ; endLabelE: /* empty */ { } | ':' idAny { } | ':' yNEW__ETC { } ; //************************************************ // Clocking clocking_declaration: // IEEE: clocking_declaration clockingFront clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE { PARSEP->symPopScope(VAstType::CLOCKING); } // // global clocking below - we allow item list, though not in grammar ; clockingFront: // IEEE: part of class_declaration yCLOCKING { PARSEP->symPushNewAnon(VAstType::CLOCKING); } | yCLOCKING idAny/*clocking_identifier*/ { PARSEP->symPushNew(VAstType::CLOCKING,$2); } | yDEFAULT yCLOCKING { PARSEP->symPushNewAnon(VAstType::CLOCKING); } | yDEFAULT yCLOCKING idAny/*clocking_identifier*/ { PARSEP->symPushNew(VAstType::CLOCKING,$3); } | yGLOBAL__CLOCKING yCLOCKING { PARSEP->symPushNewAnon(VAstType::CLOCKING); } | yGLOBAL__CLOCKING yCLOCKING idAny/*clocking_identifier*/ { PARSEP->symPushNew(VAstType::CLOCKING,$3); } ; clocking_event: // ==IEEE: clocking_event '@' id { } | '@' '(' event_expression ')' { } ; clocking_itemListE: /* empty */ { } | clocking_itemList { } ; clocking_itemList: // IEEE: [ clocking_item ] clocking_item { } | clocking_itemList clocking_item { } ; clocking_item: // ==IEEE: clocking_item yDEFAULT default_skew ';' { } | clocking_direction list_of_clocking_decl_assign ';' { } | assertion_item_declaration { } ; default_skew: // ==IEEE: default_skew yINPUT clocking_skew { } | yOUTPUT clocking_skew { } | yINPUT clocking_skew yOUTPUT clocking_skew { } ; clocking_direction: // ==IEEE: clocking_direction yINPUT clocking_skewE { } | yOUTPUT clocking_skewE { } | yINPUT clocking_skewE yOUTPUT clocking_skewE { } | yINOUT { } ; list_of_clocking_decl_assign: // ==IEEE: list_of_clocking_decl_assign clocking_decl_assign { } | list_of_clocking_decl_assign ',' clocking_decl_assign { } ; clocking_decl_assign: // ==IEEE: clocking_decl_assign idAny/*new-signal_identifier*/ { } | idAny/*new-signal_identifier*/ '=' expr { } ; clocking_skewE: // IEEE: [clocking_skew] /* empty */ { } | clocking_skew { } ; clocking_skew: // ==IEEE: clocking_skew yPOSEDGE { } | yPOSEDGE delay_control { } | yNEGEDGE { } | yNEGEDGE delay_control { } | yEDGE { NEED_S09($1,"edge"); } | yEDGE delay_control { NEED_S09($1,"edge"); } | delay_control { } ; cycle_delay: // ==IEEE: cycle_delay yP_POUNDPOUND yaINTNUM { } | yP_POUNDPOUND id { } | yP_POUNDPOUND '(' expr ')' { } ; //************************************************ // Asserts assertion_item_declaration: // ==IEEE: assertion_item_declaration property_declaration { } | sequence_declaration { } | let_declaration { } ; assertion_item: // ==IEEE: assertion_item concurrent_assertion_item { } | deferred_immediate_assertion_item { } ; deferred_immediate_assertion_item: // ==IEEE: deferred_immediate_assertion_item deferred_immediate_assertion_statement { } | id/*block_identifier*/ ':' deferred_immediate_assertion_statement { } ; procedural_assertion_statement: // ==IEEE: procedural_assertion_statement concurrent_assertion_statement { } | immediate_assertion_statement { } // // IEEE: checker_instantiation // // Unlike modules, checkers are the only "id id (...)" form in statements. | checker_instantiation { } ; immediate_assertion_statement: // ==IEEE: immediate_assertion_statement simple_immediate_assertion_statement { } | deferred_immediate_assertion_statement { } ; simple_immediate_assertion_statement: // ==IEEE: simple_immediate_assertion_statement // // IEEE: simple_immediate_assert_statement yASSERT '(' expr ')' action_block { } // // IEEE: simple_immediate_assume_statement | yASSUME '(' expr ')' action_block { } // // IEEE: simple_immediate_cover_statement | yCOVER '(' expr ')' stmt { } ; deferred_immediate_assertion_statement: // ==IEEE: deferred_immediate_assertion_statement // // IEEE: deferred_immediate_assert_statement yASSERT '#' yaINTNUM '(' expr ')' action_block { } // yaINTNUM is always a '0' // // 1800-2012: | yASSERT yFINAL '(' expr ')' action_block { } // // IEEE: deferred_immediate_assume_statement | yASSUME '#' yaINTNUM '(' expr ')' action_block { } // yaINTNUM is always a '0' // // 1800-2012: | yASSUME yFINAL '(' expr ')' action_block { } // // IEEE: deferred_immediate_cover_statement | yCOVER '#' yaINTNUM '(' expr ')' stmt { } // yaINTNUM is always a '0' // // 1800-2012: | yCOVER yFINAL '(' expr ')' action_block { } ; expect_property_statement: // ==IEEE: expect_property_statement yEXPECT '(' property_spec ')' action_block { } ; concurrent_assertion_item: // IEEE: concurrent_assertion_item concurrent_assertion_statement { } | id/*block_identifier*/ ':' concurrent_assertion_statement { } // // IEEE: checker_instantiation // // identical to module_instantiation; see etcInst ; concurrent_assertion_statement: // ==IEEE: concurrent_assertion_statement // // IEEE: assert_property_statement yASSERT yPROPERTY '(' property_spec ')' action_block { } // // IEEE: assume_property_statement | yASSUME yPROPERTY '(' property_spec ')' action_block { } // // IEEE: cover_property_statement | yCOVER yPROPERTY '(' property_spec ')' stmtBlock { } // // IEEE: cover_sequence_statement | yCOVER ySEQUENCE '(' sexpr ')' stmt { } // // IEEE: yCOVER ySEQUENCE '(' clocking_event sexpr ')' stmt // // sexpr already includes "clocking_event sexpr" | yCOVER ySEQUENCE '(' clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt { } | yCOVER ySEQUENCE '(' yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt { } // // IEEE: restrict_property_statement | yRESTRICT yPROPERTY '(' property_spec ')' ';' { } ; property_declaration: // ==IEEE: property_declaration property_declarationFront property_port_listE ';' property_declarationBody yENDPROPERTY endLabelE { PARSEP->symPopScope(VAstType::PROPERTY); } ; property_declarationFront: // IEEE: part of property_declaration yPROPERTY idAny/*property_identifier*/ { PARSEP->symPushNew(VAstType::PROPERTY,$2); } ; property_port_listE: // IEEE: [ ( [ property_port_list ] ) ] /* empty */ { } | '(' {VARRESET_LIST(""); VARIO("input"); } property_port_list ')' { VARRESET_NONLIST(""); } ; property_port_list: // ==IEEE: property_port_list property_port_item { } | property_port_list ',' property_port_item { } ; property_port_item: // IEEE: property_port_item/sequence_port_item // // Merged in sequence_port_item // // IEEE: property_lvar_port_direction ::= yINPUT // // prop IEEE: [ yLOCAL [ yINPUT ] ] property_formal_type // // id {variable_dimension} [ '=' property_actual_arg ] // // seq IEEE: [ yLOCAL [ sequence_lvar_port_direction ] ] sequence_formal_type // // id {variable_dimension} [ '=' sequence_actual_arg ] property_port_itemFront property_port_itemAssignment { } ; property_port_itemFront: // IEEE: part of property_port_item/sequence_port_item // property_port_itemDirE property_formal_typeNoDt { VARDTYPE($2); } // // data_type_or_implicit | property_port_itemDirE data_type { VARDTYPE($2); } | property_port_itemDirE yVAR data_type { VARDTYPE($3); } | property_port_itemDirE yVAR implicit_typeE { VARDTYPE($3); } | property_port_itemDirE signingE rangeList { VARDTYPE(SPACED($2,$3)); } | property_port_itemDirE /*implicit*/ { /*VARDTYPE-same*/ } ; property_port_itemAssignment: // IEEE: part of property_port_item/sequence_port_item/checker_port_direction portSig variable_dimensionListE { VARDONE($1, $1, $2, ""); PINNUMINC(); } | portSig variable_dimensionListE '=' property_actual_arg { VARDONE($1, $1, $2, $4); PINNUMINC(); } ; property_port_itemDirE: /* empty */ { } | yLOCAL__ETC { } | yLOCAL__ETC port_direction { } ; property_declarationBody: // IEEE: part of property_declaration assertion_variable_declarationList property_statement_spec { } // // IEEE-2012: Incorectly hasyCOVER ySEQUENCE then property_spec here. // // Fixed in IEEE 1800-2017 | property_statement_spec { } ; assertion_variable_declarationList: // IEEE: part of assertion_variable_declaration assertion_variable_declaration { } | assertion_variable_declarationList assertion_variable_declaration { } ; sequence_declaration: // ==IEEE: sequence_declaration sequence_declarationFront sequence_port_listE ';' sequence_declarationBody yENDSEQUENCE endLabelE { PARSEP->symPopScope(VAstType::SEQUENCE); } ; sequence_declarationFront: // IEEE: part of sequence_declaration ySEQUENCE idAny/*new_sequence*/ { PARSEP->symPushNew(VAstType::SEQUENCE,$2); } ; sequence_port_listE: // IEEE: [ ( [ sequence_port_list ] ) ] // // IEEE: sequence_lvar_port_direction ::= yINPUT | yINOUT | yOUTPUT // // IEEE: [ yLOCAL [ sequence_lvar_port_direction ] ] sequence_formal_type // // id {variable_dimension} [ '=' sequence_actual_arg ] // // All this is almost identically the same as a property. // // Difference is only yINOUT/yOUTPUT (which might be added to 1800-2012) // // and yPROPERTY. So save some work. property_port_listE { } ; property_formal_typeNoDt: // IEEE: property_formal_type (w/o implicit) sequence_formal_typeNoDt { $$ = $1; } | yPROPERTY { $$ = "property"; } ; sequence_formal_typeNoDt: // ==IEEE: sequence_formal_type (w/o data_type_or_implicit) // // IEEE: data_type_or_implicit // // implicit expanded where used ySEQUENCE { $$ = "sequence"; } // // IEEE-2009: yEVENT // // already part of data_type. Removed in 1800-2012. | yUNTYPED { $$ = "untyped"; } ; sequence_declarationBody: // IEEE: part of sequence_declaration // // 1800-2012 makes ';' optional assertion_variable_declarationList sexpr { } | assertion_variable_declarationList sexpr ';' { } | sexpr { } | sexpr ';' { } ; property_spec: // IEEE: property_spec // // IEEE: [clocking_event ] [ yDISABLE yIFF '(' expression_or_dist ')' ] property_expr // // matches property_spec: "clocking_event property_expr" so we put it there yDISABLE yIFF '(' expr ')' pexpr { } | pexpr { } ; property_statement_spec: // ==IEEE: property_statement_spec // // IEEE: [ clocking_event ] [ yDISABLE yIFF '(' expression_or_dist ')' ] property_statement property_statement { } | yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' property_statement { } // // IEEE: clocking_event property_statement // // IEEE: clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' property_statement // // Both overlap pexpr:"clocking_event pexpr" the difference is // // property_statement:property_statementCaseIf so replicate it | clocking_event property_statementCaseIf { } | clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' property_statementCaseIf { } ; property_statement: // ==IEEE: property_statement // // Doesn't make sense to have "pexpr ;" in pexpr rule itself, so we split out case/if pexpr ';' { } // // Note this term replicated in property_statement_spec // // If committee adds terms, they may need to be there too. | property_statementCaseIf { } ; property_statementCaseIf: // IEEE: property_statement - minus pexpr yCASE '(' expr/*expression_or_dist*/ ')' property_case_itemList yENDCASE { } | yCASE '(' expr/*expression_or_dist*/ ')' yENDCASE { } | yIF '(' expr/*expression_or_dist*/ ')' pexpr %prec prLOWER_THAN_ELSE { } | yIF '(' expr/*expression_or_dist*/ ')' pexpr yELSE pexpr { } ; property_case_itemList: // IEEE: {property_case_item} property_case_item { } | property_case_itemList ',' property_case_item { } ; property_case_item: // ==IEEE: property_case_item // // IEEE: expression_or_dist { ',' expression_or_dist } ':' property_statement // // IEEE 1800-2012 changed from property_statement to property_expr // // IEEE 1800-2017 changed to require the semicolon caseCondList ':' pexpr { } | caseCondList ':' pexpr ';' { } | yDEFAULT pexpr { } | yDEFAULT ':' pexpr ';' { } ; pev_expr: // IEEE: property_actual_arg | expr // // which expands to pexpr | event_expression // // Used in port and function calls, when we can't know yet if something // // is a function/sequence/property or instance/checker pin. // // // '(' pev_expr ')' // // Already in pexpr // // IEEE: event_expression ',' event_expression // // ','s are legal in event_expressions, but parens required to avoid conflict with port-sep-, // // IEEE: event_expression yOR event_expression // // Already in pexpr - needs removal there // // IEEE: event_expression yIFF expr // // Already in pexpr - needs removal there // senitemEdge { $$=$1; } // //============= pexpr rules copied for pev_expr | BISONPRE_COPY_ONCE(pexpr,{s/~o~p/pev_/g; }) // {copied} // //============= sexpr rules copied for pev_expr | BISONPRE_COPY_ONCE(sexpr,{s/~p~s/pev_/g; }) // {copied} // //============= expr rules copied for pev_expr | BISONPRE_COPY_ONCE(expr,{s/~l~/pev_/g; s/~p~/pev_/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied} ; pexpr: // IEEE: property_expr (The name pexpr is important as regexps just add an "p" to expr.) // // // IEEE: sequence_expr // // Expanded below // // // IEEE: '(' pexpr ')' // // Expanded below // yNOT pexpr %prec prNEGATION { } | ySTRONG '(' sexpr ')' { } | yWEAK '(' sexpr ')' { } // // IEEE: pexpr yOR pexpr // // IEEE: pexpr yAND pexpr // // Under ~p~sexpr and/or ~p~sexpr // // // IEEE: "sequence_expr yP_ORMINUSGT pexpr" // // Instead we use pexpr to prevent conflicts | ~o~pexpr yP_ORMINUSGT pexpr { } | ~o~pexpr yP_OREQGT pexpr { } // // // IEEE-2009: property_statement // // IEEE-2012: yIF and yCASE | property_statementCaseIf { } // | ~o~pexpr/*sexpr*/ yP_POUNDMINUSPD pexpr { } | ~o~pexpr/*sexpr*/ yP_POUNDEQPD pexpr { } | yNEXTTIME pexpr { } | yS_NEXTTIME pexpr { } | yNEXTTIME '[' expr/*const*/ ']' pexpr %prec yNEXTTIME { } | yS_NEXTTIME '[' expr/*const*/ ']' pexpr %prec yS_NEXTTIME { } | yALWAYS pexpr { } | yALWAYS '[' cycle_delay_const_range_expression ']' pexpr %prec yALWAYS { } | yS_ALWAYS '[' constant_range ']' pexpr %prec yS_ALWAYS { } | yS_EVENTUALLY pexpr { } | yEVENTUALLY '[' constant_range ']' pexpr %prec yEVENTUALLY { } | yS_EVENTUALLY '[' cycle_delay_const_range_expression ']' pexpr %prec yS_EVENTUALLY { } | ~o~pexpr yUNTIL pexpr { } | ~o~pexpr yS_UNTIL pexpr { } | ~o~pexpr yUNTIL_WITH pexpr { } | ~o~pexpr yS_UNTIL_WITH pexpr { } | ~o~pexpr yIMPLIES pexpr { } // // yIFF also used by event_expression | ~o~pexpr yIFF ~o~pexpr { } | yACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec yACCEPT_ON { } | yREJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec yREJECT_ON { } | ySYNC_ACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec ySYNC_ACCEPT_ON { } | ySYNC_REJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec ySYNC_REJECT_ON { } // // // IEEE: "property_instance" // // Looks just like a function/method call // // // Note "clocking_event pexpr" overlaps property_statement_spec: clocking_event property_statement // // // Include property_specDisable to match property_spec rule | clocking_event yDISABLE yIFF '(' expr ')' pexpr %prec prSEQ_CLOCKING { } // //============= sexpr rules copied for property_expr | BISONPRE_COPY_ONCE(sexpr,{s/~p~s/p/g; }) // {copied} // //============= expr rules copied for property_expr | BISONPRE_COPY_ONCE(expr,{s/~l~/p/g; s/~p~/p/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied} ; sexpr: // ==IEEE: sequence_expr (The name sexpr is important as regexps just add an "s" to expr.) // // ********* RULES COPIED IN sequence_exprProp // // For precedence, see IEEE 17.7.1 // // // IEEE: "cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }" // // IEEE: "sequence_expr cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }" // // Both rules basically mean we can repeat sequences, so make it simpler: cycle_delay_range sexpr %prec yP_POUNDPOUND { } | ~p~sexpr cycle_delay_range sexpr %prec prPOUNDPOUND_MULTI { } // // // IEEE: expression_or_dist [ boolean_abbrev ] // // Note expression_or_dist includes "expr"! // // sexpr/*sexpression_or_dist*/ --- Hardcoded below | ~p~sexpr/*sexpression_or_dist*/ boolean_abbrev { } // // // IEEE: "sequence_instance [ sequence_abbrev ]" // // version without sequence_abbrev looks just like normal function call // // version w/sequence_abbrev matches above; expression_or_dist:expr:func boolean_abbrev:sequence_abbrev // // // IEEE: '(' expression_or_dist {',' sequence_match_item } ')' [ boolean_abbrev ] // // IEEE: '(' sexpr {',' sequence_match_item } ')' [ sequence_abbrev ] // // As sequence_expr includes expression_or_dist, and boolean_abbrev includes sequence_abbrev: // // '(' sequence_expr {',' sequence_match_item } ')' [ boolean_abbrev ] // // "'(' sexpr ')' boolean_abbrev" matches "[sexpr:'(' expr ')'] boolean_abbrev" so we can simply drop it | '(' ~p~sexpr ')' { $$=$1; $$=$1+$2+$3; } | '(' ~p~sexpr ',' sequence_match_itemList ')' { } // // // AND/OR are between pexprs OR sexprs | ~p~sexpr yAND ~p~sexpr { $$=$1; $$=$1+$2+$3; } | ~p~sexpr yOR ~p~sexpr { $$=$1; $$=$1+$2+$3; } // // Intersect always has an sexpr rhs | ~p~sexpr yINTERSECT sexpr { $$=$1; $$=$1+$2+$3; } // | yFIRST_MATCH '(' sexpr ')' { } | yFIRST_MATCH '(' sexpr ',' sequence_match_itemList ')' { } | ~p~sexpr/*sexpression_or_dist*/ yTHROUGHOUT sexpr { } // // Below pexpr's are really sequence_expr, but avoid conflict // // IEEE: sexpr yWITHIN sexpr | ~p~sexpr yWITHIN sexpr { $$=$1; $$=$1+$2+$3; } // // Note concurrent_assertion had duplicate rule for below | clocking_event ~p~sexpr %prec prSEQ_CLOCKING { } // //============= expr rules copied for sequence_expr | BISONPRE_COPY_ONCE(expr,{s/~l~/s/g; s/~p~/s/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied} ; cycle_delay_range: // IEEE: ==cycle_delay_range // // These three terms in 1800-2005 ONLY yP_POUNDPOUND yaINTNUM { } | yP_POUNDPOUND id { } | yP_POUNDPOUND '(' constExpr ')' { } // // In 1800-2009 ONLY: // // IEEE: yP_POUNDPOUND constant_primary // // UNSUP: This causes a big grammer ambiguity // // as ()'s mismatch between primary and the following statement // // the sv-ac committee has been asked to clarify (Mantis 1901) | yP_POUNDPOUND '[' cycle_delay_const_range_expression ']' { } | yP_POUNDPOUND yP_BRASTAR ']' { } | yP_POUNDPOUND yP_BRAPLUSKET { } ; sequence_match_itemList: // IEEE: [sequence_match_item] part of sequence_expr sequence_match_item { } | sequence_match_itemList ',' sequence_match_item { } ; sequence_match_item: // ==IEEE: sequence_match_item // // IEEE says: operator_assignment // // IEEE says: inc_or_dec_expression // // IEEE says: subroutine_call // // This is the same list as... for_step_assignment { } ; boolean_abbrev: // ==IEEE: boolean_abbrev // // IEEE: consecutive_repetition yP_BRASTAR const_or_range_expression ']' { } | yP_BRASTAR ']' { } | yP_BRAPLUSKET { } // // IEEE: non_consecutive_repetition | yP_BRAEQ const_or_range_expression ']' { } // // IEEE: goto_repetition | yP_BRAMINUSGT const_or_range_expression ']' { } ; const_or_range_expression: // ==IEEE: const_or_range_expression constExpr { } | cycle_delay_const_range_expression { } ; constant_range: // ==IEEE: constant_range constExpr ':' constExpr { } ; cycle_delay_const_range_expression: // ==IEEE: cycle_delay_const_range_expression // // Note '$' is part of constExpr constExpr ':' constExpr { } ; //************************************************ // Let let_declaration: // ==IEEE: let_declaration let_declarationFront let_port_listE '=' expr ';' { PARSEP->symPopScope(VAstType::LET); } ; let_declarationFront: // IEEE: part of let_declaration yLET idAny/*let_identifier*/ { PARSEP->symPushNew(VAstType::LET,$2); } ; let_port_listE: // ==IEEE: let_port_list /* empty */ // // IEEE: let_port_list // // No significant difference from task ports | '(' tf_port_listE ')' { VARRESET_NONLIST(""); } ; //************************************************ // Covergroup covergroup_declaration: // ==IEEE: covergroup_declaration covergroup_declarationFront coverage_eventE ';' coverage_spec_or_optionListE yENDGROUP endLabelE { PARSEP->endgroupCb($5,$5); PARSEP->symPopScope(VAstType::COVERGROUP); } | covergroup_declarationFront '(' tf_port_listE ')' coverage_eventE ';' coverage_spec_or_optionListE yENDGROUP endLabelE { PARSEP->endgroupCb($8,$8); PARSEP->symPopScope(VAstType::COVERGROUP); } ; covergroup_declarationFront: // IEEE: part of covergroup_declaration yCOVERGROUP idAny { PARSEP->symPushNew(VAstType::COVERGROUP,$2); PARSEP->covergroupCb($1,$1,$2); } ; cgexpr: // IEEE-2012: covergroup_expression, before that just expression expr { $$=$1; $$ = $1; } ; coverage_spec_or_optionListE: // IEEE: [{coverage_spec_or_option}] /* empty */ { } | coverage_spec_or_optionList { } ; coverage_spec_or_optionList: // IEEE: {coverage_spec_or_option} coverage_spec_or_option { } | coverage_spec_or_optionList coverage_spec_or_option { } ; coverage_spec_or_option: // ==IEEE: coverage_spec_or_option // // IEEE: coverage_spec cover_point { } | cover_cross { } | coverage_option ';' { } | error { } ; coverage_option: // ==IEEE: coverage_option // // option/type_option aren't really keywords id/*yOPTION | yTYPE_OPTION*/ '.' idAny/*member_identifier*/ '=' expr { } ; cover_point: // ==IEEE: cover_point /**/ yCOVERPOINT expr iffE bins_or_empty { } // // IEEE-2012: class_scope before an ID | /**/ /**/ /**/ id ':' yCOVERPOINT expr iffE bins_or_empty { } | class_scope_id ':' yCOVERPOINT expr iffE bins_or_empty { } | class_scope_id id data_type id ':' yCOVERPOINT expr iffE bins_or_empty { } | class_scope_id id /**/ id ':' yCOVERPOINT expr iffE bins_or_empty { } | /**/ id /**/ id ':' yCOVERPOINT expr iffE bins_or_empty { } // // IEEE-2012: | bins_or_empty { } ; iffE: // IEEE: part of cover_point, others /* empty */ { } | yIFF '(' expr ')' { } ; bins_or_empty: // ==IEEE: bins_or_empty '{' bins_or_optionsList '}' { } | '{' '}' { } | ';' { } ; bins_or_optionsList: // IEEE: { bins_or_options ';' } bins_or_options ';' { } | bins_or_optionsList bins_or_options ';' { } ; bins_or_options: // ==IEEE: bins_or_options // // Superset of IEEE - we allow []'s in more places coverage_option { } // // Can't use wildcardE as results in conflicts | /**/ bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE { } | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE { } | /**/ bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr ')' iffE { } | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr ')' iffE { } // // // cgexpr part of trans_list // | /**/ bins_keyword id/*bin_identifier*/ bins_orBraE '=' trans_list iffE { } | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' trans_list iffE { } // | bins_keyword id/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE { } // | bins_keyword id/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE { } ; bins_orBraE: // IEEE: part of bins_or_options: /* empty */ { } | '[' ']' { } | '[' cgexpr ']' { } ; bins_keyword: // ==IEEE: bins_keyword yBINS { } | yILLEGAL_BINS { } | yIGNORE_BINS { } ; covergroup_range_list: // ==IEEE: covergroup_range_list covergroup_value_range { } | covergroup_range_list ',' covergroup_value_range { } ; trans_list: // ==IEEE: trans_list '(' trans_set ')' { } | trans_list ',' '(' trans_set ')' { } ; trans_set: // ==IEEE: trans_set trans_range_list { } // // Note the { => } in the grammer, this is really a list | trans_set yP_EQGT trans_range_list { } ; trans_range_list: // ==IEEE: trans_range_list trans_item { } | trans_item yP_BRASTAR repeat_range ']' { } | trans_item yP_BRAMINUSGT repeat_range ']' { } | trans_item yP_BRAEQ repeat_range ']' { } ; trans_item: // ==IEEE: range_list covergroup_range_list { } ; repeat_range: // ==IEEE: repeat_range cgexpr { } | cgexpr ':' cgexpr { } ; cover_cross: // ==IEEE: cover_cross id/*cover_point_identifier*/ ':' yCROSS list_of_cross_items iffE cross_body { } | /**/ yCROSS list_of_cross_items iffE cross_body { } ; list_of_cross_items: // ==IEEE: list_of_cross_items cross_item ',' cross_item { } | cross_item ',' cross_item ',' cross_itemList { } ; cross_itemList: // IEEE: part of list_of_cross_items cross_item | cross_itemList ',' cross_item { } ; cross_item: // ==IEEE: cross_item idAny/*cover_point_identifier or variable_identifier*/ { } ; cross_body: // ==IEEE: cross_body '{' '}' { } // // IEEE-2012: No semicolon here, mistake in spec | '{' cross_body_itemSemiList '}' { } | ';' { } ; cross_body_itemSemiList: // IEEE: part of cross_body cross_body_item ';' { } | cross_body_itemSemiList cross_body_item ';' { } ; cross_body_item: // ==IEEE: cross_body_item // // IEEE: our semicolon is in the list bins_selection_or_option { } | function_declaration { } ; bins_selection_or_option: // ==IEEE: bins_selection_or_option coverage_option { } | bins_selection { } ; bins_selection: // ==IEEE: bins_selection bins_keyword idAny/*new-bin_identifier*/ '=' select_expression iffE { } ; select_expression: // ==IEEE: select_expression // // IEEE: select_condition expanded here yBINSOF '(' bins_expression ')' { } | yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { } | yWITH__PAREN '(' cgexpr ')' { } // // IEEE-2012: Need clarification as to precedence //UNSUP yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { } | '!' yBINSOF '(' bins_expression ')' { } | '!' yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { } | '!' yWITH__PAREN '(' cgexpr ')' { } // // IEEE-2012: Need clarification as to precedence //UNSUP '!' yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { } | select_expression yP_ANDAND select_expression { } | select_expression yP_OROR select_expression { } | '(' select_expression ')' { } // // IEEE-2012: cross_identifier // // Part of covergroup_expression - generic identifier // // IEEE-2012: Need clarification as to precedence //UNSUP covergroup_expression [ yMATCHES covergroup_expression ] ; bins_expression: // ==IEEE: bins_expression // // "cover_point_identifier" and "variable_identifier" look identical id/*variable_identifier or cover_point_identifier*/ { } | id/*cover_point_identifier*/ '.' idAny/*bins_identifier*/ { } ; coverage_eventE: // IEEE: [ coverage_event ] /* empty */ { } | clocking_event { } | yWITH__ETC function idAny/*"sample"*/ '(' tf_port_listE ')' { } | yP_ATAT '(' block_event_expression ')' { } ; block_event_expression: // ==IEEE: block_event_expression block_event_expressionTerm { } | block_event_expression yOR block_event_expressionTerm { } ; block_event_expressionTerm: // IEEE: part of block_event_expression yBEGIN hierarchical_btf_identifier { } | yEND hierarchical_btf_identifier { } ; hierarchical_btf_identifier: // ==IEEE: hierarchical_btf_identifier // // hierarchical_tf_identifier + hierarchical_block_identifier hierarchical_identifier/*tf_or_block*/ { } // // method_identifier | hierarchical_identifier class_scope_id { } | hierarchical_identifier id { } ; //********************************************************************** // Randsequence randsequence_statement: // ==IEEE: randsequence_statement yRANDSEQUENCE '(' ')' productionList yENDSEQUENCE { } | yRANDSEQUENCE '(' id/*production_identifier*/ ')' productionList yENDSEQUENCE { } ; productionList: // IEEE: production+ production { } | productionList production { } ; production: // ==IEEE: production productionFront ':' rs_ruleList ';' { } ; productionFront: // IEEE: part of production function_data_type id/*production_identifier*/ { } | /**/ id/*production_identifier*/ { } | function_data_type id/*production_identifier*/ '(' tf_port_listE ')' { } | /**/ id/*production_identifier*/ '(' tf_port_listE ')' { } ; rs_ruleList: // IEEE: rs_rule+ part of production rs_rule { } | rs_ruleList '|' rs_rule { } ; rs_rule: // ==IEEE: rs_rule rs_production_list { } | rs_production_list yP_COLONEQ weight_specification { } | rs_production_list yP_COLONEQ weight_specification rs_code_block { } ; rs_production_list: // ==IEEE: rs_production_list rs_prodList { } | yRAND yJOIN /**/ production_item production_itemList { } | yRAND yJOIN '(' expr ')' production_item production_itemList { } ; weight_specification: // ==IEEE: weight_specification yaINTNUM { } | idClassSel/*ps_identifier*/ { } | '(' expr ')' { } ; rs_code_block: // ==IEEE: rs_code_block '{' '}' { } | '{' rs_code_blockItemList '}' { } ; rs_code_blockItemList: // IEEE: part of rs_code_block rs_code_blockItem { } | rs_code_blockItemList rs_code_blockItem { } ; rs_code_blockItem: // IEEE: part of rs_code_block data_declaration { } | stmt { } ; rs_prodList: // IEEE: rs_prod+ rs_prod { } | rs_prodList rs_prod { } ; rs_prod: // ==IEEE: rs_prod production_item { } | rs_code_block { } // // IEEE: rs_if_else | yIF '(' expr ')' production_item %prec prLOWER_THAN_ELSE { } | yIF '(' expr ')' production_item yELSE production_item { } // // IEEE: rs_repeat | yREPEAT '(' expr ')' production_item { } // // IEEE: rs_case | yCASE '(' expr ')' rs_case_itemList yENDCASE { } ; production_itemList: // IEEE: production_item+ production_item { } | production_itemList production_item { } ; production_item: // ==IEEE: production_item id/*production_identifier*/ { } | id/*production_identifier*/ '(' list_of_argumentsE ')' { } ; rs_case_itemList: // IEEE: rs_case_item+ rs_case_item { } | rs_case_itemList rs_case_item { } ; rs_case_item: // ==IEEE: rs_case_item caseCondList ':' production_item ';' { } | yDEFAULT production_item ';' { } | yDEFAULT ':' production_item ';' { } ; //********************************************************************** // Checker checker_declaration: // ==IEEE: part of checker_declaration checkerFront checker_port_listE ';' checker_or_generate_itemListE yENDCHECKER endLabelE { PARSEP->symPopScope(VAstType::CHECKER); } ; checkerFront: // IEEE: part of checker_declaration yCHECKER idAny/*checker_identifier*/ { PARSEP->symPushNew(VAstType::CHECKER, $2); } ; checker_port_listE: // IEEE: [ ( [ checker_port_list ] ) ] // // checker_port_item is basically the same as property_port_item, minus yLOCAL:: // // Want to bet 1800-2012 adds local to checkers? property_port_listE { } ; checker_or_generate_itemListE: // IEEE: [{ checker_or_generate_itemList }] /* empty */ { } | checker_or_generate_itemList { } ; checker_or_generate_itemList: // IEEE: { checker_or_generate_itemList } checker_or_generate_item { } | checker_or_generate_itemList checker_or_generate_item { } ; checker_or_generate_item: // ==IEEE: checker_or_generate_item checker_or_generate_item_declaration { } | initial_construct { } // // IEEE: checker_construct | yALWAYS stmtBlock { } | final_construct { } | assertion_item { } | continuous_assign { } | checker_generate_item { } ; checker_or_generate_item_declaration: // ==IEEE: checker_or_generate_item_declaration data_declaration { } | yRAND data_declaration { } | function_declaration { } | checker_declaration { } | assertion_item_declaration { } | covergroup_declaration { } | overload_declaration { } | genvar_declaration { } | clocking_declaration { } | yDEFAULT yCLOCKING id/*clocking_identifier*/ ';' { } | yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';' { } | ';' { } ; checker_generate_item: // ==IEEE: checker_generate_item // // Specialized for checker so need "c_" prefixes here c_loop_generate_construct { } | c_conditional_generate_construct { } | c_generate_region { } // | elaboration_system_task { } ; checker_instantiation: // // Only used for procedural_assertion_item's // // Version in concurrent_assertion_item looks like etcInst // // Thus instead of *_checker_port_connection we can use etcInst's cellpinList id/*checker_identifier*/ id '(' cellpinList ')' ';' { } ; //********************************************************************** // Class class_declaration: // ==IEEE: part of class_declaration // // IEEE-2012: using this also for interface_class_declaration // // The classExtendsE rule relys on classFront having the // // new class scope correct via classFront classFront parameter_port_listE classExtendsE classImplementsE ';' class_itemListE yENDCLASS endLabelE { PARSEP->endclassCb($7,$7); PARSEP->symPopScope(VAstType::CLASS); } ; classFront: // IEEE: part of class_declaration classVirtualE yCLASS lifetimeE idAny/*class_identifier*/ { PARSEP->symPushNew(VAstType::CLASS, $4); PARSEP->classCb($2,$2,$4,$1); } // // IEEE: part of interface_class_declaration | yINTERFACE yCLASS lifetimeE idAny/*class_identifier*/ { PARSEP->symPushNew(VAstType::CLASS, $4); PARSEP->classCb($2,$2,$4,$1); } ; classVirtualE: /* empty */ { $$=""; } | yVIRTUAL__CLASS { $$=$1; $$=$1; } ; classExtendsE: // IEEE: part of class_declaration // // The classExtendsE rule relys on classFront having the // // new class scope correct via classFront /* empty */ { } | yEXTENDS class_typeWithoutId { PARSEP->syms().import($1,$2,$2,"*"); } | yEXTENDS class_typeWithoutId '(' list_of_argumentsE ')' { PARSEP->syms().import($1,$2,$2,"*"); } ; classImplementsE: // IEEE: part of class_declaration // // All 1800-2012 /* empty */ { } | yIMPLEMENTS classImplementsList { PARSEP->syms().import($1,$2,$2,"*"); } ; classImplementsList: // IEEE: part of class_declaration // // All 1800-2012 class_typeWithoutId { } | classImplementsList ',' class_typeWithoutId { } ; //========= // Package scoping - to traverse the symbol table properly, the final identifer // must be included in the rules below. // Each of these must end with {symsPackageDone | symsClassDone} ps_id_etc: // package_scope + general id package_scopeIdFollowsE id { $$=$1; $$=$1+$2; } ; class_scope_id: // class_scope + id etc class_scopeIdFollows id { $$=$1; $$=$1; $$=$1+$2; } ; //=== Below rules assume special scoping per above class_typeWithoutId: // as with class_typeWithoutId but allow yaID__aTYPE // // and we thus don't need to resolve it in specified package package_scopeIdFollowsE class_typeOneList { $$=$2; $$=$2; $$=$1+$2; } ; class_scopeWithoutId: // class_type standalone without following id // // and we thus don't need to resolve it in specified package class_scopeIdFollows { $$=$1; $$=$1; $$=$1; PARSEP->symTableNextId(NULL); } ; class_scopeIdFollows: // IEEE: class_scope + type // // IEEE: "class_type yP_COLONCOLON" // // IMPORTANT: The lexer will parse the following ID to be in the found package // // But class_type:'::' conflicts with class_scope:'::' so expand here package_scopeIdFollowsE class_typeOneListColonIdFollows { $$=$2; $$=$2; $$=$1+$2; } ; class_typeOneListColonIdFollows: // IEEE: class_type :: but allow yaID__aTYPE class_typeOneList yP_COLONCOLON { $$=$1; $$=$1; $$=$1+$2; PARSEP->symTableNextId($1); } ; class_typeOneList: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE // // If you follow the rules down, class_type is really a list via ps_class_identifier // // Must propagate scp up for next id class_typeOne { $$=$1; $$=$1; $$=$1; } | class_typeOneListColonIdFollows class_typeOne { $$=$1; $$=$2; $$=$1+$2; } ; class_typeOne: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE // // If you follow the rules down, class_type is really a list via ps_class_identifier // // Not listed in IEEE, but see bug627 any parameter type maybe a class yaID__aTYPE parameter_value_assignmentE { $$=$1; $$=$1; $$=$1; } ; package_scopeIdFollowsE: // IEEE: [package_scope] // // IMPORTANT: The lexer will parse the following ID to be in the found package /* empty */ { $$=""; } | package_scopeIdFollows { $$=$1; $$=$1; } ; package_scopeIdFollows: // IEEE: package_scope // // IMPORTANT: The lexer will parse the following ID to be in the found package // // class_qualifier := [ yLOCAL '::' ] [ implicit_class_handle '.' | class_scope ] // //vv mid rule action needed otherwise we might not have NextId in time to parse the id token yD_UNIT { PARSEP->symTableNextId(PARSEP->syms().netlistSymp()); } /*cont*/ yP_COLONCOLON { $$=$1; $$=$1+$3; } | yaID__aPACKAGE { PARSEP->symTableNextId($1); } /*cont*/ yP_COLONCOLON { $$=$1; $$=$1+$3; } | yLOCAL__COLONCOLON { PARSEP->symTableNextId($1); } /*cont*/ yP_COLONCOLON { $$=$1; $$=$1+$3; } ; //^^^========= class_itemListE: /* empty */ { } | class_itemList { } ; class_itemList: class_item { } | class_itemList class_item { } ; class_item: // ==IEEE: class_item class_property { } | class_method { } | class_constraint { } // | class_declaration { } | timeunits_declaration { } | covergroup_declaration { } | local_parameter_declaration ';' { } // 1800-2009 | parameter_declaration ';' { } // 1800-2009 | ';' { } // | error ';' { } ; class_method: // ==IEEE: class_method memberQualResetListE task_declaration { } | memberQualResetListE function_declaration { } // // 1800-2009 adds yPURE yVIRTUAL, already in memberQualResetListE | yEXTERN memberQualResetListE method_prototype ';' { } // // IEEE: "method_qualifierE class_constructor_declaration" // // part of function_declaration | yEXTERN memberQualResetListE class_constructor_prototype { } ; // IEEE: class_constructor_prototype // See function_declaration class_item_qualifier: // IEEE: class_item_qualifier minus ySTATIC // // IMPORTANT: yPROTECTED | yLOCAL is in a lex rule yPROTECTED { $$=$1; $$=$1; } | yLOCAL__ETC { $$=$1; $$=$1; } | ySTATIC__ETC { $$=$1; $$=$1; } ; memberQualResetListE: // Called from class_property for all qualifiers before yVAR // // Also before method declarations, to prevent grammar conflict // // Thus both types of qualifiers (method/property) are here /*empty*/ { VARRESET(); VARDTYPE(""); } | memberQualList { VARRESET(); VARDTYPE($1); } ; memberQualList: memberQualOne { $$=$1; $$=$1; } | memberQualList memberQualOne { $$=$1; $$=SPACED($1,$2); } ; memberQualOne: // IEEE: property_qualifier + method_qualifier // // Part of method_qualifier and property_qualifier class_item_qualifier { $$=$1; $$=$1; } // // Part of method_qualifier only | yVIRTUAL__ETC { $$=$1; $$=$1; } // // IMPORTANT: lexer looks for yPURE yVIRTUAL | yPURE yVIRTUAL__ETC { $$=$1; $$=$1+" "+$2; } // // Part of property_qualifier only | random_qualifier { $$=$1; $$=$1; } // // Part of lifetime, but here as ySTATIC can be in different positions | yAUTOMATIC { $$=$1; $$=$1; } // // Part of data_declaration, but not in data_declarationVarFrontClass | yCONST__ETC { $$=$1; $$=$1; } ; //********************************************************************** // Constraints class_constraint: // ==IEEE: class_constraint // // IEEE: constraint_declaration constraintStaticE yCONSTRAINT idAny constraint_block { } // // IEEE: constraint_prototype + constraint_prototype_qualifier | constraintStaticE yCONSTRAINT idAny ';' { } | yEXTERN constraintStaticE yCONSTRAINT idAny ';' { } | yPURE constraintStaticE yCONSTRAINT idAny ';' { } ; constraint_block: // ==IEEE: constraint_block '{' constraint_block_itemList '}' { } ; constraint_block_itemList: // IEEE: { constraint_block_item } constraint_block_item { } | constraint_block_itemList constraint_block_item { } ; constraint_block_item: // ==IEEE: constraint_block_item ySOLVE solve_before_list yBEFORE solve_before_list ';' { } | constraint_expression { } ; solve_before_list: // ==IEEE: solve_before_list constraint_primary { } | solve_before_list ',' constraint_primary { } ; constraint_primary: // ==IEEE: constraint_primary // // exprScope more general than: [ implicit_class_handle '.' | class_scope ] hierarchical_identifier select exprScope { } ; constraint_expressionList: // ==IEEE: { constraint_expression } constraint_expression { $$=$1; } | constraint_expressionList constraint_expression { $$=$1+" "+$2; } ; constraint_expression: // ==IEEE: constraint_expression expr/*expression_or_dist*/ ';' { $$=$1; } // // 1800-2012: | ySOFT expr/*expression_or_dist*/ ';' { $$="soft "+$1; } // // 1800-2012: // // IEEE: uniqueness_constraint ';' | yUNIQUE '{' open_range_list '}' { $$="unique {...}"; } // // IEEE: expr yP_MINUSGT constraint_set // // Conflicts with expr:"expr yP_MINUSGT expr"; rule moved there // | yIF '(' expr ')' constraint_set %prec prLOWER_THAN_ELSE { $$=$1; } | yIF '(' expr ')' constraint_set yELSE constraint_set { $$=$1;} // // IEEE says array_identifier here, but dotted accepted in VMM + 1800-2009 | yFOREACH '(' idClassForeach/*array_id[loop_variables]*/ ')' constraint_set { $$=$1; } // // soft is 1800-2012 | yDISABLE ySOFT expr/*constraint_primary*/ ';' { $$="disable soft "+$1; } ; constraint_set: // ==IEEE: constraint_set constraint_expression { $$=$1; } | '{' constraint_expressionList '}' { $$=$1+$2+$3; } ; dist_list: // ==IEEE: dist_list dist_item { } | dist_list ',' dist_item { } ; dist_item: // ==IEEE: dist_item + dist_weight value_range { } | value_range yP_COLONEQ expr { } | value_range yP_COLONDIV expr { } ; extern_constraint_declaration: // ==IEEE: extern_constraint_declaration constraintStaticE yCONSTRAINT class_scope_id constraint_block { } ; constraintStaticE: // IEEE: part of extern_constraint_declaration /* empty */ { } | ySTATIC__CONSTRAINT { } ; //********************************************************************** %% int VParseGrammar::parse() { s_grammarp = this; return VParseBisonparse(); } void VParseGrammar::debug(int level) { VParseBisondebug = level; } const char* VParseGrammar::tokenName(int token) { #if YYDEBUG || YYERROR_VERBOSE if (token >= 255) { switch (token) { /*BISONPRE_TOKEN_NAMES*/ default: return yytname[token-255]; } } else { static char ch[2]; ch[0]=token; ch[1]='\0'; return ch; } #else return ""; #endif } //YACC = /kits/sources/bison-2.4.1/src/bison --report=lookahead // --report=lookahead // --report=itemset // --graph // // Local Variables: // compile-command: "cd .. ; make -j 8 && make test" // End: