diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index e04993af2..ae76df10b 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -288,3 +288,5 @@ string V3ParseGrammar::unquoteString(FileLine* fileline, const std::string& text if (!errMsg.empty()) fileline->v3error(errMsg.c_str()); return res; } + +int V3ParseGrammar::s_typeImpNum = 0; diff --git a/src/V3ParseGrammar.h b/src/V3ParseGrammar.h new file mode 100644 index 000000000..0827f2651 --- /dev/null +++ b/src/V3ParseGrammar.h @@ -0,0 +1,329 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Parse syntax tree +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2025 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. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include "V3Ast.h" +#include "V3Control.h" +#include "V3Global.h" +#include "V3ParseImp.h" // Defines YYTYPE; before including bison header + +#include + +class V3ParseGrammar final { +public: + AstVar* m_varAttrp = nullptr; // Current variable for attribute adding + AstRange* m_gateRangep = nullptr; // Current range for gate declarations + AstNode* m_scopedSigAttr = nullptr; // Pointer to default signal attribute + AstCase* m_caseAttrp = nullptr; // Current case statement for attribute adding + AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration + AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration + std::unique_ptr m_netDelayp = nullptr; // Pointer to delay for next signal + // declaration + AstStrengthSpec* m_netStrengthp = nullptr; // Pointer to strength for next net declaration + FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations + AstPin* m_instParamp = nullptr; // Parameters for instantiations + string m_instModule; // Name of module referenced for instantiations + VVarType m_varDecl = VVarType::UNKNOWN; // Type for next signal declaration (reg/wire/etc) + VDirection m_varIO = VDirection::NONE; // Direction for next signal declaration (reg/wire/etc) + VLifetime m_varLifetime; // Static/Automatic for next signal + bool m_impliedDecl = false; // Allow implied wire declarations + bool m_varDeclTyped = false; // Var got reg/wire for dedup check + bool m_pinAnsi = false; // In ANSI parameter or port list + bool m_tracingParse = true; // Tracing disable for parser + bool m_inImplements = false; // Is inside class implements list + bool m_insideProperty = false; // Is inside property declaration + bool m_specifyignWarned = false; // Issued a SPECIFYIGN warning + bool m_typedPropertyPort = false; // Typed property port occurred on port lists + bool m_modportImpExpActive + = false; // Standalone ID is a tf_identifier instead of port_identifier + bool m_modportImpExpLastIsExport + = false; // Last import_export statement in modportPortsDecl is an export + + int m_pinNum = -1; // Pin number currently parsing + std::stack m_pinStack; // Queue of pin numbers being parsed + + static int s_typeImpNum; // Implicit type number, incremented each module + + // CONSTRUCTORS + V3ParseGrammar() {} + static V3ParseGrammar* singletonp() { + static V3ParseGrammar singleton; + return &singleton; + } + + // METHODS + AstArg* argWrapList(AstNodeExpr* nodep) VL_MT_DISABLED; + bool allTracingOn(FileLine* fl) { + return v3Global.opt.trace() && m_tracingParse && fl->tracingOn(); + } + AstRange* scrubRange(AstNodeRange* rangep) VL_MT_DISABLED; + AstNodePreSel* scrubSel(AstNodeExpr* fromp, AstNodePreSel* selp) VL_MT_DISABLED; + AstNodeDType* createArray(AstNodeDType* basep, AstNodeRange* rangep, + bool isPacked) VL_MT_DISABLED; + AstVar* createVariable(FileLine* fileline, const string& name, AstNodeRange* arrayp, + AstNode* attrsp) VL_MT_DISABLED; + AstNode* createSupplyExpr(FileLine* fileline, const string& name, int value) VL_MT_DISABLED; + AstText* createTextQuoted(FileLine* fileline, const string& text) { + string newtext = singletonp()->unquoteString(fileline, text); + return new AstText{fileline, newtext}; + } + AstNode* createCell(FileLine* fileline, const string& name, AstPin* pinlistp, + AstNodeRange* rangelistp) { + // Must clone m_instParamp as may be comma'ed list of instances + AstCell* const nodep = new AstCell{ + fileline, + singletonp()->m_instModuleFl, + name, + singletonp()->m_instModule, + pinlistp, + (singletonp()->m_instParamp ? singletonp()->m_instParamp->cloneTree(true) : nullptr), + singletonp()->scrubRange(rangelistp)}; + nodep->trace(singletonp()->allTracingOn(fileline)); + return nodep; + } + void createCoverGroupMethods(AstClass* nodep, AstNode* sampleArgs) { + // Hidden static to take unspecified reference argument results + AstVar* const defaultVarp + = new AstVar{nodep->fileline(), VVarType::MEMBER, "__Vint", nodep->findIntDType()}; + defaultVarp->lifetime(VLifetime::STATIC); + nodep->addStmtsp(defaultVarp); + + // IEEE: function void sample() + AstFunc* const funcp = new AstFunc{nodep->fileline(), "sample", nullptr, nullptr}; + funcp->addStmtsp(sampleArgs); + funcp->classMethod(true); + funcp->dtypep(funcp->findVoidDType()); + nodep->addMembersp(funcp); + + // IEEE: function void start(), void stop() + for (const string& name : {"start"s, "stop"s}) { + AstFunc* const funcp = new AstFunc{nodep->fileline(), name, nullptr, nullptr}; + funcp->classMethod(true); + funcp->dtypep(funcp->findVoidDType()); + nodep->addMembersp(funcp); + } + + // IEEE: static function real get_coverage(optional ref int, optional ref int) + // IEEE: function real get_inst_coverage(optional ref int, optional ref int) + for (const string& name : {"get_coverage"s, "get_inst_coverage"s}) { + AstFunc* const funcp = new AstFunc{nodep->fileline(), name, nullptr, nullptr}; + funcp->isStatic(name == "get_coverage"); + funcp->classMethod(true); + funcp->dtypep(funcp->findVoidDType()); + nodep->addMembersp(funcp); + { + AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, name, + nodep->findDoubleDType()}; + varp->lifetime(VLifetime::AUTOMATIC); + varp->funcLocal(true); + varp->direction(VDirection::OUTPUT); + varp->funcReturn(true); + funcp->fvarp(varp); + } + for (const string& varname : {"covered_bins"s, "total_bins"s}) { + AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, varname, + nodep->findStringDType()}; + varp->lifetime(VLifetime::AUTOMATIC); + varp->funcLocal(true); + varp->direction(VDirection::INPUT); + varp->valuep(new AstVarRef{nodep->fileline(), defaultVarp, VAccess::READ}); + funcp->addStmtsp(varp); + } + } + // IEEE: function void set_inst_name(string) + { + AstFunc* const funcp + = new AstFunc{nodep->fileline(), "set_inst_name", nullptr, nullptr}; + funcp->classMethod(true); + funcp->dtypep(funcp->findVoidDType()); + nodep->addMembersp(funcp); + AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, "name", + nodep->findStringDType()}; + varp->lifetime(VLifetime::AUTOMATIC); + varp->funcLocal(true); + varp->direction(VDirection::INPUT); + funcp->addStmtsp(varp); + } + } + AstDisplay* createDisplayError(FileLine* fileline) { + AstDisplay* nodep = new AstDisplay{fileline, VDisplayType::DT_ERROR, "", nullptr, nullptr}; + AstNode::addNext(nodep, new AstStop{fileline, false}); + return nodep; + } + AstNodeExpr* createGatePin(AstNodeExpr* exprp) { + AstRange* const rangep = m_gateRangep; + if (!rangep) { + return exprp; + } else { + return new AstGatePin{rangep->fileline(), exprp, rangep->cloneTree(true)}; + } + } + AstSenTree* createSenTreeChanged(FileLine* fl, AstNodeExpr* exprp) { + return new AstSenTree{fl, new AstSenItem{fl, VEdgeType::ET_CHANGED, exprp}}; + } + AstSenTree* createSenTreeDotStar(FileLine* fl) { + return new AstSenTree{fl, new AstSenItem{fl, VEdgeType::ET_COMBO_STAR, nullptr}}; + } + AstNodeExpr* createGlobalClockParseRef(FileLine* fl) { + return new AstParseRef{fl, VParseRefExp::PX_TEXT, "__024global_clock", nullptr, nullptr}; + } + AstSenTree* createGlobalClockSenTree(FileLine* fl) { + return createSenTreeChanged(fl, createGlobalClockParseRef(fl)); + } + AstNode* createNettype(FileLine* fl, const string& name) { + // As nettypes are unsupported, we just alias to logic + AstTypedef* const nodep = new AstTypedef{fl, name, nullptr, VFlagChildDType{}, + new AstBasicDType{fl, VFlagLogicPacked{}, 1}}; + V3ParseImp::parsep()->tagNodep(nodep); + return nodep; + } + AstNode* createTypedef(FileLine* fl, const string& name, AstNode* attrsp, AstNodeDType* basep, + AstNodeRange* rangep) { + AstTypedef* const nodep = new AstTypedef{fl, name, attrsp, VFlagChildDType{}, + singletonp()->createArray(basep, rangep, false)}; + V3ParseImp::parsep()->tagNodep(nodep); + return nodep; + } + AstNode* createTypedefFwd(FileLine* fl, const string& name, const VFwdType& fwdType) { + AstTypedefFwd* const nodep = new AstTypedefFwd{fl, name, fwdType}; + V3ParseImp::parsep()->tagNodep(nodep); + return nodep; + } + void endLabel(FileLine* fl, AstNode* nodep, string* endnamep) { + endLabel(fl, nodep->prettyName(), endnamep); + } + void endLabel(FileLine* fl, const string& name, string* endnamep) { + if (fl && endnamep && *endnamep != "" && name != *endnamep + && name != AstNode::prettyName(*endnamep)) { + fl->v3warn(ENDLABEL, "End label '" << *endnamep << "' does not match begin label '" + << name << "'"); + } + } + void setDType(AstNodeDType* dtypep) { + if (m_varDTypep) VL_DO_CLEAR(m_varDTypep->deleteTree(), m_varDTypep = nullptr); + m_varDTypep = dtypep; + } + void setNetDelay(AstDelay* netDelayp) { m_netDelayp.reset(netDelayp); } + AstDelay* getNetDelay() { return m_netDelayp.release(); } + void setNetStrength(AstStrengthSpec* netStrengthp) { m_netStrengthp = netStrengthp; } + void pinPush() { + m_pinStack.push(m_pinNum); + m_pinNum = 1; + } + void pinPop(FileLine* fl) { + if (VL_UNCOVERABLE(m_pinStack.empty())) fl->v3fatalSrc("Underflow of pin stack"); + m_pinNum = m_pinStack.top(); + m_pinStack.pop(); + } + AstNodeDType* addRange(AstBasicDType* dtypep, AstNodeRange* rangesp, bool isPacked) { + // If dtypep isn't basic, don't use this, call createArray() instead + if (!rangesp) { + return dtypep; + } else { + // If rangesp is "wire [3:3][2:2][1:1] foo [5:5][4:4]" + // then [1:1] becomes the basicdtype range; everything else is arraying + // the final [5:5][4:4] will be passed in another call to createArray + AstNodeRange* rangearraysp = nullptr; + if (dtypep->isRanged()) { + rangearraysp = rangesp; // Already a range; everything is an array + } else { + AstNodeRange* finalp = rangesp; + while (finalp->nextp()) finalp = VN_CAST(finalp->nextp(), Range); + if (finalp != rangesp) { + finalp->unlinkFrBack(); + rangearraysp = rangesp; + } + if (AstRange* const finalRangep = VN_CAST(finalp, Range)) { // not an UnsizedRange + if (dtypep->implicit()) { + // It's no longer implicit but a wire logic type + AstBasicDType* const newp = new AstBasicDType{ + dtypep->fileline(), VBasicDTypeKwd::LOGIC, dtypep->numeric(), + dtypep->width(), dtypep->widthMin()}; + VL_DO_DANGLING(dtypep->deleteTree(), dtypep); + dtypep = newp; + } + dtypep->rangep(finalRangep); + } + } + return createArray(dtypep, rangearraysp, isPacked); + } + } + string unquoteString(FileLine* fileline, const std::string& text) VL_MT_DISABLED; + void checkDpiVer(FileLine* fileline, const string& str) { + if (str != "DPI-C" && !v3Global.opt.bboxSys()) { + fileline->v3error("Unsupported DPI type '" << str << "': Use 'DPI-C'"); + } + } + // Given a list of clocking declarations, put them in clocking items + AstClockingItem* makeClockingItemList(FileLine* flp, const VDirection direction, + AstNodeExpr* skewp, AstNode* const clockingDeclps) { + AstClockingItem* itemsp = nullptr; + for (AstNode *nodep = clockingDeclps, *nextp; nodep; nodep = nextp) { + nextp = nodep->nextp(); + if (nextp) nextp->unlinkFrBackWithNext(); + if (itemsp && skewp) skewp = skewp->cloneTree(false); + AstClockingItem* itemp = new AstClockingItem{flp, direction, skewp, nodep}; + itemsp = itemsp ? itemsp->addNext(itemp) : itemp; + } + return itemsp; + } + + void setScopedSigAttr(AstNode* attrsp) { + if (m_scopedSigAttr) { // clearing set attribute + VL_DO_DANGLING(m_scopedSigAttr->deleteTree(), m_scopedSigAttr); + } + m_scopedSigAttr = attrsp; + } + + void createScopedSigAttr(VAttrType vattrT) { + setScopedSigAttr(new AstAttrOf{V3ParseImp::parsep()->lexFileline(), vattrT}); + } + + AstNode* cloneScopedSigAttr() const { + return m_scopedSigAttr ? m_scopedSigAttr->cloneTree(true) : nullptr; + } + + static void addForkStmtsp(AstFork* forkp, AstNode* stmtsp) { + forkp->addStmtsp(stmtsp); + for (AstNode* stmtp = stmtsp; stmtp; stmtp = stmtp->nextp()) { + AstVar* const varp = VN_CAST(stmtp, Var); + if (!varp) break; + varp->unlinkFrBack(); + varp->funcLocal(true); + forkp->addInitsp(varp); + } + } + + void createGenericIface(AstNode* const nodep, AstNodeRange* const rangep, + AstNode* sigAttrListp, FileLine* const modportFileline = nullptr, + const string& modportstrp = "") { + m_varDecl = VVarType::GPARAM; + m_varIO = VDirection::NONE; + setDType(new AstParseTypeDType{nodep->fileline(), VFwdType::GENERIC_INTERFACE}); + m_varDeclTyped = true; + const std::string uniqueName = "__VGIfaceParam" + nodep->name(); + AstNode::addNext(nodep, + createVariable(nodep->fileline(), uniqueName, rangep, sigAttrListp)); + m_varDecl = VVarType::IFACEREF; + AstIfaceGenericDType* const refdtypep + = new AstIfaceGenericDType{nodep->fileline(), modportFileline, modportstrp}; + setDType(refdtypep); + m_varDeclTyped = true; + m_varIO = VDirection::INPUT; + AstNode::addNext(nodep, + createVariable(nodep->fileline(), nodep->name(), rangep, sigAttrListp)); + m_varDecl = VVarType::VAR; + } +}; diff --git a/src/bisonpre b/src/bisonpre index 21bffd544..3830c972d 100755 --- a/src/bisonpre +++ b/src/bisonpre @@ -106,11 +106,6 @@ def clean_output(filename, outname, is_output, is_c): with open(filename, "r", encoding="utf-8") as fh: lines = fh.readlines() - basename = re.sub(r'.*/', '', tmp_prefix() + ".") - basename = re.escape(basename) - newbase = re.sub(r'.*/', '', Args.input) - newbase = re.sub(r'\.y', '.', newbase) - if is_output: state_line = {} lineno = 0 @@ -151,9 +146,15 @@ def clean_output(filename, outname, is_output, is_c): out = [] with open(outname, "w", encoding="utf-8") as fh: + tmpy = re.escape(tmp_prefix() + ".y") + newy = Args.input + tmpc = re.escape(tmp_prefix() + ".c") + newc = output_prefix() + ".c" + for line in lines: # Fix filename refs - line = re.sub(basename, newbase, line) + line = re.sub(tmpy, newy, line) + line = re.sub(tmpc, newc, line) # Fix bison 2.3 and GCC 4.2.1 line = re.sub(r'\(YY_\("', '(YY_((char*)"', line) # Fix bison 2.3 glr-parser warning about yyerrorloc.YYTYPE::yydummy uninit diff --git a/src/verilog.y b/src/verilog.y index 0d125d3fb..d5448cb1a 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -22,14 +22,7 @@ } #endif // clang-format on -#include "V3Ast.h" -#include "V3Control.h" -#include "V3Global.h" -#include "V3ParseImp.h" // Defines YYTYPE; before including bison header - -#include -#include -#include +#include "V3ParseGrammar.h" // Defines YYTYPE; before including bison header #define YYERROR_VERBOSE 1 // For prior to Bison 3.6 #define YYINITDEPTH 10000 // Older bisons ignore YYMAXDEPTH @@ -75,318 +68,9 @@ #define PARSEP V3ParseImp::parsep() #define GRAMMARP V3ParseGrammar::singletonp() -class V3ParseGrammar { -public: - AstVar* m_varAttrp = nullptr; // Current variable for attribute adding - AstRange* m_gateRangep = nullptr; // Current range for gate declarations - AstNode* m_scopedSigAttr = nullptr; // Pointer to default signal attribute - AstCase* m_caseAttrp = nullptr; // Current case statement for attribute adding - AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration - AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration - std::unique_ptr m_netDelayp = nullptr; // Pointer to delay for next signal - // declaration - AstStrengthSpec* m_netStrengthp = nullptr; // Pointer to strength for next net declaration - FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations - AstPin* m_instParamp = nullptr; // Parameters for instantiations - string m_instModule; // Name of module referenced for instantiations - VVarType m_varDecl = VVarType::UNKNOWN; // Type for next signal declaration (reg/wire/etc) - VDirection m_varIO = VDirection::NONE; // Direction for next signal declaration (reg/wire/etc) - VLifetime m_varLifetime; // Static/Automatic for next signal - bool m_impliedDecl = false; // Allow implied wire declarations - bool m_varDeclTyped = false; // Var got reg/wire for dedup check - bool m_pinAnsi = false; // In ANSI parameter or port list - bool m_tracingParse = true; // Tracing disable for parser - bool m_inImplements = false; // Is inside class implements list - bool m_insideProperty = false; // Is inside property declaration - bool m_specifyignWarned = false; // Issued a SPECIFYIGN warning - bool m_typedPropertyPort = false; // Typed property port occurred on port lists - bool m_modportImpExpActive - = false; // Standalone ID is a tf_identifier instead of port_identifier - bool m_modportImpExpLastIsExport - = false; // Last import_export statement in modportPortsDecl is an export - - int m_pinNum = -1; // Pin number currently parsing - std::stack m_pinStack; // Queue of pin numbers being parsed - - static int s_typeImpNum; // Implicit type number, incremented each module - - // CONSTRUCTORS - V3ParseGrammar() {} - static V3ParseGrammar* singletonp() { - static V3ParseGrammar singleton; - return &singleton; - } - - // METHODS - AstArg* argWrapList(AstNodeExpr* nodep) VL_MT_DISABLED; - bool allTracingOn(FileLine* fl) { - return v3Global.opt.trace() && m_tracingParse && fl->tracingOn(); - } - AstRange* scrubRange(AstNodeRange* rangep) VL_MT_DISABLED; - AstNodePreSel* scrubSel(AstNodeExpr* fromp, AstNodePreSel* selp) VL_MT_DISABLED; - AstNodeDType* createArray(AstNodeDType* basep, AstNodeRange* rangep, - bool isPacked) VL_MT_DISABLED; - AstVar* createVariable(FileLine* fileline, const string& name, AstNodeRange* arrayp, - AstNode* attrsp) VL_MT_DISABLED; - AstNode* createSupplyExpr(FileLine* fileline, const string& name, int value) VL_MT_DISABLED; - AstText* createTextQuoted(FileLine* fileline, const string& text) { - string newtext = GRAMMARP->unquoteString(fileline, text); - return new AstText{fileline, newtext}; - } - AstNode* createCell(FileLine* fileline, const string& name, AstPin* pinlistp, - AstNodeRange* rangelistp) { - // Must clone m_instParamp as may be comma'ed list of instances - AstCell* const nodep = new AstCell{ - fileline, - GRAMMARP->m_instModuleFl, - name, - GRAMMARP->m_instModule, - pinlistp, - (GRAMMARP->m_instParamp ? GRAMMARP->m_instParamp->cloneTree(true) : nullptr), - GRAMMARP->scrubRange(rangelistp)}; - nodep->trace(GRAMMARP->allTracingOn(fileline)); - return nodep; - } - void createCoverGroupMethods(AstClass* nodep, AstNode* sampleArgs) { - // Hidden static to take unspecified reference argument results - AstVar* const defaultVarp - = new AstVar{nodep->fileline(), VVarType::MEMBER, "__Vint", nodep->findIntDType()}; - defaultVarp->lifetime(VLifetime::STATIC); - nodep->addStmtsp(defaultVarp); - - // IEEE: function void sample() - AstFunc* const funcp = new AstFunc{nodep->fileline(), "sample", nullptr, nullptr}; - funcp->addStmtsp(sampleArgs); - funcp->classMethod(true); - funcp->dtypep(funcp->findVoidDType()); - nodep->addMembersp(funcp); - - // IEEE: function void start(), void stop() - for (const string& name : {"start"s, "stop"s}) { - AstFunc* const funcp = new AstFunc{nodep->fileline(), name, nullptr, nullptr}; - funcp->classMethod(true); - funcp->dtypep(funcp->findVoidDType()); - nodep->addMembersp(funcp); - } - - // IEEE: static function real get_coverage(optional ref int, optional ref int) - // IEEE: function real get_inst_coverage(optional ref int, optional ref int) - for (const string& name : {"get_coverage"s, "get_inst_coverage"s}) { - AstFunc* const funcp = new AstFunc{nodep->fileline(), name, nullptr, nullptr}; - funcp->isStatic(name == "get_coverage"); - funcp->classMethod(true); - funcp->dtypep(funcp->findVoidDType()); - nodep->addMembersp(funcp); - { - AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, name, - nodep->findDoubleDType()}; - varp->lifetime(VLifetime::AUTOMATIC); - varp->funcLocal(true); - varp->direction(VDirection::OUTPUT); - varp->funcReturn(true); - funcp->fvarp(varp); - } - for (const string& varname : {"covered_bins"s, "total_bins"s}) { - AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, varname, - nodep->findStringDType()}; - varp->lifetime(VLifetime::AUTOMATIC); - varp->funcLocal(true); - varp->direction(VDirection::INPUT); - varp->valuep(new AstVarRef{nodep->fileline(), defaultVarp, VAccess::READ}); - funcp->addStmtsp(varp); - } - } - // IEEE: function void set_inst_name(string) - { - AstFunc* const funcp - = new AstFunc{nodep->fileline(), "set_inst_name", nullptr, nullptr}; - funcp->classMethod(true); - funcp->dtypep(funcp->findVoidDType()); - nodep->addMembersp(funcp); - AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, "name", - nodep->findStringDType()}; - varp->lifetime(VLifetime::AUTOMATIC); - varp->funcLocal(true); - varp->direction(VDirection::INPUT); - funcp->addStmtsp(varp); - } - } - AstDisplay* createDisplayError(FileLine* fileline) { - AstDisplay* nodep = new AstDisplay{fileline, VDisplayType::DT_ERROR, "", nullptr, nullptr}; - AstNode::addNext(nodep, new AstStop{fileline, false}); - return nodep; - } - AstNodeExpr* createGatePin(AstNodeExpr* exprp) { - AstRange* const rangep = m_gateRangep; - if (!rangep) { - return exprp; - } else { - return new AstGatePin{rangep->fileline(), exprp, rangep->cloneTree(true)}; - } - } - AstSenTree* createSenTreeChanged(FileLine* fl, AstNodeExpr* exprp) { - return new AstSenTree{fl, new AstSenItem{fl, VEdgeType::ET_CHANGED, exprp}}; - } - AstSenTree* createSenTreeDotStar(FileLine* fl) { - return new AstSenTree{fl, new AstSenItem{fl, VEdgeType::ET_COMBO_STAR, nullptr}}; - } - AstNodeExpr* createGlobalClockParseRef(FileLine* fl) { - return new AstParseRef{fl, VParseRefExp::PX_TEXT, "__024global_clock", nullptr, nullptr}; - } - AstSenTree* createGlobalClockSenTree(FileLine* fl) { - return createSenTreeChanged(fl, createGlobalClockParseRef(fl)); - } - AstNode* createNettype(FileLine* fl, const string& name) { - // As nettypes are unsupported, we just alias to logic - AstTypedef* const nodep = new AstTypedef{fl, name, nullptr, VFlagChildDType{}, - new AstBasicDType{fl, VFlagLogicPacked{}, 1}}; - PARSEP->tagNodep(nodep); - return nodep; - } - AstNode* createTypedef(FileLine* fl, const string& name, AstNode* attrsp, AstNodeDType* basep, - AstNodeRange* rangep) { - AstTypedef* const nodep = new AstTypedef{fl, name, attrsp, VFlagChildDType{}, - GRAMMARP->createArray(basep, rangep, false)}; - PARSEP->tagNodep(nodep); - return nodep; - } - AstNode* createTypedefFwd(FileLine* fl, const string& name, const VFwdType& fwdType) { - AstTypedefFwd* const nodep = new AstTypedefFwd{fl, name, fwdType}; - PARSEP->tagNodep(nodep); - return nodep; - } - void endLabel(FileLine* fl, AstNode* nodep, string* endnamep) { - endLabel(fl, nodep->prettyName(), endnamep); - } - void endLabel(FileLine* fl, const string& name, string* endnamep) { - if (fl && endnamep && *endnamep != "" && name != *endnamep - && name != AstNode::prettyName(*endnamep)) { - fl->v3warn(ENDLABEL, "End label '" << *endnamep << "' does not match begin label '" - << name << "'"); - } - } - void setDType(AstNodeDType* dtypep) { - if (m_varDTypep) VL_DO_CLEAR(m_varDTypep->deleteTree(), m_varDTypep = nullptr); - m_varDTypep = dtypep; - } - void setNetDelay(AstDelay* netDelayp) { m_netDelayp.reset(netDelayp); } - AstDelay* getNetDelay() { return m_netDelayp.release(); } - void setNetStrength(AstStrengthSpec* netStrengthp) { m_netStrengthp = netStrengthp; } - void pinPush() { - m_pinStack.push(m_pinNum); - m_pinNum = 1; - } - void pinPop(FileLine* fl) { - if (VL_UNCOVERABLE(m_pinStack.empty())) fl->v3fatalSrc("Underflow of pin stack"); - m_pinNum = m_pinStack.top(); - m_pinStack.pop(); - } - AstNodeDType* addRange(AstBasicDType* dtypep, AstNodeRange* rangesp, bool isPacked) { - // If dtypep isn't basic, don't use this, call createArray() instead - if (!rangesp) { - return dtypep; - } else { - // If rangesp is "wire [3:3][2:2][1:1] foo [5:5][4:4]" - // then [1:1] becomes the basicdtype range; everything else is arraying - // the final [5:5][4:4] will be passed in another call to createArray - AstNodeRange* rangearraysp = nullptr; - if (dtypep->isRanged()) { - rangearraysp = rangesp; // Already a range; everything is an array - } else { - AstNodeRange* finalp = rangesp; - while (finalp->nextp()) finalp = VN_CAST(finalp->nextp(), Range); - if (finalp != rangesp) { - finalp->unlinkFrBack(); - rangearraysp = rangesp; - } - if (AstRange* const finalRangep = VN_CAST(finalp, Range)) { // not an UnsizedRange - if (dtypep->implicit()) { - // It's no longer implicit but a wire logic type - AstBasicDType* const newp = new AstBasicDType{ - dtypep->fileline(), VBasicDTypeKwd::LOGIC, dtypep->numeric(), - dtypep->width(), dtypep->widthMin()}; - VL_DO_DANGLING(dtypep->deleteTree(), dtypep); - dtypep = newp; - } - dtypep->rangep(finalRangep); - } - } - return createArray(dtypep, rangearraysp, isPacked); - } - } - string unquoteString(FileLine* fileline, const std::string& text) VL_MT_DISABLED; - void checkDpiVer(FileLine* fileline, const string& str) { - if (str != "DPI-C" && !v3Global.opt.bboxSys()) { - fileline->v3error("Unsupported DPI type '" << str << "': Use 'DPI-C'"); - } - } - // Given a list of clocking declarations, put them in clocking items - AstClockingItem* makeClockingItemList(FileLine* flp, const VDirection direction, - AstNodeExpr* skewp, AstNode* const clockingDeclps) { - AstClockingItem* itemsp = nullptr; - for (AstNode *nodep = clockingDeclps, *nextp; nodep; nodep = nextp) { - nextp = nodep->nextp(); - if (nextp) nextp->unlinkFrBackWithNext(); - if (itemsp && skewp) skewp = skewp->cloneTree(false); - AstClockingItem* itemp = new AstClockingItem{flp, direction, skewp, nodep}; - itemsp = itemsp ? itemsp->addNext(itemp) : itemp; - } - return itemsp; - } - - void setScopedSigAttr(AstNode* attrsp) { - if (m_scopedSigAttr) { // clearing set attribute - VL_DO_DANGLING(m_scopedSigAttr->deleteTree(), m_scopedSigAttr); - } - m_scopedSigAttr = attrsp; - } - - void createScopedSigAttr(VAttrType vattrT) { - setScopedSigAttr(new AstAttrOf{PARSEP->lexFileline(), vattrT}); - } - - AstNode* cloneScopedSigAttr() const { - return m_scopedSigAttr ? m_scopedSigAttr->cloneTree(true) : nullptr; - } - - static void addForkStmtsp(AstFork* forkp, AstNode* stmtsp) { - forkp->addStmtsp(stmtsp); - for (AstNode* stmtp = stmtsp; stmtp; stmtp = stmtp->nextp()) { - AstVar* const varp = VN_CAST(stmtp, Var); - if (!varp) break; - varp->unlinkFrBack(); - varp->funcLocal(true); - forkp->addInitsp(varp); - } - } - - void createGenericIface(AstNode* const nodep, AstNodeRange* const rangep, - AstNode* sigAttrListp, FileLine* const modportFileline = nullptr, - const string& modportstrp = "") { - m_varDecl = VVarType::GPARAM; - m_varIO = VDirection::NONE; - setDType(new AstParseTypeDType{nodep->fileline(), VFwdType::GENERIC_INTERFACE}); - m_varDeclTyped = true; - const std::string uniqueName = "__VGIfaceParam" + nodep->name(); - AstNode::addNext(nodep, - createVariable(nodep->fileline(), uniqueName, rangep, sigAttrListp)); - m_varDecl = VVarType::IFACEREF; - AstIfaceGenericDType* const refdtypep - = new AstIfaceGenericDType{nodep->fileline(), modportFileline, modportstrp}; - setDType(refdtypep); - m_varDeclTyped = true; - m_varIO = VDirection::INPUT; - AstNode::addNext(nodep, - createVariable(nodep->fileline(), nodep->name(), rangep, sigAttrListp)); - m_varDecl = VVarType::VAR; - } -}; - const VBasicDTypeKwd LOGIC = VBasicDTypeKwd::LOGIC; // Shorthand "LOGIC" const VBasicDTypeKwd LOGIC_IMPLICIT = VBasicDTypeKwd::LOGIC_IMPLICIT; -int V3ParseGrammar::s_typeImpNum = 0; - //====================================================================== // Macro functions