forked from github/verilator
166 lines
6.1 KiB
C++
166 lines
6.1 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//*************************************************************************
|
|
// DESCRIPTION: Verilator: Common header between parser and lex
|
|
//
|
|
// Code available from: https://verilator.org
|
|
//
|
|
//*************************************************************************
|
|
//
|
|
// Copyright 2009-2020 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
|
|
//
|
|
//*************************************************************************
|
|
|
|
#ifndef _V3PARSESYM_H_
|
|
#define _V3PARSESYM_H_ 1
|
|
|
|
#include "config_build.h"
|
|
#include "verilatedos.h"
|
|
|
|
#include "V3Error.h"
|
|
#include "V3FileLine.h"
|
|
#include "V3Global.h"
|
|
#include "V3SymTable.h"
|
|
|
|
#include <deque>
|
|
|
|
//######################################################################
|
|
// Symbol table for parsing
|
|
|
|
class V3ParseSym {
|
|
// TYPES
|
|
typedef std::vector<VSymEnt*> SymStack;
|
|
|
|
private:
|
|
// MEMBERS
|
|
static int s_anonNum; // Number of next anonymous object (parser use only)
|
|
VSymGraph m_syms; // Graph of symbol tree
|
|
VSymEnt* m_symTableNextId; // Symbol table for next lexer lookup (parser use only)
|
|
VSymEnt* m_symCurrentp; // Active symbol table for additions/lookups
|
|
SymStack m_sympStack; // Stack of upper nodes with pending symbol tables
|
|
|
|
public:
|
|
// CONSTRUCTORS
|
|
explicit V3ParseSym(AstNetlist* rootp)
|
|
: m_syms(rootp) {
|
|
s_anonNum = 0; // Number of next anonymous object
|
|
pushScope(findNewTable(rootp));
|
|
m_symTableNextId = NULL;
|
|
m_symCurrentp = symCurrentp();
|
|
}
|
|
~V3ParseSym() {}
|
|
|
|
private:
|
|
// METHODS
|
|
static VSymEnt* getTable(AstNode* nodep) {
|
|
UASSERT_OBJ(nodep->user4p(), nodep, "Current symtable not found");
|
|
return nodep->user4u().toSymEnt();
|
|
}
|
|
|
|
public:
|
|
VSymEnt* nextId() const { return m_symTableNextId; }
|
|
VSymEnt* symCurrentp() const { return m_symCurrentp; }
|
|
VSymEnt* symRootp() const { return m_syms.rootp(); }
|
|
|
|
VSymEnt* findNewTable(AstNode* nodep) {
|
|
if (!nodep->user4p()) {
|
|
VSymEnt* symsp = new VSymEnt(&m_syms, nodep);
|
|
nodep->user4p(symsp);
|
|
}
|
|
return getTable(nodep);
|
|
}
|
|
void nextId(AstNode* entp) {
|
|
if (entp) {
|
|
UINFO(9, "symTableNextId under " << entp << "-" << entp->type().ascii() << endl);
|
|
m_symTableNextId = getTable(entp);
|
|
} else {
|
|
UINFO(9, "symTableNextId under NULL" << endl);
|
|
m_symTableNextId = NULL;
|
|
}
|
|
}
|
|
void reinsert(AstNode* nodep, VSymEnt* parentp = NULL) {
|
|
reinsert(nodep, parentp, nodep->name());
|
|
}
|
|
void reinsert(AstNode* nodep, VSymEnt* parentp, string name) {
|
|
if (!parentp) parentp = symCurrentp();
|
|
if (name == "") { // New name with space in name so can't collide with users
|
|
name = string(" anon") + nodep->type().ascii() + cvtToStr(++s_anonNum);
|
|
}
|
|
parentp->reinsert(name, findNewTable(nodep));
|
|
}
|
|
void pushNew(AstNode* nodep) { pushNewUnder(nodep, NULL); }
|
|
void pushNewUnder(AstNode* nodep, VSymEnt* parentp) {
|
|
if (!parentp) parentp = symCurrentp();
|
|
VSymEnt* symp
|
|
= findNewTable(nodep); // Will set user4p, which is how we connect table to node
|
|
symp->fallbackp(parentp);
|
|
reinsert(nodep, parentp);
|
|
pushScope(symp);
|
|
}
|
|
void pushScope(VSymEnt* symp) {
|
|
m_sympStack.push_back(symp);
|
|
m_symCurrentp = symp;
|
|
}
|
|
void popScope(AstNode* nodep) {
|
|
if (symCurrentp()->nodep() != nodep) {
|
|
if (debug()) {
|
|
showUpward();
|
|
dump(cout, "-mism: ");
|
|
}
|
|
nodep->v3fatalSrc("Symbols suggest ending " << symCurrentp()->nodep()->prettyTypeName()
|
|
<< " but parser thinks ending "
|
|
<< nodep->prettyTypeName());
|
|
return;
|
|
}
|
|
m_sympStack.pop_back();
|
|
UASSERT_OBJ(!m_sympStack.empty(), nodep, "symbol stack underflow");
|
|
m_symCurrentp = m_sympStack.back();
|
|
}
|
|
void showUpward() {
|
|
UINFO(1, "ParseSym Stack:\n");
|
|
for (SymStack::reverse_iterator it = m_sympStack.rbegin(); it != m_sympStack.rend();
|
|
++it) {
|
|
VSymEnt* symp = *it;
|
|
UINFO(1, " " << symp->nodep() << endl);
|
|
}
|
|
UINFO(1, "ParseSym Current: " << symCurrentp()->nodep() << endl);
|
|
}
|
|
void dump(std::ostream& os, const string& indent = "") { m_syms.dump(os, indent); }
|
|
AstNode* findEntUpward(const string& name) const {
|
|
// Lookup the given string as an identifier, return type of the id, scanning upward
|
|
VSymEnt* foundp = symCurrentp()->findIdFallback(name);
|
|
if (foundp) {
|
|
return foundp->nodep();
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
void importItem(AstNode* packagep, const string& id_or_star) {
|
|
// Import from package::id_or_star to this
|
|
VSymEnt* symp = getTable(packagep);
|
|
UASSERT_OBJ(symp, packagep,
|
|
// Internal problem, because we earlier found pkg to label it an ID__aPACKAGE
|
|
"Import package not found");
|
|
// Walk old sym table and reinsert into current table
|
|
// We let V3LinkDot report the error instead of us
|
|
symCurrentp()->importFromPackage(&m_syms, symp, id_or_star);
|
|
}
|
|
void exportItem(AstNode* packagep, const string& id_or_star) {
|
|
// Export from this the remote package::id_or_star
|
|
VSymEnt* symp = getTable(packagep);
|
|
UASSERT_OBJ(symp, packagep,
|
|
// Internal problem, because we earlier found pkg to label it an ID__aPACKAGE
|
|
"Export package not found");
|
|
symCurrentp()->exportFromPackage(&m_syms, symp, id_or_star);
|
|
}
|
|
void exportStarStar(AstNode* packagep) {
|
|
// Export *::* from remote packages
|
|
symCurrentp()->exportStarStar(&m_syms);
|
|
}
|
|
};
|
|
|
|
#endif // Guard
|