📄 types.cpp
字号:
/* TYPES.CPP
* The UC type system interface
* UnderC C++ interpreter
* Steve Donovan, 2001
* This is GPL'd software, and the usual disclaimers apply.
* See LICENCE
*/
#include "types.h"
#include "common.h"
#include "templates.h"
ostream& operator << (ostream&, string);
istream& operator >> (istream&, string&);
const Type
t_bool(TT_BOOL), t_null(TT_NULL,0), t_template_type((Class *)-1),
t_void, t_char(TT_CHAR), t_uchar(TT_CHAR,TT_UNSIGNED), t_int(TT_INT), t_uint(TT_INT,TT_UNSIGNED),
t_short(TT_SHORT), t_ushort(TT_SHORT,TT_UNSIGNED), t_long(TT_INT,TT_LONG),
t_ulong(TT_INT,TT_LONG | TT_UNSIGNED),
t_float(TT_FLOAT), t_double(TT_FLOAT,TT_LONG),
t_void_ptr(TT_VOID,TT_PTR), t_char_ptr(TT_CHAR,TT_PTR),
t_zero(TT_ZERO),t_label(TT_NULL,1);
namespace { // local to this module
std::vector<Class *> _classes_;
std::vector<Signature *> _signatures_;
std::vector<Enum *> _enums_;
}
template <class T>
int index_into(std::vector<T>& v, T val)
{
for(int i = 0; i < v.size(); i++)
if (v[i] == val) return i;
// otherwise it ain't here - add to vector!
v.push_back(val);
return v.size()-1;
}
// *fix 0.9.4 Looks through the signature list for matches...
// *fix 1.1.0 Insist that they are completely equal, down to the return type
// Should this not be part of what it means for signatures to match?
Signature *unique_signature(Signature *sig)
{
std::vector<Signature *>::iterator is = _signatures_.begin(),
ie = _signatures_.end();
for(; is != ie; ++is) {
Signature *s = *is;
// *change 1.2.3a Signature::match() is here called in "exact match" mode!
if (s->return_type()==sig->return_type() && s->match(*sig,true)) return *is;
}
return sig;
}
Signature *find_signature(void *type_data)
{
Signature *orig = (Signature *)type_data;
Signature *uniq = unique_signature(orig);
return uniq ? uniq : orig;
}
Type::Type(TypeEnum t, int extra)
{
*((long *)this) = 0; //*SJD* Nasty but effective!
if(t == TT_NULL) {
m_extra = extra;
return;
}
// hmm...are bools considered a kind of integer?
if (t != TT_VOID && t != TT_FLOAT && t != TT_BOOL) m_int = 1;
else m_int = 0;
if (t==TT_CHAR) m_char = 1; else
if (t==TT_SHORT) m_short = 1; else
if (t==TT_VOID) m_char = 1; else // a fiddle....
if (t==TT_FLOAT) m_float = 1; else
if (t==TT_ZERO) { m_zero = 1; m_const = 1; } else
if (t==TT_BOOL) {
m_bool = 1;
}
if (extra & TT_LONG) m_long = 1;
if (extra & TT_UNSIGNED) m_unsigned = 1;
if (extra & TT_PTR) m_ptr = 1;
m_extra = 0;
}
void Type::complex_init(TypeEnum t, void *type_data)
{
*((long *)this) = 0; //*SJD* Nasty but effective!
if (t == TT_CLASS || t == TT_NAMESPACE) {
m_class = 1; m_extra = index_into(_classes_,(Class *)type_data);
// this might seem like asking for trouble, but namespace entries
// are always TYPENAMEs not IDENs. So the chances of confusion are slim.
if (t == TT_NAMESPACE) m_zero = 1;
} else
if (t == TT_SIGNATURE) {
// *change 1.2.2 (Eric) Always try to keep signatures unique
m_signature = 1; m_extra = index_into(_signatures_,find_signature(type_data));
} else
if (t == TT_ENUM || t == TT_DUMMY) {
if (t == TT_DUMMY) m_short = 1;
m_enum = 1;
// for dummies , _identical names_ means equality!
// (can get away with this because both types derive from NamedType)
Enum *ndata = (Enum *)type_data;
int sz = _enums_.size();
if (ndata->name() != "" || t != TT_DUMMY) {
for(int i = 0; i < sz; i++)
if (_enums_[i]==ndata
/*|| t == TT_DUMMY && _enums_[i]->name() == ndata->name()*/)
{ m_extra = i; return; }
} else {
//*change 1.2.9 To support numerical template parameters properly,
// we have to keep dummies with the same value identical; this
// code will only work with integer types (you're on your own
// with other types)
DummyType* dt = (DummyType*)type_data;
int val = Parser::const_int_expr(dt->entry());
for(int i = 0; i < sz; i++) {
if (_enums_[i]->name() == "") {
DummyType* de = (DummyType*)_enums_[i];
if (val == Parser::const_int_expr(de->entry())) {
m_extra = i; return;
}
}
}
}
// otherwise, add to the end!!
m_extra = _enums_.size();
_enums_.push_back(ndata);
}
}
bool Type::operator == (Type t) const
{
// a complete kludge!
// again, a basic assumption that the Type object fits snugly into a 32-bit word.
return *((long *)this) == *((long *)&t);
}
bool Type::is_null() const
{ return *((long *)this) == 0; }
bool Type::is_bare() const
{
return !is_const() && !is_pointer() && !is_reference();
}
bool Type::is_unbound() const
{
if (is_null()) return false; // null!
if (!is_dummy()) return true; // everything else has a definite type value
return as_dummy()->unbound();
}
bool Type::is_template_class() const
{
return is_class() && as_class()->get_template() != NULL;
}
Type Type::make_dummy(const string& name, Type t, PEntry pe)
{
Type rt;
DummyType *pdum = new DummyType(name,t,pe);
rt.complex_init(TT_DUMMY,pdum);
return rt;
}
bool Type::is_dummy() const
{
if (m_enum && m_short) return true; // plain dummy
if (is_template_class()) { // otherwise it may have at least one dummy parameter!
Class *pc = as_class();
const TypeList& tl = pc->get_template()->type_parms();
TypeList::const_iterator tli;
int kount = 0;
FORALL(tli,tl)
if (tli->is_dummy()) kount++;
return kount > 0;
}
return false;
}
Signature *Type::as_signature() const
{
if (m_signature) return _signatures_[m_extra]; else return NULL;
}
Class *Type::as_class() const
{
if (m_class) return _classes_[m_extra]; else return NULL;
}
Enum *Type::as_enum() const
{
return _enums_[m_extra];
}
//----- depth of derivation; 0 for no relation (delegated to class object)
int Type::inherits_from(Type t) const
{
if (is_class() && t.is_class()) return as_class()->inherits_from(t.as_class());
else return 0;
}
int Type::size() const // implements sizeof()
{
if (is_pointer()) return sizeof(void *);
else
if (is_enum()) return sizeof(int); else; // for now....
if (is_int()) {
if (is_short()) return sizeof(short); else
if (is_long()) return sizeof(long); else
if (is_char()) return sizeof(char);
else return sizeof(int);
} else
if (is_float()) {
if (is_double()) return sizeof(double); else return sizeof(float);
} else
if (is_class()) return as_class()->size();
// *fix 1.2.3 Our bools now have standard size (8-bits)
else if (is_bool()) return sizeof(bool);
else return sizeof(int);
}
class TypeSearch: public TableSearcher {
private:
Class* m_class;
Type m_type;
Type m_dummy;
Type m_result;
public:
TypeSearch() {
m_dummy = Type::make_dummy("_*_",t_void,NULL);
}
void set_type(Type t) {
m_type = t;
m_class = t.as_class();
}
Type result() { return m_result; }
virtual bool match(PEntry pe)
{
Type tt = pe->type;
if (tt.is_class() && tt.as_class() == m_class) {
Type ta = m_type, td = m_dummy;
if (ta.is_const() && ! tt.is_const()) {
ta.strip_const();
td.make_const();
}
while (ta.is_pointer() && ! tt.is_pointer()) {
ta.decr_pointer();
td.incr_pointer();
}
if (ta.is_reference() && ! tt.is_reference()) {
ta.strip_reference();
td.make_reference();
}
if (ta == tt) {
td.as_dummy()->set_name(pe->name);
m_result = td;
return true;
}
}
return false;
}
};
// *fix 1.2.7 We dump out the fully qualified names of classes and enums,
// which was necessary for delayed compilation of method bodies.
// *add 1.2.7 debug.use_typedef_names not only forces a global search for
// a typedef for a particular type, but leaves off 'std::' when std has
// been injected. Not likely to be a popular feature with the ISO committee.
NamedTable* nested_context(PEntry pe)
{
int type = pe->context->type();
if (type == IS_NAMESPACE || type == IS_STRUCT) {
if (Parser::debug.use_typedef_names && pe->context == Parser::std_namespace()
&& Parser::global().is_injected((Namespace*)pe->context)) return NULL;
else return (NamedTable*) pe->context;
}
else return NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -