/*=============================================================================
Wave: A Standard compliant C++ preprocessor
Copyright (c) 2001-2003 Hartmut Kaiser
http://spirit.sourceforge.net/
Permission to copy, use, modify, sell and distribute this software
is granted provided this copyright notice appears in all copies.
This software is provided "as is" without express or implied
warranty, and with no claim as to its suitability for any purpose.
See Copyright.txt for full copyright notices and acknowledgements.
=============================================================================*/
#if !defined(SYMBOL_TABLE_HPP_32B0F7C6_3DD6_4113_95A5_E16516C6F45A_INCLUDED)
#define SYMBOL_TABLE_HPP_32B0F7C6_3DD6_4113_95A5_E16516C6F45A_INCLUDED
#include <map>
#include <boost/shared_ptr.hpp>
#if !defined(WAVE_ENABLE_CPP0X_EXTENSIONS)
///////////////////////////////////////////////////////////////////////////////
namespace wave {
namespace util {
///////////////////////////////////////////////////////////////////////////////
//
// The symbol_table class is used for the storage of defined macros.
//
///////////////////////////////////////////////////////////////////////////////
template <typename StringT, typename MacroDefT>
struct symbol_table
: public std::map<StringT, boost::shared_ptr<MacroDefT> >
{
};
///////////////////////////////////////////////////////////////////////////////
} // namespace util
} // namespace wave
#else
#include <utility>
#include <algorithm>
#include <boost/concept_check.hpp>
#if defined(WAVE_USE_TST_SYMBOLTABLE)
#include "wave/util/tst.hpp"
#endif // defined(WAVE_USE_TST_SYMBOLTABLE)
///////////////////////////////////////////////////////////////////////////////
namespace wave {
namespace util {
namespace {
template <typename StringT>
inline StringT
make_name(StringT const &name)
{
return !name.empty() ? name : "<unnamed>";
}
}
///////////////////////////////////////////////////////////////////////////////
//
// The symbol_table class is used for structured storage of defined macros. It
// supports macro scoping.
//
///////////////////////////////////////////////////////////////////////////////
template <typename StringT, typename MacroDefT>
class symbol_table {
typedef symbol_table<StringT, MacroDefT> self_t;
typedef boost::shared_ptr<self_t> self_ref_t;
typedef boost::shared_ptr<MacroDefT> macro_ref_t;
#if !defined(WAVE_USE_TST_SYMBOLTABLE)
typedef std::map<StringT, macro_ref_t> defined_macros_t;
#else
typedef typename StringT::value_type char_t;
typedef tst<macro_ref_t, char_t, StringT> defined_macros_t;
#endif // !defined(WAVE_USE_TST_SYMBOLTABLE)
typedef std::map<StringT, self_ref_t> enclosed_scopes_t;
public:
typedef typename defined_macros_t::value_type value_type;
typedef typename defined_macros_t::iterator iterator;
typedef typename defined_macros_t::const_iterator const_iterator;
typedef typename enclosed_scopes_t::value_type scope_type;
typedef typename enclosed_scopes_t::iterator scope_iterator;
typedef typename enclosed_scopes_t::const_iterator const_scope_iterator;
public:
// constructs global scope symbol table
symbol_table()
: contains_unnamed_part(false)
{}
// constructs any non-global scope symbol table
symbol_table(StringT const &scope_name_, StringT const &full_outer_name_,
bool contains_unnamed_part_)
: scope_name(scope_name_),
full_scope_name(full_outer_name_ + "::" + make_name(scope_name_)),
contains_unnamed_part(contains_unnamed_part_)
{}
// generated copy constructor
// generated destructor
// generated assignment operator
// symbol table operations
iterator find(StringT const ¯o_name)
{ return macro_names.find(macro_name); }
const_iterator find(StringT const ¯o_name) const
{ return macro_names.find(macro_name); }
iterator begin() { return macro_names.begin(); }
const_iterator begin() const { return macro_names.begin(); }
iterator end() { return macro_names.end(); }
const_iterator end() const { return macro_names.end(); }
#if !defined(WAVE_USE_TST_SYMBOLTABLE)
std::pair<iterator, bool> insert(value_type const &value)
{ return macro_names.insert(value); }
void erase(iterator where) { macro_names.erase(where); }
#else
std::pair<iterator, bool> insert(StringT const &value)
{ return macro_names.insert(value); }
void erase(iterator where)
{ macro_names.erase((*where).data().macroname.get_value()); }
#endif // !defined(WAVE_USE_TST_SYMBOLTABLE)
void clear() { macro_names.clear(); }
// scope manipulation
self_ref_t begin_scope(StringT const &name);
self_t *end_scope() const;
bool get_scope(StringT const &name, self_ref_t &scope) const;
bool get_contains_unnamed_part() const { return contains_unnamed_part; }
scope_iterator scope_begin() { return scopes.begin(); }
const_scope_iterator scope_begin() const { return scopes.begin(); }
scope_iterator scope_end() { return scopes.end(); }
const_scope_iterator scope_end() const { return scopes.end(); }
// import a given macro name into this scope
bool import_macroname (StringT const &name, macro_ref_t const &value);
// import a given scope into this scope
template <typename PositionT>
void import_scope (self_t *value, PositionT const &act_pos);
StringT const &get_full_name() const { return full_scope_name; }
private:
defined_macros_t macro_names; // macros defined inside this scope
StringT scope_name; // name of this scope (empty for global)
StringT full_scope_name; // full name of this scope ('::' for global)
enclosed_scopes_t scopes; // scopes defined inside this scope
bool contains_unnamed_part; // name contains unnamed part(s)
};
///////////////////////////////////////////////////////////////////////////////
//
// begin_scope
//
// This function opens a new scope with the given name inside the current
// scope. If this scope already exists, the function does nothing.
// The newly created or existing scopes are returned.
//
///////////////////////////////////////////////////////////////////////////////
template <typename StringT, typename MacroDefT>
inline boost::shared_ptr<symbol_table<StringT, MacroDefT> >
symbol_table<StringT, MacroDefT>::begin_scope(StringT const &name)
{
// if this scope does not exist, create it, otherwise reuse the existing
scope_iterator it = scopes.find(name);
if (it == scopes.end()) {
// create the new scope
self_ref_t new_symbol_table(new self_t(name, full_scope_name,
contains_unnamed_part || name.empty()));
std::pair<scope_iterator, bool> p = scopes.insert(
scope_type(name, new_symbol_table));
BOOST_SPIRIT_ASSERT(p.second);
it = p.first;
}
// return a pointer to the new scope
return (*it).second;
}
///////////////////////////////////////////////////////////////////////////////
//
// end_scope
//
// This function closes (ends) the currently active scope
// The next outer scope is returned
//
///////////////////////////////////////////////////////////////////////////////
template <typename StringT, typename MacroDefT>
inline symbol_table<StringT, MacroDefT> *
symbol_table<StringT, MacroDefT>::end_scope() const
{
return 0; // not used anymore
}
///////////////////////////////////////////////////////////////////////////////
//
// get_scope
//
// This function returns a scope with a given name, if this scope exists.
// The return value of this function indicates whether a scope with the
// given name was found or not.
//
///////////////////////////////////////////////////////////////////////////////
template <typename StringT, typename MacroDefT>
inline bool
symbol_table<StringT, MacroDefT>::get_scope(StringT const &name,
boost::shared_ptr<symbol_table<StringT, MacroDefT> > &scope) const
{
const_scope_iterator cit = scopes.find(name);
if (cit == scopes.end())
return false;
scope = (*cit).second;
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// import_macroname
//
// Import a given macro name into this scope
//
// The name parameter should be an unqualified macro name.
//
///////////////////////////////////////////////////////////////////////////////
template <typename StringT, typename MacroDefT>
inline bool
symbol_table<StringT, MacroDefT>::import_macroname (StringT const &name,
macro_ref_t const &value)
{
// the new name shouldn't exist in this scope
iterator it = find(name);
if (it != end()) {
// name already defined in this scope as a macro, may not be imported
return false;
}
const_scope_iterator its = scopes.find(name);
if (its != scopes.end()) {
// name already defined in this scope as a scope, may not be imported
return false;
}
#if !defined(WAVE_USE_TST_SYMBOLTABLE)
std::pair<iterator, bool> p = macro_names.insert(value_type(name, value));
BOOST_SPIRIT_ASSERT(p.second);
boost::ignore_unused_variable_warning(p);
#else
std::pair<iterator, bool> p = macro_names.insert(name);
BOOST_SPIRIT_ASSERT(p.second);
(*p.first).data() = value;
#endif // !defined(WAVE_USE_TST_SYMBOLTABLE)
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// import_scope
//
// Import a given scope into this scope. This effectively makes available
// the whole scope hierarchy based at the scope to import into this scope.
//
// The name parameter should be an unqualified scope name.
//
///////////////////////////////////////////////////////////////////////////////
template <typename StringT, typename MacroDefT>
template <typename PositionT>
inline void
symbol_table<StringT, MacroDefT>::import_scope (self_t *value,
PositionT const &act_pos)
{
// import all macro names from the given scope
const_iterator end = value -> end();
for (const_iterator it = value -> begin(); it != end; ++it) {
#if !defined(WAVE_USE_TST_SYMBOLTABLE)
if ((*it).second->is_predefined)
continue; // do not import predefined macros
if (!import_macroname((*it).first, (*it).second)) {
CPP_THROW(preprocess_exception, alreadydefined_name,
(*it).first, act_pos);
}
#else
if ((*it).data().is_predefined)
continue; // do not import predefined macros
if (!import_macroname((*it).key(), (*it).data())) {
CPP_THROW(preprocess_exception, alreadydefined_name,
(*it).key(), act_pos);
}
#endif // !defined(WAVE_USE_TST_SYMBOLTABLE)
}
// import all child scopes of the given one into this scope
const_scope_iterator scope_end = value -> scope_end();
for (const_scope_iterator scope_it = value -> scope_begin();
scope_it != scope_end; ++scope_it)
{
StringT name ((*scope_it).first);
// the new name shouldn't exist in this scope
iterator itm = find(name);
if (itm != this->end()) {
// name already defined in this scope as a macro, may not be imported
CPP_THROW(preprocess_exception, alreadydefined_name,
name, act_pos);
}
scope_iterator its = scopes.find(name);
if (its != scopes.end()) {
// name already defined in this scope as a scope, may not be imported
CPP_THROW(preprocess_exception, alreadydefined_name,
name, act_pos);
}
// if this scope does not exist, import it
std::pair<scope_iterator, bool> p = scopes.insert(
scope_type(name, (*scope_it).second));
BOOST_SPIRIT_ASSERT(p.second);
boost::ignore_unused_variable_warning(p);
}
}
///////////////////////////////////////////////////////////////////////////////
} // namespace util
} // namespace wave
#endif // !defined(WAVE_ENABLE_CPP0X_EXTENSIONS)
#endif // !defined(SYMBOL_TABLE_HPP_32B0F7C6_3DD6_4113_95A5_E16516C6F45A_INCLUDED)