⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 class.cpp

📁 UC Library Extensions UnderC comes with a pocket implementation of the standard C++ libraries, wh
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/* CLASS.CPP
 * The type Class
 * UnderC C++ interpreter
 * Steve Donovan, 2001
 * This is GPL'd software, and the usual disclaimers apply.
 * See LICENCE
 */
#pragma warning (disable:4786)
#define IN_TABLE_CPP
#include "common.h"
#include "directcall.h"
#include "operators.h"
#include "opcodes.h"
#include "tparser.h"
#include "std_utils.h"
#include "module.h"
#include "input.h"

void error(string msg);  // shd be in common...
 // in main.cpp
int uc_eval(char *expr, bool append_semicolon, bool synchronous, char *name, int lineno);

namespace {// private utility stuff
  bool grab_list(const TypeList& tl1, TypeList& tl2);
  typedef std::map<PEntry,PExprList> Entry2ExprMap;
  FunctionContext *mFe;

  PEntry begin_method(string name, Type rtype, char *arg_name, Type atype, int ftype);
  void declare_method(string name, Type rtype, char *arg_name, Type atype, int ftype);
  void   end_method();
  Function *get_std_match(const TypeList& tl, const FunctionList& fl, Type t);

  PFBlock mVMT[MAX_VMT_ENTRIES];

  Entry2ExprMap s_entry_map;

  char *TRY_BLOCK_HANDLER_CLASS = "_tbhc_";
};

void *mVtable[MAX_VMT_ENTRIES];

// HACK ALERT!
#define m_base_ctor m_finalized

Class::Class(Table *parent,int access) 
        : NamedTable(parent,OREL,0),m_base_access(access),m_simple_struct(true),
          m_default_constructor(NULL),m_copy_constructor(NULL),m_destructor(NULL),
          m_has_constructors(false),m_base_entry(NULL),m_templ_info(NULL),
          m_vtable_size(0),m_is_union(false),
          m_abstract(false),m_base_ctor(false), m_import(NULL),m_imported(false),m_struct(false)
{
    m_type = IS_STRUCT;
    m_VMT = NULL;
  
    set_base_class(base_class(),access);
}

void Class::set_base_class(Class *base, int access)
{
  using namespace Parser;
  clear();
  if (base) m_parent = base;
  m_base_access = access;

  // *fix 1.1.2 Field alignment moved here from ctor, in case of redefinition.
  set_dword_align(Parser::debug.class_dword_align);

  if (base) {
        PPClass vmt;        
        m_VMT = NULL;  // hm, really shd clear out if NOT null...
        // *NB* use the actual size, not the VMT-adjusted size!
        m_data = (char *)m_parent->size();
        m_slot_id = base->last_slot();
        vmt = base->get_VMT();
        int vmt_size = sizeof(void *)*(m_slot_id+1);
        if (vmt) //...copy our parent's VMT into the local buffer
            memcpy(mVMT,vmt,vmt_size);

        copy_convert_to_list();


        // if we are derived from an imported class w/ a vtable,
        // then we will have to generate a vtable for these objects.
        // *fix 1.2.0 Use the inherited vtable size
        // *fix 1.2.7 Such classes must have the _same_ kind of import scheme
        // as their bases; this was not working if there was a subsequent DLL load.
        if((base->imported() && vmt) || (base->vtable_size() > 0)) { 
           m_vtable_size = base->vtable_size(); 
		   m_import = Import::create_scheme(base->import_scheme()->scheme_type());
		   m_imported = Builtin::get_dll_handle() != NULL;
		   m_import->set_first_virtual_class(base->m_import->vmt_offset());
        } 
        // *hack 0.9.8 A forward declaration of ctor; hack for factory functions. 
        // *OUT*this interferes w/ normal default ctor rules.
        //declare_method(constructor_name(),t_void,NULL,t_void,IsConstructor);
        //m_base_ctor = true;
   } else {
        m_slot_id = 0;
   }
}

Function *Class::default_constructor() { return m_default_constructor; }
Function *Class::copy_constructor()    { return m_copy_constructor;    }
Function *Class::destructor()          { return m_destructor;          }
bool  Class::has_constructors()
{ 
    return m_has_constructors;
}

// defines our convention for internally naming the constructor/destructor
// cf. parser.y line 110...
string Class::constructor_name()
{ return "__C__"; }

string Class::destructor_name()
{ return "__D__"; }

bool Class::is_anonymous_union()
{
  return m_is_union && name()[0] == '$';
}

void Class::set_anonymous_union()
{
 switch_off_allocator_advance();
 m_is_union = true;
}

PEntry
Class::add(const string& name)
{
  PEntry pe = Table::add(name);
  pe->set_access(get_access_mode());
  m_entries.push_back(pe);
  return pe;
}

// compare this to Table::list_entries(), which uses the underlying map.
// Class keeps an explicit list of entries so it can deliver entries
// in _order of declaration_.  No doubt there is more than one way to
// do this
void Class::list_entries(EntryList &el, int flags)
{
	if (flags & DO_PARENT && base_class() != NULL) base_class()->list_entries(el,flags);
	EntryList::iterator eli;
	for(eli = m_entries.begin(); eli != m_entries.end(); ++eli) 
		if (check_entry(*eli,flags)) el.push_back(*eli);
}

void 
Class::add_constructor(Function *fn, bool no_implicit_type_conversion)
{
  if (fn->can_match(0)) { 
      m_default_constructor = fn;
  }  else
  if (fn->can_match(1)) {
    Type t = entry()->type;     t.make_const_reference();
    Type at = *(fn->signature()->begin());  // the type of the argument

    // was this a copy constructor?
    if (at == t) m_copy_constructor = fn;
    else if (! no_implicit_type_conversion) {
     // defines a Conversion From - _except_ for copy constructor and if marked 'explicit'!
      m_from_list.push_back(at);
      m_from_fn.push_back(fn);
    }
  }
  m_has_constructors = true;
  m_simple_struct = false;
}

void Class::destructor(Function *fn) 
{
 m_destructor = fn;  // *change 1.0.0 does NOT imply this class has to have VMT
 // *fix 1.2.0 This caused enormous grief - I'm not at all sure _why_ it was here!
 // construct_VMT() shd _only_ be called when all the class' virtual slots are filled,
 // i.e. at class finalization.
 //construct_VMT();    // *temporary - depends on _gForceVMT
}

void Class::construct_VMT()
{
  if (m_VMT) return;  // already built one!
  if (m_slot_id > 0) {
    // increase our size to accomodate VMT 
    // - but only if this is the first class to have a VMT!
    //if (!is_derived() || is_derived() && PClass(m_parent)->last_slot() == 0)  m_data += 4;  
    mVMT[0] = PFBlock(this);  // our class pointer!
    m_VMT = new PClass [m_slot_id+1];
    memcpy(m_VMT, mVMT, sizeof(PFBlock)*(m_slot_id+1));
 }
}

void Class::clear()
{
 Table::clear();  // just to test - not sure about inheritance!
 m_has_constructors = false; // NB to reset state fully!
 m_default_constructor = m_copy_constructor = m_destructor = NULL;
 s_entry_map.clear();
 m_obj_list.clear();
 m_field_list.clear();
 m_entries.clear();
 m_vtable_slots.clear();
 m_vtable_funs.clear();
 m_base_entry = NULL;
 m_VMT = NULL;
 m_slot_id = 0;
}

Namespace *Class::inside_namespace()
{
 if (Parser::is_namespace(entry()->context)) return (Namespace *)entry()->context;
 else return NULL;
}

bool not_locally_defined(Class *pc, PEntry pe)
{ 
 return !pe || !pc->is_local_entry(pe);
}  

Type ref_to(Class *pc, bool is_const=true)
{
  Type t_oref = pc->entry()->type; //??
  t_oref.make_reference();
  if (is_const) t_oref.make_const(); 
  return t_oref;
}

PEntry Class::get_constructor()
{
 return  lookup(constructor_name());
}

static int s_first_line = -1, s_last_line;

void Class::add_line_no(const string& file, int line)
{
  if (s_first_line == -1) s_first_line = line;
  else s_last_line = line;
}

// *add 1.2.7 support for the defered compilation of method bodies

void Class::add_defered_method_body(Function* fn, char* body_buff)
{
  m_DeferedBodies.push_back(new MethodBody(fn,body_buff));
}

void save_parser_state();
void restore_parser_state();

string s;
Class* mClass;

void* _copy_body(char* buff)
{
  strcpy(buff,s.c_str());
  return mClass;
}

void Class::compile_methods()
{
 if (Parser::debug.skip_method_bodies) {
      using namespace Parser;
      Module *pm = Module::current();
      //string s;
      bool success;
      int line;
      mClass = this;
      string file = pm->name(); 
      debug.skip_method_bodies = false;
      ParserState old_state = state;
      save_parser_state();  // save the BISON state...
      while (m_DeferedBodies.size() > 0) {
          MethodBody* mb = m_DeferedBodies.front();
          s = mb->body;
          line = pm->get_function_line(mb->pf);
          try {
            success = uc_eval(s.c_str(),false,true,file.c_str(),line) == 0;
          } catch(string msg) {
            success = false;
          }
          if (! success) {
             cerr << s << "*\n";        
             debug.skip_method_bodies = true;
             m_DeferedBodies.clear();
             return;
          }
          delete mb;
          m_DeferedBodies.pop_front();
      }
      m_DeferedBodies.clear();
      Input::insert_string(";");
      state = old_state;
      debug.skip_method_bodies = true;
      restore_parser_state();
      Parser::state.in_declaration = false; //*HACK*
  }
}


void Class::finalize()
{
  Module::current()->add_class(this,s_first_line,s_last_line);
  s_last_line = -1;

  construct_VMT();
  // not entirely the whole story.....
  m_simple_struct = !has_constructors();
  m_finalized = true;

  if (imported()) {
      // *fix 1.2.0 Ensure that imported classes have a proper vtable
      m_vtable_size = m_slot_id;
     // *add 1.2.3 __vftable is used to reserve the class layout
     // of an imported class with virtual methods, but only if it's the first such class.
      if (! base_class() && m_vtable_size > 0) {          
        PEntry pe;
        // in case of the vtable being at the begining, we have to shuffle entries along

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -