// -*- C++ -*- //************************************************************************* // DESCRIPTION: Verilator: Bison grammer file // // Code available from: http://www.veripool.org/verilator // //************************************************************************* // // Copyright 2003-2009 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. // // Verilator 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. // //************************************************************************* // Original code here by Paul Wasson and Duane Galbi //************************************************************************* %{ #include #include #include #include #include "V3Read.h" #include "V3Ast.h" #include "V3Global.h" #define YYERROR_VERBOSE 1 #define YYINITDEPTH 10000 // Older bisons ignore YYMAXDEPTH #define YYMAXDEPTH 10000 // Pick up new lexer #define yylex V3Read::yylex #define PSLUNSUP(what) NULL; yyerrorf("Unsupported: PSL language feature not implemented"); extern void yyerror(const char* errmsg); extern void yyerrorf(const char* format, ...); //====================================================================== // Statics (for here only) class V3Parse { public: static bool s_impliedDecl; // Allow implied wire declarations static AstVarType s_varDecl; // Type for next signal declaration (reg/wire/etc) static AstVarType s_varIO; // Type for next signal declaration (input/output/etc) static bool s_varSigned; // Signed state for next signal declaration static AstVar* s_varAttrp; // Current variable for attribute adding static AstCase* s_caseAttrp; // Current case statement for attribute adding static AstRange* s_varRangep; // Pointer to range for next signal declaration static int s_pinNum; // Pin number currently parsing static string s_instModule; // Name of module referenced for instantiations static AstPin* s_instParamp; // Parameters for instantiations static int s_uniqueAttr; // Bitmask of unique/priority keywords static AstVar* createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp); static AstNode* createSupplyExpr(FileLine* fileline, string name, int value); static AstText* createTextQuoted(FileLine* fileline, string text); static AstDisplay* createDisplayError(FileLine* fileline) { AstDisplay* nodep = new AstDisplay(fileline,AstDisplayType::ERROR, "", NULL,NULL); nodep->addNext(new AstStop(fileline)); return nodep; } static void setRange(AstRange* rangep) { if (s_varRangep) { s_varRangep->deleteTree(); s_varRangep=NULL; } // It was cloned, so this is safe. s_varRangep = rangep; } static string deQuote(FileLine* fileline, string text); }; bool V3Parse::s_impliedDecl = false; AstVarType V3Parse::s_varDecl = AstVarType::UNKNOWN; AstVarType V3Parse::s_varIO = AstVarType::UNKNOWN; bool V3Parse::s_varSigned = false; AstRange* V3Parse::s_varRangep = NULL; int V3Parse::s_pinNum = -1; string V3Parse::s_instModule; AstPin* V3Parse::s_instParamp = NULL; AstVar* V3Parse::s_varAttrp = NULL; AstCase* V3Parse::s_caseAttrp = NULL; //====================================================================== // Utility functions static AstNode* newVarInit(FileLine* fileline, AstNode* varp, AstNode* initp) { return new AstInitial(fileline, new AstAssign(fileline, new AstVarRef(fileline, varp->name(),true), initp)); } //====================================================================== // Macro functions #define CRELINE() (V3Read::copyOrSameFileLine()) #define VARRESET_LIST(decl) { V3Parse::s_pinNum=1; VARRESET(); VARDECL(decl); } // Start of pinlist #define VARRESET_NONLIST(decl) { V3Parse::s_pinNum=0; VARRESET(); VARDECL(decl); } // Not in a pinlist #define VARRESET() { VARDECL(UNKNOWN); VARIO(UNKNOWN); VARSIGNED(false); VARRANGE(NULL); } #define VARDECL(type) { V3Parse::s_varDecl = AstVarType::type; } #define VARIO(type) { V3Parse::s_varIO = AstVarType::type; } #define VARSIGNED(value) { V3Parse::s_varSigned = value; } #define VARRANGE(rangep) { V3Parse::setRange(rangep); } #define VARTYPE(typep) { VARRANGE(typep); } // Temp until other data types supported #define VARDONEA(name,array,attrs) V3Parse::createVariable(CRELINE(),(name),(array),(attrs)) #define VARDONEP(portp,array,attrs) V3Parse::createVariable((portp)->fileline(),(portp)->name(),(array),(attrs)) #define PINNUMINC() (V3Parse::s_pinNum++) #define INSTPREP(modname,paramsp) { V3Parse::s_impliedDecl = true; V3Parse::s_instModule = modname; V3Parse::s_instParamp = paramsp; } //====================================================================== class AstSenTree; %} %union { FileLine* fileline; V3Number* nump; string* strp; int cint; double cdouble; V3UniqState uniqstate; AstNode* nodep; AstAssignW* assignwp; AstBegin* beginp; AstCase* casep; AstCaseItem* caseitemp; AstCell* cellp; AstConst* constp; AstFunc* funcp; AstModule* modulep; AstNodeVarRef* varnodep; AstParseRef* parserefp; AstPin* pinp; AstPort* portp; AstRange* rangep; AstNodeSenItem* senitemp; AstSenTree* sentreep; AstVar* varp; AstVarRef* varrefp; } // 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" // 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 yaSCHDR "`systemc_header BLOCK" %token yaSCINT "`systemc_ctor BLOCK" %token yaSCIMP "`systemc_dtor BLOCK" %token yaSCIMPH "`systemc_interface BLOCK" %token yaSCCTOR "`systemc_implementation BLOCK" %token yaSCDTOR "`systemc_imp_header BLOCK" %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 yALWAYS "always" %token yAND "and" %token yASSERT "assert" %token yASSIGN "assign" %token yAUTOMATIC "automatic" %token yBEGIN "begin" %token yBUF "buf" %token yBUFIF0 "bufif0" %token yBUFIF1 "bufif1" %token yCASE "case" %token yCASEX "casex" %token yCASEZ "casez" %token yCLOCKING "clocking" %token yCOVER "cover" %token yDEFAULT "default" %token yDEFPARAM "defparam" %token yDISABLE "disable" %token yDO "do" %token yELSE "else" %token yEND "end" %token yENDCASE "endcase" %token yENDCLOCKING "endclocking" %token yENDFUNCTION "endfunction" %token yENDGENERATE "endgenerate" %token yENDMODULE "endmodule" %token yENDPROPERTY "endproperty" %token yENDSPECIFY "endspecify" %token yENDTASK "endtask" %token yFINAL "final" %token yFOR "for" %token yFOREVER "forever" %token yFUNCTION "function" %token yGENERATE "generate" %token yGENVAR "genvar" %token yIF "if" %token yIFF "iff" %token yLOGIC "logic" %token yINITIAL "initial" %token yINOUT "inout" %token yINPUT "input" %token yINTEGER "integer" %token yLOCALPARAM "localparam" %token yMODULE "module" %token yNAND "nand" %token yNEGEDGE "negedge" %token yNOR "nor" %token yNOT "not" %token yNOTIF0 "notif0" %token yNOTIF1 "notif1" %token yOR "or" %token yOUTPUT "output" %token yPARAMETER "parameter" %token yPOSEDGE "posedge" %token yPRIORITY "priority" %token yPROPERTY "property" %token yPULLDOWN "pulldown" %token yPULLUP "pullup" %token yREG "reg" %token yREPEAT "repeat" %token ySCALARED "scalared" %token ySIGNED "signed" %token ySPECIFY "specify" %token ySPECPARAM "specparam" %token ySTATIC "static" %token ySUPPLY0 "supply0" %token ySUPPLY1 "supply1" %token yTASK "task" %token yTIMEPRECISION "timeprecision" %token yTIMEUNIT "timeunit" %token yTRI "tri" %token yTRUE "true" %token yUNIQUE "unique" %token yUNSIGNED "unsigned" %token yVECTORED "vectored" %token yWHILE "while" %token yWIRE "wire" %token yXNOR "xnor" %token yXOR "xor" %token yD_BITS "$bits" %token yD_C "$c" %token yD_CLOG2 "$clog2" %token yD_COUNTONES "$countones" %token yD_DISPLAY "$display" %token yD_ERROR "$error" %token yD_FATAL "$fatal" %token yD_FCLOSE "$fclose" %token yD_FDISPLAY "$fdisplay" %token yD_FEOF "$feof" %token yD_FFLUSH "$fflush" %token yD_FGETC "$fgetc" %token yD_FGETS "$fgets" %token yD_FINISH "$finish" %token yD_FOPEN "$fopen" %token yD_FSCANF "$fscanf" %token yD_FWRITE "$fwrite" %token yD_INFO "$info" %token yD_ISUNKNOWN "$isunknown" %token yD_ONEHOT "$onehot" %token yD_ONEHOT0 "$onehot0" %token yD_RANDOM "$random" %token yD_READMEMB "$readmemb" %token yD_READMEMH "$readmemh" %token yD_SIGNED "$signed" %token yD_SSCANF "$sscanf" %token yD_STIME "$stime" %token yD_STOP "$stop" %token yD_TIME "$time" %token yD_UNSIGNED "$unsigned" %token yD_WARNING "$warning" %token yD_WRITE "$write" %token yPSL "psl" %token yPSL_ASSERT "PSL assert" %token yPSL_CLOCK "PSL clock" %token yPSL_COVER "PSL cover" %token yPSL_REPORT "PSL report" %token yVL_CLOCK "/*verilator sc_clock*/" %token yVL_CLOCK_ENABLE "/*verilator clock_enable*/" %token yVL_COVERAGE_BLOCK_OFF "/*verilator coverage_block_off*/" %token yVL_FULL_CASE "/*verilator full_case*/" %token yVL_INLINE_MODULE "/*verilator inline_module*/" %token yVL_ISOLATE_ASSIGNMENTS "/*verilator isolate_assignments*/" %token yVL_NO_INLINE_MODULE "/*verilator no_inline_module*/" %token yVL_NO_INLINE_TASK "/*verilator no_inline_task*/" %token yVL_PARALLEL_CASE "/*verilator parallel_case*/" %token yVL_PUBLIC "/*verilator public*/" %token yVL_PUBLIC_FLAT "/*verilator public_flat*/" %token yVL_PUBLIC_MODULE "/*verilator public_module*/" %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_SLEFT "<<" %token yP_SRIGHT ">>" %token yP_SSRIGHT ">>>" %token yP_POW "**" %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_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_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 ">>>=" %token yPSL_BRA "{" %token yPSL_KET "}" %token yP_LOGIFF // [* is not a operator, as "[ * ]" is legal // [= and [-> could be repitition operators, but to match [* we don't add them. // '( is not a operator, as "' (" is legal //******************** // PSL op precedence %right yP_MINUSGT yP_LOGIFF %right yP_ORMINUSGT yP_OREQGT %left prPSLCLK // Verilog op precedence %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 %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 %start source_text %% //********************************************************************** // Feedback to the Lexer // Note we read a parenthesis ahead, so this may not change the lexer at the right point. stateExitPsl: // For PSL lexing, return from PSL state /* empty */ { V3Read::stateExitPsl(); } ; statePushVlg: // For PSL lexing, escape current state into Verilog state /* empty */ { V3Read::statePushVlg(); } ; statePop: // Return to previous lexing state /* empty */ { V3Read::statePop(); } ; //********************************************************************** // 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 { } //UNSUP interface_declaration { } //UNSUP program_declaration { } //UNSUP package_declaration { } //UNSUP package_item { } //UNSUP bind_directive { } // unsupported // IEEE: config_declaration | error { } ; timeunits_declaration: // ==IEEE: timeunits_declaration yTIMEUNIT yaTIMENUM ';' { } | yTIMEPRECISION yaTIMENUM ';' { } ; //********************************************************************** // Packages package_or_generate_item_declaration: // ==IEEE: package_or_generate_item_declaration net_declaration { $$ = $1; } | data_declaration { $$ = $1; } | task_declaration { $$ = $1; } | function_declaration { $$ = $1; } //UNSUP dpi_import_export { $$ = $1; } //UNSUP extern_constraint_declaration { $$ = $1; } //UNSUP class_declaration { $$ = $1; } // // class_constructor_declaration is part of function_declaration | parameter_declaration ';' { $$ = $1; } | local_parameter_declaration { $$ = $1; } //UNSUP covergroup_declaration { $$ = $1; } //UNSUP overload_declaration { $$ = $1; } //UNSUP concurrent_assertion_item_declaration { $$ = $1; } | ';' { $$ = NULL; } ; //********************************************************************** // Module headers module_declaration: // ==IEEE: module_declaration // // timeunits_declaration instead in module_item // // IEEE: module_nonansi_header + module_ansi_header modFront parameter_port_listE portsStarE ';' module_itemListE yENDMODULE endLabelE { $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3); if ($5) $1->addStmtp($5); } // //UNSUP yEXTERN modFront parameter_port_listE portsStarE ';' //UNSUP { UNSUP } ; modFront: yMODULE lifetimeE idAny { $$ = new AstModule($1,*$3); $$->inLibrary(V3Read::inLibrary()||V3Read::inCellDefine()); $$->modTrace(v3Global.opt.trace()); V3Read::rootp()->addModulep($$); } ; parameter_value_assignmentE: // IEEE: [ parameter_value_assignment ] /* empty */ { $$ = NULL; } | '#' '(' cellpinList ')' { $$ = $3; } // // Not needed in Verilator: // // Side effect of combining *_instantiations // // '#' delay_value { UNSUP } ; parameter_port_listE: // IEEE: parameter_port_list + empty == parameter_value_assignment /* empty */ { $$ = NULL; } | '#' '(' ')' { $$ = NULL; } // // 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(GPARAM);} paramPortDeclOrArgList ')' { $$ = $4; VARRESET_NONLIST(UNKNOWN); } // // Note legal to start with "a=b" with no parameter statement ; paramPortDeclOrArgList: // IEEE: list_of_param_assignments + { parameter_port_declaration } paramPortDeclOrArg { $$ = $1; } | paramPortDeclOrArgList ',' paramPortDeclOrArg { $$ = $1->addNext($3); } ; paramPortDeclOrArg: // IEEE: param_assignment + parameter_port_declaration // // We combine the two as we can't tell which follows a comma param_assignment { $$ = $1; } | parameter_port_declarationFront param_assignment { $$ = $2; } ; portsStarE: // IEEE: .* + list_of_ports + list_of_port_declarations + empty /* empty */ { $$ = NULL; } | '(' ')' { $$ = NULL; } // // .* expanded from module_declaration //UNSUP '(' yP_DOTSTAR ')' { UNSUP } | '(' {VARRESET_LIST(PORT);} list_of_ports ')' { $$ = $3; VARRESET_NONLIST(UNKNOWN); } ; list_of_ports: // IEEE: list_of_ports + list_of_port_declarations port { $$ = $1; } | list_of_ports ',' port { $$ = $1->addNextNull($3); } ; port: // ==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 //UNSUP portDirNetE id/*interface*/ idAny/*port*/ regArRangeE sigAttrListE { VARTYPE($2); VARDONEA($3, $4); PARSEP->instantCb(CRELINE(), $2, $3, $4); PINNUMINC(); } //UNSUP portDirNetE yINTERFACE idAny/*port*/ regArRangeE sigAttrListE { VARTYPE($2); VARDONEA($3, $4); PINNUMINC(); } //UNSUP portDirNetE id/*interface*/ '.' idAny/*modport*/ idAny/*port*/ regArRangeE sigAttrListE { VARTYPE($2); VARDONEA($5, $6); PARSEP->instantCb(CRELINE(), $2, $5, $6); PINNUMINC(); } //UNSUP portDirNetE yINTERFACE '.' idAny/*modport*/ idAny/*port*/ regArRangeE sigAttrListE { VARTYPE($2); VARDONEA($5, $6); PINNUMINC(); } // // // IEEE: ansi_port_declaration, with [port_direction] removed // // IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension } // // 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 // // Substitute var_data_type = data_type | yVAR data_type_or_implicit // // [ [ 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 // // // variable_dimensionListE instead of regArRangeE 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 //UNSUP portDirNetE data_type '.' portSig '(' portAssignExprE ')' sigAttrListE { UNSUP } //UNSUP portDirNetE yVAR data_type '.' portSig '(' portAssignExprE ')' sigAttrListE { UNSUP } //UNSUP portDirNetE yVAR implicit_type '.' portSig '(' portAssignExprE ')' sigAttrListE { UNSUP } //UNSUP portDirNetE signingE rangeList '.' portSig '(' portAssignExprE ')' sigAttrListE { UNSUP } //UNSUP portDirNetE /*implicit*/ '.' portSig '(' portAssignExprE ')' sigAttrListE { UNSUP } // portDirNetE data_type portSig variable_dimensionListE sigAttrListE { $$=$3; VARTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); } //UNSUP portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE { $$=$4; VARTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } //UNSUP portDirNetE yVAR implicit_type portSig variable_dimensionListE sigAttrListE { $$=$4; VARTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } | portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE { $$=$4; VARTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } | portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE { $$=$2; /*VARTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); } // | portDirNetE data_type portSig variable_dimensionListE sigAttrListE '=' constExpr { $$=$3; VARTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); $$->addNextNull(newVarInit($6,$$,$7)); } //UNSUP portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE '=' constExpr { $$=$3; VARTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); $$->addNextNull(newVarInit($7,$$,$8)); } //UNSUP portDirNetE yVAR implicit_type portSig variable_dimensionListE sigAttrListE '=' constExpr { $$=$3; VARTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); $$->addNextNull(newVarInit($7,$$,$8)); } | portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE '=' constExpr { $$=$3; /*VARTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); $$->addNextNull(newVarInit($5,$$,$6)); } ; 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 VARTYPE with one later in the parse. | port_direction { VARDECL(PORT); VARTYPE(NULL/*default_nettype*/); } | port_direction net_type { VARDECL(PORT); VARTYPE(NULL/*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 ; portSig: id/*port*/ { $$ = new AstPort(CRELINE(),PINNUMINC(),*$1); } ; //********************************************************************** // Interface headers //********************************************************************** // Program headers //************************************************ // Variable Declarations genvar_declaration: // ==IEEE: genvar_declaration yGENVAR list_of_genvar_identifiers ';' { $$ = $2; } ; list_of_genvar_identifiers: // IEEE: list_of_genvar_identifiers (for declaration) genvar_identifierDecl { $$ = $1; } | list_of_genvar_identifiers ',' genvar_identifierDecl { $$ = $1->addNext($3); } ; genvar_identifierDecl: // IEEE: genvar_identifier (for declaration) id/*new-genvar_identifier*/ sigAttrListE { VARRESET_NONLIST(GENVAR); $$ = VARDONEA(*$1, NULL, $2); } ; local_parameter_declaration: // IEEE: local_parameter_declaration // // See notes in parameter_declaration local_parameter_declarationFront list_of_param_assignments ';' { $$ = $2; } ; 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 { $$ = $2; } ; local_parameter_declarationFront: // IEEE: local_parameter_declaration w/o assignment varLParamReset implicit_type { /*VARRESET-in-varLParam*/ VARTYPE($2); } //UNSUP varLParamReset data_type { /*VARRESET-in-varLParam*/ VARTYPE($2); } //UNSUP varLParamReset yTYPE { /*VARRESET-in-varLParam*/ VARTYPE($2); } ; parameter_declarationFront: // IEEE: parameter_declaration w/o assignment varGParamReset implicit_type { /*VARRESET-in-varGParam*/ VARTYPE($2); } //UNSUP varGParamReset data_type { /*VARRESET-in-varGParam*/ VARTYPE($2); } //UNSUP varGParamReset yTYPE { /*VARRESET-in-varGParam*/ VARTYPE($2); } ; parameter_port_declarationFront: // IEEE: parameter_port_declaration w/o assignment // // IEEE: parameter_declaration (minus assignment) parameter_declarationFront { } // //UNSUP data_type { VARTYPE($1); } //UNSUP yTYPE { VARTYPE($1); } ; net_declaration: // IEEE: net_declaration - excluding implict net_declarationFront netSigList ';' { $$ = $2; } ; net_declarationFront: // IEEE: beginning of net_declaration net_declRESET net_type strengthSpecE signingE delayrange { } ; net_declRESET: /* empty */ { VARRESET_NONLIST(UNKNOWN); } ; net_type: // ==IEEE: net_type ySUPPLY0 { VARDECL(SUPPLY0); } | ySUPPLY1 { VARDECL(SUPPLY1); } | yTRI { VARDECL(TRIWIRE); } //UNSUP yTRI0 { VARDECL(TRI0); } //UNSUP yTRI1 { VARDECL(TRI1); } //UNSUP yTRIAND { VARDECL(TRIAND); } //UNSUP yTRIOR { VARDECL(TRIOR); } //UNSUP yTRIREG { VARDECL(TRIREG); } //UNSUP yWAND { VARDECL(WAND); } | yWIRE { VARDECL(WIRE); } //UNSUP yWOR { VARDECL(WOR); } ; varRESET: /* empty */ { VARRESET(); } ; varGParamReset: yPARAMETER { VARRESET_NONLIST(GPARAM); } ; varLParamReset: yLOCALPARAM { VARRESET_NONLIST(LPARAM); } ; 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(INPUT); } | yOUTPUT { VARIO(OUTPUT); } | yINOUT { VARIO(INOUT); } //UNSUP yREF { VARIO(REF); } //UNSUP yCONST__REF yREF { VARIO(CONSTREF); } ; port_directionReset: // IEEE: port_direction that starts a port_declaraiton // // Used only for declarations outside the port list yINPUT { VARRESET_NONLIST(UNKNOWN); VARIO(INPUT); } | yOUTPUT { VARRESET_NONLIST(UNKNOWN); VARIO(OUTPUT); } | yINOUT { VARRESET_NONLIST(UNKNOWN); VARIO(INOUT); } //UNSUP yREF { VARRESET_NONLIST(UNKNOWN); VARIO(REF); } //UNSUP yCONST__REF yREF { VARRESET_NONLIST(UNKNOWN); VARIO(CONSTREF); } ; 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 data_type { VARTYPE($3); } list_of_variable_decl_assignments { $$ = $5; } //UNSUP port_directionReset port_declNetE yVAR data_type { VARTYPE($4); } list_of_variable_decl_assignments { $$ = $6; } //UNSUP port_directionReset port_declNetE yVAR implicit_type { VARTYPE($4); } list_of_variable_decl_assignments { $$ = $6; } | port_directionReset port_declNetE signingE rangeList { VARTYPE($4); } list_of_variable_decl_assignments { $$ = $6; } | port_directionReset port_declNetE signing { VARTYPE(NULL); } list_of_variable_decl_assignments { $$ = $5; } | port_directionReset port_declNetE /*implicit*/ { VARTYPE(NULL);/*default_nettype*/} list_of_variable_decl_assignments { $$ = $4; } ; tf_port_declaration: // ==IEEE: tf_port_declaration // // Used inside function; followed by ';' // // SIMILAR to port_declaration // port_directionReset data_type { VARTYPE($2); } list_of_tf_variable_identifiers ';' { $$ = $4; } | port_directionReset implicit_type { VARTYPE($2); } list_of_tf_variable_identifiers ';' { $$ = $4; } //UNSUP port_directionReset yVAR data_type { VARTYPE($3); } list_of_tf_variable_identifiers ';' { $$ = $5; } //UNSUP port_directionReset yVAR implicit_type { VARTYPE($3); } list_of_tf_variable_identifiers ';' { $$ = $5; } ; signingE: // IEEE: signing - plus empty /*empty*/ { } | signing { } ; signing: // ==IEEE: signing ySIGNED { VARSIGNED(true); } | yUNSIGNED { VARSIGNED(false); } ; //************************************************ // Data Types data_type: // ==IEEE: data_type // // This expansion also replicated elsewhere, IE data_type__AndID data_typeNoRef { $$ = $1; } // // IEEE: [ class_scope | package_scope ] type_identifier { packed_dimension } //UNSUP ps_type packed_dimensionE { UNSUP } //UNSUP class_scope_type packed_dimensionE { UNSUP } // // IEEE: class_type //UNSUP class_typeWithoutId { $$ = $1; } // // IEEE: ps_covergroup_identifier //UNSUP ps_covergroup_identifier { $$ = $1; } ; data_typeNoRef: // ==IEEE: data_type, excluding class_type etc references yINTEGER { VARDECL(INTEGER); $$ = new AstRange($1,31,0); $$->isSigned(true); } | yREG signingE rangeListE { VARDECL(REG); $$ = $3; } | yLOGIC signingE rangeListE { VARDECL(REG); $$ = $3; } //UNSUP: above instead of integer_type // //UNSUP integer_type signingE regArRangeE { UNSUP } //UNSUP non_integer_type { UNSUP } //UNSUP ySTRUCT packedSigningE '{' struct_union_memberList '}' packed_dimensionE { UNSUP } //UNSUP yUNION taggedE packedSigningE '{' struct_union_memberList '}' packed_dimensionE { UNSUP } //UNSUP enumDecl { UNSUP } //UNSUP ySTRING { UNSUP } //UNSUP yCHANDLE { UNSUP } //UNSUP yEVENT { UNSUP } //UNSUP yVIRTUAL__INTERFACE yINTERFACE id/*interface*/ { UNSUP } //UNSUP yVIRTUAL__anyID id/*interface*/ { UNSUP } //UNSUP type_reference { UNSUP } // // IEEE: class_scope: see data_type above // // IEEE: class_type: see data_type above // // IEEE: ps_covergroup: see data_type above ; list_of_variable_decl_assignments: // ==IEEE: list_of_variable_decl_assignments variable_decl_assignment { $$ = $1; } | list_of_variable_decl_assignments ',' variable_decl_assignment { $$ = $1->addNextNull($3); } ; variable_decl_assignment: // ==IEEE: variable_decl_assignment id variable_dimensionListE sigAttrListE { $$ = VARDONEA(*$1,$2,$3); } | id variable_dimensionListE sigAttrListE '=' variable_declExpr { $$ = VARDONEA(*$1,$2,$3); $$->addNext(new AstInitial($4,new AstAssign($4, new AstVarRef($4, *$1, true), $5))); } // // // 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 //UNSUP '=' class_new { UNSUP } ; list_of_tf_variable_identifiers: // ==IEEE: list_of_tf_variable_identifiers tf_variable_identifier { $$ = $1; } | list_of_tf_variable_identifiers ',' tf_variable_identifier { $$ = $1->addNext($3); } ; tf_variable_identifier: // IEEE: part of list_of_tf_variable_identifiers id variable_dimensionListE sigAttrListE { $$ = VARDONEA(*$1, $2, $3); } | id variable_dimensionListE sigAttrListE '=' expr { $$ = VARDONEA(*$1, $2, $3); $$->addNext(new AstAssign($4, new AstVarRef($4, *$1, true), $5)); } ; variable_declExpr: // IEEE: part of variable_decl_assignment - rhs of expr expr { $$ = $1; } //UNSUP dynamic_array_new { $$ = $1; } //UNSUP class_new { $$ = $1; } ; variable_dimensionListE: // IEEE: variable_dimension + empty /*empty*/ { $$ = NULL; } | variable_dimensionList { $$ = $1; } ; variable_dimensionList: // IEEE: variable_dimension + empty variable_dimension { $$ = $1; } | variable_dimensionList variable_dimension { $$ = $1->addNext($2)->castRange(); } ; variable_dimension: // ==IEEE: variable_dimension // // IEEE: unsized_dimension //UNSUP '[' ']' { UNSUP } // // IEEE: unpacked_dimension anyrange { $$ = $1; } | '[' constExpr ']' { $$ = new AstRange($1,$2,$2->cloneTree(true)); } // // IEEE: associative_dimension //UNSUP '[' data_type ']' { UNSUP } //UNSUP yP_BRASTAR ']' { UNSUP } //UNSUP '[' '*' ']' { UNSUP } // // IEEE: queue_dimension // // '[' '$' ']' -- $ is part of expr // // '[' '$' ':' expr ']' -- anyrange:expr:$ ; //************************************************ // Typedef data_declaration: // ==IEEE: data_declaration // // VARRESET can't be called here - conflicts data_declarationVar { $$ = $1; } //UNSUP type_declaration { $$ = $1; } //UNSUP package_import_declaration { $$ = $1; } // // 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 varRESET data_declarationVarFront list_of_variable_decl_assignments ';' { $$ = $3; } ; data_declarationVarFront: // IEEE: part of data_declaration // // implicit_type expanded into /*empty*/ or "signingE rangeList" //UNSUP constE yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDECL("var"); VARTYPE(SPACED($1,$4)); } //UNSUP constE yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDECL("var"); VARTYPE($1); } //UNSUP constE yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDECL("var"); VARTYPE(SPACED($1,SPACED($4,$5))); } // // // Expanded: "constE lifetimeE data_type" /**/ data_type { /*VARRESET-in-ddVar*/ VARTYPE($1); } | /**/ lifetime data_type { /*VARRESET-in-ddVar*/ VARTYPE($2); } //UNSUP yCONST__ETC lifetimeE data_type { /*VARRESET-in-ddVar*/ VARTYPE($3); } // // = class_new is in variable_decl_assignment ; implicit_type: // IEEE: part of *data_type_or_implicit // // Also expanded in data_declaration /* empty */ { $$ = NULL; } | signingE rangeList { $$ = $2; } // signing sets VARSIGNED, so not passed up | signing { $$ = NULL; } // signing sets VARSIGNED, so not passed up ; //************************************************ // Module Items module_itemListE: // IEEE: Part of module_declaration /* empty */ { $$ = NULL; } | module_itemList { $$ = $1; } ; module_itemList: // IEEE: Part of module_declaration module_item { $$ = $1; } | module_itemList module_item { $$ = $1->addNextNull($2); } ; module_item: // ==IEEE: module_item port_declaration ';' { $$ = $1; } | non_port_module_item { $$ = $1; } ; non_port_module_item: // ==IEEE: non_port_module_item generate_region { $$ = $1; } | module_or_generate_item { $$ = $1; } | specify_block { $$ = $1; } | specparam_declaration { $$ = $1; } //UNSUP program_declaration { $$ = $1; } //UNSUP module_declaration { $$ = $1; } //UNSUP interface_declaration { $$ = $1; } | timeunits_declaration { $$ = NULL; } // // Verilator specific | yaSCHDR { $$ = new AstScHdr(CRELINE(),*$1); } | yaSCINT { $$ = new AstScInt(CRELINE(),*$1); } | yaSCIMP { $$ = new AstScImp(CRELINE(),*$1); } | yaSCIMPH { $$ = new AstScImpHdr(CRELINE(),*$1); } | yaSCCTOR { $$ = new AstScCtor(CRELINE(),*$1); } | yaSCDTOR { $$ = new AstScDtor(CRELINE(),*$1); } | yVL_INLINE_MODULE { $$ = new AstPragma($1,AstPragmaType::INLINE_MODULE); } | yVL_NO_INLINE_MODULE { $$ = new AstPragma($1,AstPragmaType::NO_INLINE_MODULE); } | yVL_PUBLIC_MODULE { $$ = new AstPragma($1,AstPragmaType::PUBLIC_MODULE); } ; generate_region: // ==IEEE: generate_region yGENERATE genTopBlock yENDGENERATE { $$ = new AstGenerate($1, $2); } ; module_or_generate_item: // ==IEEE: module_or_generate_item // // IEEE: parameter_override yDEFPARAM list_of_defparam_assignments ';' { $$ = $2; } // // IEEE: gate_instantiation + udp_instantiation + module_instantiation // // not here, see etcInst in module_common_item // // We joined udp & module definitions, so this goes here //UNSUP combinational_body { $$ = $1; } | module_common_item { $$ = $1; } ; module_common_item: // ==IEEE: module_common_item module_or_generate_item_declaration { $$ = $1; } // // IEEE: interface_instantiation // // + IEEE: program_instantiation // // + module_instantiation from module_or_generate_item | etcInst { $$ = $1; } | concurrent_assertion_item { $$ = $1; } //UNSUP bind_directive { $$ = $1; } | continuous_assign { $$ = $1; } // // IEEE: net_alias //UNSUP yALIAS variable_lvalue aliasEqList ';' { UNSUP } | initial_construct { $$ = $1; } | final_construct { $$ = $1; } // // IEEE: always_construct // // Verilator only - event_control attached to always | yALWAYS event_controlE stmtBlock { $$ = new AstAlways($1,$2,$3); } | loop_generate_construct { $$ = $1; } | conditional_generate_construct { $$ = $1; } // // Verilator only | pslStmt { $$ = $1; } // | error ';' { $$ = NULL; } ; continuous_assign: // IEEE: continuous_assign yASSIGN delayE assignList ';' { $$ = $3; } //UNSUP: strengthSpecE not in above assign ; initial_construct: // IEEE: initial_construct yINITIAL stmtBlock { $$ = new AstInitial($1,$2); } ; final_construct: // IEEE: final_construct yFINAL stmtBlock { $$ = new AstFinal($1,$2); } ; module_or_generate_item_declaration: // ==IEEE: module_or_generate_item_declaration package_or_generate_item_declaration { $$ = $1; } | genvar_declaration { $$ = $1; } | clocking_declaration { $$ = $1; } //UNSUP yDEFAULT yCLOCKING idAny/*new-clocking_identifier*/ ';' { $$ = $1; } ; //************************************************ // Generates generate_block_or_null: // IEEE: generate_block_or_null // ';' // is included in // // IEEE: generate_block genItem { $$ = new AstBegin(CRELINE(),"genblk",$1); } | genItemBegin { $$ = $1; } ; genTopBlock: genItemList { $$ = $1; } | genItemBegin { $$ = $1; } ; genItemBegin: // IEEE: part of generate_block yBEGIN genItemList yEND { $$ = new AstBegin($1,"genblk",$2); } | yBEGIN yEND { $$ = NULL; } | id ':' yBEGIN genItemList yEND endLabelE { $$ = new AstBegin($2,*$1,$4); } | id ':' yBEGIN yEND endLabelE { $$ = NULL; } | yBEGIN ':' idAny genItemList yEND endLabelE { $$ = new AstBegin($2,*$3,$4); } | yBEGIN ':' idAny yEND endLabelE { $$ = NULL; } ; genItemList: genItem { $$ = $1; } | genItemList genItem { $$ = $1->addNextNull($2); } ; genItem: // IEEE: module_or_interface_or_generate_item module_or_generate_item { $$ = $1; } //UNSUP interface_or_generate_item { $$ = $1; } ; conditional_generate_construct: // ==IEEE: conditional_generate_construct yCASE '(' expr ')' case_generate_itemListE yENDCASE { $$ = new AstGenCase($1,$3,$5); } | yIF '(' expr ')' generate_block_or_null %prec prLOWER_THAN_ELSE { $$ = new AstGenIf($1,$3,$5,NULL); } | yIF '(' expr ')' generate_block_or_null yELSE generate_block_or_null { $$ = new AstGenIf($1,$3,$5,$7); } ; loop_generate_construct: // ==IEEE: loop_generate_construct yFOR '(' genvar_initialization ';' expr ';' genvar_iteration ')' generate_block_or_null { $$ = new AstGenFor($1,$3,$5,$7,$9); } ; genvar_initialization: // ==IEEE: genvar_initalization varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); } //UNSUP yGENVAR genvar_identifierDecl '=' constExpr { UNSUP } ; genvar_iteration: // ==IEEE: genvar_iteration varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); } //UNSUP id '=' expr { UNSUP } //UNSUP id yP_PLUSEQ expr { UNSUP } //UNSUP id yP_MINUSEQ expr { UNSUP } //UNSUP id yP_TIMESEQ expr { UNSUP } //UNSUP id yP_DIVEQ expr { UNSUP } //UNSUP id yP_MODEQ expr { UNSUP } //UNSUP id yP_ANDEQ expr { UNSUP } //UNSUP id yP_OREQ expr { UNSUP } //UNSUP id yP_XOREQ expr { UNSUP } //UNSUP id yP_SLEFTEQ expr { UNSUP } //UNSUP id yP_SRIGHTEQ expr { UNSUP } //UNSUP id yP_SSRIGHTEQ expr { UNSUP } // // inc_or_dec_operator //UNSUP yP_PLUSPLUS id { UNSUP } //UNSUP yP_MINUSMINUS id { UNSUP } //UNSUP id yP_PLUSPLUS { UNSUP } //UNSUP id yP_MINUSMINUS { UNSUP } ; case_generate_itemListE: // IEEE: [{ case_generate_itemList }] /* empty */ { $$ = NULL; } | case_generate_itemList { $$ = $1; } ; case_generate_itemList: // IEEE: { case_generate_itemList } case_generate_item { $$=$1; } | case_generate_itemList case_generate_item { $$=$1; $1->addNext($2); } ; case_generate_item: // ==IEEE: case_generate_item caseCondList ':' generate_block_or_null { $$ = new AstCaseItem($2,$1,$3); } | yDEFAULT ':' generate_block_or_null { $$ = new AstCaseItem($2,NULL,$3); } | yDEFAULT generate_block_or_null { $$ = new AstCaseItem($1,NULL,$2); } ; //************************************************ // Assignments and register declarations assignList: assignOne { $$ = $1; } | assignList ',' assignOne { $$ = $1->addNext($3); } ; assignOne: variable_lvalue '=' expr { $$ = new AstAssignW($2,$1,$3); } ; delayE: /* empty */ { } | delay_control { } /* ignored */ ; delay_control: //== IEEE: delay_control '#' delay_value { $$ = $1; } /* ignored */ | '#' '(' minTypMax ')' { $$ = $1; } /* ignored */ | '#' '(' minTypMax ',' minTypMax ')' { $$ = $1; } /* ignored */ | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' { $$ = $1; } /* ignored */ ; delay_value: // ==IEEE:delay_value // // IEEE: ps_identifier ps_id_etc { } | yaINTNUM { } | yaFLOATNUM { } | yaTIMENUM { } ; delayExpr: expr { } // // Verilator doesn't support yaFLOATNUM/yaTIMENUM, so not in expr | yaFLOATNUM { } | yaTIMENUM { } ; minTypMax: // IEEE: mintypmax_expression and constant_mintypmax_expression delayExpr { } | delayExpr ':' delayExpr ':' delayExpr { } ; netSigList: // IEEE: list_of_port_identifiers netSig { $$ = $1; } | netSigList ',' netSig { $$ = $1; $1->addNext($3); } ; netSig: // IEEE: net_decl_assignment - one element from list_of_port_identifiers netId sigAttrListE { $$ = VARDONEA(*$1, NULL, $2); } | netId sigAttrListE '=' expr { $$ = VARDONEA(*$1, NULL, $2); $$->addNext(new AstAssignW($3,new AstVarRef($3,$$->name(),true),$4)); } | netId rangeList sigAttrListE { $$ = VARDONEA(*$1, $2, $3); } ; netId: id/*new-net*/ { $$ = $1; } ; sigId: id { $$ = VARDONEA(*$1, NULL, NULL); } ; sigAttrListE: /* empty */ { $$ = NULL; } | sigAttrList { $$ = $1; } ; sigAttrList: sigAttr { $$ = $1; } | sigAttrList sigAttr { $$ = $1->addNextNull($2); } ; sigAttr: yVL_CLOCK { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK); } | yVL_CLOCK_ENABLE { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK_ENABLE); } | yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC); } | yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); } | yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); } ; rangeListE: // IEEE: [{packed_dimension}] /* empty */ { $$ = NULL; } | rangeList { $$ = $1; } ; rangeList: // IEEE: {packed_dimension} anyrange { $$ = $1; } | rangeList anyrange { $$ = $1; $1->addNext($2); } ; regrangeE: /* empty */ { $$ = NULL; VARRANGE($$); } | anyrange { $$ = $1; VARRANGE($$); } ; // IEEE: select // Merged into more general idArray anyrange: '[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$2,$4); } ; delayrange: regrangeE delayE { $$ = $1; } | ySCALARED regrangeE delayE { $$ = $2; } | yVECTORED regrangeE delayE { $$ = $2; } //UNSUP: ySCALARED/yVECTORED ignored ; //************************************************ // Parameters param_assignment: // ==IEEE: param_assignment // // IEEE: constant_param_expression // // constant_param_expression: '$' is in expr sigId sigAttrListE '=' expr { $$ = $1; $1->addAttrsp($2); $$->initp($4); } //UNSUP: exprOrDataType instead of expr ; list_of_param_assignments: // ==IEEE: list_of_param_assignments param_assignment { $$ = $1; } | list_of_param_assignments ',' param_assignment { $$ = $1; $1->addNext($3); } ; list_of_defparam_assignments: //== IEEE: list_of_defparam_assignments defparam_assignment { $$ = $1; } | list_of_defparam_assignments ',' defparam_assignment { $$ = $1->addNext($3); } ; defparam_assignment: // ==IEEE: defparam_assignment id '.' id '=' expr { $$ = new AstDefParam($4,*$1,*$3,$5); } //UNSUP More general dotted identifiers ; //************************************************ // 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 etcInst: // IEEE: module_instantiation + gate_instantiation + udp_instantiation instDecl { $$ = $1; } | gateDecl { $$ = $1; } ; instDecl: id parameter_value_assignmentE {INSTPREP(*$1,$2);} instnameList ';' { $$ = $4; V3Parse::s_impliedDecl=false;} //UNSUP: strengthSpecE for udp_instantiations ; instnameList: instnameParen { $$ = $1; } | instnameList ',' instnameParen { $$ = $1->addNext($3); } ; instnameParen: id instRangeE '(' cellpinList ')' { $$ = new AstCell($3, *$1,V3Parse::s_instModule,$4, V3Parse::s_instParamp,$2); } | id instRangeE { $$ = new AstCell(CRELINE(),*$1,V3Parse::s_instModule,NULL,V3Parse::s_instParamp,$2); } //UNSUP instRangeE '(' cellpinList ')' { UNSUP } // UDP ; instRangeE: /* empty */ { $$ = NULL; } | '[' constExpr ']' { $$ = new AstRange($1,$2,$2->cloneTree(true)); } | '[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$2,$4); } ; cellpinList: {VARRESET_LIST(UNKNOWN);} cellpinItList { $$ = $2; VARRESET_NONLIST(UNKNOWN); } ; cellpinItList: // IEEE: list_of_port_connections + list_of_parameter_assignmente cellpinItemE { $$ = $1; } | cellpinItList ',' cellpinItemE { $$ = $1->addNextNull($3)->castPin(); } ; cellpinItemE: // IEEE: named_port_connection + named_parameter_assignment + empty /* empty: ',,' is legal */ { $$ = NULL; PINNUMINC(); } | yP_DOTSTAR { $$ = new AstPin($1,PINNUMINC(),".*",NULL); } | '.' idAny { $$ = new AstPin($1,PINNUMINC(),*$2,new AstVarRef($1,*$2,false)); $$->svImplicit(true);} | '.' idAny '(' ')' { $$ = NULL; PINNUMINC(); } | '.' idAny '(' expr ')' { $$ = new AstPin($1,PINNUMINC(),*$2,$4); } // // For parameters //UNSUP '.' idAny '(' data_type ')' { PINDONE($1,$2,$4); GRAMMARP->pinNumInc(); } // // For parameters //UNSUP data_type { PINDONE($1->fileline(),"",$1); GRAMMARP->pinNumInc(); } // | expr { $$ = new AstPin($1->fileline(),PINNUMINC(),"",$1); } ; //************************************************ // EventControl lists event_controlE: /* empty */ { $$ = NULL; } | event_control { $$ = $1; } ; event_control: // ==IEEE: event_control '@' '(' event_expression ')' { $$ = new AstSenTree($1,$3); } | '@' '(' '*' ')' { $$ = NULL; } | '@' '*' { $$ = NULL; } // // IEEE: hierarchical_event_identifier | '@' senitemVar { $$ = new AstSenTree($1,$2); } /* For events only */ // // IEEE: sequence_instance // // 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 //| '@' idClassSel '(' list_of_argumentsE ')' { } ; event_expression: // IEEE: event_expression - split over several senitem { $$ = $1; } | event_expression yOR senitem { $$ = $1;$1->addNext($3); } | event_expression ',' senitem { $$ = $1;$1->addNext($3); } /* Verilog 2001 */ ; senitem: // IEEE: part of event_expression, non-'OR' ',' terms senitemEdge { $$ = $1; } | senitemVar { $$ = $1; } | '(' senitemVar ')' { $$ = $2; } //UNSUP expr { UNSUP } //UNSUP expr yIFF expr { UNSUP } ; senitemVar: idClassSel { $$ = new AstSenItem(CRELINE(),AstEdgeType::ANYEDGE,$1); } ; senitemEdge: // IEEE: part of event_expression yPOSEDGE idClassSel { $$ = new AstSenItem($1,AstEdgeType::POSEDGE,$2); } | yNEGEDGE idClassSel { $$ = new AstSenItem($1,AstEdgeType::NEGEDGE,$2); } | yPOSEDGE '(' idClassSel ')' { $$ = new AstSenItem($1,AstEdgeType::POSEDGE,$3); } | yNEGEDGE '(' idClassSel ')' { $$ = new AstSenItem($1,AstEdgeType::NEGEDGE,$3); } //UNSUP yIFF... ; //************************************************ // Statements stmtBlock: // IEEE: statement + seq_block + par_block stmt { $$ = $1; } ; seq_block: // ==IEEE: seq_block // // IEEE doesn't allow declarations in unnamed blocks, but several simulators do. yBEGIN blockDeclStmtList yEND { $$ = $2; } | yBEGIN /**/ yEND { $$ = NULL; } | yBEGIN ':' seq_blockId blockDeclStmtList yEND endLabelE { $$ = new AstBegin($2,*$3,$4); } | yBEGIN ':' seq_blockId /**/ yEND endLabelE { $$ = new AstBegin($2,*$3,NULL); } ; seq_blockId: // IEEE: part of seq_block idAny/*new-block_identifier*/ { $$ = $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 { $$ = $1; } | block_item_declarationList stmtList { $$ = $1->addNextNull($2); } | stmtList { $$ = $1; } ; block_item_declarationList: // IEEE: [ block_item_declaration ] block_item_declaration { $$ = $1; } | block_item_declarationList block_item_declaration { $$ = $1->addNextNull($2); } ; block_item_declaration: // ==IEEE: block_item_declaration data_declaration { $$ = $1; } | local_parameter_declaration { $$ = $1; } | parameter_declaration ';' { $$ = $1; } //UNSUP overload_declaration { $$ = $1; } ; stmtList: stmtBlock { $$ = $1; } | stmtList stmtBlock { $$ = ($2==NULL)?($1):($1->addNext($2)); } ; stmt: // IEEE: statement_or_null == function_statement_or_null statement_item { } //UNSUP: Labeling any statement | labeledStmt { $$ = $1; } | id ':' labeledStmt { $$ = new AstBegin($2, *$1, $3); } /*S05 block creation rule*/ // // from _or_null | ';' { $$ = NULL; } ; statement_item: // IEEE: statement_item // // IEEE: operator_assignment foperator_assignment ';' { $$ = $1; } // // // IEEE: blocking_assignment //UNSUP fexprLvalue '=' class_new ';' { UNSUP } //UNSUP fexprLvalue '=' dynamic_array_new ';' { UNSUP } // // // IEEE: nonblocking_assignment | idClassSel yP_LTE delayE expr ';' { $$ = new AstAssignDly($2,$1,$4); } | '{' variable_lvalueConcList '}' yP_LTE delayE expr ';' { $$ = new AstAssignDly($4,$2,$6); } //UNSUP fexprLvalue yP_LTE delay_or_event_controlE expr ';' { UNSUP } // // // IEEE: procedural_continuous_assignment | yASSIGN idClassSel '=' delayE expr ';' { $$ = new AstAssign($1,$2,$5); } //UNSUP: delay_or_event_controlE above //UNSUP yDEASSIGN variable_lvalue ';' { UNSUP } //UNSUP yFORCE expr '=' expr ';' { UNSUP } //UNSUP yRELEASE variable_lvalue ';' { UNSUP } // // // IEEE: case_statement | unique_priorityE caseStart caseAttrE case_itemListE yENDCASE { $$ = $2; if ($4) $2->addItemsp($4); if ($1 == uniq_UNIQUE) $2->parallelPragma(true); if ($1 == uniq_PRIORITY) $2->fullPragma(true); } //UNSUP caseStart caseAttrE yMATCHES case_patternListE yENDCASE { } //UNSUP caseStart caseAttrE yINSIDE case_insideListE yENDCASE { } // // // IEEE: conditional_statement | unique_priorityE yIF '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstIf($2,$4,$6,NULL); } | unique_priorityE yIF '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstIf($2,$4,$6,$8); } // //UNSUP finc_or_dec_expression ';' { } // // IEEE: inc_or_dec_expression // // Below under expr // // // IEEE: subroutine_call_statement //UNSUP yVOID yP_TICK '(' function_subroutine_callNoMethod ')' ';' { } //UNSUP 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 ';' { $$ = $1; } //UNSUP fexpr '.' array_methodNoRoot ';' { UNSUP } //UNSUP fexpr '.' task_subroutine_callNoMethod ';' { UNSUP } //UNSUP fexprScope ';' { UNSUP } // // 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 ')' ] ';' ] //UNSUP fexpr '.' class_new ';' { } // | statementVerilatorPragmas { $$ = $1; } // // // IEEE: disable_statement //UNSUP yDISABLE hierarchical_identifier/*task_or_block*/ ';' { UNSUP } //UNSUP yDISABLE yFORK ';' { UNSUP } // // IEEE: event_trigger //UNSUP yP_MINUSGT hierarchical_identifier/*event*/ ';' { UNSUP } //UNSUP yP_MINUSGTGT delay_or_event_controlE hierarchical_identifier/*event*/ ';' { UNSUP } // // IEEE: loop_statement | yFOREVER stmtBlock { $$ = new AstWhile($1,new AstConst($1,V3Number($1,1,1)),$2); } | yREPEAT '(' expr ')' stmtBlock { $$ = new AstRepeat($1,$3,$5);} | yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile($1,$3,$5);} // // for's first ';' is in for_initalization | yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock { $$ = new AstFor($1, $3,$4,$6, $8);} | yDO stmtBlock yWHILE '(' expr ')' { $$ = $2->cloneTree(true); $$->addNext(new AstWhile($1,$5,$2));} //UNSUP yFOREACH '(' idClassForeach/*array_id[loop_variables]*/ ')' stmt { UNSUP } // // // IEEE: jump_statement //UNSUP yRETURN ';' { UNSUP } //UNSUP yRETURN expr ';' { UNSUP } //UNSUP yBREAK ';' { UNSUP } //UNSUP yCONTINUE ';' { UNSUP } // //UNSUP par_block { $$ = $1; } // // IEEE: procedural_timing_control_statement + procedural_timing_control | delay_control stmtBlock { $$ = $2; $1->v3warn(STMTDLY,"Ignoring delay on this delayed statement.\n"); } //UNSUP event_control stmtBlock { UNSUP } //UNSUP cycle_delay stmtBlock { UNSUP } // | seq_block { $$ = $1; } // // // IEEE: wait_statement //UNSUP yWAIT '(' expr ')' stmtBlock { UNSUP } //UNSUP yWAIT yFORK ';' { UNSUP } //UNSUP yWAIT_ORDER '(' hierarchical_identifierList ')' action_block { UNSUP } // // // IEEE: procedural_assertion_statement // // Verilator: Label included instead | concurrent_assertion_item { $$ = $1; } // // concurrent_assertion_statement { $$ = $1; } // // Verilator: Part of labeledStmt instead // // immediate_assert_statement { UNSUP } // // // IEEE: clocking_drive ';' // // Pattern w/o cycle_delay handled by nonblocking_assign above // // clockvar_expression made to fexprLvalue to prevent reduce conflict // // Note LTE in this context is highest precedence, so first on left wins //UNSUP cycle_delay fexprLvalue yP_LTE ';' { UNSUP } //UNSUP fexprLvalue yP_LTE cycle_delay expr ';' { UNSUP } // //UNSUP randsequence_statement { $$ = $1; } // // // IEEE: randcase_statement //UNSUP yRANDCASE case_itemList yENDCASE { UNSUP } // //UNSUP expect_property_statement { $$ = $1; } // | error ';' { $$ = NULL; } ; statementVerilatorPragmas: yVL_COVERAGE_BLOCK_OFF { $$ = new AstPragma($1,AstPragmaType::COVERAGE_BLOCK_OFF); } ; foperator_assignment: // IEEE: operator_assignment (for first part of expression) idClassSel '=' delayE expr { $$ = new AstAssign($2,$1,$4); } | idClassSel '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen($3,$1,$5,$7); } | '{' variable_lvalueConcList '}' '=' delayE expr { $$ = new AstAssign($4,$2,$6); } // //UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { UNSUP } //UNSUP ~f~exprLvalue yP_PLUSEQ expr { UNSUP } //UNSUP ~f~exprLvalue yP_MINUSEQ expr { UNSUP } //UNSUP ~f~exprLvalue yP_TIMESEQ expr { UNSUP } //UNSUP ~f~exprLvalue yP_DIVEQ expr { UNSUP } //UNSUP ~f~exprLvalue yP_MODEQ expr { UNSUP } //UNSUP ~f~exprLvalue yP_ANDEQ expr { UNSUP } //UNSUP ~f~exprLvalue yP_OREQ expr { UNSUP } //UNSUP ~f~exprLvalue yP_XOREQ expr { UNSUP } //UNSUP ~f~exprLvalue yP_SLEFTEQ expr { UNSUP } //UNSUP ~f~exprLvalue yP_SRIGHTEQ expr { UNSUP } //UNSUP ~f~exprLvalue yP_SSRIGHTEQ expr { UNSUP } ; //************************************************ // Case/If unique_priorityE: // IEEE: unique_priority + empty /*empty*/ { $$ = uniq_NONE; } | yPRIORITY { $$ = uniq_PRIORITY; } | yUNIQUE { $$ = uniq_UNIQUE; } ; caseStart: // IEEE: part of case_statement yCASE '(' expr ')' { $$ = V3Parse::s_caseAttrp = new AstCase($1,AstCaseType::CASE,$3,NULL); } | yCASEX '(' expr ')' { $$ = V3Parse::s_caseAttrp = new AstCase($1,AstCaseType::CASEX,$3,NULL); $1->v3warn(CASEX,"Suggest casez (with ?'s) in place of casex (with X's)\n"); } | yCASEZ '(' expr ')' { $$ = V3Parse::s_caseAttrp = new AstCase($1,AstCaseType::CASEZ,$3,NULL); } ; caseAttrE: /*empty*/ { } | caseAttrE yVL_FULL_CASE { V3Parse::s_caseAttrp->fullPragma(true); } | caseAttrE yVL_PARALLEL_CASE { V3Parse::s_caseAttrp->parallelPragma(true); } ; case_itemListE: // IEEE: [ { case_item } ] /* empty */ { $$ = NULL; } | case_itemList { $$ = $1; } ; case_itemList: // IEEE: { case_item + ... } caseCondList ':' stmtBlock { $$ = new AstCaseItem($2,$1,$3); } | yDEFAULT ':' stmtBlock { $$ = new AstCaseItem($2,NULL,$3); } | yDEFAULT stmtBlock { $$ = new AstCaseItem($1,NULL,$2); } | case_itemList caseCondList ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($3,$2,$4)); } | case_itemList yDEFAULT stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($2,NULL,$3)); } | case_itemList yDEFAULT ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($3,NULL,$4)); } ; caseCondList: // IEEE: part of case_item expr { $$ = $1; } | caseCondList ',' expr { $$ = $1;$1->addNext($3); } ; // "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 varRefBase '=' expr ';' { $$ = new AstAssign($2,$1,$3); } //UNSUP: List of initializations ; for_stepE: // IEEE: for_step + empty /* empty */ { $$ = NULL; } | for_step { $$ = $1; } ; for_step: // IEEE: for_step varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); } //UNSUP: List of steps ; //************************************************ // Functions/tasks taskRef: // IEEE: part of tf_call idDotted { $$ = new AstTaskRef(CRELINE(),new AstParseRef($1->fileline(), AstParseRefExp::TASK, $1),NULL);} | idDotted '(' list_of_argumentsE ')' { $$ = new AstTaskRef(CRELINE(),new AstParseRef($1->fileline(), AstParseRefExp::TASK, $1),$3);} //UNSUP: idDotted is really just id to allow dotted method calls ; funcRef: // IEEE: part of tf_call idDotted '(' list_of_argumentsE ')' { $$ = new AstFuncRef($2,new AstParseRef($1->fileline(), AstParseRefExp::FUNC, $1), $3); } //UNSUP: idDotted is really just id to allow dotted method calls ; task_subroutine_callNoMethod: // function_subroutine_callNoMethod (as task) // // IEEE: tf_call taskRef { $$ = $1; } | system_t_call { $$ = $1; } // // IEEE: method_call requires a "." so is in expr //UNSUP randomize_call { $$ = $1; } ; function_subroutine_callNoMethod: // IEEE: function_subroutine_call (as function) // // IEEE: tf_call funcRef { $$ = $1; } | system_f_call { $$ = $1; } // // IEEE: method_call requires a "." so is in expr //UNSUP randomize_call { $$ = $1; } ; system_t_call: // IEEE: system_tf_call (as task) // yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCStmt($1,$3)); } | yD_FCLOSE '(' idClassSel ')' { $$ = new AstFClose($1, $3); } | yD_FFLUSH { $1->v3error("Unsupported: $fflush of all handles does not map to C++.\n"); } | yD_FFLUSH '(' ')' { $1->v3error("Unsupported: $fflush of all handles does not map to C++.\n"); } | yD_FFLUSH '(' idClassSel ')' { $$ = new AstFClose($1, $3); } | yD_FINISH parenE { $$ = new AstFinish($1); } | yD_FINISH '(' expr ')' { $$ = new AstFinish($1); } | yD_STOP parenE { $$ = new AstStop($1); } | yD_STOP '(' expr ')' { $$ = new AstStop($1); } // | yD_DISPLAY parenE { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,"", NULL,NULL); } | yD_DISPLAY '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$3,NULL,$4); } | yD_WRITE '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$3,NULL,$4); } | yD_FDISPLAY '(' idClassSel ',' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$5,$3,$6); } | yD_FWRITE '(' idClassSel ',' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$5,$3,$6); } | yD_INFO parenE { $$ = new AstDisplay($1,AstDisplayType::INFO, "", NULL,NULL); } | yD_INFO '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::INFO, *$3,NULL,$4); } | yD_WARNING parenE { $$ = new AstDisplay($1,AstDisplayType::WARNING,"", NULL,NULL); } | yD_WARNING '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WARNING,*$3,NULL,$4); } | yD_ERROR parenE { $$ = V3Parse::createDisplayError($1); } | yD_ERROR '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::ERROR, *$3,NULL,$4); $$->addNext(new AstStop($1)); } | yD_FATAL parenE { $$ = new AstDisplay($1,AstDisplayType::FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); } | yD_FATAL '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); if ($3) $3->deleteTree(); } | yD_FATAL '(' expr ',' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::FATAL, *$5,NULL,$6); $$->addNext(new AstStop($1)); if ($3) $3->deleteTree(); } // | yD_READMEMB '(' expr ',' varRefMem ')' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); } | yD_READMEMB '(' expr ',' varRefMem ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); } | yD_READMEMB '(' expr ',' varRefMem ',' expr ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); } | yD_READMEMH '(' expr ',' varRefMem ')' { $$ = new AstReadMem($1,true, $3,$5,NULL,NULL); } | yD_READMEMH '(' expr ',' varRefMem ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); } | yD_READMEMH '(' expr ',' varRefMem ',' expr ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); } ; system_f_call: // IEEE: system_tf_call (as func) yD_BITS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::BITS,$3); } | yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCFunc($1,$3)); } | yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); } | yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); } | yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); } | yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); } | yD_FGETS '(' idClassSel ',' expr ')' { $$ = new AstFGetS($1,$3,$5); } | yD_FSCANF '(' expr ',' yaSTRING commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); } | yD_SSCANF '(' expr ',' yaSTRING commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); } | yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1,$3); } | yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); } | yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); } | yD_RANDOM '(' expr ')' { $1->v3error("Unsupported: Seeding $random doesn't map to C++, use $c(\"srand\")\n"); } | yD_RANDOM '(' ')' { $$ = new AstRand($1); } | yD_RANDOM { $$ = new AstRand($1); } | yD_SIGNED '(' expr ')' { $$ = new AstSigned($1,$3); } | yD_STIME { $$ = new AstSel($1,new AstTime($1),0,32); } | yD_TIME { $$ = new AstTime($1); } | yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1,$3); } ; list_of_argumentsE: // IEEE: [list_of_arguments] /* empty */ { $$ = NULL; } | argsExprList { $$ = $1; } //UNSUP empty arguments with just ,, ; task_declaration: // ==IEEE: task_declaration yTASK lifetimeE taskId tfGuts yENDTASK endLabelE { $$ = new AstTask ($1,*$3,$4);} ; function_declaration: // IEEE: function_declaration + function_body_declaration yFUNCTION lifetimeE funcTypeE tfIdScoped tfGuts yENDFUNCTION endLabelE { $$ = new AstFunc ($1,*$4,$5,$3); if ($3) $$->isSigned($3->isSigned()); } | yFUNCTION lifetimeE funcTypeE tfIdScoped yVL_ISOLATE_ASSIGNMENTS tfGuts yENDFUNCTION endLabelE { $$ = new AstFunc ($1,*$4,$6,$3); $$->attrIsolateAssign(true); if ($3) $$->isSigned($3->isSigned()); } //UNSUP: Generic function return types ; lifetimeE: // IEEE: [lifetime] /* empty */ { } | lifetime { } ; lifetime: // ==IEEE: lifetime // // Note lifetime used by members is instead under memberQual ySTATIC { $1->v3error("Unsupported: Static in this context\n"); } | yAUTOMATIC { } ; taskId: tfIdScoped { $$ = $1; } ; tfIdScoped: // IEEE: part of function_body_declaration/task_body_declaration // // IEEE: [ interface_identifier '.' | class_scope ] function_identifier id { $$ = $1; } //UNSUP id/*interface_identifier*/ '.' id { UNSUP } //UNSUP class_scope_id { UNSUP } ; tfGuts: '(' tf_port_listE ')' ';' tfBodyE { $$ = $2->addNextNull($5); } | ';' tfBodyE { $$ = $2; } ; tfBodyE: // IEEE: part of function_body_declaration/task_body_declaration /* empty */ { $$ = NULL; } | tf_item_declarationList { $$ = $1; } | tf_item_declarationList stmtList { $$ = $1->addNextNull($2); } | stmtList { $$ = $1; } ; funcTypeE: /* empty */ { $$ = NULL; } | yINTEGER { $$ = new AstRange($1,31,0); $$->isSigned(true); } | ySIGNED { $$ = new AstRange($1,0,0); $$->isSigned(true); } | ySIGNED '[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$3,$5); $$->isSigned(true); } | '[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$2,$4); } ; tf_item_declarationList: tf_item_declaration { $$ = $1; } | tf_item_declarationList tf_item_declaration { $$ = $1->addNextNull($2); } ; tf_item_declaration: // ==IEEE: tf_item_declaration block_item_declaration { $$ = $1; } | tf_port_declaration { $$ = $1; } | tf_item_declarationVerilator { $$ = $1; } ; tf_item_declarationVerilator: // Verilator extensions yVL_PUBLIC { $$ = new AstPragma($1,AstPragmaType::PUBLIC_TASK); } | yVL_NO_INLINE_TASK { $$ = new AstPragma($1,AstPragmaType::NO_INLINE_TASK); } ; tf_port_listE: // IEEE: tf_port_list + empty // // Empty covered by tf_port_item {VARRESET_LIST(UNKNOWN);} tf_port_listList { $$ = $2; VARRESET_NONLIST(UNKNOWN); } ; tf_port_listList: // IEEE: part of tf_port_list tf_port_item { $$ = $1; } | tf_port_listList ',' tf_port_item { $$ = $1->addNextNull($3); } ; 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 */ { $$ = NULL; PINNUMINC(); } // For example a ",," port | tf_port_itemFront tf_port_itemAssignment { $$ = $2; } | tf_port_itemAssignment { $$ = $1; } ; tf_port_itemFront: // IEEE: part of tf_port_item, which has the data type data_type { VARTYPE($1); } | signingE rangeList { VARTYPE($2); } | signing { VARTYPE(NULL); } //UNSUP yVAR data_type { VARTYPE($2); } //UNSUP yVAR implicit_type { VARTYPE($2); } // | tf_port_itemDir /*implicit*/ { VARTYPE(NULL); /*default_nettype-see spec*/ } | tf_port_itemDir data_type { VARTYPE($2); } | tf_port_itemDir signingE rangeList { VARTYPE($3); } | tf_port_itemDir signing { VARTYPE(NULL); } //UNSUP tf_port_itemDir yVAR data_type { VARTYPE($3); } //UNSUP tf_port_itemDir yVAR implicit_type { VARTYPE($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 { $$ = VARDONEA(*$1, $2, $3); } | id variable_dimensionListE sigAttrListE '=' expr { $$ = VARDONEA(*$1, $2, $3); $$->initp($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 //************************************************ // 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; } ; expr: // IEEE: part of expression/constant_expression/primary // *SEE BELOW* // IEEE: primary/constant_primary // // // IEEE: unary_operator primary '+' ~r~expr %prec prUNARYARITH { $$ = $2; } | '-' ~r~expr %prec prUNARYARITH { $$ = new AstUnaryMin ($1,$2); } | '!' ~r~expr %prec prNEGATION { $$ = new AstLogNot ($1,$2); } | '&' ~r~expr %prec prREDUCTION { $$ = new AstRedAnd ($1,$2); } | '~' ~r~expr %prec prNEGATION { $$ = new AstNot ($1,$2); } | '|' ~r~expr %prec prREDUCTION { $$ = new AstRedOr ($1,$2); } | '^' ~r~expr %prec prREDUCTION { $$ = new AstRedXor ($1,$2); } | yP_NAND ~r~expr %prec prREDUCTION { $$ = new AstNot($1,new AstRedAnd($1,$2)); } | yP_NOR ~r~expr %prec prREDUCTION { $$ = new AstNot($1,new AstRedOr ($1,$2)); } | yP_XNOR ~r~expr %prec prREDUCTION { $$ = new AstRedXnor ($1,$2); } // // // IEEE: inc_or_dec_expression //UNSUP ~l~inc_or_dec_expression { UNSUP } // // // IEEE: '(' operator_assignment ')' // // Need exprScope of variable_lvalue to prevent conflict //UNSUP '(' ~p~exprScope '=' expr ')' { UNSUP } //UNSUP '(' ~p~exprScope yP_PLUSEQ expr ')' { UNSUP } //UNSUP '(' ~p~exprScope yP_MINUSEQ expr ')' { UNSUP } //UNSUP '(' ~p~exprScope yP_TIMESEQ expr ')' { UNSUP } //UNSUP '(' ~p~exprScope yP_DIVEQ expr ')' { UNSUP } //UNSUP '(' ~p~exprScope yP_MODEQ expr ')' { UNSUP } //UNSUP '(' ~p~exprScope yP_ANDEQ expr ')' { UNSUP } //UNSUP '(' ~p~exprScope yP_OREQ expr ')' { UNSUP } //UNSUP '(' ~p~exprScope yP_XOREQ expr ')' { UNSUP } //UNSUP '(' ~p~exprScope yP_SLEFTEQ expr ')' { UNSUP } //UNSUP '(' ~p~exprScope yP_SRIGHTEQ expr ')' { UNSUP } //UNSUP '(' ~p~exprScope yP_SSRIGHTEQ expr ')' { UNSUP } // // // IEEE: expression binary_operator expression | ~l~expr '+' ~r~expr { $$ = new AstAdd ($2,$1,$3); } | ~l~expr '-' ~r~expr { $$ = new AstSub ($2,$1,$3); } | ~l~expr '*' ~r~expr { $$ = new AstMul ($2,$1,$3); } | ~l~expr '/' ~r~expr { $$ = new AstDiv ($2,$1,$3); } | ~l~expr '%' ~r~expr { $$ = new AstModDiv ($2,$1,$3); } | ~l~expr yP_EQUAL ~r~expr { $$ = new AstEq ($2,$1,$3); } | ~l~expr yP_NOTEQUAL ~r~expr { $$ = new AstNeq ($2,$1,$3); } | ~l~expr yP_CASEEQUAL ~r~expr { $$ = new AstEqCase ($2,$1,$3); } | ~l~expr yP_CASENOTEQUAL ~r~expr { $$ = new AstNeqCase ($2,$1,$3); } | ~l~expr yP_WILDEQUAL ~r~expr { $$ = new AstEqWild ($2,$1,$3); } | ~l~expr yP_WILDNOTEQUAL ~r~expr { $$ = new AstNeqWild ($2,$1,$3); } | ~l~expr yP_ANDAND ~r~expr { $$ = new AstLogAnd ($2,$1,$3); } | ~l~expr yP_OROR ~r~expr { $$ = new AstLogOr ($2,$1,$3); } | ~l~expr yP_POW ~r~expr { $$ = new AstPow ($2,$1,$3); } | ~l~expr '<' ~r~expr { $$ = new AstLt ($2,$1,$3); } | ~l~expr '>' ~r~expr { $$ = new AstGt ($2,$1,$3); } | ~l~expr yP_GTE ~r~expr { $$ = new AstGte ($2,$1,$3); } | ~l~expr '&' ~r~expr { $$ = new AstAnd ($2,$1,$3); } | ~l~expr '|' ~r~expr { $$ = new AstOr ($2,$1,$3); } | ~l~expr '^' ~r~expr { $$ = new AstXor ($2,$1,$3); } | ~l~expr yP_XNOR ~r~expr { $$ = new AstXnor ($2,$1,$3); } | ~l~expr yP_NOR ~r~expr { $$ = new AstNot($2,new AstOr ($2,$1,$3)); } | ~l~expr yP_NAND ~r~expr { $$ = new AstNot($2,new AstAnd ($2,$1,$3)); } | ~l~expr yP_SLEFT ~r~expr { $$ = new AstShiftL ($2,$1,$3); } | ~l~expr yP_SRIGHT ~r~expr { $$ = new AstShiftR ($2,$1,$3); } | ~l~expr yP_SSRIGHT ~r~expr { $$ = new AstShiftRS ($2,$1,$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 { $$ = new AstLte ($2,$1,$3); } // // // IEEE: conditional_expression | ~l~expr '?' ~r~expr ':' ~r~expr { $$ = new AstCond($2,$1,$3,$5); } // // // IEEE: inside_expression //UNSUP ~l~expr yINSIDE '{' open_range_list '}' { UNSUP } // // // IEEE: tagged_union_expression //UNSUP yTAGGED id/*member*/ %prec prTAGGED { UNSUP } //UNSUP yTAGGED id/*member*/ %prec prTAGGED expr { UNSUP } // //======================// PSL expressions // | ~l~expr yP_MINUSGT ~r~expr { $$ = new AstLogIf ($2,$1,$3); } | ~l~expr yP_LOGIFF ~r~expr { $$ = new AstLogIff ($2,$1,$3); } // //======================// IEEE: primary/constant_primary // // // IEEE: primary_literal (minus string, which is handled specially) | yaINTNUM { $$ = new AstConst(CRELINE(),*$1); } //UNSUP yaFLOATNUM { UNSUP } //UNSUP yaTIMENUM { UNSUP } | strAsInt~noStr__IGNORE~ { $$ = $1; } // // // IEEE: "... hierarchical_identifier select" see below // // // IEEE: empty_queue //UNSUP '{' '}' // // // IEEE: concatenation/constant_concatenation // // Part of exprOkLvalue below // // // IEEE: multiple_concatenation/constant_multiple_concatenation | '{' constExpr '{' cateList '}' '}' { $$ = new AstReplicate($1,$4,$2); } // | function_subroutine_callNoMethod { $$ = $1; } // // method_call //UNSUP ~l~expr '.' function_subroutine_callNoMethod { UNSUP } // // method_call:array_method requires a '.' //UNSUP ~l~expr '.' array_methodNoRoot { UNSUP } // // // IEEE: '(' mintypmax_expression ')' | ~noPar__IGNORE~'(' expr ')' { $$ = $2; } //UNSUP ~noPar__IGNORE~'(' expr ':' expr ':' expr ')' { $$ = $4; } // // PSL rule | '_' '(' statePushVlg expr statePop ')' { $$ = $4; } // Arbitrary Verilog inside PSL // // // IEEE: cast/constant_cast //UNSUP casting_type yP_TICK '(' expr ')' { UNSUP } // // Spec only allows primary with addition of a type reference // // We'll be more general, and later assert LHS was a type. //UNSUP ~l~expr yP_TICK '(' expr ')' { UNSUP } // // // IEEE: assignment_pattern_expression // // IEEE: streaming_concatenation // // See exprOkLvalue // // // IEEE: sequence_method_call // // Indistinguishable from function_subroutine_call:method_call // //UNSUP '$' { UNSUP } //UNSUP yNULL { UNSUP } // // IEEE: yTHIS // // See exprScope // //---------------------- // | ~l~exprOkLvalue { $$ = $1; } // //---------------------- // // // IEEE: cond_predicate - here to avoid reduce problems // // Note expr includes cond_pattern //UNSUP ~l~expr yP_ANDANDAND ~r~expr { UNSUP } // // // IEEE: cond_pattern - here to avoid reduce problems // // "expr yMATCHES pattern" // // IEEE: pattern - expanded here to avoid conflicts //UNSUP ~l~expr yMATCHES patternNoExpr { UNSUP } //UNSUP ~l~expr yMATCHES ~r~expr { UNSUP } // // // IEEE: expression_or_dist - here to avoid reduce problems // // "expr yDIST '{' dist_list '}'" //UNSUP ~l~expr yDIST '{' dist_list '}' { UNSUP } ; exprNoStr: // expression with string removed BISONPRE_COPY(expr,{s/~noStr__IGNORE~/Ignore/g;}) // {copied} ; exprOkLvalue: // expression that's also OK to use as a variable_lvalue ~l~exprScope { $$ = $1; } // // IEEE: concatenation/constant_concatenation | '{' cateList '}' { $$ = $2; } // // IEEE: assignment_pattern_expression // // IEEE: [ assignment_pattern_expression_type ] == [ ps_type_id /ps_paremeter_id] // // We allow more here than the spec requires //UNSUP ~l~exprScope assignment_pattern { UNSUP } //UNSUP data_type assignment_pattern { UNSUP } //UNSUP assignment_pattern { UNSUP } // //UNSUP streaming_concatenation { UNSUP } ; 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. // // // 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 //UNSUP yTHIS { UNSUP } idClassSel { $$ = $1; } //UNSUP: idArrayed instead of idClassSel //UNSUP package_scopeIdFollows idArrayed { UNSUP } //UNSUP class_scopeIdFollows idArrayed { UNSUP } //UNSUP ~l~expr '.' idArrayed { UNSUP } // // expr below must be a "yTHIS" //UNSUP ~l~expr '.' ySUPER { UNSUP } // // Part of implicit_class_handle //UNSUP ySUPER { UNSUP } ; // Psl excludes {}'s by lexer converting to different token exprPsl: expr { $$ = $1; } ; // PLI calls exclude "" as integers, they're strings // For $c("foo","bar") we want "bar" as a string, not a Verilog integer. exprStrText: exprNoStr { $$ = $1; } | strAsText { $$ = $1; } ; cStrList: exprStrText { $$ = $1; } | exprStrText ',' cStrList { $$ = $1;$1->addNext($3); } ; cateList: // // Not just 'expr' to prevent conflict via stream_concOrExprOrType stream_expression { $$ = $1; } | cateList ',' stream_expression { $$ = new AstConcat($2,$1,$3); } ; exprList: expr { $$ = $1; } | exprList ',' expr { $$ = $1;$1->addNext($3); } ; commaEListE: /* empty */ { $$ = NULL; } | ',' exprList { $$ = $2; } ; vrdList: idClassSel { $$ = $1; } | vrdList ',' idClassSel { $$ = $1;$1->addNext($3); } ; commaVRDListE: /* empty */ { $$ = NULL; } | ',' vrdList { $$ = $2; } ; argsExprList: // IEEE: part of list_of_arguments (used where ,, isn't legal) expr { $$ = $1; } | argsExprList ',' expr { $$ = $1->addNext($3); } ; stream_expression: // ==IEEE: stream_expression // // IEEE: array_range_expression expanded below expr { $$ = $1; } //UNSUP expr yWITH__BRA '[' expr ']' { UNSUP } //UNSUP expr yWITH__BRA '[' expr ':' expr ']' { UNSUP } //UNSUP expr yWITH__BRA '[' expr yP_PLUSCOLON expr ']' { UNSUP } //UNSUP expr yWITH__BRA '[' expr yP_MINUSCOLON expr ']' { UNSUP } ; //************************************************ // Gate declarations gateDecl: yBUF delayE gateBufList ';' { $$ = $3; } | yBUFIF0 delayE gateBufif0List ';' { $$ = $3; } | yBUFIF1 delayE gateBufif1List ';' { $$ = $3; } | yNOT delayE gateNotList ';' { $$ = $3; } | yNOTIF0 delayE gateNotif0List ';' { $$ = $3; } | yNOTIF1 delayE gateNotif1List ';' { $$ = $3; } | yAND delayE gateAndList ';' { $$ = $3; } | yNAND delayE gateNandList ';' { $$ = $3; } | yOR delayE gateOrList ';' { $$ = $3; } | yNOR delayE gateNorList ';' { $$ = $3; } | yXOR delayE gateXorList ';' { $$ = $3; } | yXNOR delayE gateXnorList ';' { $$ = $3; } | yPULLUP delayE gatePullupList ';' { $$ = $3; } | yPULLDOWN delayE gatePulldownList ';' { $$ = $3; } ; gateBufList: gateBuf { $$ = $1; } | gateBufList ',' gateBuf { $$ = $1->addNext($3); } ; gateBufif0List: gateBufif0 { $$ = $1; } | gateBufif0List ',' gateBufif0 { $$ = $1->addNext($3); } ; gateBufif1List: gateBufif1 { $$ = $1; } | gateBufif1List ',' gateBufif1 { $$ = $1->addNext($3); } ; gateNotList: gateNot { $$ = $1; } | gateNotList ',' gateNot { $$ = $1->addNext($3); } ; gateNotif0List: gateNotif0 { $$ = $1; } | gateNotif0List ',' gateNotif0 { $$ = $1->addNext($3); } ; gateNotif1List: gateNotif1 { $$ = $1; } | gateNotif1List ',' gateNotif1 { $$ = $1->addNext($3); } ; gateAndList: gateAnd { $$ = $1; } | gateAndList ',' gateAnd { $$ = $1->addNext($3); } ; gateNandList: gateNand { $$ = $1; } | gateNandList ',' gateNand { $$ = $1->addNext($3); } ; gateOrList: gateOr { $$ = $1; } | gateOrList ',' gateOr { $$ = $1->addNext($3); } ; gateNorList: gateNor { $$ = $1; } | gateNorList ',' gateNor { $$ = $1->addNext($3); } ; gateXorList: gateXor { $$ = $1; } | gateXorList ',' gateXor { $$ = $1->addNext($3); } ; gateXnorList: gateXnor { $$ = $1; } | gateXnorList ',' gateXnor { $$ = $1->addNext($3); } ; gatePullupList: gatePullup { $$ = $1; } | gatePullupList ',' gatePullup { $$ = $1->addNext($3); } ; gatePulldownList: gatePulldown { $$ = $1; } | gatePulldownList ',' gatePulldown { $$ = $1->addNext($3); } ; gateBuf: gateIdE instRangeE '(' idClassSel ',' expr ')' { $$ = new AstAssignW ($3,$4,$6); $$->allowImplicit(true); } ; gateBufif0: gateIdE instRangeE '(' idClassSel ',' expr ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstCond($3,$8, new AstConst($3,V3Number($3,"1'bz")), $6)); } ; gateBufif1: gateIdE instRangeE '(' idClassSel ',' expr ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstCond($3,$8, $6, new AstConst($3,V3Number($3,"1'bz")))); } ; gateNot: gateIdE instRangeE '(' idClassSel ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); $$->allowImplicit(true); } ; gateNotif0: gateIdE instRangeE '(' idClassSel ',' expr ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstCond($3,$8, new AstConst($3,V3Number($3,"1'bz")), new AstNot($3, $6))); } ; gateNotif1: gateIdE instRangeE '(' idClassSel ',' expr ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstCond($3,$8, new AstNot($3,$6), new AstConst($3,V3Number($3,"1'bz")))); } ; gateAnd: gateIdE instRangeE '(' idClassSel ',' gateAndPinList ')' { $$ = new AstAssignW ($3,$4,$6); $$->allowImplicit(true); } ; gateNand: gateIdE instRangeE '(' idClassSel ',' gateAndPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); $$->allowImplicit(true); } ; gateOr: gateIdE instRangeE '(' idClassSel ',' gateOrPinList ')' { $$ = new AstAssignW ($3,$4,$6); $$->allowImplicit(true); } ; gateNor: gateIdE instRangeE '(' idClassSel ',' gateOrPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); $$->allowImplicit(true); } ; gateXor: gateIdE instRangeE '(' idClassSel ',' gateXorPinList ')' { $$ = new AstAssignW ($3,$4,$6); $$->allowImplicit(true); } ; gateXnor: gateIdE instRangeE '(' idClassSel ',' gateXorPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); $$->allowImplicit(true); } ; gatePullup: gateIdE instRangeE '(' idClassSel ')' { $$ = new AstPull ($3, $4, true); } ; gatePulldown: gateIdE instRangeE '(' idClassSel ')' { $$ = new AstPull ($3, $4, false); } ; gateIdE: /*empty*/ {} | id {} ; gateAndPinList: expr { $$ = $1; } | gateAndPinList ',' expr { $$ = new AstAnd($2,$1,$3); } ; gateOrPinList: expr { $$ = $1; } | gateOrPinList ',' expr { $$ = new AstOr($2,$1,$3); } ; gateXorPinList: expr { $$ = $1; } | gateXorPinList ',' expr { $$ = new AstXor($2,$1,$3); } ; strengthSpecE: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty /* empty */ { } //UNSUP strengthSpec { } ; //************************************************ // Tables // Not supported //************************************************ // Specify specify_block: // ==IEEE: specify_block ySPECIFY specifyJunkList yENDSPECIFY { $$ = NULL; } | ySPECIFY yENDSPECIFY { $$ = NULL; } ; specifyJunkList: specifyJunk { } /* ignored */ | specifyJunkList specifyJunk { } /* ignored */ ; specifyJunk: BISONPRE_NOT(ySPECIFY,yENDSPECIFY) { } | ySPECIFY specifyJunk yENDSPECIFY { } | error {} ; specparam_declaration: // ==IEEE: specparam_declaration ySPECPARAM junkToSemi ';' { $$ = NULL; } ; junkToSemi: BISONPRE_NOT(';',yENDSPECIFY,yENDMODULE) { } | error {} ; //************************************************ // IDs id: yaID__ETC { $$ = $1; } ; idAny: // Any kind of identifier //UNSUP yaID__aCLASS { $$ = $1; } //UNSUP yaID__aCOVERGROUP { $$ = $1; } //UNSUP yaID__aPACKAGE { $$ = $1; } //UNSUP yaID__aTYPE { $$ = $1; } yaID__ETC { $$ = $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; } | '{' variable_lvalueConcList '}' { $$ = $2; } // // IEEE: [ assignment_pattern_expression_type ] assignment_pattern_variable_lvalue // // We allow more assignment_pattern_expression_types then strictly required //UNSUP data_type yP_TICKBRA variable_lvalueList '}' { UNSUP } //UNSUP idClassSel yP_TICKBRA variable_lvalueList '}' { UNSUP } //UNSUP /**/ yP_TICKBRA variable_lvalueList '}' { UNSUP } //UNSUP streaming_concatenation { UNSUP } ; variable_lvalueConcList: // IEEE: part of variable_lvalue: '{' variable_lvalue { ',' variable_lvalue } '}' variable_lvalue { $$ = $1; } | variable_lvalueConcList ',' variable_lvalue { $$ = new AstConcat($2,$1,$3); } ; // VarRef to a Memory varRefMem: idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::VAR_MEM, $1); } ; // VarRef to dotted, and/or arrayed, and/or bit-ranged variable idClassSel: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::VAR_ANY, $1); } // // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select //UNSUP yTHIS '.' idDotted { UNSUP } //UNSUP ySUPER '.' idDotted { UNSUP } //UNSUP yTHIS '.' ySUPER '.' idDotted { UNSUP } // // Expanded: package_scope idDotted //UNSUP package_scopeIdFollows idDotted { UNSUP } ; idDotted: //UNSUP yD_ROOT '.' idDottedMore { UNSUP } idDottedMore { $$ = $1; } ; idDottedMore: idArrayed { $$ = $1; } | idDotted '.' idArrayed { $$ = new AstDot($2,$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 { $$ = new AstText(CRELINE(),*$1); } // // IEEE: id + part_select_range/constant_part_select_range | idArrayed '[' expr ']' { $$ = new AstSelBit($2,$1,$3); } // Or AstArraySel, don't know yet. | idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2,$1,$3,$5); } // // IEEE: id + indexed_range/constant_indexed_range | idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus($2,$1,$3,$5); } | idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2,$1,$3,$5); } ; // VarRef without any dots or vectorizaion varRefBase: id { $$ = new AstVarRef(CRELINE(),*$1,false);} ; strAsInt: yaSTRING { $$ = new AstConst(CRELINE(),V3Number(V3Number::VerilogString(),CRELINE(),V3Parse::deQuote(CRELINE(),*$1)));} ; strAsIntIgnore: // strAsInt, but never matches for when expr shouldn't parse strings yaSTRING__IGNORE { $$ = NULL; yyerror("Impossible token"); } ; strAsText: yaSTRING { $$ = V3Parse::createTextQuoted(CRELINE(),*$1);} ; endLabelE: /* empty */ { } | ':' idAny { } //UNSUP ':' yNEW__ETC { } ; //************************************************ // Clocking clocking_declaration: // IEEE: clocking_declaration (INCOMPLETE) yDEFAULT yCLOCKING '@' '(' senitemEdge ')' ';' yENDCLOCKING { $$ = new AstClocking($1, $5, NULL); } //UNSUP: Vastly simplified grammar ; //************************************************ // Asserts labeledStmt: immediate_assert_statement { $$ = $1; } ; concurrent_assertion_item: // IEEE: concurrent_assertion_item concurrent_assertion_statement { $$ = $1; } | id/*block_identifier*/ ':' concurrent_assertion_statement { $$ = new AstBegin($2,*$1,$3); } ; concurrent_assertion_statement: // ==IEEE: concurrent_assertion_statement //UNSUP: assert/assume // // IEEE: cover_property_statement yCOVER yPROPERTY '(' property_spec ')' stmtBlock { $$ = new AstPslCover($1,$4,$6); } ; property_spec: // IEEE: property_spec //UNSUP: This rule has been super-specialized to what is supported now '@' '(' senitemEdge ')' property_specDisable expr { $$ = new AstPslClocked($1,$3,$5,$6); } | '@' '(' senitemEdge ')' expr { $$ = new AstPslClocked($1,$3,NULL,$5); } | property_specDisable expr { $$ = new AstPslClocked($2->fileline(),NULL,$1,$2); } | expr { $$ = new AstPslClocked($1->fileline(),NULL,NULL,$1); } ; property_specDisable: // IEEE: part of property_spec yDISABLE yIFF '(' expr ')' { $$ = $4; } ; immediate_assert_statement: // ==IEEE: immediate_assert_statement // // action_block expanded here, for compatibility with AstVAssert yASSERT '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstVAssert($1,$3,$5, V3Parse::createDisplayError($1)); } | yASSERT '(' expr ')' yELSE stmtBlock { $$ = new AstVAssert($1,$3,NULL,$6); } | yASSERT '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstVAssert($1,$3,$5,$7); } ; //************************************************ // Covergroup //********************************************************************** // Randsequence //********************************************************************** // Class //========= // 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 { $$=$2; } ; //=== Below rules assume special scoping per above package_scopeIdFollowsE: // IEEE: [package_scope] // // IMPORTANT: The lexer will parse the following ID to be in the found package /* empty */ { } //UNSUP package_scopeIdFollows { UNSUP } ; //************************************************ // PSL Statements pslStmt: yPSL pslDir stateExitPsl { $$ = $2; } | yPSL pslDecl stateExitPsl { $$ = $2; } ; pslDir: id ':' pslDirOne { $$ = $3; } | pslDirOne { $$ = $1; } ; pslDirOne: yPSL_ASSERT pslProp ';' { $$ = new AstPslAssert($1,$2); } | yPSL_ASSERT pslProp yPSL_REPORT yaSTRING ';' { $$ = new AstPslAssert($1,$2,*$4); } | yPSL_COVER pslProp ';' { $$ = new AstPslCover($1,$2,NULL); } | yPSL_COVER pslProp yPSL_REPORT yaSTRING ';' { $$ = new AstPslCover($1,$2,NULL,*$4); } ; pslDecl: yDEFAULT yPSL_CLOCK '=' senitemEdge ';' { $$ = new AstPslDefClock($3, $4); } | yDEFAULT yPSL_CLOCK '=' '(' senitemEdge ')' ';' { $$ = new AstPslDefClock($3, $5); } ; //************************************************ // PSL Properties, Sequences and SEREs // Don't use '{' or '}'; in PSL they're yPSL_BRA and yPSL_KET to avoid expr concatenates pslProp: pslSequence { $$ = $1; } | pslSequence '@' %prec prPSLCLK '(' senitemEdge ')' { $$ = new AstPslClocked($2,$4,NULL,$1); } // or pslSequence @ ...? ; pslSequence: yPSL_BRA pslSere yPSL_KET { $$ = $2; } ; pslSere: pslExpr { $$ = $1; } | pslSequence { $$ = $1; } // Sequence containing sequence ; // Undocumented PSL rule is that {} is always a SERE; concatenation is not allowed. // This can be bypassed with the _(...) embedding of any arbitrary expression. pslExpr: exprPsl { $$ = new AstPslBool($1->fileline(), $1); } | yTRUE { $$ = new AstPslBool($1, new AstConst($1, V3Number($1,1,1))); } ; //********************************************************************** %% void V3Read::parserClear() { // Clear up any dynamic memory V3Parser required V3Parse::setRange(NULL); } AstNode* V3Parse::createSupplyExpr(FileLine* fileline, string name, int value) { FileLine* newfl = new FileLine (fileline); newfl->warnOff(V3ErrorCode::WIDTH, true); AstNode* nodep = new AstConst(newfl, V3Number(fileline)); // Adding a NOT is less work than figuring out how wide to make it if (value) nodep = new AstNot(newfl, nodep); nodep = new AstAssignW(newfl, new AstVarRef(fileline, name, true), nodep); return nodep; } AstVar* V3Parse::createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp) { AstVarType type = V3Parse::s_varIO; AstRange* rangep = V3Parse::s_varRangep; AstRange* cleanup_rangep = NULL; //UINFO(0,"CREVAR "<ascii()<<" decl="<v3fatalSrc("Unknown signal type declared"); // Linting, because we allow parsing of a superset of the language if (type == AstVarType::INTEGER || V3Parse::s_varDecl == AstVarType::INTEGER || type == AstVarType::GENVAR) { if (rangep) { if (rangep->msbConst()==31 && rangep->lsbConst()==0) { // For backward compatibility with functions some INTEGERS are internally made as [31:0] rangep->deleteTree(); rangep=NULL; V3Parse::s_varRangep=NULL; } else { fileline->v3error("Integers may not be ranged: "<v3error("Genvars may not be arrayed: "<cloneTree(false), arrayp); nodep->addAttrsp(attrsp); nodep->isSigned(V3Parse::s_varSigned); if (type == AstVarType::INTEGER || V3Parse::s_varDecl == AstVarType::INTEGER || type == AstVarType::GENVAR) { nodep->isSigned(true); } if (V3Parse::s_varDecl != AstVarType::UNKNOWN) nodep->combineType(V3Parse::s_varDecl); if (V3Parse::s_varIO != AstVarType::UNKNOWN) nodep->combineType(V3Parse::s_varIO); if (V3Parse::s_varDecl == AstVarType::SUPPLY0) { nodep->addNext(V3Parse::createSupplyExpr(fileline, nodep->name(), 0)); } if (V3Parse::s_varDecl == AstVarType::SUPPLY1) { nodep->addNext(V3Parse::createSupplyExpr(fileline, nodep->name(), 1)); } // Clear any widths that got presumed by the ranging; // We need to autosize parameters and integers separately nodep->width(0,0); // Propagate from current module tracing state if (nodep->isGenVar() || nodep->isParam()) nodep->trace(false); else nodep->trace(v3Global.opt.trace() && nodep->fileline()->tracingOn()); // Remember the last variable created, so we can attach attributes to it in later parsing V3Parse::s_varAttrp = nodep; if (cleanup_rangep) { cleanup_rangep->deleteTree(); cleanup_rangep=NULL; } return nodep; } string V3Parse::deQuote(FileLine* fileline, string text) { // Fix up the quoted strings the user put in, for example "\"" becomes " bool quoted = false; string newtext; unsigned char octal_val = 0; int octal_digits = 0; for (const char* cp=text.c_str(); *cp; ++cp) { if (quoted) { if (isdigit(*cp)) { octal_val = octal_val*8 + (*cp-'0'); if (++octal_digits == 3) { octal_digits = 0; quoted = false; newtext += octal_val; } } else { if (octal_digits) { // Spec allows 1-3 digits octal_digits = 0; quoted = false; newtext += octal_val; --cp; // Backup to reprocess terminating character as non-escaped continue; } quoted = false; if (*cp == 'n') newtext += '\n'; else if (*cp == 'a') newtext += '\a'; // SystemVerilog 3.1 else if (*cp == 'f') newtext += '\f'; // SystemVerilog 3.1 else if (*cp == 'r') newtext += '\r'; else if (*cp == 't') newtext += '\t'; else if (*cp == 'v') newtext += '\v'; // SystemVerilog 3.1 else if (*cp == 'x' && isxdigit(cp[1]) && isxdigit(cp[2])) { // SystemVerilog 3.1 #define vl_decodexdigit(c) ((isdigit(c)?((c)-'0'):(tolower((c))-'a'+10))) newtext += (char)(16*vl_decodexdigit(cp[1]) + vl_decodexdigit(cp[2])); cp += 2; } else if (isalnum(*cp)) { fileline->v3error("Unknown escape sequence: \\"<<*cp); break; } else newtext += *cp; } } else if (*cp == '\\') { quoted = true; octal_digits = 0; } else if (*cp != '"') { newtext += *cp; } } return newtext; } AstText* V3Parse::createTextQuoted(FileLine* fileline, string text) { string newtext = deQuote(fileline, text); return new AstText(fileline, newtext); } //YACC = /kits/sources/bison-2.4.1/src/bison --report=lookahead // --report=lookahead // --report=itemset // --graph // // Local Variables: // compile-command: "cd obj_dbg ; /usr/bin/bison -y -d -v ../verilog.y ; cat y.output" // End: