📄 common.cpp
字号:
pe->m_typename = false;
FunctionEntry *pfe = new FunctionEntry(pe);
pe->data = (int)pfe;
return pfe;
}
// *add 1.2.8 convenient function for working with signatures
string sig_as_str(Signature* sig, const string& name)
{
char buff[255];
Signature::set_fun_name(name);
ostrstream out(buff,255);
out << *sig;
return buff;
}
string class_name(Type t)
{ return t.is_class() ? t.as_class()->name() : string("<unknown>"); }
void error_not_in_class(const string& name, Type class_type)
{
fail(quotes(name) + " not found in class " + quotes(class_name(class_type)));
}
// *change 1.2.9 template functions in enclosing scopes are NOT handled specially
// any more. We just have to be careful for the case where a function entry has
// no functions.
// *fix 1.2.9 member templates now work.
FunctionEntry *
lookup_function_entry(Signature *sig, const string& name,bool fn_defn,
Function **fn, int& slot_id)
{
Type method_scope = state.class_dcl;
state.class_dcl = t_void;
bool method_body = method_scope != t_void;
PEntry pe = symbol_lookup(name);
mIsConversion = name == CONVERSION_OPNAME;
FunctionEntry *pfe = NULL, *local_entry = NULL;
slot_id = 0;
*fn = NULL;
if (pe) { // already is an entry
bool is_function = pe->type.is_signature();
Table* cntxt = &state.context();
pfe = (FunctionEntry *)pe->data;
// but is it local? In which case we try to overload
if (cntxt->is_local_entry(pe)){
// *add 1.2.8 'main' can't be overloaded...
if (name == "main") return NULL;
if (is_function) {
*fn = pfe->simple_match(sig);
if (*fn) { // but not if this signature is already present!
// if this function is already complete, we can only
// redeclare it, not redefine it.
if ((*fn)->context() && fn_defn) {
if (!interactive_mode()) { error_already_defined(name); return NULL; }
else (*fn)->clear(); // ISSUE: again, interactive mode is more lenient
}
// *issue 0.9.5 allows us to actually change the return type; when shd it be an error?
if ((*fn)->return_type() != sig->return_type()) { *fn = NULL; return NULL; }
return pfe; // reuse entry...
} else // another case: the set is virtual - in which case, this entry
// is hiding the original virtual entry!
if (state.in_template != NULL && pfe->size() > 0 && pfe->back()->is_virtual()) {
pe = cntxt->parent_context()->lookup(name);
if (pe==NULL) return pfe; // this set was created in the current class...
if (pe->type.is_signature()) { // continue to find virtual slot....
local_entry = pfe; //save local entry
pfe = (FunctionEntry *)pe->data; //but look at inherited entry!
} else return NULL; // wasn't a function, so ditto
} else { // cool - can now try to overload....
// *fix 1.2.8 except of course, if this is a method body definition;
// there must be a corresponding method declaration!
// *fix 1.2.9 unless this is a member template instantiation; the function
// doesn't exist at this point!
if (method_body && state.in_template == NULL)
error_not_in_class(sig_as_str(sig,name),method_scope);
else return pfe;
}
} else { error_already_defined(name); return NULL; }// and it wasn't a function!
}
// *fix 1.2.4 Qualified method name (C::name(...)) where 'name' is not found directly in 'C'
else if (method_body) error_not_in_class(name,method_scope);
// an entry in some enclosing scope
if (is_class(pe->context)) {
*fn = pfe->simple_match(sig);
// if a virtual method, get its slot id
// but always redeclare (hence hiding the original entry)
if (*fn != NULL) {
if ((*fn)->is_virtual()) {
slot_id = (*fn)->slot_id();
if (slot_id > 512) slot_id = 1;
}
//*HACK* this was very irritating - switch it off while importing...
// else warning(quotes(name) + " will be hidden");
}
}
*fn = NULL; //*????*
// *fix 1.2.9 The _specific case_ where we're instantiating a function template;
// the entry already exists!
if (state.in_template &&
state.in_template->get_template()->get_entry()->entry() == pe) return pfe;
else return local_entry ? local_entry : NULL; // NULL create a new entry please!
} else // not found!
if (method_body) {
error_not_in_class(name,method_scope);
return NULL;
} else return NULL;
}
void ParserState::set_construct_destruct(int ftype)
{
in_construct_destruct = ftype;
}
Function *generate_function(Signature *sig, FunctionEntry *pfe, int slot_id, bool imported)
{
PClass pclass = class_context();
Function *fn = new Function(sig,pfe);
//*NOTE* This is somewhat awkward, and needs to be done up
// before _anybody else_ sees it!
if (pclass != NULL && state.modifier != Static && state.in_construct_destruct == IsPlain)
state.in_construct_destruct = 3;
fn->set_construct_destruct(state.in_construct_destruct, state.modifier == Explicit);
state.in_construct_destruct = IsPlain;
pfe->push_back(fn);
fn->builtin(imported ? Function::CDECL : Function::UCFN);
// *change 1.2.3 Flag how this function must be exported as a callback
fn->export_as_cdecl(state.modifier != Stdcall);
if (state.modifier==Virtual || slot_id > 0) {
if (!pclass) fail("'virtual' not allowed here");
/// A new virtual method gets a new (non-zero) slot id
if (slot_id == 0) slot_id = pclass->next_slot();
fn->slot_id(slot_id);
// *fix 1.1.0 add the slot to the class...
pclass->set_slot(fn->slot_id(),fn);
}
state.modifier = None;
if (mIsConversion) {
if (!pclass) fail("conversion operator must be a method");
pclass->set_conversion_to(fn);
}
//REF:TEMPLATE
// *fix 0.9.3 Didn't check to see that this was the same template....
// (got confused during class instantiation)
if (pfe->get_template() != NULL && state.in_template != NULL
&& ! state.in_template->get_template()->is_class()) {
fn->set_template(state.in_template);
fn->get_template()->data(fn);
}
return fn;
}
void set_default_args(Function *fn, bool do_clear, bool is_defn=false)
{
// set any default arguments - will overwrite any currently defined ones!
PExprList pel = get_default_arguments();
if (pel) {
// *fix 0.9.4 Now complains about default args in fn. defn
// *NOTE* We should move this 'not defined' test to Function...
if (is_defn && fn->fun_block()->pstart == NULL
&& fn->has_default_args()) fail("Cannot redefine default arguments");
fn->set_default_args(pel);
delete pel;
}
if (do_clear) state.arg_list.clear();
}
Table* enclosing_namespace(Table* pt)
{
while (pt->type() != IS_NAMESPACE && pt != &global())
pt = pt->parent_context();
return pt;
}
Function *ParserState::declare_function(Type t,const string& name, PExpr poss_init)
{
int slot_id, modifier_flags = modifier;
in_declaration = false;
Function* fn = NULL;
Table* fcntext = NULL;
try {
Signature *sig = get_signature(t);
bool was_import = Builtin::get_dll_handle() && poss_init == NULL;
PClass class_ptr = class_context();
// string cname = class_ptr ? class_ptr->name() : ""; //*DEBUG
if (in_friend_dcl) { // *add 0.9.5 Friend function declaration
if (class_ptr == NULL) fail("Friend declaration only allowed in class declaration");
pop_context(); // to ensure that friend dcl lookup is outside this scope...
} else if (context().type()==FUNCTION) { // *fix 1.2.6 declaration within function scope
fcntext = enclosing_namespace(&context());
push_context(fcntext);
}
FunctionEntry *pfe = lookup_function_entry(sig,name,false,&fn, slot_id);
if (in_friend_dcl) { // Parser::state.in_friend_dcl
push_context(class_ptr);
}
if (!pfe) pfe = create_function_entry(sig,name);
if (!fn) { // add a new function to the overloaded set!
fn = generate_function(sig,pfe,slot_id,was_import);
}
if (fcntext) pop_context();
set_default_args(fn,true);
if (in_friend_dcl) { // *fix 1.1.0 friend declarations act as forward declarations
class_ptr->add_friend_object(fn,false);
in_friend_dcl = false;
return fn;
}
if (state.in_template && class_ptr) { // w/in class template instantiation
// *add 1.1.0 Any externally defined method template entries must be attached
// to corresp methods
TemplateInstance *ti = state.in_template; // i.e. the class template instance
const EntryList *pfl = ti->get_template()->get_entry()->method_entries();
if (pfl) {
EntryList::const_iterator eli;
FORALL(eli,*pfl) {
PEntry pe = *eli;
if (pe->name == name) // attach the method templates to the methods...
pfe->set_template(PFunctionEntry(pe->data)->get_template());
}
}
}
if (poss_init != NULL) { // *add 0.9.5 pure virtual methods
if (class_ptr == NULL) fail("must be in class context");
if (!fn->is_virtual()) fail("method must be virtual");
if (!poss_init->type().is_zero()) fail("must be zero for pure virtual method");
class_ptr->make_abstract();
} else {
// This prototype may represent a dynamic link to a DLL
// *fix 1.2.3 Don't try to import a pure virtual method
if (was_import) {
string name;
// *fix 0.9.5 state.modifier is reset - this CONTINUOUSLY gives trouble...
// *hack 1.1.4 Some libraries have a number of entries which can't be found.
if (!Builtin::add_dll_function(fn,modifier_flags,name) && ! debug.suppress_link_errors)
cerr << "cannot link to " + quotes(name) << endl;
}
}
} catch(string msg) { error(msg); }
// NB to reset state!!
modifier = None;
in_friend_dcl = false;
return fn;
}
Function *ParserState::start_function(Type t, const string& name,bool init_context, int ftype)
{
int slot_id, modifier_flags = modifier;
PEntry pe;
Function *fn = NULL;
ArgList by_val_list;
try {
PClass class_ptr = class_context();
Signature *sig = get_signature(t);
FunctionEntry *pfe = lookup_function_entry(sig,name,true,&fn,slot_id);
if (!pfe) pfe = create_function_entry(sig,name);
if (!fn) // add a new function to the overloaded set!
fn = generate_function(sig,pfe,slot_id,false);
fn->builtin(ftype);
if (fn->builtin()) fn->import_scheme(Import::scheme());
set_default_args(fn,false,true);
#if _DEBUG
gLastFunction = fn; //*DEBUG*
if (gDebugBreak) {
if (gDebugBreak == 2)
__break(2);
else
gFunBlock = fn->fun_block();
gDebugBreak = 0;
}
#endif
// Create a function context and make it current!
FunctionContext *fcntxt;
Table *cntxt = &context();
if (fn->is_constructor()) fcntxt = new ConstructorContext(cntxt,fn); else
if (fn->is_destructor()) fcntxt = new DestructorContext(cntxt,fn);
else fcntxt = new FunctionContext(cntxt,fn);
if (init_context) fcntxt->initialize();
else {
fn->clear();
set_function_code(true); // *fix 0.9.5 was not called before constructor init. lists
}
push_context(fcntxt);
if (class_ptr) { // methods need a 'this' variable!
Type cpt = class_ptr->entry()->type;
cpt.incr_pointer();
// cpt.make_const(); // *fix 1.2.7
PEntry p_this = fcntxt->add("this");
p_this->type = cpt;
p_this->data = THIS_OFFSET;
}
dcl_init_size = 0;
// Add any args, ignoring the initializers
// (1) Passing objects _by value_ is achieved by a dummy ref. argument,
// which is then used to initialize a proper local object.
// *add 1.1.0 unless we're importing a function which does need true by value passing! (like MSC++)
// *add 1.2.6 which may well be conditional on the object size and type (like GCC 3)
// (2) We pass a hidden first arg for routines returning object values
// *add 1.2.6 unless this is a function which does true by value return (like GCC 3)
ImportScheme* import = fn->import_scheme();
if (t.is_object() && ! (import && import->true_return_by_value(t))) {
t.make_reference();
fn->return_object(add_variable(t,"*",NULL,ARG));
}
ArgList::iterator ali;
bool passing_obj_by_value = false;
// *fix 0.9.2 Template class arguments may be instantiated during add_variable()
// The state is restored ok, but the arg_list iterator was no longer valid.
for(; arg_list.size() > 0; arg_list.pop_front()) {
Type t = arg_list.front().type;
string name = arg_list.front().name;
// *fix 1.2.2b if this name is empty, replace by '*', which means 'create temporary name'
if (name == "") name = "*";
if (t.is_object() && ! (import && import->true_pass_by_value(t))) {
by_val_list.push_back(ArgEntry(t,name,NULL));
t.make_reference();
name = "*";
passing_obj_by_value = true;
}
pe = add_variable(t,name,NULL,ARG);
if (passing_obj_by_value) {
by_val_list.back().init = Expressions::entry_op(pe);
passing_obj_by_value = false;
}
}
// any objects passed by value are now declared in the function context; these
// are initialized using the reference parameter created above.
// *add 1.1.0 except if this was a native call...
if (by_val_list.size() > 0 && ! fn->builtin()) {
for(ali = by_val_list.begin(); ali != by_val_list.end(); ++ali)
add_variable(ali->type,ali->name,ali->init);
by_val_list.clear();
}
} catch(string msg) { error(msg); }
class_dcl = t_void; // just in case...
return fn;
}
PEntry ParserState::add_typedef(Type t, const string& name)
{
in_typedef = true;
PEntry pe = add_variable(t,name,NULL,None);
in_typedef = false;
return pe;
}
// this structure makes sure that the state is _always_ properly sorted out
// when we leave add_variable(), even if we just return.
// *fix 1.2.7 this sorts out a problem with extern arrays followed by plain const defs:
// extern char obuff[BUFFSIZE];
// const int TOPLEFT = 1; // blew up because s_array_size was NOT reset
struct PopAtEnd {
bool m_context_pushed;
PopAtEnd() : m_context_pushed(false) { }
void set() { m_context_pushed = true; }
~PopAtEnd() {
if (m_context_pushed) state.pop_context();
reset_array_size();
}
};
PEntry ParserState::add_variable(Type t, string name, Expression init, int mode)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -