📄 types.cpp
字号:
string enum_as_str(Enum *em)
{
string s = em->name();
// the issue here is that in C mode 'enum Fred' actually generates
// a slightly mangled name $_Fred.
if (s[0]=='$' && s[1] == '_') s = s.substr(2,s.length()-2);
NamedTable* parent = nested_context(em->entry());
if (parent) s = parent->name() + "::" + s;
return s;
}
bool lookup_typedef_name(Type t, string& s)
{
static TypeSearch type_search;
type_search.set_type(t);
PEntry pe = Parser::global().search_entries(&type_search,NULL,TYPEDEFS);
if (pe != NULL) {
type_search.result().as_string(s);
return true;
} else return false;
}
string class_as_str(Class *pc)
{
string s;
NamedTable* parent = nested_context(pc->entry());
if (parent) s = parent->name() + "::";
s += pc->name();
return s;
}
void Type::as_string(string& s) const
{
if (Parser::debug.use_typedef_names && lookup_typedef_name(*this,s)) return;
s = "";
if (is_enum()) { s = enum_as_str(as_enum()); return; }
if (is_const()) s += "const ";
if (is_unsigned()) s += "unsigned ";
if (is_long() && is_int()) s += "long ";
if (is_char()) s += "char"; else
if (is_short()) s += "short"; else
if (is_double()) s += "double"; else
if (is_float()) s += "float"; else
if (is_void()) s += "void"; else
if (is_int()) s += "int"; else
if (is_bool()) s += "bool"; else
if (is_class()) s += class_as_str(as_class());
else
if (is_signature()) {
char buff[256];
ostrstream out(buff,256);
if (is_pointer()) Signature::set_fun_name("(*)");
out << *as_signature();
if (is_pointer()) Signature::set_fun_name("");
out << ends;
s = buff;
return;
} else
if (is_dummy()) s += as_dummy()->value_as_string();
if (is_pointer()) {
for(int i = 0; i < pointer_depth(); i++) s += "*";
}
#ifdef _DEBUG
if (is_variable()) s += "!"; else
#endif
if (is_reference() && !is_variable()) s += "&";
}
ostream& operator << (ostream& os, Type t)
{
string stemp="";
t.as_string(stemp);
os << stemp;
return os;
}
// in these match functions, the first arg represents the formal
// parameter, and the second the actual argument.
// Must remove the zero bit, in case we had a variable! (see note(3), Expressions::entry_op)
inline Type make_const(Type t)
{ Type tc = t; tc.make_const(); tc.make_zero_int(); return tc; }
inline Type strip_qualifiers(Type t)
{ Type tc = t; tc.strip_qualifiers(); return tc; }
inline Type make_const_ref(Type t)
{ Type tc = t; tc.make_const_reference(); tc.make_zero_int(); return tc; }
inline Type make_ref(Type t)
{ Type tc = t; tc.make_reference(); tc.make_zero_int(); return tc; }
TypeDistance
trivial_match(Type t1, Type t2)
//-----------------------------
{
// trivial match between t2 (actual) and t1 (formal) argument.
if (t1.is_reference()) {
if (t1.is_variable() && strip_qualifiers(t1) == strip_qualifiers(t2))
return TRIVIAL_MATCH; //const T& => T! (variable type) is fine...
t2.make_zero_int(); // clear VARIABLE type
t1.make_zero_int();
// these are really exact or trivial matches but we need to know for arg passing
if (t1 == t2) return REFERENCE_MATCH;
if (t1.is_const()) {
// a non-const reference converts trivially to its const equivalent;
if(t1 == make_const(t2)) return REFERENCE_MATCH; //T& => const T&
// T => const T& -- always cool because our constants have addresses
// *fix 1.2.1 Must however exclude const T => T&!
Type t2r = t2;
t2r.make_reference();
if (t2.is_const()) {
if (t1 == t2r) return REFERENCE_MATCH; // const T => const T&
} else { // exclude const T => T& !
t2r.make_const();
if (t1 == t2r) return REFERENCE_MATCH; // T => const T&
}
}
}
t2.make_zero_int();
t1.make_zero_int();
if (!t1.is_ref_or_ptr()) t2.strip_const();
if (t1 == t2) return EXACT_MATCH;
// T * => const T *; T[] => T*, T* => T[]
if (t1.is_pointer()) {
if (t1.is_const()) t1.strip_const();
if (t1.is_array()) t1.strip_array();
if (t2.is_array()) t2.strip_array();
if (t2 == t1) return TRIVIAL_MATCH;
}
//T => T&,const T&
// *fix 1.2.1 Must however exclude const T => T&!
// if (!t2.is_ref_or_ptr()) t2.strip_const();
if (t2.is_reference() && strip_qualifiers(t2) == t1) return TRIVIAL_MATCH;
//if (t1.is_reference() && strip_qualifiers(t1) == t2) return TRIVIAL_MATCH;
return NO_MATCH;
}
TypeDistance
promote_match(Type t1, Type t2)
{
// promotions between t2 (actual) and t1 (formal) argument.
// *fix 0.9.7 Allow for t2 => const t1&, if we can promote t2 to t1.
bool is_ref = t1.is_reference() & t1.is_const();
if (is_ref) t1.strip_qualifiers();
Type pt = t2.promote();
if (pt == t1) return is_ref ? REF_PROMOTE_MATCH : PROMOTE_MATCH;
return NO_MATCH;
}
TypeDistance
std_match(Type t1, Type t2)
{
// standard conversions between t2 (actual) and t1 (formal) argument.
//cout << "std: f= " << t1 << " a= " << t2 << endl;
bool ref_argument = t1.is_plain_reference();
// *add 1.1.4 C is less fussy about integer conversions to enumerations...
if (Parser::debug.c_mode && t1.is_enum() && t2.is_int()) return STD_MATCH;
if (t1.is_number() && !ref_argument) {
// in strict mode, there are no implicit bool conversions...
// *change 1.2.3 Retired until we can think this through.....
// if (t2==t_bool && Parser::debug.strict) return NO_MATCH;
if (t2.is_number() || t2.is_enum()) return STD_MATCH;
if (t2.is_zero()) return STD_MATCH;
} else
if (t2.is_pointer()) {
if (t1.is_void() && t1.pointer_depth()==1)
return ref_argument ? REF_STD_MATCH : STD_MATCH;
if (!t1.is_pointer()) return NO_MATCH;
}
if (t1 == t_bool && t2.is_int()) {
return STD_MATCH;
}
if (t1.is_pointer()) {
if(t2.is_zero()) return STD_MATCH;
if(t1.is_signature() && t2.is_signature() /*&& t1.as_signature()==t2.as_signature()*/)
return FUN_PTR_MATCH; //*note* t2 is not a ptr in 'pf = sin' etc!
if(!t2.is_pointer()) return NO_MATCH;
}
// *fix 0.9.5 Standard reference matches score lower than ordinary reference matches
if (t2.inherits_from(t1)) return (ref_argument && ! t2.is_plain_reference()) ?
REF_STD_MATCH : STD_MATCH;
return NO_MATCH; // for now
}
TypeDistance
match(Type t1,Type t2)
{
TypeDistance td = trivial_match(t1,t2);
if (td != NO_MATCH) return td;
td = promote_match(t1,t2);
if (td != NO_MATCH) return td;
td = std_match(t1,t2);
if (td != NO_MATCH) return td;
// for now
return NO_MATCH;
}
Type Type::promote() const
{
// from Lippman (2nd, 174)
if (is_pointer() || is_reference() && ! is_variable()) return *this; //* doesn't apply!!
if (is_char() || is_short()) return t_int;
if (is_short() && is_unsigned()) return t_int; // sizeof(int) > sizeof(short)
if (is_float()) return t_double;
if (is_bool()) return t_int;
return *this;
}
typedef unsigned long unsigned_t;
string Type::value_as_string(void *ptr, bool do_quotes) const
{
// *add 1.1.2 Putting quotes around strings is now optional.
static char buff[512];
memset(buff,0,512);
ostrstream out(buff,512);
if (is_pointer()) {
//*fix 1.2.6 Was attempting to dump char** etc as character constants
if (is_char() && pointer_depth() == 1){
char *cp = *(char **)ptr;
if (cp) {
if (do_quotes) out << '"';
out << cp;
if (do_quotes) out << '"';
} else out << "NULL";
} else
out << (void *)*(int **)ptr;
} else
if (is_enum()) { // *add 1.2.6 show enumeration constants, if possible
int val = *(int *)ptr;
string name = as_enum()->lookup_value(val);
out << val << ' ' << name;
} else
if (is_bool()) out << (*(int *)ptr ? "true" : "false"); else
if (is_int()) {
bool unsign = is_unsigned();
if(is_char()) {
out << '\'' << *(char *)ptr << '\'';
if (unsign) out << " (" << (unsigned_t)*(unsigned char *)ptr << ')';
} else if(is_short()) {
if (unsign) out << (unsigned_t)*(unsigned short *)ptr;
else out << *(short *)ptr;
} else {
if (unsign) out << (unsigned_t)*(unsigned int *)ptr;
else out << *(int *)ptr;
}
} else
if (is_double()) out << *(double *)ptr; else
if (is_float()) out << *(float *)ptr; else
if (is_class()) {
PClass pc = as_class();
// HACK02 -- strings outputed directly - assume first member field is char *
if (pc->name()=="string") {
if (do_quotes) out << '\'';
out << **(char ***)ptr;
if (do_quotes) out << '\'';
} else out << pc->name() << " {}";
}
out << ends;
return buff;
}
ostream& operator << (ostream& os, TypeDistance td)
{
char *txt;
switch(td) {
#define CASE(x) case x: txt = #x; break;
CASE(EXACT_MATCH)
CASE(REFERENCE_MATCH)
CASE(TRIVIAL_MATCH)
CASE(PROMOTE_MATCH)
CASE(STD_MATCH)
CASE(CONVERT_FROM_MATCH)
CASE(CONVERT_TO_MATCH)
CASE(FUN_PTR_MATCH)
CASE(NO_MATCH)
#undef CASE
}
os << txt;
return os;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -