📄 main.cpp
字号:
/* main.cpp
* Main Program, initialization, and # command implementation
* UnderC C++ interpreter
* Steve Donovan, 2001
* This is GPL'd software, and the usual disclaimers apply.
* See LICENCE
*/
#include <ctype.h>
#include <stdio.h>
#include "common.h"
#include "breakpoints.h"
#include "module.h"
#include "tokens.h"
#include "engine.h"
#include "mangle.h"
#include "directcall.h"
#include <time.h>
#include "keywords.h"
#include "operators.h"
#include "uc_tokens.h"
#include "program.h"
#include "utils.h"
#include "input.h"
#include "version.h"
#include "errors.h"
#include "hard_except.h"
#include "main.h"
#include "config.h"
#include "loaded_module_list.h"
#ifdef _WCON
#include "ide.h"
#endif
// *DEBUG*
#ifdef _DEBUG
#include <crtdbg.h>
int check_mem(); // *DEBUG*
// *add 1.2.8 A debug interface for assisting the poor debuggers of UC
int gDebugBreak = 0;
FBlock* gFunBlock = 0;
void __break(int);
#else
int check_mem()
{
return 1;
}
#endif
void dump_fun_stack(); // in engine.cpp
int yyparse(); // found in TPARSER.CPP (generated by Bison from parser.y)
bool check_error(); // ditto
void clear_global_namespace(); // in table.cpp
void dump_module_traceback(); // in uc_tokens.cpp
#ifdef BUILD_WITH_GTK
void special_init(int *argc, char ***argv, bool on_off); // found in UCW_GTK
#else
void special_init(int *argc, char ***argv, bool on_off) { }
#endif
void macro_cleanup(); // in tokens.cpp (backdoor!!)
void add_builtin_macro(const char* name); // in uc_tokens.cpp (ditto, I suppose)
const int EXPR_BUFF_SIZE = 1024, PATHSIZE = 256;
// *hack 1.2.2b The console version experiences a most odd problem
// when running a program occaisionally. yylex() returns 0, but yyparse()
// considers this an error, and gives us a characteristic 'DUD' error message.
// To get around this, the console version shuts down by _throwing an int_
int call_parser()
{
try {
if (yyparse()==1) { // an error occured!
Input::clear();
return FAIL;
} else
return OK; // successful exit!
} catch(int) {
#ifndef _WCON
//cerr << "DUD err" << endl;
#endif
return OK;
}
}
int uc_eval(char *expr, bool append_semicolon=true, bool synchronous=false, char *name=NULL, int lineno=0)
{
static char buffer[EXPR_BUFF_SIZE];
char *ibuff = synchronous ? new char[strlen(expr)+10] : buffer;
strcpy(ibuff,expr);
if (append_semicolon) strcat(ibuff,";");
if (synchronous) strcat(ibuff,"\n#q");
//cout << "*ibuff " << ibuff;
Parser::state.lineno = 0; // reset error state and go for it...
Parser::state.file = "";
bool old_compile_flag = Parser::debug.compile_program;
Parser::debug.compile_program = false;
Input::insert_stream(new istrstream(ibuff),name ? name : "$EXPR",lineno);
if (synchronous) {
int ret = call_parser();
delete ibuff;
Parser::debug.compile_program = old_compile_flag;
if (ret == OK) {
if (Engine::paused()) return HALTED;
if (Parser::state.lineno > 0) return CRASHED;
}
return ret;
}
else {
Parser::debug.compile_program = old_compile_flag;
return PENDING;
}
}
// *change 1.2.8 May be passed an optional (file,position) for
// incremental compilation. In this mode, we force compilation
// to occur in global context.
int redirected_eval(char *s, bool do_semi, char *name=NULL, int lineno=0)
{
Table* tbl = &Parser::state.context();
bool pushing_context = false;
if (name != NULL && tbl != &Parser::global()) {
Parser::state.push_context(&Parser::global());
pushing_context = true;
}
// synchronous execution
Errors::redirect_output(true);
int ret = uc_eval(s,do_semi,true,name,lineno);
Errors::check_output(); // make sure errors & messages no longer redirected
if (pushing_context) { // restore context
Parser::state.pop_context();
if (ret == HALTED) ret = OK; // engine state was halted; no problem
}
return ret;
}
void save_parser_state();
void restore_parser_state();
// *add 1.2.4 exported as uc_exec()
int _uc_exec(char* s, void* cntxt, char* filename, int line)
{
string file;
int lineno;
// protect the temporary code block from being trashed
Instruction* immed_code = Parser::immediate_code_ptr();
Parser::immediate_code_ptr(NULL);
// redirect errors and messages
Errors::reset_error_state();
Errors::redirect_output(true);
// keep old parser state for later
Parser::ParserState old_state = Parser::state;
dcl_set(false,false); // save the DCL & ALS stacks...
save_parser_state(); // save the BISON state...
// do the compilation/evaluation, using the context if requested.
if (cntxt) Parser::state.push_context((Table*)cntxt);
int ret = uc_eval(s,false,true,filename,line);
if (cntxt) Parser::state.pop_context();
// reset parser state, but make sure the error state is kept!
file = Parser::state.file;
lineno = Parser::state.lineno;
restore_parser_state();
dcl_reset();
Parser::state = old_state;
Parser::state.file = file;
Parser::state.lineno = lineno;
// make sure errors & messages no longer redirected
Errors::check_output();
Parser::immediate_code_ptr(immed_code);
return ret;
}
// *add 1.2.4 exported as uc_result()
void _uc_result(int ret, char *output, int sz, char* filename, int* line)
{
char *out;
if (ret==OK) out = Errors::get_redirect_buffer(1);
else out = Errors::get_redirect_buffer(2);
strncpy(output,out,sz);
if (filename) {
*line = Errors::get_stop_position(filename);
}
}
int ext_uc_eval(char *expr, char *output, int sz)
{
int ret = redirected_eval(expr,true);
_uc_result(ret,output,sz,0,0);
return ret;
}
bool s_single_step = false;
static char* gCurrentArgs = "";
int ext_run_program(char *cmdline, int stepping)
{
Errors::redirect_output(true,false);
char buff[256];
strcpy(buff,cmdline);
if (stepping) { Engine::set_single_stepping(stepping == 1); } // *HACK*
if (Program::run(buff)) return 0; // main() not found!
else return 1;
}
bool insert_input_file(char *filename)
{
ifstream *pfs = new ifstream(filename,IOS_IN_FLAGS);
if (!(*pfs)) {
delete pfs;
return false;
}
Input::insert_stream(pfs,filename);
return true;
}
int safe_atoi(char *str)
{
return str==NULL ? 0 : atoi(str);
}
bool command_error(char *msg, char *sym=NULL)
{
cerr << msg;
if (sym != NULL) cerr << '\'' << sym << '\'';
cerr << endl;
return true;
}
bool cant_open_err(char *cfile)
{ return command_error("Cannot open",cfile); }
bool cant_find(char *name)
{ return command_error("Cannot find",name); }
static char *TMPFILE = "_tmp010_u.txt";
void uc_system(char *cmd)
{
#ifndef _WCON
system(cmd);
#else
int exec(char *msg, int cshow, bool do_wait);
const int BUFFSIZE = 200;
char buff[BUFFSIZE];
// The idea here is to direct output to a temporary
// (if not already redirecting!) and dump this file.
string spath = getenv("COMSPEC"); // Win32 warning...
string cmdl = spath + " /c " + string(cmd);
bool redirect_stdout = cmdl.find(">") == -1;
if(redirect_stdout) { cmdl += " > "; cmdl += TMPFILE; }
exec(cmdl.c_str(),0,true);
if(redirect_stdout) {
ifstream inf(TMPFILE,IOS_IN_FLAGS);
if (!inf) return;
while (!inf.eof()) {
inf.getline(buff,BUFFSIZE);
puts(buff);
}
}
#endif
}
char *get_temp_log()
{
static char buff[30];
struct tm *ts;
time_t t;
time(&t);
ts = localtime(&t);
ts->tm_mon++;
sprintf(buff,"%02d%02d-%02d%02d",ts->tm_mon,ts->tm_mday,ts->tm_hour,ts->tm_min);
return buff;
}
// *add 1.2.1 Getting interactive help
string uc_home_dir(); // forward
void show_help(char* help_text, char* cmd, char marker)
{
char buff[256];
string help_file = uc_home_dir()+"/";
help_file += help_text;
ifstream in(help_file.c_str(),IOS_IN_FLAGS);
if (! in) { cerr << "cannot find " << help_file << endl; return; }
if (cmd && *cmd == marker) cmd++;
while (! in.eof()) {
in.getline(buff,sizeof(buff));
if (buff[0] == marker) {
if (! cmd) cmsg << buff << endl;
else {
if (strncmp(cmd,buff+1,strlen(cmd))==0) {
buff[0] = ' ';
while (buff[0] != marker) {
cmsg << buff << endl;
in.getline(buff,sizeof(buff));
}
return;
}
}
}
}
}
//* #endif
// *change 1.2.8 added more control on whether one wants the contents of the parent
// context as well.
void display_locals(Table *tbl, void *pobj, bool is_ptr = false, bool do_all = false)
{
// *add 1.1.2 Will dereference a pointer or reference variable
const int LOCALBUFF = 1024;
char buff[LOCALBUFF];
bool pushing_context = tbl != NULL;
if (!pushing_context) tbl = &Parser::state.context();
else {
Parser::state.push_context(tbl);
if (is_ptr) pobj = *(void **)pobj;
Engine::object_ptr(pobj);
}
ostrstream os(buff,LOCALBUFF);
int flags = Table::SEMICOLON_SEP | Table::VARS;
if (do_all) flags |= Table::ALL;
tbl->dump_entries(os,flags);
os << ends;
Parser::debug.no_access_control = true;
uc_eval(buff,false,true);
Parser::debug.no_access_control = false;
if (pushing_context) Parser::state.pop_context();
}
/// These guys bracket every LOAD operation; the idea here
/// is to clean up any namespace pollution so that
/// the module compilation won't be bothered. Afterwards,
/// the crud is put back in.
/// *add 1.2.0 Any files with extension ".c" are loaded in C-mode
/// *add 1.2.3 Ditto, files with extension .c, .cpp or .cxx loaded in _strict mode_
/// This will attempt to enforce the standard language as much as possible.
/// *add 1.2.9 Managing the program ODL (Object Destructor List)
/// The basic assumption around here is that compile_module() is _not_ reentrant;
/// e.g. using #l within a file loaded with #l is not guaranteed to work properly.
static bool s_last_c_mode, s_last_strict_mode, s_is_cpp_source = false, s_is_conditional;
// only called if the file could be opened...
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -