📄 function.cpp.svn-base
字号:
/* FUNCTION.CPP
* Support for functions: classes: Function,FunctionEntry,LocalContext
* UnderC C++ interpreter
* Steve Donovan, 2001
* This is GPL'd software, and the usual disclaimers apply.
* See LICENCE
*/
#include "common.h"
#include "opcodes.h"
#include "module.h"
#include <ctype.h>
#include "directcall.h"
#include "input.h"
#ifdef __GNUC__
#include <strstream.h>
#endif
const int MAX_FUN_NAME = 256;
//#include "function.h"
//#include "expressions.h"
namespace { // private stuff
string s_fun_name = "<none>";
bool s_ctor = false, s_dtor = false;
inline int max(int i, int j)
{ return i > j ? i : j; }
};
// Line Number Management
typedef std::list<LineInfo> LineInfoList;
// this overrides the virtual base class
class LineNumbers: public LineNumbersB {
private:
LineInfoList m_li;
int m_module;
public:
void add(const LineInfo& li) // override
{
m_li.push_back(li);
}
// *fix 1.2.7 necessary to look for the next line, if we match exactly
bool lookup_line(LineInfo& li, bool find_line) // override
{
LineInfoList::iterator lili, lili_end = m_li.end();
for(lili = m_li.begin(); lili != lili_end; lili++)
if (find_line && lili->ip_offset >= li.ip_offset) {
if (lili->ip_offset == li.ip_offset) {
lili++;
if (lili == lili_end) return false; //*ALWAYS?*
}
li = *lili;
return true;
} else
if (!find_line && lili->line >= li.line) {
li = *lili;
return true;
}
return false;
}
// *add 1.2.7
void dump(ostream& out)
{
LineInfoList::iterator lili;
for(lili = m_li.begin(); lili != m_li.end(); lili++)
out << lili->line << ' ' << lili->ip_offset << ' ' << lili->file << endl;
}
int lookup_ip(int line) // override
{
LineInfo li;
li.line = line;
if (lookup_line(li,false)) return li.ip_offset;
else return 0;
}
void lookup_range(int& l1, int& l2)
{
LineInfoList::iterator lili;
if (m_li.size()==0)
{
l1 = l2 = -1;
}
l1 = m_li.front().line;
l2 = m_li.back().line;
}
LineNumbers() : m_module(-1) {}
void module(int id) { m_module = id; }
int module() { return m_module; }
};
static bool s_full_names = true;
void Signature::set_fun_name(const string& name, bool is_ctor, bool is_dtor)
{
s_ctor = is_ctor;
s_dtor = is_dtor;
s_fun_name = name;
}
string Signature::get_fun_name()
{ return s_fun_name; }
void Signature::write_qualified_names(bool yesno)
{ s_full_names = yesno; }
// miscelaneous output routines
ostream& operator << (ostream& os, Signature& sig)
{
Signature::iterator si;
StringList::iterator sli;
StringList *args = sig.get_arg_names();
if (args && args->size()==0) args = NULL;
if (!s_ctor && !s_dtor) // *fix 1.1.2 these don't have return types!
os << sig.return_type() << ' ';
string na = s_fun_name;
char first = na[0];
// *fix 1.2.7 wasn't outputing 'operator' in front of '()'
if (!isalpha(first) && first != '_' /*&& first != '('*/) na = "operator" + na;
PClass pc = sig.class_ptr();
if (pc != NULL) {
string classn = pc->name();
if (! s_full_names && pc->is_template()) classn = pc->get_template()->name();
if (s_ctor) na = classn; else
if (s_dtor) na = "~" + classn;
if (s_full_names) na = classn + "::" + na;
}
os << na << '(';
if (args != NULL) sli = args->begin();
for(si = sig.begin(); si != sig.end(); ) {
os << *si++;
if (args != NULL) os << ' ' << *sli++;
if (si != sig.end()) os << ',';
}
os << ')';
if (sig.is_const()) os << " const";
return os;
}
ostream& operator <<(ostream& os, Function& f)
{
f.dump(os);
return os;
}
LocalContext::LocalContext(Table *parent, Function *f)
: Table(parent,SREL,0),m_function(f), m_no_auto_dtor(false)
{
m_type = FUNCTION;
set_mem_unit(4); // we work in DWORDS
set_dword_align(4); // *fix 1.2.3 Local contexts have 32-bit alignment _explicitly_
set_parent(parent);
}
int LocalContext::alloc(int sz, void *data)
{
// remember to keep the parent updated!
if (m_parent->type()==FUNCTION) m_parent->alloc(sz,NULL);
return Table::alloc(sz,data);
}
void LocalContext::set_parent(Table *parent)
{
m_parent = parent; // *fix 0.9.5 m_parent was set _after_ calling update_parent!
// start off where our parent ended....
if (parent->type()== FUNCTION) {
if (m_data == 0) m_data = (char *)parent->size();
}
}
bool LocalContext::check_objects(bool do_clear)
{
// Any local objects requiring destruction must be unwound...
if (m_first_obj != NULL) {
Parser::code().emit(UNWIND,SREL,m_first_obj->data);
if (do_clear) m_first_obj = NULL;
return true;
} else return false;
}
void LocalContext::finalize()
{
check_objects();
}
void LocalContext::add_line_no(const string& file, int line) // override
{
LineInfo li;
if (function() == NULL) return; // local context in interactive mode
li.file = file;
li.cntxt = this;
li.line = line;
li.ip_offset = Parser::code().ip_offset();
// *fix 1.2.7 We were adding line numbers in interactive debugging mode.
// So check that the module id has been set (which only happens on finalization of context)
LineNumbersB* lnb = function()->line_nos();
if (lnb->module() == -1) lnb->add(li);
}
FunctionContext::FunctionContext(Table *parent, Function *f)
: LocalContext(parent,f)
{
}
FBlock *
FunctionContext::fun_block()
{
return function()->fun_block();
}
void FunctionContext::initialize()
{
Function *fn = function();
fn->attach_context(this);
FBlock *fb = fun_block();
if (fb->pstart) delete fb->pstart; // may be previously defined!
fb->pstart = 0;
fb->nargs = 0; // crucial to clear this!
// and switch to the function compile context!
Parser::set_function_code(true);
// *change 1.2.9 This is now retired; this is called explicitly before main()
// *fix 1.2.5 Ensure that any library initializations occur before a program is run!
//if (fn->name()=="main") {
// Parser::code().compile(Expressions::function_call("_init_lib",NULL),DROP_VALUE);
//}
}
void FunctionContext::finalize()
{
UCContext& code = Parser::code();
// if the last instruction was a trival RETURN jump, ignore it!
int op = code.last_pi()->opcode;
Label *ret_lbl = Parser::state.return_label();
if (op == JMP && code.last_pi()->data == code.ip_offset()) {
ret_lbl->remove(code.last_pi()); // take out this JMP
code.backspace(); // skip back
ret_lbl->here(); // repatch all other instances of return jump
} else
if (ret_lbl && op == UNWIND) ret_lbl->here(-1);
LocalContext::finalize();
// *fix 1.1.0 Finalizing the context often generates an UNWIND;
// ensure that all returns jump to it first!
if (ret_lbl && code.last_pi()->opcode == UNWIND) ret_lbl->here(-1);
// appropriate RETx instruction
code.emit_return(m_function->return_type());
fun_block()->finalize(size());
// and switch to back to the static compile context...
Parser::set_function_code(false);
// update the module structure with our line number range
int lstart, lend;
function()->line_nos()->lookup_range(lstart,lend);
if (lstart < 0 || lend < 0)
lstart = 0;
Module *pm = Module::current();
if(pm) {
pm->add_function(function(),lstart,lend);
function()->line_nos()->module(pm->id());
} else function()->line_nos()->module(0);
}
bool FunctionContext::ip_to_line(LineInfo& li)
{
return function()->line_nos()->lookup_line(li,true);
}
ConstructorContext::ConstructorContext(Table *parent, Function *fun)
: FunctionContext(parent,fun)
{
}
void ConstructorContext::initialize()
{
FunctionContext::initialize();
if (!function()->builtin()) function()->class_context()->auto_construct(false);
}
void ConstructorContext::finalize()
{
Parser::check_temp_context(); // *fix 0.9.5 force this where there's no code in constructor body
FunctionContext::finalize();
}
DestructorContext::DestructorContext(Table *parent, Function *fun)
: FunctionContext(parent,fun)
{
}
void DestructorContext::finalize()
{
if (!function()->builtin()) function()->class_context()->auto_destruct(false);
FunctionContext::finalize(); // *fix 0.9.4 auto-generated destructor code wasn't written to function!
}
FBlock *FBlock::create(PEntry pe, PClass pc)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -