// -*- C++ -*-
//*************************************************************************
//
// Copyright 2009-2018 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
/// \file
/// \brief Verilog::Parse: Symbol table accessing
///
/// Authors: Wilson Snyder
///
/// Code available from: http://www.veripool.org/verilog-perl
///
//*************************************************************************
#ifndef _VSYMTABLE_H_
#define _VSYMTABLE_H_ 1
#include "VFileLine.h"
#include "VAst.h"
#include <vector>
#include <cassert>
using namespace std;
//######################################################################
// List of symbol tables
class VSymStack {
typedef vector<VAstEnt*> SymStack;
SymStack m_sympStack; // Stack of symbol tables
VAstEnt* m_currentSymp; // Current symbol table
public:
// CONSTRUCTORS
VSymStack(VFileLine* fl, struct av* symp); // Pass in top-level symbol table array
~VSymStack() {}
// ACCESSORS
VAstEnt* currentSymp() const { return m_currentSymp; }
VAstEnt* netlistSymp() const { return m_sympStack.front(); }
// METHODS
/// Insert a new entry, and return the new entry
VAstEnt* replaceInsert(VAstType type, const string& name) {
return m_currentSymp->replaceInsert(type,name);
}
/// Insert an entry if it doesn't exist
VAstEnt* findInsert(VAstType type, const string& name) {
return m_currentSymp->findInsert(type,name);
}
/// Return type of current lookup
VAstType curType() { return m_currentSymp->type(); }
void showUpward () {
cout<<"SymTable Stack:\n";
for (SymStack::reverse_iterator it=m_sympStack.rbegin(); it!=m_sympStack.rend(); ++it) {
VAstEnt* symp = *it;
cout<<"\t"<<symp->ascii()<<endl;
}
cout<<"SymTable Parents of current:\n";
for (VAstEnt* symp=currentSymp(); symp; symp=symp->parentp()) {
cout<<"\t"<<symp->ascii()<<endl;
}
}
/// Lookup the given string as an identifier, return type of the id
// This recurses upwards if not found; for flat lookup use symp->findSym
VAstEnt* findEntUpward (const string& name) {
for (VAstEnt* symp=currentSymp(); symp; symp=symp->parentp()) {
if (VAstEnt* subp = symp->findSym(name)) {
return subp;
}
}
return NULL;
}
VAstType findTypeUpward (const string& name) {
if (VAstEnt* subp = findEntUpward(name)) {
return subp->type();
} else {
return VAstType::NOT_FOUND;
}
}
/// Return what this object is a member of, ignoring blocks
string objofUpward() {
for (VAstEnt* symp=currentSymp(); symp; symp=symp->parentp()) {
if (!symp->typeIgnoreObjof()) {
return symp->type().ascii();
}
}
assert(0); // Should have been a NETLIST if nothing else
return ""; // Asserts maybe NOPed
}
/// Push current scope down to a new scope
void pushScope(VAstEnt* symp) {
m_sympStack.push_back(symp);
m_currentSymp = symp;
}
/// Pop current scope up to a previous scope
void popScope(VFileLine* fl) {
m_sympStack.pop_back();
// Must always have one remaining - it's globals. Thus this is after the pop.
if (m_sympStack.empty()) { fl->error("symbol stack underflow"); return; }
m_currentSymp = m_sympStack.back();
}
/// Import from package::id_or_star to this
void import(VFileLine* fl, const string& pkg, const string& id_or_star) {
import (fl, pkg, findEntUpward(pkg), id_or_star);
}
void import(VFileLine* fl, const string& pkg, VAstEnt* entp, const string& id_or_star) {
if (!entp) { // Internal problem, because we earlier found pkg to label it an ID__aPACKAGE
fl->error("Internal: Import package not found: "+pkg);
return;
}
m_currentSymp->import(entp, id_or_star);
}
static void selftest();
};
#endif // guard