292 lines
9.9 KiB
C++
292 lines
9.9 KiB
C++
#ifndef IVL_scope_H
|
|
#define IVL_scope_H
|
|
/*
|
|
* Copyright (c) 2011-2016 Stephen Williams (steve@icarus.com)
|
|
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
|
*
|
|
* This source code is free software; you can redistribute it
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
* General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
# include <algorithm>
|
|
# include <list>
|
|
# include <map>
|
|
# include "StringHeap.h"
|
|
# include "entity.h"
|
|
# include "expression.h"
|
|
# include "vsignal.h"
|
|
|
|
class ActiveScope;
|
|
class Architecture;
|
|
class ComponentBase;
|
|
class Package;
|
|
class SubprogramHeader;
|
|
class VType;
|
|
class SequentialStmt;
|
|
|
|
typedef list<SubprogramHeader*> SubHeaderList;
|
|
|
|
template<typename T>
|
|
struct delete_object{
|
|
void operator()(T* item) { delete item; }
|
|
};
|
|
|
|
template<typename T>
|
|
struct delete_pair_second{
|
|
void operator()(pair<perm_string, T*> item){ delete item.second; }
|
|
};
|
|
|
|
class ScopeBase {
|
|
|
|
public:
|
|
ScopeBase() : package_header_(0) { }
|
|
explicit ScopeBase(const ActiveScope&ref);
|
|
virtual ~ScopeBase() =0;
|
|
|
|
ScopeBase* find_scope(perm_string name) const;
|
|
const VType* find_type(perm_string by_name);
|
|
virtual bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp) const;
|
|
Signal* find_signal(perm_string by_name) const;
|
|
virtual Variable* find_variable(perm_string by_name) const;
|
|
virtual const InterfacePort* find_param(perm_string by_name) const;
|
|
const InterfacePort* find_param_all(perm_string by_name) const;
|
|
SubHeaderList find_subprogram(perm_string by_name) const;
|
|
// Checks if a string is one of possible enum values. If so, the enum
|
|
// type is returned, otherwise NULL.
|
|
const VTypeEnum* is_enum_name(perm_string name) const;
|
|
|
|
virtual bool is_subprogram() const { return false; }
|
|
|
|
// Moves signals, variables and components from another scope to
|
|
// this one. After the transfer new_* maps are cleared in the source scope.
|
|
enum transfer_type_t { SIGNALS = 1, VARIABLES = 2, COMPONENTS = 4, ALL = 0xffff };
|
|
void transfer_from(ScopeBase&ref, transfer_type_t what = ALL);
|
|
|
|
inline void bind_subprogram(perm_string name, SubprogramHeader*obj)
|
|
{ map<perm_string, SubHeaderList>::iterator it;
|
|
if((it = use_subprograms_.find(name)) != use_subprograms_.end() )
|
|
it->second.remove(obj);
|
|
cur_subprograms_[name].push_back(obj);
|
|
}
|
|
|
|
// Adds a statement to implicit initializers list
|
|
// (emitted in a 'initial block).
|
|
void add_initializer(SequentialStmt* s)
|
|
{
|
|
initializers_.push_back(s);
|
|
}
|
|
|
|
// Adds a statement to implicit finalizers list
|
|
// (emitted in a 'final' block).
|
|
void add_finalizer(SequentialStmt* s)
|
|
{
|
|
finalizers_.push_back(s);
|
|
}
|
|
|
|
void dump_scope(ostream&out) const;
|
|
|
|
// Looks for a subprogram with specified name and parameter types.
|
|
SubprogramHeader*match_subprogram(perm_string name,
|
|
const list<const VType*>*params) const;
|
|
|
|
perm_string peek_name() const { return name_; }
|
|
|
|
void set_package_header(Package*pkg) {
|
|
assert(package_header_ == 0);
|
|
package_header_ = pkg;
|
|
}
|
|
|
|
protected:
|
|
void cleanup();
|
|
|
|
//containers' cleaning helper functions
|
|
template<typename T> void delete_all(list<T*>& c)
|
|
{
|
|
for_each(c.begin(), c.end(), ::delete_object<T>());
|
|
}
|
|
template<typename T> void delete_all(map<perm_string, T*>& c)
|
|
{
|
|
for_each(c.begin(), c.end(), ::delete_pair_second<T>());
|
|
}
|
|
|
|
// The new_*_ maps below are managed only by the ActiveScope
|
|
// derived class. When any scope is constructed from the
|
|
// ActiveScope, the new_*_ and old_*_ maps are merged and
|
|
// installed into the old_*_ maps. Thus, all other derived
|
|
// classes should only use the old_*_ maps.
|
|
|
|
// Signal declarations...
|
|
std::map<perm_string,Signal*> old_signals_; //previous scopes
|
|
std::map<perm_string,Signal*> new_signals_; //current scope
|
|
// Variable declarations...
|
|
std::map<perm_string,Variable*> old_variables_; //previous scopes
|
|
std::map<perm_string,Variable*> new_variables_; //current scope
|
|
// Component declarations...
|
|
std::map<perm_string,ComponentBase*> old_components_; //previous scopes
|
|
std::map<perm_string,ComponentBase*> new_components_; //current scope
|
|
// Type declarations...
|
|
std::map<perm_string,const VType*> use_types_; //imported types
|
|
std::map<perm_string,const VType*> cur_types_; //current types
|
|
// Constant declarations...
|
|
struct const_t {
|
|
~const_t() {delete val;}
|
|
const_t(const VType*t, Expression* v) : typ(t), val(v) {};
|
|
|
|
const VType*typ;
|
|
Expression*val;
|
|
};
|
|
std::map<perm_string, struct const_t*> use_constants_; //imported constants
|
|
std::map<perm_string, struct const_t*> cur_constants_; //current constants
|
|
|
|
std::map<perm_string, SubHeaderList> use_subprograms_; //imported
|
|
std::map<perm_string, SubHeaderList> cur_subprograms_; //current
|
|
|
|
std::map<perm_string, ScopeBase*> scopes_;
|
|
|
|
std::list<const VTypeEnum*> use_enums_;
|
|
|
|
// List of statements that should be emitted in a 'initial' block
|
|
std::list<SequentialStmt*> initializers_;
|
|
|
|
// List of statements that should be emitted in a 'final' block
|
|
std::list<SequentialStmt*> finalizers_;
|
|
|
|
void do_use_from(const ScopeBase*that);
|
|
|
|
// If this is a package body, then there is a Package header
|
|
// already declared.
|
|
Package*package_header_;
|
|
|
|
// Generates an unique name for the scope
|
|
void generate_name();
|
|
|
|
private:
|
|
perm_string name_;
|
|
};
|
|
|
|
class Scope : public ScopeBase {
|
|
|
|
public:
|
|
explicit Scope(const ActiveScope&ref) : ScopeBase(ref) {}
|
|
virtual ~Scope() {}
|
|
|
|
ComponentBase* find_component(perm_string by_name);
|
|
|
|
protected:
|
|
// Helper method for emitting signals in the scope.
|
|
int emit_signals(ostream&out, Entity*ent, ScopeBase*scope);
|
|
int emit_variables(ostream&out, Entity*ent, ScopeBase*scope);
|
|
};
|
|
|
|
/*
|
|
* The active_scope object accumulates declarations for the scope that
|
|
* is in the process of being parsed. When the declarations are over,
|
|
* they are transferred over to the specific scope. The ActiveScope is
|
|
* used by the parser to build up scopes.
|
|
*/
|
|
class ActiveScope : public ScopeBase {
|
|
|
|
public:
|
|
ActiveScope() : context_entity_(0) { }
|
|
explicit ActiveScope(const ActiveScope*par);
|
|
|
|
~ActiveScope() { }
|
|
|
|
// Pull items from "that" scope into "this" scope as is
|
|
// defined by a "use" directive. The parser uses this method
|
|
// to implement the "use <pkg>::*" directive.
|
|
void use_from(const Scope*that) { do_use_from(that); }
|
|
|
|
// This function returns true if the name is a vectorable
|
|
// name. The parser uses this to distinguish between function
|
|
// calls and array index operations.
|
|
bool is_vector_name(perm_string name) const;
|
|
|
|
// Locate the subprogram by name. The subprogram body uses
|
|
// this to locate the subprogram declaration. Note that the
|
|
// subprogram may be in a package header.
|
|
SubprogramHeader* recall_subprogram(const SubprogramHeader*subp) const;
|
|
|
|
/* All bind_name function check if the given name was present
|
|
* in previous scopes. If it is found, it is erased (but the pointer
|
|
* is not freed), in order to implement name shadowing. The pointer
|
|
* be freed only in the scope where the object was defined. This is
|
|
* done in ScopeBase::cleanup() function .*/
|
|
|
|
void bind_name(perm_string name, Signal*obj)
|
|
{ map<perm_string, Signal*>::iterator it;
|
|
if((it = old_signals_.find(name)) != old_signals_.end() )
|
|
old_signals_.erase(it);
|
|
new_signals_[name] = obj;
|
|
}
|
|
|
|
void bind_name(perm_string name, Variable*obj)
|
|
{ map<perm_string, Variable*>::iterator it;
|
|
if((it = old_variables_.find(name)) != old_variables_.end() )
|
|
old_variables_.erase(it);
|
|
new_variables_[name] = obj;
|
|
}
|
|
|
|
void bind_name(perm_string name, ComponentBase*obj)
|
|
{ map<perm_string, ComponentBase*>::iterator it;
|
|
if((it = old_components_.find(name)) != old_components_.end() )
|
|
old_components_.erase(it);
|
|
new_components_[name] = obj;
|
|
}
|
|
|
|
void bind_name(perm_string name, const VType* t)
|
|
{ map<perm_string, const VType*>::iterator it;
|
|
if((it = use_types_.find(name)) != use_types_.end() )
|
|
use_types_.erase(it);
|
|
cur_types_[name] = t;
|
|
}
|
|
|
|
void bind_scope(perm_string name, ScopeBase*scope)
|
|
{
|
|
assert(scopes_.find(name) == scopes_.end());
|
|
scopes_[name] = scope;
|
|
}
|
|
|
|
inline void use_enum(const VTypeEnum* t)
|
|
{ use_enums_.push_back(t); }
|
|
|
|
inline void use_name(perm_string name, const VType* t)
|
|
{ use_types_[name] = t; }
|
|
|
|
void bind_name(perm_string name, const VType*obj, Expression*val)
|
|
{ map<perm_string, const_t*>::iterator it;
|
|
if((it = use_constants_.find(name)) != use_constants_.end() )
|
|
use_constants_.erase(it);
|
|
cur_constants_[name] = new const_t(obj, val);
|
|
}
|
|
|
|
void bind(Entity*ent)
|
|
{ context_entity_ = ent; }
|
|
|
|
void destroy_global_scope()
|
|
{
|
|
cleanup();
|
|
}
|
|
|
|
// Keep track of incomplete types until their proper
|
|
// definition shows up.
|
|
std::map<perm_string,VTypeDef*> incomplete_types;
|
|
|
|
private:
|
|
Entity*context_entity_;
|
|
};
|
|
|
|
#endif /* IVL_scope_H */
|