Internals: Make bison output have correct debug info (#6409)
1. Move class V3ParseGrammar into V3ParseGrammar.h so editors understand it as c++ code 2. Fix #line directives in the bison output file This together enables us to gdb through V3ParseGrammar, verilog.y, and the bison generated C code step by step, with all source annotations in the debug info pointing to the right place (e.g.: you will step to the right place in verilog.y, then step back to the bison generated switch statement/loop, and then step into calls in V3ParseGrammar as kind of expected.
This commit is contained in:
parent
77e5bb9ec9
commit
83ff8e13ba
|
|
@ -288,3 +288,5 @@ string V3ParseGrammar::unquoteString(FileLine* fileline, const std::string& text
|
||||||
if (!errMsg.empty()) fileline->v3error(errMsg.c_str());
|
if (!errMsg.empty()) fileline->v3error(errMsg.c_str());
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int V3ParseGrammar::s_typeImpNum = 0;
|
||||||
|
|
|
||||||
|
|
@ -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 <stack>
|
||||||
|
|
||||||
|
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<AstDelay> 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<int> 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<AstNode, AstNode>(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;
|
||||||
|
}
|
||||||
|
};
|
||||||
13
src/bisonpre
13
src/bisonpre
|
|
@ -106,11 +106,6 @@ def clean_output(filename, outname, is_output, is_c):
|
||||||
with open(filename, "r", encoding="utf-8") as fh:
|
with open(filename, "r", encoding="utf-8") as fh:
|
||||||
lines = fh.readlines()
|
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:
|
if is_output:
|
||||||
state_line = {}
|
state_line = {}
|
||||||
lineno = 0
|
lineno = 0
|
||||||
|
|
@ -151,9 +146,15 @@ def clean_output(filename, outname, is_output, is_c):
|
||||||
out = []
|
out = []
|
||||||
|
|
||||||
with open(outname, "w", encoding="utf-8") as fh:
|
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:
|
for line in lines:
|
||||||
# Fix filename refs
|
# 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
|
# Fix bison 2.3 and GCC 4.2.1
|
||||||
line = re.sub(r'\(YY_\("', '(YY_((char*)"', line)
|
line = re.sub(r'\(YY_\("', '(YY_((char*)"', line)
|
||||||
# Fix bison 2.3 glr-parser warning about yyerrorloc.YYTYPE::yydummy uninit
|
# Fix bison 2.3 glr-parser warning about yyerrorloc.YYTYPE::yydummy uninit
|
||||||
|
|
|
||||||
318
src/verilog.y
318
src/verilog.y
|
|
@ -22,14 +22,7 @@
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// clang-format on
|
// clang-format on
|
||||||
#include "V3Ast.h"
|
#include "V3ParseGrammar.h" // Defines YYTYPE; before including bison header
|
||||||
#include "V3Control.h"
|
|
||||||
#include "V3Global.h"
|
|
||||||
#include "V3ParseImp.h" // Defines YYTYPE; before including bison header
|
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <stack>
|
|
||||||
|
|
||||||
#define YYERROR_VERBOSE 1 // For prior to Bison 3.6
|
#define YYERROR_VERBOSE 1 // For prior to Bison 3.6
|
||||||
#define YYINITDEPTH 10000 // Older bisons ignore YYMAXDEPTH
|
#define YYINITDEPTH 10000 // Older bisons ignore YYMAXDEPTH
|
||||||
|
|
@ -75,318 +68,9 @@
|
||||||
#define PARSEP V3ParseImp::parsep()
|
#define PARSEP V3ParseImp::parsep()
|
||||||
#define GRAMMARP V3ParseGrammar::singletonp()
|
#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<AstDelay> 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<int> 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<AstNode, AstNode>(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 = VBasicDTypeKwd::LOGIC; // Shorthand "LOGIC"
|
||||||
const VBasicDTypeKwd LOGIC_IMPLICIT = VBasicDTypeKwd::LOGIC_IMPLICIT;
|
const VBasicDTypeKwd LOGIC_IMPLICIT = VBasicDTypeKwd::LOGIC_IMPLICIT;
|
||||||
|
|
||||||
int V3ParseGrammar::s_typeImpNum = 0;
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Macro functions
|
// Macro functions
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue