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

📄 templates.cpp

📁 UC Library Extensions UnderC comes with a pocket implementation of the standard C++ libraries, wh
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* TEMPLATES.CPP
 * Support for C++ templates
 * UnderC C++ interpreter
 * Steve Donovan, 2001
 * This is GPL'd software, and the usual disclaimers apply.
 * See LICENCE
*/
#include "common.h"
#include "templates.h"
#include "std_utils.h"
#include "tparser.h"  // for CLASS token
#include <ctype.h>
#include "input.h"
#include "directcall.h"

const int TEMPL_BUFFSIZE = 20000;

 // in main.cpp
 
int uc_eval(char *expr, bool append_semicolon, bool synchronous, char *name, int lineno);

#define YYEMPTY (-2)
extern int yychar;
int	save_yychar;
YYSTYPE	save_yylval;	

void save_parser_state()
{
 save_yychar = yychar;
 save_yylval = yylval;
 yychar = YYEMPTY;
}

void restore_parser_state()
{
 yychar = save_yychar;
 yylval = save_yylval;
}

int count(char *, char);  // at end of this file.
string build_qualified_name(const string& name, const TypeList& tl);
ostream& operator<< (ostream& outs, const TypeList& tl);
void massage_type_list(TypeList& tl);
void copy_type_list(TypeList& tlp, const TypeList& tlt);

typedef TypeList::iterator TLI;
typedef TypeList::const_iterator TLCI;

static char mIBuffer[TEMPL_BUFFSIZE];

bool DummyType::bind_to(Type t)
{
// Plain dummies bind to types in a straightforward manner; they only complain when
// they are already bound and an attempt is made to bind them to a different type
// Binding a constant dummy to a variable dummy involves some copying, which will
// only work for simple types at the mo.
 PEntry pe = entry() != NULL && t.is_dummy() ? t.as_dummy()->entry() : NULL;
 if (t == t_null) m_type = t_null;  // that is, unbound us (NB for us to _reuse_ this)
 else if (pe != NULL && pe->name == "") {  // constant dummy...
   memcpy(entry()->global_ptr(),pe->global_ptr(),pe->type.size());
   // *fix 1.2.9 indicates that we are properly bound! 
   m_type = entry()->type;  
   // *change 1.2.4 no longer function_trace
   if (Parser::debug.verbose) cout << "*bound (const) " << name() << ' ' << *(int *)pe->global_ptr() << endl;
 } else {
   if (! unbound() && t != m_type) return false;
   m_type = t;
   if (entry()) entry()->type = t;
   if (Parser::debug.verbose) cout << "*bound " << name() << ' ' << t << endl;
 }
 return true;
}

string DummyType::value_as_string()
{
  string s;
  if (name() != "") s += name();
  else { 
    if (entry()==NULL) s += "unbound";
    else s += type().value_as_string(entry()->global_ptr());
  }
  return s;
}

IContext::IContext(Table *parent)
 : Table(parent,DIRECT,0)
{ m_type = INSTANTIATION_CONTEXT; }

Template::Template(TemplateEntry *te, const TypeList& tl, IContext *cntxt)
 : m_context(cntxt), m_templ_entry(te), m_formal_args(tl)
{
  m_file = Input::filename();
  m_lineno = Input::lineno();
}

bool Template::is_class()
{ return m_templ_entry->is_class(); }

string Template::name()
{ return m_templ_entry->name();     }

void Template::instantiate(TemplateInstance *instance)
{
  using Parser::state;
  const TypeList& tl = instance->get_template()->formal_parms();

  TLCI ti;
 // don't try to instantiate templates using dummy types!
  int unbound_count = 0;
  FORALL(ti,tl) if (ti->is_dummy()){
    Type t = *ti;
	if (t.is_dummy()  && (t.is_unbound() || t.as_dummy()->type().is_dummy()) )
	    unbound_count++;
  }
  string inst_err = "";
  bool success = true;
  if (unbound_count > 0) success = false; 
  else {  
    Parser::ParserState old_state = state;
    // *hack 1.2.7 Can't use defered method compilation for instantiating template classes.
    bool old_skip = Parser::debug.skip_method_bodies;
    Parser::debug.skip_method_bodies = false;
    state.reset();
    state.push_context(m_context);
    state.in_template = instance;
    dcl_set(false,false); // save the DCL & ALS stacks...
    save_parser_state();  // save the BISON state...
	// *fix 1.1.0 Don't try to instantiate while in importing mode...
	void *slib = Builtin::get_dll_handle();
	Builtin::set_dll_handle(NULL);
  
    try {
      success = uc_eval(m_buffer,false,true,m_file.c_str(),m_lineno) == 0;
    } catch(string s) {
      inst_err = s;  
    } catch(...) {
      //inst_err = "unknown instantiation error";
     success = false;
    }

	Builtin::set_dll_handle(slib);
    state.in_template = NULL;
    state.pop_context();
    restore_parser_state();
    // *fix 1.2.7 lines swopped around...
    state = old_state;
   // dcl_reset();
    Parser::debug.skip_method_bodies = old_skip;

    // NB to _unbind_ the dummy parameters, ready for the next instantiation!
    FORALL(ti,tl) if (ti->is_dummy()) ti->as_dummy()->unbind();
  } 

  if (! success) {
     instance->instantiated(false);
     fail(inst_err);
  } else {
    instance->instantiated(true);
	// can't call type() until the data is set!
    if (Parser::debug.verbose) { //*change 1.2.4 no longer function_trace
	  cout << "instantiated: ";
	  Signature::set_fun_name(instance->name()); // only for function templates, of course!
	  try {
	   if (instance->data() != NULL) cout << instance->type();
      } catch(...) {
        cout << "<unknown>";
	  }
	  cout << endl;
	}
  }
}

TypeList& Template::formal_parms()
{ return (TypeList&)m_context->formal_parms(); }

const TypeList& Template::formal_args()
{ return m_formal_args; }

// static support routines for the parser
Type Template::get_template_type(PEntry te, TypeList *ptl)
{
 // resolving the actual type, given an expression like Type <int,20> etc.
 TemplateEntry *pte = (TemplateEntry *)te->data;
 if(pte->match(*ptl)) {
   return pte->match_instance()->type();
  } else error("Cannot match this template");
 return t_null;
}

bool in_template = false;

void Template::do_template_header(TypeList *ptl)
{
 using Parser::state;
 IContext *ic = new IContext(&state.context());
 state.push_context(ic);
 TLI tli;
 FORALL(tli,*ptl) {
    Type t = *tli;
    DummyType *pd = tli->as_dummy();
	string name = pd->name();
	bool is_dummy = tli->is_unbound();
	Type type;
	// the 'true' dummy types are put in as is; the constants are put in as
	// their type value.
    if (is_dummy) type =  *tli;
    else type = pd->type();
	
	PEntry pe;
	if (is_dummy) pe = state.add_typedef(type,name);
    else pe = state.add_variable(type,name,NULL,None);

	// We bind the actual entry to any dummies
	tli->as_dummy()->entry(pe);
 }
   
 ic->set_formal_parms(*ptl);
 delete ptl;

 // *hack 1.1.4 lexical tie-in 
 in_template = true;

}

void Template::do_function_template()
{
// appears immediately after the function prototype;
// *add 1.1.0 special case of method template; keep track of any entries created.
// *fix 1.1.3 exclude genuine member function templates!
 // *hack 1.1.4 lexical tie-in 
 in_template = false;

 try {
  bool was_outside_class;
  Signature *sig = Parser::get_prototype(was_outside_class);
  string name    = Signature::get_fun_name();
  TypeList formal_args = sig->type_list();

  IContext *ic = (IContext *)Parser::state.pop_context();
 
  PEntry pe;
  Table *cntxt;
  bool was_method = false;
  if (sig->class_ptr() != NULL && was_outside_class) {
    cntxt = sig->class_ptr();
    if (PClass(cntxt)->get_template()==NULL) fail("must be a class template here");
    was_method = true;
  } else cntxt = &Parser::state.context();

  pe = cntxt->lookup(name);
  FunctionEntry *pfun;
  TemplateEntry *ptmpl;  
  if (pe == NULL) { 
 // Create a new FunctionEntry with a TemplateEntry
 	pe = cntxt->add(name);
	pfun = Parser::create_function_entry(sig,name,pe);
	ptmpl = new TemplateEntry(pe,false);
	if (was_method) ptmpl->set_method();
	pfun->set_template(ptmpl);
	pe->type = Type(sig);
    pe->data = (int)pfun;
    if (was_method) 
       PClass(cntxt)->get_template()->get_template()->get_entry()->add_method_entry(pe);
  } else if (! pe->type.is_function()) {
     fail("already defined as a non-function");
  } else {
   // was previously defined as a function (which might not have been a template!)
    pfun = (FunctionEntry *)pe->data;
    ptmpl = pfun->get_template();
 // Not really an error...but watch this carefully!  (especially w/ methods!)
    if (ptmpl == NULL) { //    fail("previously defined as a function");
      ptmpl = new TemplateEntry(pe,false);
	  pfun->set_template(ptmpl);
    }
  }

 // add a new template to the TemplateEntry
  Template *pnt = new Template(ptmpl,formal_args,ic);
  ptmpl->add_template(pnt);

 // Lippman 183, 2nd ed.  formal args must contain all formal template type parms.
 // (Not applicable to class template members, which don't need matching)
  if (! was_method) {
    bool all_present = true;
    TLCI tlip, tlia;
    const TypeList& formal_parms = pnt->formal_parms();
    if (!ptmpl->is_method()) {
    FORALL(tlip,formal_parms)  {
      int times_present = 0;
      FORALL(tlia,formal_args) if (type_contains(*tlia,*tlip)) times_present++;
      all_present = all_present && times_present > 0;
    }
    if (!all_present) { fail("All formal template type parms must be present at least once"); return; }
   }
  }

// and grab the function!! 
  generate_function_header(name,sig,true);
  pnt->grab();

  //*fix 1.2.0L Should not have deleted the signature! 
  // delete sig;
} catch(string msg) {
  error(msg);
}

}

char* Template::generate_function_header(Function* pf, bool plain_method, bool qualified_names)
{ 
 *mIBuffer = 0;
  ostrstream outs(mIBuffer,TEMPL_BUFFSIZE);
  Signature::write_qualified_names(qualified_names);
  pf->dump(outs);
  outs << ' ' << (plain_method ? '{' : ':') << ends;
  Signature::write_qualified_names(true); // maintain the default setting!
  return mIBuffer;
}

char* Template::generate_function_header(string name, Signature* sig, bool plain_method)
{
  *mIBuffer = 0;
  ostrstream outs(mIBuffer,TEMPL_BUFFSIZE);
  Signature::set_fun_name(name);
  outs << *sig << " {" << ends;
  return mIBuffer;
}

void Template::do_class_template(int s_or_c, string name, int look_ahead, TypeList *ptl)
{
 using Parser::state;
 IContext *ic = (IContext *)state.pop_context();
 // *hack 1.1.4 lexical tie-in 
 in_template = false;
 
// *fix 0.9.8 Doing class template specializations properly
 TypeList formal_args;
 PEntry pe = state.context().lookup(name);
 if (pe && pe->type != t_template_type) { error("Not a template class " + Parser::quotes(name)); return; }
 if (ptl != NULL) { // formal_args will only be non-trivial if this is a specialization;
    if (pe == NULL) { error("Can only specialize a class template if it already exists"); return; }    
    formal_args = *ptl;
 } else
    formal_args = ic->formal_parms();

 TemplateEntry *pte;
 
 if (pe == NULL) {  
   pe = state.context().add(name);
   pe->type = t_template_type;
   pte = new TemplateEntry(pe,true);
   pe->data = (int)pte;
   pe->m_typename = true;
 } else pte = (TemplateEntry *)pe->data;

 Template *pct = new Template(pte,formal_args,ic);
 pte->add_template(pct);

 *mIBuffer = 0;
 ostrstream outs(mIBuffer,TEMPL_BUFFSIZE);
 outs << (s_or_c == CLASS_X ? "class " : "struct ") << name;
 //* -2 (Obscure Bison number) means that there's no lookahead token...    
 //* in this case the look-ahead can be either '{' or ':'  
 if (look_ahead != -2) outs << (char)look_ahead;
 outs << endl;
 outs << ends;

 pct->grab();

}

bool Template::type_contains(Type t1, Type t2)
// does the dummy type t1 contain t2?  Two cases:
// (a) t1 is a qualified form of t2, e.g const T&
// (b) t1 is a template containing t2, e.g. list<T,A>&
{
 if (t1.is_dummy() && t2.is_dummy()) {
    DummyType *d1 = t1.as_dummy(), *d2 = t2.as_dummy();
	if (d1 == d2 || d1 && d2 && d1->name() == d2->name()) return true;  // case (a)
    if (t1.is_class()) {
	  Class *pc = t1.as_class();
	  const TypeList& tl = pc->get_template()->type_parms();
	  TLCI tli;
	  FORALL(tli,tl) {
	   Type tp = *tli;
	   if (tp == t2) // || d2 && tp.is_dummy() && d2->name() == tp.as_dummy()->name())
	      return true; 
      }
	  return false;
	  //return utils::find(tl,t2);  // case (b)
	}
 }
 return false;	    
}

void massage_type_list(TypeList& tl)
{
 TLI tli;
 FORALL(tli,tl) {
  Type t = *tli;
  if (t.is_const() && ! t.is_ref_or_ptr()) t.strip_const();  // e.g. 'const int' -> 'int'
 // 'variable references'! (see Expressions::entry_op())
  else if (t.is_reference()) t.strip_reference();   //t.is_variable()
  // the appearance of a function name means an _implied_ function pointer
  if (t.is_signature() && !t.is_pointer()) t.incr_pointer();
  *tli = t;
 }
}

// support for things like Stack<int,20> and template<class T, int n>
// these guys will grab the four possibilities in such lists.
// For example , these would be:
//  1) class T     - a named dummy
//  2) int N       - a variable parameter
//  3) int         - a type
//  4) 20          - a constant

⌨️ 快捷键说明

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