Internals: Move variable referencing into LinkDot in support of structs.
This commit is contained in:
parent
e655c85489
commit
b52d94273c
11
src/V3Ast.h
11
src/V3Ast.h
|
|
@ -500,10 +500,11 @@ class AstParseRefExp {
|
||||||
public:
|
public:
|
||||||
enum en {
|
enum en {
|
||||||
PX_NONE, // Used in V3LinkParse only
|
PX_NONE, // Used in V3LinkParse only
|
||||||
PX_VAR_MEM,
|
PX_TEXT, // Unknown ID component
|
||||||
PX_VAR_ANY,
|
PX_PREDOT, // Module name or misc component above var/task/func/member
|
||||||
PX_TASK,
|
PX_VAR_MEM, // Variable that must be a memory
|
||||||
PX_FUNC
|
PX_VAR_ANY, // Variable/structure member
|
||||||
|
PX_FTASK // Task/Function (AstParse::ftaskrefp() will be set)
|
||||||
};
|
};
|
||||||
enum en m_e;
|
enum en m_e;
|
||||||
inline AstParseRefExp() : m_e(PX_NONE) {}
|
inline AstParseRefExp() : m_e(PX_NONE) {}
|
||||||
|
|
@ -512,7 +513,7 @@ public:
|
||||||
operator en () const { return m_e; }
|
operator en () const { return m_e; }
|
||||||
const char* ascii() const {
|
const char* ascii() const {
|
||||||
static const char* names[] = {
|
static const char* names[] = {
|
||||||
"","VAR_MEM","VAR_ANY","TASK","FUNC"};
|
"","TEXT","PREDOT","VAR_MEM","VAR_ANY","FTASK"};
|
||||||
return names[m_e]; }
|
return names[m_e]; }
|
||||||
};
|
};
|
||||||
inline bool operator== (AstParseRefExp lhs, AstParseRefExp rhs) { return (lhs.m_e == rhs.m_e); }
|
inline bool operator== (AstParseRefExp lhs, AstParseRefExp rhs) { return (lhs.m_e == rhs.m_e); }
|
||||||
|
|
|
||||||
|
|
@ -806,6 +806,11 @@ void AstSenItem::dump(ostream& str) {
|
||||||
void AstParseRef::dump(ostream& str) {
|
void AstParseRef::dump(ostream& str) {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str<<" ["<<expect().ascii()<<"]";
|
str<<" ["<<expect().ascii()<<"]";
|
||||||
|
if (start()) str<<" [START]";
|
||||||
|
}
|
||||||
|
void AstDot::dump(ostream& str) {
|
||||||
|
this->AstNode::dump(str);
|
||||||
|
if (start()) str<<" [START]";
|
||||||
}
|
}
|
||||||
void AstActive::dump(ostream& str) {
|
void AstActive::dump(ostream& str) {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
|
|
|
||||||
|
|
@ -1263,33 +1263,48 @@ struct AstParseRef : public AstNode {
|
||||||
// We don't know which at parse time due to bison constraints
|
// We don't know which at parse time due to bison constraints
|
||||||
// The link stages will replace this with AstVarRef, or AstTaskRef, etc.
|
// The link stages will replace this with AstVarRef, or AstTaskRef, etc.
|
||||||
// Parents: math|stmt
|
// Parents: math|stmt
|
||||||
// Children: TEXT|DOT|SEL* (or expression under sel)
|
// Children: TEXT|DOT|SEL*|TASK|FUNC (or expression under sel)
|
||||||
private:
|
private:
|
||||||
AstParseRefExp m_expect; // Type we think it should resolve to
|
AstParseRefExp m_expect; // Type we think it should resolve to
|
||||||
|
string m_name;
|
||||||
|
bool m_start; // Start of parseref stack
|
||||||
public:
|
public:
|
||||||
AstParseRef(FileLine* fl, AstParseRefExp expect, AstNode* lhsp)
|
AstParseRef(FileLine* fl, AstParseRefExp expect, const string& name, AstNode* lhsp, AstNodeFTaskRef* ftaskrefp)
|
||||||
:AstNode(fl), m_expect(expect) { setOp1p(lhsp); }
|
:AstNode(fl), m_expect(expect), m_name(name) { setNOp1p(lhsp); setNOp2p(ftaskrefp); m_start=false; }
|
||||||
ASTNODE_NODE_FUNCS(ParseRef, PARSEREF)
|
ASTNODE_NODE_FUNCS(ParseRef, PARSEREF)
|
||||||
virtual void dump(ostream& str);
|
virtual void dump(ostream& str);
|
||||||
virtual V3Hash sameHash() const { return V3Hash(m_expect); }
|
virtual string name() const { return m_name; } // * = Var name
|
||||||
virtual bool same(AstNode* samep) const { return expect() == samep->castParseRef()->expect(); }
|
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_expect),V3Hash(m_name)); }
|
||||||
|
virtual bool same(AstNode* samep) const { return expect() == samep->castParseRef()->expect() && m_name==samep->castParseRef()->m_name; }
|
||||||
virtual string emitVerilog() { V3ERROR_NA; return ""; }
|
virtual string emitVerilog() { V3ERROR_NA; return ""; }
|
||||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||||
|
virtual void name(const string& name) { m_name = name; }
|
||||||
AstParseRefExp expect() const { return m_expect; }
|
AstParseRefExp expect() const { return m_expect; }
|
||||||
|
void expect(AstParseRefExp exp) { m_expect=exp; }
|
||||||
// op1 = Components
|
// op1 = Components
|
||||||
AstNode* lhsp() const { return op1p(); } // op1 = List of statements
|
AstNode* lhsp() const { return op1p(); } // op1 = List of statements
|
||||||
|
AstNode* ftaskrefp() const { return op2p(); } // op2 = Function/task reference
|
||||||
|
void ftaskrefp(AstNodeFTaskRef* nodep) { setNOp2p(nodep); } // op2 = Function/task reference
|
||||||
|
bool start() const { return m_start; }
|
||||||
|
void start(bool flag) { m_start = flag; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstDot : public AstNode {
|
struct AstDot : public AstNode {
|
||||||
// A dot separating paths in an AstXRef, AstFuncRef or AstTaskRef
|
// A dot separating paths in an AstXRef, AstFuncRef or AstTaskRef
|
||||||
// These are elimiated in the link stage
|
// These are eliminated in the link stage
|
||||||
|
private:
|
||||||
|
bool m_start; // Start of parseref stack
|
||||||
|
public:
|
||||||
AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||||
:AstNode(fl) { setOp1p(lhsp); setOp2p(rhsp); }
|
:AstNode(fl) { setOp1p(lhsp); setOp2p(rhsp); m_start=false; }
|
||||||
ASTNODE_NODE_FUNCS(Dot, DOT)
|
ASTNODE_NODE_FUNCS(Dot, DOT)
|
||||||
|
virtual void dump(ostream& str);
|
||||||
virtual string emitVerilog() { V3ERROR_NA; return ""; }
|
virtual string emitVerilog() { V3ERROR_NA; return ""; }
|
||||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||||
AstNode* lhsp() const { return op1p(); }
|
AstNode* lhsp() const { return op1p(); }
|
||||||
AstNode* rhsp() const { return op2p(); }
|
AstNode* rhsp() const { return op2p(); }
|
||||||
|
bool start() const { return m_start; }
|
||||||
|
void start(bool flag) { m_start = flag; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
|
||||||
|
|
@ -773,9 +773,9 @@ class LinkDotParamVisitor : public AstNVisitor {
|
||||||
private:
|
private:
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// Cleared on global
|
// Cleared on global
|
||||||
// *:user1p() -> See LinkDotState
|
// *::user1p() -> See LinkDotState
|
||||||
// *:user2p() -> See LinkDotState
|
// *::user2p() -> See LinkDotState
|
||||||
// *:user4() -> See LinkDotState
|
// *::user4() -> See LinkDotState
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
LinkDotState* m_statep; // State to pass between visitors, including symbol table
|
LinkDotState* m_statep; // State to pass between visitors, including symbol table
|
||||||
|
|
@ -786,7 +786,10 @@ private:
|
||||||
void pinImplicitExprRecurse(AstNode* nodep) {
|
void pinImplicitExprRecurse(AstNode* nodep) {
|
||||||
// Under a pin, Check interconnect expression for a pin reference or a concat.
|
// Under a pin, Check interconnect expression for a pin reference or a concat.
|
||||||
// Create implicit variable as needed
|
// Create implicit variable as needed
|
||||||
if (nodep->castVarRef()) {
|
if (nodep->castDot()) { // Not creating a simple implied type,
|
||||||
|
// and implying something else would just confuse later errors
|
||||||
|
}
|
||||||
|
if (nodep->castVarRef() || (nodep->castParseRef() && nodep->castParseRef()->start())) {
|
||||||
// To prevent user errors, we should only do single bit
|
// To prevent user errors, we should only do single bit
|
||||||
// implicit vars, however some netlists (MIPS) expect single
|
// implicit vars, however some netlists (MIPS) expect single
|
||||||
// bit implicit wires to get created with range 0:0 etc.
|
// bit implicit wires to get created with range 0:0 etc.
|
||||||
|
|
@ -982,47 +985,37 @@ class LinkDotResolveVisitor : public AstNVisitor {
|
||||||
private:
|
private:
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// Cleared on global
|
// Cleared on global
|
||||||
// *:user1p() -> See LinkDotState
|
// *::user1p() -> See LinkDotState
|
||||||
// *:user2p() -> See LinkDotState
|
// *::user2p() -> See LinkDotState
|
||||||
// *:user4() -> See LinkDotState
|
// *::user3() // bool. Processed
|
||||||
|
// *::user4() -> See LinkDotState
|
||||||
// Cleared on Cell
|
// Cleared on Cell
|
||||||
// AstVar::user5() // bool True if pin used in this cell
|
// AstVar::user5() // bool. True if pin used in this cell
|
||||||
|
AstUser3InUse m_inuser3;
|
||||||
AstUser5InUse m_inuser5;
|
AstUser5InUse m_inuser5;
|
||||||
|
|
||||||
|
// TYPES
|
||||||
|
enum DotPosition { DP_SCOPE, DP_VARETC, DP_MEMBER };
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
LinkDotState* m_statep; // State, including dotted symbol table
|
LinkDotState* m_statep; // State, including dotted symbol table
|
||||||
VSymEnt* m_curSymp; // SymEnt for current lookup point
|
VSymEnt* m_curSymp; // SymEnt for current lookup point
|
||||||
VSymEnt* m_modSymp; // SymEnt for current module
|
VSymEnt* m_modSymp; // SymEnt for current module
|
||||||
|
VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup
|
||||||
VSymEnt* m_pinSymp; // SymEnt for pin lookups
|
VSymEnt* m_pinSymp; // SymEnt for pin lookups
|
||||||
AstCell* m_cellp; // Current cell
|
AstCell* m_cellp; // Current cell
|
||||||
AstNodeModule* m_modp; // Current module
|
AstNodeModule* m_modp; // Current module
|
||||||
AstNodeFTask* m_ftaskp; // Current function/task
|
AstNodeFTask* m_ftaskp; // Current function/task
|
||||||
|
AstDot* m_dotp; // Current dot
|
||||||
|
DotPosition m_dotPos; // Scope part of dotted resolution
|
||||||
|
bool m_dotErr; // Error found in dotted resolution, ignore upwards
|
||||||
|
string m_dotText; // String of dotted names found in below parseref
|
||||||
|
|
||||||
int debug() { return LinkDotState::debug(); }
|
int debug() { return LinkDotState::debug(); }
|
||||||
|
|
||||||
// METHODS - Variables
|
// METHODS - Variables
|
||||||
bool linkVarName (VSymEnt* lookupSymp, AstVarRef* nodep) {
|
|
||||||
// Return true if changed, and caller should end processing
|
|
||||||
if (!nodep->varp()) {
|
|
||||||
UINFO(9," linkVarName se"<<(void*)lookupSymp<<" n="<<nodep<<endl);
|
|
||||||
if (!lookupSymp) nodep->v3fatalSrc("NULL lookup symbol table");
|
|
||||||
VSymEnt* foundp = lookupSymp->findIdFallback(nodep->name());
|
|
||||||
if (AstVar* varp = foundp->nodep()->castVar()) {
|
|
||||||
nodep->varp(varp);
|
|
||||||
nodep->packagep(foundp->packagep());
|
|
||||||
}
|
|
||||||
else if (AstEnumItem* valuep = foundp->nodep()->castEnumItem()) {
|
|
||||||
AstNode* newp = new AstEnumItemRef(nodep->fileline(), valuep, foundp->packagep());
|
|
||||||
nodep->replaceWith(newp);
|
|
||||||
nodep->deleteTree(); nodep=NULL;
|
|
||||||
return true; // Edited
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void createImplicitVar (VSymEnt* lookupSymp, AstVarRef* nodep, AstNodeModule* modp, VSymEnt* moduleSymp, bool noWarn) {
|
void createImplicitVar (VSymEnt* lookupSymp, AstVarRef* nodep, AstNodeModule* modp, VSymEnt* moduleSymp, bool noWarn) {
|
||||||
// Create implicit after warning
|
// Create implicit after warning
|
||||||
if (linkVarName(lookupSymp, nodep)) { nodep=NULL; return; }
|
|
||||||
if (!nodep->varp()) {
|
if (!nodep->varp()) {
|
||||||
if (!noWarn) {
|
if (!noWarn) {
|
||||||
if (nodep->fileline()->warnIsOff(V3ErrorCode::I_DEF_NETTYPE_WIRE)) {
|
if (nodep->fileline()->warnIsOff(V3ErrorCode::I_DEF_NETTYPE_WIRE)) {
|
||||||
|
|
@ -1054,18 +1047,18 @@ private:
|
||||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||||
if (nodep->dead()) return;
|
if (nodep->dead()) return;
|
||||||
UINFO(8," "<<nodep<<endl);
|
UINFO(8," "<<nodep<<endl);
|
||||||
m_curSymp = m_modSymp = m_statep->getNodeSym(nodep); // Until overridden by a SCOPE
|
m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep); // Until overridden by a SCOPE
|
||||||
m_cellp = NULL;
|
m_cellp = NULL;
|
||||||
m_modp = nodep;
|
m_modp = nodep;
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
m_curSymp = m_modSymp = NULL;
|
m_dotSymp = m_curSymp = m_modSymp = NULL;
|
||||||
}
|
}
|
||||||
virtual void visit(AstScope* nodep, AstNUser*) {
|
virtual void visit(AstScope* nodep, AstNUser*) {
|
||||||
UINFO(8," "<<nodep<<endl);
|
UINFO(8," "<<nodep<<endl);
|
||||||
m_curSymp = m_statep->getScopeSym(nodep);
|
m_dotSymp = m_curSymp = m_statep->getScopeSym(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
m_curSymp = NULL;
|
m_dotSymp = m_curSymp = NULL;
|
||||||
}
|
}
|
||||||
virtual void visit(AstCellInline* nodep, AstNUser*) {
|
virtual void visit(AstCellInline* nodep, AstNUser*) {
|
||||||
if (m_statep->forScopeCreation()) {
|
if (m_statep->forScopeCreation()) {
|
||||||
|
|
@ -1129,20 +1122,214 @@ private:
|
||||||
}
|
}
|
||||||
// Early return() above when deleted
|
// Early return() above when deleted
|
||||||
}
|
}
|
||||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
virtual void visit(AstDot* nodep, AstNUser*) {
|
||||||
// VarRef: Resolve its reference
|
if (nodep->user3SetOnce()) return;
|
||||||
nodep->iterateChildren(*this);
|
UINFO(8," "<<nodep<<endl);
|
||||||
if (!nodep->varp()) {
|
AstDot* lastDotp = m_dotp;
|
||||||
if (linkVarName(m_curSymp, nodep)) { nodep=NULL; return; }
|
string lastText = m_dotText;
|
||||||
if (!nodep->varp()) {
|
bool lastErr = m_dotErr;
|
||||||
bool err = (m_statep->forPrimary()
|
DotPosition lastDotPos = m_dotPos;
|
||||||
&& !m_statep->implicitOk(m_modp, nodep->name()));
|
VSymEnt* lastDotSymp = m_dotSymp;
|
||||||
|
bool start = nodep->start(); // Save, as nodep may go NULL
|
||||||
|
{
|
||||||
|
m_dotp = nodep; // Always, not just at start
|
||||||
|
if (start) { // Starting dot sequence
|
||||||
|
if (debug()>=9) nodep->dumpTree("-dot-in: ");
|
||||||
|
m_dotText = "";
|
||||||
|
m_dotErr = false;
|
||||||
|
m_dotSymp = m_curSymp; // Start from current point
|
||||||
|
}
|
||||||
|
// m_dotText communicates the cell prefix between stages
|
||||||
|
m_dotPos = DP_SCOPE;
|
||||||
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
|
if (!m_dotErr) { // Once something wrong, give up
|
||||||
|
if (start && m_dotPos==DP_SCOPE) m_dotPos = DP_VARETC; // Top dot RHS is final RHS, else it's a DOT(DOT(x,*here*),real-rhs) which we consider a RHS
|
||||||
|
nodep->rhsp()->iterateAndNext(*this);
|
||||||
|
}
|
||||||
|
if (start) {
|
||||||
|
AstNode* newp;
|
||||||
|
if (m_dotErr) {
|
||||||
|
newp = new AstConst(nodep->fileline(),AstConst::LogicFalse());
|
||||||
|
} else {
|
||||||
|
// RHS is what we're left with
|
||||||
|
newp = nodep->rhsp()->unlinkFrBack();
|
||||||
|
}
|
||||||
|
if (debug()>=9) newp->dumpTree("-dot-out: ");
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
pushDeletep(nodep); nodep=NULL;
|
||||||
|
} else { // Dot midpoint
|
||||||
|
AstNode* newp = nodep->rhsp()->unlinkFrBack();
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
pushDeletep(nodep); nodep=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_dotp = lastDotp;
|
||||||
|
if (start) {
|
||||||
|
m_dotText = lastText;
|
||||||
|
m_dotErr = lastErr;
|
||||||
|
m_dotPos = lastDotPos;
|
||||||
|
m_dotSymp = lastDotSymp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void visit(AstParseRef* nodep, AstNUser*) {
|
||||||
|
if (nodep->user3SetOnce()) return;
|
||||||
|
UINFO(9," linkPARSEREF se"<<(void*)m_dotSymp<<" pos="<<m_dotPos<<" txt="<<m_dotText<<" n="<<nodep<<endl);
|
||||||
|
// m_curSymp is symbol table of outer expression
|
||||||
|
// m_dotSymp is symbol table relative to "."'s above now
|
||||||
|
if (!m_dotSymp) nodep->v3fatalSrc("NULL lookup symbol table");
|
||||||
|
if (!m_statep->forPrimary()) nodep->v3fatalSrc("ParseRefs should no longer exist");
|
||||||
|
AstDot* lastDotp = m_dotp;
|
||||||
|
string lastText = m_dotText;
|
||||||
|
bool lastErr = m_dotErr;
|
||||||
|
DotPosition lastDotPos = m_dotPos;
|
||||||
|
VSymEnt* lastDotSymp = m_dotSymp;
|
||||||
|
bool start = nodep->start(); // Save, as nodep may go NULL
|
||||||
|
if (nodep->start()) {
|
||||||
|
m_dotp = NULL;
|
||||||
|
m_dotText = "";
|
||||||
|
m_dotErr = false;
|
||||||
|
m_dotPos = DP_VARETC;
|
||||||
|
m_dotSymp = m_curSymp;
|
||||||
|
}
|
||||||
|
if (m_dotPos == DP_MEMBER) {
|
||||||
|
nodep->v3error("Unsupported: Structs and dotted reference into variable");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//
|
||||||
|
string expectWhat;
|
||||||
|
bool allowScope = false;
|
||||||
|
bool allowVar = false;
|
||||||
|
bool onlyVar = false;
|
||||||
|
if (nodep->expect() == AstParseRefExp::PX_PREDOT) {
|
||||||
|
// {a}.{b}, where {a} maybe a module name
|
||||||
|
// FUTURE: or variable, where dotting into structure member
|
||||||
|
expectWhat = "scope/variable";
|
||||||
|
allowScope = true;
|
||||||
|
allowVar = true;
|
||||||
|
} else if (nodep->expect() == AstParseRefExp::PX_VAR_MEM
|
||||||
|
|| nodep->expect() == AstParseRefExp::PX_VAR_ANY) {
|
||||||
|
expectWhat = "variable";
|
||||||
|
onlyVar = true;
|
||||||
|
allowVar = true;
|
||||||
|
} else if (nodep->expect() == AstParseRefExp::PX_FTASK) {
|
||||||
|
expectWhat = "task/function";
|
||||||
|
} else {
|
||||||
|
nodep->v3fatalSrc("Unhandled AstParseRefExp");
|
||||||
|
}
|
||||||
|
// Lookup
|
||||||
|
VSymEnt* foundp;
|
||||||
|
string baddot;
|
||||||
|
VSymEnt* okSymp = NULL;
|
||||||
|
if (allowScope) {
|
||||||
|
foundp = m_statep->findDotted(m_dotSymp, nodep->name(), baddot, okSymp); // Maybe NULL
|
||||||
|
} else {
|
||||||
|
foundp = m_dotSymp->findIdFallback(nodep->name());
|
||||||
|
}
|
||||||
|
if (foundp) UINFO(9," found=se"<<(void*)foundp<<" n="<<foundp->nodep()<<endl);
|
||||||
|
// What fell out?
|
||||||
|
bool ok = false;
|
||||||
|
if (foundp->nodep()->castCell() || foundp->nodep()->castBegin()
|
||||||
|
|| foundp->nodep()->castModule()) { // if top
|
||||||
|
if (allowScope) {
|
||||||
|
ok = true;
|
||||||
|
if (m_dotText!="") m_dotText += ".";
|
||||||
|
m_dotText += nodep->name();
|
||||||
|
m_dotSymp = foundp;
|
||||||
|
// Upper AstDot visitor will handle it from here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (AstVar* varp = foundp->nodep()->castVar()) {
|
||||||
|
if (allowVar) {
|
||||||
|
AstNodeVarRef* newp;
|
||||||
|
if (m_dotText != "") {
|
||||||
|
newp = new AstVarXRef(nodep->fileline(), nodep->name(), m_dotText, false); // lvalue'ness computed later
|
||||||
|
newp->varp(varp);
|
||||||
|
m_dotText = "";
|
||||||
|
} else {
|
||||||
|
newp = new AstVarRef(nodep->fileline(), nodep->name(), false); // lvalue'ness computed later
|
||||||
|
newp->varp(varp);
|
||||||
|
newp->packagep(foundp->packagep());
|
||||||
|
}
|
||||||
|
nodep->replaceWith(newp); pushDeletep(nodep); nodep = NULL;
|
||||||
|
m_dotPos = DP_MEMBER;
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (AstEnumItem* valuep = foundp->nodep()->castEnumItem()) {
|
||||||
|
if (allowVar) {
|
||||||
|
AstNode* newp = new AstEnumItemRef(nodep->fileline(), valuep, foundp->packagep());
|
||||||
|
nodep->replaceWith(newp); pushDeletep(nodep); nodep = NULL;
|
||||||
|
ok = true;
|
||||||
|
m_dotText = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (AstNodeFTask* ftaskp = foundp->nodep()->castNodeFTask()) {
|
||||||
|
if (nodep->expect() == AstParseRefExp::PX_FTASK) {
|
||||||
|
AstNodeFTaskRef* refp = nodep->ftaskrefp()->castNodeFTaskRef();
|
||||||
|
if (!refp) nodep->v3fatalSrc("Parseref indicates FTASKref but none found");
|
||||||
|
refp->name(nodep->name());
|
||||||
|
refp->dotted(m_dotText); // Maybe ""
|
||||||
|
refp->taskp(ftaskp);
|
||||||
|
refp->packagep(foundp->packagep()); // Generally set by parse, but might be an import
|
||||||
|
taskFuncSwapCheck(refp);
|
||||||
|
refp->unlinkFrBack();
|
||||||
|
nodep->replaceWith(refp); pushDeletep(nodep); nodep = NULL;
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if (!ok) {
|
||||||
|
bool checkImplicit = (onlyVar && m_dotText=="");
|
||||||
|
bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name()));
|
||||||
if (err) {
|
if (err) {
|
||||||
m_statep->preErrorDump();
|
m_statep->preErrorDump();
|
||||||
nodep->v3error("Can't find definition of signal: "<<nodep->prettyName());
|
if (foundp) {
|
||||||
|
nodep->v3error("Found definition of '"<<m_dotText<<(m_dotText==""?"":".")<<nodep->prettyName()
|
||||||
|
<<"'"<<" as a "<<foundp->nodep()->typeName()
|
||||||
|
<<" but expected a "<<expectWhat);
|
||||||
|
} else if (m_dotText=="") {
|
||||||
|
nodep->v3error("Can't find definition of "<<expectWhat
|
||||||
|
<<": "<<nodep->prettyName());
|
||||||
|
} else {
|
||||||
|
nodep->v3error("Can't find definition of '"<<(baddot!=""?baddot:nodep->prettyName())<<"' in dotted "
|
||||||
|
<<expectWhat<<": "<<m_dotText+"."+nodep->prettyName());
|
||||||
|
okSymp->cellErrorScopes(nodep, AstNode::prettyName(m_dotText));
|
||||||
|
}
|
||||||
|
m_dotErr = true;
|
||||||
}
|
}
|
||||||
// Create even if error, so only complain once
|
if (checkImplicit) { // Else if a scope is allowed, making a signal won't help error cascade
|
||||||
createImplicitVar (m_curSymp, nodep, m_modp, m_modSymp, err);
|
// Create if implicit, and also if error (so only complain once)
|
||||||
|
AstVarRef* newp = new AstVarRef(nodep->fileline(), nodep->name(), false);
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
pushDeletep(nodep); nodep = NULL;
|
||||||
|
createImplicitVar (m_curSymp, newp, m_modp, m_modSymp, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start) {
|
||||||
|
m_dotp = lastDotp;
|
||||||
|
m_dotText = lastText;
|
||||||
|
m_dotErr = lastErr;
|
||||||
|
m_dotPos = lastDotPos;
|
||||||
|
m_dotSymp = lastDotSymp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||||
|
// VarRef: Resolve its reference
|
||||||
|
// ParseRefs are used the first pass (forPrimary) so we shouldn't get can't find
|
||||||
|
// errors here now that we have a VarRef.
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
if (!nodep->varp()) {
|
||||||
|
UINFO(9," linkVarRef se"<<(void*)m_curSymp<<" n="<<nodep<<endl);
|
||||||
|
if (!m_curSymp) nodep->v3fatalSrc("NULL lookup symbol table");
|
||||||
|
VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());
|
||||||
|
if (AstVar* varp = foundp->nodep()->castVar()) {
|
||||||
|
nodep->varp(varp);
|
||||||
|
nodep->packagep(foundp->packagep()); // Generally set by parse, but might be an import
|
||||||
|
}
|
||||||
|
if (!nodep->varp()) {
|
||||||
|
m_statep->preErrorDump();
|
||||||
|
nodep->v3error("Can't find definition of signal, again: "<<nodep->prettyName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1150,6 +1337,7 @@ private:
|
||||||
// VarRef: Resolve its reference
|
// VarRef: Resolve its reference
|
||||||
// We always link even if varp() is set, because the module we choose may change
|
// We always link even if varp() is set, because the module we choose may change
|
||||||
// due to creating new modules, flattening, etc.
|
// due to creating new modules, flattening, etc.
|
||||||
|
if (nodep->user3SetOnce()) return;
|
||||||
UINFO(8," "<<nodep<<endl);
|
UINFO(8," "<<nodep<<endl);
|
||||||
if (!m_modSymp) {
|
if (!m_modSymp) {
|
||||||
UINFO(9,"Dead module for "<<nodep<<endl);
|
UINFO(9,"Dead module for "<<nodep<<endl);
|
||||||
|
|
@ -1208,6 +1396,7 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||||
|
if (nodep->user3SetOnce()) return;
|
||||||
UINFO(8," "<<nodep<<endl);
|
UINFO(8," "<<nodep<<endl);
|
||||||
if (nodep->packagep() && nodep->taskp()) {
|
if (nodep->packagep() && nodep->taskp()) {
|
||||||
// References into packages don't care about cell hierarchy.
|
// References into packages don't care about cell hierarchy.
|
||||||
|
|
@ -1259,15 +1448,30 @@ private:
|
||||||
}
|
}
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstSelBit* nodep, AstNUser*) {
|
||||||
|
if (nodep->user3SetOnce()) return;
|
||||||
|
if (m_dotPos == DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||||
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
|
if (AstConst* constp = nodep->rhsp()->castConst()) {
|
||||||
|
string index = AstNode::encodeNumber(constp->toSInt());
|
||||||
|
m_dotText += "__BRA__"+index+"__KET__";
|
||||||
|
} else {
|
||||||
|
nodep->v3error("Unsupported: Non-constant inside []'s in the cell part of a dotted reference");
|
||||||
|
}
|
||||||
|
// And pass up m_dotText
|
||||||
|
} else {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
}
|
||||||
|
}
|
||||||
virtual void visit(AstBegin* nodep, AstNUser*) {
|
virtual void visit(AstBegin* nodep, AstNUser*) {
|
||||||
UINFO(5," "<<nodep<<endl);
|
UINFO(5," "<<nodep<<endl);
|
||||||
VSymEnt* oldCurSymp = m_curSymp;
|
VSymEnt* oldCurSymp = m_curSymp;
|
||||||
{
|
{
|
||||||
m_curSymp = m_statep->getNodeSym(nodep);
|
m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
||||||
UINFO(5," cur=se"<<(void*)m_curSymp<<endl);
|
UINFO(5," cur=se"<<(void*)m_curSymp<<endl);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
m_curSymp = oldCurSymp;
|
m_dotSymp = m_curSymp = oldCurSymp;
|
||||||
UINFO(5," cur=se"<<(void*)m_curSymp<<endl);
|
UINFO(5," cur=se"<<(void*)m_curSymp<<endl);
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||||
|
|
@ -1275,14 +1479,15 @@ private:
|
||||||
VSymEnt* oldCurSymp = m_curSymp;
|
VSymEnt* oldCurSymp = m_curSymp;
|
||||||
{
|
{
|
||||||
m_ftaskp = nodep;
|
m_ftaskp = nodep;
|
||||||
m_curSymp = m_statep->getNodeSym(nodep);
|
m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
m_curSymp = oldCurSymp;
|
m_dotSymp = m_curSymp = oldCurSymp;
|
||||||
m_ftaskp = NULL;
|
m_ftaskp = NULL;
|
||||||
}
|
}
|
||||||
virtual void visit(AstRefDType* nodep, AstNUser*) {
|
virtual void visit(AstRefDType* nodep, AstNUser*) {
|
||||||
// Resolve its reference
|
// Resolve its reference
|
||||||
|
if (nodep->user3SetOnce()) return;
|
||||||
if (!nodep->defp()) {
|
if (!nodep->defp()) {
|
||||||
VSymEnt* foundp;
|
VSymEnt* foundp;
|
||||||
if (nodep->packagep()) {
|
if (nodep->packagep()) {
|
||||||
|
|
@ -1324,10 +1529,14 @@ public:
|
||||||
m_statep = statep;
|
m_statep = statep;
|
||||||
m_modSymp = NULL;
|
m_modSymp = NULL;
|
||||||
m_curSymp = NULL;
|
m_curSymp = NULL;
|
||||||
|
m_dotSymp = NULL;
|
||||||
m_pinSymp = NULL;
|
m_pinSymp = NULL;
|
||||||
m_cellp = NULL;
|
m_cellp = NULL;
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
m_ftaskp = NULL;
|
m_ftaskp = NULL;
|
||||||
|
m_dotp = NULL;
|
||||||
|
m_dotPos = DP_VARETC;
|
||||||
|
m_dotErr = false;
|
||||||
//
|
//
|
||||||
rootp->accept(*this);
|
rootp->accept(*this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
// LinkParse TRANSFORMATIONS:
|
// LinkParse TRANSFORMATIONS:
|
||||||
// Top-down traversal
|
// Top-down traversal
|
||||||
// Replace ParseRef with VarRef, VarXRef, FuncRef or TaskRef
|
// Replace ParseRef with lower parseref
|
||||||
// TASKREF(PARSEREF(DOT(TEXTa,TEXTb))) -> TASKREF(a,b)
|
// TASKREF(PARSEREF(DOT(TEXTa,TEXTb))) -> DOT(PARSEREF(a),TASKREF(b))
|
||||||
// PARSEREF(TEXTa) -> VARREF(a)
|
// PARSEREF(TEXTa) -> PARSEREF(a) (no change)
|
||||||
// PARSEREF(DOT(TEXTa,TEXTb)) -> VARXREF("a","b")
|
// PARSEREF(DOT(TEXTa,TEXTb)) -> DOT(PARSEREF(A),PARSEREF(b)
|
||||||
// PARSEREF(DOT(DOT(TEXTa,TEXTb),TEXTc)) -> VARXREF("a.b","c")
|
// PARSEREF(DOT(DOT(TEXTa,TEXTb),TEXTc)) -> DOT(DOT(PARSEREF(a),PARSEREF(b)),PARSEREF(c))
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
|
|
||||||
#include "config_build.h"
|
#include "config_build.h"
|
||||||
|
|
@ -57,17 +57,16 @@ private:
|
||||||
typedef set <FileLine*> FileLineSet;
|
typedef set <FileLine*> FileLineSet;
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
string m_dotText; // Dotted module text we are building for a dotted node, passed up
|
AstParseRefExp m_exp; // Type of data we're looking for
|
||||||
bool m_inModDot; // We're inside module part of dotted name
|
AstVar* m_varp; // Variable we're under
|
||||||
AstParseRefExp m_exp; // Type of data we're looking for
|
|
||||||
AstText* m_baseTextp; // Lowest TEXT node that needs replacement with varref
|
|
||||||
AstVar* m_varp; // Variable we're under
|
|
||||||
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name>
|
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name>
|
||||||
FileLineSet m_filelines; // Filelines that have been seen
|
FileLineSet m_filelines; // Filelines that have been seen
|
||||||
bool m_inAlways; // Inside an always
|
bool m_inAlways; // Inside an always
|
||||||
bool m_inGenerate; // Inside a generate
|
bool m_inGenerate; // Inside a generate
|
||||||
|
bool m_needStart; // Need start marker on lower AstParse
|
||||||
AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module
|
AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module
|
||||||
AstNodeModule* m_modp; // Current module
|
AstNodeModule* m_modp; // Current module
|
||||||
|
AstParseRef* m_rightParsep; // RHS()-most parseref
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
static int debug() {
|
static int debug() {
|
||||||
|
|
@ -104,17 +103,6 @@ private:
|
||||||
cleanFileline(nodep);
|
cleanFileline(nodep);
|
||||||
UINFO(5," "<<nodep<<endl);
|
UINFO(5," "<<nodep<<endl);
|
||||||
checkExpected(nodep);
|
checkExpected(nodep);
|
||||||
// Due to a need to get the arguments, the ParseRefs are under here,
|
|
||||||
// rather than the NodeFTaskRef under the ParseRef.
|
|
||||||
if (nodep->namep()) {
|
|
||||||
m_exp = AstParseRefExp::PX_FUNC;
|
|
||||||
nodep->namep()->accept(*this); // No next, we don't want to do the edit
|
|
||||||
m_exp = AstParseRefExp::PX_NONE;
|
|
||||||
if (!m_baseTextp) nodep->v3fatalSrc("No TEXT found to indicate function name");
|
|
||||||
nodep->name(m_baseTextp->text());
|
|
||||||
nodep->dotted(m_dotText);
|
|
||||||
nodep->namep()->unlinkFrBack()->deleteTree(); m_baseTextp=NULL;
|
|
||||||
}
|
|
||||||
AstNodeModule* upperValueModp = m_valueModp;
|
AstNodeModule* upperValueModp = m_valueModp;
|
||||||
m_valueModp = NULL;
|
m_valueModp = NULL;
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
|
|
@ -122,99 +110,81 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstParseRef* nodep, AstNUser*) {
|
virtual void visit(AstParseRef* nodep, AstNUser*) {
|
||||||
|
if (nodep->user1SetOnce()) return; // Process only once.
|
||||||
// VarRef: Parse its reference
|
// VarRef: Parse its reference
|
||||||
UINFO(5," "<<nodep<<endl);
|
UINFO(5," "<<nodep<<endl);
|
||||||
// May be a varref inside a select, etc, so save state and recurse
|
{ // First do any function call
|
||||||
string oldText = m_dotText;
|
AstParseRefExp lastExp = m_exp;
|
||||||
bool oldDot = m_inModDot;
|
{
|
||||||
AstParseRefExp oldExp = m_exp;
|
|
||||||
AstText* oldBasep = m_baseTextp;
|
|
||||||
{
|
|
||||||
// Replace the parsed item with its child IE the selection tree down to the varref itself
|
|
||||||
// Do this before iterating, so we don't have to process the edited tree twice
|
|
||||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
|
||||||
nodep->replaceWith(lhsp);
|
|
||||||
|
|
||||||
// Process lower nodes
|
|
||||||
m_dotText = "";
|
|
||||||
m_baseTextp = NULL;
|
|
||||||
if (m_exp == AstParseRefExp::PX_FUNC) {
|
|
||||||
lhsp->accept(*this);
|
|
||||||
// Return m_dotText to invoker
|
|
||||||
} else if (nodep->expect() == AstParseRefExp::PX_VAR_MEM
|
|
||||||
|| nodep->expect() == AstParseRefExp::PX_VAR_ANY) {
|
|
||||||
m_exp = nodep->expect();
|
|
||||||
lhsp->accept(*this);
|
|
||||||
m_exp = AstParseRefExp::PX_NONE;
|
m_exp = AstParseRefExp::PX_NONE;
|
||||||
if (!m_baseTextp) nodep->v3fatalSrc("No TEXT found to indicate function name");
|
if (nodep->ftaskrefp()) nodep->ftaskrefp()->iterateAndNext(*this);
|
||||||
if (m_dotText == "") {
|
|
||||||
AstNode* newp = new AstVarRef(nodep->fileline(), m_baseTextp->text(), false); // lvalue'ness computed later
|
|
||||||
m_baseTextp->replaceWith(newp); m_baseTextp->deleteTree(); m_baseTextp=NULL;
|
|
||||||
} else {
|
|
||||||
AstNode* newp = new AstVarXRef(nodep->fileline(), m_baseTextp->text(), m_dotText, false); // lvalue'ness computed later
|
|
||||||
m_baseTextp->replaceWith(newp); m_baseTextp->deleteTree(); m_baseTextp=NULL;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nodep->v3fatalSrc("Unknown ParseRefExp type\n");
|
|
||||||
}
|
}
|
||||||
nodep->deleteTree(); nodep=NULL;
|
m_exp = lastExp;
|
||||||
}
|
}
|
||||||
if (m_exp != AstParseRefExp::PX_FUNC) { // Fuctions need to look at the name themself
|
if (nodep->start()) { // Start of new parseref stack
|
||||||
m_dotText = oldText;
|
// The start parseref indicates the type of element to be created.
|
||||||
m_inModDot = oldDot;
|
// Push the start marking down to the lowest non-start parseref under any DOTs.
|
||||||
m_exp = oldExp;
|
// May be a varref inside a select, etc, so save state and recurse
|
||||||
m_baseTextp = oldBasep;
|
AstParseRefExp lastExp = m_exp;
|
||||||
|
AstParseRef* lastRightp = m_rightParsep;
|
||||||
|
{
|
||||||
|
m_exp = nodep->expect();
|
||||||
|
m_rightParsep = NULL;
|
||||||
|
m_needStart = true;
|
||||||
|
nodep->lhsp()->accept(*this);
|
||||||
|
if (!m_rightParsep) nodep->v3fatalSrc("No child ParseRef found");
|
||||||
|
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||||
|
if (nodep->expect() == AstParseRefExp::PX_FTASK) {
|
||||||
|
// Put the FTaskRef under the final DOT
|
||||||
|
AstNodeFTaskRef* ftaskrefp = nodep->ftaskrefp()->castNodeFTaskRef();
|
||||||
|
if (!ftaskrefp) nodep->v3fatalSrc("Parseref indicates FTASKref but none found");
|
||||||
|
ftaskrefp->name(m_rightParsep->name());
|
||||||
|
ftaskrefp->unlinkFrBack();
|
||||||
|
if (ftaskrefp->packagep()) {
|
||||||
|
// Can remove the parse stack entirely and V3LinkDot will deal with it natively
|
||||||
|
lhsp = ftaskrefp;
|
||||||
|
} else {
|
||||||
|
m_rightParsep->ftaskrefp(ftaskrefp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodep->replaceWith(lhsp);
|
||||||
|
nodep->deleteTree(); nodep=NULL;
|
||||||
|
}
|
||||||
|
m_exp = lastExp;
|
||||||
|
m_rightParsep = lastRightp;
|
||||||
|
}
|
||||||
|
else { // inside existing stack
|
||||||
|
nodep->expect(m_exp);
|
||||||
|
m_rightParsep = nodep;
|
||||||
|
// Move the start marker down to a standalone parse reference
|
||||||
|
if (m_needStart) { nodep->start(true); m_needStart = false; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstDot* nodep, AstNUser*) {
|
virtual void visit(AstDot* nodep, AstNUser*) {
|
||||||
UINFO(5," "<<nodep<<endl);
|
UINFO(5," "<<nodep<<endl);
|
||||||
cleanFileline(nodep);
|
if (!nodep->user1SetOnce()) { // Process only once.
|
||||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
cleanFileline(nodep);
|
||||||
m_dotText = "";
|
if (m_exp == AstParseRefExp::PX_NONE) nodep->v3fatalSrc("Tree syntax error: Not expecting "<<nodep->type()<<" under a "<<nodep->backp()->type());
|
||||||
|
AstParseRefExp lastExp = m_exp;
|
||||||
|
m_exp = AstParseRefExp::PX_PREDOT;
|
||||||
|
if (m_needStart) { nodep->start(true); m_needStart = false; }
|
||||||
nodep->lhsp()->iterateAndNext(*this);
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
string namelhs = m_dotText;
|
m_exp = lastExp;
|
||||||
|
|
||||||
m_dotText = "";
|
|
||||||
nodep->rhsp()->iterateAndNext(*this);
|
nodep->rhsp()->iterateAndNext(*this);
|
||||||
m_dotText = namelhs + "." + m_dotText;
|
|
||||||
} else { // Not in ModDot, so this is {modulepart} DOT {name}
|
|
||||||
m_inModDot = true;
|
|
||||||
m_dotText = "";
|
|
||||||
nodep->lhsp()->iterateAndNext(*this);
|
|
||||||
string namelhs = m_dotText;
|
|
||||||
|
|
||||||
m_inModDot = false;
|
|
||||||
m_dotText = "";
|
|
||||||
nodep->rhsp()->iterateAndNext(*this);
|
|
||||||
m_dotText = namelhs;
|
|
||||||
|
|
||||||
nodep->replaceWith(nodep->rhsp()->unlinkFrBack()); nodep->deleteTree(); nodep=NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstSelBit* nodep, AstNUser*) {
|
virtual void visit(AstSelBit* nodep, AstNUser*) {
|
||||||
if (!nodep->user1SetOnce()) { // Process only once.
|
if (!nodep->user1SetOnce()) { // Process only once.
|
||||||
cleanFileline(nodep);
|
cleanFileline(nodep);
|
||||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
if (m_exp==AstParseRefExp::PX_FTASK) {
|
||||||
m_dotText = "";
|
nodep->v3error("Syntax Error: Range selection '[]' is not allowed as part of function/task names");
|
||||||
nodep->lhsp()->iterateAndNext(*this);
|
|
||||||
if (AstConst* constp = nodep->rhsp()->castConst()) {
|
|
||||||
string index = AstNode::encodeNumber(constp->toSInt());
|
|
||||||
m_dotText = m_dotText+"__BRA__"+index+"__KET__";
|
|
||||||
} else {
|
|
||||||
nodep->v3error("Unsupported: Non-constant inside []'s in the cell part of a dotted reference");
|
|
||||||
}
|
|
||||||
// And pass up m_dotText
|
|
||||||
} else if (m_exp==AstParseRefExp::PX_FUNC) {
|
|
||||||
nodep->v3error("Syntax Error: Range selection '[]' is not allowed as part of function names");
|
|
||||||
} else {
|
} else {
|
||||||
nodep->lhsp()->iterateAndNext(*this);
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
AstParseRefExp lastExp = m_exp;
|
AstParseRefExp lastExp = m_exp;
|
||||||
AstText* lasttextp = m_baseTextp;
|
|
||||||
{
|
{
|
||||||
m_exp = AstParseRefExp::PX_NONE;
|
m_exp = AstParseRefExp::PX_NONE;
|
||||||
nodep->rhsp()->iterateAndNext(*this);
|
nodep->rhsp()->iterateAndNext(*this);
|
||||||
}
|
}
|
||||||
m_baseTextp = lasttextp;
|
|
||||||
m_exp = lastExp;
|
m_exp = lastExp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -223,40 +193,24 @@ private:
|
||||||
// Excludes simple AstSel, see above
|
// Excludes simple AstSel, see above
|
||||||
if (!nodep->user1SetOnce()) { // Process only once.
|
if (!nodep->user1SetOnce()) { // Process only once.
|
||||||
cleanFileline(nodep);
|
cleanFileline(nodep);
|
||||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
if (m_exp == AstParseRefExp::PX_PREDOT) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||||
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference");
|
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference");
|
||||||
} else if (m_exp==AstParseRefExp::PX_FUNC) {
|
} else if (m_exp==AstParseRefExp::PX_FTASK) {
|
||||||
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed as part of function names");
|
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed as part of function/task names");
|
||||||
} else if (m_exp==AstParseRefExp::PX_VAR_MEM) {
|
} else if (m_exp==AstParseRefExp::PX_VAR_MEM) {
|
||||||
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed when expecting memory reference");
|
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed when expecting memory reference");
|
||||||
} else {
|
} else {
|
||||||
nodep->lhsp()->iterateAndNext(*this);
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
AstParseRefExp lastExp = m_exp;
|
AstParseRefExp lastExp = m_exp;
|
||||||
AstText* lasttextp = m_baseTextp;
|
|
||||||
{
|
{
|
||||||
m_exp = AstParseRefExp::PX_NONE;
|
m_exp = AstParseRefExp::PX_NONE;
|
||||||
nodep->rhsp()->iterateAndNext(*this);
|
nodep->rhsp()->iterateAndNext(*this);
|
||||||
nodep->thsp()->iterateAndNext(*this);
|
nodep->thsp()->iterateAndNext(*this);
|
||||||
}
|
}
|
||||||
m_baseTextp = lasttextp;
|
|
||||||
m_exp = lastExp;
|
m_exp = lastExp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstText* nodep, AstNUser*) {
|
|
||||||
if (!nodep->user1SetOnce()) { // Process only once.
|
|
||||||
cleanFileline(nodep);
|
|
||||||
if (m_exp != AstParseRefExp::PX_NONE) {
|
|
||||||
UINFO(7," "<<nodep<<endl);
|
|
||||||
if (m_inModDot) { // Dotted part, just pass up
|
|
||||||
m_dotText = nodep->text();
|
|
||||||
} else {
|
|
||||||
if (m_baseTextp) nodep->v3fatalSrc("Multiple low-level ParseRef text's found; which one is var name?");
|
|
||||||
m_baseTextp = nodep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual void visit(AstEnumItem* nodep, AstNUser*) {
|
virtual void visit(AstEnumItem* nodep, AstNUser*) {
|
||||||
// Expand ranges
|
// Expand ranges
|
||||||
cleanFileline(nodep);
|
cleanFileline(nodep);
|
||||||
|
|
@ -470,14 +424,14 @@ private:
|
||||||
public:
|
public:
|
||||||
// CONSTUCTORS
|
// CONSTUCTORS
|
||||||
LinkParseVisitor(AstNetlist* rootp) {
|
LinkParseVisitor(AstNetlist* rootp) {
|
||||||
m_inModDot = false;
|
|
||||||
m_exp = AstParseRefExp::PX_NONE;
|
|
||||||
m_baseTextp = NULL;
|
|
||||||
m_varp = NULL;
|
m_varp = NULL;
|
||||||
|
m_exp = AstParseRefExp::PX_NONE;
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
m_inAlways = false;
|
m_inAlways = false;
|
||||||
m_inGenerate = false;
|
m_inGenerate = false;
|
||||||
|
m_needStart = false;
|
||||||
m_valueModp = NULL;
|
m_valueModp = NULL;
|
||||||
|
m_rightParsep = NULL;
|
||||||
rootp->accept(*this);
|
rootp->accept(*this);
|
||||||
}
|
}
|
||||||
virtual ~LinkParseVisitor() {}
|
virtual ~LinkParseVisitor() {}
|
||||||
|
|
|
||||||
|
|
@ -2135,17 +2135,17 @@ for_step<nodep>: // IEEE: for_step
|
||||||
//************************************************
|
//************************************************
|
||||||
// Functions/tasks
|
// Functions/tasks
|
||||||
|
|
||||||
taskRef<ftaskrefp>: // IEEE: part of tf_call
|
taskRef<parserefp>: // IEEE: part of tf_call
|
||||||
idDotted { $$ = new AstTaskRef($1->fileline(),new AstParseRef($1->fileline(), AstParseRefExp::PX_TASK, $1),NULL);}
|
idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::PX_FTASK, "", $1, new AstTaskRef($1->fileline(),"",NULL)); $$->start(true); }
|
||||||
| idDotted '(' list_of_argumentsE ')' { $$ = new AstTaskRef($1->fileline(),new AstParseRef($1->fileline(), AstParseRefExp::PX_TASK, $1),$3);}
|
| idDotted '(' list_of_argumentsE ')' { $$ = new AstParseRef($1->fileline(), AstParseRefExp::PX_FTASK, "", $1, new AstTaskRef($1->fileline(),"",$3)); $$->start(true); }
|
||||||
//UNSUP: package_scopeIdFollows idDotted { $$ = new AstTaskRef($1->fileline(),new AstParseRef($2->fileline(), AstParseRefExp::PX_TASK, $2),NULL);}
|
//UNSUP: package_scopeIdFollows idDotted { }
|
||||||
//UNSUP: package_scopeIdFollows idDotted '(' list_of_argumentsE ')' { $$ = new AstTaskRef($1->fileline(),new AstParseRef($2->fileline(), AstParseRefExp::PX_TASK, $2),$4);}
|
//UNSUP: package_scopeIdFollows idDotted '(' list_of_argumentsE ')' { }
|
||||||
//UNSUP: idDotted is really just id to allow dotted method calls
|
//UNSUP: idDotted is really just id to allow dotted method calls
|
||||||
;
|
;
|
||||||
|
|
||||||
funcRef<ftaskrefp>: // IEEE: part of tf_call
|
funcRef<parserefp>: // IEEE: part of tf_call
|
||||||
idDotted '(' list_of_argumentsE ')' { $$ = new AstFuncRef($2,new AstParseRef($1->fileline(), AstParseRefExp::PX_FUNC, $1), $3); }
|
idDotted '(' list_of_argumentsE ')' { $$ = new AstParseRef($1->fileline(), AstParseRefExp::PX_FTASK, "", $1, new AstFuncRef($2, "", $3)); $$->start(true); }
|
||||||
| package_scopeIdFollows idDotted '(' list_of_argumentsE ')' { $$ = new AstFuncRef($3,new AstParseRef($2->fileline(), AstParseRefExp::PX_FUNC, $2), $4); $$->packagep($1); }
|
| package_scopeIdFollows idDotted '(' list_of_argumentsE ')' { AstFuncRef* f=new AstFuncRef($3,"",$4); f->packagep($1); $$ = new AstParseRef($2->fileline(), AstParseRefExp::PX_FTASK, "", $2, f); $$->start(true); }
|
||||||
//UNSUP: idDotted is really just id to allow dotted method calls
|
//UNSUP: idDotted is really just id to allow dotted method calls
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
@ -2978,12 +2978,12 @@ variable_lvalueConcList<nodep>: // IEEE: part of variable_lvalue: '{' variable_l
|
||||||
|
|
||||||
// VarRef to a Memory
|
// VarRef to a Memory
|
||||||
varRefMem<parserefp>:
|
varRefMem<parserefp>:
|
||||||
idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::PX_VAR_MEM, $1); }
|
idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::PX_VAR_MEM, "", $1, NULL); $$->start(true); }
|
||||||
;
|
;
|
||||||
|
|
||||||
// VarRef to dotted, and/or arrayed, and/or bit-ranged variable
|
// VarRef to dotted, and/or arrayed, and/or bit-ranged variable
|
||||||
idClassSel<parserefp>: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable
|
idClassSel<parserefp>: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable
|
||||||
idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::PX_VAR_ANY, $1); }
|
idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::PX_VAR_ANY, "", $1, NULL); $$->start(true); }
|
||||||
// // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select
|
// // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select
|
||||||
//UNSUP yTHIS '.' idDotted { UNSUP }
|
//UNSUP yTHIS '.' idDotted { UNSUP }
|
||||||
//UNSUP ySUPER '.' idDotted { UNSUP }
|
//UNSUP ySUPER '.' idDotted { UNSUP }
|
||||||
|
|
@ -3008,7 +3008,7 @@ idDottedMore<nodep>:
|
||||||
// id below includes:
|
// id below includes:
|
||||||
// enum_identifier
|
// enum_identifier
|
||||||
idArrayed<nodep>: // IEEE: id + select
|
idArrayed<nodep>: // IEEE: id + select
|
||||||
id { $$ = new AstText($<fl>1,*$1); }
|
id { $$ = new AstParseRef($<fl>1,AstParseRefExp::PX_TEXT,*$1,NULL,NULL); }
|
||||||
// // IEEE: id + part_select_range/constant_part_select_range
|
// // IEEE: id + part_select_range/constant_part_select_range
|
||||||
| idArrayed '[' expr ']' { $$ = new AstSelBit($2,$1,$3); } // Or AstArraySel, don't know yet.
|
| idArrayed '[' expr ']' { $$ = new AstSelBit($2,$1,$3); } // Or AstArraySel, don't know yet.
|
||||||
| idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2,$1,$3,$5); }
|
| idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2,$1,$3,$5); }
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||||
compile (
|
compile (
|
||||||
fails=>1,
|
fails=>1,
|
||||||
expect=>
|
expect=>
|
||||||
'%Error: t/t_var_notfound_bad.v:\d+: Can\'t find definition of signal: nf
|
'%Error: t/t_var_notfound_bad.v:\d+: Can\'t find definition of variable: nf
|
||||||
%Error: t/t_var_notfound_bad.v:\d+: Can\'t find definition of \'subsubz\' in dotted signal: sub.subsubz.inss
|
%Error: t/t_var_notfound_bad.v:\d+: Can\'t find definition of \'subsubz\' in dotted scope/variable: sub.subsubz
|
||||||
%Error: Known scopes under \'inss\': subsub
|
%Error: Known scopes under \'sub\': subsub
|
||||||
%Error: t/t_var_notfound_bad.v:\d+: Can\'t find definition of task/function: nofunc
|
%Error: t/t_var_notfound_bad.v:\d+: Can\'t find definition of task/function: nofunc
|
||||||
%Error: t/t_var_notfound_bad.v:\d+: Can\'t find definition of task/function: notask
|
%Error: t/t_var_notfound_bad.v:\d+: Can\'t find definition of task/function: notask
|
||||||
|
%Error: t/t_var_notfound_bad.v:\d+: Found definition of \'a_var\' as a VAR but expected a task/function
|
||||||
%Error: Exiting due to.*',
|
%Error: Exiting due to.*',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
module t (/*AUTOARG*/);
|
module t (/*AUTOARG*/);
|
||||||
|
|
||||||
integer i;
|
integer i;
|
||||||
|
integer a_var;
|
||||||
|
|
||||||
sub sub ();
|
sub sub ();
|
||||||
|
|
||||||
|
|
@ -14,6 +15,7 @@ module t (/*AUTOARG*/);
|
||||||
sub.subsubz.inss = 0; // subsub not found
|
sub.subsubz.inss = 0; // subsub not found
|
||||||
i = nofunc(); // nofunc not found
|
i = nofunc(); // nofunc not found
|
||||||
notask(); // notask not found
|
notask(); // notask not found
|
||||||
|
a_var(); // Calling variable as task
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue