summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug/express.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/debug/express.cpp')
-rw-r--r--src/emu/debug/express.cpp1165
1 files changed, 830 insertions, 335 deletions
diff --git a/src/emu/debug/express.cpp b/src/emu/debug/express.cpp
index bcd9269db30..9ab75b7b655 100644
--- a/src/emu/debug/express.cpp
+++ b/src/emu/debug/express.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles
/***************************************************************************
- express.c
+ express.cpp
Generic expressions engine.
@@ -31,7 +31,9 @@
#include "emu.h"
#include "express.h"
-#include <ctype.h>
+
+#include "corestr.h"
+#include <cctype>
@@ -39,19 +41,17 @@
DEBUGGING
***************************************************************************/
-#define DEBUG_TOKENS 0
+#define LOG_OUTPUT_FUNC osd_printf_info
+#define VERBOSE 0
+#include "logmacro.h"
+namespace {
/***************************************************************************
CONSTANTS
***************************************************************************/
-#ifndef DEFAULT_BASE
-#define DEFAULT_BASE 16 // hex unless otherwise specified
-#endif
-
-
// token.value values if token.is_operator()
enum
{
@@ -104,7 +104,7 @@ enum
//**************************************************************************
-// TYPE DEFINITIONS
+// REGISTER SYMBOL ENTRY
//**************************************************************************
// a symbol entry representing a register, with read/write callbacks
@@ -117,8 +117,8 @@ public:
integer_symbol_entry(symbol_table &table, const char *name, symbol_table::getter_func getter, symbol_table::setter_func setter, const std::string &format);
// symbol access
- virtual bool is_lval() const override;
- virtual u64 value() const override;
+ virtual bool is_lval() const override { return m_setter != nullptr; }
+ virtual u64 value() const override { return m_getter(); }
virtual void set_value(u64 newvalue) override;
private:
@@ -129,6 +129,61 @@ private:
};
+//-------------------------------------------------
+// integer_symbol_entry - constructor
+//-------------------------------------------------
+
+integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, symbol_table::read_write rw, u64 *ptr)
+ : symbol_entry(table, SMT_INTEGER, name, ""),
+ m_getter(ptr
+ ? symbol_table::getter_func([ptr] () { return *ptr; })
+ : symbol_table::getter_func([this] () { return m_value; })),
+ m_setter((rw == symbol_table::READ_ONLY)
+ ? symbol_table::setter_func(nullptr)
+ : ptr
+ ? symbol_table::setter_func([ptr] (u64 value) { *ptr = value; })
+ : symbol_table::setter_func([this] (u64 value) { m_value = value; })),
+ m_value(0)
+{
+}
+
+
+integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, u64 constval)
+ : symbol_entry(table, SMT_INTEGER, name, ""),
+ m_getter([this] () { return m_value; }),
+ m_setter(nullptr),
+ m_value(constval)
+{
+}
+
+
+integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, symbol_table::getter_func getter, symbol_table::setter_func setter, const std::string &format)
+ : symbol_entry(table, SMT_INTEGER, name, format),
+ m_getter(std::move(getter)),
+ m_setter(std::move(setter)),
+ m_value(0)
+{
+}
+
+
+//-------------------------------------------------
+// set_value - set the value of this symbol
+//-------------------------------------------------
+
+void integer_symbol_entry::set_value(u64 newvalue)
+{
+ if (m_setter != nullptr)
+ m_setter(newvalue);
+ else
+ throw emu_fatalerror("Symbol '%s' is read-only", m_name);
+}
+
+
+
+//**************************************************************************
+// FUNCTION SYMBOL ENTRY
+//**************************************************************************
+
// a symbol entry representing a function
class function_symbol_entry : public symbol_entry
{
@@ -136,8 +191,12 @@ public:
// construction/destruction
function_symbol_entry(symbol_table &table, const char *name, int minparams, int maxparams, symbol_table::execute_func execute);
+ // getters
+ u16 minparams() const { return m_minparams; }
+ u16 maxparams() const { return m_maxparams; }
+
// symbol access
- virtual bool is_lval() const override;
+ virtual bool is_lval() const override { return false; }
virtual u64 value() const override;
virtual void set_value(u64 newvalue) override;
@@ -152,6 +211,82 @@ private:
};
+//-------------------------------------------------
+// function_symbol_entry - constructor
+//-------------------------------------------------
+
+function_symbol_entry::function_symbol_entry(symbol_table &table, const char *name, int minparams, int maxparams, symbol_table::execute_func execute)
+ : symbol_entry(table, SMT_FUNCTION, name, ""),
+ m_minparams(minparams),
+ m_maxparams(maxparams),
+ m_execute(std::move(execute))
+{
+}
+
+
+//-------------------------------------------------
+// value - return the value of this symbol
+//-------------------------------------------------
+
+u64 function_symbol_entry::value() const
+{
+ throw emu_fatalerror("Symbol '%s' is a function and cannot be used in this context", m_name);
+}
+
+
+//-------------------------------------------------
+// set_value - set the value of this symbol
+//-------------------------------------------------
+
+void function_symbol_entry::set_value(u64 newvalue)
+{
+ throw emu_fatalerror("Symbol '%s' is a function and cannot be written", m_name);
+}
+
+
+//-------------------------------------------------
+// execute - execute the function
+//-------------------------------------------------
+
+u64 function_symbol_entry::execute(int numparams, const u64 *paramlist)
+{
+ if (numparams < m_minparams)
+ throw emu_fatalerror("Function '%s' requires at least %d parameters", m_name, m_minparams);
+ if (numparams > m_maxparams)
+ throw emu_fatalerror("Function '%s' accepts no more than %d parameters", m_name, m_maxparams);
+ return m_execute(numparams, paramlist);
+}
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+inline std::pair<device_t &, char const *> get_device_search(running_machine &machine, device_memory_interface *memintf, char const *tag)
+{
+ if (tag)
+ {
+ if (('.' == tag[0]) && (!tag[1] || (':' == tag[1]) || ('^' == tag[1])))
+ return std::pair<device_t &, char const *>(memintf ? memintf->device() : machine.root_device(), tag + ((':' == tag[1]) ? 2 : 1));
+ else if (('^' == tag[0]) && memintf)
+ return std::pair<device_t &, char const *>(memintf->device(), tag);
+ else
+ return std::pair<device_t &, char const *>(machine.root_device(), tag);
+ }
+ else if (memintf)
+ {
+ return std::pair<device_t &, char const *>(memintf->device(), "");
+ }
+ else
+ {
+ return std::pair<device_t &, char const *>(machine.root_device(), "");
+ }
+}
+
+} // anonymous namespace
+
+
//**************************************************************************
// EXPRESSION ERROR
@@ -162,7 +297,7 @@ private:
// given expression error
//-------------------------------------------------
-const char *expression_error::code_string() const
+std::string expression_error::code_string() const
{
switch (m_code)
{
@@ -178,6 +313,8 @@ const char *expression_error::code_string() const
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 TOO_FEW_PARAMS: return util::string_format("too few parameters (at least %d required)", m_num);
+ case TOO_MANY_PARAMS: return util::string_format("too many parameters (no more than %d accepted)", m_num);
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)";
@@ -200,8 +337,7 @@ const char *expression_error::code_string() const
//-------------------------------------------------
symbol_entry::symbol_entry(symbol_table &table, symbol_type type, const char *name, const std::string &format)
- : m_next(nullptr),
- m_table(table),
+ : m_table(table),
m_type(type),
m_name(name),
m_format(format)
@@ -220,312 +356,652 @@ symbol_entry::~symbol_entry()
//**************************************************************************
-// REGISTER SYMBOL ENTRY
+// SYMBOL TABLE
//**************************************************************************
//-------------------------------------------------
-// integer_symbol_entry - constructor
+// symbol_table - constructor
//-------------------------------------------------
-integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, symbol_table::read_write rw, u64 *ptr)
- : symbol_entry(table, SMT_INTEGER, name, ""),
- m_getter(ptr
- ? symbol_table::getter_func([ptr] (symbol_table &table) { return *ptr; })
- : symbol_table::getter_func([this] (symbol_table &table) { return m_value; })),
- m_setter((rw == symbol_table::READ_ONLY)
- ? symbol_table::setter_func(nullptr)
- : ptr
- ? symbol_table::setter_func([ptr] (symbol_table &table, u64 value) { *ptr = value; })
- : symbol_table::setter_func([this] (symbol_table &table, u64 value) { m_value = value; })),
- m_value(0)
-{
-}
-
-
-integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, u64 constval)
- : symbol_entry(table, SMT_INTEGER, name, ""),
- m_getter([this] (symbol_table &table) { return m_value; }),
- m_setter(nullptr),
- m_value(constval)
-{
-}
-
-
-integer_symbol_entry::integer_symbol_entry(symbol_table &table, const char *name, symbol_table::getter_func getter, symbol_table::setter_func setter, const std::string &format)
- : symbol_entry(table, SMT_INTEGER, name, format),
- m_getter(getter),
- m_setter(setter),
- m_value(0)
+symbol_table::symbol_table(running_machine &machine, symbol_table *parent, device_t *device)
+ : m_machine(machine)
+ , m_parent(parent)
+ , m_memintf(dynamic_cast<device_memory_interface *>(device))
+ , m_memory_modified(nullptr)
{
}
//-------------------------------------------------
-// is_lval - is this symbol allowable as an lval?
+// set_memory_modified_func - install notifier
+// for when memory is modified in debugger
//-------------------------------------------------
-bool integer_symbol_entry::is_lval() const
+void symbol_table::set_memory_modified_func(memory_modified_func modified)
{
- return (m_setter != nullptr);
+ m_memory_modified = std::move(modified);
}
//-------------------------------------------------
-// value - return the value of this symbol
+// add - add a new u64 pointer symbol
//-------------------------------------------------
-u64 integer_symbol_entry::value() const
+symbol_entry &symbol_table::add(const char *name, read_write rw, u64 *ptr)
{
- return m_getter(m_table);
+ m_symlist.erase(name);
+ return *m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, rw, ptr)).first->second;
}
//-------------------------------------------------
-// set_value - set the value of this symbol
+// add - add a new value symbol
//-------------------------------------------------
-void integer_symbol_entry::set_value(u64 newvalue)
+symbol_entry &symbol_table::add(const char *name, u64 value)
{
- if (m_setter != nullptr)
- m_setter(m_table, newvalue);
- else
- throw emu_fatalerror("Symbol '%s' is read-only", m_name.c_str());
+ m_symlist.erase(name);
+ return *m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, value)).first->second;
}
-
-//**************************************************************************
-// FUNCTION SYMBOL ENTRY
-//**************************************************************************
-
//-------------------------------------------------
-// function_symbol_entry - constructor
+// add - add a new register symbol
//-------------------------------------------------
-function_symbol_entry::function_symbol_entry(symbol_table &table, const char *name, int minparams, int maxparams, symbol_table::execute_func execute)
- : symbol_entry(table, SMT_FUNCTION, name, ""),
- m_minparams(minparams),
- m_maxparams(maxparams),
- m_execute(execute)
+symbol_entry &symbol_table::add(const char *name, getter_func getter, setter_func setter, const std::string &format_string)
{
+ m_symlist.erase(name);
+ return *m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, getter, setter, format_string)).first->second;
}
//-------------------------------------------------
-// is_lval - is this symbol allowable as an lval?
+// add - add a new function symbol
//-------------------------------------------------
-bool function_symbol_entry::is_lval() const
+symbol_entry &symbol_table::add(const char *name, int minparams, int maxparams, execute_func execute)
{
- return false;
+ m_symlist.erase(name);
+ return *m_symlist.emplace(name, std::make_unique<function_symbol_entry>(*this, name, minparams, maxparams, execute)).first->second;
}
//-------------------------------------------------
-// value - return the value of this symbol
+// find_deep - do a deep search for a symbol,
+// looking in the parent if needed
//-------------------------------------------------
-u64 function_symbol_entry::value() const
+symbol_entry *symbol_table::find_deep(const char *symbol)
{
- throw emu_fatalerror("Symbol '%s' is a function and cannot be used in this context", m_name.c_str());
+ // walk up the table hierarchy to find the owner
+ for (symbol_table *symtable = this; symtable != nullptr; symtable = symtable->m_parent)
+ {
+ symbol_entry *entry = symtable->find(symbol);
+ if (entry != nullptr)
+ return entry;
+ }
+ return nullptr;
}
//-------------------------------------------------
-// set_value - set the value of this symbol
+// value - return the value of a symbol
//-------------------------------------------------
-void function_symbol_entry::set_value(u64 newvalue)
+u64 symbol_table::value(const char *symbol)
{
- throw emu_fatalerror("Symbol '%s' is a function and cannot be written", m_name.c_str());
+ symbol_entry *entry = find_deep(symbol);
+ return (entry != nullptr) ? entry->value() : 0;
}
//-------------------------------------------------
-// execute - execute the function
+// set_value - set the value of a symbol
//-------------------------------------------------
-u64 function_symbol_entry::execute(int numparams, const u64 *paramlist)
+void symbol_table::set_value(const char *symbol, u64 value)
{
- if (numparams < m_minparams)
- throw emu_fatalerror("Function '%s' requires at least %d parameters", m_name.c_str(), m_minparams);
- if (numparams > m_maxparams)
- throw emu_fatalerror("Function '%s' accepts no more than %d parameters", m_name.c_str(), m_maxparams);
- return m_execute(m_table, numparams, paramlist);
+ symbol_entry *entry = find_deep(symbol);
+ if (entry != nullptr)
+ entry->set_value(value);
}
//**************************************************************************
-// SYMBOL TABLE
+// EXPRESSION MEMORY HANDLERS
//**************************************************************************
//-------------------------------------------------
-// symbol_table - constructor
+// read_memory - return 1,2,4 or 8 bytes
+// from the specified memory space
//-------------------------------------------------
-symbol_table::symbol_table(void *globalref, symbol_table *parent)
- : m_parent(parent),
- m_globalref(globalref),
- m_memory_param(nullptr),
- m_memory_valid(nullptr),
- m_memory_read(nullptr),
- m_memory_write(nullptr)
+u64 symbol_table::read_memory(address_space &space, offs_t address, int size, bool apply_translation)
{
-}
+ u64 result = ~u64(0) >> (64 - 8*size);
+ address_space *tspace = &space;
-//-------------------------------------------------
-// add - add a new u64 pointer symbol
-//-------------------------------------------------
+ if (apply_translation)
+ {
+ // mask against the logical byte mask
+ address &= space.logaddrmask();
-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;
+ // translate if necessary; if not mapped, return 0xffffffffffffffff
+ if (!space.device().memory().translate(space.spacenum(), device_memory_interface::TR_READ, address, tspace))
+ return result;
+ }
+
+ // otherwise, call the reading function for the translated address
+ switch (size)
+ {
+ case 1: result = tspace->read_byte(address); break;
+ case 2: result = tspace->read_word_unaligned(address); break;
+ case 4: result = tspace->read_dword_unaligned(address); break;
+ case 8: result = tspace->read_qword_unaligned(address); break;
+ }
+ return result;
}
//-------------------------------------------------
-// add - add a new u64 pointer symbol
+// write_memory - write 1,2,4 or 8 bytes to the
+// specified memory space
//-------------------------------------------------
-void symbol_table::add(const char *name, read_write rw, u64 *ptr)
+void symbol_table::write_memory(address_space &space, offs_t address, u64 data, int size, bool apply_translation)
{
- m_symlist.erase(name);
- m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, rw, ptr));
+ address_space *tspace = &space;
+
+ if (apply_translation)
+ {
+ // mask against the logical byte mask
+ address &= space.logaddrmask();
+
+ // translate if necessary; if not mapped, we're done
+ if (!space.device().memory().translate(space.spacenum(), device_memory_interface::TR_WRITE, address, tspace))
+ return;
+ }
+
+ // otherwise, call the writing function for the translated address
+ switch (size)
+ {
+ case 1: tspace->write_byte(address, data); break;
+ case 2: tspace->write_word_unaligned(address, data); break;
+ case 4: tspace->write_dword_unaligned(address, data); break;
+ case 8: tspace->write_qword_unaligned(address, data); break;
+ }
+
+ notify_memory_modified();
}
//-------------------------------------------------
-// add - add a new value symbol
+// expression_get_space - return a space
+// based on a case insensitive tag search
//-------------------------------------------------
-void symbol_table::add(const char *name, u64 value)
+expression_error symbol_table::expression_get_space(const char *tag, int &spacenum, device_memory_interface *&memory)
{
- m_symlist.erase(name);
- m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, value));
+ device_t *device = nullptr;
+ std::string spacename;
+ if (tag)
+ {
+ // convert to lowercase then lookup the name (tags are enforced to be all lower case)
+ auto base = get_device_search(m_machine, m_memintf, tag);
+ device = base.first.subdevice(strmakelower(base.second));
+
+ // if that failed, treat the last component as an address space
+ if (!device)
+ {
+ std::string_view t = base.second;
+ auto const delimiter = t.find_last_of(":^");
+ bool const found = std::string_view::npos != delimiter;
+ if (!found || (':' == t[delimiter]))
+ {
+ spacename = strmakelower(t.substr(found ? (delimiter + 1) : 0));
+ t = t.substr(0, !found ? 0 : !delimiter ? 1 : delimiter);
+ if (!t.empty())
+ device = base.first.subdevice(strmakelower(t));
+ else
+ device = m_memintf ? &m_memintf->device() : &m_machine.root_device();
+ }
+ }
+ }
+ else if (m_memintf)
+ {
+ device = &m_memintf->device();
+ }
+
+ // if still no device, report error
+ if (!device)
+ {
+ memory = nullptr;
+ return expression_error::INVALID_MEMORY_NAME;
+ }
+
+ // ensure device has memory interface, and check for space if search not required
+ if (!device->interface(memory) || (spacename.empty() && (0 <= spacenum) && !memory->has_space(spacenum)))
+ {
+ memory = nullptr;
+ return expression_error::NO_SUCH_MEMORY_SPACE;
+ }
+
+ // search not required
+ if (spacename.empty() && (0 <= spacenum))
+ return expression_error::NONE;
+
+ // find space by name or take first populated space if required
+ for (int i = 0; memory->max_space_count() > i; ++i)
+ {
+ if (memory->has_space(i) && (spacename.empty() || (memory->space(i).name() == spacename)))
+ {
+ spacenum = i;
+ return expression_error::NONE;
+ }
+ }
+
+ // space not found
+ memory = nullptr;
+ return expression_error::NO_SUCH_MEMORY_SPACE;
}
//-------------------------------------------------
-// add - add a new register symbol
+// notify_memory_modified - notify that memory
+// has been changed
//-------------------------------------------------
-void symbol_table::add(const char *name, getter_func getter, setter_func setter, const std::string &format_string)
+void symbol_table::notify_memory_modified()
{
- m_symlist.erase(name);
- m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, getter, setter, format_string));
+ // walk up the table hierarchy to find the owner
+ for (symbol_table *symtable = this; symtable != nullptr; symtable = symtable->m_parent)
+ if (symtable->m_memory_modified)
+ symtable->m_memory_modified();
}
//-------------------------------------------------
-// add - add a new function symbol
+// memory_value - read 1,2,4 or 8 bytes at the
+// given offset in the given address space
//-------------------------------------------------
-void symbol_table::add(const char *name, int minparams, int maxparams, execute_func execute)
+u64 symbol_table::memory_value(const char *name, expression_space spacenum, u32 address, int size, bool disable_se)
{
- m_symlist.erase(name);
- m_symlist.emplace(name, std::make_unique<function_symbol_entry>(*this, name, minparams, maxparams, execute));
+ device_memory_interface *memory = m_memintf;
+
+ bool logical = true;
+ int space = -1;
+ switch (spacenum)
+ {
+ case EXPSPACE_PROGRAM_PHYSICAL:
+ case EXPSPACE_DATA_PHYSICAL:
+ case EXPSPACE_IO_PHYSICAL:
+ case EXPSPACE_OPCODE_PHYSICAL:
+ spacenum = expression_space(spacenum - (EXPSPACE_PROGRAM_PHYSICAL - EXPSPACE_PROGRAM_LOGICAL));
+ logical = false;
+ [[fallthrough]];
+ case EXPSPACE_PROGRAM_LOGICAL:
+ case EXPSPACE_DATA_LOGICAL:
+ case EXPSPACE_IO_LOGICAL:
+ case EXPSPACE_OPCODE_LOGICAL:
+ space = AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL);
+ expression_get_space(name, space, memory);
+ if (memory)
+ {
+ auto dis = m_machine.disable_side_effects(disable_se);
+ return read_memory(memory->space(space), address, size, logical);
+ }
+ break;
+
+ case EXPSPACE_PRGDIRECT:
+ case EXPSPACE_OPDIRECT:
+ space = (spacenum == EXPSPACE_OPDIRECT) ? AS_OPCODES : AS_PROGRAM;
+ expression_get_space(name, space, memory);
+ if (memory)
+ {
+ auto dis = m_machine.disable_side_effects(disable_se);
+ return read_program_direct(memory->space(space), (spacenum == EXPSPACE_OPDIRECT) ? 1 : 0, address, size);
+ }
+ break;
+
+ case EXPSPACE_REGION:
+ if (name)
+ return read_memory_region(name, address, size);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
}
//-------------------------------------------------
-// find_deep - do a deep search for a symbol,
-// looking in the parent if needed
+// read_program_direct - read memory directly
+// from an opcode or RAM pointer
//-------------------------------------------------
-symbol_entry *symbol_table::find_deep(const char *symbol)
+u64 symbol_table::read_program_direct(address_space &space, int opcode, offs_t address, int size)
{
- // walk up the table hierarchy to find the owner
- for (symbol_table *symtable = this; symtable != nullptr; symtable = symtable->m_parent)
+ u8 *base;
+
+ // adjust the address into a byte address, but not if being called recursively
+ if ((opcode & 2) == 0)
+ address = space.address_to_byte(address);
+
+ // call ourself recursively until we are byte-sized
+ if (size > 1)
{
- symbol_entry *entry = symtable->find(symbol);
- if (entry != nullptr)
- return entry;
+ int halfsize = size / 2;
+
+ // read each half, from lower address to upper address
+ u64 r0 = read_program_direct(space, opcode | 2, address + 0, halfsize);
+ u64 r1 = read_program_direct(space, opcode | 2, address + halfsize, halfsize);
+
+ // assemble based on the target endianness
+ if (space.endianness() == ENDIANNESS_LITTLE)
+ return r0 | (r1 << (8 * halfsize));
+ else
+ return r1 | (r0 << (8 * halfsize));
}
- return nullptr;
+
+ // handle the byte-sized final requests
+ else
+ {
+ // lowmask specified which address bits are within the databus width
+ offs_t lowmask = space.data_width() / 8 - 1;
+
+ // get the base of memory, aligned to the address minus the lowbits
+ base = (u8 *)space.get_read_ptr(address & ~lowmask);
+
+ // if we have a valid base, return the appropriate byte
+ if (base != nullptr)
+ {
+ if (space.endianness() == ENDIANNESS_LITTLE)
+ return base[BYTE8_XOR_LE(address) & lowmask];
+ else
+ return base[BYTE8_XOR_BE(address) & lowmask];
+ }
+ }
+
+ return 0;
}
//-------------------------------------------------
-// value - return the value of a symbol
+// read_memory_region - read memory from a
+// memory region
//-------------------------------------------------
-u64 symbol_table::value(const char *symbol)
+u64 symbol_table::read_memory_region(const char *rgntag, offs_t address, int size)
{
- symbol_entry *entry = find_deep(symbol);
- return (entry != nullptr) ? entry->value() : 0;
+ auto search = get_device_search(m_machine, m_memintf, rgntag);
+ memory_region *const region = search.first.memregion(search.second);
+ u64 result = ~u64(0) >> (64 - 8*size);
+
+ // make sure we get a valid base before proceeding
+ if (region)
+ {
+ // call ourself recursively until we are byte-sized
+ if (size > 1)
+ {
+ int halfsize = size / 2;
+ u64 r0, r1;
+
+ // read each half, from lower address to upper address
+ r0 = read_memory_region(rgntag, address + 0, halfsize);
+ r1 = read_memory_region(rgntag, address + halfsize, halfsize);
+
+ // assemble based on the target endianness
+ if (region->endianness() == ENDIANNESS_LITTLE)
+ result = r0 | (r1 << (8 * halfsize));
+ else
+ result = r1 | (r0 << (8 * halfsize));
+ }
+
+ // only process if we're within range
+ else if (address < region->bytes())
+ {
+ // lowmask specified which address bits are within the databus width
+ u32 lowmask = region->bytewidth() - 1;
+ u8 *base = region->base() + (address & ~lowmask);
+
+ // if we have a valid base, return the appropriate byte
+ if (region->endianness() == ENDIANNESS_LITTLE)
+ result = base[BYTE8_XOR_LE(address) & lowmask];
+ else
+ result = base[BYTE8_XOR_BE(address) & lowmask];
+ }
+ }
+ return result;
}
//-------------------------------------------------
-// set_value - set the value of a symbol
+// set_memory_value - write 1,2,4 or 8 bytes at
+// the given offset in the given address space
//-------------------------------------------------
-void symbol_table::set_value(const char *symbol, u64 value)
+void symbol_table::set_memory_value(const char *name, expression_space spacenum, u32 address, int size, u64 data, bool disable_se)
{
- symbol_entry *entry = find_deep(symbol);
- if (entry != nullptr)
- entry->set_value(value);
+ device_memory_interface *memory = m_memintf;
+
+ bool logical = true;
+ int space = -1;
+ switch (spacenum)
+ {
+ case EXPSPACE_PROGRAM_PHYSICAL:
+ case EXPSPACE_DATA_PHYSICAL:
+ case EXPSPACE_IO_PHYSICAL:
+ case EXPSPACE_OPCODE_PHYSICAL:
+ spacenum = expression_space(spacenum - (EXPSPACE_PROGRAM_PHYSICAL - EXPSPACE_PROGRAM_LOGICAL));
+ logical = false;
+ [[fallthrough]];
+ case EXPSPACE_PROGRAM_LOGICAL:
+ case EXPSPACE_DATA_LOGICAL:
+ case EXPSPACE_IO_LOGICAL:
+ case EXPSPACE_OPCODE_LOGICAL:
+ space = AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL);
+ expression_get_space(name, space, memory);
+ if (memory)
+ {
+ auto dis = m_machine.disable_side_effects(disable_se);
+ write_memory(memory->space(space), address, data, size, logical);
+ }
+ break;
+
+ case EXPSPACE_PRGDIRECT:
+ case EXPSPACE_OPDIRECT:
+ space = (spacenum == EXPSPACE_OPDIRECT) ? AS_OPCODES : AS_PROGRAM;
+ expression_get_space(name, space, memory);
+ if (memory)
+ {
+ auto dis = m_machine.disable_side_effects(disable_se);
+ write_program_direct(memory->space(space), (spacenum == EXPSPACE_OPDIRECT) ? 1 : 0, address, size, data);
+ }
+ break;
+
+ case EXPSPACE_REGION:
+ if (name)
+ write_memory_region(name, address, size, data);
+ break;
+
+ default:
+ break;
+ }
}
//-------------------------------------------------
-// memory_valid - return true if the given
-// memory name/space/offset combination is valid
+// write_program_direct - write memory directly
+// to an opcode or RAM pointer
//-------------------------------------------------
-expression_error::error_code symbol_table::memory_valid(const char *name, expression_space space)
+void symbol_table::write_program_direct(address_space &space, int opcode, offs_t address, int size, u64 data)
{
- // walk up the table hierarchy to find the owner
- for (symbol_table *symtable = this; symtable != nullptr; symtable = symtable->m_parent)
- if (symtable->m_memory_valid != nullptr)
+ // adjust the address into a byte address, but not if being called recursively
+ if ((opcode & 2) == 0)
+ address = space.address_to_byte(address);
+
+ // call ourself recursively until we are byte-sized
+ if (size > 1)
+ {
+ int halfsize = size / 2;
+
+ // break apart based on the target endianness
+ u64 halfmask = ~u64(0) >> (64 - 8 * halfsize);
+ u64 r0, r1;
+ if (space.endianness() == ENDIANNESS_LITTLE)
{
- 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;
+ r0 = data & halfmask;
+ r1 = (data >> (8 * halfsize)) & halfmask;
}
- return expression_error::NO_SUCH_MEMORY_SPACE;
+ else
+ {
+ r0 = (data >> (8 * halfsize)) & halfmask;
+ r1 = data & halfmask;
+ }
+
+ // write each half, from lower address to upper address
+ write_program_direct(space, opcode | 2, address + 0, halfsize, r0);
+ write_program_direct(space, opcode | 2, address + halfsize, halfsize, r1);
+ }
+
+ // handle the byte-sized final case
+ else
+ {
+ // lowmask specified which address bits are within the databus width
+ offs_t lowmask = space.data_width() / 8 - 1;
+
+ // get the base of memory, aligned to the address minus the lowbits
+ u8 *base = (u8 *)space.get_read_ptr(address & ~lowmask);
+
+ // if we have a valid base, write the appropriate byte
+ if (base != nullptr)
+ {
+ if (space.endianness() == ENDIANNESS_LITTLE)
+ base[BYTE8_XOR_LE(address) & lowmask] = data;
+ else
+ base[BYTE8_XOR_BE(address) & lowmask] = data;
+ notify_memory_modified();
+ }
+ }
}
//-------------------------------------------------
-// memory_value - return a value read from memory
+// write_memory_region - write memory to a
+// memory region
//-------------------------------------------------
-u64 symbol_table::memory_value(const char *name, expression_space space, u32 offset, int size, bool disable_se)
+void symbol_table::write_memory_region(const char *rgntag, offs_t address, int size, u64 data)
{
- // walk up the table hierarchy to find the owner
- for (symbol_table *symtable = this; symtable != nullptr; symtable = symtable->m_parent)
- if (symtable->m_memory_valid != nullptr)
+ auto search = get_device_search(m_machine, m_memintf, rgntag);
+ memory_region *const region = search.first.memregion(search.second);
+
+ // make sure we get a valid base before proceeding
+ if (region)
+ {
+ // call ourself recursively until we are byte-sized
+ if (size > 1)
{
- 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 != nullptr)
- return symtable->m_memory_read(symtable->m_memory_param, name, space, offset, size, disable_se);
- return 0;
+ int halfsize = size / 2;
+
+ // break apart based on the target endianness
+ u64 halfmask = ~u64(0) >> (64 - 8 * halfsize);
+ u64 r0, r1;
+ if (region->endianness() == ENDIANNESS_LITTLE)
+ {
+ r0 = data & halfmask;
+ r1 = (data >> (8 * halfsize)) & halfmask;
+ }
+ else
+ {
+ r0 = (data >> (8 * halfsize)) & halfmask;
+ r1 = data & halfmask;
+ }
+
+ // write each half, from lower address to upper address
+ write_memory_region(rgntag, address + 0, halfsize, r0);
+ write_memory_region(rgntag, address + halfsize, halfsize, r1);
}
- return 0;
+
+ // only process if we're within range
+ else if (address < region->bytes())
+ {
+ // lowmask specified which address bits are within the databus width
+ u32 lowmask = region->bytewidth() - 1;
+ u8 *base = region->base() + (address & ~lowmask);
+
+ // if we have a valid base, set the appropriate byte
+ if (region->endianness() == ENDIANNESS_LITTLE)
+ {
+ base[BYTE8_XOR_LE(address) & lowmask] = data;
+ }
+ else
+ {
+ base[BYTE8_XOR_BE(address) & lowmask] = data;
+ }
+ notify_memory_modified();
+ }
+ }
}
//-------------------------------------------------
-// set_memory_value - write a value to memory
+// memory_valid - return true if the given
+// memory name/space/offset combination is valid
//-------------------------------------------------
-void symbol_table::set_memory_value(const char *name, expression_space space, u32 offset, int size, u64 value, bool disable_se)
+expression_error::error_code symbol_table::memory_valid(const char *name, expression_space space)
{
- // walk up the table hierarchy to find the owner
- for (symbol_table *symtable = this; symtable != nullptr; symtable = symtable->m_parent)
- if (symtable->m_memory_valid != nullptr)
+ device_memory_interface *memory = m_memintf;
+
+ int spaceno = -1;
+ switch (space)
+ {
+ case EXPSPACE_PROGRAM_LOGICAL:
+ case EXPSPACE_DATA_LOGICAL:
+ case EXPSPACE_IO_LOGICAL:
+ case EXPSPACE_OPCODE_LOGICAL:
+ spaceno = AS_PROGRAM + (space - EXPSPACE_PROGRAM_LOGICAL);
+ return expression_get_space(name, spaceno, memory);
+
+ case EXPSPACE_PROGRAM_PHYSICAL:
+ case EXPSPACE_DATA_PHYSICAL:
+ case EXPSPACE_IO_PHYSICAL:
+ case EXPSPACE_OPCODE_PHYSICAL:
+ spaceno = AS_PROGRAM + (space - EXPSPACE_PROGRAM_PHYSICAL);
+ return expression_get_space(name, spaceno, memory);
+
+ case EXPSPACE_PRGDIRECT:
+ case EXPSPACE_OPDIRECT:
+ spaceno = (space == EXPSPACE_OPDIRECT) ? AS_OPCODES : AS_PROGRAM;
+ return expression_get_space(name, spaceno, memory);
+
+ case EXPSPACE_REGION:
+ if (!name)
{
- 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 != nullptr)
- symtable->m_memory_write(symtable->m_memory_param, name, space, offset, size, value, disable_se);
- return;
+ return expression_error::MISSING_MEMORY_NAME;
}
+ else
+ {
+ auto search = get_device_search(m_machine, m_memintf, name);
+ memory_region *const region = search.first.memregion(search.second);
+ if (!region || !region->base())
+ return expression_error::INVALID_MEMORY_NAME;
+ }
+ break;
+
+ default:
+ return expression_error::NO_SUCH_MEMORY_SPACE;
+ }
+
+ return expression_error::NONE;
}
@@ -538,16 +1014,33 @@ void symbol_table::set_memory_value(const char *name, expression_space space, u3
// parsed_expression - constructor
//-------------------------------------------------
-parsed_expression::parsed_expression(symbol_table *symtable, const char *expression, u64 *result)
+parsed_expression::parsed_expression(symbol_table &symtable)
: m_symtable(symtable)
+ , m_default_base(16)
{
- // if we got an expression parse it
- if (expression != nullptr)
- parse(expression);
+}
+
+parsed_expression::parsed_expression(symbol_table &symtable, std::string_view expression, int default_base)
+ : m_symtable(symtable)
+ , m_default_base(default_base)
+{
+ assert(default_base == 8 || default_base == 10 || default_base == 16);
+
+ parse(expression);
+}
+
- // if we get a result pointer, execute it
- if (result != nullptr)
- *result = execute();
+//-------------------------------------------------
+// parsed_expression - copy constructor
+//-------------------------------------------------
+
+parsed_expression::parsed_expression(const parsed_expression &src)
+ : m_symtable(src.m_symtable)
+ , m_default_base(src.m_default_base)
+ , m_original_string(src.m_original_string)
+{
+ if (!m_original_string.empty())
+ parse_string_into_tokens();
}
@@ -555,12 +1048,12 @@ parsed_expression::parsed_expression(symbol_table *symtable, const char *express
// parse - parse an expression into tokens
//-------------------------------------------------
-void parsed_expression::parse(const char *expression)
+void parsed_expression::parse(std::string_view expression)
{
// copy the string and reset our parsing state
m_original_string.assign(expression);
- m_tokenlist.reset();
- m_stringlist.reset();
+ m_tokenlist.clear();
+ m_stringlist.clear();
// first parse the tokens into the token array in order
parse_string_into_tokens();
@@ -577,6 +1070,7 @@ void parsed_expression::parse(const char *expression)
void parsed_expression::copy(const parsed_expression &src)
{
m_symtable = src.m_symtable;
+ m_default_base = src.m_default_base;
m_original_string.assign(src.m_original_string);
if (!m_original_string.empty())
parse_string_into_tokens();
@@ -588,89 +1082,72 @@ void parsed_expression::copy(const parsed_expression &src)
// human readable token representation
//-------------------------------------------------
-void parsed_expression::print_tokens(FILE *out)
+void parsed_expression::print_tokens()
{
-#if DEBUG_TOKENS
- osd_printf_debug("----\n");
- for (parse_token *token = m_tokens.first(); token != nullptr; token = token->next())
+ LOG("----\n");
+ for (parse_token &token : m_tokenlist)
{
- switch (token->type)
+ if (token.is_number())
+ LOG("NUMBER: %016X\n", token.value());
+ else if (token.is_string())
+ LOG("STRING: ""%s""\n", token.string());
+ else if (token.is_symbol())
+ LOG("SYMBOL: %s%s%s\n", token.symbol().name(), token.symbol().is_function() ? "()" : "", token.symbol().is_lval() ? " &" : "");
+ else if (token.is_operator())
{
- default:
- case parse_token::INVALID:
- fprintf(out, "INVALID\n");
- break;
-
- case parse_token::END:
- fprintf(out, "END\n");
- break;
-
- case parse_token::NUMBER:
- fprintf(out, "NUMBER: %08X%08X\n", (u32)(token->value.i >> 32), u32(token->value.i));
- break;
-
- case parse_token::STRING:
- fprintf(out, "STRING: ""%s""\n", token->string);
- break;
-
- case parse_token::SYMBOL:
- fprintf(out, "SYMBOL: %08X%08X\n", u32(token->value.i >> 32), u32(token->value.i));
- break;
-
- case parse_token::OPERATOR:
- switch (token->value.i)
- {
- case TVL_LPAREN: fprintf(out, "(\n"); break;
- case TVL_RPAREN: fprintf(out, ")\n"); break;
- case TVL_PLUSPLUS: fprintf(out, "++ (unspecified)\n"); break;
- case TVL_MINUSMINUS: fprintf(out, "-- (unspecified)\n"); break;
- case TVL_PREINCREMENT: fprintf(out, "++ (prefix)\n"); break;
- case TVL_PREDECREMENT: fprintf(out, "-- (prefix)\n"); break;
- case TVL_POSTINCREMENT: fprintf(out, "++ (postfix)\n"); break;
- case TVL_POSTDECREMENT: fprintf(out, "-- (postfix)\n"); break;
- case TVL_COMPLEMENT: fprintf(out, "!\n"); break;
- case TVL_NOT: fprintf(out, "~\n"); break;
- case TVL_UPLUS: fprintf(out, "+ (unary)\n"); break;
- case TVL_UMINUS: fprintf(out, "- (unary)\n"); break;
- case TVL_MULTIPLY: fprintf(out, "*\n"); break;
- case TVL_DIVIDE: fprintf(out, "/\n"); break;
- case TVL_MODULO: fprintf(out, "%%\n"); break;
- case TVL_ADD: fprintf(out, "+\n"); break;
- case TVL_SUBTRACT: fprintf(out, "-\n"); break;
- case TVL_LSHIFT: fprintf(out, "<<\n"); break;
- case TVL_RSHIFT: fprintf(out, ">>\n"); break;
- case TVL_LESS: fprintf(out, "<\n"); break;
- case TVL_LESSOREQUAL: fprintf(out, "<=\n"); break;
- case TVL_GREATER: fprintf(out, ">\n"); break;
- case TVL_GREATEROREQUAL:fprintf(out, ">=\n"); break;
- case TVL_EQUAL: fprintf(out, "==\n"); break;
- case TVL_NOTEQUAL: fprintf(out, "!=\n"); break;
- case TVL_BAND: fprintf(out, "&\n"); break;
- case TVL_BXOR: fprintf(out, "^\n"); break;
- case TVL_BOR: fprintf(out, "|\n"); break;
- case TVL_LAND: fprintf(out, "&&\n"); break;
- case TVL_LOR: fprintf(out, "||\n"); break;
- case TVL_ASSIGN: fprintf(out, "=\n"); break;
- case TVL_ASSIGNMULTIPLY:fprintf(out, "*=\n"); break;
- case TVL_ASSIGNDIVIDE: fprintf(out, "/=\n"); break;
- case TVL_ASSIGNMODULO: fprintf(out, "%%=\n"); break;
- case TVL_ASSIGNADD: fprintf(out, "+=\n"); break;
- case TVL_ASSIGNSUBTRACT:fprintf(out, "-=\n"); break;
- case TVL_ASSIGNLSHIFT: fprintf(out, "<<=\n"); break;
- case TVL_ASSIGNRSHIFT: fprintf(out, ">>=\n"); break;
- case TVL_ASSIGNBAND: fprintf(out, "&=\n"); break;
- case TVL_ASSIGNBXOR: fprintf(out, "^=\n"); break;
- case TVL_ASSIGNBOR: fprintf(out, "|=\n"); break;
- case TVL_COMMA: fprintf(out, ",\n"); break;
- case TVL_MEMORYAT: fprintf(out, token.memory_size_effect() ? "mem!\n" : "mem@\n");break;
- case TVL_EXECUTEFUNC: fprintf(out, "execute\n"); break;
- default: fprintf(out, "INVALID OPERATOR\n"); break;
- }
- break;
+ switch (token.optype())
+ {
+ case TVL_LPAREN: LOG("(\n"); break;
+ case TVL_RPAREN: LOG(")\n"); break;
+ case TVL_PLUSPLUS: LOG("++ (unspecified)\n"); break;
+ case TVL_MINUSMINUS: LOG("-- (unspecified)\n"); break;
+ case TVL_PREINCREMENT: LOG("++ (prefix)\n"); break;
+ case TVL_PREDECREMENT: LOG("-- (prefix)\n"); break;
+ case TVL_POSTINCREMENT: LOG("++ (postfix)\n"); break;
+ case TVL_POSTDECREMENT: LOG("-- (postfix)\n"); break;
+ case TVL_COMPLEMENT: LOG("!\n"); break;
+ case TVL_NOT: LOG("~\n"); break;
+ case TVL_UPLUS: LOG("+ (unary)\n"); break;
+ case TVL_UMINUS: LOG("- (unary)\n"); break;
+ case TVL_MULTIPLY: LOG("*\n"); break;
+ case TVL_DIVIDE: LOG("/\n"); break;
+ case TVL_MODULO: LOG("%%\n"); break;
+ case TVL_ADD: LOG("+\n"); break;
+ case TVL_SUBTRACT: LOG("-\n"); break;
+ case TVL_LSHIFT: LOG("<<\n"); break;
+ case TVL_RSHIFT: LOG(">>\n"); break;
+ case TVL_LESS: LOG("<\n"); break;
+ case TVL_LESSOREQUAL: LOG("<=\n"); break;
+ case TVL_GREATER: LOG(">\n"); break;
+ case TVL_GREATEROREQUAL:LOG(">=\n"); break;
+ case TVL_EQUAL: LOG("==\n"); break;
+ case TVL_NOTEQUAL: LOG("!=\n"); break;
+ case TVL_BAND: LOG("&\n"); break;
+ case TVL_BXOR: LOG("^\n"); break;
+ case TVL_BOR: LOG("|\n"); break;
+ case TVL_LAND: LOG("&&\n"); break;
+ case TVL_LOR: LOG("||\n"); break;
+ case TVL_ASSIGN: LOG("=\n"); break;
+ case TVL_ASSIGNMULTIPLY:LOG("*=\n"); break;
+ case TVL_ASSIGNDIVIDE: LOG("/=\n"); break;
+ case TVL_ASSIGNMODULO: LOG("%%=\n"); break;
+ case TVL_ASSIGNADD: LOG("+=\n"); break;
+ case TVL_ASSIGNSUBTRACT:LOG("-=\n"); break;
+ case TVL_ASSIGNLSHIFT: LOG("<<=\n"); break;
+ case TVL_ASSIGNRSHIFT: LOG(">>=\n"); break;
+ case TVL_ASSIGNBAND: LOG("&=\n"); break;
+ case TVL_ASSIGNBXOR: LOG("^=\n"); break;
+ case TVL_ASSIGNBOR: LOG("|=\n"); break;
+ case TVL_COMMA: LOG(",\n"); break;
+ case TVL_MEMORYAT: LOG(token.memory_side_effects() ? "mem!\n" : "mem@\n");break;
+ case TVL_EXECUTEFUNC: LOG("execute\n"); break;
+ default: LOG("INVALID OPERATOR\n"); break;
+ }
}
+ else
+ LOG("INVALID\n");
}
- osd_printf_debug("----\n");
-#endif
+ LOG("----\n");
}
@@ -693,7 +1170,8 @@ void parsed_expression::parse_string_into_tokens()
break;
// initialize the current token object
- parse_token &token = m_tokenlist.append(*global_alloc(parse_token(string - stringstart)));
+ m_tokenlist.emplace_back(string - stringstart);
+ parse_token &token = m_tokenlist.back();
// switch off the first character
switch (tolower(u8(string[0])))
@@ -854,12 +1332,15 @@ void parsed_expression::parse_symbol_or_number(parse_token &token, const char *&
// check for memory @ and ! operators
if (string[0] == '@' || string[0] == '!')
{
- try {
+ try
+ {
bool disable_se = string[0] == '@';
parse_memory_operator(token, buffer.c_str(), disable_se);
string += 1;
return;
- } catch(const expression_error &) {
+ }
+ catch (const expression_error &)
+ {
// Try some other operator instead
}
}
@@ -943,21 +1424,20 @@ void parsed_expression::parse_symbol_or_number(parse_token &token, const char *&
catch (expression_error const &err)
{
// this is really a hack, but 0B1234 could also hex depending on default base
- if (expression_error::INVALID_NUMBER == err)
- return parse_number(token, buffer.c_str(), DEFAULT_BASE, expression_error::INVALID_NUMBER);
+ if (expression_error::INVALID_NUMBER == err && m_default_base == 16)
+ return parse_number(token, buffer.c_str(), m_default_base, expression_error::INVALID_NUMBER);
else
throw;
}
- // TODO: for octal address spaces, treat 0123 as octal
default:
; // fall through
}
- // fall through
+ [[fallthrough]];
default:
// check for a symbol match
- symbol_entry *symbol = m_symtable->find_deep(buffer.c_str());
+ symbol_entry *symbol = m_symtable.get().find_deep(buffer.c_str());
if (symbol != nullptr)
{
token.configure_symbol(*symbol);
@@ -965,14 +1445,15 @@ void parsed_expression::parse_symbol_or_number(parse_token &token, const char *&
// if this is a function symbol, synthesize an execute function operator
if (symbol->is_function())
{
- parse_token &newtoken = m_tokenlist.append(*global_alloc(parse_token(string - stringstart)));
+ m_tokenlist.emplace_back(string - stringstart);
+ parse_token &newtoken = m_tokenlist.back();
newtoken.configure_operator(TVL_EXECUTEFUNC, 0);
}
return;
}
// attempt to parse as a number in the default base
- parse_number(token, buffer.c_str(), DEFAULT_BASE, expression_error::UNKNOWN_SYMBOL);
+ parse_number(token, buffer.c_str(), m_default_base, expression_error::UNKNOWN_SYMBOL);
}
}
@@ -1072,7 +1553,7 @@ void parsed_expression::parse_quoted_string(parse_token &token, const char *&str
string++;
// make the token
- token.configure_string(m_stringlist.append(*global_alloc(expression_string(buffer.c_str()))));
+ token.configure_string(m_stringlist.emplace(m_stringlist.end(), buffer.c_str())->c_str());
}
@@ -1089,17 +1570,17 @@ void parsed_expression::parse_memory_operator(parse_token &token, const char *st
const char *dot = strrchr(string, '.');
if (dot != nullptr)
{
- namestring = m_stringlist.append(*global_alloc(expression_string(string, dot - string)));
+ namestring = m_stringlist.emplace(m_stringlist.end(), string, dot)->c_str();
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)
{
+ // length 3 means logical/physical, then space, then size
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')
@@ -1108,21 +1589,22 @@ void parsed_expression::parse_memory_operator(parse_token &token, const char *st
space = string[1];
size = string[2];
}
-
- // length 2 means space then size
else if (length == 2)
{
+ // length 2 means space then size
space = string[0];
size = string[1];
}
-
- // length 1 means size
else if (length == 1)
+ {
+ // length 1 means size
size = string[0];
-
- // anything else is invalid
+ }
else
+ {
+ // anything else is invalid
throw expression_error(expression_error::INVALID_TOKEN, token.offset());
+ }
// convert the space to flags
expression_space memspace;
@@ -1131,9 +1613,9 @@ void parsed_expression::parse_memory_operator(parse_token &token, const char *st
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 '3': memspace = physical ? EXPSPACE_OPCODE_PHYSICAL : EXPSPACE_OPCODE_LOGICAL; break;
+ case 'r': memspace = EXPSPACE_PRGDIRECT; break;
+ case 'o': memspace = EXPSPACE_OPDIRECT; break;
case 'm': memspace = EXPSPACE_REGION; break;
default: throw expression_error(expression_error::INVALID_MEMORY_SPACE, token.offset() + (string - startstring));
}
@@ -1150,12 +1632,9 @@ void parsed_expression::parse_memory_operator(parse_token &token, const char *st
}
// validate the name
- if (m_symtable != nullptr)
- {
- expression_error::error_code err = m_symtable->memory_valid(namestring, memspace);
- if (err != expression_error::NONE)
- throw expression_error(err, token.offset() + (string - startstring));
- }
+ expression_error::error_code err = m_symtable.get().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).set_memory_side_effects(disable_se);
@@ -1167,9 +1646,8 @@ void parsed_expression::parse_memory_operator(parse_token &token, const char *st
// ambiguities based on neighboring tokens
//-------------------------------------------------
-void parsed_expression::normalize_operator(parse_token *prevtoken, parse_token &thistoken)
+void parsed_expression::normalize_operator(parse_token &thistoken, parse_token *prevtoken, parse_token *nexttoken, const std::list<parse_token> &stack, bool was_rparen)
{
- parse_token *nexttoken = thistoken.next();
switch (thistoken.optype())
{
// Determine if an open paren is part of a function or not
@@ -1203,15 +1681,15 @@ void parsed_expression::normalize_operator(parse_token *prevtoken, parse_token &
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 == nullptr || (!prevtoken->is_symbol() && !prevtoken->is_number() && !prevtoken->is_operator(TVL_RPAREN)))
+ if (prevtoken == nullptr || (!prevtoken->is_symbol() && !prevtoken->is_number() && !was_rparen))
thistoken.configure_operator(thistoken.is_operator(TVL_ADD) ? TVL_UPLUS : TVL_UMINUS, 2);
break;
// Determine if , refers to a function parameter
case TVL_COMMA:
- for (auto lookback = m_token_stack.rbegin(); lookback != m_token_stack.rend(); ++lookback)
+ for (auto lookback = stack.begin(); lookback != stack.end(); ++lookback)
{
- parse_token &peek = *lookback;
+ const parse_token &peek = *lookback;
// if we hit an execute function operator, or else a left parenthesis that is
// already tagged, then tag us as well
@@ -1233,51 +1711,63 @@ void parsed_expression::normalize_operator(parse_token *prevtoken, parse_token &
void parsed_expression::infix_to_postfix()
{
- simple_list<parse_token> stack;
+ std::list<parse_token> stack;
+ parse_token *prev = nullptr;
+
+ // this flag is used to avoid looking back at a closing parenthesis that was already destroyed
+ bool was_rparen = false;
// loop over all the original tokens
- parse_token *prev = nullptr;
- parse_token *next;
- for (parse_token *token = m_tokenlist.detach_all(); token != nullptr; prev = token, token = next)
+ std::list<parse_token>::iterator next;
+ std::list<parse_token> origlist = std::move(m_tokenlist);
+ m_tokenlist.clear();
+ for (std::list<parse_token>::iterator token = origlist.begin(); token != origlist.end(); token = next)
{
// pre-determine our next token
- next = token->next();
+ next = std::next(token);
// 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);
+ {
+ m_tokenlist.splice(m_tokenlist.end(), origlist, token);
+
+ // remember this as the previous token
+ prev = &*token;
+ was_rparen = false;
+ }
// if this is an operator, process it
else if (token->is_operator())
{
// normalize the operator based on neighbors
- normalize_operator(prev, *token);
+ normalize_operator(*token, prev, next != origlist.end() ? &*next : nullptr, stack, was_rparen);
+ was_rparen = false;
// if the token is an opening parenthesis, push it onto the stack.
if (token->is_operator(TVL_LPAREN))
- stack.prepend(*token);
+ stack.splice(stack.begin(), origlist, token);
// 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
+ // discarding the open parenthesis
else if (token->is_operator(TVL_RPAREN))
{
- // loop until we find our matching opener
- parse_token *popped;
- while ((popped = stack.detach_head()) != nullptr)
- {
- if (popped->is_operator(TVL_LPAREN))
- break;
- m_tokenlist.append(*popped);
- }
+ // find our matching opener
+ std::list<parse_token>::iterator lparen = std::find_if(stack.begin(), stack.end(),
+ [] (const parse_token &token) { return token.is_operator(TVL_LPAREN); }
+ );
// if we didn't find an open paren, it's an error
- if (popped == nullptr)
+ if (lparen == stack.end())
throw expression_error(expression_error::UNBALANCED_PARENS, token->offset());
+ // move the stacked operators to the end of the new list
+ m_tokenlist.splice(m_tokenlist.end(), stack, stack.begin(), lparen);
+
// free ourself and our matching opening parenthesis
- global_free(token);
- global_free(popped);
+ origlist.erase(token);
+ stack.erase(lparen);
+ was_rparen = true;
}
// if the token is an operator, pop operators until we reach an opening parenthesis,
@@ -1288,8 +1778,8 @@ void parsed_expression::infix_to_postfix()
int our_precedence = token->precedence();
// loop until we can't peek at the stack anymore
- parse_token *peek;
- while ((peek = stack.first()) != nullptr)
+ std::list<parse_token>::iterator peek;
+ for (peek = stack.begin(); peek != stack.end(); ++peek)
{
// break if any of the above conditions are true
if (peek->is_operator(TVL_LPAREN))
@@ -1297,28 +1787,29 @@ void parsed_expression::infix_to_postfix()
int stack_precedence = peek->precedence();
if (stack_precedence > our_precedence || (stack_precedence == our_precedence && peek->right_to_left()))
break;
-
- // pop this token
- m_tokenlist.append(*stack.detach_head());
}
+ // move the stacked operands to the end of the new list
+ m_tokenlist.splice(m_tokenlist.end(), stack, stack.begin(), peek);
+
// push the new operator
- stack.prepend(*token);
+ stack.splice(stack.begin(), origlist, token);
}
+
+ if (!was_rparen)
+ prev = &*token;
}
}
- // finish popping the stack
- parse_token *popped;
- while ((popped = stack.detach_head()) != nullptr)
- {
- // 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());
+ // it is an error to have a left parenthesis still on the stack
+ std::list<parse_token>::iterator lparen = std::find_if(stack.begin(), stack.end(),
+ [] (const parse_token &token) { return token.is_operator(TVL_LPAREN); }
+ );
+ if (lparen != stack.end())
+ throw expression_error(expression_error::UNBALANCED_PARENS, lparen->offset());
- // pop this token
- m_tokenlist.append(*popped);
- }
+ // pop all remaining tokens
+ m_tokenlist.splice(m_tokenlist.end(), stack, stack.begin(), stack.end());
}
@@ -1664,8 +2155,7 @@ u64 parsed_expression::execute_tokens()
//-------------------------------------------------
parsed_expression::parse_token::parse_token(int offset)
- : m_next(nullptr),
- m_type(INVALID),
+ : m_type(INVALID),
m_offset(offset),
m_value(0),
m_flags(0),
@@ -1680,16 +2170,15 @@ parsed_expression::parse_token::parse_token(int offset)
// for a SYMBOL token
//-------------------------------------------------
-u64 parsed_expression::parse_token::get_lval_value(symbol_table *table)
+u64 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 != nullptr) {
- return table->memory_value(m_string, memory_space(), address(), 1 << memory_size(), memory_side_effects());
- }
+ else if (is_memory())
+ return table.memory_value(m_string, memory_space(), address(), 1 << memory_size(), memory_side_effects());
return 0;
}
@@ -1700,15 +2189,15 @@ u64 parsed_expression::parse_token::get_lval_value(symbol_table *table)
// for a SYMBOL token
//-------------------------------------------------
-inline void parsed_expression::parse_token::set_lval_value(symbol_table *table, u64 value)
+inline void parsed_expression::parse_token::set_lval_value(symbol_table &table, u64 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 != nullptr)
- table->set_memory_value(m_string, memory_space(), address(), 1 << memory_size(), value, memory_side_effects());
+ else if (is_memory())
+ table.set_memory_value(m_string, memory_space(), address(), 1 << memory_size(), value, memory_side_effects());
}
@@ -1733,7 +2222,7 @@ void parsed_expression::execute_function(parse_token &token)
// if it is a function symbol, break out of the loop
if (peek.is_symbol())
{
- symbol = peek.symbol();
+ symbol = &peek.symbol();
if (symbol->is_function())
{
m_token_stack.pop_back();
@@ -1751,8 +2240,14 @@ void parsed_expression::execute_function(parse_token &token)
if (paramcount == MAX_FUNCTION_PARAMS)
throw expression_error(expression_error::INVALID_PARAM_COUNT, token.offset());
- // execute the function and push the result
+ // validate parameters
function_symbol_entry *function = downcast<function_symbol_entry *>(symbol);
+ if (paramcount < function->minparams())
+ throw expression_error(expression_error::TOO_FEW_PARAMS, token.offset(), function->minparams());
+ if (paramcount > function->maxparams())
+ throw expression_error(expression_error::TOO_MANY_PARAMS, token.offset(), function->maxparams());
+
+ // execute the function and push the result
parse_token result(token.offset());
result.configure_number(function->execute(paramcount, &funcparams[MAX_FUNCTION_PARAMS - paramcount]));
push_token(result);