UC Library Extensions UnderC comes with a pocket implementation of the standard C++ libraries, wh

源代码在线查看: table.cpp

软件大小: 419 K
上传用户: stuoju
关键词: implementation Extensions libraries standard
下载地址: 免注册下载 普通下载 VIP

相关代码

				/* TABLE.CPP
				 * Lookup tables
				 * UnderC C++ interpreter
				 * Steve Donovan, 2001
				 * This is GPL'd software, and the usual disclaimers apply.
				 * See LICENCE
				 *
				 * Describes general lookup tables, from which all
				 * contexts, such as namespaces, function blocks, classes etc
				 * are derived.
				 */
				
				// get rid of nasty & irrevalent messages about debug map names
				#pragma warning(disable:4786)
				#define IN_TABLE_CPP
				#include "table.h"
				#include "std_utils.h"
				
				//------------------ CLASS Allocator
				
				int Allocator::dword_align(int sz)
				//--------------------------------
				{ 
				  if (sz % 4 == 0) return sz;
				  else return sz + 4 - sz%4;
				}
				
				// *add 1.2.0 Support for 8-byte alignment of doubles (MS default)
				
				int Allocator::qword_align(int sz)
				//--------------------------------
				{ 
				  if (sz % 8 == 0) return sz;
				  else return sz + 8 - sz%8;
				}
				
				Allocator::Allocator(void *buff, int sz)
				: m_dword_align(true),m_reserved(0),m_own_ptr(false),m_mem_unit(1),m_move_to_next(-1)
				//-------------------------------------------------------------------------------------
				{ 
				  m_buff = (char *)buff;
				  if(sz)   { m_buff = new char [sz];  m_own_ptr = true; }
				  m_data  = m_buff;
				}
				
				Allocator::~Allocator()
				{
				 if (m_own_ptr) delete [] m_buff;
				}
				
				inline int max(int i, int j)
				{ return i > j ? i : j; }
				
				int Allocator::alloc(int sz, void *data)
				//--------------------------------------
				{
				  int ret;
				  char *start;
				 // *add 1.2.6 allocators for unions are reset on each new allocation
				  if (m_move_to_next > -1) {
					  m_move_to_next = max(sz,m_move_to_next); 
					  m_data = (char*) m_move_to_next;
					  return 0;
				  } else {
				    start = m_data;
				    // *fix 1.2.3 Since the alignment flag redefinition, we've not been respecting pack(1)
				    if (m_dword_align > 1) sz = dword_align(sz);
				    if (data && m_data) memcpy(m_data, data, sz); 
				    m_data += sz;
				    ret = (long)start - (long)m_buff;
				    return ret/m_mem_unit;
				  } 
				}
				
				int Allocator::alloc_qword()
				//---------------------------
				{
				  if (m_move_to_next > -1) return alloc(8,NULL);
				// *add 1.2.0 this is specialized to return proper 8-byte aligned offsets...
				  m_data = (char *)qword_align((int)m_data);
				  char *start = m_data;
				  m_data += 8;
				  return (int)start;
				}
				
				int Allocator::current_offset()
				//-----------------------------
				{
				  return ((long)m_data - (long)m_buff)/m_mem_unit;
				}
				
				
				////------------------ CLASS Table
				Table::Table(Table *parent, RMode mode, int sz)
				: Allocator(NULL,sz),m_parent(parent),m_mode(mode),
				  m_entries(0), m_first_obj(NULL),m_unwind_flag(0)
				{
				 m_map = new EntryMap;
				 m_type = TABLE;
				}
				
				bool
				Table::is_local_entry(PEntry pe)
				//-----------------------------
				{ return pe ? pe->context == this : false; }
				
				PEntry
				Table::lookup(const string& name, bool look_in_parent)
				//---------------------------------------------------
				{
				 PEntry se;
				 /// Look in any injected namespaces....
				  NamespaceList::iterator nli;
				  if (m_injected_namespaces.size() > 0)
				   FORALL(nli,m_injected_namespaces)
				    if((se = (*nli)->lookup(name,false)) != NULL) return se;
				
				 /// Try to look up this symbol locally
				 try {
				  EntryMap::iterator iem = m_map->find(name);
				  se = (iem != m_map->end()) ? iem->second : NULL;
				  if (se) return se; 
				 } catch(...) {
				   return NULL;
				 }
				
				 /// If not found, then ask our parent context (if it exists)
				 if(m_parent && look_in_parent) {
				       se = m_parent->lookup(name); 
				       if (se) return se; 
				 } 
				 return NULL;  // no can do!!
				} 
				
				                       
				void
				Table::add_entry(const string& name, PEntry pe)
				{
				 (*m_map)[name] = pe;
				}
				
				bool 
				Table::remove(PEntry pe)
				{
				 EntryMap::iterator iem = m_map->find(pe->name);
				 if (iem == m_map->end()) return false;
				 m_map->erase(iem);
				 return true;
				}
				
				Entry *
				Table::new_entry(const string& name)
				{
				 PEntry se = new Entry;
				 se->set_access(Public);
				 se->type = t_void;
				 se->name = (string)name;  // pasop w/ MSTRING.H
				 se->size = 1;
				 se->set_access(Public); // by default!
				 se->m_typename = false; 
				 se->context = this;
				 return se;
				}
				
				Entry *
				Table::add(const string& name)
				{
				 PEntry se = new_entry(name);
				 add_entry(name,se);
				 m_entries++;
				 return se;
				}
				
				void Table::dump_entries(ostream& os,int flags)
				{
				  EntryMap::iterator ei;
				  const char *sep = (flags & SEMICOLON_SEP) ? "; " : " ";
				  bool do_vars = flags & VARS;
				  int i = 1;
				  for(ei = m_map->begin(); ei != m_map->end(); ++ei,++i) {
				    PEntry pe = ei->second;
				    // note; we exclude _temporaries_ in this enumeration!
				    if (do_vars && (pe->type.is_const() || pe->type.is_signature() || pe->m_typename==true || pe->name[0]=='$')) continue;
				    os first 				    if (i % 4 == 0) os 				  }
				  os 				  // for now...idea is to have more control later
				  if ((flags & ALL) && m_parent && m_parent->m_type == m_type) m_parent->dump_entries(os,flags);
				}
				
				// This defines how the search flags are used to filter symbol table entries
				// *add 1.2.3 Can now specifically look for imported and undefined functions
				bool Table::check_entry(PEntry pe, int flags)
				{
					 Type t = pe->type;
					 if (t.is_function()) {
						 if (! (flags & FUNCTIONS))  return false; // only if requested explicitly!
						 // Assume here that all members of an overloaded set have the same distinguishing characteristics!
						 FunctionEntry *pfe = (FunctionEntry *)pe->data;
				         // *fix 1.2.3 Template function entries are often empty
				         if (pfe->size() == 0) return false;
				         Function *pf = pfe->back() ;
						 if (flags & NON_STATIC && ! pf->is_method())   return false;
						 if (flags & VIRTUALS   && ! pf->is_virtual())  return false;
						 if (flags & BUILTINS   && ! pf->builtin())     return false;
						 if (flags & CTORS      && ! pf->is_constructor()) return false;
						 if (flags & DTORS      && ! pf->is_destructor())  return false;  
				         if (flags & CONSTS     && ! pf->is_const())       return false;
				         if (flags & IMPORTS    && ! pf->import_scheme())  return false;
				         if (flags & UNDEFINED  && ! pf->undefined())      return false;
						 return true;  // plain ordinary function...
				     } else { 
						 if (flags & FUNCTIONS)  return false; // this isn't a function!
						 if (pe->is_typename()) {
						   if (flags & TYPEDEFS   && pe->is_typedef())   return true;
						   if (flags & NAMESPACES && pe->is_namespace()) return true;
						   if (flags & CLASSES    && pe->is_class())     return true;
						   return false;
						 }
						 else if (flags & NON_STATIC && pe->is_direct()) return false;
						 else {
				          if (! (flags & FIELDS)) return false;
					      if (flags & TEMPS  && pe->name[0] != '$')  return false;
					      if (flags & CONSTS && ! t.is_const())      return false;
						  return true;
				         }
				     } 	 
				}
				
				void Table::list_entries(EntryList &el,int flags)
				{
				  search_entries((TableSearcher *)NULL,&el,flags);
				}
				
				class PostMatcher: public TableSearcher {
				private:
					const char *m_t;
				
				public:
					PostMatcher(const char *t)
					: m_t(t) {}
				
				   virtual bool match(PEntry pe) 
				   {
				     const char *s = pe->name.c_str();
				     return strstr(s,m_t) != NULL;
				   }
				
				};
				
				class PreMatcher: public TableSearcher {
				private:
					const char *m_t;
					int m_sz;
				public:
					PreMatcher(const char *t, int sz)
					: m_t(t), m_sz(sz) {}
				
				   virtual bool match(PEntry pe) 
				   {
				     const char *s = pe->name.c_str();
				     return strncmp(s,m_t,m_sz) == 0; 
				   }
				};
				
				// *add 1.2.4 Can now list all symbols which _exactly_ match a name
				class ExactMatcher: public TableSearcher {
				private:
				    string m_target;
				public:
				    ExactMatcher(string t)
				        : m_target(t)
				    {}
				
				    virtual bool match(PEntry pe)
				    {
				        return pe->name == m_target;
				    }
				};
				
				
				// *fix 1.2.4 Passing a non-wildcarded pattern will return all entries with that exact name.
				PEntry Table::search_entries(const char *pat,EntryList* el,int flags)
				{
				  TableSearcher *tsearch;
				  if (pat[0]=='*') {
				      tsearch = new PostMatcher(pat+1);
				  } else {
					  char *buff = strdup(pat);
					  char *s = strchr(buff,'*');
				      if (s != NULL)  {
				        *s = '\0';
				        tsearch = new PreMatcher(buff,strlen(buff));
				      } else 
				        tsearch = new ExactMatcher(buff);
				   }
				  return search_entries(tsearch,el,flags);
				}
				    
				
				// *add 1.1.4 This is a general-purpose entry searcher and extractor,
				//   which will fill a list with matching entries, if the list is defined.
				//   If not, then we return the first matching entry.
				//   If the search object doesn't exist, then we match anything that satisfies the flags.
				//   It follows the same search order as Table::lookup().
				//   This function will always return a valid entry on success (that is, at least
				//   one entry found) and otherwise NULL.
				// *fix 1.2.0 we were bailing out immediately if we found stuff in the parent, etc
				// and were collecting all entries (el != NULL)
				PEntry Table::search_entries(TableSearcher *search,EntryList* el,int flags)
				{
				  PEntry pe;  
				  // look in the parent context if requested
				  if (flags & DO_PARENT && m_parent != NULL) {
					  pe = m_parent->search_entries(search,el,flags);
					  if (pe && ! el) return pe;
				  }  
				   /// Look in any injected namespaces....
				  NamespaceList::iterator nli;
				  if (m_injected_namespaces.size() > 0)
				    FORALL(nli,m_injected_namespaces) {
				      pe = (*nli)->search_entries(search,el,flags);   
				      if(pe && ! el) return pe;
				    }
				  /// and finally traverse the entries...
				  EntryMap::iterator ei;
				  for(ei = m_map->begin(); ei != m_map->end(); ++ei) {
				     pe = ei->second;
					 if (check_entry(pe,flags) && (search && search->match(pe) || ! search)) {
						 if (el) el->push_back(pe);
						 else return pe;
				     }
				  }
				  bool success = el && el->size() > 0;
				  return success ? el->front() : NULL;  
				}
				
				
				void Table::reclaim(string s)
				{
				}
				
				void Table::clear()
				{ 
				 Allocator::clear();
				 m_map->clear();
				}
				
				void Table::first_obj(PEntry pe)
				{
				 if (m_first_obj == NULL) m_first_obj = pe;
				}
				
				/*REF:NAMESPACE*/
				
				PEntry Table::inject_entry(PEntry pe)
				{
				 // Add a new entry, copying the relevant information (note: the _access rights_ may change!)
				 PEntry new_pe = add(pe->name);
				 new_pe->type = pe->type;
				 new_pe->data = pe->data;
				 new_pe->rmode = pe->rmode;
				 new_pe->size = pe->size;
				 new_pe->m_typename = pe->m_typename;
				 return new_pe;
				}
				
				void error(string msg);
				
				bool Table::inject_namespace(Namespace *tbl)
				{
				    if (tbl==NULL) { error("Not a namespace!"); return false; }
				    return utils::add_unique(m_injected_namespaces,tbl);
				}
				
				// *add 1.2.7 Can query whether a particular namespace has been injected into a context...
				bool Table::is_injected(Namespace *tbl)
				{
					return utils::find(m_injected_namespaces,tbl);
				}
				
				//------------------ CLASS NamedTable
				NamedTable::NamedTable(Table *parent, RMode mode, int sz)
				: Table(parent,mode,sz)
				{
				}
				
				string
				NamedTable::name()
				{ 
				 return m_entry->name;
				}
				//------------------ CLASS InjectState
				InjectState *
				InjectState::clone()
				{
				 if (injected_entries().size()==0 && injected_namespaces().size()==0 && 
				     masked_entries().size()==0) return NULL;  // this was a TRIVIAL state!
				 else {
				   InjectState *is = new InjectState;
				   is->injected_entries() = injected_entries();
				   is->masked_entries() = masked_entries();
				   is->injected_namespaces() = injected_namespaces();
				   return is;
				 }
				}
				
				void
				InjectState::clear()
				{
				 injected_entries().clear();
				 injected_namespaces().clear();
				 masked_entries().clear();
				}
				
				//------------------ CLASS Namespace
				Namespace::Namespace(Table *parent, int sz)
				: NamedTable(parent,DIRECT,sz),m_inject_state(NULL)
				{
				 m_type = IS_NAMESPACE;
				}
				
				Namespace::~Namespace()
				{
				 delete m_inject_state;
				}
				
				InjectState *
				Namespace::inject_state()
				{
				  if (m_inject_state==NULL) m_inject_state = new InjectState;
				  return m_inject_state;
				}
				
				PEntry Namespace::inject_entry(PEntry pe)
				{
				// Are we masking an existing _local_ entry with this injected entry?
				 PEntry masked_pe = lookup(pe->name);
				 if (masked_pe != NULL && is_local_entry(masked_pe))
				     inject_state()->add_masked_entry(masked_pe);
				
				 PEntry new_pe = Table::inject_entry(pe);
				 // keep tabs on what's been injected!
				 inject_state()->add_injected_entry(new_pe);
				 return new_pe;
				}
				
				bool Namespace::inject_namespace(Namespace *ns)
				{
				 if (!Table::inject_namespace(ns)) return false;
				 inject_state()->add_injected_namespace(ns);
				 return true;
				}
				
				void Namespace::clean()
				{
				  if (is_clean()) return;
				
				  EntryList::iterator eli;
				  // remove injected entries
				  EntryList& elj = inject_state()->injected_entries();
				  FORALL(eli,elj) remove(*eli);
				  // restore any masked entries
				  EntryList& elm = inject_state()->masked_entries();
				  FORALL(eli,elm) add_entry((*eli)->name , (*eli));
				  m_injected_namespaces.clear();
				
				  inject_state()->clear();
				
				}
				
				void Namespace::restore()
				{
				  if (is_clean()) return;
				
				  EntryList::iterator eli;
				  // re-insert injected entries
				  EntryList& elj = inject_state()->injected_entries();
				  FORALL(eli,elj) Table::inject_entry(*eli);
				
				  m_injected_namespaces = inject_state()->injected_namespaces();
				
				}
				
				//------------------ CLASS Global
				
				// Global namespace!!
				const int GLOBAL = TABLE+1;
				
				Global::Global(int sz)
				 : Namespace(NULL,sz) //Table(NULL,DIRECT,sz)
				{
				  m_type = GLOBAL;
				  PEntry pe = new Entry;
				  pe->name = "$G$";
				  entry(pe);
				}
				
				void Global::finalize()
				{
				}
				
				
				
							

相关资源