mirror of
https://github.com/cheat-engine/cheat-engine
synced 2026-08-15 02:26:08 -04:00
285 lines
6.8 KiB
C++
285 lines
6.8 KiB
C++
|
|
/* uc_tokens.cpp
|
||
|
|
* Specialized tokenizer for C++ lexical scanner
|
||
|
|
* UnderC C++ interpreter
|
||
|
|
* Steve Donovan, 2001
|
||
|
|
* This is GPL'd software, and the usual disclaimers apply.
|
||
|
|
* See LICENCE
|
||
|
|
*
|
||
|
|
* UCTokenStream specializes the general C tokenizer TokenStream
|
||
|
|
* by overriding things like macro handling and the interactive prompt.
|
||
|
|
* The user_cmd() virtual method is overriden in main.cpp
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <time.h>
|
||
|
|
#include "common.h"
|
||
|
|
#include "module.h"
|
||
|
|
#include "uc_tokens.h"
|
||
|
|
#include "version.h"
|
||
|
|
#include "errors.h"
|
||
|
|
|
||
|
|
// *fix 1.2.7 full strftime() flags not supported with MSC++ 6.0
|
||
|
|
#ifndef _MSC_VER
|
||
|
|
#define DATE_FORMAT "%b %e %G"
|
||
|
|
#define TIME_FORMAT "%T"
|
||
|
|
#else
|
||
|
|
#define DATE_FORMAT "%x"
|
||
|
|
#define TIME_FORMAT "%X"
|
||
|
|
#endif
|
||
|
|
|
||
|
|
bool check_error(); // in parser.y
|
||
|
|
bool interactive_mode(); // in main.cpp
|
||
|
|
|
||
|
|
enum {BM_LINE=1, BM_FILE, BM_UNDERC, BM_NOVALUE, BM_DATE, BM_TIME, BM_EMPTY};
|
||
|
|
|
||
|
|
void add_builtin_macro(const char* name)
|
||
|
|
{
|
||
|
|
TokenStream::macro_builtin(name,BM_NOVALUE);
|
||
|
|
}
|
||
|
|
|
||
|
|
void UCTokenStream::init()
|
||
|
|
{
|
||
|
|
macro_builtin("__LINE__",BM_LINE);
|
||
|
|
macro_builtin("__FILE__",BM_FILE);
|
||
|
|
macro_builtin("__DATE__",BM_DATE);
|
||
|
|
macro_builtin("__TIME__",BM_TIME);
|
||
|
|
macro_builtin("__UNDERC__",BM_UNDERC);
|
||
|
|
macro_builtin("__cplusplus",BM_NOVALUE);
|
||
|
|
#ifdef _CONSOLE
|
||
|
|
macro_builtin("_CONSOLE",BM_NOVALUE);
|
||
|
|
#endif
|
||
|
|
#ifdef _USRDLL
|
||
|
|
macro_builtin("_USRDLL",BM_NOVALUE);
|
||
|
|
#endif
|
||
|
|
#ifdef __unix__
|
||
|
|
# ifdef __linux__
|
||
|
|
macro_builtin("__linux__",BM_NOVALUE);
|
||
|
|
# endif
|
||
|
|
# ifdef __FreeBSD__
|
||
|
|
macro_builtin("__FreeBSD__",BM_NOVALUE);
|
||
|
|
# endif
|
||
|
|
macro_builtin("__unix__",BM_NOVALUE);
|
||
|
|
#else
|
||
|
|
# ifdef __BEOS__
|
||
|
|
macro_builtin("__beos__",BM_NOVALUE);
|
||
|
|
macro_builtin("__BEOS__",BM_NOVALUE); /* that's the official one */
|
||
|
|
# else
|
||
|
|
macro_builtin("__win32__",BM_NOVALUE);
|
||
|
|
# endif
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef _MSC_VER
|
||
|
|
macro_builtin("__MS_BUILT",BM_NOVALUE);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if (Parser::debug.range_check)
|
||
|
|
macro_builtin("_RANGE_CHECK",BM_NOVALUE);
|
||
|
|
|
||
|
|
// *hack 1.0.0 Until these keywords are implemented...
|
||
|
|
macro_builtin("mutable", BM_EMPTY);
|
||
|
|
macro_builtin("inline", BM_EMPTY);
|
||
|
|
macro_builtin("typename",BM_EMPTY);
|
||
|
|
macro_builtin("register",BM_EMPTY);
|
||
|
|
macro_builtin("volatile",BM_EMPTY);
|
||
|
|
}
|
||
|
|
|
||
|
|
void UCTokenStream::handle_builtin_macro(char *tbuff, int id)
|
||
|
|
{
|
||
|
|
time_t t;
|
||
|
|
char buff[120];
|
||
|
|
switch(id) {
|
||
|
|
case BM_LINE:
|
||
|
|
itoa(lineno(),tbuff,10);
|
||
|
|
break;
|
||
|
|
case BM_FILE:
|
||
|
|
quote_str(tbuff,file().c_str());
|
||
|
|
break;
|
||
|
|
case BM_DATE: // *fix 1.2.6 same format as CPP
|
||
|
|
time(&t);
|
||
|
|
strftime(buff,sizeof(buff),DATE_FORMAT,localtime(&t));
|
||
|
|
quote_str(tbuff,buff);
|
||
|
|
break;
|
||
|
|
case BM_TIME:
|
||
|
|
time(&t);
|
||
|
|
strftime(buff,sizeof(buff),TIME_FORMAT,localtime(&t));
|
||
|
|
quote_str(tbuff,buff);
|
||
|
|
break;
|
||
|
|
case BM_EMPTY:
|
||
|
|
strcpy(tbuff," ");
|
||
|
|
break;
|
||
|
|
case BM_UNDERC:
|
||
|
|
quote_str(tbuff,mUCVersion);
|
||
|
|
break;
|
||
|
|
case BM_NOVALUE:
|
||
|
|
strcpy(tbuff,"1");
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void UCTokenStream::on_add_macro(char *name, PMEntry pme)
|
||
|
|
{
|
||
|
|
Module::current()->add_macro(name);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// used to explicitly flag the statement/command as finished and not 'hanging'
|
||
|
|
// so we can change the prompt (*add 1.1.0)
|
||
|
|
bool s_hanging_statement;
|
||
|
|
|
||
|
|
void next_statement()
|
||
|
|
{
|
||
|
|
s_hanging_statement = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
int tstack_depth(); // *DEBUG*
|
||
|
|
|
||
|
|
void UCTokenStream::do_prompt()
|
||
|
|
{
|
||
|
|
Parser::state.context().add_line_no(file(),lineno());
|
||
|
|
if(is_interactive()) {
|
||
|
|
#ifdef _USE_READLINE
|
||
|
|
ostrstream out (get_prompt_buffer(),MAX_PROMPT_SIZE);
|
||
|
|
#else
|
||
|
|
ostream& out = cout;
|
||
|
|
#endif
|
||
|
|
int bdepth = Parser::block_depth();
|
||
|
|
out << ';';
|
||
|
|
if (is_in_comment()) out << "*/";
|
||
|
|
#ifdef _DEBUG
|
||
|
|
else if (Parser::is_in_declaration()) out << "DCL> ";
|
||
|
|
#endif
|
||
|
|
else if (bdepth > 0) out << bdepth << '}';
|
||
|
|
else if (s_hanging_statement) out << ';';
|
||
|
|
else { out << '>'; s_hanging_statement = true; }
|
||
|
|
out << ' ';
|
||
|
|
#ifdef _USE_READLINE
|
||
|
|
out << ends;
|
||
|
|
#else
|
||
|
|
cout.flush(); // iostream.h requires this!
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void UCTokenStream::on_hash_cmd()
|
||
|
|
{
|
||
|
|
next_statement();
|
||
|
|
}
|
||
|
|
|
||
|
|
// *add 1.2.5 support for #if expressions
|
||
|
|
int _uc_exec(char* s, void* cntxt, char* filename, int line); // in main.cpp
|
||
|
|
static int sResult;
|
||
|
|
|
||
|
|
static void eval_expr(PExpr e)
|
||
|
|
{
|
||
|
|
sResult = Parser::const_int_expr(e);
|
||
|
|
}
|
||
|
|
|
||
|
|
int UCTokenStream::eval_const_expr(const char* expr)
|
||
|
|
{
|
||
|
|
char buff[160];
|
||
|
|
strcpy(buff,expr);
|
||
|
|
strcat(buff,";");
|
||
|
|
sResult = 1;
|
||
|
|
Parser::set_expression_handler(eval_expr);
|
||
|
|
int ret = _uc_exec(buff,0,0,0);
|
||
|
|
Parser::set_expression_handler(NULL);
|
||
|
|
if (ret != 0) {
|
||
|
|
cerr << "Can't evaluate " << expr << " in #if" << endl;
|
||
|
|
return 1;
|
||
|
|
} else
|
||
|
|
return sResult;
|
||
|
|
}
|
||
|
|
|
||
|
|
static std::list<string> s_file_targets;
|
||
|
|
static std::list<RESTOREFN> s_restore_fn;
|
||
|
|
|
||
|
|
void UCTokenStream::set_restore_op(RESTOREFN fn) {
|
||
|
|
s_file_targets.push_back(m_original_file);
|
||
|
|
s_restore_fn.push_back(m_restore);
|
||
|
|
m_restore = fn;
|
||
|
|
m_original_file = file();
|
||
|
|
}
|
||
|
|
|
||
|
|
void UCTokenStream::set_open_op(RESTOREFN fn) {
|
||
|
|
m_openfn = fn;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void UCTokenStream::on_open()
|
||
|
|
{
|
||
|
|
Module::set_current(file(),true);
|
||
|
|
if (m_openfn) {
|
||
|
|
(*m_openfn)();
|
||
|
|
m_openfn = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void UCTokenStream::on_restore()
|
||
|
|
{
|
||
|
|
Module::set_current(file(),false);
|
||
|
|
if (m_restore && file() == m_original_file) {
|
||
|
|
(*m_restore)();
|
||
|
|
Errors::check_output();
|
||
|
|
m_original_file = s_file_targets.back();
|
||
|
|
m_restore = s_restore_fn.back();
|
||
|
|
s_file_targets.pop_back();
|
||
|
|
s_restore_fn.pop_back();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// *add 1.2.9 the module traceback list
|
||
|
|
struct FileRef {
|
||
|
|
string filename;
|
||
|
|
int lineno;
|
||
|
|
};
|
||
|
|
|
||
|
|
typedef std::list<FileRef> FileRefList;
|
||
|
|
static FileRefList mModuleTraceList;
|
||
|
|
|
||
|
|
void dump_module_traceback()
|
||
|
|
{
|
||
|
|
while (mModuleTraceList.size() > 0) {
|
||
|
|
FileRef& fr = mModuleTraceList.front();
|
||
|
|
cmsg << fr.filename << ' ' << fr.lineno << ": (included from)" << endl;
|
||
|
|
mModuleTraceList.pop_front();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void UCTokenStream::on_clear(const string& filename, int line)
|
||
|
|
{
|
||
|
|
if (! Parser::debug.interactive_debugging)
|
||
|
|
cerr << "included from " << filename << ' ' << line << endl;
|
||
|
|
else
|
||
|
|
{
|
||
|
|
FileRef fr;
|
||
|
|
fr.filename = filename;
|
||
|
|
fr.lineno = line;
|
||
|
|
mModuleTraceList.push_back(fr);
|
||
|
|
}
|
||
|
|
Module* pm = Module::from_name(filename);
|
||
|
|
if (pm) pm->clean_macros_and_typedefs();
|
||
|
|
}
|
||
|
|
|
||
|
|
void UCTokenStream::on_error(const char *msg, bool is_error)
|
||
|
|
{
|
||
|
|
if (is_error) {
|
||
|
|
error(msg);
|
||
|
|
check_error();
|
||
|
|
throw string(msg);
|
||
|
|
}
|
||
|
|
else warning(msg);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool UCTokenStream::next_two(char *ts, bool skip)
|
||
|
|
{
|
||
|
|
if (look_ahead()==ts[0] && peek_ahead(1)==ts[1]) {
|
||
|
|
if (skip) { next(); next(); }
|
||
|
|
return true;
|
||
|
|
} else return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool UCTokenStream::is_interactive_mode()
|
||
|
|
{
|
||
|
|
return interactive_mode();
|
||
|
|
}
|