📄 common.cpp.svn-base
字号:
{
Table *cntxt = context_stack.TOS();
if (!cntxt) { // *DEBUG*
warning("Restoring lost context...");
cntxt = &global();
push_context(cntxt);
}
return *cntxt;
}
void ParserState::add_to_arg_list(Type t, const string& name, Expression init)
{
arg_list.push_back(ArgEntry(t,name,init));
}
static ArgList tmp_arg_list;
void ParserState::begin_args()
{
tmp_arg_list = arg_list;
arg_list.clear();
}
void ParserState::end_args()
{
arg_list = tmp_arg_list;
}
void clear_parse_flags()
{
force_comma_flag(); // *hack 0.9.6 the dcl stack is getting out of order...
state.token_stack.clear();
}
void restore_global_context()
{
if (is_local(&state.context())) state.pop_context();
}
bool mFakeInitBlock = false;
// *add 1.2.7 Method bodies are cached for later compilation
bool ParserState::handle_method_body(Class* pc, bool plain_method)
{
// With imported methods, the idea is to ignore the inline code and link to the exported fn.
if (Builtin::get_dll_handle() != NULL) {
// *fix 1.2.0L GCC under Linux doesn't export these guys, so compile them as usual!
// *ch 1.2.9 patch
#ifndef _WIN32
return false;
#else
// (ignore case of methods outside class defn...)
if (pc != NULL) pop_context();
// but force a dynamic link to those w/in the class body
else declare_function(tpop(),token_stack.pop(),NULL);
// and ignore the method body
Template::grab_function_body(plain_method,NULL);
// *fix 1.2.8 see 'hack of the week' in the next block - we gotta fool the parser!
if (! plain_method) {
Input::insert_string("__init_block__ {}");
mFakeInitBlock = true;
}
#endif
} else {
// Only method bodies _inside_ class definitions are cached. Or caching can be switched off...
if (! debug.skip_method_bodies || pc != NULL) return false;
// otherwise, we want to cache these bodies for later compilation when the class is finalized;
// make sure they're declared
TemplateInstance* ti = in_template;
in_template = NULL;
Function* pf = declare_function(tpop(),token_stack.pop(),NULL);
in_template = ti;
char* body_buff = Template::generate_function_header(pf,plain_method,false);
Template::grab_function_body(plain_method,body_buff);
pf->class_context()->add_defered_method_body(pf,body_buff);
// *hack 1.2.7 hack of the week: we have grabbed the init list, but need to push
// something into the input stream which the parser recognizes as 'class_init_list block'
if (! plain_method) {
Input::insert_string("__init_block__ {}");
mFakeInitBlock = true;
} else {
block_stack.push(0);
Input::insert_string("}");
}
}
dcl_reset(); // and ensure that the state is properly reset!
while (tstack_depth() > 2) tpop();
clear_parse_flags();
return true;
}
/// Managing blocks!
// also used to start function definitions....
void ParserState::init_block(int type)
{
// parser can ask us to ignore the next init_block(); used w/
// constructor initialization lists to prematurely start the function
// definition. That is, we break the usual function init_block up into
// two separate operations: constructing the function and its block,
// and then initializing it!
if (in_method) {
in_method = false;
// if we're inside a class body, then skip this initialization
if (debug.skip_method_bodies && (class_dcl != t_void || mFakeInitBlock)) {
block_stack.push(0);
mFakeInitBlock = false;
return;
}
if (!is_local(&context())) {
error("Context not local!");
return;
}
FunctionContext& fc = static_cast<FunctionContext&>(context());
FBlock *fb = fc.fun_block();
int nargs = fb->nargs; // *hack 0.9.8 was being reset to zero...MUST OVERHAUL!
fc.initialize();
fb->nargs = nargs;
return;
}
bool is_continueable = in_loop, is_breakable = in_loop;
int flags = 0;
if (in_declaration) { // _only_ if this is a function block!
Table *cntxt = &context();
PClass pc = NULL;
// *fix 1.1.3 If this was a template method, then don't muck up the IC!
// Careful to exclude the case of instantiating methods of a template class.
bool template_instantiating =
cntxt->type() == INSTANTIATION_CONTEXT
&& ! in_template->get_template()->get_entry()->is_method();
flags = CONTEXT_PUSHED;
if (class_dcl != t_void) { // nested Class:: notation...
if (!class_dcl.is_class()) { error("Not a class name"); return; }
pc = class_dcl.as_class();
// class context may _already_ be pushed in the case of constructor
// initialization lists - but we flag it as a method anyhow.
if (cntxt != pc /*&& ! template_instantiating*/) {
push_context(pc);
cntxt = pc;
}
if (! template_instantiating) flags |= IN_METHOD;
}
// *add 1.1.0 Expressly forbid nested functions! Otherwise we get nasty brace mismatch issues...
if (is_local(cntxt)) {
error("Cannot have functions within functions"); return;
}
string name = token_stack.TOS();
// *add 1.1.0 Skip the bodies of any inline imported methods, except for ctors w/ init lists
if (is_class(cntxt)) {
if (handle_method_body(pc,type != CONSTRUCTOR_BLOCK)) return;
}
start_function(tpop(),token_stack.pop(), type != CONSTRUCTOR_BLOCK);
dcl_reset();
// *change 1.2.3 The return label is now backed by a stack
m_ret_label = new Label(&code());
m_ret_label_stack.push(m_ret_label);
flags |= FUN_BLOCK;
} else
if (in_switch) {
flags = IN_SWITCH;
is_breakable = true;
} else
if (in_class) {
flags = CONTEXT_PUSHED;
in_class = false;
} else
if (type==LOOP_BLOCK) {
flags = LOOP_SCOPE;
}
if (is_breakable) {
flags |= BREAKABLE;
break_stack.push(label_stack.TOS());
if (in_switch) { // *fix 0.9.4 switch left label stack pushed - mucked w/ while!
label_stack.pop();
in_switch = false;
}
}
if (is_continueable) {
flags |= CONTINUEABLE;
continue_stack.push(new Label(&code()));
in_loop = false;
}
block_stack.push(flags);
clear_parse_flags();
}
bool ParserState::context_generated()
{
return block_stack.depth() == 0 || block_stack.TOS() & CONTEXT_PUSHED;
}
void ParserState::check_context(int mode)
{
// if a fresh context has been pushed, cool...
if (context_generated()) return;
Function *function = current_function();
// function==NULL is a C++ error, but is allowed in interactive mode
push_context(new LocalContext(&context(),function));
block_stack.TOS() |= CONTEXT_PUSHED;
}
bool ParserState::in_loop_dcl()
{
return block_stack.TOS() & LOOP_SCOPE;
}
void end_switch();
void ParserState::finalize_block()
{
if (block_stack.depth() < 1)
block_stack.push(CONTEXT_PUSHED);
int flags = block_stack.pop();
if (flags & IN_SWITCH) end_switch();
if (flags & CONTINUEABLE) {
m_continue = continue_stack.pop();
m_continue->here();
} else m_continue = NULL;
if (flags & BREAKABLE) break_stack.pop();
if (flags & FUN_BLOCK) { // *fix 0.9.5 UCW can fall over if braces are mismatched..
if (m_ret_label_stack.empty()) error("misplaced braces");
else m_ret_label->here();
// *hack 1.1.0 It's difficult to skip the body of a imported ctor w/ init list,
// so ensure that declare_function() is called to import this function!
if (Builtin::get_dll_handle() && is_class(&context())) {
string name;
if (!Builtin::add_dll_function(current_function(),0,name))
cerr << "cannot link to ctor " + quotes(name) << endl;
// fn->builtin(Function::CDECL); //?
}
}
if (flags & CONTEXT_PUSHED) {
context().finalize();
pop_context();
class_dcl = t_void;
}
// If we were in a method body, then the class context must be dropped
if (flags & IN_METHOD) pop_context();
// can now dispose of the continue/return label
if (flags & CONTINUEABLE) delete m_continue;
if (flags & FUN_BLOCK) {
delete m_ret_label;
m_ret_label = NULL;
m_ret_label_stack.pop();
}
state.in_construct_destruct = IsPlain; //*fix 1.2.4
}
Label *ParserState::return_label()
{
return m_ret_label;
}
//---------------doing control statements---------------
// *fix 1.2.7 In 'A::B<C>', C was looked up in A's context.
// The fix involves detecting whether we're in a scoped context,
// and popping and pushing the context.
void ParserState::begin_templ_list()
{
if (scope_context != NULL) pop_context();
}
void ParserState::end_templ_list()
{
if (scope_context != NULL) push_context(scope_context);
}
void push_label_stack()
{ state.label_stack.push(new Label(&code())); }
void label_jump(int jtype, bool do_push)
{
if (do_push) push_label_stack();
code().jump(jtype,state.label_stack.TOS());
if (!do_push) { delete state.label_stack.pop(); }
}
void label_here()
{
push_label_stack();
state.label_stack.TOS()->here();
}
void compile_condition(PExpr cond)
{
code().compile(Expressions::cast_to_bool_op(cond));
}
bool do_loop_start(PExpr cond, bool jump_back)
{
// skip the controlled statement if not true!
// *fix 0.9.4 Push a non-zero value to ensure for(;;) keeps going..
if (!cond) cond = Expressions::sizeof_op(1);
compile_condition(cond);
// Quite NB to dispose of any temporaries before we continue...
check_temp_context();
/*if (jump_back)*/ label_jump(JZ,true);
return true;
}
bool do_loop_end(bool is_jump, bool is_forward)
{
Label *l1 = state.label_stack.pop();
// now either jump forward (if-else) or back (while-do-for)
if (is_jump) label_jump(JMP, is_forward);
l1->here(); // the forward jump!
return true;
}
bool do_for_end(PExpr e)
{
if (e) code().compile(e,DROP_VALUE);
do_loop_end(true);
return true;
}
// *fix 1.2.3 break inside a do-while loop was broken!
bool do_do_end(PExpr cond)
{
// this will be the break label
Label *l1 = state.label_stack.pop();
compile_condition(cond);
check_temp_context();
// if condition fails, we jump back to the top label;
code().jump(JNZ,state.label_stack.pop());
// break will jump to here
l1->here();
return true;
}
void check_enclosing_scopes(LocalContext *outer)
// Given a local context, look at the enclosing scopes until we hit
// some outer context (usually the outermost function context). If the
// outer context has auto objects, then do nothing, since the jump will
// go to a proper unwind. Otherwise, find the first enclosing scope
// that does have auto objects.
// note: must only be called from within a local function context
{
LocalContext *cntxts[BLOCK_DEPTH];
LocalContext *lc = (LocalContext *)&state.context();
int ic = 0;
while ((cntxts[ic++] = lc) != outer)
lc = (LocalContext *)lc->parent_context();
while (--ic >= 0)
if (cntxts[ic] != outer && cntxts[ic]->first_obj() != NULL) {
cntxts[ic]->check_objects();
return;
}
}
bool do_return(PExpr e)
{
Label *ret_label = state.return_label();
if (!ret_label) { error("return only in function"); return false; }
Function *fn = ((LocalContext&)state.context()).function();
Type rt = fn->return_type();
// if (fn->name()=="bh_begin")
// ret_label = 0;
// *add 1.1.1 support for __declare; uses first return type!
if (rt == t_null) { // t_undefined
rt = e->type();
rt.strip_const();
fn->adjust_return_type(rt);
}
// *change 1.1.0 Void functions can return void 'values' (ISO standard behaviour)
if (rt == t_void && e != NULL && e->type() != t_void) {
error("void function cannot return value");
return false;
}
if (e) {
PExpr ret_exp = Expressions::return_op(fn,rt,e);
if (ret_exp->is_nil()) {
error("Could not copy return object");
return false;
}
code().compile(ret_exp);
}
// *fix 1.1.0 Must ensure that a proper UNWIND operation occurs for any locals
check_enclosing_scopes(fn->context());
code().jump(JMP,ret_label);
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -