diff --git a/src/emu/cheat.c b/src/emu/cheat.c index 151dbfc04ff..2ba822089c7 100644 --- a/src/emu/cheat.c +++ b/src/emu/cheat.c @@ -108,7 +108,6 @@ #include "uimenu.h" #include "cheat.h" #include "debug/debugcpu.h" -#include "debug/express.h" #include @@ -198,7 +197,7 @@ cheat_parameter::cheat_parameter(cheat_manager &manager, symbol_table &symbols, } // add a variable to the symbol table for our value - symtable_add_register(&symbols, "param", &m_value, cheat_manager::variable_get, NULL); + symbols.add("param", symbol_table::READ_ONLY, &m_value); } @@ -432,20 +431,17 @@ void cheat_script::save(mame_file &cheatfile) const cheat_script::script_entry::script_entry(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &entrynode, bool isaction) : m_next(NULL), - m_condition(NULL), - m_expression(NULL), + m_condition(&symbols), + m_expression(&symbols), m_arglist(manager.machine().m_respool) { + const char *expression = NULL; try { // read the condition if present - const char *expression = xml_get_attribute_string(&entrynode, "condition", NULL); + expression = xml_get_attribute_string(&entrynode, "condition", NULL); if (expression != NULL) - { - EXPRERR experr = expression_parse(expression, &symbols, &debug_expression_callbacks, &manager.machine(), &m_condition); - if (experr != EXPRERR_NONE) - throw emu_fatalerror("%s.xml(%d): error parsing cheat expression \"%s\" (%s)\n", filename, entrynode.line, expression, exprerr_to_string(experr)); - } + m_condition.parse(expression); // if this is an action, parse the expression if (isaction) @@ -453,10 +449,7 @@ cheat_script::script_entry::script_entry(cheat_manager &manager, symbol_table &s expression = entrynode.value; if (expression == NULL || expression[0] == 0) throw emu_fatalerror("%s.xml(%d): missing expression in action tag\n", filename, entrynode.line); - - EXPRERR experr = expression_parse(expression, &symbols, &debug_expression_callbacks, &manager.machine(), &m_expression); - if (experr != EXPRERR_NONE) - throw emu_fatalerror("%s.xml(%d): error parsing cheat expression \"%s\" (%s)\n", filename, entrynode.line, expression, exprerr_to_string(experr)); + m_expression.parse(expression); } // otherwise, parse the attributes and arguments @@ -495,28 +488,13 @@ cheat_script::script_entry::script_entry(cheat_manager &manager, symbol_table &s validate_format(filename, entrynode.line); } } - catch (emu_fatalerror &) + catch (expression_error &err) { - // call our destructor and re-throw - this->~script_entry(); - throw; + throw emu_fatalerror("%s.xml(%d): error parsing cheat expression \"%s\" (%s)\n", filename, entrynode.line, expression, err.code_string()); } } -//------------------------------------------------- -// script_entry - destructor -//------------------------------------------------- - -cheat_script::script_entry::~script_entry() -{ - if (m_condition != NULL) - expression_free(m_condition); - if (m_expression != NULL) - expression_free(m_expression); -} - - //------------------------------------------------- // execute - execute a single script entry //------------------------------------------------- @@ -524,25 +502,32 @@ cheat_script::script_entry::~script_entry() void cheat_script::script_entry::execute(cheat_manager &manager, UINT64 &argindex) { // evaluate the condition - if (m_condition != NULL) + if (!m_condition.is_empty()) { - UINT64 result; - EXPRERR error = expression_execute(m_condition, &result); - if (error != EXPRERR_NONE) - mame_printf_warning("Error executing conditional expression \"%s\": %s\n", expression_original_string(m_condition), exprerr_to_string(error)); - - // if the condition is false, or we got an error, don't execute - if (error != EXPRERR_NONE || result == 0) + try + { + UINT64 result = m_condition.execute(); + if (result == 0) + return; + } + catch (expression_error &err) + { + mame_printf_warning("Error executing conditional expression \"%s\": %s\n", m_condition.original_string(), err.code_string()); return; + } } // if there is an action, execute it - if (m_expression != NULL) + if (!m_expression.is_empty()) { - UINT64 result; - EXPRERR error = expression_execute(m_expression, &result); - if (error != EXPRERR_NONE) - mame_printf_warning("Error executing expression \"%s\": %s\n", expression_original_string(m_expression), exprerr_to_string(error)); + try + { + m_expression.execute(); + } + catch (expression_error &err) + { + mame_printf_warning("Error executing expression \"%s\": %s\n", m_expression.original_string(), err.code_string()); + } } // if there is a string to display, compute it @@ -580,17 +565,17 @@ void cheat_script::script_entry::save(mame_file &cheatfile) const if (!m_format) { mame_fprintf(&cheatfile, "\t\t\t%s\n", cheat_manager::quote_expression(tempstring, *m_expression)); + if (!m_condition.is_empty()) + mame_fprintf(&cheatfile, " condition=\"%s\"", cheat_manager::quote_expression(tempstring, m_condition)); + mame_fprintf(&cheatfile, ">%s\n", cheat_manager::quote_expression(tempstring, m_expression)); } // output an output else { mame_fprintf(&cheatfile, "\t\t\t%s\n", cheat_manager::quote_expression(tempstring, *m_expression)); + mame_fprintf(&cheatfile, ">%s\n", cheat_manager::quote_expression(tempstring, m_expression)); } @@ -734,11 +719,10 @@ cheat_entry::cheat_entry(cheat_manager &manager, symbol_table &globaltable, cons m_off_script(NULL), m_change_script(NULL), m_run_script(NULL), - m_symbols(NULL), + m_symbols(&manager.machine(), &globaltable), m_state(SCRIPT_STATE_OFF), m_numtemp(DEFAULT_TEMP_VARIABLES), - m_argindex(0), - m_tempvar(NULL) + m_argindex(0) { // reset scripts try @@ -750,7 +734,6 @@ cheat_entry::cheat_entry(cheat_manager &manager, symbol_table &globaltable, cons // allocate memory for the cheat m_numtemp = tempcount; - m_tempvar = auto_alloc_array_clear(&manager.machine(), UINT64, tempcount); // get the description const char *description = xml_get_attribute_string(&cheatnode, "desc", NULL); @@ -759,11 +742,10 @@ cheat_entry::cheat_entry(cheat_manager &manager, symbol_table &globaltable, cons m_description = description; // create the symbol table - m_symbols = symtable_alloc(&globaltable, &manager.machine()); - symtable_add_register(m_symbols, "argindex", &m_argindex, cheat_manager::variable_get, NULL); + m_symbols.add("argindex", symbol_table::READ_ONLY, &m_argindex); astring tempname; for (int curtemp = 0; curtemp < tempcount; curtemp++) - symtable_add_register(m_symbols, tempname.format("temp%d", curtemp), &m_tempvar[curtemp], cheat_manager::variable_get, cheat_manager::variable_set); + m_symbols.add(tempname.format("temp%d", curtemp), symbol_table::READ_WRITE); // read the first comment node xml_data_node *commentnode = xml_get_sibling(cheatnode.child, "comment"); @@ -784,7 +766,7 @@ cheat_entry::cheat_entry(cheat_manager &manager, symbol_table &globaltable, cons if (paramnode != NULL) { // load this parameter - m_parameter = auto_alloc(&manager.machine(), cheat_parameter(manager, *m_symbols, filename, *paramnode)); + m_parameter = auto_alloc(&manager.machine(), cheat_parameter(manager, m_symbols, filename, *paramnode)); // only one parameter allowed paramnode = xml_get_sibling(paramnode->next, "parameter"); @@ -796,7 +778,7 @@ cheat_entry::cheat_entry(cheat_manager &manager, symbol_table &globaltable, cons for (xml_data_node *scriptnode = xml_get_sibling(cheatnode.child, "script"); scriptnode != NULL; scriptnode = xml_get_sibling(scriptnode->next, "script")) { // load this entry - cheat_script *curscript = auto_alloc(&manager.machine(), cheat_script(manager, *m_symbols, filename, *scriptnode)); + cheat_script *curscript = auto_alloc(&manager.machine(), cheat_script(manager, m_symbols, filename, *scriptnode)); // if we have a script already for this slot, it is an error cheat_script *&slot = script_for_state(curscript->state()); @@ -821,14 +803,11 @@ cheat_entry::cheat_entry(cheat_manager &manager, symbol_table &globaltable, cons cheat_entry::~cheat_entry() { - if (m_symbols != NULL) - symtable_free(m_symbols); auto_free(&m_manager.machine(), m_on_script); auto_free(&m_manager.machine(), m_off_script); auto_free(&m_manager.machine(), m_change_script); auto_free(&m_manager.machine(), m_run_script); auto_free(&m_manager.machine(), m_parameter); - auto_free(&m_manager.machine(), m_tempvar); } @@ -1110,7 +1089,8 @@ cheat_script *&cheat_entry::script_for_state(script_state state) cheat_manager::cheat_manager(running_machine &machine) : m_machine(machine), m_cheatlist(machine.m_respool), - m_disabled(true) + m_disabled(true), + m_symtable(&machine) { // if the cheat engine is disabled, we're done if (!options_get_bool(machine.options(), OPTION_CHEAT)) @@ -1120,27 +1100,20 @@ cheat_manager::cheat_manager(running_machine &machine) machine.add_notifier(MACHINE_NOTIFY_FRAME, frame_update_static); // create a global symbol table - m_symtable = symtable_alloc(NULL, &machine); - symtable_add_register(m_symtable, "frame", &m_framecount, variable_get, NULL); - symtable_add_function(m_symtable, "frombcd", NULL, 1, 1, execute_frombcd); - symtable_add_function(m_symtable, "tobcd", NULL, 1, 1, execute_tobcd); - - // load the cheats - reload(); + m_symtable.add("frame", symbol_table::READ_ONLY, &m_framecount); + m_symtable.add("frombcd", NULL, 1, 1, execute_frombcd); + m_symtable.add("tobcd", NULL, 1, 1, execute_tobcd); // we rely on the debugger expression callbacks; if the debugger isn't // enabled, we must jumpstart them manually if ((machine.debug_flags & DEBUG_FLAG_ENABLED) == 0) debug_cpu_init(&machine); -} + // configure for memory access (shared with debugger) + debug_cpu_configure_memory(machine, m_symtable); -//------------------------------------------------- -// ~cheat_manager - destructor -//------------------------------------------------- - -cheat_manager::~cheat_manager() -{ + // load the cheats + reload(); } @@ -1324,9 +1297,9 @@ astring &cheat_manager::get_output_astring(int row, int justify) // document //------------------------------------------------- -const char *cheat_manager::quote_expression(astring &string, parsed_expression &expression) +const char *cheat_manager::quote_expression(astring &string, const parsed_expression &expression) { - string.cpy(expression_original_string(&expression)); + string.cpy(expression.original_string()); string.replace(0, " && ", " and "); string.replace(0, " &&", " and "); @@ -1357,31 +1330,11 @@ const char *cheat_manager::quote_expression(astring &string, parsed_expression & } -//------------------------------------------------- -// variable_get - return the value of a variable -//------------------------------------------------- - -UINT64 cheat_manager::variable_get(void *globalref, void *ref) -{ - return *(UINT64 *)ref; -} - - -//------------------------------------------------- -// variable_set - set the value of a variable -//------------------------------------------------- - -void cheat_manager::variable_set(void *globalref, void *ref, UINT64 value) -{ - *(UINT64 *)ref = value; -} - - //------------------------------------------------- // execute_frombcd - convert a value from BCD //------------------------------------------------- -UINT64 cheat_manager::execute_frombcd(void *globalref, void *ref, UINT32 params, const UINT64 *param) +UINT64 cheat_manager::execute_frombcd(symbol_table &table, void *ref, int params, const UINT64 *param) { UINT64 value = param[0]; UINT64 multiplier = 1; @@ -1401,7 +1354,7 @@ UINT64 cheat_manager::execute_frombcd(void *globalref, void *ref, UINT32 params, // execute_tobcd - convert a value to BCD //------------------------------------------------- -UINT64 cheat_manager::execute_tobcd(void *globalref, void *ref, UINT32 params, const UINT64 *param) +UINT64 cheat_manager::execute_tobcd(symbol_table &table, void *ref, int params, const UINT64 *param) { UINT64 value = param[0]; UINT64 result = 0; @@ -1488,7 +1441,7 @@ void cheat_manager::load_cheats(const char *filename) for (xml_data_node *cheatnode = xml_get_sibling(mamecheatnode->child, "cheat"); cheatnode != NULL; cheatnode = xml_get_sibling(cheatnode->next, "cheat")) { // load this entry - cheat_entry *curcheat = auto_alloc(&m_machine, cheat_entry(*this, *m_symtable, filename, *cheatnode)); + cheat_entry *curcheat = auto_alloc(&m_machine, cheat_entry(*this, m_symtable, filename, *cheatnode)); // make sure we're not a duplicate cheat_entry *scannode = NULL; diff --git a/src/emu/cheat.h b/src/emu/cheat.h index 2f04388b235..bca1832dc6d 100644 --- a/src/emu/cheat.h +++ b/src/emu/cheat.h @@ -42,6 +42,7 @@ #ifndef __CHEAT_H__ #define __CHEAT_H__ +#include "debug/express.h" #include "ui.h" @@ -66,8 +67,6 @@ DECLARE_ENUM_OPERATORS(script_state) //************************************************************************** class cheat_manager; -typedef struct _symbol_table symbol_table; -typedef struct _parsed_expression parsed_expression; // ======================> number_and_format @@ -180,7 +179,6 @@ private: public: // construction/destruction script_entry(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &entrynode, bool isaction); - ~script_entry(); // getters script_entry *next() const { return m_next; } @@ -198,7 +196,6 @@ private: public: // construction/destruction output_argument(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &argnode); - ~output_argument(); // getters output_argument *next() const { return m_next; } @@ -211,7 +208,7 @@ private: private: // internal state output_argument * m_next; // link to next argument - parsed_expression * m_expression; // expression for argument + parsed_expression m_expression; // expression for argument UINT64 m_count; // number of repetitions }; @@ -220,8 +217,8 @@ private: // internal state script_entry * m_next; // link to next entry - parsed_expression * m_condition; // condition under which this is executed - parsed_expression * m_expression; // expression to execute + parsed_expression m_condition; // condition under which this is executed + parsed_expression m_expression; // expression to execute astring m_format; // string format to print simple_list m_arglist; // list of arguments INT8 m_line; // which line to print on @@ -304,11 +301,10 @@ private: cheat_script * m_off_script; // script to run when turning off cheat_script * m_change_script; // script to run when value changes cheat_script * m_run_script; // script to run each frame when on - symbol_table * m_symbols; // symbol table for this cheat + symbol_table m_symbols; // symbol table for this cheat script_state m_state; // current cheat state UINT32 m_numtemp; // number of temporary variables UINT64 m_argindex; // argument index variable - UINT64 * m_tempvar; // value of the temporary variables // constants static const int DEFAULT_TEMP_VARIABLES = 10; @@ -323,7 +319,6 @@ class cheat_manager public: // construction/destruction cheat_manager(running_machine &machine); - ~cheat_manager(); // getters running_machine &machine() const { return m_machine; } @@ -342,11 +337,9 @@ public: astring &get_output_astring(int row, int justify); // global helpers - static const char *quote_expression(astring &string, parsed_expression &expression); - static UINT64 variable_get(void *globalref, void *ref); - static void variable_set(void *globalref, void *ref, UINT64 value); - static UINT64 execute_frombcd(void *globalref, void *ref, UINT32 params, const UINT64 *param); - static UINT64 execute_tobcd(void *globalref, void *ref, UINT32 params, const UINT64 *param); + static const char *quote_expression(astring &string, const parsed_expression &expression); + static UINT64 execute_frombcd(symbol_table &table, void *ref, int params, const UINT64 *param); + static UINT64 execute_tobcd(symbol_table &table, void *ref, int params, const UINT64 *param); private: // internal helpers @@ -363,7 +356,7 @@ private: UINT8 m_numlines; // number of lines available for output INT8 m_lastline; // last line used for output bool m_disabled; // true if the cheat engine is disabled - symbol_table * m_symtable; // global symbol table + symbol_table m_symtable; // global symbol table // constants static const int CHEAT_VERSION = 1; @@ -371,4 +364,3 @@ private: #endif /* __CHEAT_H__ */ - diff --git a/src/emu/cpu/i386/i386.c b/src/emu/cpu/i386/i386.c index 93db8dea6f5..6eba89454a0 100644 --- a/src/emu/cpu/i386/i386.c +++ b/src/emu/cpu/i386/i386.c @@ -461,7 +461,7 @@ static void I386OP(decode_two_byte)(i386_state *cpustate) /*************************************************************************/ -static UINT64 i386_debug_segbase(void *globalref, void *ref, UINT32 params, const UINT64 *param) +static UINT64 i386_debug_segbase(symbol_table &table, void *ref, int params, const UINT64 *param) { legacy_cpu_device *device = (legacy_cpu_device *)ref; i386_state *cpustate = get_safe_token(device); @@ -482,7 +482,7 @@ static UINT64 i386_debug_segbase(void *globalref, void *ref, UINT32 params, cons return result; } -static UINT64 i386_debug_seglimit(void *globalref, void *ref, UINT32 params, const UINT64 *param) +static UINT64 i386_debug_seglimit(symbol_table &table, void *ref, int params, const UINT64 *param) { legacy_cpu_device *device = (legacy_cpu_device *)ref; i386_state *cpustate = get_safe_token(device); @@ -501,8 +501,8 @@ static UINT64 i386_debug_seglimit(void *globalref, void *ref, UINT32 params, con static CPU_DEBUG_INIT( i386 ) { - symtable_add_function(device->debug()->symtable(), "segbase", (void *)device, 1, 1, i386_debug_segbase); - symtable_add_function(device->debug()->symtable(), "seglimit", (void *)device, 1, 1, i386_debug_seglimit); + device->debug()->symtable().add("segbase", (void *)device, 1, 1, i386_debug_segbase); + device->debug()->symtable().add("seglimit", (void *)device, 1, 1, i386_debug_seglimit); } /*************************************************************************/ diff --git a/src/emu/debug/debugcmd.c b/src/emu/debug/debugcmd.c index dc4e644b6b4..ec9f9afe344 100644 --- a/src/emu/debug/debugcmd.c +++ b/src/emu/debug/debugcmd.c @@ -92,12 +92,12 @@ static cheat_system cheat; static void debug_command_exit(running_machine &machine); -static UINT64 execute_min(void *globalref, void *ref, UINT32 params, const UINT64 *param); -static UINT64 execute_max(void *globalref, void *ref, UINT32 params, const UINT64 *param); -static UINT64 execute_if(void *globalref, void *ref, UINT32 params, const UINT64 *param); +static UINT64 execute_min(symbol_table &table, void *ref, int params, const UINT64 *param); +static UINT64 execute_max(symbol_table &table, void *ref, int params, const UINT64 *param); +static UINT64 execute_if(symbol_table &table, void *ref, int params, const UINT64 *param); -static UINT64 global_get(void *globalref, void *ref); -static void global_set(void *globalref, void *ref, UINT64 value); +static UINT64 global_get(symbol_table &table, void *ref); +static void global_set(symbol_table &table, void *ref, UINT64 value); static void execute_help(running_machine *machine, int ref, int params, const char **param); static void execute_print(running_machine *machine, int ref, int params, const char **param); @@ -232,9 +232,9 @@ void debug_command_init(running_machine *machine) int itemnum; /* add a few simple global functions */ - symtable_add_function(symtable, "min", NULL, 2, 2, execute_min); - symtable_add_function(symtable, "max", NULL, 2, 2, execute_max); - symtable_add_function(symtable, "if", NULL, 3, 3, execute_if); + symtable->add("min", NULL, 2, 2, execute_min); + symtable->add("max", NULL, 2, 2, execute_max); + symtable->add("if", NULL, 3, 3, execute_if); /* add all single-entry save state globals */ for (itemnum = 0; itemnum < MAX_GLOBALS; itemnum++) @@ -254,7 +254,7 @@ void debug_command_init(running_machine *machine) sprintf(symname, ".%s", strrchr(name, '/') + 1); global_array[itemnum].base = base; global_array[itemnum].size = valsize; - symtable_add_register(symtable, symname, &global_array, global_get, global_set); + symtable->add(symname, &global_array, global_get, global_set); } } @@ -397,7 +397,7 @@ static void debug_command_exit(running_machine &machine) execute_min - return the minimum of two values -------------------------------------------------*/ -static UINT64 execute_min(void *globalref, void *ref, UINT32 params, const UINT64 *param) +static UINT64 execute_min(symbol_table &table, void *ref, int params, const UINT64 *param) { return (param[0] < param[1]) ? param[0] : param[1]; } @@ -407,7 +407,7 @@ static UINT64 execute_min(void *globalref, void *ref, UINT32 params, const UINT6 execute_max - return the maximum of two values -------------------------------------------------*/ -static UINT64 execute_max(void *globalref, void *ref, UINT32 params, const UINT64 *param) +static UINT64 execute_max(symbol_table &table, void *ref, int params, const UINT64 *param) { return (param[0] > param[1]) ? param[0] : param[1]; } @@ -417,7 +417,7 @@ static UINT64 execute_max(void *globalref, void *ref, UINT32 params, const UINT6 execute_if - if (a) return b; else return c; -------------------------------------------------*/ -static UINT64 execute_if(void *globalref, void *ref, UINT32 params, const UINT64 *param) +static UINT64 execute_if(symbol_table &table, void *ref, int params, const UINT64 *param) { return param[0] ? param[1] : param[2]; } @@ -432,7 +432,7 @@ static UINT64 execute_if(void *globalref, void *ref, UINT32 params, const UINT64 global_get - symbol table getter for globals -------------------------------------------------*/ -static UINT64 global_get(void *globalref, void *ref) +static UINT64 global_get(symbol_table &table, void *ref) { global_entry *global = (global_entry *)ref; switch (global->size) @@ -450,7 +450,7 @@ static UINT64 global_get(void *globalref, void *ref) global_set - symbol table setter for globals -------------------------------------------------*/ -static void global_set(void *globalref, void *ref, UINT64 value) +static void global_set(symbol_table &table, void *ref, UINT64 value) { global_entry *global = (global_entry *)ref; switch (global->size) @@ -475,22 +475,24 @@ static void global_set(void *globalref, void *ref, UINT64 value) int debug_command_parameter_number(running_machine *machine, const char *param, UINT64 *result) { - EXPRERR err; - /* NULL parameter does nothing and returns no error */ if (param == NULL) return TRUE; /* evaluate the expression; success if no error */ - err = expression_evaluate(param, debug_cpu_get_visible_symtable(machine), &debug_expression_callbacks, machine, result); - if (err == EXPRERR_NONE) + try + { + parsed_expression expression(debug_cpu_get_visible_symtable(machine), param, result); return TRUE; - - /* print an error pointing to the character that caused it */ - debug_console_printf(machine, "Error in expression: %s\n", param); - debug_console_printf(machine, " %*s^", EXPRERR_ERROR_OFFSET(err), ""); - debug_console_printf(machine, "%s\n", exprerr_to_string(err)); - return FALSE; + } + catch (expression_error &error) + { + /* print an error pointing to the character that caused it */ + debug_console_printf(machine, "Error in expression: %s\n", param); + debug_console_printf(machine, " %*s^", error.offset(), ""); + debug_console_printf(machine, "%s\n", error.code_string()); + return FALSE; + } } @@ -502,7 +504,6 @@ int debug_command_parameter_number(running_machine *machine, const char *param, int debug_command_parameter_cpu(running_machine *machine, const char *param, device_t **result) { UINT64 cpunum; - EXPRERR err; /* if no parameter, use the visible CPU */ if (param == NULL) @@ -522,8 +523,11 @@ int debug_command_parameter_cpu(running_machine *machine, const char *param, dev return TRUE; /* then evaluate as an expression; on an error assume it was a tag */ - err = expression_evaluate(param, debug_cpu_get_visible_symtable(machine), &debug_expression_callbacks, machine, &cpunum); - if (err != EXPRERR_NONE) + try + { + parsed_expression expression(debug_cpu_get_visible_symtable(machine), param, &cpunum); + } + catch (expression_error &) { debug_console_printf(machine, "Unable to find CPU '%s'\n", param); return FALSE; @@ -574,27 +578,26 @@ int debug_command_parameter_cpu_space(running_machine *machine, const char *para an expression parameter -------------------------------------------------*/ -static int debug_command_parameter_expression(running_machine *machine, const char *param, parsed_expression **result) +static int debug_command_parameter_expression(running_machine *machine, const char *param, parsed_expression &result) { - EXPRERR err; - /* NULL parameter does nothing and returns no error */ if (param == NULL) - { - *result = NULL; return TRUE; - } /* parse the expression; success if no error */ - err = expression_parse(param, debug_cpu_get_visible_symtable(machine), &debug_expression_callbacks, machine, result); - if (err == EXPRERR_NONE) + try + { + result.parse(param); return TRUE; - - /* output an error */ - debug_console_printf(machine, "Error in expression: %s\n", param); - debug_console_printf(machine, " %*s^", EXPRERR_ERROR_OFFSET(err), ""); - debug_console_printf(machine, "%s\n", exprerr_to_string(err)); - return FALSE; + } + catch (expression_error &err) + { + /* output an error */ + debug_console_printf(machine, "Error in expression: %s\n", param); + debug_console_printf(machine, " %*s^", err.offset(), ""); + debug_console_printf(machine, "%s\n", err.code_string()); + return FALSE; + } } @@ -1160,7 +1163,7 @@ static void execute_comment_save(running_machine *machine, int ref, int params, static void execute_bpset(running_machine *machine, int ref, int params, const char *param[]) { - parsed_expression *condition = NULL; + parsed_expression condition(debug_cpu_get_global_symtable(machine)); device_t *cpu; const char *action = NULL; UINT64 address; @@ -1171,7 +1174,7 @@ static void execute_bpset(running_machine *machine, int ref, int params, const c return; /* param 2 is the condition */ - if (!debug_command_parameter_expression(machine, param[1], &condition)) + if (!debug_command_parameter_expression(machine, param[1], condition)) return; /* param 3 is the action */ @@ -1183,7 +1186,7 @@ static void execute_bpset(running_machine *machine, int ref, int params, const c return; /* set the breakpoint */ - bpnum = cpu->debug()->breakpoint_set(address, condition, action); + bpnum = cpu->debug()->breakpoint_set(address, (condition.is_empty()) ? NULL : condition.original_string(), action); debug_console_printf(machine, "Breakpoint %X set\n", bpnum); } @@ -1300,7 +1303,7 @@ static void execute_bplist(running_machine *machine, int ref, int params, const static void execute_wpset(running_machine *machine, int ref, int params, const char *param[]) { - parsed_expression *condition = NULL; + parsed_expression condition(debug_cpu_get_global_symtable(machine)); address_space *space; const char *action = NULL; UINT64 address, length; @@ -1329,7 +1332,7 @@ static void execute_wpset(running_machine *machine, int ref, int params, const c } /* param 4 is the condition */ - if (!debug_command_parameter_expression(machine, param[3], &condition)) + if (!debug_command_parameter_expression(machine, param[3], condition)) return; /* param 5 is the action */ @@ -1341,7 +1344,7 @@ static void execute_wpset(running_machine *machine, int ref, int params, const c return; /* set the watchpoint */ - wpnum = space->cpu->debug()->watchpoint_set(*space, type, address, length, condition, action); + wpnum = space->cpu->debug()->watchpoint_set(*space, type, address, length, (condition.is_empty()) ? NULL : condition.original_string(), action); debug_console_printf(machine, "Watchpoint %X set\n", wpnum); } @@ -2544,7 +2547,7 @@ static void execute_symlist(running_machine *machine, int ref, int params, const if (cpu != NULL) { - symtable = cpu->debug()->symtable(); + symtable = &cpu->debug()->symtable(); debug_console_printf(machine, "CPU '%s' symbols:\n", cpu->tag()); } else @@ -2554,19 +2557,12 @@ static void execute_symlist(running_machine *machine, int ref, int params, const } /* gather names for all symbols */ - for (symnum = 0; symnum < 100000; symnum++) + for (symbol_entry *entry = symtable->first(); entry != NULL; entry = entry->next()) { - const symbol_entry *entry; - const char *name = symtable_find_indexed(symtable, symnum, &entry); - - /* if we didn't get anything, we're done */ - if (name == NULL) - break; - /* only display "register" type symbols */ - if (entry->type == SMT_REGISTER) + if (!entry->is_function()) { - namelist[count++] = name; + namelist[count++] = entry->name(); if (count >= ARRAY_LENGTH(namelist)) break; } @@ -2579,13 +2575,13 @@ static void execute_symlist(running_machine *machine, int ref, int params, const /* iterate over symbols and print out relevant ones */ for (symnum = 0; symnum < count; symnum++) { - const symbol_entry *entry = symtable_find(symtable, namelist[symnum]); - UINT64 value = (*entry->info.reg.getter)(symtable_get_globalref(entry->table), entry->ref); + const symbol_entry *entry = symtable->find(namelist[symnum]); assert(entry != NULL); + UINT64 value = entry->value(); /* only display "register" type symbols */ debug_console_printf(machine, "%s = %s", namelist[symnum], core_i64_hex_format(value, 0)); - if (entry->info.reg.setter == NULL) + if (!entry->is_lval()) debug_console_printf(machine, " (read-only)"); debug_console_printf(machine, "\n"); } diff --git a/src/emu/debug/debugcon.c b/src/emu/debug/debugcon.c index 78641ed6797..58073de9f7a 100644 --- a/src/emu/debug/debugcon.c +++ b/src/emu/debug/debugcon.c @@ -338,10 +338,15 @@ static CMDERR internal_parse_command(running_machine *machine, const char *origi /* if it smells like an assignment expression, treat it as such */ if (isexpr && paramcount == 1) { - UINT64 expresult; - EXPRERR exprerr = expression_evaluate(command_start, debug_cpu_get_visible_symtable(machine), &debug_expression_callbacks, machine, &expresult); - if (exprerr != EXPRERR_NONE) - return MAKE_CMDERR_EXPRESSION_ERROR(EXPRERR_ERROR_OFFSET(exprerr)); + try + { + UINT64 expresult; + parsed_expression expression(debug_cpu_get_visible_symtable(machine), command_start, &expresult); + } + catch (expression_error &err) + { + return MAKE_CMDERR_EXPRESSION_ERROR(err); + } } else { diff --git a/src/emu/debug/debugcpu.c b/src/emu/debug/debugcpu.c index 09d1acdee32..fcc03a2d6db 100644 --- a/src/emu/debug/debugcpu.c +++ b/src/emu/debug/debugcpu.c @@ -121,30 +121,13 @@ static UINT64 expression_read_memory_region(running_machine *machine, const char static void expression_write_memory(void *param, const char *name, int space, UINT32 address, int size, UINT64 data); static void expression_write_program_direct(address_space *space, int opcode, offs_t address, int size, UINT64 data); static void expression_write_memory_region(running_machine *machine, const char *rgntag, offs_t address, int size, UINT64 data); -static EXPRERR expression_validate(void *param, const char *name, int space); +static expression_error::error_code expression_validate(void *param, const char *name, int space); /* variable getters/setters */ -static UINT64 get_wpaddr(void *globalref, void *ref); -static UINT64 get_wpdata(void *globalref, void *ref); -static UINT64 get_cpunum(void *globalref, void *ref); -static UINT64 get_tempvar(void *globalref, void *ref); -static void set_tempvar(void *globalref, void *ref, UINT64 value); -static UINT64 get_beamx(void *globalref, void *ref); -static UINT64 get_beamy(void *globalref, void *ref); -static UINT64 get_frame(void *globalref, void *ref); - - - -/*************************************************************************** - GLOBAL CONSTANTS -***************************************************************************/ - -const express_callbacks debug_expression_callbacks = -{ - expression_read_memory, - expression_write_memory, - expression_validate -}; +static UINT64 get_cpunum(symbol_table &table, void *ref); +static UINT64 get_beamx(symbol_table &table, void *ref); +static UINT64 get_beamy(symbol_table &table, void *ref); +static UINT64 get_frame(symbol_table &table, void *ref); @@ -170,22 +153,25 @@ void debug_cpu_init(running_machine *machine) global->wpindex = 1; /* create a global symbol table */ - global->symtable = symtable_alloc(NULL, machine); + global->symtable = global_alloc(symbol_table(machine)); + + // configure our base memory accessors + debug_cpu_configure_memory(*machine, *global->symtable); /* add "wpaddr", "wpdata", "cycles", "cpunum", "logunmap" to the global symbol table */ - symtable_add_register(global->symtable, "wpaddr", NULL, get_wpaddr, NULL); - symtable_add_register(global->symtable, "wpdata", NULL, get_wpdata, NULL); - symtable_add_register(global->symtable, "cpunum", NULL, get_cpunum, NULL); - symtable_add_register(global->symtable, "beamx", (void *)first_screen, get_beamx, NULL); - symtable_add_register(global->symtable, "beamy", (void *)first_screen, get_beamy, NULL); - symtable_add_register(global->symtable, "frame", (void *)first_screen, get_frame, NULL); + global->symtable->add("wpaddr", symbol_table::READ_ONLY, &global->wpaddr); + global->symtable->add("wpdata", symbol_table::READ_ONLY, &global->wpdata); + global->symtable->add("cpunum", NULL, get_cpunum); + global->symtable->add("beamx", (void *)first_screen, get_beamx); + global->symtable->add("beamy", (void *)first_screen, get_beamy); + global->symtable->add("frame", (void *)first_screen, get_frame); /* add the temporary variables to the global symbol table */ for (regnum = 0; regnum < NUM_TEMP_VARIABLES; regnum++) { char symname[10]; sprintf(symname, "temp%d", regnum); - symtable_add_register(global->symtable, symname, &global->tempvar[regnum], get_tempvar, set_tempvar); + global->symtable->add(symname, symbol_table::READ_WRITE, &global->tempvar[regnum]); } /* first CPU is visible by default */ @@ -199,6 +185,12 @@ void debug_cpu_init(running_machine *machine) } +void debug_cpu_configure_memory(running_machine &machine, symbol_table &table) +{ + table.configure_memory(&machine, expression_validate, expression_read_memory, expression_write_memory); +} + + /*------------------------------------------------- debug_cpu_flush_traces - flushes all traces; this is useful if a trace is going on when we @@ -277,7 +269,7 @@ symbol_table *debug_cpu_get_global_symtable(running_machine *machine) symbol_table *debug_cpu_get_visible_symtable(running_machine *machine) { - return machine->debugcpu_data->visiblecpu->debug()->symtable(); + return &machine->debugcpu_data->visiblecpu->debug()->symtable(); } @@ -1071,8 +1063,8 @@ static void debug_cpu_exit(running_machine &machine) debugcpu_private *global = machine.debugcpu_data; /* free the global symbol table */ - if (global != NULL && global->symtable != NULL) - symtable_free(global->symtable); + if (global != NULL) + global_free(global->symtable); } @@ -1523,7 +1515,7 @@ static void expression_write_memory_region(running_machine *machine, const char appropriate name -------------------------------------------------*/ -static EXPRERR expression_validate(void *param, const char *name, int space) +static expression_error::error_code expression_validate(void *param, const char *name, int space) { running_machine *machine = (running_machine *)param; device_t *device = NULL; @@ -1538,12 +1530,12 @@ static EXPRERR expression_validate(void *param, const char *name, int space) { device = expression_get_device(machine, name); if (device == NULL) - return EXPRERR_INVALID_MEMORY_NAME; + return expression_error::INVALID_MEMORY_NAME; } if (device == NULL) device = debug_cpu_get_visible_cpu(machine); if (cpu_get_address_space(device, ADDRESS_SPACE_PROGRAM + (space - EXPSPACE_PROGRAM_LOGICAL)) == NULL) - return EXPRERR_NO_SUCH_MEMORY_SPACE; + return expression_error::NO_SUCH_MEMORY_SPACE; break; case EXPSPACE_PROGRAM_PHYSICAL: @@ -1554,12 +1546,12 @@ static EXPRERR expression_validate(void *param, const char *name, int space) { device = expression_get_device(machine, name); if (device == NULL) - return EXPRERR_INVALID_MEMORY_NAME; + return expression_error::INVALID_MEMORY_NAME; } if (device == NULL) device = debug_cpu_get_visible_cpu(machine); if (cpu_get_address_space(device, ADDRESS_SPACE_PROGRAM + (space - EXPSPACE_PROGRAM_PHYSICAL)) == NULL) - return EXPRERR_NO_SUCH_MEMORY_SPACE; + return expression_error::NO_SUCH_MEMORY_SPACE; break; case EXPSPACE_OPCODE: @@ -1568,22 +1560,22 @@ static EXPRERR expression_validate(void *param, const char *name, int space) { device = expression_get_device(machine, name); if (device == NULL) - return EXPRERR_INVALID_MEMORY_NAME; + return expression_error::INVALID_MEMORY_NAME; } if (device == NULL) device = debug_cpu_get_visible_cpu(machine); if (cpu_get_address_space(device, ADDRESS_SPACE_PROGRAM) == NULL) - return EXPRERR_NO_SUCH_MEMORY_SPACE; + return expression_error::NO_SUCH_MEMORY_SPACE; break; case EXPSPACE_REGION: if (name == NULL) - return EXPRERR_MISSING_MEMORY_NAME; + return expression_error::MISSING_MEMORY_NAME; if (memory_region(machine, name) == NULL) - return EXPRERR_INVALID_MEMORY_NAME; + return expression_error::INVALID_MEMORY_NAME; break; } - return EXPRERR_NONE; + return expression_error::NONE; } @@ -1596,7 +1588,7 @@ static EXPRERR expression_validate(void *param, const char *name, int space) get_beamx - get beam horizontal position -------------------------------------------------*/ -static UINT64 get_beamx(void *globalref, void *ref) +static UINT64 get_beamx(symbol_table &table, void *ref) { screen_device *screen = reinterpret_cast(ref); return (screen != NULL) ? screen->hpos() : 0; @@ -1607,7 +1599,7 @@ static UINT64 get_beamx(void *globalref, void *ref) get_beamy - get beam vertical position -------------------------------------------------*/ -static UINT64 get_beamy(void *globalref, void *ref) +static UINT64 get_beamy(symbol_table &table, void *ref) { screen_device *screen = reinterpret_cast(ref); return (screen != NULL) ? screen->vpos() : 0; @@ -1618,67 +1610,21 @@ static UINT64 get_beamy(void *globalref, void *ref) get_frame - get current frame number -------------------------------------------------*/ -static UINT64 get_frame(void *globalref, void *ref) +static UINT64 get_frame(symbol_table &table, void *ref) { screen_device *screen = reinterpret_cast(ref); return (screen != NULL) ? screen->frame_number() : 0; } -/*------------------------------------------------- - get_tempvar - getter callback for the - 'tempX' symbols --------------------------------------------------*/ - -static UINT64 get_tempvar(void *globalref, void *ref) -{ - return *(UINT64 *)ref; -} - - -/*------------------------------------------------- - set_tempvar - setter callback for the - 'tempX' symbols --------------------------------------------------*/ - -static void set_tempvar(void *globalref, void *ref, UINT64 value) -{ - *(UINT64 *)ref = value; -} - - -/*------------------------------------------------- - get_wpaddr - getter callback for the - 'wpaddr' symbol --------------------------------------------------*/ - -static UINT64 get_wpaddr(void *globalref, void *ref) -{ - running_machine *machine = (running_machine *)globalref; - return machine->debugcpu_data->wpaddr; -} - - -/*------------------------------------------------- - get_wpdata - getter callback for the - 'wpdata' symbol --------------------------------------------------*/ - -static UINT64 get_wpdata(void *globalref, void *ref) -{ - running_machine *machine = (running_machine *)globalref; - return machine->debugcpu_data->wpdata; -} - - /*------------------------------------------------- get_cpunum - getter callback for the 'cpunum' symbol -------------------------------------------------*/ -static UINT64 get_cpunum(void *globalref, void *ref) +static UINT64 get_cpunum(symbol_table &table, void *ref) { - running_machine *machine = (running_machine *)globalref; + running_machine *machine = reinterpret_cast(table.globalref()); device_t *target = machine->debugcpu_data->visiblecpu; device_execute_interface *exec = NULL; @@ -1709,7 +1655,7 @@ device_debug::device_debug(device_t &device) m_state(NULL), m_disasm(NULL), m_flags(0), - m_symtable(symtable_alloc(debug_cpu_get_global_symtable(device.machine), (void *)&device)), + m_symtable(&device, debug_cpu_get_global_symtable(device.machine)), m_instrhook(NULL), m_dasm_override(NULL), m_opwidth(0), @@ -1741,23 +1687,23 @@ device_debug::device_debug(device_t &device) { // add a global symbol for the current instruction pointer if (m_exec != NULL) - symtable_add_register(m_symtable, "cycles", NULL, get_cycles, NULL); + m_symtable.add("cycles", NULL, get_cycles); // add entries to enable/disable unmap reporting for each space if (m_memory != NULL) { if (m_memory->space(AS_PROGRAM) != NULL) - symtable_add_register(m_symtable, "logunmap", (void *)m_memory->space(AS_PROGRAM), get_logunmap, set_logunmap); + m_symtable.add("logunmap", (void *)m_memory->space(AS_PROGRAM), get_logunmap, set_logunmap); if (m_memory->space(AS_DATA) != NULL) - symtable_add_register(m_symtable, "logunmapd", (void *)m_memory->space(AS_DATA), get_logunmap, set_logunmap); + m_symtable.add("logunmapd", (void *)m_memory->space(AS_DATA), get_logunmap, set_logunmap); if (m_memory->space(AS_IO) != NULL) - symtable_add_register(m_symtable, "logunmapi", (void *)m_memory->space(AS_IO), get_logunmap, set_logunmap); + m_symtable.add("logunmapi", (void *)m_memory->space(AS_IO), get_logunmap, set_logunmap); } // add all registers into it astring tempstr; for (const device_state_entry *entry = m_state->state_first(); entry != NULL; entry = entry->next()) - symtable_add_register(m_symtable, tempstr.cpy(entry->symbol()).tolower(), (void *)(FPTR)entry->index(), get_cpu_reg, set_state); + m_symtable.add(tempstr.cpy(entry->symbol()).tolower(), (void *)(FPTR)entry->index(), get_state, set_state); } // set up execution-related stuff @@ -1767,8 +1713,8 @@ device_debug::device_debug(device_t &device) m_opwidth = min_opcode_bytes(); // if no curpc, add one - if (m_state != NULL && symtable_find(m_symtable, "curpc") == NULL) - symtable_add_register(m_symtable, "curpc", NULL, get_current_pc, 0); + if (m_state != NULL && m_symtable.find("curpc") == NULL) + m_symtable.add("curpc", NULL, get_current_pc); } } @@ -1779,10 +1725,6 @@ device_debug::device_debug(device_t &device) device_debug::~device_debug() { - // free the symbol table - if (m_symtable != NULL) - symtable_free(m_symtable); - // free breakpoints and watchpoints breakpoint_clear_all(); watchpoint_clear_all(); @@ -2337,10 +2279,10 @@ void device_debug::halt_on_next_instruction(const char *fmt, ...) // returning its index //------------------------------------------------- -int device_debug::breakpoint_set(offs_t address, parsed_expression *condition, const char *action) +int device_debug::breakpoint_set(offs_t address, const char *condition, const char *action) { // allocate a new one - breakpoint *bp = auto_alloc(m_device.machine, breakpoint(m_device.machine->debugcpu_data->bpindex++, address, condition, action)); + breakpoint *bp = auto_alloc(m_device.machine, breakpoint(m_symtable, m_device.machine->debugcpu_data->bpindex++, address, condition, action)); // hook it into our list bp->m_next = m_bplist; @@ -2426,12 +2368,12 @@ void device_debug::breakpoint_enable_all(bool enable) // returning its index //------------------------------------------------- -int device_debug::watchpoint_set(address_space &space, int type, offs_t address, offs_t length, parsed_expression *condition, const char *action) +int device_debug::watchpoint_set(address_space &space, int type, offs_t address, offs_t length, const char *condition, const char *action) { assert(space.spacenum() < ARRAY_LENGTH(m_wplist)); // allocate a new one - watchpoint *wp = auto_alloc(m_device.machine, watchpoint(m_device.machine->debugcpu_data->bpindex++, space, type, address, length, condition, action)); + watchpoint *wp = auto_alloc(m_device.machine, watchpoint(m_symtable, m_device.machine->debugcpu_data->bpindex++, space, type, address, length, condition, action)); // hook it into our list wp->m_next = m_wplist[space.spacenum()]; @@ -3115,9 +3057,9 @@ UINT32 device_debug::dasm_wrapped(astring &buffer, offs_t pc) // current instruction pointer //------------------------------------------------- -UINT64 device_debug::get_current_pc(void *globalref, void *ref) +UINT64 device_debug::get_current_pc(symbol_table &table, void *ref) { - device_t *device = reinterpret_cast(globalref); + device_t *device = reinterpret_cast(table.globalref()); return device->debug()->pc(); } @@ -3127,9 +3069,9 @@ UINT64 device_debug::get_current_pc(void *globalref, void *ref) // 'cycles' symbol //------------------------------------------------- -UINT64 device_debug::get_cycles(void *globalref, void *ref) +UINT64 device_debug::get_cycles(symbol_table &table, void *ref) { - device_t *device = reinterpret_cast(globalref); + device_t *device = reinterpret_cast(table.globalref()); return device->debug()->m_exec->cycles_remaining(); } @@ -3139,9 +3081,9 @@ UINT64 device_debug::get_cycles(void *globalref, void *ref) // symbols //------------------------------------------------- -UINT64 device_debug::get_logunmap(void *globalref, void *ref) +UINT64 device_debug::get_logunmap(symbol_table &table, void *ref) { - address_space *space = reinterpret_cast(ref); + address_space *space = reinterpret_cast(table.globalref()); return space->log_unmap(); } @@ -3151,9 +3093,9 @@ UINT64 device_debug::get_logunmap(void *globalref, void *ref) // symbols //------------------------------------------------- -void device_debug::set_logunmap(void *globalref, void *ref, UINT64 value) +void device_debug::set_logunmap(symbol_table &table, void *ref, UINT64 value) { - address_space *space = reinterpret_cast(ref); + address_space *space = reinterpret_cast(table.globalref()); space->set_log_unmap(value ? true : false); } @@ -3163,9 +3105,9 @@ void device_debug::set_logunmap(void *globalref, void *ref, UINT64 value) // state symbols //------------------------------------------------- -UINT64 device_debug::get_cpu_reg(void *globalref, void *ref) +UINT64 device_debug::get_state(symbol_table &table, void *ref) { - device_t *device = reinterpret_cast(globalref); + device_t *device = reinterpret_cast(table.globalref()); return device->debug()->m_state->state(reinterpret_cast(ref)); } @@ -3175,9 +3117,9 @@ UINT64 device_debug::get_cpu_reg(void *globalref, void *ref) // state symbols //------------------------------------------------- -void device_debug::set_state(void *globalref, void *ref, UINT64 value) +void device_debug::set_state(symbol_table &table, void *ref, UINT64 value) { - device_t *device = reinterpret_cast(globalref); + device_t *device = reinterpret_cast(table.globalref()); device->debug()->m_state->set_state(reinterpret_cast(ref), value); } @@ -3191,28 +3133,17 @@ void device_debug::set_state(void *globalref, void *ref, UINT64 value) // breakpoint - constructor //------------------------------------------------- -device_debug::breakpoint::breakpoint(int index, offs_t address, parsed_expression *condition, const char *action) +device_debug::breakpoint::breakpoint(symbol_table &symbols, int index, offs_t address, const char *condition, const char *action) : m_next(NULL), m_index(index), m_enabled(true), m_address(address), - m_condition(condition), + m_condition(&symbols, (condition != NULL) ? condition : "1"), m_action((action != NULL) ? action : "") { } -//------------------------------------------------- -// ~breakpoint - destructor -//------------------------------------------------- - -device_debug::breakpoint::~breakpoint() -{ - if (m_condition != NULL) - expression_free(m_condition); -} - - //------------------------------------------------- // hit - detect a hit //------------------------------------------------- @@ -3228,9 +3159,17 @@ bool device_debug::breakpoint::hit(offs_t pc) return false; // must satisfy the condition - UINT64 result; - if (m_condition != NULL && expression_execute(m_condition, &result) == EXPRERR_NONE && result == 0) - return false; + if (!m_condition.is_empty()) + { + try + { + return (m_condition.execute() != 0); + } + catch (expression_error &err) + { + return false; + } + } return true; } @@ -3245,7 +3184,7 @@ bool device_debug::breakpoint::hit(offs_t pc) // watchpoint - constructor //------------------------------------------------- -device_debug::watchpoint::watchpoint(int index, address_space &space, int type, offs_t address, offs_t length, parsed_expression *condition, const char *action) +device_debug::watchpoint::watchpoint(symbol_table &symbols, int index, address_space &space, int type, offs_t address, offs_t length, const char *condition, const char *action) : m_next(NULL), m_space(space), m_index(index), @@ -3253,23 +3192,12 @@ device_debug::watchpoint::watchpoint(int index, address_space &space, int type, m_type(type), m_address(space.address_to_byte(address) & space.bytemask()), m_length(space.address_to_byte(length)), - m_condition(condition), + m_condition(&symbols, (condition != NULL) ? condition : "1"), m_action((action != NULL) ? action : "") { } -//------------------------------------------------- -// ~watchpoint - destructor -//------------------------------------------------- - -device_debug::watchpoint::~watchpoint() -{ - if (m_condition != NULL) - expression_free(m_condition); -} - - //------------------------------------------------- // hit - detect a hit //------------------------------------------------- @@ -3289,10 +3217,17 @@ bool device_debug::watchpoint::hit(int type, offs_t address, int size) return false; // must satisfy the condition - UINT64 result; - if (m_condition != NULL && expression_execute(m_condition, &result) == EXPRERR_NONE && result == 0) - return false; - + if (!m_condition.is_empty()) + { + try + { + return (m_condition.execute() != 0); + } + catch (expression_error &err) + { + return false; + } + } return true; } diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h index 584e70d9147..b40e24eccef 100644 --- a/src/emu/debug/debugcpu.h +++ b/src/emu/debug/debugcpu.h @@ -79,15 +79,14 @@ public: public: // construction/destruction - breakpoint(int index, offs_t address, parsed_expression *condition = NULL, const char *action = NULL); - ~breakpoint(); + breakpoint(symbol_table &symbols, int index, offs_t address, const char *condition = NULL, const char *action = NULL); // getters breakpoint *next() const { return m_next; } int index() const { return m_index; } bool enabled() const { return m_enabled; } offs_t address() const { return m_address; } - const char *condition() const { return (m_condition != NULL) ? expression_original_string(m_condition) : NULL; } + const char *condition() const { return m_condition.original_string(); } const char *action() const { return m_action; } private: @@ -98,7 +97,7 @@ public: int m_index; // user reported index UINT8 m_enabled; // enabled? offs_t m_address; // execution address - parsed_expression * m_condition; // condition + parsed_expression m_condition; // condition astring m_action; // action }; @@ -109,8 +108,7 @@ public: public: // construction/destruction - watchpoint(int index, address_space &space, int type, offs_t address, offs_t length, parsed_expression *condition = NULL, const char *action = NULL); - ~watchpoint(); + watchpoint(symbol_table &symbols, int index, address_space &space, int type, offs_t address, offs_t length, const char *condition = NULL, const char *action = NULL); // getters watchpoint *next() const { return m_next; } @@ -120,7 +118,7 @@ public: bool enabled() const { return m_enabled; } offs_t address() const { return m_address; } offs_t length() const { return m_length; } - const char *condition() const { return (m_condition != NULL) ? expression_original_string(m_condition) : NULL; } + const char *condition() const { return m_condition.original_string(); } const char *action() const { return m_action; } private: @@ -134,7 +132,7 @@ public: UINT8 m_type; // type (read/write) offs_t m_address; // start address offs_t m_length; // length of watch area - parsed_expression * m_condition; // condition + parsed_expression m_condition; // condition astring m_action; // action }; @@ -144,7 +142,7 @@ public: ~device_debug(); // getters - symbol_table *symtable() const { return m_symtable; } + symbol_table &symtable() { return m_symtable; } // commonly-used pass-throughs offs_t pc() const { return (m_state != NULL) ? m_state->pc() : 0; } @@ -188,7 +186,7 @@ public: // breakpoints breakpoint *breakpoint_first() const { return m_bplist; } - int breakpoint_set(offs_t address, parsed_expression *condition = NULL, const char *action = NULL); + int breakpoint_set(offs_t address, const char *condition = NULL, const char *action = NULL); bool breakpoint_clear(int index); void breakpoint_clear_all(); bool breakpoint_enable(int index, bool enable = true); @@ -196,7 +194,7 @@ public: // watchpoints watchpoint *watchpoint_first(int spacenum) const { return m_wplist[spacenum]; } - int watchpoint_set(address_space &space, int type, offs_t address, offs_t length, parsed_expression *condition, const char *action); + int watchpoint_set(address_space &space, int type, offs_t address, offs_t length, const char *condition, const char *action); bool watchpoint_clear(int wpnum); void watchpoint_clear_all(); bool watchpoint_enable(int index, bool enable = true); @@ -243,12 +241,12 @@ private: void hotspot_check(address_space &space, offs_t address); // symbol get/set callbacks - static UINT64 get_current_pc(void *globalref, void *ref); - static UINT64 get_cycles(void *globalref, void *ref); - static UINT64 get_logunmap(void *globalref, void *ref); - static void set_logunmap(void *globalref, void *ref, UINT64 value); - static UINT64 get_cpu_reg(void *globalref, void *ref); - static void set_state(void *globalref, void *ref, UINT64 value); + static UINT64 get_current_pc(symbol_table &table, void *ref); + static UINT64 get_cycles(symbol_table &table, void *ref); + static UINT64 get_logunmap(symbol_table &table, void *ref); + static void set_logunmap(symbol_table &table, void *ref, UINT64 value); + static UINT64 get_state(symbol_table &table, void *ref); + static void set_state(symbol_table &table, void *ref, UINT64 value); // basic device information device_t & m_device; // device we are attached to @@ -259,7 +257,7 @@ private: // global state UINT32 m_flags; // debugging flags for this CPU - symbol_table * m_symtable; // symbol table for expression evaluation + symbol_table m_symtable; // symbol table for expression evaluation debug_instruction_hook_func m_instrhook; // per-instruction callback hook // disassembly @@ -366,14 +364,6 @@ private: -//************************************************************************** -// GLOBAL VARIABLES -//************************************************************************** - -extern const express_callbacks debug_expression_callbacks; - - - //************************************************************************** // FUNCTION PROTOTYPES //************************************************************************** @@ -382,6 +372,7 @@ extern const express_callbacks debug_expression_callbacks; /* initialize the CPU tracking for the debugger */ void debug_cpu_init(running_machine *machine); +void debug_cpu_configure_memory(running_machine &machine, symbol_table &table); /* flushes all traces; this is useful if a trace is going on when we fatalerror */ void debug_cpu_flush_traces(running_machine *machine); diff --git a/src/emu/debug/debugvw.c b/src/emu/debug/debugvw.c index 6675c7a989d..1166df72f1c 100644 --- a/src/emu/debug/debugvw.c +++ b/src/emu/debug/debugvw.c @@ -38,6 +38,7 @@ ***************************************************************************/ #include "emu.h" +#include "express.h" #include "debugvw.h" #include "dvtext.h" #include "dvstate.h" @@ -46,7 +47,6 @@ #include "debugcmd.h" #include "debugcpu.h" #include "debugcon.h" -#include "express.h" #include @@ -559,9 +559,8 @@ debug_view_expression::debug_view_expression(running_machine &machine) : m_machine(machine), m_dirty(true), m_result(0), - m_parsed(NULL), - m_string("0"), - m_context(debug_cpu_get_global_symtable(&machine)) + m_parsed(debug_cpu_get_global_symtable(&machine)), + m_string("0") { } @@ -572,20 +571,6 @@ debug_view_expression::debug_view_expression(running_machine &machine) debug_view_expression::~debug_view_expression() { - // free our parsed expression - if (m_parsed != NULL) - expression_free(m_parsed); -} - - -//------------------------------------------------- -// set_string - set the expression string -//------------------------------------------------- - -void debug_view_expression::set_string(const char *string) -{ - m_string = string; - m_dirty = true; } @@ -596,7 +581,7 @@ void debug_view_expression::set_string(const char *string) void debug_view_expression::set_context(symbol_table *context) { - m_context = (context != NULL) ? context : debug_cpu_get_global_symtable(&m_machine); + m_parsed.set_symbols((context != NULL) ? context : debug_cpu_get_global_symtable(&m_machine)); m_dirty = true; } @@ -613,28 +598,33 @@ bool debug_view_expression::recompute() // if dirty, re-evaluate if (m_dirty) { - // parse the new expression - parsed_expression *expr; - EXPRERR exprerr = expression_parse(m_string, m_context, &debug_expression_callbacks, &m_machine, &expr); - - // if it worked, update the expression - if (exprerr == EXPRERR_NONE) + astring oldstring(m_parsed.original_string()); + try { - if (m_parsed != NULL) - expression_free(m_parsed); - m_parsed = expr; + m_parsed.parse(m_string); + } + catch (expression_error &) + { + m_parsed.parse(oldstring); } } // if we have a parsed expression, evalute it - if (m_parsed != NULL) + if (!m_parsed.is_empty()) { - UINT64 oldresult = m_result; - // recompute the value of the expression - expression_execute(m_parsed, &m_result); - if (m_result != oldresult) - changed = true; + try + { + UINT64 newresult = m_parsed.execute(); + if (newresult != m_result) + { + m_result = newresult; + changed = true; + } + } + catch (expression_error &) + { + } } // expression no longer dirty by definition diff --git a/src/emu/debug/debugvw.h b/src/emu/debug/debugvw.h index 9f9e143bc0a..612c748276b 100644 --- a/src/emu/debug/debugvw.h +++ b/src/emu/debug/debugvw.h @@ -40,6 +40,8 @@ #ifndef __DEBUGVIEW_H__ #define __DEBUGVIEW_H__ +#include "express.h" + //************************************************************************** // CONSTANTS @@ -102,8 +104,6 @@ const int DCH_CTRLLEFT = 12; // ctrl+left // forward references class debug_view; -typedef struct _symbol_table symbol_table; -typedef struct _parsed_expression parsed_expression; // OSD callback function for a view @@ -305,11 +305,11 @@ public: UINT64 last_value() const { return m_result; } UINT64 value() { recompute(); return m_result; } const char *string() const { return m_string; } - symbol_table *context() const { return m_context; } + symbol_table *context() const { return m_parsed.symbols(); } // setters void mark_dirty() { m_dirty = true; } - void set_string(const char *string); + void set_string(const char *string) { m_string.cpy(string); m_dirty = true; } void set_context(symbol_table *context); private: @@ -320,9 +320,8 @@ private: running_machine & m_machine; // reference to the machine bool m_dirty; // true if the expression needs to be re-evaluated UINT64 m_result; // last result from the expression - parsed_expression * m_parsed; // parsed expression data + parsed_expression m_parsed; // parsed expression data astring m_string; // copy of the expression string - symbol_table * m_context; // context we are using }; diff --git a/src/emu/debug/dvdisasm.c b/src/emu/debug/dvdisasm.c index 679ecd22c00..8983eaae2e1 100644 --- a/src/emu/debug/dvdisasm.c +++ b/src/emu/debug/dvdisasm.c @@ -156,7 +156,7 @@ void debug_view_disasm::view_notify(debug_view_notification type) adjust_visible_y_for_cursor(); else if (type == VIEW_NOTIFY_SOURCE_CHANGED) - m_expression.set_context(downcast(m_source)->device().debug()->symtable()); + m_expression.set_context(&downcast(m_source)->device().debug()->symtable()); } diff --git a/src/emu/debug/dvmemory.c b/src/emu/debug/dvmemory.c index 2073cbc5492..c02ad5766b9 100644 --- a/src/emu/debug/dvmemory.c +++ b/src/emu/debug/dvmemory.c @@ -213,7 +213,7 @@ void debug_view_memory::view_notify(debug_view_notification type) m_chunks_per_row = m_bytes_per_chunk * m_chunks_per_row / source.m_prefsize; m_bytes_per_chunk = source.m_prefsize; if (source.m_space != NULL) - m_expression.set_context(source.m_space->cpu->debug()->symtable()); + m_expression.set_context(&source.m_space->cpu->debug()->symtable()); else m_expression.set_context(NULL); } diff --git a/src/emu/debug/express.c b/src/emu/debug/express.c index 07ef01d69b1..f1f13018fa3 100644 --- a/src/emu/debug/express.c +++ b/src/emu/debug/express.c @@ -1,12 +1,64 @@ /*************************************************************************** express.c + Generic expressions engine. - Written by Aaron Giles + +**************************************************************************** + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +**************************************************************************** + + Operator precedence + =================== + 0x0000 ( ) + 0x0001 ++ (postfix), -- (postfix) + 0x0002 ++ (prefix), -- (prefix), ~, !, - (unary), + (unary), b@, w@, d@, q@ + 0x0003 *, /, % + 0x0004 + - + 0x0005 << >> + 0x0006 < <= > >= + 0x0007 == != + 0x0008 & + 0x0009 ^ + 0x000a | + 0x000b && + 0x000c || + 0x000d = *= /= %= += -= <<= >>= &= |= ^= + 0x000e , + 0x000f func() ***************************************************************************/ +#include "emucore.h" #include "express.h" #include @@ -25,80 +77,11 @@ ***************************************************************************/ #ifndef DEFAULT_BASE -#define DEFAULT_BASE 16 /* hex unless otherwise specified */ +#define DEFAULT_BASE 16 // hex unless otherwise specified #endif -#define MAX_TOKENS 128 -#define MAX_STACK_DEPTH 128 -#define MAX_STRING_LENGTH 256 -#define MAX_SYMBOL_LENGTH 64 -#define SYM_TABLE_HASH_SIZE 97 - -/* token.type values */ -enum -{ - TOK_INVALID = 0, - TOK_END, - TOK_NUMBER, - TOK_STRING, - TOK_MEMORY, - TOK_SYMBOL, - TOK_OPERATOR -}; - - -/* token.info values */ -enum -{ - TIN_PRECEDENCE_MASK = 0x001f, - TIN_PRECEDENCE_0 = 0x0000, /* ( ) */ - TIN_PRECEDENCE_1 = 0x0001, /* ++ (postfix), -- (postfix) */ - TIN_PRECEDENCE_2 = 0x0002, /* ++ (prefix), -- (prefix), ~, !, - (unary), + (unary), b@, w@, d@, q@ */ - TIN_PRECEDENCE_3 = 0x0003, /* *, /, % */ - TIN_PRECEDENCE_4 = 0x0004, /* + - */ - TIN_PRECEDENCE_5 = 0x0005, /* << >> */ - TIN_PRECEDENCE_6 = 0x0006, /* < <= > >= */ - TIN_PRECEDENCE_7 = 0x0007, /* == != */ - TIN_PRECEDENCE_8 = 0x0008, /* & */ - TIN_PRECEDENCE_9 = 0x0009, /* ^ */ - TIN_PRECEDENCE_10 = 0x000a, /* | */ - TIN_PRECEDENCE_11 = 0x000b, /* && */ - TIN_PRECEDENCE_12 = 0x000c, /* || */ - TIN_PRECEDENCE_13 = 0x000d, /* = *= /= %= += -= <<= >>= &= |= ^= */ - TIN_PRECEDENCE_14 = 0x000e, /* , */ - TIN_PRECEDENCE_15 = 0x000f, /* func() */ - - TIN_RIGHT_TO_LEFT = 0x0040, - TIN_FUNCTION = 0x0080, - - TIN_MEMORY_SIZE_SHIFT = 8, - TIN_MEMORY_SIZE_MASK = (3 << TIN_MEMORY_SIZE_SHIFT), - TIN_MEMORY_BYTE = (0 << TIN_MEMORY_SIZE_SHIFT), - TIN_MEMORY_WORD = (1 << TIN_MEMORY_SIZE_SHIFT), - TIN_MEMORY_DWORD = (2 << TIN_MEMORY_SIZE_SHIFT), - TIN_MEMORY_QWORD = (3 << TIN_MEMORY_SIZE_SHIFT), - - TIN_MEMORY_SPACE_SHIFT = 12, - TIN_MEMORY_SPACE_MASK = (0xf << TIN_MEMORY_SPACE_SHIFT), - TIN_MEMORY_PROGRAM_LOG = (EXPSPACE_PROGRAM_LOGICAL << TIN_MEMORY_SPACE_SHIFT), - TIN_MEMORY_DATA_LOG = (EXPSPACE_DATA_LOGICAL << TIN_MEMORY_SPACE_SHIFT), - TIN_MEMORY_IO_LOG = (EXPSPACE_IO_LOGICAL << TIN_MEMORY_SPACE_SHIFT), - TIN_MEMORY_SPACE3_LOG = (EXPSPACE_SPACE3_LOGICAL << TIN_MEMORY_SPACE_SHIFT), - TIN_MEMORY_PROGRAM_PHYS = (EXPSPACE_PROGRAM_PHYSICAL << TIN_MEMORY_SPACE_SHIFT), - TIN_MEMORY_DATA_PHYS = (EXPSPACE_DATA_PHYSICAL << TIN_MEMORY_SPACE_SHIFT), - TIN_MEMORY_IO_PHYS = (EXPSPACE_IO_PHYSICAL << TIN_MEMORY_SPACE_SHIFT), - TIN_MEMORY_SPACE3_PHYS = (EXPSPACE_SPACE3_PHYSICAL << TIN_MEMORY_SPACE_SHIFT), - TIN_MEMORY_OPCODE = (EXPSPACE_OPCODE << TIN_MEMORY_SPACE_SHIFT), - TIN_MEMORY_RAMWRITE = (EXPSPACE_RAMWRITE << TIN_MEMORY_SPACE_SHIFT), - TIN_MEMORY_REGION = (EXPSPACE_REGION << TIN_MEMORY_SPACE_SHIFT), - - TIN_MEMORY_INDEX_SHIFT = 16, - TIN_MEMORY_INDEX_MASK = (0xffff << TIN_MEMORY_INDEX_SHIFT) -}; - - -/* token.value values if token.type == TOK_OPERATOR */ +// token.value values if token.is_operator() enum { TVL_LPAREN, @@ -149,314 +132,536 @@ enum -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** -typedef union _int_ptr int_ptr; -union _int_ptr +// a symbol entry representing a register, with read/write callbacks +class integer_symbol_entry : public symbol_entry { - void * p; /* pointer value */ - UINT64 i; /* integer value */ +public: + // construction/destruction + integer_symbol_entry(symbol_table &table, const char *name, symbol_table::read_write rw, UINT64 *ptr = NULL); + integer_symbol_entry(symbol_table &table, const char *name, UINT64 constval); + integer_symbol_entry(symbol_table &table, const char *name, void *ref, symbol_table::getter_func getter, symbol_table::setter_func setter); + + // symbol access + virtual bool is_lval() const; + virtual UINT64 value() const; + virtual void set_value(UINT64 newvalue); + +private: + // internal helpers + static UINT64 internal_getter(symbol_table &table, void *symref); + static void internal_setter(symbol_table &table, void *symref, UINT64 value); + + // internal state + symbol_table::getter_func m_getter; + symbol_table::setter_func m_setter; + UINT64 m_value; }; -typedef UINT32 token_type; -typedef UINT32 token_info; - - -typedef struct _parse_token parse_token; -struct _parse_token +// a symbol entry representing a function +class function_symbol_entry : public symbol_entry { - token_type type; /* type of token */ - token_info info; /* info for token */ - UINT32 offset; /* offset within the string */ - int_ptr value; /* value of token */ -}; +public: + // construction/destruction + function_symbol_entry(symbol_table &table, const char *name, void *ref, int minparams, int maxparams, symbol_table::execute_func execute); + // symbol access + virtual bool is_lval() const; + virtual UINT64 value() const; + virtual void set_value(UINT64 newvalue); -typedef struct _internal_symbol_entry internal_symbol_entry; -struct _internal_symbol_entry -{ - internal_symbol_entry * next; /* pointer to the next entry */ - const char * name; /* name of the symbol */ - symbol_entry entry; /* actual entry data */ -}; + // execution helper + virtual UINT64 execute(int numparams, const UINT64 *paramlist); - -/* typedef struct _symbol_table symbol_table -- defined in express.h */ -struct _symbol_table -{ - symbol_table * parent; /* pointer to the parent symbol table */ - void * globalref; /* global reference parameter */ - internal_symbol_entry * hash[SYM_TABLE_HASH_SIZE]; /* hash table */ -}; - - -typedef struct _expression_string expression_string; -struct _expression_string -{ - expression_string * next; /* pointer to next string */ - UINT16 index; /* index of this string */ - char string[1]; /* string data */ -}; - - -/* typedef struct _parsed_expression parsed_expression -- defined in express.h */ -struct _parsed_expression -{ - const symbol_table * table; /* symbol table */ - char * original_string; /* original string (prior to parsing) */ - express_callbacks callbacks; /* callbacks */ - void * cbparam; /* callbakc parameter */ - expression_string * stringlist; /* string list */ - UINT16 stringcount; /* number of strings allocated so far */ - parse_token token[MAX_TOKENS]; /* array of tokens */ - int token_stack_ptr; /* stack poointer */ - parse_token token_stack[MAX_STACK_DEPTH]; /* token stack */ +private: + // internal state + UINT16 m_minparams; + UINT16 m_maxparams; + symbol_table::execute_func m_execute; }; -/*************************************************************************** - PROTOTYPES -***************************************************************************/ +//************************************************************************** +// EXPRESSION ERROR +//************************************************************************** -static char *add_expression_string(parsed_expression *expr, const char *string, int length, UINT16 *index); -static const char *get_expression_string(parsed_expression *expr, UINT16 index); +//------------------------------------------------- +// code_string - return a friendly string for a +// given expression error +//------------------------------------------------- - - -/*************************************************************************** - STACK MANIPULATION -***************************************************************************/ - -/*------------------------------------------------- - init_token_stack - reset the token stack --------------------------------------------------*/ - -INLINE void init_token_stack(parsed_expression *expr) +const char *expression_error::code_string() const { - expr->token_stack_ptr = 0; -} - - -/*------------------------------------------------- - push_token - push a token onto the stack --------------------------------------------------*/ - -INLINE EXPRERR push_token(parsed_expression *expr, parse_token *token) -{ - /* check for overflow */ - if (expr->token_stack_ptr >= MAX_STACK_DEPTH) - return MAKE_EXPRERR_STACK_OVERFLOW(token->offset); - - /* push */ - expr->token_stack[expr->token_stack_ptr++] = *token; - return EXPRERR_NONE; -} - - -/*------------------------------------------------- - pop_token - pop a token off the stack --------------------------------------------------*/ - -INLINE EXPRERR pop_token(parsed_expression *expr, parse_token *token) -{ - /* check for underflow */ - if (expr->token_stack_ptr == 0) - return MAKE_EXPRERR_STACK_UNDERFLOW(token->offset); - - /* push */ - *token = expr->token_stack[--expr->token_stack_ptr]; - return EXPRERR_NONE; -} - - -/*------------------------------------------------- - peek_token - look at a token some number of - entries up the stack --------------------------------------------------*/ - -INLINE parse_token *peek_token(parsed_expression *expr, int count) -{ - if (expr->token_stack_ptr <= count) - return NULL; - return &expr->token_stack[expr->token_stack_ptr - count - 1]; -} - - - -/*************************************************************************** - LVAL/RVAL EVALUATION -***************************************************************************/ - -/*------------------------------------------------- - pop_token_lval - pop a token off the stack - and ensure that it is a proper lval --------------------------------------------------*/ - -INLINE EXPRERR pop_token_lval(parsed_expression *expr, parse_token *token, const symbol_table *table) -{ - /* check for underflow */ - if (expr->token_stack_ptr == 0) - return MAKE_EXPRERR_STACK_UNDERFLOW(token->offset); - - /* pop */ - *token = expr->token_stack[--expr->token_stack_ptr]; - - /* to be an lval, the token must be a valid read/write symbol or a memory token */ - if (token->type == TOK_SYMBOL) + switch (m_code) { - symbol_entry *symbol = (symbol_entry *)token->value.p; - if (symbol == NULL || symbol->type != SMT_REGISTER || symbol->info.reg.setter == NULL) - return MAKE_EXPRERR_NOT_LVAL(token->offset); + case NOT_LVAL: return "not an lvalue"; + case NOT_RVAL: return "not an rvalue"; + case SYNTAX: return "syntax error"; + case UNKNOWN_SYMBOL: return "unknown symbol"; + case INVALID_NUMBER: return "invalid number"; + case INVALID_TOKEN: return "invalid token"; + case STACK_OVERFLOW: return "stack overflow"; + case STACK_UNDERFLOW: return "stack underflow"; + case UNBALANCED_PARENS: return "unbalanced parentheses"; + case DIVIDE_BY_ZERO: return "divide by zero"; + case OUT_OF_MEMORY: return "out of memory"; + case INVALID_PARAM_COUNT: return "invalid number of parameters"; + case UNBALANCED_QUOTES: return "unbalanced quotes"; + case TOO_MANY_STRINGS: return "too many strings"; + case INVALID_MEMORY_SIZE: return "invalid memory size (b/w/d/q expected)"; + case NO_SUCH_MEMORY_SPACE: return "non-existent memory space"; + case INVALID_MEMORY_SPACE: return "invalid memory space (p/d/i/o/r/m expected)"; + case INVALID_MEMORY_NAME: return "invalid memory name"; + case MISSING_MEMORY_NAME: return "missing memory name"; + default: return "unknown error"; } - else if (token->type != TOK_MEMORY) - return MAKE_EXPRERR_NOT_LVAL(token->offset); - - return 0; } -/*------------------------------------------------- - pop_token_rval - pop a token off the stack - and ensure that it is a proper rval --------------------------------------------------*/ -INLINE EXPRERR pop_token_rval(parsed_expression *expr, parse_token *token, const symbol_table *table) +//************************************************************************** +// SYMBOL ENTRY +//************************************************************************** + +//------------------------------------------------- +// symbol_entry - constructor +//------------------------------------------------- + +symbol_entry::symbol_entry(symbol_table &table, symbol_type type, const char *name, void *ref) + : m_next(NULL), + m_table(table), + m_type(type), + m_name(name), + m_ref(ref) { - /* check for underflow */ - if (expr->token_stack_ptr == 0) - return MAKE_EXPRERR_STACK_UNDERFLOW(token->offset); - - /* pop */ - *token = expr->token_stack[--expr->token_stack_ptr]; - - /* symbol tokens get resolved down to number tokens */ - if (token->type == TOK_SYMBOL) - { - symbol_entry *symbol = (symbol_entry *)token->value.p; - if (symbol == NULL || (symbol->type != SMT_REGISTER && symbol->type != SMT_VALUE)) - return MAKE_EXPRERR_NOT_RVAL(token->offset); - token->type = TOK_NUMBER; - if (symbol->type == SMT_REGISTER) - token->value.i = (*symbol->info.reg.getter)(symbol->table->globalref, symbol->ref); - else - token->value.i = symbol->info.gen.value; - } - - /* memory tokens get resolved down to number tokens */ - else if (token->type == TOK_MEMORY) - { - const char *name = get_expression_string(expr, (token->info & TIN_MEMORY_INDEX_MASK) >> TIN_MEMORY_INDEX_SHIFT); - int space = (token->info & TIN_MEMORY_SPACE_MASK) >> TIN_MEMORY_SPACE_SHIFT; - int size = (token->info & TIN_MEMORY_SIZE_MASK) >> TIN_MEMORY_SIZE_SHIFT; - token->type = TOK_NUMBER; - if (expr->callbacks.read != NULL) - token->value.i = (*expr->callbacks.read)(expr->cbparam, name, space, token->value.i, 1 << size); - else - token->value.i = 0; - } - - /* to be an rval, the token must be a number */ - if (token->type != TOK_NUMBER) - return MAKE_EXPRERR_NOT_RVAL(token->offset); - return 0; } -/*------------------------------------------------- - get_lval_value - call the getter function - for a SYMBOL token --------------------------------------------------*/ +//------------------------------------------------- +// ~symbol_entry - destructor +//------------------------------------------------- -INLINE UINT64 get_lval_value(parsed_expression *expr, parse_token *token, const symbol_table *table) +symbol_entry::~symbol_entry() { - if (token->type == TOK_SYMBOL) +} + + + +//************************************************************************** +// REGISTER SYMBOL ENTRY +//************************************************************************** + +//------------------------------------------------- +// integer_symbol_entry - constructor +//------------------------------------------------- + +integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, symbol_table::read_write rw, UINT64 *ptr) + : symbol_entry(table, SMT_INTEGER, name, (ptr == NULL) ? &m_value : ptr), + m_getter(internal_getter), + m_setter((rw == symbol_table::READ_ONLY) ? NULL : internal_setter), + m_value(0) +{ +} + + +integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, UINT64 constval) + : symbol_entry(table, SMT_INTEGER, name, &m_value), + m_getter(internal_getter), + m_setter(NULL), + m_value(constval) +{ +} + + +integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, void *ref, symbol_table::getter_func getter, symbol_table::setter_func setter) + : symbol_entry(table, SMT_INTEGER, name, ref), + m_getter(getter), + m_setter(setter), + m_value(0) +{ +} + + +//------------------------------------------------- +// is_lval - is this symbol allowable as an lval? +//------------------------------------------------- + +bool integer_symbol_entry::is_lval() const +{ + return (m_setter != NULL); +} + + +//------------------------------------------------- +// value - return the value of this symbol +//------------------------------------------------- + +UINT64 integer_symbol_entry::value() const +{ + return (*m_getter)(m_table, m_ref); +} + + +//------------------------------------------------- +// set_value - set the value of this symbol +//------------------------------------------------- + +void integer_symbol_entry::set_value(UINT64 newvalue) +{ + if (m_setter != NULL) + (*m_setter)(m_table, m_ref, newvalue); + else + throw emu_fatalerror("Symbol '%s' is read-only", m_name.cstr()); +} + + +//------------------------------------------------- +// internal_getter - internal helper for +// returning the value of a variable +//------------------------------------------------- + +UINT64 integer_symbol_entry::internal_getter(symbol_table &table, void *symref) +{ + return *(UINT64 *)symref; +} + + +//------------------------------------------------- +// internal_setter - internal helper for setting +// the value of a variable +//------------------------------------------------- + +void integer_symbol_entry::internal_setter(symbol_table &table, void *symref, UINT64 value) +{ + *(UINT64 *)symref = value; +} + + + +//************************************************************************** +// FUNCTION SYMBOL ENTRY +//************************************************************************** + +//------------------------------------------------- +// function_symbol_entry - constructor +//------------------------------------------------- + +function_symbol_entry::function_symbol_entry(symbol_table &table, const char *name, void *ref, int minparams, int maxparams, symbol_table::execute_func execute) + : symbol_entry(table, SMT_FUNCTION, name, ref), + m_minparams(minparams), + m_maxparams(maxparams), + m_execute(execute) +{ +} + + +//------------------------------------------------- +// is_lval - is this symbol allowable as an lval? +//------------------------------------------------- + +bool function_symbol_entry::is_lval() const +{ + return false; +} + + +//------------------------------------------------- +// value - return the value of this symbol +//------------------------------------------------- + +UINT64 function_symbol_entry::value() const +{ + throw emu_fatalerror("Symbol '%s' is a function and cannot be used in this context", m_name.cstr()); +} + + +//------------------------------------------------- +// set_value - set the value of this symbol +//------------------------------------------------- + +void function_symbol_entry::set_value(UINT64 newvalue) +{ + throw emu_fatalerror("Symbol '%s' is a function and cannot be written", m_name.cstr()); +} + + +//------------------------------------------------- +// execute - execute the function +//------------------------------------------------- + +UINT64 function_symbol_entry::execute(int numparams, const UINT64 *paramlist) +{ + if (numparams < m_minparams) + throw emu_fatalerror("Function '%s' requires at least %d parameters", m_name.cstr(), m_minparams); + if (numparams > m_maxparams) + throw emu_fatalerror("Function '%s' accepts no more than %d parameters", m_name.cstr(), m_maxparams); + return (*m_execute)(m_table, m_ref, numparams, paramlist); +} + + + +//************************************************************************** +// SYMBOL TABLE +//************************************************************************** + +//------------------------------------------------- +// symbol_table - constructor +//------------------------------------------------- + +symbol_table::symbol_table(void *globalref, symbol_table *parent) + : m_parent(parent), + m_globalref(globalref), + m_memory_param(NULL), + m_memory_valid(NULL), + m_memory_read(NULL), + m_memory_write(NULL) +{ +} + + +//------------------------------------------------- +// add - add a new UINT64 pointer symbol +//------------------------------------------------- + +void symbol_table::configure_memory(void *param, valid_func valid, read_func read, write_func write) +{ + m_memory_param = param; + m_memory_valid = valid; + m_memory_read = read; + m_memory_write = write; +} + + +//------------------------------------------------- +// add - add a new UINT64 pointer symbol +//------------------------------------------------- + +void symbol_table::add(const char *name, read_write rw, UINT64 *ptr) +{ + m_symlist.remove(name); + m_symlist.append(name, global_alloc(integer_symbol_entry(*this, name, rw, ptr))); +} + + +//------------------------------------------------- +// add - add a new value symbol +//------------------------------------------------- + +void symbol_table::add(const char *name, UINT64 value) +{ + m_symlist.remove(name); + m_symlist.append(name, global_alloc(integer_symbol_entry(*this, name, value))); +} + + +//------------------------------------------------- +// add - add a new register symbol +//------------------------------------------------- + +void symbol_table::add(const char *name, void *ref, getter_func getter, setter_func setter) +{ + m_symlist.remove(name); + m_symlist.append(name, global_alloc(integer_symbol_entry(*this, name, ref, getter, setter))); +} + + +//------------------------------------------------- +// add - add a new function symbol +//------------------------------------------------- + +void symbol_table::add(const char *name, void *ref, int minparams, int maxparams, execute_func execute) +{ + m_symlist.remove(name); + m_symlist.append(name, global_alloc(function_symbol_entry(*this, name, ref, minparams, maxparams, execute))); +} + + +//------------------------------------------------- +// value - return the value of a symbol +//------------------------------------------------- + +UINT64 symbol_table::value(const char *symbol) +{ + // walk up the table hierarchy to find the owner + for (symbol_table *symtable = this; symtable != NULL; symtable = symtable->m_parent) { - symbol_entry *symbol = (symbol_entry *)token->value.p; - if (symbol != NULL && symbol->type == SMT_REGISTER) - return (*symbol->info.reg.getter)(symbol->table->globalref, symbol->ref); - } - else if (token->type == TOK_MEMORY) - { - const char *name = get_expression_string(expr, (token->info & TIN_MEMORY_INDEX_MASK) >> TIN_MEMORY_INDEX_SHIFT); - int space = (token->info & TIN_MEMORY_SPACE_MASK) >> TIN_MEMORY_SPACE_SHIFT; - int size = (token->info & TIN_MEMORY_SIZE_MASK) >> TIN_MEMORY_SIZE_SHIFT; - if (expr->callbacks.read != NULL) - return (*expr->callbacks.read)(expr->cbparam, name, space, token->value.i, 1 << size); + symbol_entry *entry = symtable->find(symbol); + if (entry != NULL) + return entry->value(); } return 0; } -/*------------------------------------------------- - set_lval_value - call the setter function - for a SYMBOL token --------------------------------------------------*/ +//------------------------------------------------- +// set_value - set the value of a symbol +//------------------------------------------------- -INLINE void set_lval_value(parsed_expression *expr, parse_token *token, const symbol_table *table, UINT64 value) +void symbol_table::set_value(const char *symbol, UINT64 value) { - if (token->type == TOK_SYMBOL) + // walk up the table hierarchy to find the owner + for (symbol_table *symtable = this; symtable != NULL; symtable = symtable->m_parent) { - symbol_entry *symbol = (symbol_entry *)token->value.p; - if (symbol != NULL && symbol->type == SMT_REGISTER && symbol->info.reg.setter) - (*symbol->info.reg.setter)(symbol->table->globalref, symbol->ref, value); - } - else if (token->type == TOK_MEMORY) - { - const char *name = get_expression_string(expr, (token->info & TIN_MEMORY_INDEX_MASK) >> TIN_MEMORY_INDEX_SHIFT); - int space = (token->info & TIN_MEMORY_SPACE_MASK) >> TIN_MEMORY_SPACE_SHIFT; - int size = (token->info & TIN_MEMORY_SIZE_MASK) >> TIN_MEMORY_SIZE_SHIFT; - if (expr->callbacks.write != NULL) - (*expr->callbacks.write)(expr->cbparam, name, space, token->value.i, 1 << size, value); + symbol_entry *entry = symtable->find(symbol); + if (entry != NULL) + { + entry->set_value(value); + return; + } } } +//------------------------------------------------- +// memory_valid - return true if the given +// memory name/space/offset combination is valid +//------------------------------------------------- -/*************************************************************************** - DEBUGGING -***************************************************************************/ +expression_error::error_code symbol_table::memory_valid(const char *name, int space) +{ + // walk up the table hierarchy to find the owner + for (symbol_table *symtable = this; symtable != NULL; symtable = symtable->m_parent) + if (symtable->m_memory_valid != NULL) + { + expression_error::error_code err = (*symtable->m_memory_valid)(symtable->m_memory_param, name, space); + if (err != expression_error::NO_SUCH_MEMORY_SPACE) + return err; + } + return expression_error::NO_SUCH_MEMORY_SPACE; +} -/*------------------------------------------------- - print_token - debugging took to print a - human readable token representation --------------------------------------------------*/ -static void print_tokens(FILE *out, parsed_expression *expr) +//------------------------------------------------- +// memory_value - return a value read from memory +//------------------------------------------------- + +UINT64 symbol_table::memory_value(const char *name, int space, UINT32 offset, int size) +{ + // walk up the table hierarchy to find the owner + for (symbol_table *symtable = this; symtable != NULL; symtable = symtable->m_parent) + if (symtable->m_memory_valid != NULL) + { + expression_error::error_code err = (*symtable->m_memory_valid)(symtable->m_memory_param, name, space); + if (err != expression_error::NO_SUCH_MEMORY_SPACE && symtable->m_memory_read != NULL) + return (*symtable->m_memory_read)(symtable->m_memory_param, name, space, offset, size); + return 0; + } + return 0; +} + + +//------------------------------------------------- +// set_memory_value - write a value to memory +//------------------------------------------------- + +void symbol_table::set_memory_value(const char *name, int space, UINT32 offset, int size, UINT64 value) +{ + // walk up the table hierarchy to find the owner + for (symbol_table *symtable = this; symtable != NULL; symtable = symtable->m_parent) + if (symtable->m_memory_valid != NULL) + { + expression_error::error_code err = (*symtable->m_memory_valid)(symtable->m_memory_param, name, space); + if (err != expression_error::NO_SUCH_MEMORY_SPACE && symtable->m_memory_write != NULL) + (*symtable->m_memory_write)(symtable->m_memory_param, name, space, offset, size, value); + return; + } +} + + + +//************************************************************************** +// PARSED EXPRESSION +//************************************************************************** + +//------------------------------------------------- +// parsed_expression - constructor +//------------------------------------------------- + +parsed_expression::parsed_expression(symbol_table *symtable, const char *expression, UINT64 *result) + : m_symtable(symtable) +{ + // if we got an expression parse it + if (expression != NULL) + parse(expression); + + // if we get a result pointer, execute it + if (result != NULL) + *result = execute(); +} + + +//------------------------------------------------- +// parse - parse an expression into tokens +//------------------------------------------------- + +void parsed_expression::parse(const char *expression) +{ + // copy the string and reset our parsing state + m_original_string.cpy(expression); + m_tokenlist.reset(); + m_stringlist.reset(); + + // first parse the tokens into the token array in order + parse_string_into_tokens(); + + // convert the infix order to postfix order + infix_to_postfix(); +} + + +//------------------------------------------------- +// copy - copy an expression from another source +//------------------------------------------------- + +void parsed_expression::copy(const parsed_expression &src) +{ + m_symtable = src.m_symtable; + m_original_string.cpy(src.m_original_string); + if (m_original_string) + parse_string_into_tokens(); +} + + +//------------------------------------------------- +// print_tokens - debugging took to print a +// human readable token representation +//------------------------------------------------- + +void parsed_expression::print_tokens(FILE *out) { #if DEBUG_TOKENS - parse_token *token = expr->token; - mame_printf_debug("----\n"); - while (token->type != TOK_END) + for (parse_token *token = m_tokens.first(); token != NULL; token = token->next()) { switch (token->type) { default: - case TOK_INVALID: + case parse_token::INVALID: fprintf(out, "INVALID\n"); break; - case TOK_END: + case parse_token::END: fprintf(out, "END\n"); break; - case TOK_NUMBER: + case parse_token::NUMBER: fprintf(out, "NUMBER: %08X%08X\n", (UINT32)(token->value.i >> 32), (UINT32)token->value.i); break; - case TOK_STRING: - fprintf(out, "STRING: ""%s""\n", (char *)token->value.p); + case parse_token::STRING: + fprintf(out, "STRING: ""%s""\n", token->string); break; - case TOK_SYMBOL: + case parse_token::SYMBOL: fprintf(out, "SYMBOL: %08X%08X\n", (UINT32)(token->value.i >> 32), (UINT32)token->value.i); break; - case TOK_OPERATOR: + case parse_token::OPERATOR: switch (token->value.i) { case TVL_LPAREN: fprintf(out, "(\n"); break; @@ -507,1659 +712,1064 @@ static void print_tokens(FILE *out, parsed_expression *expr) } break; } - token++; } mame_printf_debug("----\n"); #endif } +//------------------------------------------------- +// parse_string_into_tokens - take an expression +// string and break it into a sequence of tokens +//------------------------------------------------- -/*************************************************************************** - TOKENIZING -***************************************************************************/ - -/*------------------------------------------------- - parse_memory_operator - parse the several - forms of memory operators --------------------------------------------------*/ - -static EXPRERR parse_memory_operator(parsed_expression *expr, int offset, const char *buffer, token_info *flags) +void parsed_expression::parse_string_into_tokens() { - const char *startbuffer = buffer; - const char *namestring = NULL; - int space = 'p', size; - int physical = FALSE; - const char *dot; - int length; - - *flags = 0; - - /* if there is a '.', it means we have a name */ - dot = strrchr(buffer, '.'); - if (dot != NULL) - { - UINT16 index = 0; - - namestring = add_expression_string(expr, buffer, dot - buffer, &index); - if (namestring == NULL) - return MAKE_EXPRERR_OUT_OF_MEMORY(offset); - *flags |= index << TIN_MEMORY_INDEX_SHIFT; - buffer = dot + 1; - } - - /* length 3 means logical/physical, then space, then size */ - length = (int)strlen(buffer); - if (length == 3) - { - if (buffer[0] != 'l' && buffer[0] != 'p') - return MAKE_EXPRERR_INVALID_MEMORY_SPACE(offset + (buffer - startbuffer)); - if (buffer[1] != 'p' && buffer[1] != 'd' && buffer[1] != 'i' && buffer[1] != '3') - return MAKE_EXPRERR_INVALID_MEMORY_SPACE(offset + (buffer - startbuffer)); - physical = (buffer[0] == 'p'); - space = buffer[1]; - size = buffer[2]; - } - - /* length 2 means space then size */ - else if (length == 2) - { - space = buffer[0]; - size = buffer[1]; - } - - /* length 1 means size */ - else if (length == 1) - size = buffer[0]; - - /* anything else is invalid */ - else - return MAKE_EXPRERR_INVALID_TOKEN(offset); - - /* convert the space to flags */ - switch (space) - { - case 'p': *flags |= physical ? TIN_MEMORY_PROGRAM_PHYS : TIN_MEMORY_PROGRAM_LOG; break; - case 'd': *flags |= physical ? TIN_MEMORY_DATA_PHYS : TIN_MEMORY_DATA_LOG; break; - case 'i': *flags |= physical ? TIN_MEMORY_IO_PHYS : TIN_MEMORY_IO_LOG; break; - case '3': *flags |= physical ? TIN_MEMORY_SPACE3_PHYS : TIN_MEMORY_SPACE3_LOG; break; - case 'o': *flags |= TIN_MEMORY_OPCODE; break; - case 'r': *flags |= TIN_MEMORY_RAMWRITE; break; - case 'm': *flags |= TIN_MEMORY_REGION; break; - default: return MAKE_EXPRERR_INVALID_MEMORY_SPACE(offset + (buffer - startbuffer)); - } - - /* convert the size to flags */ - switch (size) - { - case 'b': *flags |= TIN_MEMORY_BYTE; break; - case 'w': *flags |= TIN_MEMORY_WORD; break; - case 'd': *flags |= TIN_MEMORY_DWORD; break; - case 'q': *flags |= TIN_MEMORY_QWORD; break; - default: return MAKE_EXPRERR_INVALID_MEMORY_SIZE(offset + (buffer - startbuffer) + length - 1); - } - - /* validate the name */ - if (expr->callbacks.valid != NULL) - { - EXPRERR err = (*expr->callbacks.valid)(expr->cbparam, namestring, (*flags & TIN_MEMORY_SPACE_MASK) >> TIN_MEMORY_SPACE_SHIFT); - if (err == EXPRERR_INVALID_MEMORY_SPACE) - return MAKE_EXPRERR_INVALID_MEMORY_SPACE(offset + (buffer - startbuffer)); - else if (err != EXPRERR_NONE) - return MAKE_EXPRERR(err, offset); - } - - return EXPRERR_NONE; -} - - -/*------------------------------------------------- - parse_string_into_tokens - take an expression - string and break it into a sequence of tokens --------------------------------------------------*/ - -static EXPRERR parse_string_into_tokens(const char *stringstart, parsed_expression *expr, const symbol_table *table) -{ - #define SET_TOKEN_INFO(_length, _type, _value, _info) \ - do { \ - token->type = _type; \ - token->value.i = _value; \ - token->info = _info; \ - string += _length; \ - } while (0) - - parse_token *token = expr->token; + // loop until done + const char *stringstart = m_original_string; const char *string = stringstart; - - /* stash the symbol table pointer */ - expr->table = table; - - /* make a copy of the original string */ - expr->original_string = (char *)osd_malloc(strlen(stringstart) + 1); - if (!expr->original_string) - return MAKE_EXPRERR_OUT_OF_MEMORY(0); - strcpy(expr->original_string, stringstart); - - /* loop until done */ - while (string[0] != 0 && token - expr->token < MAX_TOKENS) + while (string[0] != 0) { - /* ignore any whitespace */ + // ignore any whitespace while (string[0] != 0 && isspace((UINT8)string[0])) string++; if (string[0] == 0) break; - /* initialize the current token object */ - SET_TOKEN_INFO(0, TOK_INVALID, 0, 0); - token->offset = string - stringstart; + // initialize the current token object + parse_token &token = m_tokenlist.append(*global_alloc(parse_token(string - stringstart))); - /* switch off the first character */ + // switch off the first character switch (tolower((UINT8)string[0])) { case '(': - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_LPAREN, TIN_PRECEDENCE_0); + string += 1, token.configure_operator(TVL_LPAREN, 0); break; case ')': - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_RPAREN, TIN_PRECEDENCE_0); + string += 1, token.configure_operator(TVL_RPAREN, 0); break; case '~': - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_NOT, TIN_PRECEDENCE_2); + string += 1, token.configure_operator(TVL_NOT, 2); break; case ',': - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_COMMA, TIN_PRECEDENCE_14); + string += 1, token.configure_operator(TVL_COMMA, 14); break; case '+': if (string[1] == '+') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_PLUSPLUS, TIN_PRECEDENCE_1); + string += 2, token.configure_operator(TVL_PLUSPLUS, 1); else if (string[1] == '=') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNADD, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT); + string += 2, token.configure_operator(TVL_ASSIGNADD, 13).set_right_to_left(); else - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_ADD, TIN_PRECEDENCE_4); + string += 1, token.configure_operator(TVL_ADD, 4); break; case '-': if (string[1] == '-') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_MINUSMINUS, TIN_PRECEDENCE_1); + string += 2, token.configure_operator(TVL_MINUSMINUS, 1); else if (string[1] == '=') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNSUBTRACT, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT); + string += 2, token.configure_operator(TVL_ASSIGNSUBTRACT, 13).set_right_to_left(); else - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_SUBTRACT, TIN_PRECEDENCE_4); + string += 1, token.configure_operator(TVL_SUBTRACT, 4); break; case '*': if (string[1] == '=') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNMULTIPLY, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT); + string += 2, token.configure_operator(TVL_ASSIGNMULTIPLY, 13).set_right_to_left(); else - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_MULTIPLY, TIN_PRECEDENCE_3); + string += 1, token.configure_operator(TVL_MULTIPLY, 3); break; case '/': if (string[1] == '=') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNDIVIDE, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT); + string += 2, token.configure_operator(TVL_ASSIGNDIVIDE, 13).set_right_to_left(); else - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_DIVIDE, TIN_PRECEDENCE_3); + string += 1, token.configure_operator(TVL_DIVIDE, 3); break; case '%': if (string[1] == '=') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNMODULO, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT); + string += 2, token.configure_operator(TVL_ASSIGNMODULO, 13).set_right_to_left(); else - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_MODULO, TIN_PRECEDENCE_3); + string += 1, token.configure_operator(TVL_MODULO, 3); break; case '<': if (string[1] == '<' && string[2] == '=') - SET_TOKEN_INFO(3, TOK_OPERATOR, TVL_ASSIGNLSHIFT, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT); + string += 3, token.configure_operator(TVL_ASSIGNLSHIFT, 13).set_right_to_left(); else if (string[1] == '<') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_LSHIFT, TIN_PRECEDENCE_5); + string += 2, token.configure_operator(TVL_LSHIFT, 5); else if (string[1] == '=') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_LESSOREQUAL, TIN_PRECEDENCE_6); + string += 2, token.configure_operator(TVL_LESSOREQUAL, 6); else - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_LESS, TIN_PRECEDENCE_6); + string += 1, token.configure_operator(TVL_LESS, 6); break; case '>': if (string[1] == '>' && string[2] == '=') - SET_TOKEN_INFO(3, TOK_OPERATOR, TVL_ASSIGNRSHIFT, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT); + string += 3, token.configure_operator(TVL_ASSIGNRSHIFT, 13).set_right_to_left(); else if (string[1] == '>') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_RSHIFT, TIN_PRECEDENCE_5); + string += 2, token.configure_operator(TVL_RSHIFT, 5); else if (string[1] == '=') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_GREATEROREQUAL, TIN_PRECEDENCE_6); + string += 2, token.configure_operator(TVL_GREATEROREQUAL, 6); else - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_GREATER, TIN_PRECEDENCE_6); + string += 1, token.configure_operator(TVL_GREATER, 6); break; case '=': if (string[1] == '=') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_EQUAL, TIN_PRECEDENCE_7); + string += 2, token.configure_operator(TVL_EQUAL, 7); else - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_ASSIGN, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT); + string += 1, token.configure_operator(TVL_ASSIGN, 13).set_right_to_left(); break; case '!': if (string[1] == '=') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_NOTEQUAL, TIN_PRECEDENCE_7); + string += 2, token.configure_operator(TVL_NOTEQUAL, 7); else - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_COMPLEMENT, TIN_PRECEDENCE_2); + string += 2, token.configure_operator(TVL_COMPLEMENT, 2); break; case '&': if (string[1] == '&') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_LAND, TIN_PRECEDENCE_11); + string += 2, token.configure_operator(TVL_LAND, 11); else if (string[1] == '=') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNBAND, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT); + string += 2, token.configure_operator(TVL_ASSIGNBAND, 13).set_right_to_left(); else - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_BAND, TIN_PRECEDENCE_8); + string += 1, token.configure_operator(TVL_BAND, 8); break; case '|': if (string[1] == '|') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_LOR, TIN_PRECEDENCE_12); + string += 2, token.configure_operator(TVL_LOR, 12); else if (string[1] == '=') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNBOR, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT); + string += 2, token.configure_operator(TVL_ASSIGNBOR, 13).set_right_to_left(); else - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_BOR, TIN_PRECEDENCE_10); + string += 1, token.configure_operator(TVL_BOR, 10); break; case '^': if (string[1] == '=') - SET_TOKEN_INFO(2, TOK_OPERATOR, TVL_ASSIGNBXOR, TIN_PRECEDENCE_13 | TIN_RIGHT_TO_LEFT); + string += 2, token.configure_operator(TVL_ASSIGNBXOR, 13).set_right_to_left(); else - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_BXOR, TIN_PRECEDENCE_9); + string += 1, token.configure_operator(TVL_BXOR, 9); break; case '"': - { - char buffer[MAX_STRING_LENGTH]; - int bufindex = 0; - - /* accumulate a copy of the string */ - string++; - while (string[0] != 0 && bufindex < MAX_STRING_LENGTH) - { - /* allow "" to mean a nested double-quote */ - if (string[0] == '"') - { - if (string[1] != '"') - break; - string++; - } - buffer[bufindex++] = *string++; - } - - /* if we didn't find the ending quote, report an error */ - if (string[0] != '"') - return MAKE_EXPRERR_UNBALANCED_QUOTES(token->offset); - string++; - - /* make the token */ - token->value.p = add_expression_string(expr, buffer, bufindex, NULL); - if (token->value.p == NULL) - return MAKE_EXPRERR_OUT_OF_MEMORY(token->offset); - token->type = TOK_STRING; + parse_quoted_string(token, string); break; - } case '\'': - { - UINT64 value = 0; - - /* accumulate the value of the character token */ - string++; - while (string[0] != 0) - { - /* allow '' to mean a nested single quote */ - if (string[0] == '\'') - { - if (string[1] != '\'') - break; - string++; - } - value = (value << 8) | (UINT8)*string++; - } - - /* if we didn't find the ending quote, report an error */ - if (string[0] != '\'') - return MAKE_EXPRERR_UNBALANCED_QUOTES(token->offset); - string++; - - /* make it a number token */ - token->type = TOK_NUMBER; - token->value.i = value; + parse_quoted_char(token, string); break; - } default: - { - static const char valid[] = "abcdefghijklmnopqrstuvwxyz0123456789_$#.:"; - static const char numbers[] = "0123456789abcdef"; - int bufindex = 0, must_be_number = 0, numbase = DEFAULT_BASE; - char buffer[MAX_SYMBOL_LENGTH]; - UINT64 value; - - /* accumulate a lower-case version of the symbol */ - while (1) - { - char val = tolower((UINT8)string[0]); - if (val == 0 || strchr(valid, val) == NULL) - break; - buffer[bufindex++] = val; - string++; - } - buffer[bufindex] = 0; - - /* check for memory @ operators */ - if (string[0] == '@') - { - token_info info; - EXPRERR err = parse_memory_operator(expr, token->offset, buffer, &info); - if (err != EXPRERR_NONE) - return err; - SET_TOKEN_INFO(1, TOK_OPERATOR, TVL_MEMORYAT, TIN_PRECEDENCE_2 | info); - break; - } - - /* empty string is automatically invalid */ - if (buffer[0] == 0) - return MAKE_EXPRERR_INVALID_TOKEN(token->offset); - - /* check for wordy variants on standard operators */ - else if (strcmp(buffer, "bnot") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_NOT, TIN_PRECEDENCE_2); - else if (strcmp(buffer, "plus") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_ADD, TIN_PRECEDENCE_4); - else if (strcmp(buffer, "minus") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_SUBTRACT, TIN_PRECEDENCE_4); - else if (strcmp(buffer, "times") == 0 || strcmp(buffer, "mul") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_MULTIPLY, TIN_PRECEDENCE_3); - else if (strcmp(buffer, "div") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_DIVIDE, TIN_PRECEDENCE_3); - else if (strcmp(buffer, "mod") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_MODULO, TIN_PRECEDENCE_3); - else if (strcmp(buffer, "lt") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_LESS, TIN_PRECEDENCE_6); - else if (strcmp(buffer, "le") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_LESSOREQUAL, TIN_PRECEDENCE_6); - else if (strcmp(buffer, "gt") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_GREATER, TIN_PRECEDENCE_6); - else if (strcmp(buffer, "ge") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_GREATEROREQUAL, TIN_PRECEDENCE_6); - else if (strcmp(buffer, "eq") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_EQUAL, TIN_PRECEDENCE_7); - else if (strcmp(buffer, "ne") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_NOTEQUAL, TIN_PRECEDENCE_7); - else if (strcmp(buffer, "not") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_COMPLEMENT, TIN_PRECEDENCE_2); - else if (strcmp(buffer, "and") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_LAND, TIN_PRECEDENCE_8); - else if (strcmp(buffer, "band") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_BAND, TIN_PRECEDENCE_8); - else if (strcmp(buffer, "or") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_LOR, TIN_PRECEDENCE_12); - else if (strcmp(buffer, "bor") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_BOR, TIN_PRECEDENCE_10); - else if (strcmp(buffer, "bxor") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_BXOR, TIN_PRECEDENCE_9); - else if (strcmp(buffer, "lshift") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_LSHIFT, TIN_PRECEDENCE_5); - else if (strcmp(buffer, "rshift") == 0) - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_RSHIFT, TIN_PRECEDENCE_5); - - /* process anything else as a number or string */ - else - { - /* if we have a number prefix, assume it is a number */ - bufindex = 0; - if (buffer[0] == '0' && buffer[1] == 'x') { numbase = 16; bufindex += 2; must_be_number = 1; } - else if (buffer[0] == '#') { numbase = 10; bufindex++; must_be_number = 1; } - - /* if we're not forced to be a number, check for a symbol match first */ - if (!must_be_number) - { - const symbol_entry *symbol = symtable_find(expr->table, buffer); - if (symbol != NULL) - { - token->type = TOK_SYMBOL; - token->value.p = (void *)symbol; - - /* if this is a function symbol, synthesize an execute function operator */ - if (symbol->type == SMT_FUNCTION) - { - token++; - SET_TOKEN_INFO(0, TOK_OPERATOR, TVL_EXECUTEFUNC, TIN_PRECEDENCE_0); - } - } - } - - /* see if we parse as a number */ - if (token->type == TOK_INVALID) - { - if (buffer[0] == '$') { numbase = 16; bufindex++; must_be_number = 1; } - value = 0; - while (buffer[bufindex] != 0) - { - const char *ptr = strchr(numbers, tolower((UINT8)buffer[bufindex])); - int digit; - - if (ptr == NULL) - break; - digit = ptr - numbers; - if (digit >= numbase) - break; - value = (value * (UINT64)numbase) + digit; - bufindex++; - } - - /* if we succeeded as a number, make it so */ - if (buffer[bufindex] == 0) - { - token->type = TOK_NUMBER; - token->value.i = value; - } - } - - /* report errors */ - if (token->type == TOK_INVALID) - { - if (must_be_number) - return MAKE_EXPRERR_INVALID_NUMBER(token->offset); - else - return MAKE_EXPRERR_UNKNOWN_SYMBOL(token->offset); - } - } + parse_symbol_or_number(token, string); break; - } } - - /* advance to the next token */ - token++; } - - /* add an ending token */ - token->type = TOK_END; - token->value.i = 0; - return EXPRERR_NONE; } +//------------------------------------------------- +// parse_symbol_or_number - parse a substring +// into either a symbol or a number or an +// expanded operator +//------------------------------------------------- -/*************************************************************************** - INFIX TO POSTFIX CONVERSION -***************************************************************************/ - -/*------------------------------------------------- - normalize_operator - resolve operator - ambiguities based on neighboring tokens --------------------------------------------------*/ - -static EXPRERR normalize_operator(parsed_expression *expr, int tokindex) +void parsed_expression::parse_symbol_or_number(parse_token &token, const char *&string) { - parse_token *thistoken = &expr->token[tokindex]; - parse_token *nexttoken = thistoken + 1; - parse_token *prevtoken = (tokindex == 0) ? NULL : (thistoken - 1); - - switch (thistoken->value.i) + // accumulate a lower-case version of the symbol + const char *stringstart = string; + astring buffer; + while (1) { - /* Determine if an open paren is part of a function or not */ + static const char valid[] = "abcdefghijklmnopqrstuvwxyz0123456789_$#.:"; + char val = tolower((UINT8)string[0]); + if (val == 0 || strchr(valid, val) == NULL) + break; + buffer.cat(&val, 1); + string++; + } + + // check for memory @ operators + if (string[0] == '@') + { + string += 1; + return parse_memory_operator(token, buffer); + } + + // empty string is automatically invalid + if (!buffer) + throw expression_error(expression_error::INVALID_TOKEN, token.offset()); + + // check for wordy variants on standard operators + if (buffer == "bnot") + { token.configure_operator(TVL_NOT, 2); return; } + if (buffer == "plus") + { token.configure_operator(TVL_ADD, 4); return; } + if (buffer == "minus") + { token.configure_operator(TVL_SUBTRACT, 4); return; } + if (buffer == "times" || buffer == "mul") + { token.configure_operator(TVL_MULTIPLY, 3); return; } + if (buffer == "div") + { token.configure_operator(TVL_DIVIDE, 3); return; } + if (buffer == "mod") + { token.configure_operator(TVL_MODULO, 3); return; } + if (buffer == "lt") + { token.configure_operator(TVL_LESS, 6); return; } + if (buffer == "le") + { token.configure_operator(TVL_LESSOREQUAL, 6); return; } + if (buffer == "gt") + { token.configure_operator(TVL_GREATER, 6); return; } + if (buffer == "ge") + { token.configure_operator(TVL_GREATEROREQUAL, 6); return; } + if (buffer == "eq") + { token.configure_operator(TVL_EQUAL, 7); return; } + if (buffer == "ne") + { token.configure_operator(TVL_NOTEQUAL, 7); return; } + if (buffer == "not") + { token.configure_operator(TVL_COMPLEMENT, 2); return; } + if (buffer == "and") + { token.configure_operator(TVL_LAND, 8); return; } + if (buffer == "band") + { token.configure_operator(TVL_BAND, 8); return; } + if (buffer == "or") + { token.configure_operator(TVL_LOR, 12); return; } + if (buffer == "bor") + { token.configure_operator(TVL_BOR, 10); return; } + if (buffer == "bxor") + { token.configure_operator(TVL_BXOR, 9); return; } + if (buffer == "lshift") + { token.configure_operator(TVL_LSHIFT, 5); return; } + if (buffer == "rshift") + { token.configure_operator(TVL_RSHIFT, 5); return; } + + // if we have an 0x prefix, we must be a hex value + if (buffer[0] == '0' && buffer[1] == 'x') + return parse_number(token, &buffer[2], 16, expression_error::INVALID_NUMBER); + + // if we have a # prefix, we must be a decimal value + if (buffer[0] == '#') + return parse_number(token, &buffer[1], 10, expression_error::INVALID_NUMBER); + + // if we have a $ prefix, we are a hex value + if (buffer[0] == '$') + return parse_number(token, &buffer[1], 16, expression_error::INVALID_NUMBER); + + // check for a symbol match + symbol_entry *symbol = m_symtable->find(buffer); + if (symbol != NULL) + { + token.configure_symbol(*symbol); + + // if this is a function symbol, synthesize an execute function operator + if (symbol->is_function()) + { + token = m_tokenlist.append(*global_alloc(parse_token(string - stringstart))); + token.configure_operator(TVL_EXECUTEFUNC, 0); + } + return; + } + + // attempt to parse as a number in the default base + parse_number(token, buffer, DEFAULT_BASE, expression_error::UNKNOWN_SYMBOL); +} + + +//------------------------------------------------- +// parse_number - parse a number using the +// given base +//------------------------------------------------- + +void parsed_expression::parse_number(parse_token &token, const char *string, int base, expression_error::error_code errcode) +{ + // parse the actual value + UINT64 value = 0; + while (*string != 0) + { + // look up the number's value, stopping if not valid + static const char numbers[] = "0123456789abcdef"; + const char *ptr = strchr(numbers, tolower((UINT8)*string)); + if (ptr == NULL) + break; + + // if outside of the base, we also stop + int digit = ptr - numbers; + if (digit >= base) + break; + + // shift previous digits up and add in new digit + value = (value * (UINT64)base) + digit; + string++; + } + + // if we succeeded as a number, make it so + if (*string == 0) + token.configure_number(value); + else + throw expression_error(errcode, token.offset()); +} + + +//------------------------------------------------- +// parse_quoted_char - parse a single-quoted +// character constant +//------------------------------------------------- + +void parsed_expression::parse_quoted_char(parse_token &token, const char *&string) +{ + // accumulate the value of the character token + string++; + UINT64 value = 0; + while (string[0] != 0) + { + // allow '' to mean a nested single quote + if (string[0] == '\'') + { + if (string[1] != '\'') + break; + string++; + } + value = (value << 8) | (UINT8)*string++; + } + + // if we didn't find the ending quote, report an error + if (string[0] != '\'') + throw expression_error(expression_error::UNBALANCED_QUOTES, token.offset()); + string++; + + // make it a number token + token.configure_number(value); +} + + +//------------------------------------------------- +// parse_quoted_string - parse a double-quoted +// string constant +//------------------------------------------------- + +void parsed_expression::parse_quoted_string(parse_token &token, const char *&string) +{ + // accumulate a copy of the quoted string + string++; + astring buffer; + while (string[0] != 0) + { + // allow "" to mean a nested double-quote + if (string[0] == '"') + { + if (string[1] != '"') + break; + string++; + } + buffer.cat(string++, 1); + } + + // if we didn't find the ending quote, report an error + if (string[0] != '"') + throw expression_error(expression_error::UNBALANCED_QUOTES, token.offset()); + string++; + + // make the token + token.configure_string(m_stringlist.append(*global_alloc(expression_string(buffer)))); +} + + +//------------------------------------------------- +// parse_memory_operator - parse the several +// forms of memory operators +//------------------------------------------------- + +void parsed_expression::parse_memory_operator(parse_token &token, const char *string) +{ + // if there is a '.', it means we have a name + const char *startstring = string; + const char *namestring = NULL; + const char *dot = strrchr(string, '.'); + if (dot != NULL) + { + namestring = m_stringlist.append(*global_alloc(expression_string(string, dot - string))); + string = dot + 1; + } + + // length 3 means logical/physical, then space, then size + int length = (int)strlen(string); + bool physical = false; + int space = 'p'; + int size; + if (length == 3) + { + if (string[0] != 'l' && string[0] != 'p') + throw expression_error(expression_error::INVALID_MEMORY_SPACE, token.offset() + (string - startstring)); + if (string[1] != 'p' && string[1] != 'd' && string[1] != 'i' && string[1] != '3') + throw expression_error(expression_error::INVALID_MEMORY_SPACE, token.offset() + (string - startstring)); + physical = (string[0] == 'p'); + space = string[1]; + size = string[2]; + } + + // length 2 means space then size + else if (length == 2) + { + space = string[0]; + size = string[1]; + } + + // length 1 means size + else if (length == 1) + size = string[0]; + + // anything else is invalid + else + throw expression_error(expression_error::INVALID_TOKEN, token.offset()); + + // convert the space to flags + expression_space memspace = EXPSPACE_INVALID; + switch (space) + { + case 'p': memspace = physical ? EXPSPACE_PROGRAM_PHYSICAL : EXPSPACE_PROGRAM_LOGICAL; break; + case 'd': memspace = physical ? EXPSPACE_DATA_PHYSICAL : EXPSPACE_DATA_LOGICAL; break; + case 'i': memspace = physical ? EXPSPACE_IO_PHYSICAL : EXPSPACE_IO_LOGICAL; break; + case '3': memspace = physical ? EXPSPACE_SPACE3_PHYSICAL : EXPSPACE_SPACE3_LOGICAL; break; + case 'o': memspace = EXPSPACE_OPCODE; break; + case 'r': memspace = EXPSPACE_RAMWRITE; break; + case 'm': memspace = EXPSPACE_REGION; break; + default: throw expression_error(expression_error::INVALID_MEMORY_SPACE, token.offset() + (string - startstring)); + } + + // convert the size to flags + int memsize; + switch (size) + { + case 'b': memsize = 0; break; + case 'w': memsize = 1; break; + case 'd': memsize = 2; break; + case 'q': memsize = 3; break; + default: throw expression_error(expression_error::INVALID_MEMORY_SIZE, token.offset() + (string - startstring) + length - 1); + } + + // validate the name + if (m_symtable != NULL) + { + expression_error::error_code err = m_symtable->memory_valid(namestring, memspace); + if (err != expression_error::NONE) + throw expression_error(err, token.offset() + (string - startstring)); + } + + // configure the token + token.configure_operator(TVL_MEMORYAT, 2).set_memory_size(memsize).set_memory_space(memspace).set_memory_source(namestring); +} + + +//------------------------------------------------- +// normalize_operator - resolve operator +// ambiguities based on neighboring tokens +//------------------------------------------------- + +void parsed_expression::normalize_operator(parse_token *prevtoken, parse_token &thistoken) +{ + parse_token *nexttoken = thistoken.next(); + switch (thistoken.optype()) + { + // Determine if an open paren is part of a function or not case TVL_LPAREN: - if (prevtoken != NULL && prevtoken->type == TOK_OPERATOR && prevtoken->value.i == TVL_EXECUTEFUNC) - thistoken->info |= TIN_FUNCTION; + if (prevtoken != NULL && prevtoken->is_operator(TVL_EXECUTEFUNC)) + thistoken.set_function_separator(); break; - /* Determine if ++ is a pre or post increment */ + // Determine if ++ is a pre or post increment case TVL_PLUSPLUS: - if (nexttoken->type == TOK_SYMBOL || (nexttoken->type == TOK_OPERATOR && nexttoken->value.i == TVL_MEMORYAT)) - { - thistoken->value.i = TVL_PREINCREMENT; - thistoken->info = TIN_PRECEDENCE_2; - } - else if (prevtoken != NULL && (prevtoken->type == TOK_SYMBOL || (prevtoken->type == TOK_OPERATOR && prevtoken->value.i == TVL_MEMORYAT))) - { - thistoken->value.i = TVL_POSTINCREMENT; - thistoken->info = TIN_PRECEDENCE_1; - } + if (nexttoken != NULL && (nexttoken->is_symbol() || (nexttoken->is_operator(TVL_MEMORYAT)))) + thistoken.configure_operator(TVL_PREINCREMENT, 2); + else if (prevtoken != NULL && (prevtoken->is_symbol() || (prevtoken->is_operator(TVL_MEMORYAT)))) + thistoken.configure_operator(TVL_POSTINCREMENT, 1); else - return MAKE_EXPRERR_SYNTAX(thistoken->offset); + throw expression_error(expression_error::SYNTAX, thistoken.offset()); break; - /* Determine if -- is a pre or post decrement */ + // Determine if -- is a pre or post decrement case TVL_MINUSMINUS: - if (nexttoken->type == TOK_SYMBOL || (nexttoken->type == TOK_OPERATOR && nexttoken->value.i == TVL_MEMORYAT)) - { - thistoken->value.i = TVL_PREDECREMENT; - thistoken->info = TIN_PRECEDENCE_2; - } - else if (prevtoken != NULL && (prevtoken->type == TOK_SYMBOL || (prevtoken->type == TOK_OPERATOR && prevtoken->value.i == TVL_MEMORYAT))) - { - thistoken->value.i = TVL_POSTDECREMENT; - thistoken->info = TIN_PRECEDENCE_1; - } + if (nexttoken != NULL && (nexttoken->is_symbol() || (nexttoken->is_operator(TVL_MEMORYAT)))) + thistoken.configure_operator(TVL_PREDECREMENT, 2); + else if (prevtoken != NULL && (prevtoken->is_symbol() || (prevtoken->is_operator(TVL_MEMORYAT)))) + thistoken.configure_operator(TVL_POSTDECREMENT, 1); else - return MAKE_EXPRERR_SYNTAX(thistoken->offset); + throw expression_error(expression_error::SYNTAX, thistoken.offset()); break; - /* Determine if +/- is a unary or binary */ + // Determine if +/- is a unary or binary case TVL_ADD: case TVL_SUBTRACT: - /* Assume we're unary if we are the first token, or if the previous token is not - a symbol, a number, or a right parenthesis */ - if (prevtoken == NULL || - (prevtoken->type != TOK_SYMBOL && prevtoken->type != TOK_NUMBER && - (prevtoken->type != TOK_OPERATOR || prevtoken->value.i != TVL_RPAREN))) - { - thistoken->value.i = (thistoken->value.i == TVL_ADD) ? TVL_UPLUS : TVL_UMINUS; - thistoken->info = TIN_PRECEDENCE_2; - } + // Assume we're unary if we are the first token, or if the previous token is not + // a symbol, a number, or a right parenthesis + if (prevtoken == NULL || (!prevtoken->is_symbol() && !prevtoken->is_number() && !prevtoken->is_operator(TVL_RPAREN))) + thistoken.configure_operator(thistoken.is_operator(TVL_ADD) ? TVL_UPLUS : TVL_UMINUS, 2); break; - /* Determine if , refers to a function parameter */ + // Determine if , refers to a function parameter case TVL_COMMA: - { - int lookback; - - for (lookback = 0; lookback < MAX_STACK_DEPTH; lookback++) + for (int lookback = 0; lookback < MAX_STACK_DEPTH; lookback++) { - parse_token *peek = peek_token(expr, lookback); - if (!peek) + parse_token *peek = peek_token(lookback); + if (peek == NULL) break; - if (peek->value.i == TVL_LPAREN) + + // if we hit an execute function operator, or else a left parenthesis that is + // already tagged, then tag us as well + if (peek->is_operator(TVL_EXECUTEFUNC) || (peek->is_operator(TVL_LPAREN) && peek->is_function_separator())) { - if (peek->info & TIN_FUNCTION) - thistoken->info |= TIN_FUNCTION; - break; - } - if (peek->value.i == TVL_EXECUTEFUNC) - { - thistoken->info |= TIN_FUNCTION; + thistoken.set_function_separator(); break; } } break; - } } - return EXPRERR_NONE; } -/*------------------------------------------------- - infix_to_postfix - convert an infix sequence - of tokens to a postfix sequence for processing --------------------------------------------------*/ +//------------------------------------------------- +// infix_to_postfix - convert an infix sequence +// of tokens to a postfix sequence for processing +//------------------------------------------------- -static EXPRERR infix_to_postfix(parsed_expression *expr) +void parsed_expression::infix_to_postfix() { - parse_token *dest = expr->token; - parse_token dummy; - parse_token *peek; - int tokindex = 0; - EXPRERR exprerr; + simple_list stack; - memset(&dummy, 0, sizeof(dummy)); - - /* start with an empty stack */ - init_token_stack(expr); - - /* loop over all the original tokens */ - for ( ; expr->token[tokindex].type != TOK_END; tokindex++) + // loop over all the original tokens + parse_token *prev = NULL; + parse_token *next = NULL; + for (parse_token *token = m_tokenlist.detach_all(); token != NULL; prev = token, token = next) { - parse_token *token = &expr->token[tokindex]; + // pre-determine our next token + next = token->next(); + + // if the character is an operand, append it to the result string + if (token->is_number() || token->is_symbol() || token->is_string()) + m_tokenlist.append(*token); - /* If the character is an operand, append it to the result string */ - if (token->type == TOK_NUMBER || token->type == TOK_SYMBOL || token->type == TOK_STRING) - *dest++ = *token; - - /* If this is an operator, process it */ - else if (token->type == TOK_OPERATOR) + // if this is an operator, process it + else if (token->is_operator()) { - exprerr = normalize_operator(expr, tokindex); - if (exprerr != 0) - return exprerr; + // normalize the operator based on neighbors + normalize_operator(prev, *token); - /* If the token is an opening parenthesis, push it onto the stack. */ - if (token->value.i == TVL_LPAREN) - { - exprerr = push_token(expr, token); - if (exprerr != 0) - return exprerr; - } + // if the token is an opening parenthesis, push it onto the stack. + if (token->is_operator(TVL_LPAREN)) + stack.prepend(*token); - /* If the token is a closing parenthesis, pop all operators until we - reach an opening parenthesis and append them to the result string. */ - else if (token->value.i == TVL_RPAREN) + // if the token is a closing parenthesis, pop all operators until we + // reach an opening parenthesis and append them to the result string, + // discaring the open parenthesis + else if (token->is_operator(TVL_RPAREN)) { - /* loop until we can't peek at the stack anymore */ - while ((peek = peek_token(expr, 0)) != NULL) + // loop until we find our matching opener + parse_token *popped; + while ((popped = stack.detach_head()) != NULL) { - if (peek->value.i == TVL_LPAREN) + if (popped->is_operator(TVL_LPAREN)) break; - exprerr = pop_token(expr, dest++); - if (exprerr != 0) - return exprerr; + m_tokenlist.append(*popped); } - /* if we didn't find an open paren, it's an error */ - if (peek == NULL) - return MAKE_EXPRERR_UNBALANCED_PARENS(token->offset); + // if we didn't find an open paren, it's an error + if (popped == NULL) + throw expression_error(expression_error::UNBALANCED_PARENS, token->offset()); - /* pop the open paren off the stack */ - exprerr = pop_token(expr, &dummy); - if (exprerr != 0) - return exprerr; + // free ourself and our matching opening parenthesis + global_free(token); + global_free(popped); } - /* If the token is an operator, pop operators until we reach an opening parenthesis, - an operator of lower precedence, or a right associative symbol of equal precedence. - Push the operator onto the stack. */ + // if the token is an operator, pop operators until we reach an opening parenthesis, + // an operator of lower precedence, or a right associative symbol of equal precedence. + // Push the operator onto the stack. else { - int our_precedence = token->info & TIN_PRECEDENCE_MASK; + int our_precedence = token->precedence(); - /* loop until we can't peek at the stack anymore */ - while ((peek = peek_token(expr, 0)) != NULL) + // loop until we can't peek at the stack anymore + parse_token *peek; + while ((peek = stack.first()) != NULL) { - int stack_precedence = peek->info & TIN_PRECEDENCE_MASK; - - /* break if any of the above conditions are true */ - if (peek->value.i == TVL_LPAREN) + // break if any of the above conditions are true + if (peek->is_operator(TVL_LPAREN)) break; - if (stack_precedence > our_precedence) - break; - if (stack_precedence == our_precedence && (peek->info & TIN_RIGHT_TO_LEFT)) + int stack_precedence = peek->precedence(); + if (stack_precedence > our_precedence || (stack_precedence == our_precedence && peek->right_to_left())) break; - /* pop this token */ - exprerr = pop_token(expr, dest++); - if (exprerr != 0) - return exprerr; + // pop this token + m_tokenlist.append(*stack.detach_head()); } - /* push the new operator */ - exprerr = push_token(expr, token); - if (exprerr != 0) - return exprerr; + // push the new operator + stack.prepend(*token); } } } - /* finish popping the stack */ - while ((peek = peek_token(expr, 0)) != NULL) + // finish popping the stack + parse_token *popped; + while ((popped = stack.detach_head()) != NULL) { - /* it is an error to have a left parenthesis still on the stack */ - if (peek->value.i == TVL_LPAREN) - return MAKE_EXPRERR_UNBALANCED_PARENS(peek->offset); + // it is an error to have a left parenthesis still on the stack + if (popped->is_operator(TVL_LPAREN)) + throw expression_error(expression_error::UNBALANCED_PARENS, popped->offset()); - /* pop this token */ - exprerr = pop_token(expr, dest++); - if (exprerr != 0) - return exprerr; + // pop this token + m_tokenlist.append(*popped); + } +} + + +//------------------------------------------------- +// push_token - push a token onto the stack +//------------------------------------------------- + +inline void parsed_expression::push_token(parse_token &token) +{ + // check for overflow + if (m_token_stack_ptr >= MAX_STACK_DEPTH) + throw expression_error(expression_error::STACK_OVERFLOW, token.offset()); + + // push + m_token_stack[m_token_stack_ptr++] = token; +} + + +//------------------------------------------------- +// pop_token - pop a token off the stack +//------------------------------------------------- + +inline void parsed_expression::pop_token(parse_token &token) +{ + // check for underflow + if (m_token_stack_ptr == 0) + throw expression_error(expression_error::STACK_UNDERFLOW, token.offset()); + + // pop + token = m_token_stack[--m_token_stack_ptr]; +} + + +//------------------------------------------------- +// peek_token - look at a token some number of +// entries up the stack +//------------------------------------------------- + +inline parsed_expression::parse_token *parsed_expression::peek_token(int count) +{ + if (m_token_stack_ptr <= count) + return NULL; + return &m_token_stack[m_token_stack_ptr - count - 1]; +} + + +//------------------------------------------------- +// pop_token_lval - pop a token off the stack +// and ensure that it is a proper lval +//------------------------------------------------- + +inline void parsed_expression::pop_token_lval(parse_token &token) +{ + // start with normal pop + pop_token(token); + + // if we're not an lval, throw an error + if (!token.is_lval()) + throw expression_error(expression_error::NOT_LVAL, token.offset()); +} + + +//------------------------------------------------- +// pop_token_rval - pop a token off the stack +// and ensure that it is a proper rval +//------------------------------------------------- + +inline void parsed_expression::pop_token_rval(parse_token &token) +{ + // start with normal pop + pop_token(token); + + // symbol and memory tokens get resolved down to number tokens + if (token.is_symbol() || token.is_memory()) + token.configure_number(token.get_lval_value(m_symtable)); + + // to be an rval, the final token must be a number + if (!token.is_number()) + throw expression_error(expression_error::NOT_RVAL, token.offset()); +} + + +//------------------------------------------------- +// execute_tokens - execute a postfix sequence +// of tokens +//------------------------------------------------- + +UINT64 parsed_expression::execute_tokens() +{ + // reset the token stack + m_token_stack_ptr = 0; + + // loop over the entire sequence + parse_token t1, t2, result; + for (parse_token *token = m_tokenlist.first(); token != NULL; token = token->next()) + { + // symbols/numbers/strings just get pushed + if (!token->is_operator()) + { + push_token(*token); + continue; + } + + // otherwise, switch off the operator + switch (token->optype()) + { + case TVL_PREINCREMENT: + pop_token_lval(t1); + push_token(result.configure_number(t1.get_lval_value(m_symtable) + 1).set_offset(t1)); + t1.set_lval_value(m_symtable, result.value()); + break; + + case TVL_PREDECREMENT: + pop_token_lval(t1); + push_token(result.configure_number(t1.get_lval_value(m_symtable) - 1).set_offset(t1)); + t1.set_lval_value(m_symtable, result.value()); + break; + + case TVL_POSTINCREMENT: + pop_token_lval(t1); + push_token(result.configure_number(t1.get_lval_value(m_symtable)).set_offset(t1)); + t1.set_lval_value(m_symtable, result.value() + 1); + break; + + case TVL_POSTDECREMENT: + pop_token_lval(t1); + push_token(result.configure_number(t1.get_lval_value(m_symtable)).set_offset(t1)); + t1.set_lval_value(m_symtable, result.value() - 1); + break; + + case TVL_COMPLEMENT: + pop_token_rval(t1); + push_token(result.configure_number(!t1.value()).set_offset(t1)); + break; + + case TVL_NOT: + pop_token_rval(t1); + push_token(result.configure_number(~t1.value()).set_offset(t1)); + break; + + case TVL_UPLUS: + pop_token_rval(t1); + push_token(result.configure_number(t1.value()).set_offset(t1)); + break; + + case TVL_UMINUS: + pop_token_rval(t1); + push_token(result.configure_number(-t1.value()).set_offset(t1)); + break; + + case TVL_MULTIPLY: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() * t2.value()).set_offset(t1, t2)); + break; + + case TVL_DIVIDE: + pop_token_rval(t2); pop_token_rval(t1); + if (t2.value() == 0) + throw expression_error(expression_error::DIVIDE_BY_ZERO, t2.offset()); + push_token(result.configure_number(t1.value() / t2.value()).set_offset(t1, t2)); + break; + + case TVL_MODULO: + pop_token_rval(t2); pop_token_rval(t1); + if (t2.value() == 0) + throw expression_error(expression_error::DIVIDE_BY_ZERO, t2.offset()); + push_token(result.configure_number(t1.value() % t2.value()).set_offset(t1, t2)); + break; + + case TVL_ADD: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() + t2.value()).set_offset(t1, t2)); + break; + + case TVL_SUBTRACT: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() - t2.value()).set_offset(t1, t2)); + break; + + case TVL_LSHIFT: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() << t2.value()).set_offset(t1, t2)); + break; + + case TVL_RSHIFT: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() >> t2.value()).set_offset(t1, t2)); + break; + + case TVL_LESS: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() < t2.value()).set_offset(t1, t2)); + break; + + case TVL_LESSOREQUAL: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() <= t2.value()).set_offset(t1, t2)); + break; + + case TVL_GREATER: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() > t2.value()).set_offset(t1, t2)); + break; + + case TVL_GREATEROREQUAL: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() >= t2.value()).set_offset(t1, t2)); + break; + + case TVL_EQUAL: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() == t2.value()).set_offset(t1, t2)); + break; + + case TVL_NOTEQUAL: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() != t2.value()).set_offset(t1, t2)); + break; + + case TVL_BAND: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() & t2.value()).set_offset(t1, t2)); + break; + + case TVL_BXOR: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() ^ t2.value()).set_offset(t1, t2)); + break; + + case TVL_BOR: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() | t2.value()).set_offset(t1, t2)); + break; + + case TVL_LAND: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() && t2.value()).set_offset(t1, t2)); + break; + + case TVL_LOR: + pop_token_rval(t2); pop_token_rval(t1); + push_token(result.configure_number(t1.value() || t2.value()).set_offset(t1, t2)); + break; + + case TVL_ASSIGN: + pop_token_rval(t2); pop_token_lval(t1); + push_token(result.configure_number(t2.value()).set_offset(t2)); + t1.set_lval_value(m_symtable, t2.value()); + break; + + case TVL_ASSIGNMULTIPLY: + pop_token_rval(t2); pop_token_lval(t1); + push_token(result.configure_number(t1.get_lval_value(m_symtable) * t2.value()).set_offset(t1, t2)); + t1.set_lval_value(m_symtable, result.value()); + break; + + case TVL_ASSIGNDIVIDE: + pop_token_rval(t2); pop_token_lval(t1); + if (t2.value() == 0) + throw expression_error(expression_error::DIVIDE_BY_ZERO, t2.offset()); + push_token(result.configure_number(t1.get_lval_value(m_symtable) / t2.value()).set_offset(t1, t2)); + t1.set_lval_value(m_symtable, result.value()); + break; + + case TVL_ASSIGNMODULO: + pop_token_rval(t2); pop_token_lval(t1); + if (t2.value() == 0) + throw expression_error(expression_error::DIVIDE_BY_ZERO, t2.offset()); + push_token(result.configure_number(t1.get_lval_value(m_symtable) % t2.value()).set_offset(t1, t2)); + t1.set_lval_value(m_symtable, result.value()); + break; + + case TVL_ASSIGNADD: + pop_token_rval(t2); pop_token_lval(t1); + push_token(result.configure_number(t1.get_lval_value(m_symtable) + t2.value()).set_offset(t1, t2)); + t1.set_lval_value(m_symtable, result.value()); + break; + + case TVL_ASSIGNSUBTRACT: + pop_token_rval(t2); pop_token_lval(t1); + push_token(result.configure_number(t1.get_lval_value(m_symtable) - t2.value()).set_offset(t1, t2)); + t1.set_lval_value(m_symtable, result.value()); + break; + + case TVL_ASSIGNLSHIFT: + pop_token_rval(t2); pop_token_lval(t1); + push_token(result.configure_number(t1.get_lval_value(m_symtable) << t2.value()).set_offset(t1, t2)); + t1.set_lval_value(m_symtable, result.value()); + break; + + case TVL_ASSIGNRSHIFT: + pop_token_rval(t2); pop_token_lval(t1); + push_token(result.configure_number(t1.get_lval_value(m_symtable) >> t2.value()).set_offset(t1, t2)); + t1.set_lval_value(m_symtable, result.value()); + break; + + case TVL_ASSIGNBAND: + pop_token_rval(t2); pop_token_lval(t1); + push_token(result.configure_number(t1.get_lval_value(m_symtable) & t2.value()).set_offset(t1, t2)); + t1.set_lval_value(m_symtable, result.value()); + break; + + case TVL_ASSIGNBXOR: + pop_token_rval(t2); pop_token_lval(t1); + push_token(result.configure_number(t1.get_lval_value(m_symtable) ^ t2.value()).set_offset(t1, t2)); + t1.set_lval_value(m_symtable, result.value()); + break; + + case TVL_ASSIGNBOR: + pop_token_rval(t2); pop_token_lval(t1); + push_token(result.configure_number(t1.get_lval_value(m_symtable) | t2.value()).set_offset(t1, t2)); + t1.set_lval_value(m_symtable, result.value()); + break; + + case TVL_COMMA: + if (!token->is_function_separator()) + { + pop_token_rval(t2); pop_token_rval(t1); + push_token(t2); + } + break; + + case TVL_MEMORYAT: + pop_token_rval(t1); + push_token(result.configure_memory(t1.value(), *token)); + break; + + case TVL_EXECUTEFUNC: + execute_function(*token); + break; + + default: + throw expression_error(expression_error::SYNTAX, token->offset()); + } } - /* copy the end token to the final stream */ - *dest++ = expr->token[tokindex]; - return EXPRERR_NONE; + // pop the final result + pop_token_rval(result); + + // error if our stack isn't empty + if (peek_token(0) != NULL) + throw expression_error(expression_error::SYNTAX, 0); + + return result.value(); } -/*************************************************************************** - EXPRESSION EVALUATION -***************************************************************************/ +//************************************************************************** +// PARSE TOKEN +//************************************************************************** -/*------------------------------------------------- - execute_function - handle an execute function - operator --------------------------------------------------*/ +//------------------------------------------------- +// parse_token - constructor +//------------------------------------------------- -static EXPRERR execute_function(parsed_expression *expr, parse_token *token) +parsed_expression::parse_token::parse_token(int offset) + : m_next(NULL), + m_type(INVALID), + m_offset(offset), + m_value(0), + m_string(NULL), + m_symbol(NULL) { +} + + +//------------------------------------------------- +// get_lval_value - call the getter function +// for a SYMBOL token +//------------------------------------------------- + +UINT64 parsed_expression::parse_token::get_lval_value(symbol_table *table) +{ + // get the value of a symbol + if (is_symbol()) + return m_symbol->value(); + + // or get the value from the memory callbacks + else if (is_memory() && table != NULL) + return table->memory_value(m_string, memory_space(), address(), 1 << memory_size()); + + return 0; +} + + +//------------------------------------------------- +// set_lval_value - call the setter function +// for a SYMBOL token +//------------------------------------------------- + +inline void parsed_expression::parse_token::set_lval_value(symbol_table *table, UINT64 value) +{ + // set the value of a symbol + if (is_symbol()) + m_symbol->set_value(value); + + // or set the value via the memory callbacks + else if (is_memory() && table != NULL) + table->set_memory_value(m_string, memory_space(), address(), 1 << memory_size(), value); +} + + +//------------------------------------------------- +// execute_function - handle an execute function +// operator +//------------------------------------------------- + +void parsed_expression::execute_function(parse_token &token) +{ + // pop off all pushed parameters UINT64 funcparams[MAX_FUNCTION_PARAMS]; symbol_entry *symbol = NULL; int paramcount = 0; - parse_token t1; - EXPRERR exprerr; - - memset(&t1, 0, sizeof(t1)); - - /* pop off all pushed parameters */ while (paramcount < MAX_FUNCTION_PARAMS) { - /* peek at the next token on the stack */ - parse_token *peek = peek_token(expr, 0); - if (!peek) - return MAKE_EXPRERR_INVALID_PARAM_COUNT(token->offset); + // peek at the next token on the stack + parse_token *peek = peek_token(0); + if (peek == NULL) + throw expression_error(expression_error::INVALID_PARAM_COUNT, token.offset()); - /* if it is a function symbol, break out of the loop */ - if (peek->type == TOK_SYMBOL) + // if it is a function symbol, break out of the loop + if (peek->is_symbol()) { - symbol = (symbol_entry *)peek->value.p; - if (symbol != NULL && symbol->type == SMT_FUNCTION) + symbol = peek->symbol(); + if (symbol->is_function()) { - pop_token(expr, &t1); + parse_token t1; + pop_token(t1); break; } } - /* otherwise, pop as a standard rval */ - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - funcparams[MAX_FUNCTION_PARAMS - (++paramcount)] = t1.value.i; + // otherwise, pop as a standard rval + parse_token t1; + pop_token_rval(t1); + funcparams[MAX_FUNCTION_PARAMS - (++paramcount)] = t1.value(); } - /* if we didn't find the symbol, fail */ + // if we didn't find the symbol, fail if (paramcount == MAX_FUNCTION_PARAMS) - return MAKE_EXPRERR_INVALID_PARAM_COUNT(token->offset); + throw expression_error(expression_error::INVALID_PARAM_COUNT, token.offset()); - /* validate the number of parameters */ - if (paramcount < symbol->info.func.minparams || paramcount > symbol->info.func.maxparams) - return MAKE_EXPRERR_INVALID_PARAM_COUNT(token->offset); - - /* execute the function and push the result */ - t1.type = TOK_NUMBER; - t1.offset = token->offset; - t1.value.i = (*symbol->info.func.execute)(symbol->table->globalref, symbol->ref, paramcount, &funcparams[MAX_FUNCTION_PARAMS - paramcount]); - push_token(expr, &t1); - - return EXPRERR_NONE; -} - - -/*------------------------------------------------- - execute_tokens - execute a postfix sequence - of tokens --------------------------------------------------*/ - -static EXPRERR execute_tokens(parsed_expression *expr, UINT64 *result) -{ - parse_token t1, t2, tempnum, tempmem; - EXPRERR exprerr; - int tokindex; - - /* reset the token stack */ - init_token_stack(expr); - - /* Initialize t1, t2 to keep gcc's warnings-as-errors happy */ - t1.type = TOK_INVALID; - t1.offset = 0; - t2.type = TOK_INVALID; - t2.offset = 0; - - /* create a temporary token for holding intermediate number and memory values */ - tempnum.type = TOK_NUMBER; - tempnum.offset = 0; - tempnum.info = 0; - tempmem.type = TOK_MEMORY; - tempmem.offset = 0; - tempmem.info = 0; - - /* loop over the entire sequence */ - for (tokindex = 0; expr->token[tokindex].type != TOK_END; tokindex++) - { - parse_token *token = &expr->token[tokindex]; - - switch (token->type) - { - default: - case TOK_INVALID: - return MAKE_EXPRERR_INVALID_TOKEN(token->offset); - - case TOK_SYMBOL: - case TOK_NUMBER: - case TOK_STRING: - exprerr = push_token(expr, token); - if (exprerr != 0) - return exprerr; - break; - - case TOK_OPERATOR: - switch (token->value.i) - { - case TVL_PREINCREMENT: - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table) + 1; - tempnum.offset = t1.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i); - break; - - case TVL_PREDECREMENT: - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table) - 1; - tempnum.offset = t1.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i); - break; - - case TVL_POSTINCREMENT: - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table); - tempnum.offset = t1.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i + 1); - break; - - case TVL_POSTDECREMENT: - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table); - tempnum.offset = t1.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i - 1); - break; - - case TVL_COMPLEMENT: - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = !t1.value.i; - tempnum.offset = t1.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_NOT: - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = ~t1.value.i; - tempnum.offset = t1.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_UPLUS: - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i; - tempnum.offset = t1.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_UMINUS: - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = -t1.value.i; - tempnum.offset = t1.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_MULTIPLY: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i * t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_DIVIDE: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - if (t2.value.i == 0) return MAKE_EXPRERR_DIVIDE_BY_ZERO(t2.offset); - tempnum.value.i = t1.value.i / t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_MODULO: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - if (t2.value.i == 0) return MAKE_EXPRERR_DIVIDE_BY_ZERO(t2.offset); - tempnum.value.i = t1.value.i % t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_ADD: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i + t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_SUBTRACT: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i - t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_LSHIFT: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i << t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_RSHIFT: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i >> t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_LESS: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i < t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_LESSOREQUAL: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i <= t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_GREATER: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i > t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_GREATEROREQUAL: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i >= t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_EQUAL: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i == t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_NOTEQUAL: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i != t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_BAND: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i & t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_BXOR: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i ^ t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_BOR: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i | t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_LAND: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i && t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_LOR: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = t1.value.i || t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - break; - - case TVL_ASSIGN: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - push_token(expr, &t2); - set_lval_value(expr, &t1, expr->table, t2.value.i); - break; - - case TVL_ASSIGNMULTIPLY: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table); - tempnum.value.i *= t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i); - break; - - case TVL_ASSIGNDIVIDE: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table); - if (t2.value.i == 0) return MAKE_EXPRERR_DIVIDE_BY_ZERO(t2.offset); - tempnum.value.i /= t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i); - break; - - case TVL_ASSIGNMODULO: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table); - if (t2.value.i == 0) return MAKE_EXPRERR_DIVIDE_BY_ZERO(t2.offset); - tempnum.value.i %= t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i); - break; - - case TVL_ASSIGNADD: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table); - tempnum.value.i += t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i); - break; - - case TVL_ASSIGNSUBTRACT: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table); - tempnum.value.i -= t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i); - break; - - case TVL_ASSIGNLSHIFT: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table); - tempnum.value.i <<= t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i); - break; - - case TVL_ASSIGNRSHIFT: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table); - tempnum.value.i >>= t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i); - break; - - case TVL_ASSIGNBAND: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table); - tempnum.value.i &= t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i); - break; - - case TVL_ASSIGNBXOR: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table); - tempnum.value.i ^= t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i); - break; - - case TVL_ASSIGNBOR: - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_lval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempnum.value.i = get_lval_value(expr, &t1, expr->table); - tempnum.value.i |= t2.value.i; - tempnum.offset = (t1.offset < t2.offset) ? t1.offset : t2.offset; - exprerr = push_token(expr, &tempnum); if (exprerr != 0) return exprerr; - set_lval_value(expr, &t1, expr->table, tempnum.value.i); - break; - - case TVL_COMMA: - if (!(token->info & TIN_FUNCTION)) - { - exprerr = pop_token_rval(expr, &t2, expr->table); if (exprerr != 0) return exprerr; - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - exprerr = push_token(expr, &t2); if (exprerr != 0) return exprerr; - } - break; - - case TVL_MEMORYAT: - exprerr = pop_token_rval(expr, &t1, expr->table); if (exprerr != 0) return exprerr; - tempmem.value.i = t1.value.i; - tempmem.info = token->info; - exprerr = push_token(expr, &tempmem); if (exprerr != 0) return exprerr; - break; - - case TVL_EXECUTEFUNC: - exprerr = execute_function(expr, token); if (exprerr != 0) return exprerr; - break; - - default: - return MAKE_EXPRERR_SYNTAX(token->offset); - } - break; - } - } - - /* pop the final result */ - exprerr = pop_token_rval(expr, &tempnum, expr->table); - if (exprerr != 0) - return exprerr; - - /* error if our stack isn't empty */ - if (peek_token(expr, 0) != NULL) - return MAKE_EXPRERR_SYNTAX(0); - - *result = tempnum.value.i; - return EXPRERR_NONE; -} - - - -/*************************************************************************** - MISC HELPERS -***************************************************************************/ - -/*------------------------------------------------- - add_expression_string - add a string to the - list of expression strings --------------------------------------------------*/ - -static char *add_expression_string(parsed_expression *expr, const char *string, int length, UINT16 *index) -{ - expression_string *expstring; - - /* allocate memory */ - expstring = (expression_string *)osd_malloc(sizeof(expression_string) + length); - if (expstring == NULL) - return NULL; - - /* make the new string and link it in; we guarantee tha the index is never 0 */ - expstring->next = expr->stringlist; - expstring->index = ++expr->stringcount; - memcpy(expstring->string, string, length); - expstring->string[length] = 0; - expr->stringlist = expstring; - - /* return a pointer to the copied string */ - if (index != NULL) - *index = expstring->index; - return expstring->string; -} - - -/*------------------------------------------------- - get_expression_string - return an indexed - expression string --------------------------------------------------*/ - -static const char *get_expression_string(parsed_expression *expr, UINT16 index) -{ - expression_string *expstring; - - /* a 0 index is always invalid */ - if (index == 0) - return NULL; - - /* scan for the string with the matching index */ - for (expstring = expr->stringlist; expstring != NULL; expstring = expstring->next) - if (expstring->index == index) - return expstring->string; - return NULL; -} - - -/*------------------------------------------------- - free_expression_strings - free all strings - allocated to an expression --------------------------------------------------*/ - -static void free_expression_strings(parsed_expression *expr) -{ - /* free the original expression */ - if (expr->original_string != NULL) - osd_free(expr->original_string); - expr->original_string = NULL; - - /* osd_free all strings */ - while (expr->stringlist != NULL) - { - expression_string *string = expr->stringlist; - expr->stringlist = string->next; - osd_free(string); - } -} - - - -/*************************************************************************** - CORE WRAPPER FUNCTIONS -***************************************************************************/ - -/*------------------------------------------------- - expression_evaluate - evaluate a string - expression using the passed symbol table --------------------------------------------------*/ - -EXPRERR expression_evaluate(const char *expression, const symbol_table *table, const express_callbacks *callbacks, void *cbparam, UINT64 *result) -{ - parsed_expression temp_expression; - EXPRERR exprerr; - - /* zap expression object and copy the callbacks */ - memset(&temp_expression, 0, sizeof(temp_expression)); - if (callbacks != NULL) - temp_expression.callbacks = *callbacks; - temp_expression.cbparam = cbparam; - - /* first parse the tokens into the token array in order */ - exprerr = parse_string_into_tokens(expression, &temp_expression, table); - if (exprerr != EXPRERR_NONE) - goto cleanup; - - /* debugging */ - print_tokens(stdout, &temp_expression); - - /* convert the infix order to postfix order */ - exprerr = infix_to_postfix(&temp_expression); - if (exprerr != EXPRERR_NONE) - goto cleanup; - - /* debugging */ - print_tokens(stdout, &temp_expression); - - /* execute the expression to get the result */ - exprerr = execute_tokens(&temp_expression, result); - -cleanup: - free_expression_strings(&temp_expression); - return exprerr; -} - - -/*------------------------------------------------- - expression_parse - parse an expression and - return an allocated token array --------------------------------------------------*/ - -EXPRERR expression_parse(const char *expression, const symbol_table *table, const express_callbacks *callbacks, void *cbparam, parsed_expression **result) -{ - parsed_expression temp_expression; - EXPRERR exprerr; - - /* zap expression object and copy the callbacks */ - memset(&temp_expression, 0, sizeof(temp_expression)); - if (callbacks != NULL) - temp_expression.callbacks = *callbacks; - temp_expression.cbparam = cbparam; - - /* first parse the tokens into the token array in order */ - exprerr = parse_string_into_tokens(expression, &temp_expression, table); - if (exprerr != EXPRERR_NONE) - goto cleanup; - - /* convert the infix order to postfix order */ - exprerr = infix_to_postfix(&temp_expression); - if (exprerr != EXPRERR_NONE) - goto cleanup; - - /* allocate memory for the result */ - *result = (parsed_expression *)osd_malloc(sizeof(temp_expression)); - if (!*result) - { - exprerr = MAKE_EXPRERR_OUT_OF_MEMORY(0); - goto cleanup; - } - - /* copy the final expression and return */ - **result = temp_expression; - return EXPRERR_NONE; - -cleanup: - free_expression_strings(&temp_expression); - return exprerr; -} - - -/*------------------------------------------------- - expression_execute - execute a - previously-parsed expression --------------------------------------------------*/ - -EXPRERR expression_execute(parsed_expression *expr, UINT64 *result) -{ - /* execute the expression to get the result */ - return execute_tokens(expr, result); -} - - -/*------------------------------------------------- - expression_free - free a previously - allocated parsed expression --------------------------------------------------*/ - -void expression_free(parsed_expression *expr) -{ - if (expr != NULL) - { - free_expression_strings(expr); - osd_free(expr); - } -} - - -/*------------------------------------------------- - expression_original_string - return a - pointer to the original expression string --------------------------------------------------*/ - -const char *expression_original_string(parsed_expression *expr) -{ - return expr->original_string; -} - - - -/*************************************************************************** - ERROR HANDLING -***************************************************************************/ - -/*------------------------------------------------- - exprerr_to_string - return a friendly - string for a given expression error --------------------------------------------------*/ - -const char *exprerr_to_string(EXPRERR error) -{ - switch (EXPRERR_ERROR_CLASS(error)) - { - case EXPRERR_NOT_LVAL: return "not an lvalue"; - case EXPRERR_NOT_RVAL: return "not an rvalue"; - case EXPRERR_SYNTAX: return "syntax error"; - case EXPRERR_UNKNOWN_SYMBOL: return "unknown symbol"; - case EXPRERR_INVALID_NUMBER: return "invalid number"; - case EXPRERR_INVALID_TOKEN: return "invalid token"; - case EXPRERR_STACK_OVERFLOW: return "stack overflow"; - case EXPRERR_STACK_UNDERFLOW: return "stack underflow"; - case EXPRERR_UNBALANCED_PARENS: return "unbalanced parentheses"; - case EXPRERR_DIVIDE_BY_ZERO: return "divide by zero"; - case EXPRERR_OUT_OF_MEMORY: return "out of memory"; - case EXPRERR_INVALID_PARAM_COUNT: return "invalid number of parameters"; - case EXPRERR_UNBALANCED_QUOTES: return "unbalanced quotes"; - case EXPRERR_TOO_MANY_STRINGS: return "too many strings"; - case EXPRERR_INVALID_MEMORY_SIZE: return "invalid memory size (b/w/d/q expected)"; - case EXPRERR_NO_SUCH_MEMORY_SPACE: return "non-existent memory space"; - case EXPRERR_INVALID_MEMORY_SPACE: return "invalid memory space (p/d/i/o/r/m expected)"; - case EXPRERR_INVALID_MEMORY_NAME: return "invalid memory name"; - case EXPRERR_MISSING_MEMORY_NAME: return "missing memory name"; - default: return "unknown error"; - } -} - - - -/*************************************************************************** - SYMBOL TABLES -***************************************************************************/ - -/*------------------------------------------------- - hash_string - simple string hash --------------------------------------------------*/ - -INLINE UINT32 hash_string(const char *string) -{ - UINT32 hash = 0; - while (*string) - hash = (hash * 31) + *string++; - return hash; -} - - -/*------------------------------------------------- - symtable_alloc - allocate a symbol table --------------------------------------------------*/ - -symbol_table *symtable_alloc(symbol_table *parent, void *globalref) -{ - symbol_table *table; - - /* allocate memory for the table */ - table = (symbol_table *)osd_malloc(sizeof(*table)); - if (!table) - return NULL; - - /* initialize the data */ - memset(table, 0, sizeof(*table)); - table->parent = parent; - table->globalref = globalref; - return table; -} - - -/*------------------------------------------------- - symtable_get_globalref - return the globalref - value for a given symtable --------------------------------------------------*/ - -void *symtable_get_globalref(symbol_table *table) -{ - return table->globalref; -} - - -/*------------------------------------------------- - symtable_add - add a new symbol to a - symbol table --------------------------------------------------*/ - -int symtable_add(symbol_table *table, const char *name, const symbol_entry *entry) -{ - internal_symbol_entry *symbol; - symbol_entry *oldentry; - char *newstring; - UINT32 hash_index; - int strindex; - //int all_digits, i; - -// assert_always(entry->table == table, "Mismatched symbol tables"); - - /* we cannot add numeric symbols */ - /* - all_digits = TRUE; - for (i = 0; name[i]; i++) - { - if (!isdigit((UINT8)name[i])) - { - all_digits = FALSE; - break; - } - } - assert_always(!all_digits, "All-digit symbols are not allowed"); - */ - - /* see if we already have an entry and just overwrite it if we do */ - oldentry = (symbol_entry *)symtable_find(table, name); - if (oldentry) - { - *oldentry = *entry; - return 1; - } - - /* otherwise, allocate a new entry */ - symbol = (internal_symbol_entry *)osd_malloc(sizeof(*symbol)); - if (!symbol) - return 0; - memset(symbol, 0, sizeof(*symbol)); - - /* allocate space for a copy of the string */ - newstring = (char *)osd_malloc(strlen(name) + 1); - if (!newstring) - { - osd_free(symbol); - return 0; - } - - /* copy the string, converting to lowercase */ - for (strindex = 0; name[strindex] != 0; strindex++) - newstring[strindex] = tolower((UINT8)name[strindex]); - newstring[strindex] = 0; - - /* fill in the details */ - symbol->name = newstring; - symbol->entry = *entry; - symbol->entry.table = table; - - /* add the entry to the hash table */ - hash_index = hash_string(newstring) % SYM_TABLE_HASH_SIZE; - symbol->next = table->hash[hash_index]; - table->hash[hash_index] = symbol; - return 1; -} - - -/*------------------------------------------------- - symtable_add_register - add a new - register symbol to a symbol table --------------------------------------------------*/ - -int symtable_add_register(symbol_table *table, const char *name, void *symref, symbol_getter_func getter, symbol_setter_func setter) -{ - symbol_entry symbol; - - symbol.ref = symref; - symbol.type = SMT_REGISTER; - symbol.info.reg.getter = getter; - symbol.info.reg.setter = setter; - symbol.table = table; - return symtable_add(table, name, &symbol); -} - - -/*------------------------------------------------- - symtable_add_function - add a new - function symbol to a symbol table --------------------------------------------------*/ - -int symtable_add_function(symbol_table *table, const char *name, void *symref, UINT16 minparams, UINT16 maxparams, function_execute_func execute) -{ - symbol_entry symbol; - - symbol.ref = symref; - symbol.type = SMT_FUNCTION; - symbol.info.func.minparams = minparams; - symbol.info.func.maxparams = maxparams; - symbol.info.func.execute = execute; - symbol.table = table; - return symtable_add(table, name, &symbol); -} - - -/*------------------------------------------------- - symtable_add_value - add a new - value symbol to a symbol table --------------------------------------------------*/ - -int symtable_add_value(symbol_table *table, const char *name, UINT64 value) -{ - symbol_entry symbol; - - symbol.ref = NULL; - symbol.type = SMT_VALUE; - symbol.info.gen.value = value; - symbol.table = table; - return symtable_add(table, name, &symbol); -} - - -/*------------------------------------------------- - symtable_find - find a symbol in a symbol - table --------------------------------------------------*/ - -const symbol_entry *symtable_find(const symbol_table *table, const char *name) -{ - UINT32 hash_index = hash_string(name) % SYM_TABLE_HASH_SIZE; - const internal_symbol_entry *symbol; - - /* loop until we run out of tables */ - while (table) - { - /* search linearly within this hash entry */ - for (symbol = table->hash[hash_index]; symbol; symbol = symbol->next) - if (!strcmp(symbol->name, name)) - return &symbol->entry; - - /* look in the parent */ - table = table->parent; - } - - return NULL; -} - - -/*------------------------------------------------- - symtable_find_indexed - find an indexed symbol - in a symbol table --------------------------------------------------*/ - -const char *symtable_find_indexed(const symbol_table *table, int index, const symbol_entry **entry) -{ - const internal_symbol_entry *symbol; - int hash_index; - - /* loop over hash entries, then over entries within each bucket */ - for (hash_index = 0; hash_index < SYM_TABLE_HASH_SIZE; hash_index++) - for (symbol = table->hash[hash_index]; symbol; symbol = symbol->next) - if (index-- == 0) - { - if (entry) - *entry = &symbol->entry; - return symbol->name; - } - - return NULL; -} - - -/*------------------------------------------------- - symtable_free - free a symbol table --------------------------------------------------*/ - -void symtable_free(symbol_table *table) -{ - internal_symbol_entry *entry, *next; - int hash_index; - - /* free all the entries in the hash table */ - for (hash_index = 0; hash_index < SYM_TABLE_HASH_SIZE; hash_index++) - for (entry = table->hash[hash_index]; entry; entry = next) - { - /* free the allocated name */ - if (entry->name) - osd_free((void *)entry->name); - - /* remove from this list and put on the free list */ - next = entry->next; - osd_free(entry); - } - - /* free the structure */ - osd_free(table); + // execute the function and push the result + function_symbol_entry *function = downcast(symbol); + parse_token result(token.offset()); + result.configure_number(function->execute(paramcount, &funcparams[MAX_FUNCTION_PARAMS - paramcount])); + push_token(result); } diff --git a/src/emu/debug/express.h b/src/emu/debug/express.h index ba758b97181..5d0af33b3ca 100644 --- a/src/emu/debug/express.h +++ b/src/emu/debug/express.h @@ -1,193 +1,412 @@ /*************************************************************************** express.h + Generic expressions engine. - Written by Aaron Giles + +**************************************************************************** + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ +#pragma once + #ifndef __EXPRESS_H__ #define __EXPRESS_H__ #include "osdcore.h" -/*************************************************************************** - CONSTANTS -***************************************************************************/ +//************************************************************************** +// CONSTANTS +//************************************************************************** -/* maximum number of parameters in a function call */ -#define MAX_FUNCTION_PARAMS (16) - -/* values for symbol_entry.type */ -#define SMT_REGISTER (0) -#define SMT_FUNCTION (1) -#define SMT_VALUE (2) - -/* values for the error code in an expression error */ -#define EXPRERR_NONE (0) -#define EXPRERR_NOT_LVAL (1) -#define EXPRERR_NOT_RVAL (2) -#define EXPRERR_SYNTAX (3) -#define EXPRERR_UNKNOWN_SYMBOL (4) -#define EXPRERR_INVALID_NUMBER (5) -#define EXPRERR_INVALID_TOKEN (6) -#define EXPRERR_STACK_OVERFLOW (7) -#define EXPRERR_STACK_UNDERFLOW (8) -#define EXPRERR_UNBALANCED_PARENS (9) -#define EXPRERR_DIVIDE_BY_ZERO (10) -#define EXPRERR_OUT_OF_MEMORY (11) -#define EXPRERR_INVALID_PARAM_COUNT (12) -#define EXPRERR_UNBALANCED_QUOTES (13) -#define EXPRERR_TOO_MANY_STRINGS (14) -#define EXPRERR_INVALID_MEMORY_SIZE (15) -#define EXPRERR_INVALID_MEMORY_SPACE (16) -#define EXPRERR_NO_SUCH_MEMORY_SPACE (17) -#define EXPRERR_INVALID_MEMORY_NAME (18) -#define EXPRERR_MISSING_MEMORY_NAME (19) - -/* values for the address space passed to external_read/write_memory */ -#define EXPSPACE_PROGRAM_LOGICAL (0) -#define EXPSPACE_DATA_LOGICAL (1) -#define EXPSPACE_IO_LOGICAL (2) -#define EXPSPACE_SPACE3_LOGICAL (3) -#define EXPSPACE_PROGRAM_PHYSICAL (4) -#define EXPSPACE_DATA_PHYSICAL (5) -#define EXPSPACE_IO_PHYSICAL (6) -#define EXPSPACE_SPACE3_PHYSICAL (7) -#define EXPSPACE_OPCODE (8) -#define EXPSPACE_RAMWRITE (9) -#define EXPSPACE_REGION (10) - - - -/*************************************************************************** - MACROS -***************************************************************************/ - -/* expression error assembly/disassembly macros */ -#define EXPRERR_ERROR_CLASS(x) ((x) >> 16) -#define EXPRERR_ERROR_OFFSET(x) ((x) & 0xffff) -#define MAKE_EXPRERR(a,b) (((a) << 16) | ((b) & 0xffff)) - -/* macros to assemble specific error conditions */ -#define MAKE_EXPRERR_NOT_LVAL(x) MAKE_EXPRERR(EXPRERR_NOT_LVAL, (x)) -#define MAKE_EXPRERR_NOT_RVAL(x) MAKE_EXPRERR(EXPRERR_NOT_RVAL, (x)) -#define MAKE_EXPRERR_SYNTAX(x) MAKE_EXPRERR(EXPRERR_SYNTAX, (x)) -#define MAKE_EXPRERR_UNKNOWN_SYMBOL(x) MAKE_EXPRERR(EXPRERR_UNKNOWN_SYMBOL, (x)) -#define MAKE_EXPRERR_INVALID_NUMBER(x) MAKE_EXPRERR(EXPRERR_INVALID_NUMBER, (x)) -#define MAKE_EXPRERR_INVALID_TOKEN(x) MAKE_EXPRERR(EXPRERR_INVALID_TOKEN, (x)) -#define MAKE_EXPRERR_STACK_OVERFLOW(x) MAKE_EXPRERR(EXPRERR_STACK_OVERFLOW, (x)) -#define MAKE_EXPRERR_STACK_UNDERFLOW(x) MAKE_EXPRERR(EXPRERR_STACK_UNDERFLOW, (x)) -#define MAKE_EXPRERR_UNBALANCED_PARENS(x) MAKE_EXPRERR(EXPRERR_UNBALANCED_PARENS, (x)) -#define MAKE_EXPRERR_DIVIDE_BY_ZERO(x) MAKE_EXPRERR(EXPRERR_DIVIDE_BY_ZERO, (x)) -#define MAKE_EXPRERR_OUT_OF_MEMORY(x) MAKE_EXPRERR(EXPRERR_OUT_OF_MEMORY, (x)) -#define MAKE_EXPRERR_INVALID_PARAM_COUNT(x) MAKE_EXPRERR(EXPRERR_INVALID_PARAM_COUNT, (x)) -#define MAKE_EXPRERR_UNBALANCED_QUOTES(x) MAKE_EXPRERR(EXPRERR_UNBALANCED_QUOTES, (x)) -#define MAKE_EXPRERR_TOO_MANY_STRINGS(x) MAKE_EXPRERR(EXPRERR_TOO_MANY_STRINGS, (x)) -#define MAKE_EXPRERR_INVALID_MEMORY_SIZE(x) MAKE_EXPRERR(EXPRERR_INVALID_MEMORY_SIZE, (x)) -#define MAKE_EXPRERR_NO_SUCH_MEMORY_SPACE(x) MAKE_EXPRERR(EXPRERR_NO_SUCH_MEMORY_SPACE, (x)) -#define MAKE_EXPRERR_INVALID_MEMORY_SPACE(x) MAKE_EXPRERR(EXPRERR_INVALID_MEMORY_SPACE, (x)) -#define MAKE_EXPRERR_INVALID_MEMORY_NAME(x) MAKE_EXPRERR(EXPRERR_INVALID_MEMORY_NAME, (x)) - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -/* EXPRERR is an error code for expression evaluation */ -typedef UINT32 EXPRERR; - - -/* callback functions for getting/setting a symbol value */ -typedef UINT64 (*symbol_getter_func)(void *globalref, void *symref); -typedef void (*symbol_setter_func)(void *globalref, void *symref, UINT64 value); - -/* callback function for execution a function */ -typedef UINT64 (*function_execute_func)(void *globalref, void *symref, UINT32 numparams, const UINT64 *paramlist); - -/* callback function for memory reads/writes */ -typedef UINT64 (*express_read_func)(void *cbparam, const char *name, int space, UINT32 offset, int size); -typedef void (*express_write_func)(void *cbparam, const char *name, int space, UINT32 offset, int size, UINT64 value); -typedef EXPRERR (*express_valid_func)(void *cbparam, const char *name, int space); - - -/* callback parameter for executing expressions */ -typedef struct _express_callbacks express_callbacks; -struct _express_callbacks +// values for the address space passed to external_read/write_memory +enum expression_space { - express_read_func read; /* read callback */ - express_write_func write; /* write callback */ - express_valid_func valid; /* validation callback */ + EXPSPACE_INVALID, + EXPSPACE_PROGRAM_LOGICAL, + EXPSPACE_DATA_LOGICAL, + EXPSPACE_IO_LOGICAL, + EXPSPACE_SPACE3_LOGICAL, + EXPSPACE_PROGRAM_PHYSICAL, + EXPSPACE_DATA_PHYSICAL, + EXPSPACE_IO_PHYSICAL, + EXPSPACE_SPACE3_PHYSICAL, + EXPSPACE_OPCODE, + EXPSPACE_RAMWRITE, + EXPSPACE_REGION }; -/* symbol_table is an opaque structure for holding a collection of symbols */ -typedef struct _symbol_table symbol_table; + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// forward references +class symbol_table; -/* symbol_entry describes a symbol in a symbol table */ -typedef struct _symbol_entry symbol_entry; -struct _symbol_entry +// ======================> expression_error + +// an expression_error holds an error code and a string offset +class expression_error { - void * ref; /* internal reference */ - symbol_table * table; /* pointer back to the owning table */ - UINT32 type; /* type of symbol */ - union +public: + // codes + enum error_code { - /* register info */ - struct - { - symbol_getter_func getter; /* value getter */ - symbol_setter_func setter; /* value setter */ - } reg; + NONE, + NOT_LVAL, + NOT_RVAL, + SYNTAX, + UNKNOWN_SYMBOL, + INVALID_NUMBER, + INVALID_TOKEN, + STACK_OVERFLOW, + STACK_UNDERFLOW, + UNBALANCED_PARENS, + DIVIDE_BY_ZERO, + OUT_OF_MEMORY, + INVALID_PARAM_COUNT, + UNBALANCED_QUOTES, + TOO_MANY_STRINGS, + INVALID_MEMORY_SIZE, + INVALID_MEMORY_SPACE, + NO_SUCH_MEMORY_SPACE, + INVALID_MEMORY_NAME, + MISSING_MEMORY_NAME + }; - /* function info */ - struct - { - UINT16 minparams; /* minimum expected parameters */ - UINT16 maxparams; /* maximum expected parameters */ - function_execute_func execute; /* execute callback */ - } func; + // construction/destruction + expression_error(error_code code, int offset = 0) + : m_code(code), + m_offset(offset) { } - /* generic info */ - struct generic_info - { - void * ptr; /* generic pointer */ - UINT64 value; /* generic value */ - } gen; - } info; + // operators + operator error_code() const { return m_code; } + + // getters + error_code code() const { return m_code; } + int offset() const { return m_offset; } + const char *code_string() const; + +private: + // internal state + error_code m_code; + int m_offset; }; -/* parsed_expression is an opaque structure for holding a pre-parsed expression */ -typedef struct _parsed_expression parsed_expression; +// ======================> symbol_entry + +// symbol_entry describes a symbol in a symbol table +class symbol_entry +{ + friend class tagged_list; + +protected: + // symbol types + enum symbol_type + { + SMT_INTEGER, + SMT_FUNCTION + }; + + // construction/destruction + symbol_entry(symbol_table &table, symbol_type type, const char *name, void *ref); + virtual ~symbol_entry(); + +public: + // getters + symbol_entry *next() const { return m_next; } + const char *name() const { return m_name; } + + // type checking + bool is_function() const { return (m_type == SMT_FUNCTION); } + + // symbol access + virtual bool is_lval() const = 0; + virtual UINT64 value() const = 0; + virtual void set_value(UINT64 newvalue) = 0; + +protected: + // internal state + symbol_entry * m_next; // link to next entry + symbol_table & m_table; // pointer back to the owning table + symbol_type m_type; // type of symbol + astring m_name; // name of the symbol + void * m_ref; // internal reference +}; +// ======================> symbol_table -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ +// a symbol_table holds symbols of various types which the expression engine +// queries to look up symbols +class symbol_table +{ +public: + // callback functions for getting/setting a symbol value + typedef UINT64 (*getter_func)(symbol_table &table, void *symref); + typedef void (*setter_func)(symbol_table &table, void *symref, UINT64 value); + + // callback functions for function execution + typedef UINT64 (*execute_func)(symbol_table &table, void *symref, int numparams, const UINT64 *paramlist); -/* expression evaluation */ -EXPRERR expression_evaluate(const char *expression, const symbol_table *table, const express_callbacks *callbacks, void *cbparam, UINT64 *result); -EXPRERR expression_parse(const char *expression, const symbol_table *table, const express_callbacks *callbacks, void *cbparam, parsed_expression **result); -EXPRERR expression_execute(parsed_expression *expr, UINT64 *result); -void expression_free(parsed_expression *expr); -const char * expression_original_string(parsed_expression *expr); -const char * exprerr_to_string(EXPRERR error); + // callback functions for memory reads/writes + typedef expression_error::error_code (*valid_func)(void *cbparam, const char *name, int space); + typedef UINT64 (*read_func)(void *cbparam, const char *name, int space, UINT32 offset, int size); + typedef void (*write_func)(void *cbparam, const char *name, int space, UINT32 offset, int size, UINT64 value); + + enum read_write + { + READ_ONLY = 0, + READ_WRITE + }; + + // construction/destruction + symbol_table(void *globalref, symbol_table *parent = NULL); + + // getters + symbol_entry *first() const { return m_symlist.first(); } + symbol_table *parent() const { return m_parent; } + void *globalref() const { return m_globalref; } + + // setters + void configure_memory(void *param, valid_func valid, read_func read, write_func write); + + // symbol access + void add(const char *name, read_write rw, UINT64 *ptr = NULL); + void add(const char *name, UINT64 constvalue); + void add(const char *name, void *ref, getter_func getter, setter_func setter = NULL); + void add(const char *name, void *ref, int minparams, int maxparams, execute_func execute); + symbol_entry *find(const char *name) { return m_symlist.find(name); } + + // value getter/setter + UINT64 value(const char *symbol); + void set_value(const char *symbol, UINT64 value); + + // memory accessors + expression_error::error_code memory_valid(const char *name, int space); + UINT64 memory_value(const char *name, int space, UINT32 offset, int size); + void set_memory_value(const char *name, int space, UINT32 offset, int size, UINT64 value); + +private: + // internal state + symbol_table * m_parent; // pointer to the parent symbol table + void * m_globalref; // global reference parameter + tagged_list m_symlist; // list of symbols + void * m_memory_param; // callback parameter for memory + valid_func m_memory_valid; // validation callback + read_func m_memory_read; // read callback + write_func m_memory_write; // write callback +}; + + +// ======================> parsed_expression + +// a parsed_expression holds a pre-parsed expression that can be +// efficiently executed at a later time +class parsed_expression +{ +public: + // construction/destruction + parsed_expression(const parsed_expression &src) { copy(src); } + parsed_expression(symbol_table *symtable = NULL, const char *expression = NULL, UINT64 *result = NULL); + + // operators + parsed_expression &operator=(const parsed_expression &src) { copy(src); return *this; } + + // getters + bool is_empty() const { return (m_tokenlist.count() == 0); } + const char *original_string() const { return m_original_string; } + symbol_table *symbols() const { return m_symtable; } + + // setters + void set_symbols(symbol_table *symtable) { m_symtable = symtable; } + + // execution + void parse(const char *string); + UINT64 execute() { return execute_tokens(); } + +private: + // a single token + class parse_token + { + friend class simple_list; + + // operator flags + enum + { + TIN_OPTYPE_SHIFT = 0, // 8 bits (0-7) + TIN_OPTYPE_MASK = 0xff << TIN_OPTYPE_SHIFT, + TIN_RIGHT_TO_LEFT_SHIFT = 16, // 1 bit (16) + TIN_RIGHT_TO_LEFT_MASK = 1 << TIN_RIGHT_TO_LEFT_SHIFT, + TIN_FUNCTION_SHIFT = 17, // 1 bit (17) + TIN_FUNCTION_MASK = 1 << TIN_FUNCTION_SHIFT, + TIN_MEMORY_SIZE_SHIFT = 18, // 2 bits (18-19) + TIN_MEMORY_SIZE_MASK = 3 << TIN_MEMORY_SIZE_SHIFT, + TIN_MEMORY_SPACE_SHIFT = 20, // 4 bits (20-23) + TIN_MEMORY_SPACE_MASK = 0xf << TIN_MEMORY_SPACE_SHIFT, + TIN_PRECEDENCE_SHIFT = 24, // 8 bits (24-31) + TIN_PRECEDENCE_MASK = 0xff << TIN_PRECEDENCE_SHIFT + }; + + // types of tokens + enum token_type + { + INVALID = 0, + NUMBER, + STRING, + MEMORY, + SYMBOL, + OPERATOR + }; + + public: + // construction/destruction + parse_token(int offset = 0); + + // getters + parse_token *next() const { return m_next; } + int offset() const { return m_offset; } + bool is_number() const { return (m_type == NUMBER); } + bool is_string() const { return (m_type == STRING); } + bool is_memory() const { return (m_type == MEMORY); } + bool is_symbol() const { return (m_type == SYMBOL); } + bool is_operator() const { return (m_type == OPERATOR); } + bool is_operator(UINT8 type) const { return (m_type == OPERATOR && optype() == type); } + bool is_lval() const { return ((m_type == SYMBOL && m_symbol->is_lval()) || m_type == MEMORY); } + + UINT64 value() const { assert(m_type == NUMBER); return m_value; } + UINT32 address() const { assert(m_type == MEMORY); return m_value; } + symbol_entry *symbol() const { assert(m_type == SYMBOL); return m_symbol; } + + UINT8 optype() const { assert(m_type == OPERATOR); return (m_flags & TIN_OPTYPE_MASK) >> TIN_OPTYPE_SHIFT; } + UINT8 precedence() const { assert(m_type == OPERATOR); return (m_flags & TIN_PRECEDENCE_MASK) >> TIN_PRECEDENCE_SHIFT; } + bool is_function_separator() const { assert(m_type == OPERATOR); return ((m_flags & TIN_FUNCTION_MASK) != 0); } + bool right_to_left() const { assert(m_type == OPERATOR); return ((m_flags & TIN_RIGHT_TO_LEFT_MASK) != 0); } + expression_space memory_space() const { assert(m_type == OPERATOR || m_type == MEMORY); return expression_space((m_flags & TIN_MEMORY_SPACE_MASK) >> TIN_MEMORY_SPACE_SHIFT); } + int memory_size() const { assert(m_type == OPERATOR || m_type == MEMORY); return (m_flags & TIN_MEMORY_SIZE_MASK) >> TIN_MEMORY_SIZE_SHIFT; } + + // setters + parse_token &set_offset(int offset) { m_offset = offset; return *this; } + parse_token &set_offset(const parse_token &src) { m_offset = src.m_offset; return *this; } + parse_token &set_offset(const parse_token &src1, const parse_token &src2) { m_offset = MIN(src1.m_offset, src2.m_offset); return *this; } + parse_token &configure_number(UINT64 value) { m_type = NUMBER; m_value = value; return *this; } + parse_token &configure_string(const char *string) { m_type = STRING; m_string = string; return *this; } + parse_token &configure_memory(UINT32 address, parse_token &memoryat) { m_type = MEMORY; m_value = address; m_flags = memoryat.m_flags; m_string = memoryat.m_string; return *this; } + parse_token &configure_symbol(symbol_entry &symbol) { m_type = SYMBOL; m_symbol = &symbol; return *this; } + parse_token &configure_operator(UINT8 optype, UINT8 precedence) + { m_type = OPERATOR; m_flags = ((optype << TIN_OPTYPE_SHIFT) & TIN_OPTYPE_MASK) | ((precedence << TIN_PRECEDENCE_SHIFT) & TIN_PRECEDENCE_MASK); return *this; } + + parse_token &set_function_separator() { assert(m_type == OPERATOR); m_flags |= TIN_FUNCTION_MASK; return *this; } + parse_token &set_right_to_left() { assert(m_type == OPERATOR); m_flags |= TIN_RIGHT_TO_LEFT_MASK; return *this; } + parse_token &set_memory_space(expression_space space) { assert(m_type == OPERATOR || m_type == MEMORY); m_flags = (m_flags & ~TIN_MEMORY_SPACE_MASK) | ((space << TIN_MEMORY_SPACE_SHIFT) & TIN_MEMORY_SPACE_MASK); return *this; } + parse_token &set_memory_size(int log2ofbits) { assert(m_type == OPERATOR || m_type == MEMORY); m_flags = (m_flags & ~TIN_MEMORY_SIZE_MASK) | ((log2ofbits << TIN_MEMORY_SIZE_SHIFT) & TIN_MEMORY_SIZE_MASK); return *this; } + parse_token &set_memory_source(const char *string) { assert(m_type == OPERATOR || m_type == MEMORY); m_string = string; return *this; } + + // access + UINT64 get_lval_value(symbol_table *symtable); + void set_lval_value(symbol_table *symtable, UINT64 value); + + private: + // internal state + parse_token * m_next; // next token in list + token_type m_type; // type of token + int m_offset; // offset within the string + UINT64 m_value; // integral value + UINT32 m_flags; // additional flags/info + const char * m_string; // associated string + symbol_entry * m_symbol; // symbol pointer + }; + + // an expression_string holds an indexed string parsed from the expression + class expression_string + { + friend class simple_list; + + public: + // construction/destruction + expression_string(const char *string, int length = 0) + : m_next(NULL), + m_string(string, (length == 0) ? strlen(string) : length) { } + + // operators + operator const char *() { return m_string; } + operator const char *() const { return m_string; } + + private: + // internal state + expression_string * m_next; // next string in list + astring m_string; // copy of the string + }; + + // internal helpers + void copy(const parsed_expression &src); + void print_tokens(FILE *out); + + // parsing helpers + void parse_string_into_tokens(); + void parse_symbol_or_number(parse_token &token, const char *&string); + void parse_number(parse_token &token, const char *string, int base, expression_error::error_code errcode); + void parse_quoted_char(parse_token &token, const char *&string); + void parse_quoted_string(parse_token &token, const char *&string); + void parse_memory_operator(parse_token &token, const char *string); + void normalize_operator(parse_token *prevtoken, parse_token &thistoken); + void infix_to_postfix(); + + // execution helpers + void push_token(parse_token &token); + void pop_token(parse_token &token); + parse_token *peek_token(int count); + void pop_token_lval(parse_token &token); + void pop_token_rval(parse_token &token); + UINT64 execute_tokens(); + void execute_function(parse_token &token); + + // constants + static const int MAX_FUNCTION_PARAMS = 16; + static const int MAX_STACK_DEPTH = 16; + + // internal state + symbol_table * m_symtable; // symbol table + astring m_original_string; // original string (prior to parsing) + simple_list m_tokenlist; // token list + simple_list m_stringlist; // string list + int m_token_stack_ptr; // stack pointer (used during execution) + parse_token m_token_stack[MAX_STACK_DEPTH]; // token stack (used during execution) +}; -/* symbol table manipulation */ -symbol_table * symtable_alloc(symbol_table *parent, void *globalref); -void * symtable_get_globalref(symbol_table *table); -int symtable_add(symbol_table *table, const char *name, const symbol_entry *entry); -int symtable_add_register(symbol_table *table, const char *name, void *symref, symbol_getter_func getter, symbol_setter_func setter); -int symtable_add_function(symbol_table *table, const char *name, void *symref, UINT16 minparams, UINT16 maxparams, function_execute_func execute); -int symtable_add_value(symbol_table *table, const char *name, UINT64 value); -const symbol_entry * symtable_find(const symbol_table *table, const char *name); -const char * symtable_find_indexed(const symbol_table *table, int index, const symbol_entry **entry); -void symtable_free(symbol_table *table); #endif diff --git a/src/lib/util/astring.h b/src/lib/util/astring.h index 45fc43f54c0..c39c277401b 100644 --- a/src/lib/util/astring.h +++ b/src/lib/util/astring.h @@ -308,6 +308,7 @@ public: ~astring(); astring(const char *string) { init().cpy(string); } + astring(const char *string, int length) { init().cpy(string, length); } astring(const char *str1, const char *str2) { init().cpy(str1).cat(str2); } astring(const char *str1, const char *str2, const char *str3) { init().cpy(str1).cat(str2).cat(str3); } astring(const char *str1, const char *str2, const char *str3, const char *str4) { init().cpy(str1).cat(str2).cat(str3).cat(str4); } diff --git a/src/osd/sdl/debugwin.c b/src/osd/sdl/debugwin.c index f579bd99167..be42bdb2c9f 100644 --- a/src/osd/sdl/debugwin.c +++ b/src/osd/sdl/debugwin.c @@ -16,6 +16,7 @@ #include "dview.h" #include "osdsdl.h" +#include "debugger.h" #include "debug/dvdisasm.h" #include "debug/dvmemory.h" #include "debug/dvstate.h" diff --git a/src/osd/windows/debugwin.c b/src/osd/windows/debugwin.c index 746b9e52a21..f75d34daf12 100644 --- a/src/osd/windows/debugwin.c +++ b/src/osd/windows/debugwin.c @@ -51,6 +51,7 @@ // MAME headers #include "emu.h" #include "uiinput.h" +#include "debugger.h" #include "debug/debugvw.h" #include "debug/dvdisasm.h" #include "debug/dvmemory.h" @@ -58,7 +59,6 @@ #include "debug/debugvw.h" #include "debug/debugcon.h" #include "debug/debugcpu.h" -#include "debugger.h" // MAMEOS headers #include "debugwin.h"