📄 common.cpp.svn-base
字号:
PEntry pe;
bool is_class_context;
Table* alloc_context;
static int offset=0, bit_offs=0, field_size;
if (name=="") return NULL;
if (name=="obuff") //*DEBUG*
name = "obuff";
try {
PopAtEnd restore_cntxt;
int size;
// *add 1.2.3 Support for 'static' applied within file scope
// The trick here is to explicitly load this module's anonymous namespace
bool is_static = mode == ENUM_INIT;
if (mode == Static) {
is_static = true;
if (is_global(&context())) {
add_namespace("");
restore_cntxt.set();
}
}
if (name=="*") name = make_temp_name(); // assign a temporary name...
if (t == t_null && ! in_typedef) { // *add 1.1.1 support for __declare
if (init == NULL) fail("must initialize a __declare variable");
t = init->type();
t.strip_const(); // i.e. we want the base type
t.make_zero_int(); // *fix 1.1.2 the zero bit must go!
if (t.is_function()) t.incr_pointer(); // *fix 1.2.0 (Eric) otherwise we crash
}
// _cannot_ use a namespace name as if it were a plain type!
if (t.is_namespace()) fail("Namespace not allowed here");
// is our context ready?
check_context(mode);
PClass pc = t.is_class() ? t.as_class() : NULL;
//issue here is that pc->make_available() _usually_ fails because a template class
//instantiation failed, setting the error(). We need a way around this...
if (pc != NULL && /*! in_typedef &&*/ ! pc->make_available()) return NULL; //fail("Class not fully defined");
// *fix 1.1.2 Watch out for bad array init here, except for char arrays
// *fix 1.2.0 Deduce the size of the array in declarations like 'char p[] = "hello"'
if (t.is_pointer() && s_array_size != 1) { // a fiddle: means we have an array!
bool is_elist = init && init->is_expr_list();
if (init && ! is_elist) {
if (! t.is_char() || init->type() != t_char_ptr || ! init->is_entry())
error("bad array initializer");
else if (s_array_size==0) {
s_array_size = strlen((char *)init->entry()->global_ptr())+1;
}
} else
if (s_array_size == 0) { // hm, may be asking us to guess the array size!
if (init && is_elist) s_array_size = init->expr_list()->size();
else fail("arrays of size zero not allowed"); // *add 1.2.9
}
}
size = s_array_size*s_twodim_array; // will be > 1 for arrays!
// Has this variable already been added?
pe = context().lookup(name);
bool already_declared = pe != NULL;
if (already_declared) {
if (context().is_local_entry(pe)) {
// *fix 0.9.4 Redefinition is not an error if 'extern'; we reuse an entry unless it will be larger
// *fix 1.2.2 or will be differently initialized...
// *fix 1.2.3b If we've already allocated in an extern declaration, then now initialize...
if (pe->m_access == NotInitialized) {
pe->rmode = DIRECT;
is_class_context = false;
goto rest_of_init;
}
if (! in_extern()) error_already_defined(name);
else return pe; // *fix 1.2.3b Don't redeclare extern variables....
if (pe->type == t && pe->size >= size && !t.is_class() && !init) {
reset_array_size();
return pe;
}
}
//*SJD* This is very irritating - I think it should be optional
//if (pe->type == t) warning(quotes(name) + ": hidden variable");
}
pe = context().add(name);
// put any non-tempory variables in the init list
if (name[0] != '$') dcl_init_list.push_back(pe);
pe->type = t;
pe->size = size;
// extract the base type, if we have an array (1- or 2-D only)
// *fix 1.2.8 We weren't doing the 2D case properly; double [3][3] had the wrong size!
if (t.is_pointer() && s_array_size != 1) {
if (s_array_size < 0)
error("array size cannot be negative");
t.decr_pointer();
if (s_twodim_array > 1)
t.decr_pointer();
}
// use the reference size, not the size of what it's refering to!
if (t.is_reference()) size = sizeof(void *)*pe->size;
else size = t.size()*pe->size;
pe->rmode = is_static ? DIRECT : context().refmode();
is_static = pe->rmode == DIRECT; // *fix 1.0.0
pe->m_typename = false;
//*HACK* 2D arrays are _formally_ allowed in class defs...
if(pe->rmode == OREL) s_twodim_array = 1;
alloc_context = NULL;
if (in_typedef) {
pe->data = 0;
pe->m_typename = true;
if (Module::current()) Module::current()->add_typename(pe);
return pe; //*NOTE* not perfect! will mess w/ array_size!
} else
if (mode != ARG) { // i.e. default!
if(s_twodim_array > 1) { // two-dimensional array
if(pe->rmode != DIRECT) error("can only define static two-dim arrays");
// leave room for the pointer table...
size += sizeof(void *)*s_array_size;
}
alloc_context = is_static ? &global() : &context();
is_class_context = alloc_context ? is_class(alloc_context) : false;
// *add 1.1.4 Bit fields are now allowed in structures
// *fix 1.2.0 Now allocated to ensure 4-byte alignment for the next field, to be consistent with GCC
// *fix 1.2.3 Bit fields will now fit properly in structures one word in size
if (init && init->is_const()) {
if(pe->rmode != OREL || ! pe->type.is_int())
fail("Bit fields must be integer and are only allowed in structs");
int bit_size = const_int_expr(init->entry());
if (bit_offs == 0) {
size = 4 - alloc_context->size() % 4; // room available upto next 4-byte boundary
offset = alloc_context->alloc(size,NULL);
field_size = 8*size; // bits left in this field
}
pe->set_bit_field(offset,bit_offs,bit_size);
bit_offs += bit_size;
if (bit_offs > field_size) bit_offs = 0; // have we gone over a boundary?
init = NULL;
} else {
// *add 1.2.0 Support for 8-byte alignment of doubles in structures
if (is_class_context && debug.class_dword_align == 8 && t == t_double)
pe->data = alloc_context->alloc_qword();
else
pe->data = alloc_context->alloc(size,NULL);
bit_offs = 0;
}
// *change 1.1 Stack now grows downwards, so locals have -ve offset.
// *fix 1.2.2 Important to round up size to nearest dword bounary!
if (is_local(alloc_context)) pe->data = -pe->data - Allocator::dword_align(size)/sizeof(int);
if(s_twodim_array > 1) { // two-dimensional array
void **ptr = (void **)pe->global_ptr();
void **ptable_begin = ptr + s_array_size;
// row length in dwords
int row_size = t.size()*s_twodim_array/sizeof(void**);
for(int i = 0; i < s_array_size; i++)
ptr[i] = ptable_begin + row_size*i;
} else
if (t.is_class()) {
if(t.is_object() && pc->get_VMT() != NULL) { // i.e first dword is for the VMT entry
(pe->data) += (pe->is_stack_relative() ? 1 : sizeof(int));
}
}
} else
if (is_local(&context())) {
PFBlock fb = ((FunctionContext&)context()).fun_block();
pe->data = fb->nargs;
fb->nargs += Table::dword_align(size)/sizeof(int); // ie. in dwords
return pe;
} else fail("how is ARG possible here?");
pe->context = &context();
// *fix 1.2.3b Don't initialize variables in extern declarations
if (in_extern()) {
pe->m_access = NotInitialized;
return pe;
}
rest_of_init:
// no default initialization for class members!
if (init || !is_class_context) {
// even if no init, we pass objects through this in case they
// _may_ need default construction. Don't try to construct in typedefs!
if (init || (t.is_object() && mode != DEFER_TEMP/* && !in_typedef*/)) {
if (init && (!alloc_context || (is_class_context && mode != ENUM_INIT)))
fail("initialization not allowed here");
//*SJD* The context flag needs some work....
if (mode != ENUM_INIT || !init->is_entry() || !init->type().is_const()) {
PExpr e = Expressions::initialize_op(pe,init,NULL,mode==TEMP ? 1 : 0);
if (e != NULL && ! e->is_nil())
(is_static ? static_code() : code())
.compile(e,in_loop_dcl() ? 0 : DROP_VALUE);
} else if (init->is_entry()) {
pe->data = init->entry()->data;
} else fail("bad init");
}
else if (t.is_reference() && (mode != ARG && !in_typedef))
fail("uninitialized reference");
}
} catch(string msg) { error(msg); }
reset_array_size();
return pe;
}
// This is called after every declaration; used to detect anonymous unions
void ParserState::check_dcl_init(Type t)
{
if (dcl_init_list.size() > 0) {
dcl_init_list.clear();
return; // there were declarations
}
if (! t.is_class()) return; // only interested in empty class declarations...
PClass pc = t.as_class();
if (pc->is_anonymous_union()) { // which are anonymous unions
// iterate over all non-static members of the union
// and insert them into the enclosing context.
// First add a temp variable of the union type to allocate some space...
PEntry union_entry = add_variable(t,"*");
Table* cntxt = &context();
EntryList el;
EntryList::iterator eli;
pc->list_entries(el,NON_STATIC | FIELDS);
for(eli = el.begin(); eli != el.end(); ++eli) {
PEntry entry = *eli;
string name = entry->name;
PEntry new_pe = cntxt->new_entry(name);
new_pe->type = entry->type;
new_pe->size = entry->size;
new_pe->data = union_entry->data;
new_pe->rmode = is_class(cntxt) ? OREL : DIRECT;
cntxt->add_entry(name,new_pe);
}
}
}
int array_size(PEntry pe)
{
return pe->size;
}
int size_of_entry(PEntry pe)
{
Type t = pe->type;
// for arrays, use the size of the base type...
if (array_size(pe) > 1 && t.is_pointer()) {
t.decr_pointer();
return array_size(pe)*t.size();
} else return t.size();
}
int const_int_expr(PEntry pe)
{
// *fix 1.2.1 (Eric) Named enums are also valid integer constants!
// *fix 1.2.1 (Eric) Constants may be short
// *fix 1.2.1 Watch out for unsigned shorts...
void *ptr = pe->global_ptr();
Type t = pe->type;
if (t.is_enum()) return *(int *)ptr;
if (!t.is_const() || !t.is_int())
fail("const expr expected, not: " + pe->name);
if (t.is_short()) {
if (t.is_unsigned()) return *(unsigned short *)ptr;
else return *(short *)ptr;
}
if (t.is_int())
return *(int *)ptr;
else return 0;
}
int const_int_expr(Expression e)
{
// *add 1.1.4 Some limited ability to fold compile-time constants
// *add 1.2.5 Added relational ops for #if expressions
if (! e->is_entry()) {
if (e->is_function()) fail("Constant expressions cannot contain functions");
int op = e->op();
int v1 = e->arg1() ? const_int_expr(e->arg1()) : 0;
int v2 = e->arg2() ? const_int_expr(e->arg2()) : 0;
switch (op) {
case LSHIFT: return v1 << v2;
case RSHIFT: return v1 >> v2;
case STAR: return v1 * v2;
case PLUS: return v1 + v2;
case MINUS: return v1 - v2;
case DIVIDE: return v1 / v2;
case BIN_OR: return v1 | v2;
case ADDR: return v1 & v2;
case BIN_NOT: return ~v1;
case LOG_OR: return v1 || v2;
case LOG_AND: return v1 && v2;
case EQUAL: return v1 == v2;
case NOT_EQUAL: return v1 != v2;
case LESS_THAN: return v1 < v2;
case LEQ: return v1 <= v2;
case GREATER: return v1 > v2;
case GEQ: return v1 >= v2;
default: fail("Must be a simple constant integer expression");
}
}
// plain entry case...
return const_int_expr(Expressions::ExprToEntry(e));
}
void *create_const_entry(Type t, PEntry& rpe)
{
PEntry pe = new Entry;
pe->rmode = DIRECT;
t.make_const();
pe->type = t;
pe->size = 1; // by default; for arrays it's > 1!!
pe->m_typename = false;
pe->data = global().alloc(t.size(),NULL);
rpe = pe;
return pe->global_ptr();
}
//////////////////////// Enumerations /////////////////////////////////
// *fix 1.1.4
// * Enums can now be parts of declarations, and I've now made
// it possible for the optional initialization to be an earlier enum constant,
// so that 'enum {ONE,TWO=ONE+1}' will now work.
// * C mode works like w/ structs!
static int gVal;
static Enum* gEnum;
Type ParserState::do_enum(string name)
{
try {
Enum *enum_obj;
Type t_const_int = t_int; t_const_int.make_const();
Type et = t_const_int;
gVal = 0;
// True nameless enums are like 'enum {...}' and just introduce a set of constants.
// If however we get 'typedef enum {...} tag' then it is _not_ nameless
// and we need a distinct name, rather like the equivalent w/ struct.
bool nameless = name=="" && ! in_typedef;
if (nameless) name="?enum"; // entry name of nameless enum
else if (name=="") name = make_temp_name(); // assign a temporary name...
else if (debug.c_mode) name = "$_" + name;
//PEntry pe = symbol_lookup(name);
// *fix 1.2.7 _only_ look in local context;
// a previously defined enum wd collide w/ a definition w/in a class
PEntry pe = context().lookup(name,false);
// *hack 1.1.4 this test in C mode interferes w/ old-fashioned 'enum Name var'
if (! debug.c_mode && pe && !nameless) fail("already defined");
if (! pe) {
pe = context().add(name);
pe->rmode = DIRECT;
pe->m_typename = true;
enum_obj = new Enum(name);
enum_obj->entry(pe); // *add 1.2.7 Enum now carries entry...
pe->data = global().alloc(sizeof(Enum),enum_obj);
if (!nameless) {
et = Type(enum_obj);
Module::current()->add_typename(pe); // will need to clean these entries out...
}
pe->type = et;
} else
// *fix 1.2.7 The enum object is via a _direct_ reference!
enum_obj = (Enum *)global().addr(pe->data);
gEnum = enum_obj;
return pe->type;
} catch(string msg) { error(msg); }
return t_void;
}
void ParserState::add_enum(Type et, string name, PExpr init)
{
// Add a constant to the current enumeration!
// *fix 1.2.1 (Eric) Simplified, and no longer mistreats shorts...
bool was_in_typedef = in_typedef;
PEntry pe_entry,entry;
in_typedef = false;
try {
if (init)
gVal = const_int_expr(init);
*(int *)create_const_entry(t_int, pe_entry) = gVal++;
entry = add_variable(et,name,Expressions::entry_op(pe_entry),ENUM_INIT);
gEnum->add_entry(entry);
} catch(string msg)
{ error(msg); }
in_typedef = was_in_typedef;
}
/////////////////////////////// Exception handling....//////////////////////////////
void do_start_try_block()
{
Function *curr_fn = current_function();
if (curr_fn == NULL){ error("try..catch only allowed in functions"); return; }
CatchHandler *pch = new CatchHandler(curr_fn
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -