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

📄 expressions.cpp

📁 UC Library Extensions UnderC comes with a pocket implementation of the standard C++ libraries, wh
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	  if (is_arr) ed = vector_context_op(ed);
	         else ed = dynamic_context_op(ed);  
      if (overloaded && overalloc) ed = add_const_op(t,-sizeof(void *),ed);
      ed = append_op(e1,ed);
    } else ed = e1;
    er = function_call(delete_fn,expr_list(ed,ez));
 } else
 er = function_call(delete_fn,expr_list(e1,ez));
 return er;
}

PExpr construct_op(PClass pc, PExprList pel, bool check_abstract)
{
 if (pc->is_abstract() && check_abstract) return expr_error("class contains abstract methods");
// call the constructor, passing the arguments
 PEntry pec = pc->get_constructor();
 if (pec==NULL) return expr_error("cannot create constructor");
 return function_op(entry_op(pec),pel);
}

PExpr init_ref_op(PExpr el, PExpr er)
{
// NOTE(4) we are fed a _reference entry expression_, which is (* e)
 return new Expr(INIT_REF,t_void,el->arg1(),er);
}

static PExpr array_init_op(PEntry pe, PExprList pel)
{
	 ExprList::iterator eli = pel->begin();
	 PExpr arr_expr, assign_expr;
	 int mem_unit = (pe->is_stack_relative()) ? sizeof(int) : 1; // stack-relative counts in words...
	 for(int i = 0; eli != pel->end(); ++eli,++i) {
		 PEntry aie = new Entry;  *aie = *pe;	   // construct an Array Item Entry
		 aie->type.decr_pointer();				   // using base type of array
		 aie->size = 1; 						   // (which is not an array!)
		 aie->data += (i*aie->type.size())/mem_unit;
		 assign_expr = initialize_op(aie,*eli,NULL,0);	
		 if (i > 0) arr_expr = append_op(arr_expr,assign_expr,true); // i.e normal COMMA op!
		 else arr_expr = assign_expr;
	 }
	 return arr_expr;
}

static PExpr dot_op(PExpr obj, PEntry pe)
{
  PExpr ef = entry_op(pe);
  return make_op(DOT,ef->type(),obj,ef); 
}


static PExpr struct_init_op(PExpr obj, PClass pc, PExprList pel)
{
	// *add 1.1.1 Explicit initialization of structs.
	// *fix 1.1.2 Handling of array fields & simplification.
   EntryList fields;
   EntryList::iterator ei;
   ExprList::iterator eli;
   PExpr init_expr, assign_expr;
   pc->list_entries(fields,FIELDS | NON_STATIC);
   if (fields.size() != pel->size()) return expr_error("init list wrong size for this struct");
   for(ei = fields.begin(), eli = pel->begin(); ei != fields.end(); ++ei, ++eli) {
      assign_expr = init_op(entry_op(*ei),Parser::array_size(*ei),*eli,NULL,0); 
	  if (assign_expr->is_nil()) return assign_expr;  // couldn't assign to this entry!
	  if (ei != fields.begin()) init_expr = append_op(init_expr,assign_expr,true);
	  else init_expr = assign_expr;
   }
   return make_op(DOT,t_void,obj,init_expr);
}


PExpr init_op(PExpr el, int arr_sz, PExpr er, PExprList pel, int ctype)
{
// initializing an auto object, if necessary calling the constructor
// Only one of er and pel is non-NULL! 
  Type t = el->type();
  bool brace_init = false;
  if (er && er->is_expr_list()) {
       pel = er->expr_list();
	   brace_init = er->is_brace_list();
       er = NULL;
  }
  bool is_ref =  t.is_plain_reference();
  bool is_ref_or_ptr = is_ref && t.is_pointer();
  bool is_array = arr_sz > 1;
  bool is_non_init_array = is_array && pel == NULL;
  // *fix 0.9.4 Now does both initialized and non-initialized arrays of objects.
  if (t.is_class() && !is_ref && (is_non_init_array || !t.is_pointer())) { 
     PClass pc = t.as_class(); 
	 if (brace_init) return struct_init_op(el,pc,pel); // initialized struct!
     if (t.as_class()->has_constructors()) { // an object or an uninitialized array of objects...          
       if (er) pel = expr_list(er);    // object initialized w/ assign syntax
       if (!pel) pel = expr_list();    // i.e, call default constructor!
       PExpr ec = construct_op(pc,pel);
       if (ec->is_nil()) {
	     if (pel->size()==0) return expr_error("no default constructor");
	     return expr_error("cannot find constructor");
	   }
	   // either object (initialized or not), or uninitialized array.
       if (! is_non_init_array) return construct_context_op(ec, el, ctype);
       else  return vector_context_op(ec, el);
     } else
      // *fix 1.2.6 plain simple structs are just initialized with a copy operation
       if (er != NULL) return make_op(COPY_BLOCK,t,el,er);   
       else return NULL;  // no operation..
  } else { // reference or simple initialization
	 if (pel) er = pel->front();      // scalar init. w/ object syntax
	 if (!er) return expr_error("bad init");
	 if (is_ref) return init_ref_op(el,er);       // init. reference
	 else if (is_array) {
// *add 1.1.2 special case 'char p[] = "hello"'
// *fix 1.1.4 pointer test because 'char *a[] = {"one","two"}' was broken
// *add 1.2.0L special case implemented
         if (t.is_char() && t.pointer_depth()==1  && er) { 
		   return function_call("strcpy",expr_list(el,er));	   
         } else
		 return array_init_op(el->entry(),pel); // initialized array of scalars, or objects.
     }   
     else return assign_op(el,er,false);          // simple initialization
 }
}


// *change 1.2.9 When compiling in proper 'program mode', then integer
// constant expressions are directly evaluated.  If we can't fold the constant,
// then the usual defered evaluation is carried out.  We do this to
// support arrays being sized by constants.
PExpr initialize_op(PEntry pe, PExpr er, PExprList pel, int ctype)
{
  Type t = pe->type;
  if (Parser::debug.compile_program && pe->is_direct()
        && ! t.is_pointer() && t.is_int() && t.is_const()) {
      int val;
      bool succeeded = true;
      try {
         val = Parser::const_int_expr(er);
      } catch(string msg) {
       // it wasn't a simple constant expression; pass through 
       // force it to be zero, however, so it will cause a clean error if
       // if used to declare an array.
          val = 0;
          succeeded = false;
      }
      *(int*)(pe->global_ptr()) = val;
      if (succeeded) return NULL;
  } 
  return init_op(entry_op(pe), Parser::array_size(pe),er,pel,ctype);
}

PExpr expr_list_op(PExprList pel, bool is_list)
{ 
   PExpr ex = function_op(NULL,pel);
   if (! is_list) ex->set_type(t_int);
   return ex;
}

void add_to_arg_list(PExpr ec, PExpr arg)
{
  PExprList pel = (PExprList) ec->arg2();  
  pel->push_front(arg);
}

Type base_type(Type t)
{
  t.decr_pointer();
  return t;
}

PExpr new_op(Type t, PExpr e, PExprList pel)
{
// e represents the (opt.)_number_ of objects, pel the (opt.) _arguments_ to the constructor
// *change 1.1.0 we switch to the overallocating version of new when there's a VMT
// unless the operator was overloaded.
// *fix 1.2.4 Make sure that the base type of t is an object, not itself a pointer.
 PClass pc = t.is_class() ? t.as_class() : NULL;
 bool overalloc = Parser::debug.do_overalloc || (pc != NULL ? pc->has_true_VMT() : false);    
 bool is_scalar = e == NULL;
 // *NOTE* Do we do new[] yet?
 bool overload = Function::lookup(is_scalar ? "new" : "new[]") != NULL;
 const char *new_fn;
 if (is_scalar) new_fn =  overload ? "new" :   (overalloc ? "_new_ex" : "_new");
          else  new_fn =  overload ? "new[]" : (overalloc ? "_new_vect_ex" : "_new_vect");
 PExpr er, ez = constant_op(t_int,t.size());
 t.incr_pointer();
 // allocating the memory
 if (is_scalar) er = function_call(new_fn,expr_list(ez));
           else er = function_call(new_fn,expr_list(e,ez));

 // a result of T* needs construction if T::T() exists;  but T** etc doesn't!
 if (pc && t.pointer_depth() == 1 && pc->has_constructors()) {
    if (!pel) pel = expr_list();     
    PExpr ector = construct_op(pc,pel);  
    if (ector->is_nil()) return ector;
	PExpr ec;
	// wrap construction in its object context	
	if (is_scalar) ec = dynamic_context_op(ector);
	          else ec = vector_context_op(ector);
    // NB to skip first word if we're putting a VMT there!
    if (overalloc && overload) er = add_const_op(t,sizeof(void *),er);

    add_to_arg_list(ector,er);
	er = ec;
    //er = append_op(er,ec);	
 } else if (pel && pel->size() == 1){ 
  // *fix 1.1.0 a plain scalar initialization - make sure it's typecast properly!
   er = append_op(er,assign_op(NULL,typecast_op(STATIC_CAST,base_type(t),pel->front())));
 }
 er->set_type(t); // i.e. make it T *
 return er;
}

bool is_object(Type t)
{ return t.is_class() && !t.is_pointer(); }  //*NOTE* Type::is_object 

PExpr assign_op(PExpr e1, PExpr e2, bool constness)
{
 if (!e1) return make_op(ASSIGN,e2->type(),NULL,e2); // see above...only called from there?
 Type t = type_of(e1);
 // *hack 1.2.8 things like 'const char*' fox UC because it can't understand the
 // difference between a pointer which is const, and a pointer to const data.
 if (constness && t.is_const() && ! t.is_pointer())
     return expr_error("Can't assign to a const type");
 // *fix 0.9.6 We didn't check to see if the _RHS_ was an object..
 if (is_object(t) || is_object(e2->type())) {
   if (is_object(t) && t.as_class()->simple_struct()) return make_op(COPY_BLOCK,t,e1,e2);
   else return bin_op(ASSIGN,e1,e2);
 } else {
    e2 = typecast_op(STATIC_CAST,t,e2);
    return make_op(ASSIGN,t,e1,e2);
 }
}

PExpr convert_type_op(Type t, PExpr e, bool try_conversions_from = false); // forward

PExpr cast_to_bool_op(PExpr e1)
{
 Type t = e1->type();
 // it's necessary to strip the reference before is_object() works;
 // I'm sure this is going to cause grief elsewhere!
 t.strip_reference(); 
 PExpr ce; // *fix 0.9.5 We fell over when an object didn't have a conversion....
 if (t.is_object() && (ce = convert_type_op(t_int,e1)) != NULL) return ce;
 else return e1;    
}

PExpr compound_assign_op(int op, PExpr e1, PExpr e2)
{
 if (is_object(e1->type()) || is_object(e2->type()) )
    return bin_op(op,e1,e2);
 else return assign_op(e1,arith_op(assign_equiv_op[op],e1,e2));
}

PEntry add_temporary(Type t, PExpr e, bool always_construct, bool dont_call_dtor)
{
using namespace Parser;
  PEntry pe; 
  state.check_context(0);
  // *fix 0.9.6 Nested temporary contexts require special attention.
  Table *context = &state.context();
  if (context == temp_context()) context = temp_context()->parent_context();
  // *fix 0.9.4 If a temporary is the first object in a nested fn context,
  //  then we need to force this context to be available.
  //temp_context()->reserved_space(t.size());
  temp_context()->set_parent(context);
  state.push_context(temp_context());
  temp_context()->set_no_auto_dtor(dont_call_dtor);  
  pe = state.add_variable(t,"*",e,always_construct ? TEMP : DEFER_TEMP);
  temp_context()->set_no_auto_dtor(false);  
  state.pop_context();
  return pe;
}

// *fix 1.2.8 must guarantee that the temporary is initialized as close
// to the point of use; this expression ensures that ctors for temp objects
// are constructed next to the argument push value.
PExpr construct_temporary_op(Type t, PExpr e, bool dont_call_dtor=false)
{
 //* return entry_op(add_temporary(t,e,true,dont_call_dtor));
  // create a temporary entry, but don't initialize it.
  PExpr ee = entry_op(add_temporary(t,NULL,false,dont_call_dtor));
  PExpr ec = init_op(ee,1,e,NULL,1);
  // this is a comma expression which evaluates the initialization code first;
  // but explicitly use the temporary's type!
  PExpr ea;
  if (ec) ea = append_op(ec,ee,true);
  else ea = ee;
  ea->set_type(ee->type());
  return ea;
}

PExpr force_addr_op(Type tt, PExpr e);  // forward...
 
  // *note* in general this is the _initialization logic_
PExpr return_op(Function *fn, Type rt, PExpr e)
{
   if(rt.is_reference()) return force_addr_op(rt,e);  // force a reference conversion
   else if (rt.is_object()) {
    // basically, force a copy construction!
    PExpr re = entry_op(fn->return_object());
    if (rt.as_class()->has_constructors()) {
       PExpr ctor = construct_op(rt.as_class(),expr_list(e));
       if (ctor->is_nil()) return ctor;
       else return construct_context_op(ctor,re);
    } else return assign_op(re,e,false);
   } else
   return typecast_op(STATIC_CAST,rt,e);
}

// These guys are very similar by the array/pointer equivalence;
// arrays are implemented as a dereference of a pointer addition.
// note again that the result is an implicit reference!
PExpr deref_op(PExpr e1, bool do_overload)
{
 Type t = e1->type();
 if (t.is_pointer()) {
  // try to reduce (* (& x)) to x
    if (e1->op()==ADDR) return e1->arg1();
    t.decr_pointer();
    t.strip_array();    // *fix 0.9.7 damn array flag caused trouble
    t.make_reference();
    return make_op(DEREF,t,e1);
 } else
 if (do_overload) return unary_op(DEREF,e1);
 else return expr_error("Was not a pointer");
}

PExpr array_op(PExpr e1, PExpr e2)
{
 if (e1->type().is_pointer()) {
   return deref_op(make_op(ARRAY,e1->type(),e1,e2));
 } else
 return bin_op(ARRAY,e1,e2);
}

// *fix 0.9.5 Non-reference values can be passed as references via a _reference stub_
// (this copies the value into a temporary static var, and pushes the addr of that)
// *fix 0.9.7 The target type can be of a different size, so we need it explicitly!
PExpr reference_stub_op(Type tt, PExpr e)
{
 tt.strip_qualifiers();
 PExpr temp = entry_op(Parser::state.add_variable(tt,"*",NULL,Static));
 return make_op(REF_STUB,tt,e,temp);
}

PExpr addr_op(PExpr e1, bool do_overload, bool force_reference /* = false */)
{
// tricky one this - not clear how to unambiguously distinguish the ordinary
// old case!
 Type t = e1->type();
 if (t.is_reference() || e1->is_entry()) { // works also for _literal constants_
	 if (e1->op()==DEREF) { // we reduce (& (* x)) to x
       PExpr e = e1->arg1();
// NOTE(4) a reference x is represented by (* x)
// *fix 1.1.2 This typecast is necessary even if we're not an entry!
       if (t.is_reference() /*&& e->is_entry()*/) {
         t.incr_pointer();   // so ensure that we do get a pointer
         e = bcast_op(t,e);  // force a new entry w/ this type
       }  
       return e;
    }
    // *fix 1.2.1 Ensure that function pointer signatures are unique
    if (t.is_function()) t = Type(unique_signature(t.as_signature()));
    t.incr_pointer();
    return make_op(ADDR,t,e1);
 } else 
 if (do_overload) return unary_op(ADDR,e1);
 else return NULL;  /// expr_error("Not an lvalue"); *now caller is responsible*
}

PExpr force_addr_op(Type tt, PExpr e)
{
// This is ONLY called for reference conversions - so tt is always a reference....
 PExpr ex;
 if (e->op()==ADDR || e->type().size() != tt.size()) return reference_stub_op(tt,e);
 ex = addr_op(e,false);
 if (ex==NULL)   // i.e we got a 'Not an lvalue' error message!
    ex = reference_stub_op(tt,e);
 return ex;
}

Type t_const_int; // initialized in init();

PExpr unary_op(int op, PExpr e1)
{
// A special case: -<number>
// *NOTE* 1st Oct 00: let's think about this, because it would be
// a good easier to get numbers in negative right from the start;
// this JUST does integers
 if(op==UMINUS && e1->is_entry() && e1->type()==t_const_int) {
    int *data = (int *)Parser::ExprToPtr(e1);
    *data = - *data;
    return e1;
 } else
 return bin_op(op,e1,NULL);
}

PExpr arith_if_op(PExpr cond, PExpr e1, PExpr e2)
{
 PExpr rest = arith_op(':',e1,e2);
 return make_op(ARITH_IF,rest->type(),cond,rest);
}

PExpr sizeof_op(int type_size)
// *Fix 0.9.2 No longer takes a type argument;  currently
// there's no array size information in Type, so I had
// to ask the entry...
{
 return constant_op(t_int,type_size);
}

string t2s(Type t)
{
 string ts;
 t.as_string(ts);
 return "'" + ts + "'";
}

bool type_has_VMT(Type t)
{ 
 return t.is_class() ? t.as_class()->has_VMT() : false;
}

PExpr typecast_op(int which, Type t, PExpr e)
{
 Type te = type_of(e);
 if (which == DYNAMIC_CAST) { // *add 0.9.5 dynamic cast
   if (! t.is_class() && t != t_void_ptr)  return expr_error("dynamic_cast: must be class or void *");
   if (!type_has_VMT(t) || !type_has_VMT(e->type())) return expr_error("dynamic_cast: class must have virtual methods");
   return make_op(DYNACAST,t,e,NULL);
 } else {
   TypeDistance td = match(t,te);
   if (td == NO_MATCH && (which==STATIC_CAST || which==REINTERPRET_CAST)) {  //*SJD* 23/09/00 TEMP
    // *fix 0.9.8 try user-defined conversions in typecast
	// I'm not sure about the REINTERPRET_CAST; trying to distinguish from STATIC_CAST!
      PExpr et = convert_type_op(t,e,which == REINTERPRET_CAST);
      if (et != NULL) return et;
   }
   return bcast_op(t,e);

⌨️ 快捷键说明

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