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

📄 expressions.cpp

📁 UC Library Extensions UnderC comes with a pocket implementation of the standard C++ libraries, wh
💻 CPP
📖 第 1 页 / 共 3 页
字号:
 }
}

// *fix 1.2.8 It's necessary to look at the 'no args' case specially.
PExpr function_cast_op(Type t, PExprList pel)
{
 if (t.is_class() && !t.is_ref_or_ptr()) { 
     return construct_temporary_op(t,pel->size() > 0 ? function_op(NULL,pel) : NULL);   
 } else {
  if (pel->size() != 1) return expr_error("typecast needs one argument");
  return typecast_op(STATIC_CAST,t,pel->front());
 }
}

PExpr must_be_lvalue(int op)
{ return expr_error(Operators::name_from_id(op) + ": must be lvalue"); }

PExpr inc_dec_op(int op, PExpr e, bool is_postfix)
{
 Type t = e->type();
 // C++ convention for indicating whether ++ is post or prefix: a dummy parm!
 // (cd easily be constant, but what the hell...
 PExpr extra = is_postfix ? constant_op(t_int,0) : NULL;
 if (t.is_reference()) { // NOTE(3) hack!!
   // *hack 1.2.9a  'const T*' is a pointer to const _data_ (working around UC const limitation)
   if (t.is_const() && ! t.is_pointer()) return must_be_lvalue(op);
   else if (t.is_pointer()) { //*a special case*
    return make_op(op==INCR ? INCR_PTR : DECR_PTR,t,e,extra);
   } else if (t.is_int()){
     // plain ++/-- acting on variables 
     if (e->is_variable()) return make_op(op,t,e,extra); 
     // in the general case, we take the address of the argument & use it
     else {
       PExpr re = addr_op(e,false); 
       if (re == NULL) return must_be_lvalue(op);
       return make_op(op,t,re,extra);      
     }
   } else if (t.is_float()) return not_for_float(op);  //*NOTE* this isn't true!
     //else return expr_error("Que?");
 } 
 //else
  if (t.is_class()) return bin_op(op,e,extra);
 else return must_be_lvalue(op);
}


PExpr equal_op(PExpr e1, PExpr e2)
{
 return relational_op(EQUAL,e1,e2);
}

PExpr relational_op(int op, PExpr e1, PExpr e2)
{
 PExpr e;
 if (e2) e = arith_op(op,e1,e2);
 else e = unary_op(op,e1);
 // *fix 1.1.0 builtin relational ops return bool (but can be arbitrarily overloaded)
 if (e->op() == op) e->set_type(t_bool);
 return e;
}

PEntry ExprToEntry(PExpr e)
{
 return  e->entry();
}

PExpr convert_function_ptr(PFunction pf, PExpr e)
// pf is the function we're passing this fn ptr!
// *add 1.1.4: functions passed to builtin routines can be true function pointers!
{
  if (pf->builtin()) { // we must pass a native routine to such beasts!
    void *pfn;
    if (e->op()==ADDR || e->op()==BCAST) e = e->arg1();
    if (e->is_entry() && e->type().is_function()) {
      PEntry pe = e->entry();
      PFunction fun_ptr = PFunctionEntry(pe->data)->back();
      if (fun_ptr->builtin()) { // extract the addr of wrapped native routine!
        pfn = fun_ptr->fun_block()->native_addr();      
      } else { // build native code stub for this function!
        pfn = Builtin::generate_native_stub(fun_ptr);
      }
      return constant_op(t_void_ptr,(long)pfn);
    } else { 
     // a function ptr expression requires dynamic stub generation
		return function_call("_native_stub",expr_list(e));
    }
  } else return e;
}

void generate_type_list(PExprList args, TypeList& tl)
{
 ExprList::iterator eli;
 for (eli = args->begin(); eli != args->end(); ++eli)
      tl.push_back((*eli)->type());
}

PExpr convert_type_op(Type t, PExpr e, bool try_conversions_from)
{
// *fix 1.1.3 will also try to use ctors to construct a type!
    Function *pf;
  // first try user-defined conversions, if the expression is an object
  // *fix 1.2.2 This was kicking in for pointers to objects as well!
    Type et = e->type();
    if (et.is_class() && ! et.is_pointer()) {	
       pf = et.as_class()->get_conversion_to(t);
       if (pf != NULL) return method_call(pf,e,NULL); 
	} 
	// optionally try to convert the expression using a ctor
	if (try_conversions_from && t.is_class()) {
	    pf = t.as_class()->get_conversion_from(et);
		if (pf != NULL) return construct_temporary_op(t,e);
    } 
	return NULL;  // no conversions possible
}

int min(int a, int b) { return a > b ? b : a; }


bool was_plain(int match)
{ 
 return match == EXACT_MATCH || match == TRIVIAL_MATCH || match == PROMOTE_MATCH || match == STD_MATCH;
}

PExpr this_ref()
{
  PEntry pe = new Entry();
  pe->data = THIS_OFFSET;
  return entry_op(pe);
}

PExpr pass_by_value(Type t,PExpr e)
{
   PExpr ec = construct_op(t.as_class(),expr_list(e)); 
   return make_op(PASS_BY_VALUE,t,ec);
}

PExpr function_op(PExpr e, PExprList args, bool suppress_error)
{
 PExpr er;
 FunctionMatch fm;
 PFunction fn;
 // An empty function expression allows expr lists to be expressions
 if (!e) return new Expr(FUNCTION,t_void,NULL,args);
 if(e->op() == NIL) return e;      // error in function expression
 if (!args) args = new ExprList;  /// empty arg list

 
 //Extract the actual function expression (may be a method call!)
 bool was_method = e->op() == DOT;
 PExpr epf = was_method ? e->arg2() : e;

 // If the expression isn't a function, then operator() may be overloaded...
 if (!was_method && !e->type().is_signature()) {
   Type t = e->type();
   if (t.is_class() && !t.is_pointer()) {
      PEntry fpe = e->type().as_class()->lookup("()");
      if (fpe != NULL) return method_op(fpe,e,args);     
   } 
   return expr_error("Not a function");
 }

 // if the function expr is NOT an entry, it's assumed to evaluate to a function!
 bool was_fn_ptr = epf->type().is_pointer() || !epf->is_entry();
 
 PFunctionEntry pfe;
 if (was_fn_ptr) {
 // to match pointers to functions we make up a fake entry!
     PEntry pef = new Entry;
     pef->name = "";
     pfe = new FunctionEntry(pef); 
     pfe->push_back(new Function(epf->type().as_signature(),pfe));
 } else {
     pfe = PFunctionEntry(epf->entry()->data);
 }

 // extract the signature from the list of actual arguments
 Signature *sig = new Signature();
 ExprList::iterator eli;
 ImportScheme *import;
 for (eli = args->begin(); eli != args->end(); ++eli)
      sig->push_back((*eli)->type());

 if (fm.function_match(*pfe,*sig)) { 
    PExprList pdef;
    fn = fm.matched_function();
    // *add 0.9.5 Enforce const method rule *HACK exclude operator[]
//* if (was_method && !fn->is_const() && e->arg1()->type().is_const()
//*    && fn->name() != "[]") 
//*    return expr_error("cannot call a non-const method with a const object");
    //*NOTE* Be careful - shd be fn->is_complete() or something - I will
    // want to optimize this!!
    if (fn == NULL) 
        return expr_error("fn==NULL");

  // add any default arguments....
    pdef = fn->complete_arg_list(args);

// *add 1.1.0 support for pre-constructing objects when passed by value
	import = fn->import_scheme();
	
    MatchList::iterator mli = fm.matches(pdef);
    int i = 0, n_sig = min(fn->signature()->size(),args->size());  // i.e. not for default args..
    for (eli = args->begin(); i < n_sig; ++eli,++mli,++i) { 
       int match = mli->match();
       Type t = mli->type();
       Type et = (*eli)->type();

	   if (import != NULL && t.is_object()) {
	       if(import->true_pass_by_value(t)) {
		      *eli = pass_by_value(t,*eli);
			  continue;
	       } else if(was_plain(match))
		 // *fix 1.2.0 Final 'true' here means that callee is responsible for disposing of object!
		 *eli = construct_temporary_op(t,*eli,true);
       }

       switch(match) { 
        case PROMOTE_MATCH:
        case STD_MATCH:
          *eli = bcast_op(t,*eli);
          break;
        case REFERENCE_MATCH:
        case REF_STD_MATCH:
        case REF_PROMOTE_MATCH:
          if (et.is_variable()) et.strip_qualifiers();  // *hack 0.9.7 trouble w/ is_object()!
          if (! et.is_object())  // objects are always passed by reference anyhow
            *eli = force_addr_op(t,*eli);  // if necesary, force a reference conversion
          break;
        case CONVERT_TO_MATCH:
          *eli = convert_type_op(t,*eli);
          break;
        case CONVERT_FROM_MATCH:
		  t.strip_qualifiers();
          *eli = construct_temporary_op(t,*eli);
          break;
        case FUN_PTR_MATCH:
          *eli = convert_function_ptr(fn,*eli);
          break;
       }
    }
 } 
 else {
 // *add 1.2.3 Suppressed errors (like when we are looking at operators) are saved for later...
    set_function_error(pfe,fm.error());
    if (suppress_error) return NULL;
    else return function_error();
 }

 Type rt = fn->return_type();
 bool returns_object = rt.is_object();
 bool true_value_return = import != NULL && returns_object && import->true_return_by_value(rt); 
 if (returns_object && ! true_value_return) fn_return_object(rt,args);
 
 // *fix 0.9.6 The DCALL function type _forces_ a function to be directly called, virtual or not
 bool plain_fun = true;
 if (gScopeContext != NULL) {
    plain_fun = false;
    gScopeContext = NULL;
 }

 if (was_method) args->push_back(e->arg1());  // append obj ptr to arg list
 if (!was_fn_ptr) { // plain function or method
   er = new Expr(was_method ? METHOD_CALL : (plain_fun ? FUNCTION : DCALL),rt,fn,args);
 } else {          // pointer to function or method
   er = new Expr(was_method ? EXPR_METHOD : EXPR,rt,epf,args);
 }
 // Dereference any returned reference type! (can't use deref_op()!)
 if (rt.is_reference()) er = make_op(DEREF,rt,er);
 if(was_fn_ptr) { // was temporary!
    delete pfe;  
    delete fn;
 } 

 // finally, if it was a class template method then instantiate it (if not already)
 if (!was_fn_ptr && pfe->get_template() && pfe->get_template()->is_method()) 
   if (!pfe->get_template()->instantiate_method(fn)) return expr_error("instantiation failed");
           
 if (returns_object && true_value_return) return fn_return_object_as_value(rt,er);
 else return er;
}

PExpr expr_not_found_error(char *name, PClass pc)
{
 using Parser::quotes;
 return expr_error(quotes(name) + " is not a member of " + quotes(pc->name()));
}

PExpr selection_op(PExpr e, char *name,bool is_ptr,bool is_member_ptr)
{
 Type t = e->type();
 bool was_pointer = t.is_pointer();

 if (!t.is_class()) return expr_error("Not a class object or pointer");
 PClass pc = t.as_class();
 PEntry pe;
 bool not_found;
 if (!is_member_ptr) {
    pe = pc->lookup(name);                 // in the context of the first operand...
    not_found = !pe || !pc->inherits_from((Class *)pe->context);  // and not any enclosing scope...
 } else {
    pe = Parser::symbol_lookup(name);
    not_found = !pe;
 } 

 if (is_ptr && !was_pointer) { // -> may be overloaded...
    PExpr efn = unary_op(ARROW,e);
    if (efn->op() != ARROW) { // was overloaded!
      Type rtype = efn->type();   
      if (!rtype.is_class()) return expr_error("operator-> should return a class");
      return selection_op(efn,name,true);
    }
  }
  // otherwise, it's just a plain selection member operator
  if (not_found) return expr_not_found_error(name,pc);
  if (!was_pointer && is_ptr) return expr_error("Must be a pointer"); else
  if (was_pointer && !is_ptr) return expr_error("Cannot be an object pointer");
  if (was_pointer) e = deref_op(e,false);
  // crucial to use the _expression's_ type, since this will preserve
  // reference information!
  PExpr em = entry_op(pe);
  return make_op(DOT,em->type(),e,em); 
}
//----------------------------------------------------------
PExpr entry_op(PEntry pe)
{
// NOTE(3) identifiers are given an 'variable reference' type
//  (Note: this replaces a scheme where it was actually a reference type! (Algol 68
//   understood this kinda thing better).  We now have an extra type flag to indicate
//   that variable references are Different)
// NOTE(4) a reference x is represented by (* x)
// arrays are _not_variables!
  Type t = pe->type;
  if (!t.is_reference()) {
    if (pe->name != "" && Parser::array_size(pe) == 1)  t.make_variable();
    return new Expr(IREF,t,pe);
  } else
  return make_op(DEREF,t,new Expr(IREF,t,pe));
}

PExpr constant_op(Type t, unsigned long val)
{
 PEntry pe;
 //using Parser::create_const_entry;
 unsigned long *pi = (unsigned long *)Parser::create_const_entry(t,pe);
 *pi = val;
 return entry_op(pe);
}

// *add 1.2.3 Experimental implementation of __lambda
PExpr lambda_op(PEntry)
{
    PEntry pe = Parser::symbol_lookup("_");
 FunctionEntry* pfe = (FunctionEntry*)pe->data;
 // *NOTE* shd dispose of '_'!!
 Function* fn = pfe->back();
 return entry_op(pe);
}

PExpr make_op(int op,Type type, PExpr e1, PExpr e2/* = NULL */)
{
 return new Expr(op,type,e1,e2);
}

PExpr clone (PExpr e)
// make a deep copy of an expression!
{ 
  if (!e) return NULL;
  int op = e->op(); 
  Type t = e->type();
  PExpr er;
  if (e->is_function() || e->is_expr()) {
    PExprList pel = e->arg_list();
    PExprList pelc = new ExprList(*pel);
    er = new Expr(op,t,
               e->is_function() ? (PExpr)e->function() : clone(e->arg1()),
               pelc);
  } else
  if (e->is_entry()) {
    er = new Expr(op,t,e->entry());
  }
  // for all other operators, can treat the arguments as expressions
  else er = new Expr(op,t,clone(e->arg1()),clone(e->arg2()));
  return er;
}

void dump(ostream& os, PExpr e)
{
 if (!e) return;
 if (e->is_function() || e->is_expr()) {
   os << " (";
   if (e->is_expr()) dump(os,e->arg1());
                else os << '(' << e->type() << ')' << e->function()->name();
   ExprList::iterator eli;
   PExprList pel = e->arg_list();
   if (pel)
    for(eli = pel->begin();  eli != pel->end(); ++eli)
      dump(os,*eli);
   os << ')';
 } else 
 if (e->is_nil()) os << "<nil>"; 
 else
 if (! e->is_entry()) { // i.e. a binary or unary op!
     os << " (";
     if (! e->is_bcast()) os << e->name();
                     else os << '(' << e->type() << ')';
     dump(os,e->arg1());
     dump(os,e->arg2());
     os << ')';
 } else os << ' ' << e->name();
}

void init()
{
 int equiv[] = {MUL_A,STAR,DIV_A,DIVIDE,MOD_A,MODULO,ADD_A,PLUS,MINUS_A,MINUS,
               SHL_A,LSHIFT,SHR_A,RSHIFT,BAND_A,BIN_AND,BOR_A,BIN_OR,XOR_A,BIN_XOR};

 int takes_float[] = {PLUS,MINUS,UPLUS,UMINUS,STAR,DIVIDE,EQUAL,LESS_THAN,
                       NOT_EQUAL,GREATER,LEQ,GEQ,ASSIGN,COMMA,':'}; 
 // *fix 0.9.3 arith. if refused floating-point arguments - added ':' above.
 int i;

 for(i = 0; i < sizeof(equiv)/(2*sizeof(int)); i++)
   assign_equiv_op[equiv[2*i]] = equiv[2*i+1];

 for(i = 0; i < sizeof(takes_float)/sizeof(int); i++)
   float_op[takes_float[i]] = 1;

 t_const_int = t_int;
 t_const_int.make_const();

}

} // namespace Expressions


⌨️ 快捷键说明

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