Merge with develop
166 files changed, 5201 insertions(+), 2475 deletions(-) M core/core.vcxproj M core/core.vcxproj.filters M core/core/debug/timer.cpp M core/core/debug/timer.h M core/core/environment/log.cpp M core/core/environment/log.h M core/core/exceptions/exception.h M core/core/exceptions/file_exception.h M core/core/io/file_helpers.cpp M core/core/io/file_helpers.h M core/core/io/file_helpers_linux.cpp M core/core/io/file_helpers_win.cpp M core/core/io/file_id.h M core/core/io/file_id_linux.cpp M core/core/io/file_id_win.cpp M core/core/io/file_writer.cpp M core/core/io/file_writer.h M core/core/io/text_reader.cpp M core/core/io/text_reader.h A => core/core/math/sign.h M core/core/strings/murmur_hash.h M core/core/strings/string_helpers.cpp M core/core/strings/string_helpers.h M core/core/strings/utf8.cpp M core/core/strings/utf8.h M hasher/main.cpp A => jasm-6502/convert_6502_keyword_case.py M jasm/assembling/assembler.cpp M jasm/assembling/assembler.h M jasm/assembling/assembler_impl/assembler_impl.cpp M jasm/assembling/assembler_impl/assembler_impl.h M jasm/assembling/assembler_impl/expressions_impl.cpp M jasm/assembling/assembler_impl/functions_impl.cpp M jasm/assembling/assembler_impl/methods_impl.cpp M jasm/assembling/assembler_impl/operators_impl.cpp M jasm/assembling/assembler_impl/symbols_impl.cpp M jasm/assembling/assembler_impl/syntax_impl.cpp M jasm/assembling/functions.cpp M jasm/assembling/functions.h M jasm/assembling/instructions_6502.cpp M jasm/assembling/instructions_6502.h A => jasm/assembling/instructions_common.h M jasm/assembling/instructions_z80.cpp M jasm/assembling/instructions_z80.h M jasm/assembling/methods.cpp M jasm/assembling/methods.h M jasm/assembling/symbol_environment.cpp M jasm/assembling/value.cpp M jasm/assembling/value.h M jasm/docs/jasm.md M jasm/docs/syntax_highlight.py M jasm/environment/command_line_args.cpp M jasm/environment/command_line_args.h M jasm/exceptions/assembly_exception.h M jasm/exceptions/error_codes.h M jasm/io/data_reader.cpp M jasm/io/data_reader.h M jasm/jasm.cbp M jasm/jasm.vcxproj M jasm/jasm.vcxproj.filters M jasm/main.cpp M jasm/parsing/keyword_finder.cpp M jasm/parsing/keyword_finder.h M jasm/parsing/keywords.cpp M jasm/parsing/keywords.h M jasm/parsing/operators.cpp M jasm/parsing/operators.h M jasm/parsing/processor_keywords_6502.cpp M jasm/parsing/processor_keywords_6502.h M jasm/parsing/processor_keywords_z80.cpp M jasm/parsing/processor_keywords_z80.h M jasm/parsing/syntax_parser.cpp M jasm/parsing/syntax_parser.h M jasm/parsing/syntax_tokens.cpp M jasm/parsing/syntax_tokens.h M jasm/parsing/token_print.cpp M jasm/parsing/token_print.h M jasm/parsing/tokenizer.cpp M jasm/parsing/tokenizer.h M jasm/parsing/types.cpp M jasm/parsing/types.h M jasm/revision_hash.h M jasm/strings/string_conversions.cpp M jasm/strings/string_conversions.h M jasm/strings/string_hasher.h A => jasm/strings/string_locale.cpp A => jasm/strings/string_locale.h M jasm/strings/string_repository.cpp M jasm/strings/string_repository.h M jasm/unit_tests/results/test_define_array_follows_references.bin A => jasm/unit_tests/results/test_function_logn.bin A => jasm/unit_tests/results/test_function_lowercase_default.bin A => jasm/unit_tests/results/test_function_lowercase_english.bin A => jasm/unit_tests/results/test_function_lowercase_invalid_type.stdout A => jasm/unit_tests/results/test_function_lowercase_swedish.bin A => jasm/unit_tests/results/test_function_uppercase_default.bin A => jasm/unit_tests/results/test_function_uppercase_english.bin A => jasm/unit_tests/results/test_function_uppercase_invalid_type.stdout A => jasm/unit_tests/results/test_function_uppercase_swedish.bin A => jasm/unit_tests/results/test_instruction_data_label_has_lo_hi_properties_6502.bin A => jasm/unit_tests/results/test_instruction_data_label_has_lo_hi_properties_z80.bin A => jasm/unit_tests/results/test_instruction_data_label_offsets_6502.bin A => jasm/unit_tests/results/test_instruction_data_label_sizes_6502.bin A => jasm/unit_tests/results/test_instruction_data_label_sizes_z80.bin A => jasm/unit_tests/results/test_lowercase_too_many_arguments.stdout M jasm/unit_tests/results/test_map_range_for_with_local_loop_variables.bin A => jasm/unit_tests/results/test_offset_word_has_lo_hi_property.bin A => jasm/unit_tests/results/test_pseudo_instructions_16_bit_register_load_z80.bin A => jasm/unit_tests/results/test_pseudo_instructions_for_branching_6502.bin A => jasm/unit_tests/results/test_pseudo_instructions_in_standard_mode_6502.stdout A => jasm/unit_tests/results/test_pseudo_instructions_in_standard_mode_z80.stdout A => jasm/unit_tests/results/test_pseudo_instructions_use_names_in_standard_mode_6502.bin A => jasm/unit_tests/results/test_section_child_exceeds_its_size.stdout A => jasm/unit_tests/results/test_subroutine_call_6502.bin A => jasm/unit_tests/results/test_subroutine_call_must_be_in_code_section_6502.stdout A => jasm/unit_tests/results/test_subroutine_call_must_be_in_code_section_z80.stdout A => jasm/unit_tests/results/test_subroutine_call_negative_argument_6502.stdout A => jasm/unit_tests/results/test_subroutine_call_recursive_data_generation_6502.stdout A => jasm/unit_tests/results/test_subroutine_call_recursive_data_generation_z80.stdout A => jasm/unit_tests/results/test_subroutine_call_too_large_argument_6502.stdout A => jasm/unit_tests/results/test_subroutine_call_too_large_argument_z80.stdout A => jasm/unit_tests/results/test_subroutine_call_with_arguments_6502.stdout A => jasm/unit_tests/results/test_subroutine_call_with_arguments_z80.stdout A => jasm/unit_tests/results/test_subroutine_call_z80.bin A => jasm/unit_tests/results/test_uppercase_too_many_arguments.stdout A => jasm/unit_tests/test_function_logn.asm A => jasm/unit_tests/test_function_lowercase_default.asm A => jasm/unit_tests/test_function_lowercase_english.asm A => jasm/unit_tests/test_function_lowercase_invalid_type.asm A => jasm/unit_tests/test_function_lowercase_swedish.asm A => jasm/unit_tests/test_function_uppercase_default.asm A => jasm/unit_tests/test_function_uppercase_english.asm A => jasm/unit_tests/test_function_uppercase_invalid_type.asm A => jasm/unit_tests/test_function_uppercase_swedish.asm A => jasm/unit_tests/test_instruction_data_label_has_lo_hi_properties_6502.asm A => jasm/unit_tests/test_instruction_data_label_has_lo_hi_properties_z80.asm A => jasm/unit_tests/test_instruction_data_label_offsets_6502.asm A => jasm/unit_tests/test_instruction_data_label_sizes_6502.asm A => jasm/unit_tests/test_instruction_data_label_sizes_z80.asm A => jasm/unit_tests/test_lowercase_too_many_arguments.asm A => jasm/unit_tests/test_offset_word_has_lo_hi_property.asm A => jasm/unit_tests/test_pseudo_instructions_16_bit_register_load_z80.asm A => jasm/unit_tests/test_pseudo_instructions_for_branching_6502.asm A => jasm/unit_tests/test_pseudo_instructions_in_standard_mode_6502.asm A => jasm/unit_tests/test_pseudo_instructions_in_standard_mode_z80.asm A => jasm/unit_tests/test_pseudo_instructions_use_names_in_standard_mode_6502.asm A => jasm/unit_tests/test_section_child_exceeds_its_size.asm A => jasm/unit_tests/test_subroutine_call_6502.asm A => jasm/unit_tests/test_subroutine_call_must_be_in_code_section_6502.asm A => jasm/unit_tests/test_subroutine_call_must_be_in_code_section_z80.asm A => jasm/unit_tests/test_subroutine_call_negative_argument_6502.asm A => jasm/unit_tests/test_subroutine_call_recursive_data_generation_6502.asm A => jasm/unit_tests/test_subroutine_call_recursive_data_generation_z80.asm A => jasm/unit_tests/test_subroutine_call_too_large_argument_6502.asm A => jasm/unit_tests/test_subroutine_call_too_large_argument_z80.asm A => jasm/unit_tests/test_subroutine_call_with_arguments_6502.asm A => jasm/unit_tests/test_subroutine_call_with_arguments_z80.asm A => jasm/unit_tests/test_subroutine_call_z80.asm A => jasm/unit_tests/test_uppercase_too_many_arguments.asm M jasm/version.h M jasm/version.py M jasm/website/site/docs/index.html M jasm/website/site/index.html M release.py M sublime/m6502/jAsm.sublime-syntax M sublime/z80/jAsm.sublime-syntax
M core/core.vcxproj +1 -0
@@ 221,6 221,7 @@ <ClInclude Include="core\io\file_writer.h" /> <ClInclude Include="core\io\text_reader.h" /> <ClInclude Include="core\math\algorithm.h" /> + <ClInclude Include="core\math\sign.h" /> <ClInclude Include="core\ownership\destruct_call.h" /> <ClInclude Include="core\strings\murmur_hash.h" /> <ClInclude Include="core\strings\string_helpers.h" />
M core/core.vcxproj.filters +3 -0
@@ 73,6 73,9 @@ <ClInclude Include="core\math\algorithm.h"> <Filter>math</Filter> </ClInclude> + <ClInclude Include="core\math\sign.h"> + <Filter>math</Filter> + </ClInclude> <ClInclude Include="core\ownership\destruct_call.h"> <Filter>ownership</Filter> </ClInclude>
M core/core/debug/timer.cpp +2 -2
@@ 5,7 5,7 @@ namespace core { -TimerScope::TimerScope(const wchar_t *name) +TimerScope::TimerScope(const char *name) : _name(name) { _start_time = std::chrono::system_clock::now(); @@ 16,7 16,7 @@ TimerScope::~TimerScope() auto now = std::chrono::system_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - _start_time); - debug() << _name << L" took " << duration.count() / 1000.0 << L'\n'; + debug() << _name << " took " << duration.count() / 1000.0 << '\n'; } } // namespace core
M core/core/debug/timer.h +2 -2
@@ 12,11 12,11 @@ class TimerScope { public: /// @param name A pointer to a string to display at the end of the scope. The string will be copied. - explicit TimerScope(const wchar_t *name); + explicit TimerScope(const char *name); ~TimerScope(); private: - std::wstring _name; + std::string _name; std::chrono::time_point<std::chrono::system_clock> _start_time; };
M core/core/environment/log.cpp +10 -10
@@ 8,12 8,12 @@ namespace core namespace { ErrorLevel __error_level = ErrorLevel::Errors; - std::wostream *__null_ostream = nullptr; ///< This is a stream that will get a bad state and not output anything. + std::ostream *__null_ostream = nullptr; ///< This is a stream that will get a bad state and not output anything. } LogScope::LogScope() { - __null_ostream = new std::wostream(nullptr); + __null_ostream = new std::ostream(nullptr); } LogScope::~LogScope() @@ 27,30 27,30 @@ void set_log_level(ErrorLevel level) __error_level = level; } -std::wostream &error() +std::ostream &error() { - return std::wcout; + return std::cout; } -std::wostream &warning() +std::ostream &warning() { if (__error_level < ErrorLevel::Warnings) return *__null_ostream; - return std::wcout; + return std::cout; } -std::wostream &info() +std::ostream &info() { if (__error_level < ErrorLevel::Info) return *__null_ostream; - return std::wcout; + return std::cout; } -std::wostream &debug() +std::ostream &debug() { if (__error_level < ErrorLevel::Debug) return *__null_ostream; - return std::wcout; + return std::cout; } } // namespace core
M core/core/environment/log.h +4 -4
@@ 19,10 19,10 @@ enum class ErrorLevel /// Logging with this level and lower will be printed. void set_log_level(ErrorLevel level); -std::wostream &error(); -std::wostream &warning(); -std::wostream &info(); -std::wostream &debug(); +std::ostream &error(); +std::ostream &warning(); +std::ostream &info(); +std::ostream &debug(); /// Let this live as long as printouts can happen. class LogScope
M core/core/exceptions/exception.h +2 -2
@@ 11,8 11,8 @@ namespace core /// It is more tricky since the std::runtime_error isn't wide string compatible so that can't be the base class. struct Exception { - Exception(const std::wstring &msg) : message(msg) {} - std::wstring message; + Exception(const std::string &msg) : message(msg) {} + std::string message; }; /// @}
M core/core/exceptions/file_exception.h +1 -1
@@ 11,7 11,7 @@ namespace core /// Exception object for file errors. struct FileException : public Exception { - FileException(const std::wstring &msg) : Exception(msg) {} + FileException(const std::string &msg) : Exception(msg) {} }; /// @}
M core/core/io/file_helpers.cpp +14 -14
@@ 6,17 6,17 @@ namespace core { -bool match_include_dir_and_file(const std::wstring &file, const std::vector<std::wstring> &include_dirs, std::wstring &result) +bool match_include_dir_and_file(const std::string &file, const std::vector<std::string> &include_dirs, std::string &result) { - std::vector<wchar_t> temp_string; + std::vector<char> temp_string; for (auto &dir : include_dirs) { temp_string.clear(); // add dir temp_string.insert(temp_string.end(), dir.begin(), dir.end()); // add slash if not already there - if (temp_string.empty() || (temp_string.back() != L'/' && temp_string.back() != L'\\')) - temp_string.push_back(L'/'); + if (temp_string.empty() || (temp_string.back() != '/' && temp_string.back() != '\\')) + temp_string.push_back('/'); // add file temp_string.insert(temp_string.end(), file.begin(), file.end()); @@ 25,32 25,32 @@ bool match_include_dir_and_file(const st temp_string.push_back(0); // check if file exists - if (file_exists(&temp_string[0])) { - result = &temp_string[0]; + if (file_exists(temp_string.data())) { + result = temp_string.data(); return true; } } return false; } -std::wstring base_name(const std::wstring &filename) +std::string base_name(const std::string &filename) { - size_t pos = filename.rfind(L"."); + size_t pos = filename.rfind("."); // early out if no punctual character was found - if (pos == std::wstring::npos) + if (pos == std::string::npos) return filename; return filename.substr(0, pos); } -std::wstring file_extension(const std::wstring &filename) +std::string file_extension(const std::string &filename) { - size_t pos = filename.rfind(L"."); + size_t pos = filename.rfind("."); // early out if no punctual character was found - if (pos == std::wstring::npos) - return std::wstring(); + if (pos == std::string::npos) + return std::string(); - return filename.substr(pos, std::wstring::npos); + return filename.substr(pos, std::string::npos); } } // namespace core
M core/core/io/file_helpers.h +4 -4
@@ 8,17 8,17 @@ namespace core /// Determines if there is an include directory that matches a file part. /// @ return True if a file part matches an include directory. @a path is updated in that case. -bool match_include_dir_and_file(const std::wstring &file, const std::vector<std::wstring> &include_dirs, std::wstring &result); +bool match_include_dir_and_file(const std::string &file, const std::vector<std::string> &include_dirs, std::string &result); /// Check if a file exists. /// @return True if the file exists. -bool file_exists(const wchar_t *file); +bool file_exists(const char *file); /// Returns the filename without extension. -std::wstring base_name(const std::wstring &filename); +std::string base_name(const std::string &filename); /// Returns the file extension including the punctual character. -std::wstring file_extension(const std::wstring &filename); +std::string file_extension(const std::string &filename); /// @}
M core/core/io/file_helpers_linux.cpp +2 -3
@@ 3,7 3,6 @@ #if defined(__linux) || defined(__APPLE__) #include <core/io/file_helpers.h> -#include <core/strings/utf8.h> #include <cstring> #include <sys/stat.h> #include <sys/types.h> @@ 12,11 11,11 @@ namespace core { -bool file_exists(const wchar_t *file) +bool file_exists(const char *file) { struct stat s; memset(&s, 0, sizeof(s)); - int success = stat(convert_wide_to_utf8(file).c_str(), &s); + int success = stat(file, &s); if (success != 0) return false;
M core/core/io/file_helpers_win.cpp +4 -2
@@ 3,13 3,15 @@ #if defined(_WIN32) #include <core/io/file_helpers.h> +#include <core/strings/utf8.h> namespace core { -bool file_exists(const wchar_t *file) +bool file_exists(const char *file) { - DWORD attributes = GetFileAttributesW(file); + std::wstring wide_file = utf8_to_wide(file); + DWORD attributes = GetFileAttributesW(wide_file.c_str()); return (attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY)); }
M core/core/io/file_id.h +1 -1
@@ 17,7 17,7 @@ namespace core /// Get the file id from a path. This can be used to determine if /// two files are the exact same. /// @return False if the file can't be opened. -bool file_id(const std::wstring &file, FileId &id); +bool file_id(const std::string &file, FileId &id); /// @}
M core/core/io/file_id_linux.cpp +2 -3
@@ 3,7 3,6 @@ #if defined(__linux) || defined(__APPLE__) #include <core/io/file_id.h> -#include <core/strings/utf8.h> #include <cstring> #include <sys/stat.h> #include <unistd.h> @@ 11,11 10,11 @@ namespace core { -bool file_id(const std::wstring &file, FileId &id) +bool file_id(const std::string &file, FileId &id) { struct stat s; memset(&s, 0, sizeof(s)); - int success = stat(convert_wide_to_utf8(file).c_str(), &s); + int success = stat(file.c_str(), &s); if (success != 0) return false;
M core/core/io/file_id_win.cpp +3 -2
@@ 3,13 3,14 @@ #if defined(_WIN32) #include <core/io/file_id.h> +#include <core/strings/utf8.h> namespace core { -bool file_id(const std::wstring &file, FileId &id) +bool file_id(const std::string &file, FileId &id) { - HANDLE h = CreateFileW(file.c_str(), 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE h = CreateFileW(utf8_to_wide(file).c_str(), 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) return false; BY_HANDLE_FILE_INFORMATION hfi;
M core/core/io/file_writer.cpp +12 -11
@@ 2,27 2,28 @@ #include <core/exceptions/file_exception.h> #include <core/io/file_writer.h> +#include <core/strings/utf8.h> namespace core { -void FileWriter::open(const std::wstring &filename) +void FileWriter::open(const std::string &filename) { #if defined(_MSC_VER) - _file.open(filename, std::ios::out | std::ios::trunc | std::ios::binary); + std::wstring wide_filename; + try { + wide_filename = convert_utf8_to_wide(filename); + } catch (Exception &e) { + throw FileException("Path cannot be converted to wide byte format: " + filename); + } + _file.open(wide_filename, std::ios::out | std::ios::trunc | std::ios::binary); #elif defined(__GNUC__) - char name_buffer[1024]; - size_t result = wcstombs(name_buffer, filename.c_str(), 1024); - if (result == sizeof(name_buffer)) - throw FileException(L"Too long path: " + filename); - if (result == static_cast<size_t>(-1)) - throw FileException(L"Path cannot be converted to utf8: " + filename); - _file.open(name_buffer, std::ios::out | std::ios::trunc | std::ios::binary); + _file.open(filename, std::ios::out | std::ios::trunc | std::ios::binary); #else #error "Platform not supported" #endif if (!_file.is_open()) - throw FileException(L"Failed to open " + filename); + throw FileException("Failed to open " + filename); } void FileWriter::write(const uint8_t *data, uint32_t size) @@ 32,7 33,7 @@ void FileWriter::write(const uint8_t *da _file.write(reinterpret_cast<const char *>(data), size); if (_file.fail()) - throw FileException(L"Error when writing file"); + throw FileException("Error when writing file"); } } // namespace core
M core/core/io/file_writer.h +1 -1
@@ 11,7 11,7 @@ namespace core { class FileWriter { public: - void open(const std::wstring &filename); + void open(const std::string &filename); void write(const uint8_t *data, uint32_t size); private:
M core/core/io/text_reader.cpp +10 -16
@@ 10,26 10,26 @@ namespace core { -std::string load_char_file(const std::wstring &filename) +std::string load_file(const std::string &filename) { // load the file contents std::ifstream file; // open file and place read offset at end to measure size #if defined(_MSC_VER) - file.open(filename, std::ios::in | std::ios::ate | std::ios::binary); + std::wstring wide_filename; + try { + wide_filename = convert_utf8_to_wide(filename); + } catch (Exception &e) { + throw FileException("Path cannot be converted to wide byte format: " + filename); + } + file.open(wide_filename, std::ios::in | std::ios::ate | std::ios::binary); #elif defined(__GNUC__) - char name_buffer[1024]; - size_t result = wcstombs(name_buffer, filename.c_str(), 1024); - if (result == sizeof(name_buffer)) - throw FileException(L"Too long path: " + filename); - if (result == static_cast<size_t>(-1)) - throw FileException(L"Path cannot be converted to utf8: " + filename); - file.open(name_buffer, std::ios::in | std::ios::ate | std::ios::binary); + file.open(filename, std::ios::in | std::ios::ate | std::ios::binary); #else #error "Platform not supported" #endif if (!file.is_open()) - throw FileException(L"Failed to open " + filename); + throw FileException("Failed to open " + filename); // get file size uint64_t size = static_cast<uint64_t>(file.tellg()); @@ 44,10 44,4 @@ std::string load_char_file(const std::ws return std::string(data.get()); } -std::wstring load_file(const std::wstring &filename) -{ - auto utf8_data = load_char_file(filename); - return convert_utf8_to_wide(utf8_data); -} - } // namespace core
M core/core/io/text_reader.h +2 -2
@@ 6,8 6,8 @@ namespace core /// @addtogroup io /// @{ -/// Read an utf8 encoded file and return the contents as a wide character array. -std::wstring load_file(const std::wstring &filename); +/// Read an utf8 encoded file and return the contents as an utf8 encoded character array. +std::string load_file(const std::string &filename); /// @}
A => core/core/math/sign.h +34 -0
@@ 0,0 1,34 @@ +#pragma once + +#include <assert.h> +#include <limits> +#include <type_traits> + +namespace core +{ + +template<typename T> +typename std::make_signed<T>::type sign_cast(T t) +{ + using to_type = typename std::make_signed<T>::type; + static_assert(!std::is_same<T, to_type>::value, "cast is ineffective and can be removed"); + + // range check + assert(t <= std::numeric_limits<to_type>::max()); + + return static_cast<to_type>(t); +} + +template<typename T> +typename std::make_unsigned<T>::type unsign_cast(T t) +{ + using to_type = typename std::make_unsigned<T>::type; + static_assert(!std::is_same<T, to_type>::value, "cast is ineffective and can be removed"); + + // range check + assert(t >= 0); + + return static_cast<to_type>(t); +} + +}
M core/core/strings/murmur_hash.h +9 -31
@@ 1,5 1,6 @@ #pragma once +#include <cstring> #include <string> namespace core @@ 11,53 12,30 @@ namespace core uint64_t murmur_hash3_x64_64(const void *key, const int len, const uint64_t seed = 0); /// Hash a string with optional seed. -/// @param len Length of string in chars. -inline uint64_t murmur_hash3_string_x64_64(const wchar_t *str, const int len, const uint64_t seed = 0) +inline uint64_t murmur_hash3_string_x64_64(const std::string &str, const uint64_t seed = 0) { - size_t len_size = static_cast<size_t>(len); - static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "unsupported char size"); - - if (sizeof(wchar_t) == 2) { - return murmur_hash3_x64_64(str, static_cast<int>(len_size * sizeof(wchar_t)), seed); - } else if (sizeof(wchar_t) == 4) { - // To make hashes the same between 4 byte char compilers and 2 byte char compilers, - // a two byte variant of the string is constructed on the fly. Not perfect for strings - // with lots of strange characters but enough. - - std::vector<uint16_t> wide_str; - wide_str.resize(len_size + 1); // add one to be sure to be able to get a pointer - for(size_t i = 0; i < len_size; ++i) - wide_str[i] = static_cast<uint16_t>(str[i]); - - return murmur_hash3_x64_64(&wide_str[0], static_cast<int>(len_size * sizeof(uint16_t)), seed); - } + return murmur_hash3_x64_64(str.data(), static_cast<int>(str.size()), seed); } /// Hash a string with optional seed. -inline uint64_t murmur_hash3_string_x64_64(const std::wstring &str, const uint64_t seed = 0) +inline uint64_t murmur_hash3_string_x64_64(const std::string_view &str, const uint64_t seed = 0) { - return murmur_hash3_string_x64_64(str.c_str(), static_cast<int>(str.size()), seed); -} - -/// Hash a string with optional seed. -inline uint64_t murmur_hash3_string_x64_64(const std::wstring_view &str, const uint64_t seed = 0) -{ - return murmur_hash3_string_x64_64(str.data(), static_cast<int>(str.size()), seed); + return murmur_hash3_x64_64(str.data(), static_cast<int>(str.size()), seed); } /// Hash a static string without specifying its size. template<int N> -uint64_t murmur_hash3_string_x64_64(const wchar_t (&str)[N], const uint64_t seed = 0) +uint64_t murmur_hash3_string_x64_64(const char (&str)[N], const uint64_t seed = 0) { - return murmur_hash3_string_x64_64(str, N, seed); + return murmur_hash3_x64_64(str, N, seed); } /// Return the hash constant that was sent in. /// In a debug build, the hash constant is verified against the string. -inline uint64_t hash_constant(uint64_t hash, const wchar_t *str) +inline uint64_t hash_constant(uint64_t hash, const char *str) { MARK_USE(str); - assert(murmur_hash3_string_x64_64(str, static_cast<int>(wcslen(str))) == hash); + assert(murmur_hash3_x64_64(str, static_cast<int>(std::strlen(str))) == hash); return hash; }
M core/core/strings/string_helpers.cpp +3 -3
@@ 6,7 6,7 @@ namespace core { -std::wstring to_hex_string(uint32_t value) +std::string to_hex_string(uint32_t value) { // select length of string int length = 2; @@ 16,8 16,8 @@ std::wstring to_hex_string(uint32_t valu length += 4; // convert number to hex string - std::wstringstream ss; - ss << std::hex << std::setw(length) << std::setfill(L'0') << value; + std::stringstream ss; + ss << std::hex << std::setw(length) << std::setfill('0') << value; return ss.str(); }
M core/core/strings/string_helpers.h +1 -1
@@ 6,7 6,7 @@ namespace core /// @addtogroup strings /// @{ -std::wstring to_hex_string(uint32_t value); +std::string to_hex_string(uint32_t value); /// @}
M core/core/strings/utf8.cpp +427 -65
@@ 2,89 2,451 @@ #include <core/exceptions/exception.h> #include <core/strings/utf8.h> -#if defined(_MSC_VER) - #include <codecvt> -#endif #include <cstring> #include <locale> +#include <sstream> namespace core { -std::string convert_wide_to_utf8(const std::wstring &wide) +std::string wide_to_utf8(std::wstring_view wide) +{ + std::stringstream ss; + for(wchar_t c : wide) { + if (!wide_to_utf8(c, ss)) { + throw Exception("Wide to UTF8 string conversion failed."); + } + } + return ss.str(); +} + +std::wstring utf8_to_wide(std::string_view utf8) { - // early out for empty string because it isn't supported by the conversion code - if (wide.size() == 0) - return std::string(); + std::wstringstream ss; + const char *source = utf8.data(); + size_t source_size = utf8.size(); + wchar_t target; + while(source_size != 0) { + if (!utf8_to_wide(source, source_size, target)) { + throw Exception("UTF8 to wide string conversion failed."); + } + ss.put(target); + } + return ss.str(); +} - #if defined(_MSC_VER) - // this may be faster than the gcc version - test and keep/delete - // setup converter - try { - using convert_type = std::codecvt_utf8<wchar_t>; - std::wstring_convert<convert_type, wchar_t> converter; - std::string converted_str = converter.to_bytes(wide.c_str(), wide.c_str() + wide.size()); - return converted_str; - } catch (std::range_error &) { - throw Exception(L"Wide to utf8 string conversion failed."); +/* +std::u16string wide_to_utf16le(std::u32string_view wide) +{ + u16stringstream ss; + for(char32_t c : wide) { + if (!wide_to_utf16le(c, ss)) { + throw Exception("UTF16 to UTF8 string conversion failed."); + } + } + return ss.str(); +} + +std::u32string utf16le_to_wide(std::u16string_view utf16) +{ + u32stringstream ss; + const char16_t *source = utf16.data(); + size_t source_size = utf16.size(); + char32_t c; + while(source_size != 0) { + if (!utf16le_to_wide(source, source_size, c)) { + throw Exception("UTF16 to wide string conversion failed."); } - #elif defined(__GNUC__) + ss.put(c); + } + return ss.str(); +} + +std::string utf16le_to_utf8(std::u16string_view utf16) +{ + std::stringstream ss; + const char16_t *source = utf16.data(); + size_t source_size = utf16.size(); + char32_t c; + while(source_size != 0) { + if (!utf16le_to_wide(source, source_size, c)) { + throw Exception("UTF16 to UTF8 string conversion failed."); + } + if (!wide_to_utf8(c, ss)) { + throw Exception("UTF16 to UTF8 string conversion failed."); + } + } + return ss.str(); +} - // determine size of converted string in narrow characters - std::mbstate_t state; - memset(&state, 0, sizeof(state)); // there seems to be no other way without warnings - const wchar_t *char_ptr = wide.c_str(); - size_t narrow_chars = std::wcsrtombs(nullptr, &char_ptr, 0, &state); - if (narrow_chars == static_cast<size_t>(-1)) - throw Exception(L"Wide to utf8 string conversion failed."); +std::u16string utf8_to_utf16le(std::string_view utf8) +{ + u16stringstream ss; + const char *source = utf8.data(); + size_t source_size = utf8.size(); + char32_t target; + while(source_size != 0) { + if (!utf8_to_wide(source, source_size, target)) { + throw Exception("UTF8 to UTF16 string conversion failed."); + } + if (!wide_to_utf16le(target, ss)) { + throw Exception("UTF8 to UTF16 string conversion failed."); + } + } + return ss.str(); +} +*/ + +std::wstring utf8_to_wstring(std::string_view utf8) +{ + std::wstringstream ss; + const char *source = utf8.data(); + size_t source_size = utf8.size(); + wchar_t wide; + while(source_size != 0) { + if (!utf8_to_wide(source, source_size, wide)) { + throw Exception("UTF8 to wide string conversion failed."); + } + ss.put(wide); + } + return ss.str(); +} + +std::string wstring_to_utf8(std::wstring_view wide) +{ + std::stringstream ss; + for(wchar_t c : wide) { + if (!wide_to_utf8(c, ss)) { + throw Exception("UTF8 to wide string conversion failed."); + } + } + return ss.str(); +} + - // do the conversion - std::string converted_str(narrow_chars + 1, L'\0'); - char_ptr = wide.c_str(); - std::wcsrtombs(&converted_str[0], &char_ptr, converted_str.size(), &state); - converted_str.pop_back(); +uint8_t utf8_size(const char *ptr) +{ + uint8_t c = static_cast<uint8_t>(*ptr); + if ((c & 0b1000'0000) == 0) { + return 1; + } else if ((c & 0b1110'0000) == 0b1100'0000) { + return 2; + } else if ((c & 0b1111'0000) == 0b1110'0000) { + return 3; + } else if ((c & 0b1111'1000) == 0b1111'0000) { + return 4; + } else { + return 0; + } +} - return converted_str; - #else - #error "Compiler not supported" - #endif +bool step_utf8(const char *&ptr, size_t &size) +{ + uint8_t char_size = utf8_size(ptr); + if (char_size == 0) { + return false; + } + if (char_size > size) { + return false; + } + for(uint8_t i = 1; i < char_size; ++i) { + if ((ptr[i] & 0b1100'0000) != 0b1000'0000) { + return false; + } + } + ptr += char_size; + size -= char_size; + return true; +} + +bool is_utf8(const std::string &utf8) +{ + const char *ptr = utf8.data(); + size_t size = utf8.size(); + while(size != 0) { + if (!step_utf8(ptr, size)) { + return false; + } + } + return true; } -std::wstring convert_utf8_to_wide(const std::string &utf8) +bool utf8_to_wide(const char *&source, size_t &source_size, wchar_t &target) { - // early out for empty string because it isn't supported by the conversion code - if (utf8.size() == 0) - return std::wstring(); + if (source_size == 0) { + return false; + } + uint8_t c = static_cast<uint8_t>(*source); + uint32_t wc; + if ((c & 0b1000'0000) == 0) { + wc = c & 0b0111'1111; + target = static_cast<wchar_t>(wc); + source += 1; + source_size -= 1; + return true; + + } else if ((c & 0b1110'0000) == 0b1100'0000) { + if (source_size < 2) { + return false; + } + uint8_t c2 = static_cast<uint8_t>(source[1]); + if ((c2 & 0b1100'0000) != 0b1000'0000) { + return false; + } + wc = ((c & 0b0001'1111U) << 6) | (c2 & 0b0011'1111U); + target = static_cast<wchar_t>(wc); + source += 2; + source_size -= 2; + return true; + + } else if ((c & 0b1111'0000) == 0b1110'0000) { + if (source_size < 3) { + return false; + } + uint8_t c2 = static_cast<uint8_t>(source[1]); + uint8_t c3 = static_cast<uint8_t>(source[2]); + if ((c2 & 0b1100'0000) != 0b1000'0000) { + return false; + } + if ((c3 & 0b1100'0000) != 0b1000'0000) { + return false; + } + wc = ((c & 0b0000'1111U) << 12) | ((c2 & 0b0011'1111U) << 6) | (c3 & 0b0011'1111U); + target = static_cast<wchar_t>(wc); + source += 3; + source_size -= 3; + return true; + + } else if ((c & 0b1111'1000) == 0b1111'0000) { + if (source_size < 4) { + return false; + } + uint8_t c2 = static_cast<uint8_t>(source[1]); + uint8_t c3 = static_cast<uint8_t>(source[2]); + uint8_t c4 = static_cast<uint8_t>(source[3]); + if ((c2 & 0b1100'0000) != 0b1000'0000) { + return false; + } + if ((c3 & 0b1100'0000) != 0b1000'0000) { + return false; + } + if ((c4 & 0b1100'0000) != 0b1000'0000) { + return false; + } + wc = ((c & 0b0000'0111U) << 18) | ((c2 & 0b0011'1111U) << 12) | ((c3 & 0b0011'1111U) << 6) | (c4 & 0b0011'1111U); + target = static_cast<wchar_t>(wc); + source += 4; + source_size -= 4; + return true; + + } else { + return false; + } +} - #if defined(_MSC_VER) - // this may be faster than the gcc version - test and keep/delete - // setup converter - try { - using convert_type = std::codecvt_utf8<wchar_t>; - std::wstring_convert<convert_type, wchar_t> converter; - std::wstring converted_str = converter.from_bytes(utf8.c_str(), utf8.c_str() + utf8.size()); - return converted_str; - } catch (std::range_error &) { - throw Exception(L"Utf8 to wide string conversion failed. "); +/* +bool utf16le_to_wide(const char16_t *&source, size_t &source_size, char32_t &target) +{ + if (source_size < 1) { + return false; + } + + uint16_t c1 = static_cast<uint16_t>(source[0]); + if ((c1 & 0b1111'1100'0000'0000) == 0b1101'1000'0000'0000) { + // start of multiword + if (source_size < 2) { + return false; + } + uint16_t c2 = static_cast<uint16_t>(source[1]); + if ((c2 & 0b1111'1100'0000'0000) != 0b1101'1100'0000'0000) { + return false; } - #elif defined(__GNUC__) - // determine size of converted string in wide characters - std::mbstate_t state; - memset(&state, 0, sizeof(state)); // there seems to be no other way without warnings - const char *char_ptr = utf8.c_str(); - size_t wide_chars = std::mbsrtowcs(nullptr, &char_ptr, 0, &state); - if (wide_chars == static_cast<size_t>(-1)) - throw Exception(L"Utf8 to wide string conversion failed."); + + target = 0x10000U + (((c2 & 0b0000'0011'1111'1111U) << 10) | (c1 & 0b0000'0011'1111'1111U)); + source += 2; + source_size -= 2; + return true; + + } else if ((c1 & 0b1111'1100'0000'0000) == 0b1101'1100'0000'0000) { + // end of multiword + return false; + + } else { + // single word + target = c1; + source += 1; + source_size -= 1; + return true; + } +} +*/ + +bool wide_to_utf8(wchar_t source, std::stringstream &target) +{ + uint32_t usource = static_cast<uint32_t>(source); + if (usource < (1 << 7)) { + target.put(static_cast<char>(usource)); + return true; + } else if (usource < (1 << 11)) { + target.put(static_cast<char>(0b1100'0000 | ((usource >> 6) & 0b0001'1111))); + target.put(static_cast<char>(0b1000'0000 | (usource & 0b0011'1111))); + return true; + } else if (usource < (1 << 16)) { + target.put(static_cast<char>(0b1110'0000 | ((usource >> 12) & 0b0000'1111))); + target.put(static_cast<char>(0b1000'0000 | ((usource >> 6) & 0b0011'1111))); + target.put(static_cast<char>(0b1000'0000 | (usource & 0b0011'1111))); + return true; + } else if (usource < (1 << 21)) { + target.put(static_cast<char>(0b1111'0000 | ((usource >> 18) & 0b0000'0111))); + target.put(static_cast<char>(0b1000'0000 | ((usource >> 12) & 0b0011'1111))); + target.put(static_cast<char>(0b1000'0000 | ((usource >> 6) & 0b0011'1111))); + target.put(static_cast<char>(0b1000'0000 | (usource & 0b0011'1111))); + return true; + } else { + return false; + } +} + +bool wide_to_utf8(wchar_t source, std::vector<char> &target) +{ + uint32_t usource = static_cast<uint32_t>(source); + if (usource < (1 << 7)) { + target.push_back(static_cast<char>(usource)); + return true; + } else if (usource < (1 << 11)) { + target.push_back(static_cast<char>(0b1100'0000 | ((usource >> 6) & 0b0001'1111))); + target.push_back(static_cast<char>(0b1000'0000 | (usource & 0b0011'1111))); + return true; + } else if (usource < (1 << 16)) { + target.push_back(static_cast<char>(0b1110'0000 | ((usource >> 12) & 0b0000'1111))); + target.push_back(static_cast<char>(0b1000'0000 | ((usource >> 6) & 0b0011'1111))); + target.push_back(static_cast<char>(0b1000'0000 | (usource & 0b0011'1111))); + return true; + } else if (usource < (1 << 21)) { + target.push_back(static_cast<char>(0b1111'0000 | ((usource >> 18) & 0b0000'0111))); + target.push_back(static_cast<char>(0b1000'0000 | ((usource >> 12) & 0b0011'1111))); + target.push_back(static_cast<char>(0b1000'0000 | ((usource >> 6) & 0b0011'1111))); + target.push_back(static_cast<char>(0b1000'0000 | (usource & 0b0011'1111))); + return true; + } else { + return false; + } +} - // do the conversion - std::wstring converted_str(wide_chars + 1, L'\0'); - char_ptr = utf8.c_str(); - std::mbsrtowcs(&converted_str[0], &char_ptr, converted_str.size(), &state); - converted_str.pop_back(); - return converted_str; - #else - #error "Compiler not supported" - #endif +bool wide_to_utf8(wchar_t source, std::string &target) +{ + uint32_t usource = static_cast<uint32_t>(source); + if (usource < (1 << 7)) { + target.push_back(static_cast<char>(usource)); + return true; + } else if (usource < (1 << 11)) { + target.push_back(static_cast<char>(0b1100'0000 | ((usource >> 6) & 0b0001'1111))); + target.push_back(static_cast<char>(0b1000'0000 | (usource & 0b0011'1111))); + return true; + } else if (usource < (1 << 16)) { + target.push_back(static_cast<char>(0b1110'0000 | ((usource >> 12) & 0b0000'1111))); + target.push_back(static_cast<char>(0b1000'0000 | ((usource >> 6) & 0b0011'1111))); + target.push_back(static_cast<char>(0b1000'0000 | (usource & 0b0011'1111))); + return true; + } else if (usource < (1 << 21)) { + target.push_back(static_cast<char>(0b1111'0000 | ((usource >> 18) & 0b0000'0111))); + target.push_back(static_cast<char>(0b1000'0000 | ((usource >> 12) & 0b0011'1111))); + target.push_back(static_cast<char>(0b1000'0000 | ((usource >> 6) & 0b0011'1111))); + target.push_back(static_cast<char>(0b1000'0000 | (usource & 0b0011'1111))); + return true; + } else { + return false; + } +} + +/* +bool wide_to_utf16le(char32_t source, u16stringstream &target) +{ + uint32_t usource = static_cast<uint32_t>(source); + if (usource < 0x10000) { + if ((usource & 0b1111'1000'0000'0000) == 0b1101'1000'0000'0000) { + // invalid code point + return false; + } + target.put(static_cast<char16_t>(usource & 0xffff)); + return true; + } else { + usource -= 0x10000; + target.put(static_cast<char16_t>(0b1101'1000'0000'0000 | ((usource >> 10) & 0b0000'0011'1111'1111))); + target.put(static_cast<char16_t>(0b1101'1100'0000'0000 | (usource & 0b0000'0011'1111'1111))); + return true; + } +} + + +bool wide_to_utf16le(char32_t source, std::vector<char16_t> &target) +{ + uint32_t usource = static_cast<uint32_t>(source); + if (usource < 0x10000) { + if ((usource & 0b1111'1000'0000'0000) == 0b1101'1000'0000'0000) { + // invalid code point + return false; + } + target.push_back(static_cast<char16_t>(usource & 0xffff)); + return true; + } else { + usource -= 0x10000; + target.push_back(static_cast<char16_t>(0b1101'1000'0000'0000 | ((usource >> 10) & 0b0000'0011'1111'1111))); + target.push_back(static_cast<char16_t>(0b1101'1100'0000'0000 | (usource & 0b0000'0011'1111'1111))); + return true; + } +} + + +bool wide_to_utf16le(char32_t source, std::u16string &target) +{ + uint32_t usource = static_cast<uint32_t>(source); + if (usource < 0x10000) { + if ((usource & 0b1111'1000'0000'0000) == 0b1101'1000'0000'0000) { + // invalid code point + return false; + } + target.push_back(static_cast<char16_t>(usource & 0xffff)); + return true; + } else { + usource -= 0x10000; + target.push_back(static_cast<char16_t>(0b1101'1000'0000'0000 | ((usource >> 10) & 0b0000'0011'1111'1111))); + target.push_back(static_cast<char16_t>(0b1101'1100'0000'0000 | (usource & 0b0000'0011'1111'1111))); + return true; + } +} +*/ + +size_t num_utf8_characters(const std::string_view &string) +{ + size_t size = 0; + + const char *ptr = string.data(); + size_t source_size = string.size(); + while(source_size > 0) { + if (!step_utf8(ptr, source_size)) { + break; + } + ++size; + } + + return size; +} + +const char *utf8_offset(const std::string_view &string, size_t n) +{ + const char *ptr = string.data(); + size_t source_size = string.size(); + for(size_t i = 0; i < n; ++i) { + if (!step_utf8(ptr, source_size)) { + return nullptr; + } + } + if (source_size == 0) { + // at exact end of string + return nullptr; + } + return ptr; } } // namespace core
M core/core/strings/utf8.h +37 -2
@@ 6,9 6,44 @@ namespace core /// @addtogroup strings /// @{ -std::string convert_wide_to_utf8(const std::wstring &wide); +std::string wide_to_utf8(std::wstring_view wide); +std::wstring utf8_to_wide(std::string_view utf8); + +/// @return Size of the utf8 character pointed to by @a ptr, or 0 if the character is invalid. +uint8_t utf8_size(const char *ptr); + +/// @param ptr Pointer to utf8 string data. This will be modified to point to next character if the function returns true. +/// @param size Size in bytes of string data. This will be reduced by the size of the character if the function returns true. +/// @return True if there is a valid utf8 character at @a ptr. If size is zero it returns false as well. +bool step_utf8(const char *&ptr, size_t &size); + +/// @return True if the string only has valid utf8 characters. +bool is_utf8(const std::string &utf8); -std::wstring convert_utf8_to_wide(const std::string &utf8); +/// Convert a single multi byte code point to a wide character. +/// @param source Pointer to multibyte character. This will be updated to point to next character if the function returns true. +/// @param source_size Size of source data. This will be updated to size left after stepping past the next character if the function returns true. +/// @return True if successful. +bool utf8_to_wide(const char *&source, size_t &source_size, wchar_t &target); + +/// Write one wide character into an utf8 string stream. +/// @return True if the source character was in the valid range. +bool wide_to_utf8(wchar_t source, std::stringstream &target); + +/// Write one wide character into an utf8 string buffer. +/// @return True if the source character was in the valid range. +bool wide_to_utf8(wchar_t source, std::vector<char> &target); + +/// Write one wide character into an utf8 string. +/// @return True if the source character was in the valid range. +bool wide_to_utf8(wchar_t source, std::string &target); + +/// Counts the number of characters in the utf8 string. Stops at invalid characters. +/// @return Number of valid utf8 characters from the beginning of the string. +size_t num_utf8_characters(const std::string_view &string); + +/// @return A pointer to the n'th utf8 character of @a string, or nullptr if there's no n'th character. +const char *utf8_offset(const std::string_view &string, size_t n); /// @}
M hasher/main.cpp +5 -4
@@ 4,13 4,14 @@ #include <core/strings/utf8.h> #include <iostream> #include <iomanip> +#include <string_view> #if defined(_MSC_VER) - int wmain(int argc, wchar_t *argv[]) + int wmain(int argc, char16_t *argv[]) { std::wcout << std::hex << std::showbase; for (int i = 1; i < argc; ++i) - std::wcout << argv[i] << L":" << core::murmur_hash3_string_x64_64(std::wstring(argv[i])) << L'\n'; + std::wcout << argv[i] << L':' << core::murmur_hash3_string_x64_64(core::wide_to_utf8(argv[i])) << L'\n'; return 0; } @@ 19,10 20,10 @@ { std::cout << std::hex << std::showbase; for (int i = 1; i < argc; ++i) - std::cout << argv[i] << ":" << core::murmur_hash3_string_x64_64(core::convert_utf8_to_wide(argv[i])) << '\n'; + std::cout << argv[i] << ':' << core::murmur_hash3_string_x64_64(std::string_view(argv[i])) << '\n'; return 0; } #else - #error "Platform not supported" + #error "Compiler not supported" #endif
A => jasm-6502/convert_6502_keyword_case.py +106 -0
@@ 0,0 1,106 @@ +# Some old 6502 code is using the screaming syntax and jAsm doesn't accept upper case keywords. +# This script can convert the keywords in all .asm files in a directory to help migrating the +# source code. + +import os +import argparse +import sys +import re + +def convert_file(file): + with open(file, "r") as f: + contents = f.read() + + substitutions = [ + [r"\bADC\b", "adc"], + [r"\bAND\b", "and"], + [r"\bASL\b", "asl"], + [r"\bBCC\b", "bcc"], + [r"\bBCS\b", "bcs"], + [r"\bBEQ\b", "beq"], + [r"\bBIT\b", "bit"], + [r"\bBMI\b", "bmi"], + [r"\bBNE\b", "bne"], + [r"\bBPL\b", "bpl"], + [r"\bBRK\b", "brk"], + [r"\bBVC\b", "bvc"], + [r"\bBVS\b", "bvs"], + [r"\bCLC\b", "clc"], + [r"\bCLD\b", "cld"], + [r"\bCLI\b", "cli"], + [r"\bCLV\b", "clv"], + [r"\bCMP\b", "cmp"], + [r"\bCPX\b", "cpx"], + [r"\bCPY\b", "cpy"], + [r"\bDEC\b", "dec"], + [r"\bDEX\b", "dex"], + [r"\bDEY\b", "dey"], + [r"\bEOR\b", "eor"], + [r"\bINC\b", "inc"], + [r"\bINX\b", "inx"], + [r"\bINY\b", "iny"], + [r"\bJMP\b", "jmp"], + [r"\bJSR\b", "jsr"], + [r"\bLDA\b", "lda"], + [r"\bLDX\b", "ldx"], + [r"\bLDY\b", "ldy"], + [r"\bLSR\b", "lsr"], + [r"\bNOP\b", "nop"], + [r"\bORA\b", "ora"], + [r"\bPHA\b", "pha"], + [r"\bPHP\b", "php"], + [r"\bPLA\b", "pla"], + [r"\bPLP\b", "plp"], + [r"\bROL\b", "rol"], + [r"\bROR\b", "ror"], + [r"\bRTI\b", "rti"], + [r"\bRTS\b", "rts"], + [r"\bSBC\b", "sbc"], + [r"\bSEC\b", "sec"], + [r"\bSED\b", "sed"], + [r"\bSEI\b", "sei"], + [r"\bSTA\b", "sta"], + [r"\bSTX\b", "stx"], + [r"\bSTY\b", "sty"], + [r"\bTAX\b", "tax"], + [r"\bTAY\b", "tay"], + [r"\bTSX\b", "tsx"], + [r"\bTXA\b", "txa"], + [r"\bTXS\b", "txs"], + [r"\bTYA\b", "tya"], + [r"\bA\b", "a"], + [r"\bX\b", "x"], + [r"\bY\b", "y"] + ] + + for subst in substitutions: + contents = re.sub(subst[0], subst[1], contents) + + with open(file, "w") as f: + f.write(contents) + + +def convert_dir(dir): + files = [f for f in os.listdir(dir) if f.endswith(".asm")] + for file in files: + convert_file(os.path.join(dir, file)) + + +def args_parser(): + parser = argparse.ArgumentParser(description="""\ +This tool converts upper case 6502-assembler keywords to lower case for use in jAsm. +The source directory will be scanned for .asm files and all of them will have +upper case keywords replaced by lower case ones.""") + + parser.add_argument('dir', action="store", type=str, help='Directory to convert.') + return parser + +if __name__ == "__main__": + parser = args_parser() + args = parser.parse_args() + try: + convert_dir(args.dir) + except Exception as e: + print(e) + sys.exit(10) +
M jasm/assembling/assembler.cpp +7 -6
@@ 6,19 6,20 @@ namespace jasm { -std::vector<Section> assemble(bool multiple_output_files, bool multi_bank_mode +std::vector<Section> assemble(bool multiple_output_files, bool multi_bank_mode, bool pseudo_instructions , const std::vector<TokenChain> &syntax, StringRepository &strings - , const HashArrayRepository &hash_arrays, const std::vector<std::wstring> &used_files - , const std::vector<std::pair<std::wstring, bool>> &predefined_booleans - , const std::vector<std::pair<std::wstring, int32_t>> &predefined_integers - , const std::vector<std::pair<std::wstring, std::wstring>> &predefined_strings + , const HashArrayRepository &hash_arrays, const std::vector<std::string> &used_files + , const std::vector<std::pair<std::string, bool>> &predefined_booleans + , const std::vector<std::pair<std::string, int32_t>> &predefined_integers + , const std::vector<std::pair<std::string, std::string>> &predefined_strings , DataReader &data_reader, int32_t max_errors - , const std::wstring &symbol_dump_file, const std::wstring &vice_dump_file, const std::wstring &gba_dump_file) + , const std::string &symbol_dump_file, const std::string &vice_dump_file, const std::string &gba_dump_file) { std::vector<Section> output; Assembler assembler( multiple_output_files , multi_bank_mode + , pseudo_instructions , syntax , strings , hash_arrays
M jasm/assembling/assembler.h +6 -6
@@ 16,14 16,14 @@ class HashArrayRepository; /// Assemble the provided syntax chain. /// @return A vector of sections that provides output data. No section is empty and there are only code sections. -std::vector<Section> assemble(bool multiple_output_files, bool multi_bank_mode +std::vector<Section> assemble(bool multiple_output_files, bool multi_bank_mode, bool pseudo_instructions , const std::vector<TokenChain> &syntax, StringRepository &strings - , const HashArrayRepository &hash_arrays, const std::vector<std::wstring> &used_files - , const std::vector<std::pair<std::wstring, bool>> &predefined_booleans - , const std::vector<std::pair<std::wstring, int32_t>> &predefined_integers - , const std::vector<std::pair<std::wstring, std::wstring>> &predefined_strings + , const HashArrayRepository &hash_arrays, const std::vector<std::string> &used_files + , const std::vector<std::pair<std::string, bool>> &predefined_booleans + , const std::vector<std::pair<std::string, int32_t>> &predefined_integers + , const std::vector<std::pair<std::string, std::string>> &predefined_strings , DataReader &data_reader, int32_t max_errors - , const std::wstring &symbol_dump_file, const std::wstring &vice_dump_file, const std::wstring &gba_dump_file); + , const std::string &symbol_dump_file, const std::string &vice_dump_file, const std::string &gba_dump_file); /// @}
M jasm/assembling/assembler_impl/assembler_impl.cpp +164 -149
@@ 16,17 16,18 @@ namespace jasm { using namespace core; -Assembler::Assembler(bool multiple_output_files, bool multi_bank_mode +Assembler::Assembler(bool multiple_output_files, bool multi_bank_mode, bool pseudo_instructions , const std::vector<TokenChain> &syntax, StringRepository &strings - , const HashArrayRepository &hash_arrays, const std::vector<std::wstring> &used_files - , const std::vector<std::pair<std::wstring, bool>> &predefined_booleans - , const std::vector<std::pair<std::wstring, int32_t>> &predefined_integers - , const std::vector<std::pair<std::wstring, std::wstring>> &predefined_strings + , const HashArrayRepository &hash_arrays, const std::vector<std::string> &used_files + , const std::vector<std::pair<std::string, bool>> &predefined_booleans + , const std::vector<std::pair<std::string, int32_t>> &predefined_integers + , const std::vector<std::pair<std::string, std::string>> &predefined_strings , DataReader &data_reader, int32_t max_errors - , const std::wstring &symbol_dump_file, const std::wstring &vice_dump_file, const std::wstring &gba_dump_file + , const std::string &symbol_dump_file, const std::string &vice_dump_file, const std::string &gba_dump_file , std::vector<Section> &output) : _multiple_output_files(multiple_output_files) , _multi_bank_mode(multi_bank_mode) + , _pseudo_instructions(pseudo_instructions) , _input(syntax) , _strings(strings) , _hash_arrays(hash_arrays) @@ 51,7 52,7 @@ Assembler::Assembler(bool multiple_outpu , _static_float_type(0) , _static_string_type(0) , _static_string_reference_type(0) - , _static_range_type(0) + , _static_subroutine_type(0) , _static_value_reference_type(0) , _static_byte_offset_type(0) , _static_word_offset_type(0) @@ 84,9 85,9 @@ Assembler::Assembler(bool multiple_outpu _temp_namespace_list.reserve(64); // add empty string for zero hash because the root namespace has hash 0 - _strings.add(0, L""); + _strings.add(0, ""); - _symbol_names[0] = L""; + _symbol_names[0] = ""; } void Assembler::fill_type_integer_operators(TypeDescription &type) @@ 207,8 208,8 @@ void Assembler::setup_fundamental_types( type.operators[static_cast<uint32_t>(OperatorType::ArrayAccess)] = &Assembler::operator_string_array_access; type.operators[static_cast<uint32_t>(OperatorType::Period)] = &Assembler::operator_string_period; type.num_properties = num_properties; - type.name_hashes[static_cast<uint32_t>(StringProperties::Substring)] = hash_constant(0x548d19a49d349e3fULL, L"substring"); - type.name_hashes[static_cast<uint32_t>(StringProperties::Length)] = hash_constant(0xf81b879ec0702403ULL, L"length"); + type.name_hashes[static_cast<uint32_t>(StringProperties::Substring)] = hash_constant(0x906b1973c53fa0c6ULL, "substring"); + type.name_hashes[static_cast<uint32_t>(StringProperties::Length)] = hash_constant(0xea9dd03ab3c476a3ULL, "length"); _static_string_type = add_type_to_type_map(type, p); } { @@ 226,17 227,18 @@ void Assembler::setup_fundamental_types( type.operators[static_cast<uint32_t>(OperatorType::ArrayAccess)] = &Assembler::operator_string_array_access; type.operators[static_cast<uint32_t>(OperatorType::Period)] = &Assembler::operator_string_period; type.num_properties = num_properties; - type.name_hashes[static_cast<uint32_t>(StringProperties::Substring)] = hash_constant(0x548d19a49d349e3fULL, L"substring"); - type.name_hashes[static_cast<uint32_t>(StringProperties::Length)] = hash_constant(0xf81b879ec0702403ULL, L"length"); + type.name_hashes[static_cast<uint32_t>(StringProperties::Substring)] = hash_constant(0x906b1973c53fa0c6ULL, "substring"); + type.name_hashes[static_cast<uint32_t>(StringProperties::Length)] = hash_constant(0xea9dd03ab3c476a3ULL, "length"); _static_string_reference_type = add_type_to_type_map(type, p); } { TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); - type.type = ValueType::RangeValue; + type.type = ValueType::SubroutineValue; + type.operators[static_cast<uint32_t>(OperatorType::Call)] = &Assembler::operator_subroutine_call; fill_type_integer_operators(type); - _static_range_type = add_type_to_type_map(type, p); + _static_subroutine_type = add_type_to_type_map(type, p); } { TokenReadPosition p = _current_pass.types.position(); @@ 249,11 251,15 @@ void Assembler::setup_fundamental_types( } { TokenReadPosition p = _current_pass.types.position(); - uint32_t num_properties = 0; - TypeDescription &type = reserve_type(num_properties); + uint32_t num_properties = static_cast<uint32_t>(WordOffsetProperties::NumProperties); + TypeDescriptionWithPayload &type = reserve_type(num_properties); type.type = ValueType::WordOffset; type.byte_size = 2; fill_type_integer_operators(type); + type.operators[static_cast<uint32_t>(OperatorType::Period)] = &Assembler::operator_word_offset_period; + type.num_properties = num_properties; + type.name_hashes[static_cast<uint32_t>(WordOffsetProperties::Hi)] = hash_constant(0x5a2467aa43e6df96ULL, "hi"); + type.name_hashes[static_cast<uint32_t>(WordOffsetProperties::Lo)] = hash_constant(0x678034356dc3d49aULL, "lo"); _static_word_offset_type = add_type_to_type_map(type, p); } { @@ 334,14 340,14 @@ void Assembler::setup_fundamental_types( type.operators[static_cast<uint32_t>(OperatorType::Plus)] = &Assembler::operator_list_add; type.operators[static_cast<uint32_t>(OperatorType::AssignmentAdd)] = &Assembler::operator_list_assignment_add; type.num_properties = num_properties; - type.name_hashes[static_cast<uint32_t>(ListProperties::Push)] = hash_constant(0xfa1800cd5dfb79a0ULL, L"push"); - type.name_hashes[static_cast<uint32_t>(ListProperties::Pop)] = hash_constant(0x6016fa8751cfb62ULL, L"pop"); - type.name_hashes[static_cast<uint32_t>(ListProperties::Insert)] = hash_constant(0xf45042595a7b3e99ULL, L"insert"); - type.name_hashes[static_cast<uint32_t>(ListProperties::Erase)] = hash_constant(0xb5d29380f263da2dULL, L"erase"); - type.name_hashes[static_cast<uint32_t>(ListProperties::Keep)] = hash_constant(0x22a89537675c3808ULL, L"keep"); - type.name_hashes[static_cast<uint32_t>(ListProperties::Clear)] = hash_constant(0x30b8b5f2ce0e5d40ULL, L"clear"); - type.name_hashes[static_cast<uint32_t>(ListProperties::Empty)] = hash_constant(0x6fb17151c2e4292dULL, L"empty"); - type.name_hashes[static_cast<uint32_t>(ListProperties::Length)] = hash_constant(0xf81b879ec0702403ULL, L"length"); + type.name_hashes[static_cast<uint32_t>(ListProperties::Push)] = hash_constant(0x7ad30941a5437e06ULL, "push"); + type.name_hashes[static_cast<uint32_t>(ListProperties::Pop)] = hash_constant(0xd1a4d7f17ef16a40ULL, "pop"); + type.name_hashes[static_cast<uint32_t>(ListProperties::Insert)] = hash_constant(0x8c464fe67490a18aULL, "insert"); + type.name_hashes[static_cast<uint32_t>(ListProperties::Erase)] = hash_constant(0xa55568a0a6adcd51ULL, "erase"); + type.name_hashes[static_cast<uint32_t>(ListProperties::Keep)] = hash_constant(0xe994c15f836f30b9ULL, "keep"); + type.name_hashes[static_cast<uint32_t>(ListProperties::Clear)] = hash_constant(0xdb95283bae679a06ULL, "clear"); + type.name_hashes[static_cast<uint32_t>(ListProperties::Empty)] = hash_constant(0x5ed3e28128ac2df7ULL, "empty"); + type.name_hashes[static_cast<uint32_t>(ListProperties::Length)] = hash_constant(0xea9dd03ab3c476a3ULL, "length"); _static_list_type = add_type_to_type_map(type, p); } { @@ 360,13 366,13 @@ void Assembler::setup_fundamental_types( // type.operators[static_cast<uint32_t>(OperatorType::ArrayAccess)] = &Assembler::operator_map_array_access; type.operators[static_cast<uint32_t>(OperatorType::Period)] = &Assembler::operator_map_period; type.num_properties = num_properties; - type.name_hashes[static_cast<uint32_t>(MapProperties::Get)] = hash_constant(0xafcebfcb5d61ddd8ULL, L"get"); - type.name_hashes[static_cast<uint32_t>(MapProperties::Set)] = hash_constant(0xdc8e0b42d29bf687ULL, L"set"); - type.name_hashes[static_cast<uint32_t>(MapProperties::Erase)] = hash_constant(0xb5d29380f263da2dULL, L"erase"); - type.name_hashes[static_cast<uint32_t>(MapProperties::Clear)] = hash_constant(0x30b8b5f2ce0e5d40ULL, L"clear"); - type.name_hashes[static_cast<uint32_t>(MapProperties::Has)] = hash_constant(0x619c8e42eb9ab6d8ULL, L"has"); - type.name_hashes[static_cast<uint32_t>(MapProperties::Empty)] = hash_constant(0x6fb17151c2e4292dULL, L"empty"); - type.name_hashes[static_cast<uint32_t>(MapProperties::Length)] = hash_constant(0xf81b879ec0702403ULL, L"length"); + type.name_hashes[static_cast<uint32_t>(MapProperties::Get)] = hash_constant(0x5c50af7d3aca106dULL, "get"); + type.name_hashes[static_cast<uint32_t>(MapProperties::Set)] = hash_constant(0x81dc8d337b550fb3ULL, "set"); + type.name_hashes[static_cast<uint32_t>(MapProperties::Erase)] = hash_constant(0xa55568a0a6adcd51ULL, "erase"); + type.name_hashes[static_cast<uint32_t>(MapProperties::Clear)] = hash_constant(0xdb95283bae679a06ULL, "clear"); + type.name_hashes[static_cast<uint32_t>(MapProperties::Has)] = hash_constant(0x451fa349ff1558cbULL, "has"); + type.name_hashes[static_cast<uint32_t>(MapProperties::Empty)] = hash_constant(0x5ed3e28128ac2df7ULL, "empty"); + type.name_hashes[static_cast<uint32_t>(MapProperties::Length)] = hash_constant(0xea9dd03ab3c476a3ULL, "length"); _static_map_type = add_type_to_type_map(type, p); } } @@ 398,7 404,7 @@ void Assembler::setup_predefined_constan // add functions for(int i = 0; i < static_cast<int>(FunctionType::NumTypes); ++i) { FunctionType f = static_cast<FunctionType>(i); - const std::wstring_view function_name = to_string(f); + const std::string_view function_name = to_string(f); symbol_hash = murmur_hash3_string_x64_64(function_name); if (!_strings.has(symbol_hash)) _strings.add(symbol_hash, function_name); @@ 407,11 413,11 @@ void Assembler::setup_predefined_constan } // add math constants - const wchar_t *constant_name; + const char *constant_name; { - constant_name = L"PI"; - symbol_hash = hash_constant(0xc4dad59240714e9dULL, constant_name); + constant_name = "PI"; + symbol_hash = hash_constant(0x2748bbcafe4477cbULL, constant_name); if (!_strings.has(symbol_hash)) _strings.add(symbol_hash, constant_name); Value &new_value = create_unique_label(symbol_hash, is_global); @@ 419,8 425,8 @@ void Assembler::setup_predefined_constan } { - constant_name = L"E"; - symbol_hash = hash_constant(0xed4011ab799bcb64ULL, constant_name); + constant_name = "E"; + symbol_hash = hash_constant(0x63836bc0d59ab02eULL, constant_name); if (!_strings.has(symbol_hash)) _strings.add(symbol_hash, constant_name); Value &new_value = create_unique_label(symbol_hash, is_global); @@ 465,38 471,38 @@ void Assembler::setup_predefined_constan // store names of automatic labels explicitly since these will not be used by the user - _strings.add(hash_constant(0x9d60c3eb1644552dULL, L"@loop"), std::wstring(L"@loop")); - _strings.add(hash_constant(0xdaa803af4141d0e8ULL, L"@continue"), std::wstring(L"@continue")); - _strings.add(hash_constant(0x1ded7765ceceebccULL, L"@i"), std::wstring(L"@i")); + _strings.add(hash_constant(0xdb831a5e32f85dcfULL, "@loop"), std::string("@loop")); + _strings.add(hash_constant(0x232e8dde60eefef3ULL, "@continue"), std::string("@continue")); + _strings.add(hash_constant(0x2d8619a103210bb8ULL, "@i"), std::string("@i")); } -void Assembler::report_warning(const SourceLocation &location, AssemblyErrorCodes error_code, const std::wstring &msg) +void Assembler::report_warning(const SourceLocation &location, AssemblyErrorCodes error_code, const std::string &msg) { - warning() << _used_files[location.file_index] << L"(" << location.row << L"," << location.column << L") : Warning " << static_cast<unsigned>(error_code) << L" : " << msg << L'\n'; + warning() << _used_files[location.file_index] << "(" << location.row << "," << location.column << ") : Warning " << static_cast<unsigned>(error_code) << " : " << msg << '\n'; // print previous macro invocation locations backwards from the stack for(auto it = _location_stack.crbegin(); it != _location_stack.crend(); ++it) - warning() << _used_files[it->file_index] << L"(" << it->row << L"," << it->column << L") : Invoked from here\n"; + warning() << _used_files[it->file_index] << "(" << it->row << "," << it->column << ") : Invoked from here\n"; } -void Assembler::report_error(const SourceLocation &location, AssemblyErrorCodes error_code, const std::wstring &msg, bool fatal) +void Assembler::report_error(const SourceLocation &location, AssemblyErrorCodes error_code, const std::string &msg, bool fatal) { // avoid reporting same error/location again if (!fatal && _reported_error_locations.find(location) != _reported_error_locations.end()) return; _reported_error_locations.insert(location); - error() << _used_files[location.file_index] << L"(" << location.row << L"," << location.column << L") : Error " << static_cast<unsigned>(error_code) << L" : " << msg << L'\n'; + error() << _used_files[location.file_index] << "(" << location.row << "," << location.column << ") : Error " << static_cast<unsigned>(error_code) << " : " << msg << '\n'; // print previous macro invocation locations backwards from the stack for(auto it = _location_stack.crbegin(); it != _location_stack.crend(); ++it) - error() << _used_files[it->file_index] << L"(" << it->row << L"," << it->column << L") : Invoked from here\n"; + error() << _used_files[it->file_index] << "(" << it->row << "," << it->column << ") : Invoked from here\n"; ++_num_errors; if (fatal) - throw AssemblyException(L"Fatal error, aborting assembly."); + throw AssemblyException("Fatal error, aborting assembly."); if (_num_errors >= _max_errors) - throw AssemblyException(L"Too many errors, aborting assembly."); + throw AssemblyException("Too many errors, aborting assembly."); } void propagate_data(Section &parent) @@ 543,7 549,7 @@ void Assembler::prepare_next_assembly_pa void Assembler::run_assembly_pass(bool generate, int pass) { - debug() << L"Assemble pass " << pass << L'\n'; + debug() << "Assemble pass " << pass << '\n'; assert(_call_depth == 0); assert(_data_generation_depth == 0); @@ 558,7 564,7 @@ void Assembler::run_assembly_pass(bool g // and these things will not be reset otherwise _symbol_environment.reset(); // set the name of the outermost local scope to avoid unknowns in the symbol dump - _symbol_names[_symbol_environment.local_symbol_scope_stack.back()] = L""; + _symbol_names[_symbol_environment.local_symbol_scope_stack.back()] = ""; // allocated first 8 bytes to be sure that 0 is unused. It may come in handy // as a null pointer. @@ 598,7 604,7 @@ void Assembler::run_assembly_pass(bool g } else { #if 0 // a dump file for each pass to debug if (_dump_symbols) { - dump_symbols(base_name(_symbol_dump_file) + std::to_wstring(pass) + file_extension(_symbol_dump_file)); + dump_symbols(base_name(_symbol_dump_file) + std::to_string(pass) + file_extension(_symbol_dump_file)); } #endif } @@ 653,7 659,7 @@ bool Assembler::progress_was_made() } // TODO: hash variable map - debug() << L"State hash: " << std::hex << storage_hash << std::dec << L'\n'; + debug() << "State hash: " << std::hex << storage_hash << std::dec << '\n'; // if the storage hash has existed before we have ended up in a loop where the state // doesn't make any progress @@ 691,7 697,7 @@ bool Assembler::progress_was_made() struct SymbolInformation { - SymbolInformation(uint64_t hash_, size_t index_, std::wstring name_, std::wstring value_, bool constant_, ValueType type_) + SymbolInformation(uint64_t hash_, size_t index_, std::string name_, std::string value_, bool constant_, ValueType type_) : hash(hash_) , index(index_) , name(std::move(name_)) @@ 701,7 707,7 @@ struct SymbolInformation , type(type_) {} - SymbolInformation(uint64_t hash_, size_t index_, std::wstring name_, std::wstring value_, bool constant_, bool current_pass_, ValueType type_) + SymbolInformation(uint64_t hash_, size_t index_, std::string name_, std::string value_, bool constant_, bool current_pass_, ValueType type_) : hash(hash_) , index(index_) , name(std::move(name_)) @@ 720,14 726,14 @@ struct SymbolInformation uint64_t hash; ///< Combined hash for the symbol. size_t index; ///< Index into variable storage vector. - std::wstring name; ///< Readable symbol name. - std::wstring value; ///< Readable value contents. + std::string name; ///< Readable symbol name. + std::string value; ///< Readable value contents. bool constant; ///< True if constant, otherwise variable. bool current_pass; ///< True if found in current pass. This is only used when comparing variables across passes. ValueType type; ///< Type of the value. }; -void Assembler::create_difference_report(std::wstringstream &ss) +void Assembler::create_difference_report(std::stringstream &ss) { // collect and sort symbol names std::vector<SymbolInformation> symbol_list; @@ 735,13 741,13 @@ void Assembler::create_difference_report // find symbols in either pass core::HashMap<uint64_t, bool, core::NullHashCompare<uint64_t>> used_symbols; - std::wstring no_name = L"<no name>"; + std::string no_name = "<no name>"; for(const auto &pair : _current_pass.value_lookup) { uint64_t hash = pair.first; size_t value_index = pair.second; const Value &value = _current_pass.values[value_index]; auto it = _symbol_names.find(hash); - const std::wstring &symbol_name = it == _symbol_names.end() ? no_name : it->second; + const std::string &symbol_name = it == _symbol_names.end() ? no_name : it->second; symbol_list.emplace_back(hash, value_index, symbol_name, to_string(_strings, value), value.storage_type != StorageType::Variable, value.type); used_symbols[hash] = true; } @@ 751,7 757,7 @@ void Assembler::create_difference_report size_t value_index = pair.second; const Value &value = _previous_pass.values[value_index]; auto it = _symbol_names.find(hash); - const std::wstring &symbol_name = it == _symbol_names.end() ? no_name : it->second; + const std::string &symbol_name = it == _symbol_names.end() ? no_name : it->second; symbol_list.emplace_back(hash, value_index, symbol_name, to_string(_strings, value), value.storage_type != StorageType::Variable, false, value.type); used_symbols[hash] = true; } @@ 771,12 777,12 @@ void Assembler::create_difference_report continue; } else { ss << std::setw(16) << to_string(_strings, previous) << std::setw(0); - ss << L" | "; + ss << " | "; ss << std::setw(16) << symbol.value << std::setw(0); } } else { - ss << std::setw(16) << L"<missing>" << std::setw(0); - ss << L" | "; + ss << std::setw(16) << "<missing>" << std::setw(0); + ss << " | "; ss << std::setw(16) << symbol.value << std::setw(0); } @@ 791,22 797,22 @@ void Assembler::create_difference_report continue; } else { ss << std::setw(16) << symbol.value << std::setw(0); - ss << L" | "; + ss << " | "; ss << std::setw(16) << to_string(_strings, current) << std::setw(0); } } else { ss << std::setw(16) << symbol.value << std::setw(0); - ss << L" | "; - ss << std::setw(16) << L"<missing>" << std::setw(0); + ss << " | "; + ss << std::setw(16) << "<missing>" << std::setw(0); } } - ss << L" | "; - ss << symbol.name << L'\n'; + ss << " | "; + ss << symbol.name << '\n'; } } -void Assembler::dump_symbols(const std::wstring &filename) +void Assembler::dump_symbols(const std::string &filename) { // extract all relevant symbol information std::vector<SymbolInformation> symbol_list; @@ 817,37 823,36 @@ void Assembler::dump_symbols(const std:: size_t value_index = pair.second; const Value &value = _current_pass.values[value_index]; auto it = _symbol_names.find(hash); - symbol_list.emplace_back(hash, value_index, it == _symbol_names.end() ? L"<no name>" : it->second, to_string(_strings, value), value.storage_type != StorageType::Variable, value.type); + symbol_list.emplace_back(hash, value_index, it == _symbol_names.end() ? "<no name>" : it->second, to_string(_strings, value), value.storage_type != StorageType::Variable, value.type); } std::sort(symbol_list.begin(), symbol_list.end()); // generate output in memory // <hash> | variable_index | <var/const> | <type> | <value> | main::CONSTANT - std::wstringstream ss; + std::stringstream ss; for(const auto &symbol : symbol_list) { - ss << L"0x" << std::hex << std::setw(16) << std::setfill(L'0') << symbol.hash << std::setfill(L' ') << std::setw(0) << std::dec; - ss << L" | "; + ss << "0x" << std::hex << std::setw(16) << std::setfill('0') << symbol.hash << std::setfill(' ') << std::setw(0) << std::dec; + ss << " | "; ss << std::setw(5) << symbol.index << std::setw(0); - ss << L" | "; + ss << " | "; if (symbol.constant) - ss << L"constant"; + ss << "constant"; else - ss << L"variable"; - ss << L" | "; + ss << "variable"; + ss << " | "; ss << std::setw(20) << to_string(symbol.type) << std::setw(0); - ss << L" | "; + ss << " | "; ss << std::setw(16) << symbol.value << std::setw(0); - ss << L" | "; - ss << symbol.name << L'\n'; + ss << " | "; + ss << symbol.name << '\n'; } - // convert to utf8 - std::string utf8 = convert_wide_to_utf8(ss.str()); + std::string utf8 = ss.str(); // write to disk FileWriter wr; wr.open(filename); - wr.write(reinterpret_cast<const uint8_t *>(utf8.c_str()), static_cast<uint32_t>(utf8.size())); + wr.write(reinterpret_cast<const uint8_t *>(utf8.data()), static_cast<uint32_t>(utf8.size())); } struct SimpleSymbolInformation @@ 868,7 873,7 @@ struct SimpleSymbolInformation uint32_t addr; ///< Label address. }; -bool starts_with_breakpoint(const std::wstring_view &symbol, const std::wstring &beginning) +bool starts_with_breakpoint(const std::string_view &symbol, const std::string &beginning) { if (symbol.size() < beginning.size()) { return false; @@ 880,7 885,7 @@ bool starts_with_breakpoint(const std::w return true; } -void Assembler::dump_vice_symbols(const std::wstring &filename) +void Assembler::dump_vice_symbols(const std::string &filename) { // extract all relevant symbol information std::vector<SimpleSymbolInformation> symbol_list; @@ 889,9 894,9 @@ void Assembler::dump_vice_symbols(const std::set<uint32_t> w_breakpoints; symbol_list.reserve(_current_pass.value_lookup.size()); - std::wstring breakpoint_begin = L"breakpoint"; - std::wstring r_breakpoint_begin = L"read_breakpoint"; - std::wstring w_breakpoint_begin = L"write_breakpoint"; + std::string breakpoint_begin = "breakpoint"; + std::string r_breakpoint_begin = "read_breakpoint"; + std::string w_breakpoint_begin = "write_breakpoint"; for(const auto &pair : _current_pass.value_lookup) { uint64_t hash = pair.first; @@ 914,9 919,9 @@ void Assembler::dump_vice_symbols(const if (UNLIKELY(!is_integer(value))) continue; - const std::wstring_view name_str = _strings.get(it->second); + const std::string_view name_str = _strings.get(it->second); // skip automatic labels since they may override more interesting names - if (name_str.front() == L'@') + if (name_str.front() == '@') continue; uint32_t integer_value = static_cast<uint32_t>(dereference_integer(value)); @@ 943,16 948,16 @@ void Assembler::dump_vice_symbols(const std::sort(symbol_list.begin(), symbol_list.end()); // generate output in memory - std::wstringstream ss; - ss << std::setfill(L'0') << std::hex; + std::stringstream ss; + ss << std::setfill('0') << std::hex; // generate breakpoint list for(auto value : breakpoints) - ss << L"break exec " << std::setw(4) << value << std::setw(0) << L'\n'; + ss << "break exec " << std::setw(4) << value << std::setw(0) << '\n'; for(auto value : r_breakpoints) - ss << L"break load " << std::setw(4) << value << std::setw(0) << L'\n'; + ss << "break load " << std::setw(4) << value << std::setw(0) << '\n'; for(auto value : w_breakpoints) - ss << L"break store " << std::setw(4) << value << std::setw(0) << L'\n'; + ss << "break store " << std::setw(4) << value << std::setw(0) << '\n'; // generate symbol list std::set<uint32_t> used_values; @@ 965,9 970,9 @@ void Assembler::dump_vice_symbols(const uint64_t name = symbol.name; if (used_names.find(name) != used_names.end()) { // symbol exists, try combining the index in the name - std::wstring name_with_index(_strings.get(name)); + std::string name_with_index(_strings.get(name)); name_with_index.append(1, '_'); - name_with_index.append(std::to_wstring(symbol.index)); + name_with_index.append(std::to_string(symbol.index)); name = murmur_hash3_string_x64_64(name_with_index); // give up if still colliding if (used_names.find(name) != used_names.end()) @@ 978,12 983,11 @@ void Assembler::dump_vice_symbols(const used_values.insert(symbol.addr); used_names.insert(name); - const std::wstring_view name_str = _strings.get(name); - ss << L"al C:" << std::setw(4) << symbol.addr << std::setw(0) << L" ." << name_str << L'\n'; + const std::string_view name_str = _strings.get(name); + ss << "al C:" << std::setw(4) << symbol.addr << std::setw(0) << " ." << name_str << '\n'; } - // convert to utf8 - std::string utf8 = convert_wide_to_utf8(ss.str()); + std::string utf8 = ss.str(); // write to disk FileWriter wr; @@ 991,7 995,7 @@ void Assembler::dump_vice_symbols(const wr.write(reinterpret_cast<const uint8_t *>(utf8.c_str()), static_cast<uint32_t>(utf8.size())); } -void Assembler::dump_gba_symbols(const std::wstring &filename) +void Assembler::dump_gba_symbols(const std::string &filename) { // extract all relevant symbol information std::vector<SimpleSymbolInformation> symbol_list; @@ 1018,9 1022,9 @@ void Assembler::dump_gba_symbols(const s if (UNLIKELY(!is_integer(value))) continue; - const std::wstring_view name_str = _strings.get(it->second); + const std::string_view name_str = _strings.get(it->second); // skip automatic labels since they may override more interesting names - if (name_str.front() == L'@') + if (name_str.front() == '@') continue; uint32_t integer_value = static_cast<uint32_t>(dereference_integer(value)); @@ 1029,8 1033,8 @@ void Assembler::dump_gba_symbols(const s std::sort(symbol_list.begin(), symbol_list.end()); // generate output in memory - std::wstringstream ss; - ss << std::setfill(L'0') << std::hex; + std::stringstream ss; + ss << std::setfill('0') << std::hex; // generate symbol list std::set<uint32_t> used_values; @@ 1043,9 1047,9 @@ void Assembler::dump_gba_symbols(const s uint64_t name = symbol.name; if (used_names.find(name) != used_names.end()) { // symbol exists, try combining the index in the name - std::wstring name_with_index(_strings.get(name)); - name_with_index.append(1, L'_'); - name_with_index.append(std::to_wstring(symbol.index)); + std::string name_with_index(_strings.get(name)); + name_with_index.append(1, '_'); + name_with_index.append(std::to_string(symbol.index)); name = murmur_hash3_string_x64_64(name_with_index); // give up if still colliding if (used_names.find(name) != used_names.end()) @@ 1056,12 1060,11 @@ void Assembler::dump_gba_symbols(const s used_values.insert(symbol.addr); used_names.insert(name); - const std::wstring_view name_str = _strings.get(name); - ss << std::setw(4) << (symbol.addr >> 16) << L":" << (symbol.addr & 0xffff) << std::setw(0) << L" " << name_str << L'\n'; + const std::string_view name_str = _strings.get(name); + ss << std::setw(4) << (symbol.addr >> 16) << ":" << (symbol.addr & 0xffff) << std::setw(0) << " " << name_str << '\n'; } - // convert to utf8 - std::string utf8 = convert_wide_to_utf8(ss.str()); + std::string utf8 = ss.str(); // write to disk FileWriter wr; @@ 1074,15 1077,15 @@ void Assembler::recurse_print_sections(c int32_t length = section.section_type == SectionType::Code ? static_cast<int32_t>(section.generated_data().size()) : section.bss_length; for(int i = 0; i < indent; ++i) { - info() << L" "; + info() << " "; } - info() << std::setfill(L'0'); - info() << L"$" << std::setw(4) << section.start_address << std::setw(0) << L" - "; - info() << L"$" << std::setw(4) << section.start_address + length << std::setw(0); - info() << L" ($" << std::setw(4) << length << std::setw(0) << L") "; - info() << std::setfill(L' '); + info() << std::setfill('0'); + info() << "$" << std::setw(4) << section.start_address << std::setw(0) << " - "; + info() << "$" << std::setw(4) << section.start_address + length << std::setw(0); + info() << " ($" << std::setw(4) << length << std::setw(0) << ") "; + info() << std::setfill(' '); info() << std::setw(4) << to_string(section.section_type) << std::setw(0); - info() << L": " << _strings.get(section.name) << L'\n'; + info() << ": " << _strings.get(section.name) << '\n'; for(const Section &child: section.children) recurse_print_sections(child, indent + 1); @@ 1095,28 1098,40 @@ void Assembler::print_sections() for(const Section §ion : _sections) recurse_print_sections(section, 0); - info() << std::setfill(L' ') << std::dec; + info() << std::setfill(' ') << std::dec; +} + +void Assembler::verify_sections_recursive(const Section §ion) +{ + for(const Section &child : section.children) { + verify_sections_recursive(child); + } + + if (!section.has_end) { + return; + } + + int32_t length; + if (section.section_type == SectionType::Bss) { + length = section.bss_length; + } else { + length = static_cast<int32_t>(section.generated_data().size()); + } + + int32_t section_end = section.start_address + length; + + if (section_end > section.end_address) { + std::stringstream ss; + ss << "Section " << _strings.get(section.name) << " exceeds its max size. Section is " << length << " B and the maximum size is " << section.end_address - section.start_address << " B."; + report_fatal_error(section.source_location, AssemblyErrorCodes::SectionDataOverflow, ss.str()); + } + } void Assembler::verify_sections() { for(const Section §ion : _sections) { - if (!section.has_end) - continue; - - int32_t length; - if (section.section_type == SectionType::Bss) - length = section.bss_length; - else - length = static_cast<int32_t>(section.generated_data().size()); - - int32_t section_end = section.start_address + length; - - if (section_end > section.end_address) { - std::wstringstream ss; - ss << L"Section " << _strings.get(section.name) << L" exceeds its max size. Section is " << length << " B and the maximum size is " << section.end_address - section.start_address << L" B."; - report_fatal_error(section.source_location, AssemblyErrorCodes::SectionDataOverflow, ss.str()); - } + verify_sections_recursive(section); } } @@ 1134,7 1149,7 @@ void Assembler::assemble() int pass = 1; while (true) { - TimerScope timer(L"Assemble pass"); + TimerScope timer("Assemble pass"); prepare_next_assembly_pass(); constexpr bool generate_code = false; run_assembly_pass(generate_code, pass); @@ 1147,26 1162,26 @@ void Assembler::assemble() if (_oscillating_state) { error() << - L"The variable state doesn't stabilize!\n" - L"This may indicate that the source code contains conflicting conditional code.\n" - L"Try disabling the latest changes in conditional blocks or code referring to\n" - L"conditional blocks to see what triggers this condition. Unfortunately it is\n" - L"not possible right now to get detailed information about exactly where the\n" - L"problem is.\n"; + "The variable state doesn't stabilize!\n" + "This may indicate that the source code contains conflicting conditional code.\n" + "Try disabling the latest changes in conditional blocks or code referring to\n" + "conditional blocks to see what triggers this condition. Unfortunately it is\n" + "not possible right now to get detailed information about exactly where the\n" + "problem is.\n"; - std::wstringstream ss; - ss << L"Differing symbols in last two passes:\n"; + std::stringstream ss; + ss << "Differing symbols in last two passes:\n"; create_difference_report(ss); debug() << ss.str(); } { - TimerScope timer(L"Generate pass"); + TimerScope timer("Generate pass"); prepare_next_assembly_pass(); constexpr bool generate_code = true; run_assembly_pass(generate_code, pass); if (_num_errors != 0 || _oscillating_state) - throw AssemblyException(L"Assembly ended with errors."); + throw AssemblyException("Assembly ended with errors."); } std::sort(_sections.begin(), _sections.end());
M jasm/assembling/assembler_impl/assembler_impl.h +66 -52
@@ 14,6 14,7 @@ #include <parsing/syntax_parser.h> #include <set> #include <strings/string_conversions.h> +#include <strings/string_locale.h> #include <strings/string_repository.h> #include <sstream> @@ 45,14 46,14 @@ constexpr uint32_t max_call_depth = 100; class Assembler { public: - Assembler(bool multiple_output_files, bool multi_bank_mode + Assembler(bool multiple_output_files, bool multi_bank_mode, bool pseudo_instructions , const std::vector<TokenChain> &syntax, StringRepository &strings - , const HashArrayRepository &hash_arrays, const std::vector<std::wstring> &used_files - , const std::vector<std::pair<std::wstring, bool>> &predefined_booleans - , const std::vector<std::pair<std::wstring, int32_t>> &predefined_integers - , const std::vector<std::pair<std::wstring, std::wstring>> &predefined_strings + , const HashArrayRepository &hash_arrays, const std::vector<std::string> &used_files + , const std::vector<std::pair<std::string, bool>> &predefined_booleans + , const std::vector<std::pair<std::string, int32_t>> &predefined_integers + , const std::vector<std::pair<std::string, std::string>> &predefined_strings , DataReader &data_reader, int32_t max_errors - , const std::wstring &symbol_dump_file, const std::wstring &vice_dump_file, const std::wstring &gba_dump_file + , const std::string &symbol_dump_file, const std::string &vice_dump_file, const std::string &gba_dump_file , std::vector<Section> &output); Assembler &operator=(const Assembler &other) = delete; @@ 213,7 214,7 @@ private: inline bool is_integer(const Value &value) const { - if (value.type == ValueType::IntegerValue || is_member_of(value.type, value_group_offset) || value.type == ValueType::RangeValue) + if (value.type == ValueType::IntegerValue || is_member_of(value.type, value_group_offset) || value.type == ValueType::SubroutineValue) return true; if (!value.is_value_reference()) @@ 222,7 223,7 @@ private: // value reference type must follow the reference and check its type const Value &referred_value = follow_reference(value); - return referred_value.type == ValueType::IntegerValue || is_member_of(referred_value.type, value_group_offset) || referred_value.type == ValueType::RangeValue; + return referred_value.type == ValueType::IntegerValue || is_member_of(referred_value.type, value_group_offset) || referred_value.type == ValueType::SubroutineValue; } inline bool is_float(const Value &value) const @@ 244,7 245,7 @@ private: if (value.type == ValueType::IntegerValue || is_member_of(value.type, value_group_offset) || value.type == ValueType::FloatValue - || value.type == ValueType::RangeValue) + || value.type == ValueType::SubroutineValue) return true; if (!value.is_value_reference()) @@ 257,7 258,7 @@ private: referred_value.type == ValueType::IntegerValue || is_member_of(referred_value.type, value_group_offset) || referred_value.type == ValueType::FloatValue - || referred_value.type == ValueType::RangeValue; + || referred_value.type == ValueType::SubroutineValue; } inline bool is_string(const Value &value) const @@ 354,7 355,7 @@ private: static uint32_t leftmost_node_in_expression(const ExpressionComponent components[], uint32_t value_index); /// Throw an error telling that the type of expression is wrong or generate an unknown value. - void generate_value_type_error(bool generate, const wchar_t *expected_type, Value &result, const ValueVector &expression_values, const ExpressionComponent components[], uint32_t value_index); + void generate_value_type_error(bool generate, const char *expected_type, Value &result, const ValueVector &expression_values, const ExpressionComponent components[], uint32_t value_index); /// Throw an error telling that a result became infinite or generate an unknown value. void generate_infinite_value_error(bool generate, Value &result, const ExpressionComponent components[], uint32_t value_index); @@ 369,7 370,7 @@ private: double dereference_float(const Value &value) const; /// Return the char pointer value of a string value. The value argument /// must be a string value or reference to an string value. - std::wstring_view dereference_string(const Value &value) const; + std::string_view dereference_string(const Value &value) const; /// Return the string hash of a string value. The value argument /// must be a string value or reference to an string value. uint64_t dereference_string_hash(const Value &value) const; @@ 382,15 383,17 @@ private: void set_integer(Value &result, int32_t value) const; void set_float(Value &result, double value) const; void set_string(Value &result, uint64_t value) const; - void set_string(Value &result, const std::wstring_view &value) const; - void set_string(Value &result, const std::wstring &value) const; - void set_string(Value &result, std::wstring &&value) const; - void set_range(Value &result, int32_t value, int32_t size) const; + void set_string(Value &result, const std::string_view &value) const; + void set_string(Value &result, const std::string &value) const; + void set_string(Value &result, std::string &&value) const; + void set_subroutine(Value &result, int32_t value, int32_t size) const; void set_function(Value &result, FunctionType f) const; void set_method(Value &result, MethodType method, const Value &object) const; void set_list(Value &result) const; void set_list_element_reference(Value &result, StorageType storage_type, const Value &list, int32_t index) const; void set_map(Value &result) const; + void set_byte_offset(Value &result, int32_t offset_base, int32_t offset); + void set_word_offset(Value &result, int32_t offset_base, int32_t offset); /// @} using FloatFunction1 = double (*)(double a); @@ 399,7 402,7 @@ private: using BooleanOperation = bool (*)(bool a, bool b); using IntegerCompareOperation = bool (*)(int32_t a, int32_t b); using FloatCompareOperation = bool (*)(double a, double b); - using StringCompareOperation = bool (*)(const std::wstring_view &a, const std::wstring_view &b); + using StringCompareOperation = bool (*)(const std::string_view &a, const std::string_view &b); /// Get left value, result and the index of the applied property. Returns true if successful or false (with result set to unknown) if it to find the property. bool get_operator_period_property_index(bool generate, const ExpressionComponent components[], Value &result, const Value &arg1, uint32_t next_index, uint32_t &key_index); @@ 445,8 448,8 @@ private: // value is out of range if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, value_index)]; - std::wstringstream ss; - ss << L"Value " << value << L" is outside range for cast. Value must be in range [" << min_range << L", " << max_range << ")."; + std::stringstream ss; + ss << "Value " << value << " is outside range for cast. Value must be in range [" << min_range << ", " << max_range << ")."; report_error(ec.source_location, AssemblyErrorCodes::ValueOutOfRangeForCast, ss.str()); } set_unknown(result); @@ 552,6 555,7 @@ private: void operator_array_offset_access(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, const Value &arg2); void operator_string_array_access(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, const Value &arg2); void operator_list_array_access(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1_ref, Value &arg1, const Value &arg2); + void operator_subroutine_call(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, uint32_t next_index); void operator_function_call(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, uint32_t next_index); void operator_method_closure_call(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, uint32_t next_index); void operator_byte_conversion(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, uint32_t next_index); @@ 564,7 568,8 @@ private: void operator_list_add(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, const Value &arg2); void operator_list_assignment_add(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &ref, Value &arg1, const Value &arg2); void operator_map_period(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, uint32_t next_index); - + void operator_word_offset_period(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, uint32_t next_index); + /// Returns a member function pointer that contains a union of member function pointers. static Function function_pointer(FunctionType type); @@ 584,6 589,7 @@ private: void function_pow(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1, uint32_t arg2); void function_log(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1); void function_log10(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1); + void function_logn(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1, uint32_t arg2); void function_exp(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1); void function_abs(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1); void function_floor(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1); @@ 602,6 608,8 @@ private: void function_string(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1); void function_hexstring(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1); void function_unicode(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1); + void function_uppercase(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1); + void function_lowercase(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1); void function_list(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op); void function_map(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op); void function_static_assert(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1, uint32_t arg2); @@ 623,7 631,6 @@ private: RIGHT, }; - enum class NumberFormat { OFF, @@ 650,15 657,15 @@ private: /// @param format_string A pointer to the character after the initial curly bracket. This will be modified to point after the closing bracket if parsing was successful. /// @param format Will be updated with the parsing information if parsing was successful. /// @return True if the parsing was successful. - bool parse_argument_format(bool generate, const SourceLocation &format_location, std::wstring_view &format_string, ArgFormat &format); + bool parse_argument_format(bool generate, const SourceLocation &format_location, std::string_view &format_string, ArgFormat &format); /// Generate a string based on the specified format. /// @param depth Recursion depth to stop recursion because objects can contain references to themselves. - bool argument_to_string(bool generate, const SourceLocation &format_location, const ArgFormat &format, const Value &arg_value, std::wstringstream &arg_string, uint32_t depth = 0); + bool argument_to_string(bool generate, const SourceLocation &format_location, const ArgFormat &format, const Value &arg_value, std::stringstream &arg_string, uint32_t depth = 0); /// Parse the arguments for the format or print functions. /// @return True if successful and @a result will contain the formatted string. - bool parse_format_arguments(bool generate, const ValueVector &expression_values, const ExpressionComponent components[], uint32_t arg1, std::wstring &result); + bool parse_format_arguments(bool generate, const ValueVector &expression_values, const ExpressionComponent components[], uint32_t arg1, std::string &result); /// @} @@ 714,10 721,10 @@ private: /// @param hash Will be set to the symbol hash, if correctly formatted. /// @param global Will be set according to symbol type, if correctly formatted. /// @return True if the string is correctly formatted. - static bool parse_symbol_string(const std::wstring_view &symbol, uint64_t &hash, bool &global); + bool parse_symbol_string(const std::string_view &symbol, uint64_t &hash, bool &global); /// Store a symbol name in the string repository, taking away the initial '.' on a local symbol before. - void store_symbol_string_in_repository(uint64_t hash, const std::wstring_view &symbol); + void store_symbol_string_in_repository(uint64_t hash, const std::string_view &symbol); /// Store a symbol in the current pass using a prehashed symbol name (with namespace or instance hash). void store_symbol_value(uint64_t symbol_hash, const Value &value, bool global, bool is_address, StorageType type); @@ 907,6 914,10 @@ private: const SyntaxToken *parse_section_map(bool generate, const SyntaxToken *t); const SyntaxToken *parse_declare(bool generate, const SyntaxToken *t); const SyntaxToken *parse_declaration(bool generate, const SyntaxToken *t, bool export_enabled); + #if SUPPORTS(M6502) + void generate_instruction_data_label(bool generate, bool export_enabled, const InstructionToken &token, int address, int offset, uint8_t size); + #endif + void generate_subroutine_instruction(bool generate, int32_t address, const SourceLocation &source_location); const SyntaxToken *parse_instruction(bool generate, const SyntaxToken *t, bool export_enabled); const SyntaxToken *parse_reserve(bool generate, const SyntaxToken *t, bool export_enabled); const SyntaxToken *parse_statement(bool generate, const SyntaxToken *t, bool &early_return); @@ 929,24 940,24 @@ private: const SyntaxToken *parse_incbin(bool generate, const SyntaxToken *t); /// Get the variable name for a global or local variable. - inline std::wstring variable_name(uint64_t symbol_hash, bool global) + inline std::string variable_name(uint64_t symbol_hash, bool global) { if (global) - return std::wstring(_strings.get(symbol_hash)); + return std::string(_strings.get(symbol_hash)); else - return L"." + std::wstring(_strings.get(symbol_hash)); + return "." + std::string(_strings.get(symbol_hash)); } - static inline std::wstring instance_path(const SourceLocation &source_location) + static inline std::string instance_path(const SourceLocation &source_location) { - return std::to_wstring(source_location.file_index) + L"/" - + std::to_wstring(source_location.row) + L"/" - + std::to_wstring(source_location.column); + return std::to_string(source_location.file_index) + "/" + + std::to_string(source_location.row) + "/" + + std::to_string(source_location.column); } /// Combine a name with a parent and store the combined name for lookup using the combined hash. /// This is used to make a reverse lookup table from hash to symbol names for the symbol dump. - void combine_and_store_hash_name(uint64_t parent_hash, uint64_t combined_hash, const std::wstring &child_name); + void combine_and_store_hash_name(uint64_t parent_hash, uint64_t combined_hash, const std::string &child_name); /// Store a relation between a combined name and a symbol name for lookup using the combined hash. /// This is used to find simple symbol names for the VICE symbol dump so only address label symbols @@ 957,22 968,22 @@ private: } /// Log a warning. - void report_warning(const SourceLocation &location, AssemblyErrorCodes error_code, const std::wstring &msg); + void report_warning(const SourceLocation &location, AssemblyErrorCodes error_code, const std::string &msg); /// Log an error and throw an exception if max number of errors have been printed. - void report_error(const SourceLocation &location, AssemblyErrorCodes error_code, const std::wstring &msg) + void report_error(const SourceLocation &location, AssemblyErrorCodes error_code, const std::string &msg) { report_error(location, error_code, msg, false); } /// Log a fatal error and throw an exception immediately. - void report_fatal_error(const SourceLocation &location, AssemblyErrorCodes error_code, const std::wstring &msg) + void report_fatal_error(const SourceLocation &location, AssemblyErrorCodes error_code, const std::string &msg) { report_error(location, error_code, msg, true); } /// Log any type of error. - void report_error(const SourceLocation &location, AssemblyErrorCodes error_code, const std::wstring &msg, bool fatal); + void report_error(const SourceLocation &location, AssemblyErrorCodes error_code, const std::string &msg, bool fatal); /// Create a report of the difference between current and previous pass. - void create_difference_report(std::wstringstream &ss); + void create_difference_report(std::stringstream &ss); /// Move state from current pass to previous pass. void prepare_next_assembly_pass(); @@ 982,11 993,11 @@ private: bool progress_was_made(); /// Dump all symbol information to a file. - void dump_symbols(const std::wstring &filename); + void dump_symbols(const std::string &filename); /// Dump all symbol information to a VICE compatible file. - void dump_vice_symbols(const std::wstring &filename); + void dump_vice_symbols(const std::string &filename); /// Dump all symbol information to a No$GBA compatible file. - void dump_gba_symbols(const std::wstring &filename); + void dump_gba_symbols(const std::string &filename); /// Recursively collect and store the section additional parts sizes for the next assembly pass. void collect_section_sizes(const std::vector<Section> §ions); @@ 1004,6 1015,7 @@ private: void print_sections(); /// Verify section sizes. void verify_sections(); + void verify_sections_recursive(const Section §ion); /// Remove the bss sections to only leave the ones producing output. void cleanup_sections(); @@ 1027,20 1039,22 @@ private: // input data bool _multiple_output_files; ///< When true, write one file per section. Otherwise merge them together. bool _multi_bank_mode; ///< When true, the assembler will truncate addresses in instructions. + bool _pseudo_instructions; ///< When true, some extra instructions or addressing modes can be added to simplify programming. const std::vector<TokenChain> &_input; ///< The syntax token stream to run assemble passes on. StringRepository &_strings; ///< The lookup table from uint64_t to strings. const HashArrayRepository &_hash_arrays; ///< The lookup table from uint64_t handles to uint64_t arrays. - const std::vector<std::wstring> &_used_files; ///< Filenames of assembler files to be able to print them. - const std::vector<std::pair<std::wstring, bool>> &_predefined_booleans; - const std::vector<std::pair<std::wstring, int32_t>> &_predefined_integers; - const std::vector<std::pair<std::wstring, std::wstring>> &_predefined_strings; + const std::vector<std::string> &_used_files; ///< Filenames of assembler files to be able to print them. + const std::vector<std::pair<std::string, bool>> &_predefined_booleans; + const std::vector<std::pair<std::string, int32_t>> &_predefined_integers; + const std::vector<std::pair<std::string, std::string>> &_predefined_strings; DataReader &_data_reader; ///< This handles reading binary files. int32_t _max_errors; ///< Max number of errors before aborting assembly generation pass. - const std::wstring _symbol_dump_file; ///< The filename of the symbol dump. - const std::wstring _vice_dump_file; ///< The filename of the vice symbol dump. - const std::wstring _gba_dump_file; ///< The filename of the No$GBA style symbol dump. + const std::string _symbol_dump_file; ///< The filename of the symbol dump. + const std::string _vice_dump_file; ///< The filename of the vice symbol dump. + const std::string _gba_dump_file; ///< The filename of the No$GBA style symbol dump. bool _dump_symbols; ///< True if symbol dump is enabled. + StringLocale _string_locale; ///< Converts locale names to names to be used in std::locale. StringConversions _string_conversions; ///< Converts strings to platform specific formats. TokenReader _input_reader; ///< Reads the syntax input tokens. @@ 1066,7 1080,7 @@ private: uint64_t _static_float_type; uint64_t _static_string_type; uint64_t _static_string_reference_type; - uint64_t _static_range_type; + uint64_t _static_subroutine_type; uint64_t _static_value_reference_type; uint64_t _static_byte_offset_type; uint64_t _static_word_offset_type; @@ 1092,7 1106,7 @@ private: core::HashMap<uint64_t, int32_t, core::NullHashCompare<uint64_t>> _previous_pass_section_part_size; ///< This stores the extra size added to outer sections (by name hash) by section parts. This is needed to be able to adjust the program counter after each outer section. std::vector<uint64_t> _temp_namespace_list; ///< When combining namespaces with using, this is used temporarily. - std::vector<wchar_t> _temp_string_combine; ///< When combining symbol strings this is used to avoid reallocations. + std::vector<char> _temp_string_combine; ///< When combining symbol strings this is used to avoid reallocations. uint32_t _call_depth; ///< Depth of, for now, macro calls to detect never ending recursion. uint32_t _data_generation_depth; ///< Depth of data generating code. This must never be higher than 1 because it is possible that the assembler breaks down if something generating code calls something that generates code. @@ 1102,7 1116,7 @@ private: std::set<SourceLocation> _reported_error_locations; ///< Keep track of reported error positions to avoid duplicated errors in a loop construction. int32_t _num_errors; ///< Errors encountered in the generation pass so far. - using SymbolNameMap = core::HashMap<uint64_t, std::wstring, core::NullHashCompare<uint64_t>>; + using SymbolNameMap = core::HashMap<uint64_t, std::string, core::NullHashCompare<uint64_t>>; using SymbolHashNameMap = core::HashMap<uint64_t, uint64_t, core::NullHashCompare<uint64_t>>; // map from combined hash to symbol hash SymbolNameMap _symbol_names; ///< Lookup from hash to symbol name in case symbol output is required. SymbolHashNameMap _symbol_hash_names; ///< Lookup from combined hash to symbol hash. This is used to obtain the short name of symbols for the VICE symbol dump.
M jasm/assembling/assembler_impl/expressions_impl.cpp +13 -13
@@ 74,8 74,8 @@ void Assembler::evaluate_operator(bool g if (operator_func.empty()) { if (generate) { // no operator for type is an error in the generation phase - std::wstringstream ss; - ss << L"Operator " << to_string(root.operator_type) << L" is not defined for left hand side " << to_string(left_value->type) << L" type."; + std::stringstream ss; + ss << "Operator " << to_string(root.operator_type) << " is not defined for left hand side " << to_string(left_value->type) << " type."; report_error(root.source_location, AssemblyErrorCodes::OperatorNotSupportingType, ss.str()); } // no operator for type returns an error type in non-generation phases @@ 91,8 91,8 @@ void Assembler::evaluate_operator(bool g bool allowed_to_be_modified = is_mutable(left_ref_value) || left_value->is_module_import(); if (!allowed_to_be_modified) { if (generate) { - std::wstringstream ss; - ss << L"Cannot modify constant value."; + std::stringstream ss; + ss << "Cannot modify constant value."; report_error(root.source_location, AssemblyErrorCodes::CannotModifyConstant, ss.str()); } set_unknown(result); @@ 248,8 248,8 @@ void Assembler::evaluate_expression_with // report later than the expression evaluation because errors occurring on the same line are hiding each other if (!has_side_effect) { - std::wstringstream ss; - ss << L"Expression must have side effect. If this seems confusing, the row before may lack a semicolon to end the statement or expression."; + std::stringstream ss; + ss << "Expression must have side effect. If this seems confusing, the row before may lack a semicolon to end the statement or expression."; report_error(expression_header->source_location, AssemblyErrorCodes::StatementHasNoSideEffect, ss.str()); } } @@ 270,8 270,8 @@ int32_t Assembler::evaluate_integer_expr argument_value = dereference_integer(argument); } else { if (generate) { - std::wstringstream ss; - ss << L"Addressing mode needs an integer value. Argument type was " << to_string(type_of_value(argument)) << L"."; + std::stringstream ss; + ss << "Addressing mode needs an integer value. Argument type was " << to_string(type_of_value(argument)) << "."; report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresIntegerArgument, ss.str()); } } @@ 285,15 285,15 @@ uint32_t Assembler::leftmost_node_in_exp return value_index; } -void Assembler::generate_value_type_error(bool generate, const wchar_t *expected_type, Value &result, const ValueVector &expression_values, const ExpressionComponent components[], uint32_t value_index) +void Assembler::generate_value_type_error(bool generate, const char *expected_type, Value &result, const ValueVector &expression_values, const ExpressionComponent components[], uint32_t value_index) { if (generate) { auto leftmost_index = leftmost_node_in_expression(components, value_index); const ExpressionComponent &ec = components[leftmost_index]; const Value &value = follow_reference_or_value(expression_values[value_index]); - std::wstringstream ss; - ss << L"Expected " << expected_type << " but got " << to_string(value.type) << L"."; + std::stringstream ss; + ss << "Expected " << expected_type << " but got " << to_string(value.type) << "."; report_error(ec.source_location, AssemblyErrorCodes::UnexpectedValueType, ss.str()); } set_unknown(result); @@ 305,8 305,8 @@ void Assembler::generate_infinite_value_ auto leftmost_index = leftmost_node_in_expression(components, value_index); const ExpressionComponent &ec = components[leftmost_index]; - std::wstringstream ss; - ss << L"An infinite value was created."; + std::stringstream ss; + ss << "An infinite value was created."; report_error(ec.source_location, AssemblyErrorCodes::InfiniteValueWasCreated, ss.str()); } set_unknown(result);
M jasm/assembling/assembler_impl/functions_impl.cpp +302 -145
@@ 4,7 4,9 @@ #include <assembling/functions.h> #include <cmath> #include <core/environment/log.h> +#include <core/math/sign.h> #include <core/strings/string_helpers.h> +#include <core/strings/utf8.h> #include <iomanip> #include <ios> @@ 31,6 33,7 @@ Function Assembler::function_pointer(Fun { &Assembler::function_pow }, { &Assembler::function_log }, { &Assembler::function_log10 }, + { &Assembler::function_logn }, { &Assembler::function_exp }, { &Assembler::function_abs }, { &Assembler::function_floor }, @@ 49,6 52,8 @@ Function Assembler::function_pointer(Fun { &Assembler::function_string }, { &Assembler::function_hexstring }, { &Assembler::function_unicode }, + { &Assembler::function_uppercase }, + { &Assembler::function_lowercase }, { &Assembler::function_list }, { &Assembler::function_map }, { &Assembler::function_static_assert }, @@ 67,7 72,7 @@ void Assembler::apply_float_function_wit Value &result = expression_values[op]; const Value &value = follow_reference_or_value(expression_values[arg]); if (!is_numeric(value)) { - generate_value_type_error(generate, L"numeric type", result, expression_values, components, arg); + generate_value_type_error(generate, "numeric type", result, expression_values, components, arg); return; } @@ 84,11 89,11 @@ void Assembler::apply_float_function_wit const Value &value1 = follow_reference_or_value(expression_values[arg1]); const Value &value2 = follow_reference_or_value(expression_values[arg2]); if (!is_numeric(value1)) { - generate_value_type_error(generate, L"numeric type", result, expression_values, components, arg1); + generate_value_type_error(generate, "numeric type", result, expression_values, components, arg1); return; } if (!is_numeric(value2)) { - generate_value_type_error(generate, L"numeric type", result, expression_values, components, arg2); + generate_value_type_error(generate, "numeric type", result, expression_values, components, arg2); return; } @@ 103,13 108,13 @@ void Assembler::function_sizeof(bool gen { Value &result = expression_values[op]; const Value &v1 = follow_reference_or_value(expression_values[arg1]); - bool has_size = is_offset(v1) || v1.type == ValueType::RangeValue; + bool has_size = is_offset(v1) || v1.type == ValueType::SubroutineValue; if (!has_size) { - generate_value_type_error(generate, L"offset or range type", result, expression_values, components, arg1); + generate_value_type_error(generate, "offset or range type", result, expression_values, components, arg1); return; } - if (v1.type == ValueType::RangeValue) { + if (v1.type == ValueType::SubroutineValue) { set_integer(result, v1.range_size); } else { // lookup type and get size @@ 123,7 128,7 @@ void Assembler::function_offsetof(bool g Value &result = expression_values[op]; const Value &v1 = follow_reference_or_value(expression_values[arg1]); if (!is_offset(v1)) { - generate_value_type_error(generate, L"offset type", result, expression_values, components, arg1); + generate_value_type_error(generate, "offset type", result, expression_values, components, arg1); return; } @@ 214,6 219,12 @@ void Assembler::function_log10(bool gene apply_float_function_with_validation(generate, expression_values, components, op, arg1, float_fn); } +void Assembler::function_logn(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1, uint32_t arg2) +{ + auto float_fn = [](double a, double b) { return log(a) / log(b); }; + apply_float_function_with_validation(generate, expression_values, components, op, arg1, arg2, float_fn); +} + void Assembler::function_exp(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1) { auto float_fn = [](double a) { return exp(a); }; @@ 231,7 242,7 @@ void Assembler::function_abs(bool genera double v = dereference_float(value1); set_float(result, v < 0.0 ? -v : v); } else { - generate_value_type_error(generate, L"numeric type", result, expression_values, components, arg1); + generate_value_type_error(generate, "numeric type", result, expression_values, components, arg1); } } @@ 259,11 270,11 @@ void Assembler::apply_integer_module_fun const Value &value1 = follow_reference_or_value(expression_values[arg1]); const Value &value2 = follow_reference_or_value(expression_values[arg2]); if (!is_integer(value1)) { - generate_value_type_error(generate, L"integer type", result, expression_values, components, arg1); + generate_value_type_error(generate, "integer type", result, expression_values, components, arg1); return; } if (!is_integer(value2)) { - generate_value_type_error(generate, L"integer type", result, expression_values, components, arg2); + generate_value_type_error(generate, "integer type", result, expression_values, components, arg2); return; } @@ 273,8 284,8 @@ void Assembler::apply_integer_module_fun if (b == 0) { if (generate) { const ExpressionComponent &operator_component = components[op]; - std::wstringstream ss; - ss << L"Division by zero."; + std::stringstream ss; + ss << "Division by zero."; report_error(operator_component.source_location, AssemblyErrorCodes::DivisionByZero, ss.str()); } // the result is an error @@ 319,7 330,7 @@ void Assembler::aggregate_numeric_args(b Value &result = expression_values[op]; const Value &value1 = follow_reference_or_value(expression_values[arg1]); if (!is_numeric(value1)) { - generate_value_type_error(generate, L"numeric type", result, expression_values, components, arg1); + generate_value_type_error(generate, "numeric type", result, expression_values, components, arg1); return; } @@ 331,7 342,7 @@ void Assembler::aggregate_numeric_args(b while (argument_index != 0) { const Value &value_n = follow_reference_or_value(expression_values[argument_index]); if (!is_numeric(value_n)) { - generate_value_type_error(generate, L"numeric type", result, expression_values, components, argument_index); + generate_value_type_error(generate, "numeric type", result, expression_values, components, argument_index); return; } @@ 366,15 377,15 @@ void Assembler::function_clamp(bool gene const Value &value2 = follow_reference_or_value(expression_values[arg2]); const Value &value3 = follow_reference_or_value(expression_values[arg3]); if (!is_numeric(value1)) { - generate_value_type_error(generate, L"numeric type", result, expression_values, components, arg1); + generate_value_type_error(generate, "numeric type", result, expression_values, components, arg1); return; } if (!is_numeric(value2)) { - generate_value_type_error(generate, L"numeric type", result, expression_values, components, arg2); + generate_value_type_error(generate, "numeric type", result, expression_values, components, arg2); return; } if (!is_numeric(value3)) { - generate_value_type_error(generate, L"numeric type", result, expression_values, components, arg3); + generate_value_type_error(generate, "numeric type", result, expression_values, components, arg3); return; } @@ 401,8 412,8 @@ void Assembler::function_clamp(bool gene // the range is inverted if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg2)]; - std::wstringstream ss; - ss << L"Clamp range is inverted. The smaller number must come first."; + std::stringstream ss; + ss << "Clamp range is inverted. The smaller number must come first."; report_error(ec.source_location, AssemblyErrorCodes::ClampRangeIsInverted, ss.str()); } set_unknown(result); @@ 415,15 426,15 @@ void Assembler::function_lerp(bool gener const Value &value2 = follow_reference_or_value(expression_values[arg2]); const Value &value3 = follow_reference_or_value(expression_values[arg3]); if (!is_numeric(value1)) { - generate_value_type_error(generate, L"numeric type", result, expression_values, components, arg1); + generate_value_type_error(generate, "numeric type", result, expression_values, components, arg1); return; } if (!is_numeric(value2)) { - generate_value_type_error(generate, L"numeric type", result, expression_values, components, arg2); + generate_value_type_error(generate, "numeric type", result, expression_values, components, arg2); return; } if (!is_numeric(value3)) { - generate_value_type_error(generate, L"numeric type", result, expression_values, components, arg3); + generate_value_type_error(generate, "numeric type", result, expression_values, components, arg3); return; } @@ 454,8 465,8 @@ void Assembler::function_int(bool genera if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"Integer cast from " << to_string(value1.type) << L" is not allowed."; + std::stringstream ss; + ss << "Integer cast from " << to_string(value1.type) << " is not allowed."; report_error(ec.source_location, AssemblyErrorCodes::TypeCastNotAllowed, ss.str()); } set_unknown(result); @@ 473,8 484,8 @@ void Assembler::function_float(bool gene if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"Float cast from " << to_string(value1.type) << L" is not allowed."; + std::stringstream ss; + ss << "Float cast from " << to_string(value1.type) << " is not allowed."; report_error(ec.source_location, AssemblyErrorCodes::TypeCastNotAllowed, ss.str()); } set_unknown(result); @@ 487,14 498,14 @@ void Assembler::function_string(bool gen uint32_t arg2_index = components[arg1].next_sibling; // optional argument for string conversion - std::wstring unconverted_result; + std::string unconverted_result; // first convert to a unicode string if (is_integer(value1)) { - unconverted_result = std::to_wstring(dereference_integer(value1)); + unconverted_result = std::to_string(dereference_integer(value1)); } else if (is_float(value1)) { - unconverted_result = std::to_wstring(dereference_float(value1)); + unconverted_result = std::to_string(dereference_float(value1)); } else if (is_string(value1)) { unconverted_result = dereference_string(value1); @@ 502,8 513,8 @@ void Assembler::function_string(bool gen } else { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"String cast from " << to_string(value1.type) << L" is not allowed."; + std::stringstream ss; + ss << "String cast from " << to_string(value1.type) << " is not allowed."; report_error(ec.source_location, AssemblyErrorCodes::TypeCastNotAllowed, ss.str()); } set_unknown(result); @@ 533,33 544,33 @@ void Assembler::function_string(bool gen const Value &conversion_value = follow_reference_or_value(expression_values[current_arg_index]); if (LIKELY(is_string(conversion_value))) { - const std::wstring_view format_string = dereference_string(conversion_value); + const std::string_view format_string = dereference_string(conversion_value); bool duplicate = false; - const wchar_t *duplicate_property = nullptr; + const char *duplicate_property = nullptr; if (_string_conversions.is_format(format_string, this_format)) { format = this_format; duplicate = has_format; - duplicate_property = L"Format"; + duplicate_property = "Format"; has_format = true; } else if (_string_conversions.is_subformat(format_string, this_subformat)) { subformat = this_subformat; duplicate = has_subformat; - duplicate_property = L"Subformat"; + duplicate_property = "Subformat"; has_subformat = true; } else if (_string_conversions.is_locale(format_string, this_locale)) { locale = this_locale; duplicate = has_locale; - duplicate_property = L"Locale"; + duplicate_property = "Locale"; has_locale = true; } else if (_string_conversions.is_flag(format_string, this_flag)) { duplicate = (flags & this_flag) != 0; - duplicate_property = L"Flag"; + duplicate_property = "Flag"; flags = static_cast<StringConversions::Flags>(flags | this_flag); } else { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, current_arg_index)]; - std::wstringstream ss; - ss << L"Invalid string conversion format property '" << format_string << L"'."; + std::stringstream ss; + ss << "Invalid string conversion format property '" << format_string << "'."; report_error(ec.source_location, AssemblyErrorCodes::InvalidStringConversionFormatProperty, ss.str()); } valid_formats = false; @@ 568,8 579,8 @@ void Assembler::function_string(bool gen if (duplicate) { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, current_arg_index)]; - std::wstringstream ss; - ss << duplicate_property << L" property specified twice."; + std::stringstream ss; + ss << duplicate_property << " property specified twice."; report_error(ec.source_location, AssemblyErrorCodes::AmbiguousStringConversionProperty, ss.str()); } valid_formats = false; @@ 578,8 589,8 @@ void Assembler::function_string(bool gen } else { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, current_arg_index)]; - std::wstringstream ss; - ss << L"String conversion format expected but got " << to_string(conversion_value.type) << L"."; + std::stringstream ss; + ss << "String conversion format expected but got " << to_string(conversion_value.type) << "."; report_error(ec.source_location, AssemblyErrorCodes::StringConversionFormatExpected, ss.str()); } valid_formats = false; @@ 592,15 603,15 @@ void Assembler::function_string(bool gen if (valid_formats) { if (_string_conversions.has_conversion(format, subformat, locale)) { size_t error_pos = 0; - std::wstring converted_result; + std::string converted_result; if (_string_conversions.convert(unconverted_result, format, subformat, locale, flags, converted_result, error_pos)) { set_string(result, converted_result); return; } else { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg2_index)]; - std::wstringstream ss; - ss << L"String conversion format failed at position " << error_pos << ". No conversion for character."; + std::stringstream ss; + ss << "String conversion format failed at position " << error_pos << ". No conversion for character."; report_error(ec.source_location, AssemblyErrorCodes::StringConversionFailed, ss.str()); } set_unknown(result); @@ 610,8 621,8 @@ void Assembler::function_string(bool gen } else { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg2_index)]; - std::wstringstream ss; - ss << L"Unsupported string conversion property combination."; + std::stringstream ss; + ss << "Unsupported string conversion property combination."; report_error(ec.source_location, AssemblyErrorCodes::UnknownStringConversionFormatCombination, ss.str()); } set_unknown(result); @@ 638,8 649,8 @@ void Assembler::function_hexstring(bool } else { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"String cast from " << to_string(value1.type) << L" is not allowed."; + std::stringstream ss; + ss << "String cast from " << to_string(value1.type) << " is not allowed."; report_error(ec.source_location, AssemblyErrorCodes::TypeCastNotAllowed, ss.str()); } set_unknown(result); @@ 655,15 666,15 @@ void Assembler::function_unicode(bool ge int value = dereference_integer(value1); if (value >= 0 && value < (1 << 21)) { - std::wstring char_string; - char_string.push_back(static_cast<wchar_t>(value)); + std::string char_string; + core::wide_to_utf8(static_cast<wchar_t>(value), char_string); set_string(result, std::move(char_string)); } else { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"Unicode character " << value << L" is outside valid range [0..2097151]."; + std::stringstream ss; + ss << "Unicode character " << value << " is outside valid range [0..2097151]."; report_error(ec.source_location, AssemblyErrorCodes::TypeCastNotAllowed, ss.str()); } set_unknown(result); @@ 672,14 683,160 @@ void Assembler::function_unicode(bool ge } else { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"String cast from " << to_string(value1.type) << L" is not allowed."; + std::stringstream ss; + ss << "String cast from " << to_string(value1.type) << " is not allowed."; report_error(ec.source_location, AssemblyErrorCodes::TypeCastNotAllowed, ss.str()); } set_unknown(result); } } +void Assembler::function_uppercase(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1) +{ + Value &result = expression_values[op]; + const Value &value1 = follow_reference_or_value(expression_values[arg1]); + + StringLocale::Locale locale_type = StringLocale::Locale::Default; + uint32_t arg2_index = components[arg1].next_sibling; // optional argument for string conversion + if (arg2_index != 0) { + uint32_t arg3_index = components[arg2_index].next_sibling; + if (arg3_index != 0) { + if (generate) { + const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg3_index)]; + std::stringstream ss; + ss << "Too many arguments to function."; + report_error(ec.source_location, AssemblyErrorCodes::TooManyArguments, ss.str()); + } + } + + const Value &value2 = follow_reference_or_value(expression_values[arg2_index]); + if (!is_string(value2)) { + if (generate) { + const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg2_index)]; + std::stringstream ss; + ss << "Function needs string argument but got " << to_string(value2.type) << '.'; + report_error(ec.source_location, AssemblyErrorCodes::ExpectedStringArgument, ss.str()); + } + set_unknown(result); + return; + } + if (!_string_locale.is_locale(dereference_string(value2), locale_type)) { + if (generate) { + const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg2_index)]; + std::stringstream ss; + ss << "String '" << dereference_string(value2) << "' isn't a locale name.\n"; + ss << "Possible values are:\n"; + for(std::string_view name : _string_locale.supported_locales()) { + ss << name << '\n'; + } + report_error(ec.source_location, AssemblyErrorCodes::UnsupportedLocaleName, ss.str()); + } + set_unknown(result); + return; + } + } + + std::locale locale; + if (locale_type != StringLocale::Locale::Default) { + locale = std::locale(std::string(_string_locale.std_locale_name(locale_type))); + } + const std::ctype<wchar_t> &facet(std::use_facet<std::ctype<wchar_t>>(locale)); + + if (is_integer(value1)) { + int value = dereference_integer(value1); + wchar_t uppercase = facet.toupper(static_cast<wchar_t>(value)); + set_integer(result, static_cast<int>(uppercase)); + + } else if (is_string(value1)) { + std::string_view s = dereference_string(value1); + std::wstring wide = core::utf8_to_wide(s); + facet.toupper(wide.data(), wide.data() + wide.size()); + set_string(result, core::wide_to_utf8(wide)); + + } else { + if (generate) { + const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; + std::stringstream ss; + ss << "Expected string or integer but got " << to_string(value1.type) << '.'; + report_error(ec.source_location, AssemblyErrorCodes::IntegerOrStringValueExpected, ss.str()); + } + set_unknown(result); + } +} + +void Assembler::function_lowercase(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op, uint32_t arg1) +{ + Value &result = expression_values[op]; + const Value &value1 = follow_reference_or_value(expression_values[arg1]); + + StringLocale::Locale locale_type = StringLocale::Locale::Default; + uint32_t arg2_index = components[arg1].next_sibling; // optional argument for string conversion + if (arg2_index != 0) { + uint32_t arg3_index = components[arg2_index].next_sibling; + if (arg3_index != 0) { + if (generate) { + const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg3_index)]; + std::stringstream ss; + ss << "Too many arguments to function."; + report_error(ec.source_location, AssemblyErrorCodes::TooManyArguments, ss.str()); + } + } + + const Value &value2 = follow_reference_or_value(expression_values[arg2_index]); + if (!is_string(value2)) { + if (generate) { + const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg2_index)]; + std::stringstream ss; + ss << "Function needs string argument but got " << to_string(value2.type) << '.'; + report_error(ec.source_location, AssemblyErrorCodes::ExpectedStringArgument, ss.str()); + } + set_unknown(result); + return; + } + if (!_string_locale.is_locale(dereference_string(value2), locale_type)) { + if (generate) { + const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg2_index)]; + std::stringstream ss; + ss << "String '" << dereference_string(value2) << "' isn't a locale name.\n"; + ss << "Possible values are:"; + for(std::string_view name : _string_locale.supported_locales()) { + ss << '\n' << name; + } + report_error(ec.source_location, AssemblyErrorCodes::UnsupportedLocaleName, ss.str()); + } + set_unknown(result); + return; + } + } + + std::locale locale; + if (locale_type != StringLocale::Locale::Default) { + locale = std::locale(std::string(_string_locale.std_locale_name(locale_type))); + } + const std::ctype<wchar_t> &facet(std::use_facet<std::ctype<wchar_t>>(locale)); + + if (is_integer(value1)) { + int value = dereference_integer(value1); + wchar_t lowercase = facet.tolower(static_cast<wchar_t>(value)); + set_integer(result, static_cast<int>(lowercase)); + + } else if (is_string(value1)) { + std::string_view s = dereference_string(value1); + std::wstring wide = core::utf8_to_wide(s); + facet.tolower(wide.data(), wide.data() + wide.size()); + set_string(result, core::wide_to_utf8(wide)); + + } else { + if (generate) { + const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; + std::stringstream ss; + ss << "Expected string or integer but got " << to_string(value1.type) << '.'; + report_error(ec.source_location, AssemblyErrorCodes::IntegerOrStringValueExpected, ss.str()); + } + set_unknown(result); + } +} + void Assembler::function_list(bool /*generate*/, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op) { Value &result = expression_values[op]; @@ 706,7 863,7 @@ MapKey Assembler::to_map_key(const Value return MapKey(dereference_boolean(v)); case ValueType::IntegerValue: - case ValueType::RangeValue: + case ValueType::SubroutineValue: case ValueType::ByteOffset: case ValueType::WordOffset: case ValueType::LongOffset: @@ 740,7 897,7 @@ MapKey Assembler::to_map_key(const Value assert(false); return MapKey(static_cast<int>(0)); } - UNREACHABLE_CODE(throw Exception(L"internal error")); + UNREACHABLE_CODE(throw Exception("internal error")); } void Assembler::function_map(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t op) @@ 758,8 915,8 @@ void Assembler::function_map(bool genera const ExpressionComponent &equal_op = components[arg_index]; bool valid_assignment = equal_op.type == ExpressionComponentType::Operator && equal_op.operator_type == OperatorType::Assignment; if (!valid_assignment) { - std::wstringstream ss; - ss << L"Expected assignment operator."; + std::stringstream ss; + ss << "Expected assignment operator."; // fatal error since this is really a parse error and won't be resolved report_fatal_error(equal_op.source_location, AssemblyErrorCodes::MissingKeyAssignmentInMapArgument, ss.str()); } @@ 779,8 936,8 @@ void Assembler::function_map(bool genera if (contents.find(key) != contents.end()) { if (generate) { - std::wstringstream ss; - ss << L"Duplicate map key " << to_string(_strings, key_value) << L" in map function arguments."; + std::stringstream ss; + ss << "Duplicate map key " << to_string(_strings, key_value) << " in map function arguments."; report_error(components[leftmost_node_in_expression(components, key_index)].source_location, AssemblyErrorCodes::DuplicateMapKeys, ss.str()); } } @@ 789,8 946,8 @@ void Assembler::function_map(bool genera } else { if (generate) { - std::wstringstream ss; - ss << L"Unsupported map key type '" << to_string(key_value.type) << L"'."; + std::stringstream ss; + ss << "Unsupported map key type '" << to_string(key_value.type) << "'."; report_error(components[leftmost_node_in_expression(components, key_index)].source_location, AssemblyErrorCodes::UnsupportedMapKeyType, ss.str()); } } @@ 815,15 972,15 @@ void Assembler::function_static_assert(b if (!is_boolean(value1)) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"Function needs boolean expression argument but got " << to_string(value1.type) << L"."; + std::stringstream ss; + ss << "Function needs boolean expression argument but got " << to_string(value1.type) << "."; report_error(ec.source_location, AssemblyErrorCodes::ExpectedBooleanArgument, ss.str()); return; } if (!is_string(value2)) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg2)]; - std::wstringstream ss; - ss << L"Function needs string argument but got " << to_string(value2.type) << L"."; + std::stringstream ss; + ss << "Function needs string argument but got " << to_string(value2.type) << "."; report_error(ec.source_location, AssemblyErrorCodes::ExpectedStringArgument, ss.str()); return; } @@ 833,11 990,11 @@ void Assembler::function_static_assert(b return; // assert failed - const std::wstring_view string = dereference_string(value2); + const std::string_view string = dereference_string(value2); const ExpressionComponent &ec = components[op]; - std::wstringstream ss; - ss << L"Static assert failed: " << string; + std::stringstream ss; + ss << "Static assert failed: " << string; report_error(ec.source_location, AssemblyErrorCodes::StaticAssertFailed, ss.str()); } @@ 846,7 1003,7 @@ void Assembler::function_format(bool gen { Value &result = expression_values[op]; - std::wstring str; + std::string str; if (!parse_format_arguments(generate, expression_values, components, arg1, str)) { set_unknown(result); return; @@ 867,7 1024,7 @@ void Assembler::function_print(bool gene if (!generate) return; - std::wstring str; + std::string str; if (!parse_format_arguments(generate, expression_values, components, arg1, str)) return; @@ 875,22 1032,22 @@ void Assembler::function_print(bool gene }; -bool parse_format_number(std::wstring_view &format_string, int32_t &result) +bool parse_format_number(std::string_view &format_string, int32_t &result) { if (format_string.empty()) { return false; } - wchar_t c = format_string.front(); - if (c < L'0' || c > L'9') + char c = format_string.front(); + if (c < '0' || c > '9') return false; - result = c - L'0'; + result = c - '0'; format_string.remove_prefix(1); while (!format_string.empty()) { c = format_string.front(); - if (c < L'0' || c > L'9') + if (c < '0' || c > '9') break; - result = result * 10 + (c - L'0'); + result = result * 10 + (c - '0'); format_string.remove_prefix(1); } @@ 898,58 1055,58 @@ bool parse_format_number(std::wstring_vi } -bool Assembler::parse_argument_format(bool generate, const SourceLocation &format_location, std::wstring_view &format_string, ArgFormat &format) +bool Assembler::parse_argument_format(bool generate, const SourceLocation &format_location, std::string_view &format_string, ArgFormat &format) { while (!format_string.empty()) { - wchar_t c = format_string.front(); + char c = format_string.front(); format_string.remove_prefix(1); - if (c == L'}') { + if (c == '}') { return true; } - if (c == L'L' || c == L'R') { + if (c == 'L' || c == 'R') { // alignment format if (format.align != ArgFormat::Align::OFF) { // already specified this if (generate) { - std::wstringstream ss; - ss << L"Two alignment format specifiers is not allowed for a single argument."; + std::stringstream ss; + ss << "Two alignment format specifiers is not allowed for a single argument."; report_error(format_location, AssemblyErrorCodes::TwoAlignmentFormatSpecifiers, ss.str()); } return false; } - format.align = (c == L'L' ? ArgFormat::Align::LEFT : ArgFormat::Align::RIGHT); + format.align = (c == 'L' ? ArgFormat::Align::LEFT : ArgFormat::Align::RIGHT); int32_t width = 0; if (!parse_format_number(format_string, width)) { if (generate) { - std::wstringstream ss; - ss << L"Alignment format specifier " << c << L" lacks width."; + std::stringstream ss; + ss << "Alignment format specifier " << c << " lacks width."; report_error(format_location, AssemblyErrorCodes::AlignmentFormatLacksWidth, ss.str()); } return false; } format.align_width = width; - } else if (c == L'D' || c == L'X' || c == L'F') { + } else if (c == 'D' || c == 'X' || c == 'F') { // number format if (format.format != ArgFormat::NumberFormat::OFF) { // already specified this if (generate) { - std::wstringstream ss; - ss << L"Two number format specifiers is not allowed for a single argument."; + std::stringstream ss; + ss << "Two number format specifiers is not allowed for a single argument."; report_error(format_location, AssemblyErrorCodes::TwoNumberFormatSpecifiers, ss.str()); } return false; } - format.format = (c == L'D' ? ArgFormat::NumberFormat::DECIMAL : (c == L'X' ? ArgFormat::NumberFormat::HEX : ArgFormat::NumberFormat::FIXED_POINT)); + format.format = (c == 'D' ? ArgFormat::NumberFormat::DECIMAL : (c == 'X' ? ArgFormat::NumberFormat::HEX : ArgFormat::NumberFormat::FIXED_POINT)); int32_t width = 0; if (!parse_format_number(format_string, width)) { if (generate) { - std::wstringstream ss; - ss << L"Number format specifier " << c << L" lacks width."; + std::stringstream ss; + ss << "Number format specifier " << c << " lacks width."; report_error(format_location, AssemblyErrorCodes::NumberFormatLacksWidth, ss.str()); } return false; @@ 959,49 1116,49 @@ bool Assembler::parse_argument_format(bo } else { // unknown format if (generate) { - std::wstringstream ss; - ss << L"Unsupported format specifier " << c << L"."; + std::stringstream ss; + ss << "Unsupported format specifier " << c << "."; report_error(format_location, AssemblyErrorCodes::UnknownFormatSpecifier, ss.str()); } return false; } } - std::wstringstream ss; - ss << L"Missing closing bracket in format specifier."; + std::stringstream ss; + ss << "Missing closing bracket in format specifier."; report_error(format_location, AssemblyErrorCodes::UnexpectedEndOfFormatSpecifier, ss.str()); return false; } -bool Assembler::argument_to_string(bool generate, const SourceLocation &format_location, const ArgFormat &format, const Value &arg_value, std::wstringstream &arg_string, uint32_t depth) +bool Assembler::argument_to_string(bool generate, const SourceLocation &format_location, const ArgFormat &format, const Value &arg_value, std::stringstream &arg_string, uint32_t depth) { if (format.format == ArgFormat::NumberFormat::HEX) { if (!is_integer(arg_value)) { if (generate) { - std::wstringstream ss; - ss << L"Hex format specified but type is " << to_string(arg_value.type) << L"."; + std::stringstream ss; + ss << "Hex format specified but type is " << to_string(arg_value.type) << "."; report_error(format_location, AssemblyErrorCodes::HexFormatRequiresDecimal, ss.str()); } return false; } - arg_string << std::setfill(L'0') << std::setw(format.number_width) << std::hex << dereference_integer(arg_value) << std::setw(0) << std::dec << std::setfill(L' '); + arg_string << std::setfill('0') << std::setw(format.number_width) << std::hex << dereference_integer(arg_value) << std::setw(0) << std::dec << std::setfill(' '); } else if (format.format == ArgFormat::NumberFormat::DECIMAL) { if (!is_integer(arg_value)) { if (generate) { - std::wstringstream ss; - ss << L"Decimal format specified but type is " << to_string(arg_value.type) << L"."; + std::stringstream ss; + ss << "Decimal format specified but type is " << to_string(arg_value.type) << "."; report_error(format_location, AssemblyErrorCodes::DecFormatRequiresDecimal, ss.str()); } return false; } - arg_string << std::setw(format.number_width) << std::setfill(L'0') << dereference_integer(arg_value) << std::setw(0) << std::setfill(L' '); + arg_string << std::setw(format.number_width) << std::setfill('0') << dereference_integer(arg_value) << std::setw(0) << std::setfill(' '); } else if (format.format == ArgFormat::NumberFormat::FIXED_POINT) { if (!is_numeric(arg_value)) { if (generate) { - std::wstringstream ss; - ss << L"Fixed point format specified but type is " << to_string(arg_value.type) << L"."; + std::stringstream ss; + ss << "Fixed point format specified but type is " << to_string(arg_value.type) << "."; report_error(format_location, AssemblyErrorCodes::FixedPointFormatRequiresFloat, ss.str()); } return false; @@ 1024,22 1181,22 @@ bool Assembler::argument_to_string(bool // cover all other possible cases switch (arg_value.type) { case ValueType::None: - arg_string << L"[none]"; + arg_string << "[none]"; break; case ValueType::Unknown: - arg_string << L"[unknown]"; + arg_string << "[unknown]"; break; case ValueType::BoolValue: - arg_string << (dereference_boolean(arg_value) ? L"true" : L"false"); + arg_string << (dereference_boolean(arg_value) ? "true" : "false"); break; // these should have been handled above case ValueType::IntegerValue: case ValueType::FloatValue: case ValueType::StringValue: - case ValueType::RangeValue: + case ValueType::SubroutineValue: case ValueType::ByteOffset: case ValueType::WordOffset: case ValueType::LongOffset: @@ 1048,42 1205,42 @@ bool Assembler::argument_to_string(bool case ValueType::StringReference: case ValueType::NumTypes: assert(false); - throw Exception(L"internal error"); + throw Exception("internal error"); case ValueType::ByteTypename: case ValueType::WordTypename: case ValueType::LongTypename: case ValueType::StructTypename: - arg_string << L"[typename]"; + arg_string << "[typename]"; break; // static reference types case ValueType::FunctionReference: - arg_string << L"[function]"; + arg_string << "[function]"; break; case ValueType::MacroReference: - arg_string << L"[macro]"; + arg_string << "[macro]"; break; case ValueType::ValueReference: - arg_string << L"[reference]"; + arg_string << "[reference]"; break; case ValueType::EnumReference: - arg_string << L"[enum]"; + arg_string << "[enum]"; break; case ValueType::ObjectReference: - arg_string << L"[object]"; + arg_string << "[object]"; break; case ValueType::ListReference: { // should recurse here - arg_string << L'['; + arg_string << '['; if (depth > 0) { - arg_string << L"..."; + arg_string << "..."; } else { const ArgFormat default_format; bool first = true; @@ 1091,13 1248,13 @@ bool Assembler::argument_to_string(bool if (first) { first = false; } else { - arg_string << L", "; + arg_string << ", "; } if (!argument_to_string(generate, format_location, default_format, element_value, arg_string, depth + 1)) return false; } } - arg_string << L']'; + arg_string << ']'; break; } @@ 1110,50 1267,50 @@ bool Assembler::argument_to_string(bool case ValueType::MapReference: // should recurse here - arg_string << L"[map]"; + arg_string << "[map]"; break; case ValueType::MethodClosure: - arg_string << L"[method closure]"; + arg_string << "[method closure]"; break; } } return true; } -bool Assembler::parse_format_arguments(bool generate, const ValueVector &expression_values, const ExpressionComponent components[], uint32_t arg1, std::wstring &result) +bool Assembler::parse_format_arguments(bool generate, const ValueVector &expression_values, const ExpressionComponent components[], uint32_t arg1, std::string &result) { const Value &value1 = follow_reference_or_value(expression_values[arg1]); if (!is_string(value1)) { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"Function needs string argument but got " << to_string(value1.type) << L"."; + std::stringstream ss; + ss << "Function needs string argument but got " << to_string(value1.type) << "."; report_error(ec.source_location, AssemblyErrorCodes::ExpectedStringArgument, ss.str()); } return false; } - std::wstring_view format_string = dereference_string(value1); + std::string_view format_string = dereference_string(value1); // start generating a new string based on the format and arguments - std::wstringstream result_string; + std::stringstream result_string; uint32_t current_arg = arg1; const ExpressionComponent &arg1_component = components[leftmost_node_in_expression(components, arg1)]; while(!format_string.empty()) { - wchar_t c = format_string.front(); + char c = format_string.front(); format_string.remove_prefix(1); - if (c == L'\\' && !format_string.empty() && format_string.front() == L'{') { + if (c == '\\' && !format_string.empty() && format_string.front() == '{') { // escaped curly bracket - result_string << L'{'; + result_string << '{'; format_string.remove_prefix(1); continue; } - if (c == L'{') { + if (c == '{') { // insert an argument current_arg = components[current_arg].next_sibling; @@ 1161,8 1318,8 @@ bool Assembler::parse_format_arguments(b // too few arguments if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"Number of arguments in the format string and the number of arguments following it doesn't match. Too few arguments follow."; + std::stringstream ss; + ss << "Number of arguments in the format string and the number of arguments following it doesn't match. Too few arguments follow."; report_error(ec.source_location, AssemblyErrorCodes::TooManyFormatArguments, ss.str()); } return false; @@ 1175,7 1332,7 @@ bool Assembler::parse_format_arguments(b // generate the actual string data const Value &arg_value = follow_reference_or_value(expression_values[current_arg]); - std::wstringstream arg_string; + std::stringstream arg_string; if (!argument_to_string(generate, arg1_component.source_location, format, arg_value, arg_string)) return false; @@ 1207,8 1364,8 @@ bool Assembler::parse_format_arguments(b // leftover arguments if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"Number of arguments in the format string and the number of arguments following it doesn't match. Too many arguments follow."; + std::stringstream ss; + ss << "Number of arguments in the format string and the number of arguments following it doesn't match. Too many arguments follow."; report_error(ec.source_location, AssemblyErrorCodes::TooFewFormatArguments, ss.str()); } } @@ 1225,8 1382,8 @@ void Assembler::function_symbol(bool gen if (!is_string(value1)) { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"Symbol name must be a string, but got " << to_string(value1.type) << L"."; + std::stringstream ss; + ss << "Symbol name must be a string, but got " << to_string(value1.type) << "."; report_error(ec.source_location, AssemblyErrorCodes::SymbolExpressionMustBeString, ss.str()); } set_unknown(result); @@ 1236,12 1393,12 @@ void Assembler::function_symbol(bool gen // validate string contents uint64_t hash; bool global; - const std::wstring_view symbol_string = dereference_string(value1); + const std::string_view symbol_string = dereference_string(value1); if (!parse_symbol_string(symbol_string, hash, global)) { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"Dynamic symbol name '" << symbol_string << L"' has an invalid format. It must begin with a letter or underscore and be followed by any number of letters, digits or underscores."; + std::stringstream ss; + ss << "Dynamic symbol name '" << symbol_string << "' has an invalid format. It must begin with a letter or underscore and be followed by any number of letters, digits or underscores."; report_error(ec.source_location, AssemblyErrorCodes::SymbolStringHasInvalidFormat, ss.str()); } set_unknown(result); @@ 1276,8 1433,8 @@ void Assembler::function_select(bool gen if (!is_boolean(expr_value)) { if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg1)]; - std::wstringstream ss; - ss << L"Function needs boolean expression argument but got " << to_string(expr_value.type) << L"."; + std::stringstream ss; + ss << "Function needs boolean expression argument but got " << to_string(expr_value.type) << "."; report_error(ec.source_location, AssemblyErrorCodes::ExpectedBooleanArgument, ss.str()); } set_unknown(result);
M jasm/assembling/assembler_impl/methods_impl.cpp +47 -25
@@ 2,6 2,8 @@ #include <assembling/assembler_impl/assembler_impl.h> #include <assembling/methods.h> +#include <core/math/sign.h> +#include <core/strings/utf8.h> namespace jasm { @@ 32,23 34,43 @@ void Assembler::method_string_substring( const Value &value1 = follow_reference_or_value(expression_values[arg1]); const Value &value2 = follow_reference_or_value(expression_values[arg2]); if (!is_integer(value1)) { - generate_value_type_error(generate, L"integer type", result, expression_values, components, arg1); + generate_value_type_error(generate, "integer type", result, expression_values, components, arg1); return; } if (!is_integer(value2)) { - generate_value_type_error(generate, L"integer type", result, expression_values, components, arg2); + generate_value_type_error(generate, "integer type", result, expression_values, components, arg2); return; } - const std::wstring_view source_str = dereference_string(object); + const std::string_view source_str = dereference_string(object); + + // clamp beginning offset + int32_t begin = dereference_integer(value1); + int32_t size = dereference_integer(value2); + + if (begin < 0) { + size += begin; // reduce size as much as is outside the range + begin = 0; + } + if (size <= 0) { + set_string(result, std::string_view()); + return; + } - // detect start/end - core::Range<int32_t> range; - range.low = dereference_integer(value1); - range.high = range.low + dereference_integer(value2); - range = clamp_range_by_value(range, core::Range<int32_t>{0, static_cast<int32_t>(source_str.size())}); + const char *begin_ptr = core::utf8_offset(source_str, core::unsign_cast(begin)); + if (begin_ptr == nullptr) { + // since we clamped before, start must be beyond end of string + set_string(result, std::string_view()); + return; + } - set_string(result, source_str.substr(static_cast<size_t>(range.low), static_cast<size_t>(range.size()))); + const char *end_ptr = core::utf8_offset(std::string_view(begin_ptr, core::unsign_cast(std::end(source_str) - begin_ptr)), core::unsign_cast(size)); + if (end_ptr == nullptr) { + // include everything up to the end + set_string(result, std::string_view(begin_ptr, core::unsign_cast(std::end(source_str) - begin_ptr))); + } else { + set_string(result, std::string_view(begin_ptr, core::unsign_cast(end_ptr-begin_ptr))); + } } void Assembler::method_list_push(bool /*generate*/, Value &object, ValueVector &expression_values, const ExpressionComponent /*components*/[], uint32_t op, uint32_t arg1) @@ 75,8 97,8 @@ void Assembler::method_list_pop(bool gen if (list_contents.empty()) { if (generate) { - std::wstringstream ss; - ss << L"Cannot pop from empty list."; + std::stringstream ss; + ss << "Cannot pop from empty list."; report_error(components[op].source_location, AssemblyErrorCodes::CannotPopFromEmptyList, ss.str()); } set_unknown(result); @@ 125,8 147,8 @@ bool Assembler::get_range_arguments(bool uint32_t arg3 = components[arg2].next_sibling; if (arg3 != 0) { if (generate) { - std::wstringstream ss; - ss << L"Too many method arguments."; + std::stringstream ss; + ss << "Too many method arguments."; report_error(components[arg3].source_location, AssemblyErrorCodes::TooManyMethodArguments, ss.str()); } return false; @@ 216,8 238,8 @@ void Assembler::method_map_get(bool gene if (!is_valid_key(arg1_value)) { if (generate) { - std::wstringstream ss; - ss << L"Unsupported map key type " << to_string(arg1_value.type) << L"."; + std::stringstream ss; + ss << "Unsupported map key type " << to_string(arg1_value.type) << "."; report_error(components[leftmost_node_in_expression(components, arg1)].source_location, AssemblyErrorCodes::UnsupportedMapKeyType, ss.str()); } set_unknown(result); @@ 229,8 251,8 @@ void Assembler::method_map_get(bool gene auto it = source_map.value->find(key); if (it == source_map.value->end()) { if (generate) { - std::wstringstream ss; - ss << L"Access to missing key " << to_string(_strings, arg1_value) << L" in map."; + std::stringstream ss; + ss << "Access to missing key " << to_string(_strings, arg1_value) << " in map."; report_error(components[leftmost_node_in_expression(components, arg1)].source_location, AssemblyErrorCodes::AccessToMissingMapKey, ss.str()); } set_unknown(result); @@ 250,8 272,8 @@ void Assembler::method_map_set(bool gene if (!is_valid_key(arg1_value)) { if (generate) { - std::wstringstream ss; - ss << L"Unsupported map key type " << to_string(arg1_value.type) << L"."; + std::stringstream ss; + ss << "Unsupported map key type " << to_string(arg1_value.type) << "."; report_error(components[leftmost_node_in_expression(components, arg1)].source_location, AssemblyErrorCodes::UnsupportedMapKeyType, ss.str()); } return; @@ 276,8 298,8 @@ void Assembler::method_map_erase(bool ge if (!is_valid_key(arg1_value)) { if (generate) { - std::wstringstream ss; - ss << L"Unsupported map key type " << to_string(arg1_value.type) << L"."; + std::stringstream ss; + ss << "Unsupported map key type " << to_string(arg1_value.type) << "."; report_error(components[leftmost_node_in_expression(components, arg1)].source_location, AssemblyErrorCodes::UnsupportedMapKeyType, ss.str()); } return; @@ 291,8 313,8 @@ void Assembler::method_map_erase(bool ge auto it = map_contents.find(key); if (it == map_contents.end()) { if (generate) { - std::wstringstream ss; - ss << L"Access to missing map key " << to_string(_strings, arg1_value) << L"."; + std::stringstream ss; + ss << "Access to missing map key " << to_string(_strings, arg1_value) << "."; report_error(components[leftmost_node_in_expression(components, arg1)].source_location, AssemblyErrorCodes::AccessToMissingMapKey, ss.str()); } return; @@ 320,8 342,8 @@ void Assembler::method_map_has(bool gene if (!is_valid_key(arg1_value)) { if (generate) { - std::wstringstream ss; - ss << L"Unsupported map key type " << to_string(arg1_value.type) << L"."; + std::stringstream ss; + ss << "Unsupported map key type " << to_string(arg1_value.type) << "."; report_error(components[leftmost_node_in_expression(components, arg1)].source_location, AssemblyErrorCodes::UnsupportedMapKeyType, ss.str()); } set_unknown(result);
M jasm/assembling/assembler_impl/operators_impl.cpp +167 -96
@@ 1,7 1,9 @@ #include "pch.h" #include <assembling/assembler_impl/assembler_impl.h> +#include <core/math/sign.h> #include <core/ownership/destruct_call.h> +#include <core/strings/utf8.h> namespace jasm { @@ 11,8 13,8 @@ bool Assembler::verify_numeric_argument( { if (!is_numeric(right)) { if (generate) { - std::wstringstream ss; - ss << L"Operator " << to_string(operator_component.operator_type) << L" expects numeric right argument but got " << to_string(type_of_value(right)) << L" type"; + std::stringstream ss; + ss << "Operator " << to_string(operator_component.operator_type) << " expects numeric right argument but got " << to_string(type_of_value(right)) << " type"; report_error(operator_component.source_location, AssemblyErrorCodes::OperatorExpectsNumericArguments, ss.str()); } // the result is an error @@ 26,8 28,8 @@ bool Assembler::verify_integer_argument( { if (!is_integer(right)) { if (generate) { - std::wstringstream ss; - ss << L"Operator " << to_string(operator_component.operator_type) << L" expects integer right argument but got " << to_string(type_of_value(right)) << L" type"; + std::stringstream ss; + ss << "Operator " << to_string(operator_component.operator_type) << " expects integer right argument but got " << to_string(type_of_value(right)) << " type"; report_error(operator_component.source_location, AssemblyErrorCodes::OperatorExpectsNumericArguments, ss.str()); } // the result is an error @@ 41,8 43,8 @@ bool Assembler::verify_boolean_argument( { if (!is_boolean(right)) { if (generate) { - std::wstringstream ss; - ss << L"Operator " << to_string(operator_component.operator_type) << L" expects boolean right argument but got " << to_string(type_of_value(right)) << L" type"; + std::stringstream ss; + ss << "Operator " << to_string(operator_component.operator_type) << " expects boolean right argument but got " << to_string(type_of_value(right)) << " type"; report_error(operator_component.source_location, AssemblyErrorCodes::OperatorExpectsNumericArguments, ss.str()); } // the result is an error @@ 56,8 58,8 @@ bool Assembler::verify_string_argument(b { if (!is_string(right)) { if (generate) { - std::wstringstream ss; - ss << L"Operator " << to_string(operator_component.operator_type) << L" expects string right argument but got " << to_string(type_of_value(right)) << L" type"; + std::stringstream ss; + ss << "Operator " << to_string(operator_component.operator_type) << " expects string right argument but got " << to_string(type_of_value(right)) << " type"; report_error(operator_component.source_location, AssemblyErrorCodes::OperatorExpectsStringArguments, ss.str()); } // the result is an error @@ 100,7 102,7 @@ bool Assembler::verify_comparable_argume case ValueType::IntegerValue: case ValueType::FloatValue: - case ValueType::RangeValue: + case ValueType::SubroutineValue: case ValueType::ByteOffset: case ValueType::WordOffset: case ValueType::LongOffset: @@ 127,8 129,8 @@ bool Assembler::verify_comparable_argume return true; if (generate) { - std::wstringstream ss; - ss << L"Operator " << to_string(operator_component.operator_type) << L" requires comparable types"; + std::stringstream ss; + ss << "Operator " << to_string(operator_component.operator_type) << " requires comparable types"; report_error(operator_component.source_location, AssemblyErrorCodes::OperatorNeedsComparableTypes, ss.str()); } // the result is an error @@ 155,11 157,11 @@ bool Assembler::verify_num_arguments_and // number of arguments doesn't match if (generate) { const ExpressionComponent &ec = components[operator_index]; - std::wstringstream ss; - ss << L"Wrong number of arguments. " << num_args - skip_args << L" argument"; + std::stringstream ss; + ss << "Wrong number of arguments. " << num_args - skip_args << " argument"; if (num_args - skip_args != 1) - ss << L"s"; - ss << L" was expected and " << num_args_count << L" was given."; + ss << "s"; + ss << " was expected and " << num_args_count << " was given."; report_error(ec.source_location, AssemblyErrorCodes::WrongNumberOfArguments, ss.str()); } set_unknown(result); @@ 322,8 324,8 @@ void Assembler::operator_string_add(bool if (!verify_string_argument(generate, components[operator_index], arg2, result)) return; - std::wstring a = std::wstring(dereference_string(arg1)); - const std::wstring_view b = dereference_string(arg2); + std::string a = std::string(dereference_string(arg1)); + const std::string_view b = dereference_string(arg2); a.append(b); set_string(result, a); } @@ 363,8 365,8 @@ void Assembler::operator_float_divide(bo if (b == 0.0) { if (generate) { const ExpressionComponent &operator_component = components[operator_index]; - std::wstringstream ss; - ss << L"Division by zero."; + std::stringstream ss; + ss << "Division by zero."; report_error(operator_component.source_location, AssemblyErrorCodes::DivisionByZero, ss.str()); } // the result is an error @@ 400,8 402,8 @@ void Assembler::operator_integer_divide( // handle division by zero if (generate) { const ExpressionComponent &operator_component = components[operator_index]; - std::wstringstream ss; - ss << L"Division by zero."; + std::stringstream ss; + ss << "Division by zero."; report_error(operator_component.source_location, AssemblyErrorCodes::DivisionByZero, ss.str()); } // the result is an error @@ 469,8 471,8 @@ void Assembler::compare_string_types(boo if (!verify_comparable_argument_type(generate, components[operator_index], arg1, arg2, result)) return; - const std::wstring_view a = dereference_string(arg1); - const std::wstring_view b = dereference_string(arg2); + const std::string_view a = dereference_string(arg1); + const std::string_view b = dereference_string(arg2); set_boolean(result, comp(a, b)); } @@ 490,7 492,7 @@ void Assembler::operator_float_equal_to( void Assembler::operator_string_equal_to(bool generate, ValueVector &/*expression_values*/, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, const Value &arg2) { - auto comp = [](const std::wstring_view &a, const std::wstring_view &b) { return a == b; }; + auto comp = [](const std::string_view &a, const std::string_view &b) { return a == b; }; compare_string_types(generate, components, operator_index, result, arg1, arg2, comp); } @@ 520,7 522,7 @@ void Assembler::operator_float_not_equal void Assembler::operator_string_not_equal_to(bool generate, ValueVector &/*expression_values*/, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, const Value &arg2) { - auto comp = [](const std::wstring_view &a, const std::wstring_view &b) { return a != b; }; + auto comp = [](const std::string_view &a, const std::string_view &b) { return a != b; }; compare_string_types(generate, components, operator_index, result, arg1, arg2, comp); } @@ 582,25 584,25 @@ void Assembler::operator_float_less_or_e void Assembler::operator_string_greater(bool generate, ValueVector &/*expression_values*/, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, const Value &arg2) { - auto comp = [](const std::wstring_view &a, const std::wstring_view &b) { return a > b; }; + auto comp = [](const std::string_view &a, const std::string_view &b) { return a > b; }; compare_string_types(generate, components, operator_index, result, arg1, arg2, comp); } void Assembler::operator_string_less(bool generate, ValueVector &/*expression_values*/, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, const Value &arg2) { - auto comp = [](const std::wstring_view &a, const std::wstring_view &b) { return a < b; }; + auto comp = [](const std::string_view &a, const std::string_view &b) { return a < b; }; compare_string_types(generate, components, operator_index, result, arg1, arg2, comp); } void Assembler::operator_string_greater_or_equal(bool generate, ValueVector &/*expression_values*/, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, const Value &arg2) { - auto comp = [](const std::wstring_view &a, const std::wstring_view &b) { return a >= b; }; + auto comp = [](const std::string_view &a, const std::string_view &b) { return a >= b; }; compare_string_types(generate, components, operator_index, result, arg1, arg2, comp); } void Assembler::operator_string_less_or_equal(bool generate, ValueVector &/*expression_values*/, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, const Value &arg2) { - auto comp = [](const std::wstring_view &a, const std::wstring_view &b) { return a <= b; }; + auto comp = [](const std::string_view &a, const std::string_view &b) { return a <= b; }; compare_string_types(generate, components, operator_index, result, arg1, arg2, comp); } @@ 715,8 717,8 @@ void Assembler::operator_assignment(bool if (generate && counter > 1) { const ExpressionComponent &operator_component = components[operator_index]; - std::wstringstream ss; - ss << L"Import value assigned twice."; + std::stringstream ss; + ss << "Import value assigned twice."; report_error(operator_component.source_location, AssemblyErrorCodes::ImportValueAssignedTwice, ss.str()); } @@ 752,8 754,8 @@ void Assembler::operator_assignment(bool if (generate && value->contains_address()) { if (!is_integer(*value)) { const ExpressionComponent &operator_component = components[operator_index]; - std::wstringstream ss; - ss << L"Address must be integer, but was " << to_string(value->type) << L"."; + std::stringstream ss; + ss << "Address must be integer, but was " << to_string(value->type) << "."; report_error(operator_component.source_location, AssemblyErrorCodes::AddressMustBeInteger, ss.str()); } } @@ 827,8 829,8 @@ void Assembler::operator_integer_assignm // handle division by zero if (generate) { const ExpressionComponent &operator_component = components[operator_index]; - std::wstringstream ss; - ss << L"Division by zero."; + std::stringstream ss; + ss << "Division by zero."; report_error(operator_component.source_location, AssemblyErrorCodes::DivisionByZero, ss.str()); } // the result is an error @@ 851,8 853,8 @@ void Assembler::operator_float_assignmen // handle division by zero if (generate) { const ExpressionComponent &operator_component = components[operator_index]; - std::wstringstream ss; - ss << L"Division by zero."; + std::stringstream ss; + ss << "Division by zero."; report_error(operator_component.source_location, AssemblyErrorCodes::DivisionByZero, ss.str()); } // the result is an error @@ 906,8 908,8 @@ void Assembler::operator_array_offset_ac if (!is_integer(arg2)) { if (generate) { const ExpressionComponent &operator_component = components[operator_index]; - std::wstringstream ss; - ss << L"Array index must be integer. Type is " << to_string(type_of_value(arg2)) << L"."; + std::stringstream ss; + ss << "Array index must be integer. Type is " << to_string(type_of_value(arg2)) << "."; report_error(operator_component.source_location, AssemblyErrorCodes::ArrayIndexMustBeInteger, ss.str()); } set_unknown(result); @@ 921,8 923,8 @@ void Assembler::operator_array_offset_ac if (array_index < 0 || array_index >= arg1_type.array_size) { if (generate) { const ExpressionComponent &operator_component = components[operator_index]; - std::wstringstream ss; - ss << L"Array index out of range. Index is " << array_index << L" and range is [0.." << arg1_type.array_size - 1 << L"]."; + std::stringstream ss; + ss << "Array index out of range. Index is " << array_index << " and range is [0.." << arg1_type.array_size - 1 << "]."; report_error(operator_component.source_location, AssemblyErrorCodes::ArrayIndexOutOfRange, ss.str()); } set_unknown(result); @@ 944,32 946,51 @@ void Assembler::operator_string_array_ac if (!is_integer(arg2)) { if (generate) { const ExpressionComponent &operator_component = components[operator_index]; - std::wstringstream ss; - ss << L"Array index must be integer. Type is " << to_string(type_of_value(arg2)) << L"."; + std::stringstream ss; + ss << "Array index must be integer. Type is " << to_string(type_of_value(arg2)) << "."; report_error(operator_component.source_location, AssemblyErrorCodes::ArrayIndexMustBeInteger, ss.str()); } set_unknown(result); return; } - int64_t array_index = dereference_integer(arg2); + int32_t array_index = dereference_integer(arg2); + const std::string_view str = dereference_string(arg1); + bool success = true; + + if (array_index < 0) { + success = false; + } - // check array index boundaries - const std::wstring_view str = dereference_string(arg1); - int64_t length = static_cast<int64_t>(str.size()); - if (array_index < 0 || array_index >= length) { + if (success) { + const char *ptr = core::utf8_offset(str, core::unsign_cast(array_index)); + if (ptr != nullptr) { + wchar_t wide_char; + size_t size_left = core::unsign_cast(str.end() - ptr); + success = core::utf8_to_wide(ptr, size_left, wide_char); + if (success) { + // now return the character + set_integer(result, static_cast<int32_t>(wide_char)); + } + } else { + success = false; + } + } + + if (!success) { if (generate) { const ExpressionComponent &operator_component = components[operator_index]; - std::wstringstream ss; - ss << L"Array index out of range. Index is " << array_index << L" and range is [0.." << length - 1 << L"]."; + std::stringstream ss; + size_t len = core::num_utf8_characters(str); + if (len == 0) { + ss << "Array index out of range. Index is " << array_index << " and string is empty."; + } else { + ss << "Array index out of range. Index is " << array_index << " and range is [0.." << len - 1 << "]."; + } report_error(operator_component.source_location, AssemblyErrorCodes::ArrayIndexOutOfRange, ss.str()); } set_unknown(result); - return; } - - // now return the character - set_integer(result, static_cast<int32_t>(str[static_cast<size_t>(array_index)])); } void Assembler::operator_list_array_access(bool generate, ValueVector &/*expression_values*/, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1_ref, Value &arg1, const Value &arg2) @@ 977,8 998,8 @@ void Assembler::operator_list_array_acce if (!is_integer(arg2)) { if (generate) { const ExpressionComponent &operator_component = components[operator_index]; - std::wstringstream ss; - ss << L"Array index must be integer. Type is " << to_string(type_of_value(arg2)) << L"."; + std::stringstream ss; + ss << "Array index must be integer. Type is " << to_string(type_of_value(arg2)) << "."; report_error(operator_component.source_location, AssemblyErrorCodes::ArrayIndexMustBeInteger, ss.str()); } set_unknown(result); @@ 993,8 1014,8 @@ void Assembler::operator_list_array_acce if (array_index < 0 || static_cast<size_t>(array_index) >= length) { if (generate) { const ExpressionComponent &operator_component = components[operator_index]; - std::wstringstream ss; - ss << L"Array index out of range. Index is " << array_index << L" and range is [0.." << length - 1 << L"]."; + std::stringstream ss; + ss << "Array index out of range. Index is " << array_index << " and range is [0.." << length - 1 << "]."; report_error(operator_component.source_location, AssemblyErrorCodes::ArrayIndexOutOfRange, ss.str()); } set_unknown(result); @@ 1007,6 1028,25 @@ void Assembler::operator_list_array_acce set_list_element_reference(result, combined_storage_type, arg1, array_index); } +void Assembler::operator_subroutine_call(bool generate, ValueVector &/*expression_values*/, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, uint32_t next_index) +{ + // set void return value + set_none(result); + + if (next_index != 0) { + // number of arguments doesn't match + if (generate) { + const ExpressionComponent &ec = components[operator_index]; + std::stringstream ss; + ss << "Subroutine calls don't support arguments."; + report_error(ec.source_location, AssemblyErrorCodes::ArgumentsPassedToSubroutineCall, ss.str()); + } + return; + } + + generate_subroutine_instruction(generate, dereference_integer(arg1), components[operator_index].source_location); +} + void Assembler::operator_function_call(bool generate, ValueVector &expression_values, const ExpressionComponent components[], uint32_t operator_index, Value &result, Value &arg1, uint32_t next_index) { // figure out function arguments @@ 1026,12 1066,12 @@ void Assembler::operator_function_call(b // number of arguments doesn't match if (generate) { const ExpressionComponent &ec = components[operator_index]; - std::wstringstream ss; - ss << L"Number of function arguments doesn't match function signature. Function "; - ss << to_string(func_type) << L" takes " << func_desc.num_arguments << L" argument"; + std::stringstream ss; + ss << "Number of function arguments doesn't match function signature. Function "; + ss << to_string(func_type) << " takes " << func_desc.num_arguments << " argument"; if (func_desc.num_arguments != 1) - ss << L"s"; - ss << L" and " << num_args << L" was given."; + ss << "s"; + ss << " and " << num_args << " was given."; report_error(ec.source_location, AssemblyErrorCodes::NoOfArgumentsDoesNotMatchFunctionSignature, ss.str()); } set_unknown(result); @@ 1043,12 1083,12 @@ void Assembler::operator_function_call(b // too few number of arguments if (generate) { const ExpressionComponent &ec = components[operator_index]; - std::wstringstream ss; - ss << L"Too few function arguments given. Function "; - ss << to_string(func_type) << L" takes at least " << func_desc.num_arguments << L" argument"; + std::stringstream ss; + ss << "Too few function arguments given. Function "; + ss << to_string(func_type) << " takes at least " << func_desc.num_arguments << " argument"; if (func_desc.num_arguments != 1) - ss << L"s"; - ss << L" and " << num_args << L" was given."; + ss << "s"; + ss << " and " << num_args << " was given."; report_error(ec.source_location, AssemblyErrorCodes::TooFewFunctionArguments, ss.str()); } set_unknown(result); @@ 1133,17 1173,17 @@ void Assembler::operator_method_closure_ // number of arguments doesn't match if (generate) { const ExpressionComponent &ec = components[operator_index]; - std::wstringstream ss; - ss << L"Number of method arguments doesn't match method signature. Method "; - ss << to_string(method_type) << L" takes "; + std::stringstream ss; + ss << "Number of method arguments doesn't match method signature. Method "; + ss << to_string(method_type) << " takes "; if (method_desc.variable_num_arguments) { - ss << L"at least "; + ss << "at least "; } - ss << method_desc.num_arguments << L" argument"; + ss << method_desc.num_arguments << " argument"; if (method_desc.num_arguments != 1) { - ss << L"s"; + ss << "s"; } - ss << L" and " << num_args << L" was given."; + ss << " and " << num_args << " was given."; report_error(ec.source_location, AssemblyErrorCodes::NoOfArgumentsDoesNotMatchMethodSignature, ss.str()); } set_unknown(result); @@ 1167,8 1207,8 @@ void Assembler::operator_method_closure_ if (method_desc.mutating && !object_value.is_mutable()) { if (generate) { - std::wstringstream ss; - ss << L"Cannot modify constant value."; + std::stringstream ss; + ss << "Cannot modify constant value."; report_error(components[operator_index].source_location, AssemblyErrorCodes::CannotModifyConstant, ss.str()); } set_unknown(result); @@ 1234,8 1274,8 @@ void Assembler::operator_byte_conversion if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, next_index)]; - std::wstringstream ss; - ss << L"Cast to byte from " << to_string(value1.type) << L" is not allowed."; + std::stringstream ss; + ss << "Cast to byte from " << to_string(value1.type) << " is not allowed."; report_error(ec.source_location, AssemblyErrorCodes::TypeCastNotAllowed, ss.str()); } set_unknown(result); @@ 1260,8 1300,8 @@ void Assembler::operator_word_conversion if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, next_index)]; - std::wstringstream ss; - ss << L"Cast to word from " << to_string(value1.type) << L" is not allowed."; + std::stringstream ss; + ss << "Cast to word from " << to_string(value1.type) << " is not allowed."; report_error(ec.source_location, AssemblyErrorCodes::TypeCastNotAllowed, ss.str()); } set_unknown(result); @@ 1286,8 1326,8 @@ void Assembler::operator_long_conversion if (generate) { const ExpressionComponent &ec = components[leftmost_node_in_expression(components, next_index)]; - std::wstringstream ss; - ss << L"Cast to long from " << to_string(value1.type) << L" is not allowed."; + std::stringstream ss; + ss << "Cast to long from " << to_string(value1.type) << " is not allowed."; report_error(ec.source_location, AssemblyErrorCodes::TypeCastNotAllowed, ss.str()); } set_unknown(result); @@ 1299,8 1339,8 @@ void Assembler::operator_list_add(bool g if (generate) { uint32_t arg_index = components[components[operator_index].first_child].next_sibling; const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg_index)]; - std::wstringstream ss; - ss << L"Operator expects right hand side list type but got " << to_string(arg2.type) << L'.'; + std::stringstream ss; + ss << "Operator expects right hand side list type but got " << to_string(arg2.type) << '.'; report_error(ec.source_location, AssemblyErrorCodes::ListValueExpected, ss.str()); } set_unknown(result); @@ 1327,8 1367,8 @@ void Assembler::operator_list_assignment if (generate) { uint32_t arg_index = components[components[operator_index].first_child].next_sibling; const ExpressionComponent &ec = components[leftmost_node_in_expression(components, arg_index)]; - std::wstringstream ss; - ss << L"Operator expects right hand side list type but got " << to_string(arg2.type) << L'.'; + std::stringstream ss; + ss << "Operator expects right hand side list type but got " << to_string(arg2.type) << '.'; report_error(ec.source_location, AssemblyErrorCodes::ListValueExpected, ss.str()); } set_unknown(result); @@ 1406,8 1446,8 @@ void Assembler::operator_call_macro(bool ++_call_depth; if (_call_depth >= max_call_depth) { - std::wstringstream ss; - ss << L"Reached maximum call stack depth " << max_call_depth << L". Too deep call stack. Giving up assembly. There is probably a recursive macro with a broken end condition somewhere."; + std::stringstream ss; + ss << "Reached maximum call stack depth " << max_call_depth << ". Too deep call stack. Giving up assembly. There is probably a recursive macro with a broken end condition somewhere."; throw AssemblyException(_used_files, components[operator_index].source_location, AssemblyErrorCodes::TooDeepRecursion, ss.str()); } @@ 1435,8 1475,8 @@ bool Assembler::get_operator_period_prop const ExpressionComponent &right_component = components[next_index]; if (right_component.type != ExpressionComponentType::GlobalSymbol) { if (generate) { - std::wstringstream ss; - ss << L"Structure reference requires right hand side symbol name but found " << to_string(right_component.type) << L"."; + std::stringstream ss; + ss << "Structure reference requires right hand side symbol name but found " << to_string(right_component.type) << "."; report_error(right_component.source_location, AssemblyErrorCodes::StructureReferenceRequiresRightHandSymbol, ss.str()); } set_unknown(result); @@ 1452,8 1492,8 @@ bool Assembler::get_operator_period_prop if (found == end) { // property was not found if (generate) { - std::wstringstream ss; - ss << L"Property " << _strings.get(right_component.symbol) << L" doesn't exist in type."; + std::stringstream ss; + ss << "Property " << _strings.get(right_component.symbol) << " doesn't exist in type."; report_error(right_component.source_location, AssemblyErrorCodes::MissingProperty, ss.str()); } set_unknown(result); @@ 1486,16 1526,18 @@ void Assembler::operator_string_period(b { MethodType method = static_cast<MethodType>(static_cast<uint32_t>(MethodType::StringStart) + key_index); set_method(result, method, arg1); - break; } + break; + case StringProperties::Length: size_t length; if (arg1.type == ValueType::StringValue) - length = dereference_string(arg1).size(); + length = core::num_utf8_characters(dereference_string(arg1)); else - length = arg1.object_reference.deref<StringDynamicObject>().value.size(); + length = core::num_utf8_characters(arg1.object_reference.deref<StringDynamicObject>().value); set_integer(result, static_cast<int32_t>(length)); break; + case StringProperties::NumProperties: assert(false); break; @@ 1522,18 1564,21 @@ void Assembler::operator_list_period(boo set_method(result, method, arg1); } break; + case ListProperties::Empty: { bool empty = arg1.object_reference.deref<ListDynamicObject>().value->empty(); set_boolean(result, empty); } break; + case ListProperties::Length: { size_t length = arg1.object_reference.deref<ListDynamicObject>().value->size(); set_integer(result, static_cast<int32_t>(length)); } break; + case ListProperties::NumProperties: assert(false); break; @@ 1559,22 1604,48 @@ void Assembler::operator_map_period(bool set_method(result, method, arg1); } break; + case MapProperties::Empty: { bool empty = arg1.object_reference.deref<MapDynamicObject>().value->empty(); set_boolean(result, empty); } break; + case MapProperties::Length: { size_t length = arg1.object_reference.deref<MapDynamicObject>().value->size(); set_integer(result, static_cast<int32_t>(length)); } break; + case MapProperties::NumProperties: assert(false); break; } } +void Assembler::operator_word_offset_period(bool generate, ValueVector &/*expression_values*/, const ExpressionComponent components[], uint32_t /*operator_index*/, Value &result, Value &arg1, uint32_t next_index) +{ + uint32_t key_index; + if (!get_operator_period_property_index(generate, components, result, arg1, next_index, key_index)) + return; + + // create method closure result which contains the value and method to call + switch(static_cast<WordOffsetProperties>(key_index)) + { + case WordOffsetProperties::Lo: + set_byte_offset(result, arg1.offset_base, arg1.offset); + break; + + case WordOffsetProperties::Hi: + set_byte_offset(result, arg1.offset_base, arg1.offset + 1); + break; + + case WordOffsetProperties::NumProperties: + assert(false); + break; + } +} + } // namespace jasm
M jasm/assembling/assembler_impl/symbols_impl.cpp +75 -46
@@ 1,6 1,8 @@ #include "pch.h" #include <assembling/assembler_impl/assembler_impl.h> +#include <core/math/sign.h> +#include <core/strings/utf8.h> #include <cstring> #include <locale> @@ 78,7 80,7 @@ void Assembler::set_string(Value &result result.object_reference.clear(); } -void Assembler::set_string(Value &result, const std::wstring_view &value) const +void Assembler::set_string(Value &result, const std::string_view &value) const { result.set_found_in_current_pass(false); result.union_space1 = 0; @@ 89,7 91,7 @@ void Assembler::set_string(Value &result result.object_reference = new StringDynamicObject(value); } -void Assembler::set_string(Value &result, const std::wstring &value) const +void Assembler::set_string(Value &result, const std::string &value) const { result.set_found_in_current_pass(false); result.union_space1 = 0; @@ 100,7 102,7 @@ void Assembler::set_string(Value &result result.object_reference = new StringDynamicObject(value); } -void Assembler::set_string(Value &result, std::wstring &&value) const +void Assembler::set_string(Value &result, std::string &&value) const { result.set_found_in_current_pass(false); result.union_space1 = 0; @@ 111,14 113,14 @@ void Assembler::set_string(Value &result result.object_reference = new StringDynamicObject(value); } -void Assembler::set_range(Value &result, int32_t value, int32_t size) const +void Assembler::set_subroutine(Value &result, int32_t value, int32_t size) const { result.set_found_in_current_pass(false); result.union_space1 = 0; result.union_space2 = 0; - result.type = ValueType::RangeValue; - result.type_hash = _static_range_type; + result.type = ValueType::SubroutineValue; + result.type_hash = _static_subroutine_type; result.integer_value = value; result.range_size = size; result.object_reference.clear(); @@ 170,6 172,28 @@ void Assembler::set_map(Value &result) c result.object_reference = new MapDynamicObject(); } +void Assembler::set_byte_offset(Value &result, int32_t offset_base, int32_t offset) +{ + result.set_found_in_current_pass(false); + result.offset_base = offset_base; + result.offset = offset; + + result.type = ValueType::ByteOffset; + result.type_hash = _static_byte_offset_type; + result.object_reference.clear(); +} + +void Assembler::set_word_offset(Value &result, int32_t offset_base, int32_t offset) +{ + result.set_found_in_current_pass(false); + result.offset_base = offset_base; + result.offset = offset; + + result.type = ValueType::WordOffset; + result.type_hash = _static_word_offset_type; + result.object_reference.clear(); +} + void Assembler::set_list_element_reference(Value &result, StorageType storage_type, const Value &list, int32_t index) const { result.set_found_in_current_pass(false); @@ 198,7 222,7 @@ bool Assembler::dereference_boolean(cons int32_t Assembler::dereference_integer(const Value &value) const { - if (value.type == ValueType::IntegerValue || value.type == ValueType::RangeValue) + if (value.type == ValueType::IntegerValue || value.type == ValueType::SubroutineValue) return value.integer_value; if (value.type == ValueType::ByteOffset @@ 218,7 242,7 @@ int32_t Assembler::dereference_integer(c double Assembler::dereference_float(const Value &value) const { - if (value.type == ValueType::IntegerValue || value.type == ValueType::RangeValue) + if (value.type == ValueType::IntegerValue || value.type == ValueType::SubroutineValue) return static_cast<double>(value.integer_value); if (value.type == ValueType::FloatValue) @@ 239,7 263,7 @@ double Assembler::dereference_float(cons return 666.0; } -std::wstring_view Assembler::dereference_string(const Value &value) const +std::string_view Assembler::dereference_string(const Value &value) const { if (value.type == ValueType::StringValue) return _strings.get(value.string_hash); @@ 249,7 273,7 @@ std::wstring_view Assembler::dereference return dereference_string(follow_reference(value)); // the caller should check for this case! assert(false); - return L"<invalid string reference>"; + return "<invalid string reference>"; } uint64_t Assembler::dereference_string_hash(const Value &value) const @@ 280,12 304,12 @@ uint64_t Assembler::combine_namespace(ui return seed; } -bool Assembler::parse_symbol_string(const std::wstring_view &symbol, uint64_t &hash, bool &global) +bool Assembler::parse_symbol_string(const std::string_view &symbol, uint64_t &hash, bool &global) { size_t offset = 0; // detect local symbol - global = symbol[0] != L'.'; + global = symbol[0] != '.'; if (!global) { // skip the '.' ++offset; @@ 295,37 319,42 @@ bool Assembler::parse_symbol_string(cons if (symbol.size() - offset <= 0) return false; + // convert to wide string to classify characters + std::wstring wide_symbol = core::utf8_to_wide(symbol); + using MaskType = std::ctype<wchar_t>::mask; + std::locale locale("en_US.utf8"); + const std::ctype<wchar_t> &facet(std::use_facet<std::ctype<wchar_t>>(locale)); // determine character types std::vector<MaskType> masks; // The classification of each character in the string - masks.resize(symbol.size()); + masks.resize(wide_symbol.size()); // generate character classification from locale - std::locale loc; - std::use_facet<std::ctype<wchar_t>>(loc).is(&symbol[0], &symbol[0] + symbol.size(), &masks[0]); + facet.is(wide_symbol.data(), wide_symbol.data() + wide_symbol.size(), masks.data()); // check first letter specifically - bool is_alpha = (masks[offset] & std::ctype<wchar_t>::alpha) != 0 || symbol[offset] == L'_'; + bool is_alpha = (masks[offset] & std::ctype<wchar_t>::alpha) != 0 || wide_symbol[offset] == L'_'; if (!is_alpha) return false; for(size_t i = offset + 1; i < symbol.size(); ++i) { - bool is_alpha_num = (masks[i] & std::ctype<wchar_t>::alnum) != 0 || symbol[i] == L'_'; + bool is_alpha_num = (masks[i] & std::ctype<wchar_t>::alnum) != 0 || wide_symbol[i] == L'_'; if (!is_alpha_num) return false; } - hash = murmur_hash3_string_x64_64(&symbol[offset], static_cast<int>(symbol.size() - offset)); + std::string_view symbol_name(&symbol[offset], symbol.size() - offset); + hash = murmur_hash3_string_x64_64(symbol_name); return true; } -void Assembler::store_symbol_string_in_repository(uint64_t hash, const std::wstring_view &symbol) +void Assembler::store_symbol_string_in_repository(uint64_t hash, const std::string_view &symbol) { if (_strings.has(hash)) return; - if (symbol.front() == L'.') { - _strings.add(hash, symbol.substr(1, std::wstring_view::npos)); + if (symbol.front() == '.') { + _strings.add(hash, symbol.substr(1, std::string_view::npos)); } else { _strings.add(hash, symbol); } @@ 474,8 503,8 @@ const Value *Assembler::find_global_symb if (num_hits == 0) { if (generate) { - std::wstringstream ss; - ss << L"Reference to undefined symbol " << _strings.get(symbol_hash); + std::stringstream ss; + ss << "Reference to undefined symbol " << _strings.get(symbol_hash); report_error(source_location, AssemblyErrorCodes::ReferenceToUndefinedSymbol, ss.str()); } result = nullptr; @@ 485,22 514,22 @@ const Value *Assembler::find_global_symb if (generate) { // a bit of work is required since we need to list all the possible matches // redo the scan to print all hits - std::wstringstream ss; - ss << L"Ambiguous reference to symbol " << _strings.get(symbol_hash) << L'\n'; - ss << L"Could be:"; + std::stringstream ss; + ss << "Ambiguous reference to symbol " << _strings.get(symbol_hash) << '\n'; + ss << "Could be:"; for(uint64_t namespace_start : _symbol_environment.using_scopes) { uint64_t combined_hash = combine_namespace_and_symbol(namespace_start, namespaces, num_namespaces, symbol_hash); Value *found_value; if (find_global_symbol_in_passes(combined_hash, found_in_current_pass, found_value)) { - ss << L'\n'; + ss << '\n'; // namespaces in scope ss << _strings.get(namespace_start); // namespaces in reference for(size_t i = 0; i < num_namespaces; ++i) - ss << L"::" << _strings.get(namespaces[i]); + ss << "::" << _strings.get(namespaces[i]); // the symbol itself - ss << L"::" << _strings.get(symbol_hash); + ss << "::" << _strings.get(symbol_hash); } } @@ 597,8 626,8 @@ const Value *Assembler::find_local_symbo } if (generate) { - std::wstringstream ss; - ss << L"Reference to undefined symbol ." << _strings.get(symbol_hash); + std::stringstream ss; + ss << "Reference to undefined symbol ." << _strings.get(symbol_hash); report_error(source_location, AssemblyErrorCodes::ReferenceToUndefinedSymbol, ss.str()); } @@ 683,7 712,7 @@ void Assembler::enter_variable_scope(uin if (UNLIKELY(add_loop_variable)) { // define an automatic loop variable constexpr bool global = false; - Value &value = create_unique_label(hash_constant(0x9d60c3eb1644552dULL, L"@loop"), global); + Value &value = create_unique_label(hash_constant(0xdb831a5e32f85dcfULL, "@loop"), global); set_integer(value, _program_counter.integer_value); value.set_contains_address(true); // mark as address } @@ 694,7 723,7 @@ void Assembler::leave_variable_scope(boo if (UNLIKELY(add_continue_variable)) { // define an automatic loop variable constexpr bool global = false; - Value &value = create_unique_label(hash_constant(0xdaa803af4141d0e8ULL, L"@continue"), global); + Value &value = create_unique_label(hash_constant(0x232e8dde60eefef3ULL, "@continue"), global); set_integer(value, _program_counter.integer_value); value.set_contains_address(true); // mark as address } @@ 715,7 744,7 @@ uint64_t Assembler::enter_namespace(uint uint64_t combined_hash = murmur_hash3_x64_64(&namespace_hash, sizeof(namespace_hash), _symbol_environment.namespace_scope_stack.back()); if (UNLIKELY(_dump_symbols)) - combine_and_store_hash_name(_symbol_environment.namespace_scope_stack.back(), combined_hash, std::wstring(_strings.get(namespace_hash))); + combine_and_store_hash_name(_symbol_environment.namespace_scope_stack.back(), combined_hash, std::string(_strings.get(namespace_hash))); _symbol_environment.namespace_scope_stack.push_back(combined_hash); _symbol_environment.namespace_names_scope_stack.push_back(namespace_hash); @@ 749,18 778,18 @@ void Assembler::store_namespace_string(u return; // construct a dynamic string - std::wstringstream ss; + std::stringstream ss; for(uint64_t hash : namespace_hashes) { if (hash == 0) continue; - ss << L"::" << _strings.get(hash); + ss << "::" << _strings.get(hash); } // store namespace string in string repository _strings.add(combined_hash, ss.str()); } -void Assembler::combine_and_store_hash_name(uint64_t parent_hash, uint64_t combined_hash, const std::wstring &child_name) +void Assembler::combine_and_store_hash_name(uint64_t parent_hash, uint64_t combined_hash, const std::string &child_name) { assert(_dump_symbols); // should only be used for symbol dumps since it is inefficient @@ 769,10 798,10 @@ void Assembler::combine_and_store_hash_n auto it = _symbol_names.find(parent_hash); bool add_separator = true; if (UNLIKELY(it == _symbol_names.end())) { - const wchar_t unknown_text[] = L"<unknown>"; + const char unknown_text[] = "<unknown>"; _temp_string_combine.insert(_temp_string_combine.end(), std::begin(unknown_text), std::end(unknown_text) - 1); } else { - const std::wstring &parent_name = it->second; + const std::string &parent_name = it->second; if (parent_name.empty()) { add_separator = false; } else { @@ 780,13 809,13 @@ void Assembler::combine_and_store_hash_n } } if (add_separator) { - const wchar_t separator[] = L"::"; + const char separator[] = "::"; _temp_string_combine.insert(_temp_string_combine.end(), std::begin(separator), std::end(separator) - 1); } _temp_string_combine.insert(_temp_string_combine.end(), child_name.c_str(), child_name.c_str() + child_name.size()); - _temp_string_combine.push_back(L'\0'); + _temp_string_combine.push_back('\0'); - _symbol_names[combined_hash] = &_temp_string_combine[0]; + _symbol_names[combined_hash] = _temp_string_combine.data(); } bool Assembler::create_label(bool generate, uint64_t name_hash, bool global, StorageType storage_type, const SourceLocation &location) @@ 828,16 857,16 @@ bool Assembler::create_label(bool genera // passes so we need to let it go unnoticed by skipping the declaration. // However, in the generation pass this is a fatal error. if (generate) { - std::wstringstream ss; - ss << L"Duplicate declaration of "; + std::stringstream ss; + ss << "Duplicate declaration of "; if (!global) - ss << L"."; + ss << "."; ss << _strings.get(name_hash); if (using_predeclared_symbol) { // find again to avoid having to store state all the time for rare errors auto declare_it = std::find_if(_symbol_environment.declared_symbol_hashes.begin(), _symbol_environment.declared_symbol_hashes.end(), [name_hash](LocalSymbolDeclaration &decl){ return decl.local_symbol_hash == name_hash; }); const SourceLocation &declare_location = declare_it->source_location; - ss << L'\n' << _used_files[declare_location.file_index] << L"(" << declare_location.row << L"," << declare_location.column << L") : Predeclared here"; + ss << '\n' << _used_files[declare_location.file_index] << "(" << declare_location.row << "," << declare_location.column << ") : Predeclared here"; } report_error(location, AssemblyErrorCodes::DuplicateSymbolDefinitions, ss.str()); }
M jasm/assembling/assembler_impl/syntax_impl.cpp +330 -194
@@ 5,6 5,8 @@ #include <assembling/scope_counter.h> #include <core/environment/log.h> #include <core/math/algorithm.h> +#include <core/math/sign.h> +#include <core/strings/utf8.h> #include <io/data_reader.h> #include <limits> @@ 57,8 59,8 @@ const SyntaxToken *Assembler::parse_if(b t = consume_next_token(); if (!is_boolean(value)) { if (generate) { - std::wstringstream ss; - ss << L"Expected boolean value in if expression but got " << to_string(type_of_value(value)) << L"."; + std::stringstream ss; + ss << "Expected boolean value in if expression but got " << to_string(type_of_value(value)) << "."; report_error(expression->source_location, AssemblyErrorCodes::IfExpressionMustBeBoolean, ss.str()); } // skip what comes after the expression and let the code outside the loop consume the rest @@ 114,8 116,8 @@ const SyntaxToken *Assembler::parse_sect if (_section != nullptr && _section->section_type == SectionType::Bss) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Sections can't be created inside a bss section"; + std::stringstream ss; + ss << "Sections can't be created inside a bss section"; report_fatal_error(section_token->source_location, AssemblyErrorCodes::SectionWithinBssSection, ss.str()); } @@ 156,8 158,8 @@ const SyntaxToken *Assembler::parse_sect int32_t addr = dereference_integer(section_begin); if (generate && addr < 0) { - std::wstringstream ss; - ss << L"Section start cannot be negative. It is evaluated to " << addr << L"."; + std::stringstream ss; + ss << "Section start cannot be negative. It is evaluated to " << addr << "."; report_error(expression_header->source_location, AssemblyErrorCodes::SectionStartCannotBeNegative, ss.str()); } @@ 166,8 168,8 @@ const SyntaxToken *Assembler::parse_sect _section->bss_length = 0; } else { if (generate) { - std::wstringstream ss; - ss << L"Expecting integer value, but got " << to_string(section_begin.type) << L" value"; + std::stringstream ss; + ss << "Expecting integer value, but got " << to_string(section_begin.type) << " value"; report_error(expression_header->source_location, AssemblyErrorCodes::StatementExpectsIntegerArgument, ss.str()); } // we keep the program counter valid to avoid cases when cross references can't be resolved @@ 190,8 192,8 @@ const SyntaxToken *Assembler::parse_sect if (is_integer(section_end)) { _section->end_address = dereference_integer(section_end); } else { - std::wstringstream ss; - ss << L"Expecting integer value, but got " << to_string(section_end.type) << L" value"; + std::stringstream ss; + ss << "Expecting integer value, but got " << to_string(section_end.type) << " value"; report_error(expression_header->source_location, AssemblyErrorCodes::StatementExpectsIntegerArgument, ss.str()); _section->end_address = static_cast<int32_t>(0x7cbcbcbc); } @@ 199,8 201,8 @@ const SyntaxToken *Assembler::parse_sect int32_t b = _section->start_address; int32_t e = _section->end_address; if (e < b) { - std::wstringstream ss; - ss << L"Section end address " << e << " must be after the section start address " << b << L"."; + std::stringstream ss; + ss << "Section end address " << e << " must be after the section start address " << b << "."; report_error(expression_header->source_location, AssemblyErrorCodes::SectionEndMustBeHigherThanBegin, ss.str()); _section->end_address = static_cast<int32_t>(0x7cbcbcbc); } @@ 276,8 278,8 @@ const SyntaxToken *Assembler::parse_sect // verify that part is not within a section if (_section != nullptr) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Section part '" << _strings.get(section_token.name_hash) << L"' can't be defined inside another section."; + std::stringstream ss; + ss << "Section part '" << _strings.get(section_token.name_hash) << "' can't be defined inside another section."; report_fatal_error(section_token.source_location, AssemblyErrorCodes::PartSectionMustBeOuterSection, ss.str()); } @@ 292,8 294,8 @@ const SyntaxToken *Assembler::parse_sect Section *child = find_section(section_hash, parent); if (child == nullptr) { // We can't survive this gracefully so we must throw instead of reporting and continue. - std::wstringstream ss; - ss << L"Section part '" << _strings.get(source_section_hash) << L"' mapped to '" << _strings.get(section_hash) << L"' must refer to a previously defined section."; + std::stringstream ss; + ss << "Section part '" << _strings.get(source_section_hash) << "' mapped to '" << _strings.get(section_hash) << "' must refer to a previously defined section."; report_fatal_error(section_token.source_location, AssemblyErrorCodes::SectionPartMustReferToDefinedSection, ss.str()); } @@ 359,9 361,9 @@ const SyntaxToken *Assembler::parse_decl if (UNLIKELY(it != _symbol_environment.declared_symbol_hashes.end())) { // we have a duplicate if (generate) { - std::wstringstream ss; - ss << L"Duplicated declaration of " << _strings.get(name_hash) << L".\n"; - ss << _used_files[it->source_location.file_index] << L"(" << it->source_location.row << L"," << it->source_location.column << L") : First found here"; + std::stringstream ss; + ss << "Duplicated declaration of " << _strings.get(name_hash) << ".\n"; + ss << _used_files[it->source_location.file_index] << "(" << it->source_location.row << "," << it->source_location.column << ") : First found here"; report_error(decl_token.source_location, AssemblyErrorCodes::DuplicateDeclarations, ss.str()); } } @@ 390,8 392,8 @@ const SyntaxToken *Assembler::parse_decl // exporting variables is not allowed if (UNLIKELY(export_enabled && def_token->storage_type == StorageType::Variable)) { - std::wstringstream ss; - ss << variable_name(def_token->symbol, def_token->global) << L" cannot be exported since it is a variable."; + std::stringstream ss; + ss << variable_name(def_token->symbol, def_token->global) << " cannot be exported since it is a variable."; report_error(def_token->source_location, AssemblyErrorCodes::ExportingVariablesIsNotAllowed, ss.str()); } @@ 406,8 408,8 @@ const SyntaxToken *Assembler::parse_decl if (!is_string(symbol_name)) { if (generate) { - std::wstringstream ss; - ss << L"Symbol name must be a string, but was " << to_string(symbol_name.type) << L"."; + std::stringstream ss; + ss << "Symbol name must be a string, but was " << to_string(symbol_name.type) << "."; report_error(def_token->source_location, AssemblyErrorCodes::SymbolExpressionMustBeString, ss.str()); } t = consume_next_token(); // value expression @@ 415,11 417,11 @@ const SyntaxToken *Assembler::parse_decl } // verify string format - const std::wstring_view symbol_string = dereference_string(symbol_name); + const std::string_view symbol_string = dereference_string(symbol_name); if (!parse_symbol_string(symbol_string, symbol_hash, global)) { if (generate) { - std::wstringstream ss; - ss << L"Dynamic symbol name '" << symbol_string << L"' has an invalid format. It must begin with a letter or underscore and be followed by any number of letters, digits or underscores."; + std::stringstream ss; + ss << "Dynamic symbol name '" << symbol_string << "' has an invalid format. It must begin with a letter or underscore and be followed by any number of letters, digits or underscores."; report_error(def_token->source_location, AssemblyErrorCodes::SymbolStringHasInvalidFormat, ss.str()); } t = consume_next_token(); // value expression @@ 436,8 438,8 @@ const SyntaxToken *Assembler::parse_decl // exporting local variables is not allowed if (UNLIKELY(export_enabled && !global)) { - std::wstringstream ss; - ss << variable_name(symbol_hash, global) << L" cannot be exported since it is local."; + std::stringstream ss; + ss << variable_name(symbol_hash, global) << " cannot be exported since it is local."; report_error(def_token->source_location, AssemblyErrorCodes::ExportingLocalIsNotAllowed, ss.str()); } @@ 453,8 455,8 @@ const SyntaxToken *Assembler::parse_decl // check that addresses are integers if (generate && def_token->address) { if (!is_integer(new_value)) { - std::wstringstream ss; - ss << L"Address must be integer, but was " << to_string(new_value.type) << L"."; + std::stringstream ss; + ss << "Address must be integer, but was " << to_string(new_value.type) << "."; report_error(def_token->source_location, AssemblyErrorCodes::AddressMustBeInteger, ss.str()); } } @@ 475,6 477,78 @@ const SyntaxToken *Assembler::parse_decl #if SUPPORTS(M6502) +void Assembler::generate_subroutine_instruction(bool generate, int32_t address, const SourceLocation &source_location) +{ + // instructions are only allowed within code sections. + bool instructions_allowed = _section != nullptr && _section->section_type == SectionType::Code; + if (UNLIKELY(!instructions_allowed)) { + // this is an unrecoverable error + std::stringstream ss; + ss << "Instructions must be in a code section."; + report_fatal_error(source_location, AssemblyErrorCodes::CodeMustBeInCodeSection, ss.str()); + } + + // recursive data generation may not be safe + if (_data_generation_depth != 0) { + // this is an unrecoverable error + std::stringstream ss; + ss << "Recursive data generation isn't allowed."; + report_fatal_error(source_location, AssemblyErrorCodes::RecursiveDataGenerationNotAllowed, ss.str()); + } + + ScopeCounter<uint32_t> sc(_data_generation_depth); + + if (generate && address < 0) { + std::stringstream ss; + ss << "Addressing mode needs a positive argument. Argument value was evaluated to " << address << "."; + report_error(source_location, AssemblyErrorCodes::AddressingModeRequiresPositiveArgument, ss.str()); + } + + if (_multi_bank_mode) { + // in this mode, addresses gets truncated to support memory banks + address &= 0xffff; + } + + if (generate) { + if (address > 65535) { + std::stringstream ss; + ss << "Addressing mode needs a word size argument. Argument was evaluated to " << address << "."; + report_error(source_location, AssemblyErrorCodes::AddressingModeRequiresWordSizeArgument, ss.str()); + } + Section::Contents ending_instruction = Section::Contents::ContinueExecutionInstruction; + auto &data = _section->generated_data(ending_instruction); + data.push_back(opcode(InstructionType::Jsr, AddressingModeType::AbsoluteAddr)); + data.push_back(static_cast<uint8_t>(address)); + data.push_back(static_cast<uint8_t>(address >> 8)); + } + _program_counter.integer_value += 3; +} + +void Assembler::generate_instruction_data_label(bool generate, bool export_enabled, const InstructionToken &token, int address, int offset, uint8_t size) +{ + // exporting local variables is not allowed + if (generate && export_enabled && !token.global_data_label) { + std::stringstream ss; + ss << variable_name(token.data_label_symbol_hash, token.global_data_label) << " cannot be exported since it is local."; + report_error(token.address_label_location, AssemblyErrorCodes::ExportingLocalIsNotAllowed, ss.str()); + } + + if (create_label(generate, token.data_label_symbol_hash, token.global_data_label, StorageType::Constant, token.address_label_location)) { + Value &new_label = _current_pass.values.back(); + if (size == 1) { + set_byte_offset(new_label, address, offset); + } else if (size == 2) { + set_word_offset(new_label, address, offset); + } else { + assert(false); + } + new_label.set_contains_address(true); + if (export_enabled) { + new_label.set_is_public(true); + } + } +} + const SyntaxToken *Assembler::parse_instruction(bool generate, const SyntaxToken *t, bool export_enabled) { assert(t->type == SyntaxTokenType::Instruction); @@ 484,16 558,16 @@ const SyntaxToken *Assembler::parse_inst bool instructions_allowed = _section != nullptr && _section->section_type == SectionType::Code; if (UNLIKELY(!instructions_allowed)) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Instructions must be in a code section."; + std::stringstream ss; + ss << "Instructions must be in a code section."; report_fatal_error(instruction_token.source_location, AssemblyErrorCodes::CodeMustBeInCodeSection, ss.str()); } // recursive data generation may not be safe if (_data_generation_depth != 0) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Recursive data generation isn't allowed."; + std::stringstream ss; + ss << "Recursive data generation isn't allowed."; report_fatal_error(instruction_token.source_location, AssemblyErrorCodes::RecursiveDataGenerationNotAllowed, ss.str()); } ScopeCounter<uint32_t> sc(_data_generation_depth); @@ 515,24 589,6 @@ const SyntaxToken *Assembler::parse_inst return t; } - if (instruction_token.has_instruction_data_label) { - // exporting local variables is not allowed - if (export_enabled && !instruction_token.global_data_label) { - std::wstringstream ss; - ss << variable_name(instruction_token.data_label_symbol_hash, instruction_token.global_data_label) << L" cannot be exported since it is local."; - report_error(instruction_token.address_label_location, AssemblyErrorCodes::ExportingLocalIsNotAllowed, ss.str()); - } - - if (create_label(generate, instruction_token.data_label_symbol_hash, instruction_token.global_data_label, StorageType::Constant, instruction_token.address_label_location)) { - Value &new_label = _current_pass.values.back(); - set_integer(new_label, _program_counter.integer_value + 1); - new_label.set_contains_address(true); - if (export_enabled) { - new_label.set_is_public(true); - } - } - } - // in all other instructions, we have to parse the expression for the argument const ExpressionToken *expr = static_cast<const ExpressionToken *>(t); const Value argument = evaluate_expression(generate, t); @@ 547,8 603,8 @@ const SyntaxToken *Assembler::parse_inst argument_value = dereference_integer(argument); else if (!is_unknown(argument)) { if (generate) { - std::wstringstream ss; - ss << L"Addressing mode needs an integer value. Argument type was " << to_string(type_of_value(argument)) << L"."; + std::stringstream ss; + ss << "Addressing mode needs an integer value. Argument type was " << to_string(type_of_value(argument)) << "."; report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresIntegerArgument, ss.str()); } } @@ 557,21 613,25 @@ const SyntaxToken *Assembler::parse_inst if (generate) { // handle the case where the value doesn't fit in a byte if (argument_value < -128 || argument_value > 255) { - std::wstringstream ss; - ss << L"Addressing mode needs a byte size argument. Argument was evaluated to " << argument_value << L"."; + std::stringstream ss; + ss << "Addressing mode needs a byte size argument. Argument was evaluated to " << argument_value << "."; report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresByteSizeArgument, ss.str()); } auto &data = _section->generated_data(ending_instruction); data.push_back(opcode(instruction, AddressingModeType::Immediate)); data.push_back(static_cast<uint8_t>(argument_value)); } + if (UNLIKELY(instruction_token.has_instruction_data_label)) { + generate_instruction_data_label(generate, export_enabled, instruction_token, _program_counter.integer_value + 1, 0, 1); + } + _program_counter.integer_value += 2; return t; } if (generate && argument_value < 0) { - std::wstringstream ss; - ss << L"Addressing mode needs a positive argument. Argument value was evaluated to " << argument_value << L"."; + std::stringstream ss; + ss << "Addressing mode needs a positive argument. Argument value was evaluated to " << argument_value << "."; report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresPositiveArgument, ss.str()); } @@ 588,7 648,9 @@ const SyntaxToken *Assembler::parse_inst addr_mode = argument_value > 255 ? select_word_mode(addr_mode) : select_byte_mode(addr_mode); } - _section->generated_data(ending_instruction).push_back(opcode(instruction, mask_to_addressing_mode(addr_mode))); + if (generate) { + _section->generated_data(ending_instruction).push_back(opcode(instruction, mask_to_addressing_mode(addr_mode))); + } ++_program_counter.integer_value; if (addr_mode == AddressingModeMask::Zp @@ 599,12 661,15 @@ const SyntaxToken *Assembler::parse_inst { if (generate) { if (argument_value > 255) { - std::wstringstream ss; - ss << L"Addressing mode needs a byte size argument. Argument was evaluated to " << argument_value << L"."; + std::stringstream ss; + ss << "Addressing mode needs a byte size argument. Argument was evaluated to " << argument_value << "."; report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresByteSizeArgument, ss.str()); } _section->generated_data(ending_instruction).push_back(static_cast<uint8_t>(argument_value)); } + if (UNLIKELY(instruction_token.has_instruction_data_label)) { + generate_instruction_data_label(generate, export_enabled, instruction_token, _program_counter.integer_value, 0, 1); + } ++_program_counter.integer_value; return t; } @@ 616,14 681,17 @@ const SyntaxToken *Assembler::parse_inst { if (generate) { if (argument_value > 65535) { - std::wstringstream ss; - ss << L"Addressing mode needs a word size argument. Argument was evaluated to " << argument_value << L"."; + std::stringstream ss; + ss << "Addressing mode needs a word size argument. Argument was evaluated to " << argument_value << "."; report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresWordSizeArgument, ss.str()); } auto &data = _section->generated_data(ending_instruction); data.push_back(static_cast<uint8_t>(argument_value)); data.push_back(static_cast<uint8_t>(argument_value >> 8)); } + if (UNLIKELY(instruction_token.has_instruction_data_label)) { + generate_instruction_data_label(generate, export_enabled, instruction_token, _program_counter.integer_value, 0, 2); + } _program_counter.integer_value += 2; return t; } @@ 635,18 703,70 @@ const SyntaxToken *Assembler::parse_inst int32_t reference_addr = _program_counter.integer_value + 1; // program counter has already been increased once int32_t relative_addr = argument_value - reference_addr; if (relative_addr < -128 || relative_addr > 127) { - std::wstringstream ss; - ss << L"Relative address out of range. Offset is " << relative_addr << " and needs to be in a [-128..127] range."; + std::stringstream ss; + ss << "Relative address out of range. Offset is " << relative_addr << " and needs to be in a [-128..127] range."; report_error(expr->source_location, AssemblyErrorCodes::RelativeAddressOutOfRange, ss.str()); } _section->generated_data(ending_instruction).push_back(static_cast<uint8_t>(relative_addr)); } + if (UNLIKELY(instruction_token.has_instruction_data_label)) { + generate_instruction_data_label(generate, export_enabled, instruction_token, _program_counter.integer_value, 0, 1); + } ++_program_counter.integer_value; return t; } #elif SUPPORTS(Z80) +void Assembler::generate_subroutine_instruction(bool generate, int32_t address, const SourceLocation &source_location) +{ + // instructions are only allowed within code sections. + bool instructions_allowed = _section != nullptr && _section->section_type == SectionType::Code; + if (UNLIKELY(!instructions_allowed)) { + // this is an unrecoverable error + std::stringstream ss; + ss << "Instructions must be in a code section."; + report_fatal_error(source_location, AssemblyErrorCodes::CodeMustBeInCodeSection, ss.str()); + } + + // recursive data generation may not be safe + if (_data_generation_depth != 0) { + // this is an unrecoverable error + std::stringstream ss; + ss << "Recursive data generation isn't allowed."; + report_fatal_error(source_location, AssemblyErrorCodes::RecursiveDataGenerationNotAllowed, ss.str()); + } + + ScopeCounter<uint32_t> sc(_data_generation_depth); + + const InstructionOpCode &opcode_data = opcode(InstructionType::Call, 0); + uint8_t mutable_opcode_data[4]; + mutable_opcode_data[0] = opcode_data.op[0]; + mutable_opcode_data[1] = opcode_data.op[1]; + mutable_opcode_data[2] = opcode_data.op[2]; + mutable_opcode_data[3] = opcode_data.op[3]; + + if (generate) { + if (UNLIKELY(_multi_bank_mode && address >= 0)) { + address &= 0xffff; + } + if (address < -32768 || address > 65535) { + std::stringstream ss; + ss << "Addressing mode needs a word size argument. Argument was evaluated to " << address << "."; + report_error(source_location, AssemblyErrorCodes::AddressingModeRequiresWordSizeArgument, ss.str()); + } + mutable_opcode_data[opcode_data.offset_to_data[0] + 0] = static_cast<uint8_t>(address & 0xff); + mutable_opcode_data[opcode_data.offset_to_data[0] + 1] = static_cast<uint8_t>(address >> 8); + + Section::Contents ending_instruction = Section::Contents::ContinueExecutionInstruction; + auto &data = _section->generated_data(ending_instruction); + for(decltype(opcode_data.total_size) i = 0; i < opcode_data.total_size; ++i) { + data.push_back(mutable_opcode_data[i]); + } + } + _program_counter.integer_value += static_cast<int32_t>(opcode_data.total_size); +} + const SyntaxToken *Assembler::parse_instruction(bool generate, const SyntaxToken *t, bool export_enabled) { assert(t->type == SyntaxTokenType::Instruction); @@ 656,16 776,16 @@ const SyntaxToken *Assembler::parse_inst bool instructions_allowed = _section != nullptr && _section->section_type == SectionType::Code; if (UNLIKELY(!instructions_allowed)) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Instructions must be in a code section."; + std::stringstream ss; + ss << "Instructions must be in a code section."; report_fatal_error(instruction_token.source_location, AssemblyErrorCodes::CodeMustBeInCodeSection, ss.str()); } // recursive data generation may not be safe if (_data_generation_depth != 0) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Recursive data generation isn't allowed."; + std::stringstream ss; + ss << "Recursive data generation isn't allowed."; report_fatal_error(instruction_token.source_location, AssemblyErrorCodes::RecursiveDataGenerationNotAllowed, ss.str()); } ScopeCounter<uint32_t> sc(_data_generation_depth); @@ 674,6 794,12 @@ const SyntaxToken *Assembler::parse_inst const InstructionOpCode &opcode_data = opcode(instruction, instruction_token.addressing_mode_index); Section::Contents ending_instruction = is_ending_instruction(instruction) ? Section::Contents::EndExecutionInstruction : Section::Contents::ContinueExecutionInstruction; + if (UNLIKELY(generate && !_pseudo_instructions && opcode_data.category == InstructionCategory::Pseudo)) { + std::stringstream ss; + ss << "Pseudo instructions require the pseudo instruction mode to be enabled."; + report_error(instruction_token.source_location, AssemblyErrorCodes::UseOfPseudoInstructionInStandardMode, ss.str()); + } + t = consume_next_token(); // instruction // in the generation pass, the program counter is guaranteed to be an integer value @@ 683,25 809,32 @@ const SyntaxToken *Assembler::parse_inst for(int i = 0; i < 2; ++i) { if (UNLIKELY(instruction_token.has_instruction_data_label[i])) { // verify that the data label is valid for the addressing mode (can point to actual data) - if (argument_has_data(i, opcode_data)) { + uint8_t data_size = argument_data_size(i, opcode_data); + if (data_size != 0) { // exporting local variables is not allowed if (export_enabled && !instruction_token.global_data_label[i]) { - std::wstringstream ss; - ss << variable_name(instruction_token.data_label_symbol_hash[i], instruction_token.global_data_label[i]) << L" cannot be exported since it is local."; + std::stringstream ss; + ss << variable_name(instruction_token.data_label_symbol_hash[i], instruction_token.global_data_label[i]) << " cannot be exported since it is local."; report_error(instruction_token.address_label_location[i], AssemblyErrorCodes::ExportingLocalIsNotAllowed, ss.str()); } if (create_label(generate, instruction_token.data_label_symbol_hash[i], instruction_token.global_data_label[i], StorageType::Constant, instruction_token.address_label_location[i])) { Value &new_label = _current_pass.values.back(); - set_integer(new_label, _program_counter.integer_value + argument_data_offset(i, opcode_data)); + if (data_size == 1) { + set_byte_offset(new_label, _program_counter.integer_value + argument_data_offset(i, opcode_data), 0); + } else if (data_size == 2) { + set_word_offset(new_label, _program_counter.integer_value + argument_data_offset(i, opcode_data), 0); + } else { + assert(false); + } new_label.set_contains_address(true); if (export_enabled) { new_label.set_is_public(true); } } } else { - std::wstringstream ss; - ss << L"Addressing mode argument cannot have label to instruction data."; + std::stringstream ss; + ss << "Addressing mode argument cannot have label to instruction data."; report_error(instruction_token.address_label_location[i], AssemblyErrorCodes::AddressingModeArgumentCannotHaveDataLabel, ss.str()); } } @@ 727,8 860,8 @@ const SyntaxToken *Assembler::parse_inst case OpCodeFormat::ByteArg: if (generate) { if (arg1 < -128 || arg1 > 255) { - std::wstringstream ss; - ss << L"Addressing mode needs a byte size argument. Argument was evaluated to " << arg1 << L"."; + std::stringstream ss; + ss << "Addressing mode needs a byte size argument. Argument was evaluated to " << arg1 << "."; report_error(expr1->source_location, AssemblyErrorCodes::AddressingModeRequiresByteSizeArgument, ss.str()); } mutable_opcode_data[opcode_data.offset_to_data[0]] = static_cast<uint8_t>(arg1); @@ 740,8 873,8 @@ const SyntaxToken *Assembler::parse_inst arg1 &= 0xffff; } if (arg1 < -32768 || arg1 > 65535) { - std::wstringstream ss; - ss << L"Addressing mode needs a word size argument. Argument was evaluated to " << arg1 << L"."; + std::stringstream ss; + ss << "Addressing mode needs a word size argument. Argument was evaluated to " << arg1 << "."; report_error(expr1->source_location, AssemblyErrorCodes::AddressingModeRequiresWordSizeArgument, ss.str()); } mutable_opcode_data[opcode_data.offset_to_data[0] + 0] = static_cast<uint8_t>(arg1 & 0xff); @@ 751,8 884,8 @@ const SyntaxToken *Assembler::parse_inst case OpCodeFormat::OffsetArg: if (generate) { if (arg1 < -128 || arg1 > 127) { - std::wstringstream ss; - ss << L"Addressing mode needs an offset in range [-128..127]. Argument was evaluated to " << arg1 << L"."; + std::stringstream ss; + ss << "Addressing mode needs an offset in range [-128..127]. Argument was evaluated to " << arg1 << "."; report_error(expr1->source_location, AssemblyErrorCodes::AddressingModeRequiresOffsetSizeArgument, ss.str()); } mutable_opcode_data[opcode_data.offset_to_data[0]] = static_cast<uint8_t>(arg1); @@ 767,13 900,13 @@ const SyntaxToken *Assembler::parse_inst if (generate) { if (arg1 < -128 || arg1 > 127) { - std::wstringstream ss; - ss << L"Addressing mode needs an offset in range [-128..127]. Argument was evaluated to " << arg1 << L"."; + std::stringstream ss; + ss << "Addressing mode needs an offset in range [-128..127]. Argument was evaluated to " << arg1 << "."; report_error(expr1->source_location, AssemblyErrorCodes::AddressingModeRequiresOffsetSizeArgument, ss.str()); } if (arg2 < -128 || arg2 > 255) { - std::wstringstream ss; - ss << L"Addressing mode needs a byte size argument. Argument was evaluated to " << arg2 << L"."; + std::stringstream ss; + ss << "Addressing mode needs a byte size argument. Argument was evaluated to " << arg2 << "."; report_error(expr2->source_location, AssemblyErrorCodes::AddressingModeRequiresByteSizeArgument, ss.str()); } @@ 786,8 919,8 @@ const SyntaxToken *Assembler::parse_inst { if (generate) { if (arg1 < 0 || arg1 > 2) { - std::wstringstream ss; - ss << L"Addressing mode needs an interrupt mode in range [0..2]. Argument was evaluated to " << arg1 << L"."; + std::stringstream ss; + ss << "Addressing mode needs an interrupt mode in range [0..2]. Argument was evaluated to " << arg1 << "."; report_error(expr1->source_location, AssemblyErrorCodes::AddressingModeRequiresByteSizeArgument, ss.str()); } uint8_t opcode_part = 0; @@ 806,8 939,8 @@ const SyntaxToken *Assembler::parse_inst { if (generate) { if (arg1 < 0 || arg1 > 7) { - std::wstringstream ss; - ss << L"Addressing mode needs a bit argument in range [0..7]. Argument was evaluated to " << arg1 << L"."; + std::stringstream ss; + ss << "Addressing mode needs a bit argument in range [0..7]. Argument was evaluated to " << arg1 << "."; report_error(expr1->source_location, AssemblyErrorCodes::AddressingModeRequiresBitArgument, ss.str()); } size_t bit_argument_offset = opcode_data.total_size - 1; // the bit is always placed in the last opcode byte @@ 824,13 957,13 @@ const SyntaxToken *Assembler::parse_inst if (generate) { if (arg1 < 0 || arg1 > 7) { - std::wstringstream ss; - ss << L"Addressing mode needs a bit argument in range [0..7]. Argument was evaluated to " << arg1 << L"."; + std::stringstream ss; + ss << "Addressing mode needs a bit argument in range [0..7]. Argument was evaluated to " << arg1 << "."; report_error(expr1->source_location, AssemblyErrorCodes::AddressingModeRequiresBitArgument, ss.str()); } if (arg2 < -128 || arg2 > 127) { - std::wstringstream ss; - ss << L"Addressing mode needs an offset in range [-128..127]. Argument was evaluated to " << arg2 << L"."; + std::stringstream ss; + ss << "Addressing mode needs an offset in range [-128..127]. Argument was evaluated to " << arg2 << "."; report_error(expr2->source_location, AssemblyErrorCodes::AddressingModeRequiresOffsetSizeArgument, ss.str()); } mutable_opcode_data[opcode_data.offset_to_data[0]] = static_cast<uint8_t>(arg2); @@ 843,8 976,8 @@ const SyntaxToken *Assembler::parse_inst if (generate) { int32_t relative_offset = arg1 - (_program_counter.integer_value + 2); if (relative_offset < -128 || relative_offset > 127) { - std::wstringstream ss; - ss << L"Relative address out of range. Offset is " << relative_offset << " and needs to be in a [-128..127] range."; + std::stringstream ss; + ss << "Relative address out of range. Offset is " << relative_offset << " and needs to be in a [-128..127] range."; report_error(expr1->source_location, AssemblyErrorCodes::RelativeAddressOutOfRange, ss.str()); } mutable_opcode_data[opcode_data.offset_to_data[0]] = static_cast<uint8_t>(relative_offset); @@ 853,8 986,8 @@ const SyntaxToken *Assembler::parse_inst case OpCodeFormat::PageZeroArg: if (generate) { if ((arg1 & (~0b111000)) != 0) { - std::wstringstream ss; - ss << L"Zero page address must be 0, 8, 16, 24, 32, 40, 48, 56. Argument was evaluated to " << arg1 << L"."; + std::stringstream ss; + ss << "Zero page address must be 0, 8, 16, 24, 32, 40, 48, 56. Argument was evaluated to " << arg1 << "."; report_error(expr1->source_location, AssemblyErrorCodes::AddressingModeRequiresZeroPageArgument, ss.str()); } mutable_opcode_data[0] |= static_cast<uint8_t>(mutable_opcode_data[0] | arg1); @@ 903,8 1036,8 @@ bool Assembler::resolve_type_hash(bool g if (!is_member_of(symbol_value.type, value_group_typename)) { // didn't refer to a typename if (generate) { - std::wstringstream ss; - ss << L"Expected typename but got " << to_string(symbol_value.type) << L"."; + std::stringstream ss; + ss << "Expected typename but got " << to_string(symbol_value.type) << "."; report_error(source_location, AssemblyErrorCodes::ExpectedTypename, ss.str()); } return false; @@ 914,7 1047,7 @@ bool Assembler::resolve_type_hash(bool g // generate a type description from the struct // set underlying_type_hash to it assert(false); - throw Exception(L"not implemented"); + throw Exception("not implemented"); } else { type_hash = symbol_value.type_hash; } @@ 922,7 1055,7 @@ bool Assembler::resolve_type_hash(bool g return true; } - UNREACHABLE_CODE(throw Exception(L"internal error")); + UNREACHABLE_CODE(throw Exception("internal error")); } bool Assembler::fill_offset_value(bool generate, const TypeReference &type_reference, int32_t array_length, const SourceLocation &source_location, Value &value) @@ 961,8 1094,8 @@ const SyntaxToken *Assembler::parse_arra if (!is_integer(length_value)) { if (generate) { - std::wstringstream ss; - ss << L"Array index must be an integer. The type is " << to_string(length_value.type) << L"."; + std::stringstream ss; + ss << "Array index must be an integer. The type is " << to_string(length_value.type) << "."; report_error(expr.source_location, AssemblyErrorCodes::ArrayLengthMustBeInteger, ss.str()); } success = false; @@ 972,8 1105,8 @@ const SyntaxToken *Assembler::parse_arra array_length = dereference_integer(length_value); if (array_length < min_length) { if (generate) { - std::wstringstream ss; - ss << L"Array index must be " << min_length << L" or greater. It is evaluated to " << array_length << L"."; + std::stringstream ss; + ss << "Array index must be " << min_length << " or greater. It is evaluated to " << array_length << "."; report_error(expr.source_location, AssemblyErrorCodes::ArrayLengthMustBePositive, ss.str()); } success = false; @@ 991,15 1124,15 @@ const SyntaxToken *Assembler::parse_rese bool reserve_allowed = _section != nullptr && _section->section_type == SectionType::Bss; if (UNLIKELY(!reserve_allowed)) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Space reservations must be in a bss section."; + std::stringstream ss; + ss << "Space reservations must be in a bss section."; report_fatal_error(reserve.keyword_location, AssemblyErrorCodes::ReservationsMustBeInBssSections, ss.str()); } // exporting local variables is not allowed if (export_enabled && !reserve.global) { - std::wstringstream ss; - ss << variable_name(reserve.name_hash, reserve.global) << L" cannot be exported since it is local."; + std::stringstream ss; + ss << variable_name(reserve.name_hash, reserve.global) << " cannot be exported since it is local."; report_error(reserve.source_location, AssemblyErrorCodes::ExportingLocalIsNotAllowed, ss.str()); } @@ 1105,8 1238,8 @@ const SyntaxToken *Assembler::parse_defi if (t->type == SyntaxTokenType::Expression) { if (generate) { const ExpressionToken &expr = *static_cast<const ExpressionToken *>(t); - std::wstringstream ss; - ss << L"Expected array definition."; + std::stringstream ss; + ss << "Expected array definition."; report_error(expr.source_location, AssemblyErrorCodes::ExpectedArrayDefinition, ss.str()); } success = false; @@ 1119,8 1252,8 @@ const SyntaxToken *Assembler::parse_defi if (!is_fixed_array && group->repeated_pattern) { if (generate) { - std::wstringstream ss; - ss << L"Array definition with repeating pattern must have specified size."; + std::stringstream ss; + ss << "Array definition with repeating pattern must have specified size."; report_error(group->source_location, AssemblyErrorCodes::DynamicArrayCantHaveRepeatingPattern, ss.str()); } success = false; @@ 1148,8 1281,8 @@ const SyntaxToken *Assembler::parse_defi assert(t->type == SyntaxTokenType::DefineGroup); const DefineGroupToken *g = static_cast<const DefineGroupToken *>(t); if (generate) { - std::wstringstream ss; - ss << L"Expected single value definition but found start of group."; + std::stringstream ss; + ss << "Expected single value definition but found start of group."; report_error(g->source_location, AssemblyErrorCodes::ExpectedSingleValueDefinition, ss.str()); } success = false; @@ 1163,10 1296,13 @@ const SyntaxToken *Assembler::parse_defi // special case for arrays of fundamental types, which supports strings as input if (is_string(expr_value)) { // define a range of objects - std::wstring_view s = dereference_string(expr_value); - - for(wchar_t c : s) { - if (!define_single_fundamental_type(generate, element_type.type, static_cast<int32_t>(c), expr->source_location)) { + std::string_view s = dereference_string(expr_value); + wchar_t wide = 0; + const char *source = s.data(); + size_t source_size = s.size(); + while(source_size != 0) { + core::utf8_to_wide(source, source_size, wide); + if (!define_single_fundamental_type(generate, element_type.type, static_cast<int32_t>(wide), expr->source_location)) { success = false; return t; } @@ 1185,8 1321,8 @@ const SyntaxToken *Assembler::parse_defi // check upper bounds on array in case it isn't a repeated pattern if (!group->repeated_pattern && is_fixed_array && defined_array_elements > array_length) { if (generate) { - std::wstringstream ss; - ss << L"Number of values in array exceeds array length."; + std::stringstream ss; + ss << "Number of values in array exceeds array length."; report_error(expr->source_location, AssemblyErrorCodes::NoOfValuesExceedArray, ss.str()); } success = false; @@ 1236,12 1372,12 @@ const SyntaxToken *Assembler::parse_defi } else if (is_fixed_array && defined_array_elements != array_length) { if (generate) { - std::wstringstream ss; - ss << L"Too few values to match array length. Array has size " << array_length << L" but there "; + std::stringstream ss; + ss << "Too few values to match array length. Array has size " << array_length << " but there "; if (defined_array_elements == 1) { - ss << L"is only 1 value"; + ss << "is only 1 value"; } else { - ss << L"are " << defined_array_elements << L" values."; + ss << "are " << defined_array_elements << " values."; } report_error(group->source_location, AssemblyErrorCodes::NoOfValuesTooFewForArray, ss.str()); } @@ 1260,8 1396,8 @@ bool Assembler::verify_integer_in_range( { if (value < low || value > high) { if (generate) { - std::wstringstream ss; - ss << L"Value is outside [" << low << L".." << high << L"] range. Value was evaluated to " << value << L'.'; + std::stringstream ss; + ss << "Value is outside [" << low << ".." << high << "] range. Value was evaluated to " << value << '.'; report_error(source_location, AssemblyErrorCodes::IntegerValueOutOfRange, ss.str()); } return false; @@ 1273,8 1409,8 @@ bool Assembler::verify_integer_type(bool { if (!is_integer(value)) { if (generate) { - std::wstringstream ss; - ss << L"Integer value was expected but got " << to_string(value.type) << L'.'; + std::stringstream ss; + ss << "Integer value was expected but got " << to_string(value.type) << '.'; report_error(source_location, AssemblyErrorCodes::IntegerValueExpected, ss.str()); } return false; @@ 1332,7 1468,7 @@ bool Assembler::verify_and_define_object } else if (type_desc.type == ValueType::StructOffset) { assert(false); - throw Exception(L"not implemented"); + throw Exception("not implemented"); } else { assert(false); return false; @@ 1349,8 1485,8 @@ const SyntaxToken *Assembler::parse_defi if (t->type == SyntaxTokenType::DefineGroup) { if (generate) { const DefineGroupToken &group = *static_cast<const DefineGroupToken *>(t); - std::wstringstream ss; - ss << L"Expected single value definition."; + std::stringstream ss; + ss << "Expected single value definition."; report_error(group.source_location, AssemblyErrorCodes::ExpectedSingleValueDefinition, ss.str()); } success = false; @@ 1379,24 1515,24 @@ const SyntaxToken *Assembler::parse_defi bool data_allowed = _section != nullptr && _section->section_type == SectionType::Code; if (UNLIKELY(!data_allowed)) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Data must be in a code section."; + std::stringstream ss; + ss << "Data must be in a code section."; report_fatal_error(define.keyword_location, AssemblyErrorCodes::DataMustBeInCodeSection, ss.str()); } // recursive data generation may not be safe if (_data_generation_depth != 0) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Recursive data generation isn't allowed."; + std::stringstream ss; + ss << "Recursive data generation isn't allowed."; report_fatal_error(define.source_location, AssemblyErrorCodes::RecursiveDataGenerationNotAllowed, ss.str()); } ScopeCounter<uint32_t> sc(_data_generation_depth); // exporting local variables is not allowed if (export_enabled && !define.global) { - std::wstringstream ss; - ss << variable_name(define.name_hash, define.global) << L" cannot be exported since it is local."; + std::stringstream ss; + ss << variable_name(define.name_hash, define.global) << " cannot be exported since it is local."; report_error(define.source_location, AssemblyErrorCodes::ExportingLocalIsNotAllowed, ss.str()); } @@ 1471,8 1607,8 @@ const SyntaxToken *Assembler::parse_macr // exporting local variables is not allowed if (export_enabled && !macro.global) { - std::wstringstream ss; - ss << variable_name(macro.name_hash, macro.global) << L" cannot be exported since it is local."; + std::stringstream ss; + ss << variable_name(macro.name_hash, macro.global) << " cannot be exported since it is local."; report_error(macro.source_location, AssemblyErrorCodes::ExportingLocalIsNotAllowed, ss.str()); } @@ 1562,7 1698,7 @@ const SyntaxToken *Assembler::parse_rang uint64_t scope_hash = _symbol_environment.local_symbol_scope_stack.back(); uint64_t combined_hash = murmur_hash3_x64_64(&loop_counter, sizeof(loop_counter), scope_hash); if (UNLIKELY(_dump_symbols)) - combine_and_store_hash_name(scope_hash, combined_hash, L"loop" + std::to_wstring(loop_counter)); + combine_and_store_hash_name(scope_hash, combined_hash, "loop" + std::to_string(loop_counter)); const bool uses_loop_variable = false; enter_variable_scope(combined_hash, uses_loop_variable); @@ 1578,7 1714,7 @@ const SyntaxToken *Assembler::parse_rang _current_pass.value_lookup[symbol_hash] = new_variable_index; // add the loop iteration variable @i for convenience - uint64_t loop_symbol = hash_constant(0x1ded7765ceceebccULL, L"@i"); + uint64_t loop_symbol = hash_constant(0x2d8619a103210bb8ULL, "@i"); constexpr bool global = false; Value &iteration_value = create_unique_label(loop_symbol, global); set_integer(iteration_value, loop_counter); @@ 1639,7 1775,7 @@ const SyntaxToken *Assembler::parse_rang uint64_t scope_hash = _symbol_environment.local_symbol_scope_stack.back(); uint64_t combined_hash = murmur_hash3_x64_64(&loop_counter, sizeof(loop_counter), scope_hash); if (UNLIKELY(_dump_symbols)) - combine_and_store_hash_name(scope_hash, combined_hash, L"loop" + std::to_wstring(loop_counter)); + combine_and_store_hash_name(scope_hash, combined_hash, "loop" + std::to_string(loop_counter)); const bool uses_loop_variable = false; enter_variable_scope(combined_hash, uses_loop_variable); @@ 1692,8 1828,8 @@ const SyntaxToken *Assembler::parse_rang t = parse_range_map_loop(generate, t, loop_collection_value, loop_token, early_return); } else { if (generate) { - std::wstringstream ss; - ss << L"Range-based for statement requires iterable type with value pairs, but found " << to_string(loop_collection_value.type) << L'.'; + std::stringstream ss; + ss << "Range-based for statement requires iterable type with value pairs, but found " << to_string(loop_collection_value.type) << '.'; report_error(range_expression.source_location, AssemblyErrorCodes::RangeBasedForRequiresPairEnumeration, ss.str()); } } @@ 1702,8 1838,8 @@ const SyntaxToken *Assembler::parse_rang t = parse_range_list_loop(generate, t, loop_collection_value, loop_token, early_return); } else { if (generate) { - std::wstringstream ss; - ss << L"Range-based for statement requires iterable type with single element values, but found " << to_string(loop_collection_value.type) << L'.'; + std::stringstream ss; + ss << "Range-based for statement requires iterable type with single element values, but found " << to_string(loop_collection_value.type) << '.'; report_error(range_expression.source_location, AssemblyErrorCodes::RangeBasedForRequiresSingleValueEnumeration, ss.str()); } } @@ 1745,8 1881,8 @@ const SyntaxToken *Assembler::parse_for_ // A million iterations seems like a lot. // The loop must be broken. const ExpressionToken *expr = static_cast<const ExpressionToken *>(t); - std::wstringstream ss; - ss << L"For loop ran a million loops. There doesn't seem to be an end to this."; + std::stringstream ss; + ss << "For loop ran a million loops. There doesn't seem to be an end to this."; report_error(expr->source_location, AssemblyErrorCodes::ForLoopSanityCheckTriggered, ss.str()); break; } @@ 1756,8 1892,8 @@ const SyntaxToken *Assembler::parse_for_ if (!is_boolean(condition_value)) { if (generate) { const ExpressionToken *expr = static_cast<const ExpressionToken *>(t); - std::wstringstream ss; - ss << L"For loop condition must be boolean, but got " << to_string(condition_value.type) << L" instead."; + std::stringstream ss; + ss << "For loop condition must be boolean, but got " << to_string(condition_value.type) << " instead."; report_error(expr->source_location, AssemblyErrorCodes::ForLoopNeedsBooleanCondition, ss.str()); } break; @@ 1775,7 1911,7 @@ const SyntaxToken *Assembler::parse_for_ uint64_t scope_hash = _symbol_environment.local_symbol_scope_stack.back(); uint64_t combined_hash = murmur_hash3_x64_64(&loop_counter, sizeof(loop_counter), scope_hash); if (UNLIKELY(_dump_symbols)) - combine_and_store_hash_name(scope_hash, combined_hash, L"loop" + std::to_wstring(loop_counter)); + combine_and_store_hash_name(scope_hash, combined_hash, "loop" + std::to_string(loop_counter)); const bool uses_loop_variable = false; enter_variable_scope(combined_hash, uses_loop_variable); @@ 1854,7 1990,7 @@ const SyntaxToken *Assembler::parse_repe { uint64_t combined_hash = murmur_hash3_x64_64(&loop_counter, sizeof(loop_counter), scope_hash); if (UNLIKELY(_dump_symbols)) - combine_and_store_hash_name(scope_hash, combined_hash, L"loop" + std::to_wstring(loop_counter)); + combine_and_store_hash_name(scope_hash, combined_hash, "loop" + std::to_string(loop_counter)); const bool uses_loop_variable = false; enter_variable_scope(combined_hash, uses_loop_variable); @@ 1862,7 1998,7 @@ const SyntaxToken *Assembler::parse_repe // execute inner scope and inject the loop variable auto inject_variable = [this, loop_counter] { - uint64_t loop_symbol = hash_constant(0x1ded7765ceceebccULL, L"@i"); + uint64_t loop_symbol = hash_constant(0x2d8619a103210bb8ULL, "@i"); constexpr bool global = false; Value &new_value = create_unique_label(loop_symbol, global); set_integer(new_value, loop_counter); @@ 1884,8 2020,8 @@ const SyntaxToken *Assembler::parse_repe } else { if (generate) { const ExpressionToken *expr = static_cast<const ExpressionToken *>(t); - std::wstringstream ss; - ss << L"Repeat loops value must be integer, but was " << to_string(loops_value.type) << L" instead."; + std::stringstream ss; + ss << "Repeat loops value must be integer, but was " << to_string(loops_value.type) << " instead."; report_error(expr->source_location, AssemblyErrorCodes::RepeatLoopsMustBeInteger, ss.str()); } } @@ 1902,8 2038,8 @@ const SyntaxToken *Assembler::parse_enum // exporting local variables is not allowed if (export_enabled && !enum_def.global) { - std::wstringstream ss; - ss << variable_name(enum_def.name_hash, enum_def.global) << L" cannot be exported since it is local."; + std::stringstream ss; + ss << variable_name(enum_def.name_hash, enum_def.global) << " cannot be exported since it is local."; report_error(enum_def.source_location, AssemblyErrorCodes::ExportingLocalIsNotAllowed, ss.str()); } @@ 1966,8 2102,8 @@ const SyntaxToken *Assembler::parse_enum enumeration_is_valid = false; if (generate) { const ExpressionToken *expr = static_cast<const ExpressionToken *>(t); - std::wstringstream ss; - ss << L"Enum values must be integers, but got " << to_string(member_value.type) << L"."; + std::stringstream ss; + ss << "Enum values must be integers, but got " << to_string(member_value.type) << "."; report_error(expr->source_location, AssemblyErrorCodes::EnumValuesMustBeInteger, ss.str()); } set_unknown(enum_object->values[i]); @@ 1998,16 2134,16 @@ const SyntaxToken *Assembler::parse_alig bool align_allowed = _section != nullptr; if (UNLIKELY(!align_allowed)) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Align must be in a section."; + std::stringstream ss; + ss << "Align must be in a section."; report_fatal_error(align_token.source_location, AssemblyErrorCodes::AlignMustBeInSection, ss.str()); } // recursive data generation may not be safe if (_data_generation_depth != 0) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Recursive data generation isn't allowed."; + std::stringstream ss; + ss << "Recursive data generation isn't allowed."; report_fatal_error(align_token.source_location, AssemblyErrorCodes::RecursiveDataGenerationNotAllowed, ss.str()); } ScopeCounter<uint32_t> sc(_data_generation_depth); @@ 2023,8 2159,8 @@ const SyntaxToken *Assembler::parse_alig if (!is_integer(value)) { if (generate) { - std::wstringstream ss; - ss << L"Align needs integer argument, but got " << to_string(value.type) << L"."; + std::stringstream ss; + ss << "Align needs integer argument, but got " << to_string(value.type) << "."; report_error(expr.source_location, AssemblyErrorCodes::AlignValueMustBeInteger, ss.str()); } @@ 2038,8 2174,8 @@ const SyntaxToken *Assembler::parse_alig int32_t alignment = dereference_integer(value); if (alignment < 1 || alignment > 0x10000) { if (generate) { - std::wstringstream ss; - ss << L"Align needs integer argument in range [1..65536], but got " << alignment << L"."; + std::stringstream ss; + ss << "Align needs integer argument in range [1..65536], but got " << alignment << "."; report_error(expr.source_location, AssemblyErrorCodes::AlignValueOutOfRange, ss.str()); } @@ 2060,8 2196,8 @@ const SyntaxToken *Assembler::parse_alig t = consume_next_token(); if (UNLIKELY(_section->section_type != SectionType::Code)) { if (generate) { - std::wstringstream ss; - ss << L"Align can only fill with specific data in code sections."; + std::stringstream ss; + ss << "Align can only fill with specific data in code sections."; report_error(fill_expr.source_location, AssemblyErrorCodes::AlignCanOnlyUseFillByteInCodeSections, ss.str()); } } @@ 2137,8 2273,8 @@ const SyntaxToken *Assembler::parse_usin if (generate) { // since last pass was identical to the current, only the last pass namespaces needs to be considered if (_previous_pass.namespaces.find(combined_hash) == _previous_pass.namespaces.end()) { - std::wstringstream ss; - ss << L"Using an undefined namespace."; + std::stringstream ss; + ss << "Using an undefined namespace."; report_error(using_token.source_location, AssemblyErrorCodes::UsingUndefinedNamespace, ss.str()); } } @@ 2226,8 2362,8 @@ const SyntaxToken *Assembler::parse_modu } if (generate && new_import_value.type == ValueType::Unknown) { - std::wstringstream ss; - ss << L"Import value '" << _strings.get(import_hash) << L"' was never assigned."; + std::stringstream ss; + ss << "Import value '" << _strings.get(import_hash) << "' was never assigned."; report_error(mt.imports_location, AssemblyErrorCodes::ImportValueNeverAssigned, ss.str()); } } @@ 2273,15 2409,15 @@ const SyntaxToken *Assembler::parse_subr // subroutines are only allowed within code or bss sections. if (UNLIKELY(_section == nullptr)) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Subroutine must be in a section."; + std::stringstream ss; + ss << "Subroutine must be in a section."; report_fatal_error(subroutine.source_location, AssemblyErrorCodes::SubroutineMustBeInSection, ss.str()); } // exporting local variables is not allowed if (export_enabled && !subroutine.global) { - std::wstringstream ss; - ss << variable_name(subroutine.name_hash, subroutine.global) << L" cannot be exported since it is local."; + std::stringstream ss; + ss << variable_name(subroutine.name_hash, subroutine.global) << " cannot be exported since it is local."; report_error(subroutine.source_location, AssemblyErrorCodes::ExportingLocalIsNotAllowed, ss.str()); } @@ 2295,8 2431,8 @@ const SyntaxToken *Assembler::parse_subr assert(!early_return); // subroutines are not allowed within macros so this should not happen if (generate && (_section->last_subroutine_generated_data == Section::Contents::ContinueExecutionInstruction || _section->last_subroutine_generated_data == Section::Contents::Nothing)) { - std::wstringstream ss; - ss << L"Code in subroutine " << variable_name(subroutine.name_hash, subroutine.global) << L" falls through at end of subroutine."; + std::stringstream ss; + ss << "Code in subroutine " << variable_name(subroutine.name_hash, subroutine.global) << " falls through at end of subroutine."; report_warning(subroutine.source_location, AssemblyErrorCodes::SubroutineFallthrough, ss.str()); } @@ 2304,7 2440,7 @@ const SyntaxToken *Assembler::parse_subr create_label(generate, subroutine.name_hash, subroutine.global, StorageType::Constant, subroutine.source_location); // ignore if it was unique Value &value = _current_pass.values.back(); - set_range(value, start_address, _program_counter.integer_value - start_address); + set_subroutine(value, start_address, _program_counter.integer_value - start_address); value.set_contains_address(true); // mark as address if (export_enabled) value.set_is_public(true); @@ 2320,16 2456,16 @@ const SyntaxToken *Assembler::parse_incb bool incbin_allowed = _section != nullptr && _section->section_type == SectionType::Code; if (UNLIKELY(!incbin_allowed)) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Incbin must be in a code section."; + std::stringstream ss; + ss << "Incbin must be in a code section."; report_fatal_error(incbin.keyword_location, AssemblyErrorCodes::IncbinMustBeInCodeSection, ss.str()); } // recursive data generation may not be safe if (_data_generation_depth != 0) { // this is an unrecoverable error - std::wstringstream ss; - ss << L"Recursive data generation isn't allowed."; + std::stringstream ss; + ss << "Recursive data generation isn't allowed."; report_fatal_error(incbin.keyword_location, AssemblyErrorCodes::RecursiveDataGenerationNotAllowed, ss.str()); } ScopeCounter<uint32_t> sc(_data_generation_depth); @@ 2347,8 2483,8 @@ const SyntaxToken *Assembler::parse_incb if (!is_integer(offset_value)) { if (generate) { - std::wstringstream ss; - ss << L"Incbin expects integer offset but got " << to_string(offset_value.type) << L"."; + std::stringstream ss; + ss << "Incbin expects integer offset but got " << to_string(offset_value.type) << "."; report_fatal_error(offset_expression.source_location, AssemblyErrorCodes::StatementExpectsIntegerArgument, ss.str()); } if (incbin.has_max_size) { @@ 2367,8 2503,8 @@ const SyntaxToken *Assembler::parse_incb t = consume_next_token(); if (!is_integer(max_size_value)) { if (generate) { - std::wstringstream ss; - ss << L"Incbin expects integer max size but got " << to_string(max_size_value.type) << L"."; + std::stringstream ss; + ss << "Incbin expects integer max size but got " << to_string(max_size_value.type) << "."; report_fatal_error(max_size_expression.source_location, AssemblyErrorCodes::StatementExpectsIntegerArgument, ss.str()); } return t; @@ 2467,8 2603,8 @@ const SyntaxToken *Assembler::parse_stat case SyntaxTokenType::Debug: #endif { - std::wstringstream ss; - ss << L"Expected a symbol generating statement after export."; + std::stringstream ss; + ss << "Expected a symbol generating statement after export."; report_fatal_error(location, AssemblyErrorCodes::ExpectedSymbolGeneratorAfterExport, ss.str()); } } @@ 2583,7 2719,7 @@ const SyntaxToken *Assembler::parse_stat case SyntaxTokenType::Optimize: case SyntaxTokenType::StructDef: case SyntaxTokenType::StructMember: - throw Exception(L"not implemented"); + throw Exception("not implemented"); case SyntaxTokenType::Else: case SyntaxTokenType::Elif: @@ 2599,12 2735,12 @@ const SyntaxToken *Assembler::parse_stat case SyntaxTokenType::RepeatEnd: // this should never happen assert(false); - throw Exception(L"internal error"); + throw Exception("internal error"); #if defined(_DEBUG) case SyntaxTokenType::Debug: if (generate) { - debug() << L"BREAK\n"; + debug() << "BREAK\n"; _after_break = true; } t = consume_next_token();
M jasm/assembling/functions.cpp +49 -43
@@ 28,6 28,7 @@ const FunctionDesc &function_info(Functi {not_lazy, fixed_args, 2}, // pow {not_lazy, fixed_args, 1}, // log {not_lazy, fixed_args, 1}, // log10 + {not_lazy, fixed_args, 2}, // logn {not_lazy, fixed_args, 1}, // exp {not_lazy, fixed_args, 1}, // abs {not_lazy, fixed_args, 1}, // floor @@ 46,6 47,8 @@ const FunctionDesc &function_info(Functi {not_lazy, variable_args, 1}, // string {not_lazy, fixed_args, 1}, // hexstring {not_lazy, fixed_args, 1}, // unicode + {not_lazy, variable_args, 1}, // uppercase + {not_lazy, variable_args, 1}, // lowercase {not_lazy, variable_args, 0}, // list {is_lazy, variable_args, 0}, // map (lazy because it has special handling for key=value arguments) {not_lazy, fixed_args, 2}, // static_assert @@ 60,50 63,53 @@ const FunctionDesc &function_info(Functi return desc[static_cast<int>(type)]; } -const std::wstring_view to_string(FunctionType type) +const std::string_view to_string(FunctionType type) { - static const std::wstring_view names[] = { - std::wstring_view(L"sizeof"), - std::wstring_view(L"offsetof"), - std::wstring_view(L"sin"), - std::wstring_view(L"cos"), - std::wstring_view(L"tan"), - std::wstring_view(L"sinh"), - std::wstring_view(L"cosh"), - std::wstring_view(L"tanh"), - std::wstring_view(L"asin"), - std::wstring_view(L"acos"), - std::wstring_view(L"atan"), - std::wstring_view(L"atan2"), - std::wstring_view(L"sqrt"), - std::wstring_view(L"pow"), - std::wstring_view(L"log"), - std::wstring_view(L"log10"), - std::wstring_view(L"exp"), - std::wstring_view(L"abs"), - std::wstring_view(L"floor"), - std::wstring_view(L"ceil"), - std::wstring_view(L"round"), - std::wstring_view(L"modulo"), - std::wstring_view(L"remainder"), - std::wstring_view(L"degrees"), - std::wstring_view(L"radians"), - std::wstring_view(L"min"), - std::wstring_view(L"max"), - std::wstring_view(L"clamp"), - std::wstring_view(L"lerp"), - std::wstring_view(L"int"), - std::wstring_view(L"float"), - std::wstring_view(L"string"), - std::wstring_view(L"hexstring"), - std::wstring_view(L"unicode"), - std::wstring_view(L"list"), - std::wstring_view(L"map"), - std::wstring_view(L"static_assert"), - std::wstring_view(L"format"), - std::wstring_view(L"print"), - std::wstring_view(L"symbol"), - std::wstring_view(L"select"), + static const std::string_view names[] = { + std::string_view("sizeof"), + std::string_view("offsetof"), + std::string_view("sin"), + std::string_view("cos"), + std::string_view("tan"), + std::string_view("sinh"), + std::string_view("cosh"), + std::string_view("tanh"), + std::string_view("asin"), + std::string_view("acos"), + std::string_view("atan"), + std::string_view("atan2"), + std::string_view("sqrt"), + std::string_view("pow"), + std::string_view("log"), + std::string_view("log10"), + std::string_view("logn"), + std::string_view("exp"), + std::string_view("abs"), + std::string_view("floor"), + std::string_view("ceil"), + std::string_view("round"), + std::string_view("modulo"), + std::string_view("remainder"), + std::string_view("degrees"), + std::string_view("radians"), + std::string_view("min"), + std::string_view("max"), + std::string_view("clamp"), + std::string_view("lerp"), + std::string_view("int"), + std::string_view("float"), + std::string_view("string"), + std::string_view("hexstring"), + std::string_view("unicode"), + std::string_view("uppercase"), + std::string_view("lowercase"), + std::string_view("list"), + std::string_view("map"), + std::string_view("static_assert"), + std::string_view("format"), + std::string_view("print"), + std::string_view("symbol"), + std::string_view("select"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(FunctionType::NumTypes), "Number of functions doesn't match number of strings");
M jasm/assembling/functions.h +4 -1
@@ 23,6 23,7 @@ enum class FunctionType : uint8_t Pow, Log, Log10, + LogN, Exp, Abs, Floor, @@ 41,6 42,8 @@ enum class FunctionType : uint8_t String, HexString, Unicode, + UpperCase, + LowerCase, List, Map, StaticAssert, @@ 60,7 63,7 @@ struct FunctionDesc { /// Returns information about a function. const FunctionDesc &function_info(FunctionType type); -const std::wstring_view to_string(FunctionType type); +const std::string_view to_string(FunctionType type); /// @}
M jasm/assembling/instructions_6502.cpp +87 -72
@@ 72,6 72,10 @@ uint16_t __addressing_modes_mask[static_ /* TXA */ Imp | ___ | __ | ___ | ___ | ___ | ____ | ____ | ___ | ___ | ____ | ____ , /* TXS */ Imp | ___ | __ | ___ | ___ | ___ | ____ | ____ | ___ | ___ | ____ | ____ , /* TYA */ Imp | ___ | __ | ___ | ___ | ___ | ____ | ____ | ___ | ___ | ____ | ____ , + + /* BHS */ ___ | ___ | __ | ___ | ___ | ___ | ____ | ____ | Rel | ___ | ____ | ____ , + /* BLT */ ___ | ___ | __ | ___ | ___ | ___ | ____ | ____ | Rel | ___ | ____ | ____ , + }; OpCodes __opcodes[static_cast<int>(InstructionType::NumTypes)] = { @@ 146,6 150,11 @@ OpCodes __opcodes[static_cast<int>(Instr /* TXS */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00}}, /* TYA */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00}}, /* ZP , ABSO, ZPIX, ABSX, ZPIY, ABSY, IMPL, IMME, RELA, INDI, INDX, INDY,*/ + + /* BHS */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00}}, + /* BLT */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00}}, + /* ZP , ABSO, ZPIX, ABSX, ZPIY, ABSY, IMPL, IMME, RELA, INDI, INDX, INDY,*/ + }; InstructionType __inverse_branch_instruction[static_cast<int>(InstructionType::NumTypes)] = { @@ 205,6 214,9 @@ InstructionType __inverse_branch_instruc /* TXA */ InstructionType::Brk, /* TXS */ InstructionType::Brk, /* TYA */ InstructionType::Brk, + + /* BHS */ InstructionType::Blt, + /* BLT */ InstructionType::Bhs, }; uint16_t addressing_modes(InstructionType instruction) @@ 235,21 247,21 @@ bool is_ending_instruction(InstructionTy || type == InstructionType::Rts; } -const std::wstring_view to_string(AddressingModeType type) +const std::string_view to_string(AddressingModeType type) { - const static std::wstring_view names[] = { - std::wstring_view(L"zero page address"), - std::wstring_view(L"absolute address"), - std::wstring_view(L"zero page address with x offset"), - std::wstring_view(L"absolute address with x offset"), - std::wstring_view(L"zero page address with y offset"), - std::wstring_view(L"absolute address with y offset"), - std::wstring_view(L"implied"), - std::wstring_view(L"immediate"), - std::wstring_view(L"relative address"), - std::wstring_view(L"indirect address"), - std::wstring_view(L"indirect address with x offset"), - std::wstring_view(L"indirect address with y offset"), + const static std::string_view names[] = { + std::string_view("zero page address"), + std::string_view("absolute address"), + std::string_view("zero page address with x offset"), + std::string_view("absolute address with x offset"), + std::string_view("zero page address with y offset"), + std::string_view("absolute address with y offset"), + std::string_view("implied"), + std::string_view("immediate"), + std::string_view("relative address"), + std::string_view("indirect address"), + std::string_view("indirect address with x offset"), + std::string_view("indirect address with y offset"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(AddressingModeType::NumAddressingModes), "Number of addressing modes doesn't match number of strings"); @@ 257,65 269,68 @@ const std::wstring_view to_string(Addres return names[static_cast<size_t>(type)]; } -const std::wstring_view to_string(InstructionType type) +const std::string_view to_string(InstructionType type) { - static const std::wstring_view names[] = { - std::wstring_view(L"adc"), - std::wstring_view(L"and"), - std::wstring_view(L"asl"), - std::wstring_view(L"bcc"), - std::wstring_view(L"bcs"), - std::wstring_view(L"beq"), - std::wstring_view(L"bit"), - std::wstring_view(L"bmi"), - std::wstring_view(L"bne"), - std::wstring_view(L"bpl"), - std::wstring_view(L"brk"), - std::wstring_view(L"bvc"), - std::wstring_view(L"bvs"), - std::wstring_view(L"clc"), - std::wstring_view(L"cld"), - std::wstring_view(L"cli"), - std::wstring_view(L"clv"), - std::wstring_view(L"cmp"), - std::wstring_view(L"cpx"), - std::wstring_view(L"cpy"), - std::wstring_view(L"dec"), - std::wstring_view(L"dex"), - std::wstring_view(L"dey"), - std::wstring_view(L"eor"), - std::wstring_view(L"inc"), - std::wstring_view(L"inx"), - std::wstring_view(L"iny"), - std::wstring_view(L"jmp"), - std::wstring_view(L"jsr"), - std::wstring_view(L"lda"), - std::wstring_view(L"ldx"), - std::wstring_view(L"ldy"), - std::wstring_view(L"lsr"), - std::wstring_view(L"nop"), - std::wstring_view(L"ora"), - std::wstring_view(L"pha"), - std::wstring_view(L"php"), - std::wstring_view(L"pla"), - std::wstring_view(L"plp"), - std::wstring_view(L"rol"), - std::wstring_view(L"ror"), - std::wstring_view(L"rti"), - std::wstring_view(L"rts"), - std::wstring_view(L"sbc"), - std::wstring_view(L"sec"), - std::wstring_view(L"sed"), - std::wstring_view(L"sei"), - std::wstring_view(L"sta"), - std::wstring_view(L"stx"), - std::wstring_view(L"sty"), - std::wstring_view(L"tax"), - std::wstring_view(L"tay"), - std::wstring_view(L"tsx"), - std::wstring_view(L"txa"), - std::wstring_view(L"txs"), - std::wstring_view(L"tya"), + static const std::string_view names[] = { + std::string_view("adc"), + std::string_view("and"), + std::string_view("asl"), + std::string_view("bcc"), + std::string_view("bcs"), + std::string_view("beq"), + std::string_view("bit"), + std::string_view("bmi"), + std::string_view("bne"), + std::string_view("bpl"), + std::string_view("brk"), + std::string_view("bvc"), + std::string_view("bvs"), + std::string_view("clc"), + std::string_view("cld"), + std::string_view("cli"), + std::string_view("clv"), + std::string_view("cmp"), + std::string_view("cpx"), + std::string_view("cpy"), + std::string_view("dec"), + std::string_view("dex"), + std::string_view("dey"), + std::string_view("eor"), + std::string_view("inc"), + std::string_view("inx"), + std::string_view("iny"), + std::string_view("jmp"), + std::string_view("jsr"), + std::string_view("lda"), + std::string_view("ldx"), + std::string_view("ldy"), + std::string_view("lsr"), + std::string_view("nop"), + std::string_view("ora"), + std::string_view("pha"), + std::string_view("php"), + std::string_view("pla"), + std::string_view("plp"), + std::string_view("rol"), + std::string_view("ror"), + std::string_view("rti"), + std::string_view("rts"), + std::string_view("sbc"), + std::string_view("sec"), + std::string_view("sed"), + std::string_view("sei"), + std::string_view("sta"), + std::string_view("stx"), + std::string_view("sty"), + std::string_view("tax"), + std::string_view("tay"), + std::string_view("tsx"), + std::string_view("txa"), + std::string_view("txs"), + std::string_view("tya"), + + std::string_view("bhs"), + std::string_view("blt"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(InstructionType::NumTypes), "Number of instructions doesn't match number of strings");
M jasm/assembling/instructions_6502.h +8 -2
@@ 2,6 2,8 @@ #if SUPPORTS(M6502) +#include <assembling/instructions_common.h> + namespace jasm { @@ 66,6 68,10 @@ enum class InstructionType : uint8_t Txa, Txs, Tya, + // end of standard instructions + Bhs, // branch if higher or same + NumStandard = Bhs, + Blt, // branch if less than NumTypes, }; @@ 151,9 157,9 @@ InstructionType inverse_branch(Instructi bool is_ending_instruction(InstructionType type); /// Convert an addressing mode to a string for printing. -const std::wstring_view to_string(AddressingModeType type); +const std::string_view to_string(AddressingModeType type); -const std::wstring_view to_string(InstructionType type); +const std::string_view to_string(InstructionType type); /// @}
A => jasm/assembling/instructions_common.h +7 -0
@@ 0,0 1,7 @@ +#pragma once + +enum class InstructionCategory : uint8_t +{ + Standard, ///< Standard instructions. + Pseudo, ///< Combination of instructions for convenience. +};
M jasm/assembling/instructions_z80.cpp +614 -606
@@ 9,76 9,76 @@ namespace jasm { -const std::wstring_view to_string(InstructionType type) +const std::string_view to_string(InstructionType type) { - static const std::wstring_view names[] = { - std::wstring_view(L"adc"), - std::wstring_view(L"add"), - std::wstring_view(L"and"), - std::wstring_view(L"bit"), - std::wstring_view(L"call"), - std::wstring_view(L"ccf"), - std::wstring_view(L"cp"), - std::wstring_view(L"cpd"), - std::wstring_view(L"cpdr"), - std::wstring_view(L"cpi"), - std::wstring_view(L"cpir"), - std::wstring_view(L"cpl"), - std::wstring_view(L"daa"), - std::wstring_view(L"dec"), - std::wstring_view(L"di"), - std::wstring_view(L"djnz"), - std::wstring_view(L"ei"), - std::wstring_view(L"ex"), - std::wstring_view(L"exx"), - std::wstring_view(L"halt"), - std::wstring_view(L"im"), - std::wstring_view(L"in"), - std::wstring_view(L"inc"), - std::wstring_view(L"ind"), - std::wstring_view(L"indr"), - std::wstring_view(L"ini"), - std::wstring_view(L"inir"), - std::wstring_view(L"jp"), - std::wstring_view(L"jr"), - std::wstring_view(L"ld"), - std::wstring_view(L"ldd"), - std::wstring_view(L"lddr"), - std::wstring_view(L"ldi"), - std::wstring_view(L"ldir"), - std::wstring_view(L"neg"), - std::wstring_view(L"nop"), - std::wstring_view(L"or"), - std::wstring_view(L"otdr"), - std::wstring_view(L"otir"), - std::wstring_view(L"out"), - std::wstring_view(L"outd"), - std::wstring_view(L"outi"), - std::wstring_view(L"pop"), - std::wstring_view(L"push"), - std::wstring_view(L"res"), - std::wstring_view(L"ret"), - std::wstring_view(L"reti"), - std::wstring_view(L"retn"), - std::wstring_view(L"rl"), - std::wstring_view(L"rla"), - std::wstring_view(L"rlc"), - std::wstring_view(L"rlca"), - std::wstring_view(L"rld"), - std::wstring_view(L"rr"), - std::wstring_view(L"rra"), - std::wstring_view(L"rrc"), - std::wstring_view(L"rrca"), - std::wstring_view(L"rrd"), - std::wstring_view(L"rst"), - std::wstring_view(L"sbc"), - std::wstring_view(L"scf"), - std::wstring_view(L"set"), - std::wstring_view(L"sla"), - std::wstring_view(L"sra"), - std::wstring_view(L"srl"), - std::wstring_view(L"sub"), - std::wstring_view(L"xor"), + static const std::string_view names[] = { + std::string_view("adc"), + std::string_view("add"), + std::string_view("and"), + std::string_view("bit"), + std::string_view("call"), + std::string_view("ccf"), + std::string_view("cp"), + std::string_view("cpd"), + std::string_view("cpdr"), + std::string_view("cpi"), + std::string_view("cpir"), + std::string_view("cpl"), + std::string_view("daa"), + std::string_view("dec"), + std::string_view("di"), + std::string_view("djnz"), + std::string_view("ei"), + std::string_view("ex"), + std::string_view("exx"), + std::string_view("halt"), + std::string_view("im"), + std::string_view("in"), + std::string_view("inc"), + std::string_view("ind"), + std::string_view("indr"), + std::string_view("ini"), + std::string_view("inir"), + std::string_view("jp"), + std::string_view("jr"), + std::string_view("ld"), + std::string_view("ldd"), + std::string_view("lddr"), + std::string_view("ldi"), + std::string_view("ldir"), + std::string_view("neg"), + std::string_view("nop"), + std::string_view("or"), + std::string_view("otdr"), + std::string_view("otir"), + std::string_view("out"), + std::string_view("outd"), + std::string_view("outi"), + std::string_view("pop"), + std::string_view("push"), + std::string_view("res"), + std::string_view("ret"), + std::string_view("reti"), + std::string_view("retn"), + std::string_view("rl"), + std::string_view("rla"), + std::string_view("rlc"), + std::string_view("rlca"), + std::string_view("rld"), + std::string_view("rr"), + std::string_view("rra"), + std::string_view("rrc"), + std::string_view("rrca"), + std::string_view("rrd"), + std::string_view("rst"), + std::string_view("sbc"), + std::string_view("scf"), + std::string_view("set"), + std::string_view("sla"), + std::string_view("sra"), + std::string_view("srl"), + std::string_view("sub"), + std::string_view("xor"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(InstructionType::NumTypes), "Number of instructions doesn't match number of strings"); @@ 86,59 86,59 @@ const std::wstring_view to_string(Instru return names[static_cast<size_t>(type)]; } -const std::wstring_view to_string(InstructionArgumentType type) +const std::string_view to_string(InstructionArgumentType type) { - static const std::wstring_view names[] = { - std::wstring_view(L"<none>"), - std::wstring_view(L"<number>"), - std::wstring_view(L"(<address>)"), - std::wstring_view(L"(c)"), - std::wstring_view(L"(bc)"), - std::wstring_view(L"(de)"), - std::wstring_view(L"(hl)"), - std::wstring_view(L"(ix)"), - std::wstring_view(L"(iy)"), - std::wstring_view(L"(sp)"), - std::wstring_view(L"(ix+<offset>)"), - std::wstring_view(L"(iy+<offset>)"), - std::wstring_view(L"a"), - std::wstring_view(L"b"), - std::wstring_view(L"c"), - std::wstring_view(L"d"), - std::wstring_view(L"e"), - std::wstring_view(L"h"), - std::wstring_view(L"l"), - std::wstring_view(L"i"), - std::wstring_view(L"r"), - std::wstring_view(L"af"), - std::wstring_view(L"bc"), - std::wstring_view(L"de"), - std::wstring_view(L"hl"), - std::wstring_view(L"ix"), - std::wstring_view(L"iy"), - std::wstring_view(L"sp"), - std::wstring_view(L"af'"), - std::wstring_view(L"c"), - std::wstring_view(L"m"), - std::wstring_view(L"nc"), - std::wstring_view(L"nz"), - std::wstring_view(L"p"), - std::wstring_view(L"pe"), - std::wstring_view(L"po"), - std::wstring_view(L"z"), + static const std::string_view names[] = { + std::string_view("<none>"), + std::string_view("<number>"), + std::string_view("(<address>)"), + std::string_view("(c)"), + std::string_view("(bc)"), + std::string_view("(de)"), + std::string_view("(hl)"), + std::string_view("(ix)"), + std::string_view("(iy)"), + std::string_view("(sp)"), + std::string_view("(ix+<offset>)"), + std::string_view("(iy+<offset>)"), + std::string_view("a"), + std::string_view("b"), + std::string_view("c"), + std::string_view("d"), + std::string_view("e"), + std::string_view("h"), + std::string_view("l"), + std::string_view("i"), + std::string_view("r"), + std::string_view("af"), + std::string_view("bc"), + std::string_view("de"), + std::string_view("hl"), + std::string_view("ix"), + std::string_view("iy"), + std::string_view("sp"), + std::string_view("af'"), + std::string_view("c"), + std::string_view("m"), + std::string_view("nc"), + std::string_view("nz"), + std::string_view("p"), + std::string_view("pe"), + std::string_view("po"), + std::string_view("z"), // The modes up to here is used when parsing and the actual meaning of numbers is unknown. // Past this point are the actual specific types of numbers listed since the instructions // have this information. It makes it possible to print out the required addressing mode. - std::wstring_view(L"<byte value>"), - std::wstring_view(L"<word value>"), - std::wstring_view(L"(<byte value>)"), - std::wstring_view(L"(<word value>)"), - std::wstring_view(L"<relative address>"), - std::wstring_view(L"<bit>"), - std::wstring_view(L"<zero page address>"), - std::wstring_view(L"<interrupt number>"), + std::string_view("<byte value>"), + std::string_view("<word value>"), + std::string_view("(<byte value>)"), + std::string_view("(<word value>)"), + std::string_view("<relative address>"), + std::string_view("<bit>"), + std::string_view("<zero page address>"), + std::string_view("<interrupt number>"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(InstructionArgumentType::NumTypes), "Number of instruction arguments doesn't match number of strings"); @@ 148,12 148,6 @@ const std::wstring_view to_string(Instru namespace { - // bit masks for addressable_argument_flags - constexpr uint8_t no_arg = 0; - constexpr uint8_t first_arg = 1; - constexpr uint8_t second_arg = 2; - constexpr uint8_t both_args = 3; - struct Instruction { /// This horrible constructor makes it possible to initialize with static arrays with compile time size check. @@ 559,6 553,13 @@ namespace {{InstructionArgumentType::RegisterSP, InstructionArgumentType::RegisterIX}, {InstructionArgumentType::RegisterSP, InstructionArgumentType::RegisterIX}}, {{InstructionArgumentType::RegisterSP, InstructionArgumentType::RegisterIY}, {InstructionArgumentType::RegisterSP, InstructionArgumentType::RegisterIY}}, {{InstructionArgumentType::RegisterSP, InstructionArgumentType::Number}, {InstructionArgumentType::RegisterSP, InstructionArgumentType::WordValue}}, + + {{InstructionArgumentType::RegisterBC, InstructionArgumentType::RegisterDE}, {InstructionArgumentType::RegisterBC, InstructionArgumentType::RegisterDE}}, + {{InstructionArgumentType::RegisterBC, InstructionArgumentType::RegisterHL}, {InstructionArgumentType::RegisterBC, InstructionArgumentType::RegisterHL}}, + {{InstructionArgumentType::RegisterDE, InstructionArgumentType::RegisterBC}, {InstructionArgumentType::RegisterDE, InstructionArgumentType::RegisterBC}}, + {{InstructionArgumentType::RegisterDE, InstructionArgumentType::RegisterHL}, {InstructionArgumentType::RegisterDE, InstructionArgumentType::RegisterHL}}, + {{InstructionArgumentType::RegisterHL, InstructionArgumentType::RegisterBC}, {InstructionArgumentType::RegisterHL, InstructionArgumentType::RegisterBC}}, + {{InstructionArgumentType::RegisterHL, InstructionArgumentType::RegisterDE}, {InstructionArgumentType::RegisterHL, InstructionArgumentType::RegisterDE}}, }; AddressingMode addressing_modes_ldd[] = { @@ 862,697 863,704 @@ namespace }; InstructionOpCode opcodes_adc[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x8e, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xdd, 0x8e, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xfd, 0x8e, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x8f, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x88, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x89, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x8a, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x8b, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x8c, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x8d, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0xce, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, first_arg, {0xce, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x4a, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x5a, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x6a, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x7a, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x8e, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0x8e, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0x8e, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x8f, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x88, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x89, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x8a, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x8b, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x8c, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x8d, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0xce, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {1,0}, {0xce, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x4a, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x5a, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x6a, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x7a, 0x00, 0x00}}, }; InstructionOpCode opcodes_add[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x86, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xdd, 0x86, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xfd, 0x86, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x87, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x80, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x81, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x82, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x83, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x84, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x85, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0xc6, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, first_arg, {0xc6, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x09, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x19, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x29, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x39, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xdd, 0x09, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xdd, 0x19, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xdd, 0x29, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xdd, 0x39, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xfd, 0x09, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xfd, 0x19, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xfd, 0x29, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xfd, 0x39, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x86, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0x86, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0x86, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x87, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x80, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x81, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x82, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x83, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x84, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x85, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0xc6, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {1,0}, {0xc6, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x09, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x19, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x29, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x39, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xdd, 0x09, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xdd, 0x19, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xdd, 0x29, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xdd, 0x39, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xfd, 0x09, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xfd, 0x19, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xfd, 0x29, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xfd, 0x39, 0x00, 0x00}}, }; InstructionOpCode opcodes_and[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xa6, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0xa6, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0xa6, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xa7, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xa0, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xa1, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xa2, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xa3, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xa4, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xa5, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, first_arg, {0xe6, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xa6, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0xa6, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0xa6, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xa7, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xa0, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xa1, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xa2, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xa3, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xa4, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xa5, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {1,0}, {0xe6, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_bit[] = { - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x46, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::BitAndOffsetArg, second_arg, {0xdd, 0xcb, 0x00, 0x46}}, - {4, {2,0}, OpCodeFormat::BitAndOffsetArg, second_arg, {0xfd, 0xcb, 0x00, 0x46}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x47, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x40, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x41, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x42, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x43, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x44, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x45, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x46, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::BitAndOffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0xcb, 0x00, 0x46}}, + {4, {2,0}, OpCodeFormat::BitAndOffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0xcb, 0x00, 0x46}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x47, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x40, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x41, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x42, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x43, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x44, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x45, 0x00, 0x00}}, }; InstructionOpCode opcodes_call[] = { - {3, {1,0}, OpCodeFormat::WordArg, first_arg, {0xcd, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xdc, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xfc, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xd4, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xc4, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xf4, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xec, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xe4, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xcc, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {2,0}, {0xcd, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xdc, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xfc, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xd4, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xc4, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xf4, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xec, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xe4, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xcc, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_ccf[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x3f, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x3f, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_cp[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xbe, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0xbe, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0xbe, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xbf, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xb8, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xb9, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xba, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xbb, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xbc, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xbd, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, first_arg, {0xfe, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xbe, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0xbe, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0xbe, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xbf, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xb8, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xb9, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xba, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xbb, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xbc, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xbd, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {1,0}, {0xfe, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_cpd[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xa9, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xa9, 0x00, 0x00}}, }; InstructionOpCode opcodes_cpdr[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xb9, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xb9, 0x00, 0x00}}, }; InstructionOpCode opcodes_cpi[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xa1, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xa1, 0x00, 0x00}}, }; InstructionOpCode opcodes_cpir[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xb1, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xb1, 0x00, 0x00}}, }; InstructionOpCode opcodes_cpl[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x2f, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x2f, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_daa[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x27, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x27, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_dec[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x35, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0x35, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0x35, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x3d, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x05, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x0b, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x0d, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x15, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x1b, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x1d, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x25, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x2b, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xdd, 0x2b, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xfd, 0x2b, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x2d, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x3b, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x35, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0x35, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0x35, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x3d, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x05, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x0b, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x0d, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x15, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x1b, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x1d, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x25, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x2b, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xdd, 0x2b, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xfd, 0x2b, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x2d, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x3b, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_di[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xf3, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xf3, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_djnz[] = { - {2, {1,0}, OpCodeFormat::BranchOffsetArg, first_arg, {0x10, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::BranchOffsetArg, InstructionCategory::Standard, {1,0}, {0x10, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_ei[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xfb, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xfb, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_ex[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xe3, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xdd, 0xe3, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xfd, 0xe3, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x08, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xeb, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xe3, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xdd, 0xe3, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xfd, 0xe3, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x08, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xeb, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_exx[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xd9, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xd9, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_halt[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x76, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x76, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_im[] = { - {2, {1,0}, OpCodeFormat::InterruptModeArg, first_arg, {0xed, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::InterruptModeArg, InstructionCategory::Standard, {1,0}, {0xed, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_in[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x78, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0xdb, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x40, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x48, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x50, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x58, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x60, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x68, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x78, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0xdb, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x40, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x48, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x50, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x58, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x60, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x68, 0x00, 0x00}}, }; InstructionOpCode opcodes_inc[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x34, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0x34, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0x34, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x3c, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x04, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x03, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x0c, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x14, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x13, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x1c, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x24, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x23, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xdd, 0x23, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xfd, 0x23, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x2c, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x33, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x34, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0x34, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0x34, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x3c, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x04, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x03, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x0c, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x14, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x13, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x1c, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x24, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x23, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xdd, 0x23, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xfd, 0x23, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x2c, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x33, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_ind[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xaa, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xaa, 0x00, 0x00}}, }; InstructionOpCode opcodes_indr[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xba, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xba, 0x00, 0x00}}, }; InstructionOpCode opcodes_ini[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xa2, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xa2, 0x00, 0x00}}, }; InstructionOpCode opcodes_inir[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xb2, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xb2, 0x00, 0x00}}, }; InstructionOpCode opcodes_jp[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xe9, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xdd, 0xe9, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xfd, 0xe9, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, first_arg, {0xc3, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xda, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xfa, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xd2, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xc2, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xf2, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xea, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xe2, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0xca, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xe9, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xdd, 0xe9, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xfd, 0xe9, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {2,0}, {0xc3, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xda, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xfa, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xd2, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xc2, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xf2, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xea, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xe2, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xca, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_jr[] = { - {2, {1,0}, OpCodeFormat::BranchOffsetArg, first_arg, {0x18, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::BranchOffsetArg, second_arg, {0x38, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::BranchOffsetArg, second_arg, {0x30, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::BranchOffsetArg, second_arg, {0x20, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::BranchOffsetArg, second_arg, {0x28, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::BranchOffsetArg, InstructionCategory::Standard, {1,0}, {0x18, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::BranchOffsetArg, InstructionCategory::Standard, {0,1}, {0x38, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::BranchOffsetArg, InstructionCategory::Standard, {0,1}, {0x30, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::BranchOffsetArg, InstructionCategory::Standard, {0,1}, {0x20, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::BranchOffsetArg, InstructionCategory::Standard, {0,1}, {0x28, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_ld[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x02, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x12, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x77, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x70, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x71, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x72, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x73, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x74, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x75, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0x36, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x02, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x12, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x77, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x70, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x71, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x72, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x73, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x74, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x75, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0x36, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0x77, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0x70, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0x71, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0x72, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0x73, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0x74, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0x75, 0x00, 0x00}}, - {4, {2,3}, OpCodeFormat::OffsetAndByteArg, both_args, {0xdd, 0x36, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0x77, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0x70, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0x71, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0x72, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0x73, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0x74, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0x75, 0x00, 0x00}}, + {4, {2,3}, OpCodeFormat::OffsetAndByteArg, InstructionCategory::Standard, {1,1}, {0xdd, 0x36, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0x77, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0x70, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0x71, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0x72, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0x73, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0x74, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0x75, 0x00, 0x00}}, - {4, {2,3}, OpCodeFormat::OffsetAndByteArg, both_args, {0xfd, 0x36, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0x77, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0x70, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0x71, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0x72, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0x73, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0x74, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0x75, 0x00, 0x00}}, + {4, {2,3}, OpCodeFormat::OffsetAndByteArg, InstructionCategory::Standard, {1,1}, {0xfd, 0x36, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, first_arg, {0x32, 0x00, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::WordArg, first_arg, {0xed, 0x43, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::WordArg, first_arg, {0xed, 0x53, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, first_arg, {0x22, 0x00, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::WordArg, first_arg, {0xdd, 0x22, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::WordArg, first_arg, {0xfd, 0x22, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::WordArg, first_arg, {0xed, 0x73, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {2,0}, {0x32, 0x00, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {2,0}, {0xed, 0x43, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {2,0}, {0xed, 0x53, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {2,0}, {0x22, 0x00, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {2,0}, {0xdd, 0x22, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {2,0}, {0xfd, 0x22, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {2,0}, {0xed, 0x73, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x0a, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x1a, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x7e, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xdd, 0x7e, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xfd, 0x7e, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0x3a, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x7f, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x78, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x79, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x7a, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x7b, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x7c, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x57, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x7d, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0x3e, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x5f, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x0a, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x1a, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x7e, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0x7e, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0x7e, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0x3a, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x7f, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x78, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x79, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x7a, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x7b, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x7c, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x57, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x7d, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0x3e, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x5f, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x46, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xdd, 0x46, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xfd, 0x46, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x47, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x40, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x41, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x42, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x43, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x44, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x45, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0x06, 0x00, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::WordArg, second_arg, {0xed, 0x4b, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0x01, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x46, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0x46, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0x46, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x47, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x40, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x41, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x42, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x43, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x44, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x45, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0x06, 0x00, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xed, 0x4b, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0x01, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x4e, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xdd, 0x4e, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xfd, 0x4e, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x4f, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x48, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x49, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x4a, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x4b, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x4c, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x4d, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0x0e, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x4e, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0x4e, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0x4e, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x4f, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x48, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x49, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x4a, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x4b, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x4c, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x4d, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0x0e, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x56, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xdd, 0x56, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xfd, 0x56, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x57, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x50, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x51, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x52, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x53, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x54, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x55, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0x16, 0x00, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::WordArg, second_arg, {0xed, 0x5b, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0x11, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x56, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0x56, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0x56, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x57, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x50, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x51, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x52, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x53, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x54, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x55, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0x16, 0x00, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xed, 0x5b, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0x11, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x5e, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xdd, 0x5e, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xfd, 0x5e, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x5f, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x58, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x59, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x5a, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x5b, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x5c, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x5d, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0x1e, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x5e, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0x5e, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0x5e, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x5f, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x58, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x59, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x5a, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x5b, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x5c, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x5d, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0x1e, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x66, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xdd, 0x66, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xfd, 0x66, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x67, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x60, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x61, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x62, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x63, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x64, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x65, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0x26, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0x2a, 0x00, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0x21, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x66, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0x66, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0x66, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x67, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x60, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x61, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x62, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x63, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x64, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x65, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0x26, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0x2a, 0x00, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0x21, 0x00, 0x00, 0x00}}, + + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x47, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xdd, 0x2a, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xdd, 0x21, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xfd, 0x2a, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xfd, 0x21, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x47, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::WordArg, second_arg, {0xdd, 0x2a, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::WordArg, second_arg, {0xdd, 0x21, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::WordArg, second_arg, {0xfd, 0x2a, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::WordArg, second_arg, {0xfd, 0x21, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x6e, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0x6e, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0x6e, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x6f, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x68, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x69, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x6a, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x6b, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x6c, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x6d, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0x2e, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x6e, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xdd, 0x6e, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xfd, 0x6e, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x6f, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x68, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x69, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x6a, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x6b, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x6c, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x6d, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0x2e, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x4f, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0xed, 0x7b, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xf9, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xdd, 0xf9, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xfd, 0xf9, 0x00, 0x00}}, + {3, {1,0}, OpCodeFormat::WordArg, InstructionCategory::Standard, {0,2}, {0x31, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x4f, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::WordArg, second_arg, {0xed, 0x7b, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xf9, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xdd, 0xf9, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xfd, 0xf9, 0x00, 0x00}}, - {3, {1,0}, OpCodeFormat::WordArg, second_arg, {0x31, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Pseudo, {0,0}, {0x42, 0x4b, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Pseudo, {0,0}, {0x44, 0x4d, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Pseudo, {0,0}, {0x50, 0x59, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Pseudo, {0,0}, {0x54, 0x5d, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Pseudo, {0,0}, {0x60, 0x69, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Pseudo, {0,0}, {0x62, 0x6b, 0x00, 0x00}}, }; InstructionOpCode opcodes_ldd[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xa8, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xa8, 0x00, 0x00}}, }; InstructionOpCode opcodes_lddr[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xb8, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xb8, 0x00, 0x00}}, }; InstructionOpCode opcodes_ldi[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xa0, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xa0, 0x00, 0x00}}, }; InstructionOpCode opcodes_ldir[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xb0, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xb0, 0x00, 0x00}}, }; InstructionOpCode opcodes_neg[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x44, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x44, 0x00, 0x00}}, }; InstructionOpCode opcodes_nop[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x00, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x00, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_or[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xb6, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0xb6, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0xb6, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xb7, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xb0, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xb1, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xb2, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xb3, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xb4, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xb5, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, first_arg, {0xf6, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xb6, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0xb6, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0xb6, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xb7, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xb0, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xb1, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xb2, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xb3, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xb4, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xb5, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {1,0}, {0xf6, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_otdr[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xbb, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xbb, 0x00, 0x00}}, }; InstructionOpCode opcodes_otir[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xb3, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xb3, 0x00, 0x00}}, }; InstructionOpCode opcodes_out[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x79, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x41, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x49, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x51, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x59, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x61, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x69, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, first_arg, {0xd3, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x79, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x41, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x49, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x51, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x59, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x61, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x69, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {1,0}, {0xd3, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_outd[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xab, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xab, 0x00, 0x00}}, }; InstructionOpCode opcodes_outi[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0xa3, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0xa3, 0x00, 0x00}}, }; InstructionOpCode opcodes_pop[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xf1, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xc1, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xd1, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xe1, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xdd, 0xe1, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xfd, 0xe1, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xf1, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xc1, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xd1, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xe1, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xdd, 0xe1, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xfd, 0xe1, 0x00, 0x00}}, }; InstructionOpCode opcodes_push[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xf5, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xc5, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xd5, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xe5, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xdd, 0xe5, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xfd, 0xe5, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xf5, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xc5, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xd5, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xe5, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xdd, 0xe5, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xfd, 0xe5, 0x00, 0x00}}, }; InstructionOpCode opcodes_res[] = { - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x86, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::BitAndOffsetArg, second_arg, {0xdd, 0xcb, 0x00, 0x86}}, - {4, {2,0}, OpCodeFormat::BitAndOffsetArg, second_arg, {0xfd, 0xcb, 0x00, 0x86}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x87, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x80, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x81, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x82, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x83, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x84, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0x85, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x86, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::BitAndOffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0xcb, 0x00, 0x86}}, + {4, {2,0}, OpCodeFormat::BitAndOffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0xcb, 0x00, 0x86}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x87, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x80, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x81, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x82, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x83, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x84, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0x85, 0x00, 0x00}}, }; InstructionOpCode opcodes_ret[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xc9, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xd8, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xf8, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xd0, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xc0, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xf0, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xe8, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xe0, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xc8, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xc9, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xd8, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xf8, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xd0, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xc0, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xf0, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xe8, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xe0, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xc8, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_reti[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x4d, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x4d, 0x00, 0x00}}, }; InstructionOpCode opcodes_retn[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x45, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x45, 0x00, 0x00}}, }; InstructionOpCode opcodes_rl[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x16, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0xcb, 0x00, 0x16}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0xcb, 0x00, 0x16}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x17, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x10, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x11, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x12, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x13, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x14, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x15, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x16, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0xcb, 0x00, 0x16}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0xcb, 0x00, 0x16}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x17, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x10, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x11, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x12, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x13, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x14, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x15, 0x00, 0x00}}, }; InstructionOpCode opcodes_rla[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x17, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x17, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_rlc[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x06, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0xcb, 0x00, 0x06}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0xcb, 0x00, 0x06}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x07, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x01, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x02, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x03, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x04, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x05, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x06, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0xcb, 0x00, 0x06}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0xcb, 0x00, 0x06}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x07, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x01, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x02, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x03, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x04, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x05, 0x00, 0x00}}, }; InstructionOpCode opcodes_rlca[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x07, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x07, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_rld[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x6f, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x6f, 0x00, 0x00}}, }; InstructionOpCode opcodes_rr[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x1e, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0xcb, 0x00, 0x1e}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0xcb, 0x00, 0x1e}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x1f, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x18, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x19, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x1a, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x1b, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x1c, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x1d, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x1e, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0xcb, 0x00, 0x1e}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0xcb, 0x00, 0x1e}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x1f, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x18, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x19, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x1a, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x1b, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x1c, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x1d, 0x00, 0x00}}, }; InstructionOpCode opcodes_rra[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x1f, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x1f, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_rrc[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x0e, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0xcb, 0x00, 0x0e}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0xcb, 0x00, 0x0e}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x0f, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x08, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x09, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x0a, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x0b, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x0c, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x0d, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x0e, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0xcb, 0x00, 0x0e}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0xcb, 0x00, 0x0e}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x0f, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x08, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x09, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x0a, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x0b, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x0c, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x0d, 0x00, 0x00}}, }; InstructionOpCode opcodes_rrca[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x0f, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x0f, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_rrd[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x67, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x67, 0x00, 0x00}}, }; InstructionOpCode opcodes_rst[] = { - {1, {0,0}, OpCodeFormat::PageZeroArg, no_arg, {0xc7, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::PageZeroArg, InstructionCategory::Standard, {0,0}, {0xc7, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_sbc[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x9e, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xdd, 0x9e, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, second_arg, {0xfd, 0x9e, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x9f, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x98, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x99, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x9a, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x9b, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x9c, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x9d, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0xde, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, first_arg, {0xde, 0x00, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x42, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x52, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x62, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xed, 0x72, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x9e, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0x9e, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0x9e, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x9f, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x98, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x99, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x9a, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x9b, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x9c, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x9d, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0xde, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {1,0}, {0xde, 0x00, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x42, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x52, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x62, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xed, 0x72, 0x00, 0x00}}, }; InstructionOpCode opcodes_scf[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x37, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x37, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_set[] = { - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0xc6, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::BitAndOffsetArg, second_arg, {0xdd, 0xcb, 0x00, 0xc6}}, - {4, {2,0}, OpCodeFormat::BitAndOffsetArg, second_arg, {0xfd, 0xcb, 0x00, 0xc6}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0xc7, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0xc0, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0xc1, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0xc2, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0xc3, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0xc4, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::BitAndRegisterArg, no_arg, {0xcb, 0xc5, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0xc6, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::BitAndOffsetArg, InstructionCategory::Standard, {0,1}, {0xdd, 0xcb, 0x00, 0xc6}}, + {4, {2,0}, OpCodeFormat::BitAndOffsetArg, InstructionCategory::Standard, {0,1}, {0xfd, 0xcb, 0x00, 0xc6}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0xc7, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0xc0, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0xc1, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0xc2, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0xc3, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0xc4, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::BitAndRegisterArg, InstructionCategory::Standard, {0,0}, {0xcb, 0xc5, 0x00, 0x00}}, }; InstructionOpCode opcodes_sla[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x26, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0xcb, 0x00, 0x26}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0xcb, 0x00, 0x26}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x27, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x20, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x21, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x22, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x23, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x24, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x25, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x26, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0xcb, 0x00, 0x26}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0xcb, 0x00, 0x26}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x27, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x20, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x21, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x22, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x23, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x24, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x25, 0x00, 0x00}}, }; InstructionOpCode opcodes_sra[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x2e, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0xcb, 0x00, 0x2e}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0xcb, 0x00, 0x2e}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x2f, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x28, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x29, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x2a, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x2b, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x2c, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x2d, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x2e, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0xcb, 0x00, 0x2e}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0xcb, 0x00, 0x2e}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x2f, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x28, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x29, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x2a, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x2b, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x2c, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x2d, 0x00, 0x00}}, }; InstructionOpCode opcodes_srl[] = { - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x3e, 0x00, 0x00}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0xcb, 0x00, 0x3e}}, - {4, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0xcb, 0x00, 0x3e}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x3f, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x38, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x39, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x3a, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x3b, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x3c, 0x00, 0x00}}, - {2, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xcb, 0x3d, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x3e, 0x00, 0x00}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0xcb, 0x00, 0x3e}}, + {4, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0xcb, 0x00, 0x3e}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x3f, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x38, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x39, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x3a, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x3b, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x3c, 0x00, 0x00}}, + {2, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xcb, 0x3d, 0x00, 0x00}}, }; InstructionOpCode opcodes_sub[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x96, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0x96, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0x96, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x97, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x90, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x91, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x92, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x93, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x94, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0x95, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, first_arg, {0xd6, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, second_arg, {0xd6, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x96, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0x96, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0x96, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x97, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x90, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x91, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x92, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x93, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x94, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0x95, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {1,0}, {0xd6, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {0,1}, {0xd6, 0x00, 0x00, 0x00}}, }; InstructionOpCode opcodes_xor[] = { - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xae, 0x00, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xdd, 0xae, 0x00, 0x00}}, - {3, {2,0}, OpCodeFormat::OffsetArg, first_arg, {0xfd, 0xae, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xaf, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xa8, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xa9, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xaa, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xab, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xac, 0x00, 0x00, 0x00}}, - {1, {0,0}, OpCodeFormat::OpcodeOnly, no_arg, {0xad, 0x00, 0x00, 0x00}}, - {2, {1,0}, OpCodeFormat::ByteArg, first_arg, {0xee, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xae, 0x00, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xdd, 0xae, 0x00, 0x00}}, + {3, {2,0}, OpCodeFormat::OffsetArg, InstructionCategory::Standard, {1,0}, {0xfd, 0xae, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xaf, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xa8, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xa9, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xaa, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xab, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xac, 0x00, 0x00, 0x00}}, + {1, {0,0}, OpCodeFormat::OpcodeOnly, InstructionCategory::Standard, {0,0}, {0xad, 0x00, 0x00, 0x00}}, + {2, {1,0}, OpCodeFormat::ByteArg, InstructionCategory::Standard, {1,0}, {0xee, 0x00, 0x00, 0x00}}, }; std::array<Instruction, static_cast<size_t>(InstructionType::NumTypes)> instructions = {{ @@ 1705,7 1713,7 @@ InstructionArgumentType keyword_to_instr assert(false); // this should never happen return InstructionArgumentType::None; } - UNREACHABLE_CODE(throw core::Exception(L"internal error")); + UNREACHABLE_CODE(throw core::Exception("internal error")); } InstructionArgumentType keyword_to_indirect_instruction_argument(ProcessorKeywordType keyword) @@ 1747,7 1755,7 @@ InstructionArgumentType keyword_to_indir assert(false); return InstructionArgumentType::None; } - UNREACHABLE_CODE(throw core::Exception(L"internal error")); + UNREACHABLE_CODE(throw core::Exception("internal error")); } InstructionArgumentType keyword_to_indexed_instruction_argument(ProcessorKeywordType keyword) @@ 1784,7 1792,7 @@ InstructionArgumentType keyword_to_index assert(false); return InstructionArgumentType::None; } - UNREACHABLE_CODE(throw core::Exception(L"internal error")); + UNREACHABLE_CODE(throw core::Exception("internal error")); } bool is_valid_indirect_keyword(ProcessorKeywordType keyword)
M jasm/assembling/instructions_z80.h +13 -9
@@ 2,6 2,7 @@ #if SUPPORTS(Z80) +#include <assembling/instructions_common.h> #include <core/collections/static_array.h> #include <parsing/processor_keywords_z80.h> @@ 81,6 82,7 @@ enum class InstructionType : uint8_t Sub, Xor, NumTypes, + NumStandard = NumTypes, }; enum class InstructionArgumentType : uint8_t @@ 182,8 184,10 @@ struct InstructionOpCode uint8_t offset_to_data[2]; /// Format that decides how the arguments will be written into the opcode data. OpCodeFormat format; - /// A bit for each argument telling if it can be addressed as data in the instruction. - uint8_t addressable_argument_flags; + /// Tells if the instruction is a pseudo instruction or not. + InstructionCategory category; + /// Byte size of data for each argument. Zero means no addressable data in the instruction. + uint8_t argument_data_size[2]; /// Opcode data in order. uint8_t op[4]; }; @@ 192,7 196,7 @@ struct InstructionOpCode inline uint8_t argument_data_offset(int argument_index, const InstructionOpCode &opcode) { assert(argument_index == 0 || argument_index == 1); - if (argument_index == 1 && opcode.addressable_argument_flags == 0b11) { + if (argument_index == 1 && opcode.argument_data_size[0] != 0 && opcode.argument_data_size[1] != 0) { // there are two arguments and this is the second return opcode.offset_to_data[1]; } else { @@ 201,14 205,14 @@ inline uint8_t argument_data_offset(int } } -// Returns true if the argument with argument_index stores addressable data in the instruction. -inline bool argument_has_data(int argument_index, const InstructionOpCode &opcode) +// Returns the byte size of the argument data with argument_index. Zero means no addressable data. +inline uint8_t argument_data_size(int argument_index, const InstructionOpCode &opcode) { assert(argument_index == 0 || argument_index == 1); if (argument_index == 0 || argument_index == 1) { - return (opcode.addressable_argument_flags & (1 << argument_index)) != 0; + return opcode.argument_data_size[argument_index]; } else { - return false; + return 0; } } @@ 240,8 244,8 @@ const core::StaticArray<AddressingMode> /// where the addressing mode was found. const InstructionOpCode &opcode(InstructionType instruction, uint8_t addressing_mode_index); -const std::wstring_view to_string(InstructionType type); -const std::wstring_view to_string(InstructionArgumentType type); +const std::string_view to_string(InstructionType type); +const std::string_view to_string(InstructionArgumentType type); /// @}
M jasm/assembling/methods.cpp +14 -14
@@ 34,21 34,21 @@ const MethodDesc &method_info(MethodType return desc[static_cast<int>(type)]; } -const std::wstring_view to_string(MethodType type) +const std::string_view to_string(MethodType type) { - static const std::wstring_view names[] = { - std::wstring_view(L"substring"), - std::wstring_view(L"push"), - std::wstring_view(L"pop"), - std::wstring_view(L"insert"), - std::wstring_view(L"erase"), - std::wstring_view(L"keep"), - std::wstring_view(L"clear"), - std::wstring_view(L"get"), - std::wstring_view(L"set"), - std::wstring_view(L"erase"), - std::wstring_view(L"clear"), - std::wstring_view(L"has"), + static const std::string_view names[] = { + std::string_view("substring"), + std::string_view("push"), + std::string_view("pop"), + std::string_view("insert"), + std::string_view("erase"), + std::string_view("keep"), + std::string_view("clear"), + std::string_view("get"), + std::string_view("set"), + std::string_view("erase"), + std::string_view("clear"), + std::string_view("has"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(MethodType::NumTypes), "Number of methods doesn't match number of strings");
M jasm/assembling/methods.h +13 -1
@@ 13,6 13,7 @@ enum class StringProperties : uint8_t { // methods first because the sum of this index and the method start enum in MethodType results in an index into a method array Substring, + Length, NumProperties }; @@ 26,6 27,7 @@ enum class ListProperties : uint8_t Erase, Keep, Clear, + Empty, Length, NumProperties @@ 39,11 41,21 @@ enum class MapProperties : uint8_t Erase, Clear, Has, + Empty, Length, NumProperties }; +enum class WordOffsetProperties : uint8_t +{ + // methods first because the sum of this index and the method start enum in MethodType results in an index into a method array + + Lo, + Hi, + NumProperties +}; + enum class MethodType : uint8_t { StringSubstring, @@ 77,7 89,7 @@ struct MethodDesc { /// Returns information about a function. const MethodDesc &method_info(MethodType type); -const std::wstring_view to_string(MethodType type); +const std::string_view to_string(MethodType type); /// @}
M jasm/assembling/symbol_environment.cpp +1 -1
@@ 53,7 53,7 @@ void SymbolEnvironment::reset() { // make sure we have a local scope hash for the outermost invisible scope assert(local_symbol_scope_stack.size() <= 1); - local_symbol_scope_stack = {hash_constant(0x1059f8b52dcbcfbaULL, L"<local root scope>")}; + local_symbol_scope_stack = {hash_constant(0x113db57bc67bb978ULL, "<local root scope>")}; // clear the namespace stack and add outermost invisible namespace to simplify code assert(namespace_scope_stack.size() <= 1);
M jasm/assembling/value.cpp +42 -42
@@ 9,67 9,67 @@ namespace jasm { using namespace core; -const std::wstring_view to_string(ValueType type) +const std::string_view to_string(ValueType type) { assert(type < ValueType::NumTypes); switch(type) { case ValueType::None: - return std::wstring_view(L"void"); + return std::string_view("void"); case ValueType::Unknown: - return std::wstring_view(L"unknown"); + return std::string_view("unknown"); case ValueType::BoolValue: - return std::wstring_view(L"boolean"); + return std::string_view("boolean"); case ValueType::IntegerValue: - return std::wstring_view(L"integer"); + return std::string_view("integer"); case ValueType::FloatValue: - return std::wstring_view(L"float"); + return std::string_view("float"); case ValueType::StringValue: - return std::wstring_view(L"string"); - case ValueType::RangeValue: - return std::wstring_view(L"range"); + return std::string_view("string"); + case ValueType::SubroutineValue: + return std::string_view("subroutine"); case ValueType::ByteOffset: - return std::wstring_view(L"byte offset"); + return std::string_view("byte offset"); case ValueType::WordOffset: - return std::wstring_view(L"word offset"); + return std::string_view("word offset"); case ValueType::LongOffset: - return std::wstring_view(L"long offset"); + return std::string_view("long offset"); case ValueType::StructOffset: - return std::wstring_view(L"struct offset"); + return std::string_view("struct offset"); case ValueType::ArrayOffset: - return std::wstring_view(L"array offset"); + return std::string_view("array offset"); case ValueType::ByteTypename: - return std::wstring_view(L"byte typename"); + return std::string_view("byte typename"); case ValueType::WordTypename: - return std::wstring_view(L"word typename"); + return std::string_view("word typename"); case ValueType::LongTypename: - return std::wstring_view(L"long typename"); + return std::string_view("long typename"); case ValueType::StructTypename: - return std::wstring_view(L"struct typename"); + return std::string_view("struct typename"); case ValueType::FunctionReference: - return std::wstring_view(L"function"); + return std::string_view("function"); case ValueType::MacroReference: - return std::wstring_view(L"macro"); + return std::string_view("macro"); case ValueType::ValueReference: - return std::wstring_view(L"value reference"); + return std::string_view("value reference"); case ValueType::StringReference: - return std::wstring_view(L"string"); + return std::string_view("string"); case ValueType::EnumReference: - return std::wstring_view(L"enum"); + return std::string_view("enum"); case ValueType::ObjectReference: - return std::wstring_view(L"object"); + return std::string_view("object"); case ValueType::ListReference: - return std::wstring_view(L"list"); + return std::string_view("list"); case ValueType::ListElementReference: - return std::wstring_view(L"list element reference"); + return std::string_view("list element reference"); case ValueType::MapReference: - return std::wstring_view(L"map"); + return std::string_view("map"); case ValueType::MethodClosure: - return std::wstring_view(L"method closure"); + return std::string_view("method closure"); case ValueType::NumTypes: return nullptr; } - UNREACHABLE_CODE(return std::wstring_view()); + UNREACHABLE_CODE(return std::string_view()); } StaticValue::StaticValue() { @@ 77,14 77,14 @@ StaticValue::StaticValue() { memset(this, 0, sizeof(StaticValue)); } -std::wstring make_printable(const std::wstring &str) +std::string make_printable(const std::string &str) { - std::wstring result(str.size() > 14 ? str.substr(0, 11) + L"..." : str); - std::transform(result.begin(), result.end(), result.begin(), [](wchar_t c){ return c < 32 ? L'.' : c; }); - return L"\"" + result + L"\""; + std::string result(str.size() > 14 ? str.substr(0, 11) + "..." : str); + std::transform(result.begin(), result.end(), result.begin(), [](char c){ return c < 32 ? '.' : c; }); + return "\"" + result + "\""; } -std::wstring to_string(const StringRepository &string_repo, const Value &value) +std::string to_string(const StringRepository &string_repo, const Value &value) { switch(value.type) { @@ 104,32 104,32 @@ std::wstring to_string(const StringRepos case ValueType::MapReference: case ValueType::MethodClosure: case ValueType::NumTypes: - return L""; + return ""; case ValueType::BoolValue: - return value.bool_value ? L"true" : L"false"; + return value.bool_value ? "true" : "false"; case ValueType::IntegerValue: - case ValueType::RangeValue: - return std::to_wstring(value.integer_value); + case ValueType::SubroutineValue: + return std::to_string(value.integer_value); case ValueType::FloatValue: - return std::to_wstring(value.float_value); + return std::to_string(value.float_value); case ValueType::StringValue: - return make_printable(std::wstring(string_repo.get(value.string_hash))); + return make_printable(std::string(string_repo.get(value.string_hash))); case ValueType::ByteOffset: case ValueType::WordOffset: case ValueType::LongOffset: case ValueType::StructOffset: case ValueType::ArrayOffset: - return std::to_wstring(value.offset_base); + return std::to_string(value.offset_base); case ValueType::StringReference: return make_printable(value.object_reference.deref<StringDynamicObject>().value); } - UNREACHABLE_CODE(throw Exception(L"internal error")); + UNREACHABLE_CODE(throw Exception("internal error")); } DynamicObject::DynamicObject()
M jasm/assembling/value.h +7 -7
@@ 36,7 36,7 @@ enum class ValueType : uint8_t IntegerValue, ///< 32 bit value. FloatValue, ///< 64 bit float. StringValue, ///< String hash. - RangeValue, ///< An address with a size as well. Subroutine for example. + SubroutineValue, ///< An address with a size as well. // offset types ByteOffset = value_group_offset, ///< Offset from a base address to bytes. @@ 69,7 69,7 @@ enum class ValueType : uint8_t }; -const std::wstring_view to_string(ValueType type); +const std::string_view to_string(ValueType type); /// This is the POD part of a value. struct StaticValue @@ 390,7 390,7 @@ struct Value : StaticValue using ValueVector = std::vector<Value>; using ImmovableValueVector = core::SplitVector<Value>; -std::wstring to_string(const StringRepository &string_repo, const Value &value); +std::string to_string(const StringRepository &string_repo, const Value &value); class EnumDynamicObject : public DynamicObject @@ 407,14 407,14 @@ class StringDynamicObject : public Dynam { public: StringDynamicObject() : DynamicObject() {} - StringDynamicObject(const std::wstring_view &str) : DynamicObject(), value(str) {} - StringDynamicObject(const std::wstring &str) : DynamicObject(), value(str) {} - StringDynamicObject(std::wstring &&str) : DynamicObject(), value(std::move(str)) {} + StringDynamicObject(const std::string_view &str) : DynamicObject(), value(str) {} + StringDynamicObject(const std::string &str) : DynamicObject(), value(str) {} + StringDynamicObject(std::string &&str) : DynamicObject(), value(std::move(str)) {} virtual bool equal_to(const DynamicObject &other) const override; virtual uint64_t hash(uint64_t seed) const override; - std::wstring value; + std::string value; }; class MethodClosureDynamicObject : public DynamicObject
M jasm/docs/jasm.md +195 -9
@@ 52,6 52,9 @@ This documentation covers the language a * [Max Errors](#max-errors) * [Output Files and Sections](#output-files-and-sections) * [Verboseness](#verboseness) + * [Pseudo Instructions](#pseudo-instructions) + * [6502 Pseudo Instructions](#6502-pseudo-instructions) + * [Z80 Pseudo Instructions](#z80-pseudo-instructions) * [Return Codes](#return-codes) * [Language Reference](#language-reference) * [Input Format](#input-format) @@ 1095,13 1098,25 @@ With the `[text]|--max-errors` flag, you <div id="output-files-and-sections"></div> ## Output Files and Sections -The default output mode will merge all code sections into one big binary and pad the inbetween space with zeros. With the flag `[text]|--output-multiple-files`, this can be changed to store one file per section instead. +The default output mode will merge all code sections into one big binary and pad the inbetween space with zero. With the flag `[text]|--output-multiple-files`, this can be changed to store one file per section instead. Each file will be named after the output file but add the section name before the file extension. [text] jasm-6502 --output-multiple-files input.jasm output.bin _A shortcut alternative is `[text]|-om`._ +You can choose to have jAsm name the files after the sections by not specifying an output file name. + + [text] + jasm-6502 --output-multiple-files input.jasm + +You may want to add an extension to the section names when using them as file names. Use the option `[text]|--file-extension` to do that. + + [text] + jasm-6502 --output-multiple-files --file-extension prg input.jasm + +_A shortcut alternative is `[text]|-ext`._ + <div id="verboseness"></div> ## Verboseness @@ 1114,10 1129,43 @@ jAsm supports several levels of output d <tr><th>Flag</th><th>Meaning</th></tr> <tr><td><code>[text]|-v0</code></td><td>Show errors</td></tr> <tr><td><code>[text]|-v1</code></td><td>Show errors and warnings</td></tr> - <tr><td><code>[text]|-v2</code></td><td>Show errors, warnings and general information</td></tr> + <tr><td><code>[text]|-v2</code></td><td>Show errors, warnings, printouts and general information</td></tr> <tr><td><code>[text]|-v3</code></td><td>Show errors, warnings, general information and debugging information</td></tr> </table> +<div id="pseudo-instructions"></div> +## Pseudo Instructions + +You can enable a number of extra instructions to simplify programming using the option `[text]|--pseudo-instructions`. The result differs depending on the processor. + +_A shortcut alternative is `[text]|-pi`._ + +<div id="6502-pseudo-instructions"></div> +### 6502 pseudo instructions + +These are the pseudo instructions for 6502. + + [6502] + bhs addr // branch if higher or same + blt addr // branch if lower + +These are equivalent to `[6502]|bcs` and `[6502]|bcc`, respectively. + +<div id="z80-pseudo-instructions"></div> +### Z80 pseudo instructions + +These are the pseudo instructions for Z80. + + [z80] + ld bc,de + ld bc,hl + ld de,bc + ld de,hl + ld hl,bc + ld hl,de + +They are implemented using two instructions under the hood. First the high register part is loaded and then the low. + <div id="return-codes"></div> ## Return Codes @@ 1209,6 1257,12 @@ On Z80, there are at most two arguments ld index:(ix+0), data:0 inc (hl) // increase index in instruction above +Instruction labels become [Memory Storage Types](#memory-storage-types) and it means they have a defined size and the low and high parts of word addresses can be accessed directly through the lo and hi properties. + + [6502] + lda value:$ffff + inc value.lo // the low part of the previous instruction's argument + Constant declarations look like this. [6502] @@ 1807,6 1861,52 @@ The following optional flag properties a </tr> </table> +#### String Functions + +There are a couple of functions specific to operating on string data or characters. + +<table> + <tr> + <th>Function</th> + <th>Argument types</th> + <th>Description</th> + <th style="width: 35%;">Examples</th> + </tr> + <tr> + <td><code>[6502]|uppercase(text [, locale])</code></td> + <td>string|integer, string</td> + <td>Returns an uppercase version of the string or character sent as the first argument.</td> + <td><code>[6502]|uppercase("Commodore") // "COMMODORE"</code><br/><code>[6502]|uppercase("Cåmmodåre", "swedish") // "CÅMMODÅRE"</code><br/><code>[6502]|uppercase('a') // 65</code></td> + </tr> + <tr> + <td><code>[6502]|lowercase(text [, locale])</code></td> + <td>string|integer, string</td> + <td>Returns a lowercase version of the string or character sent as the first argument.</td> + <td><code>[6502]|lowercase("Commodore") // "commodore"</code><br/><code>[6502]|lowercase("ABCÅÄÖ", "swedish") // "abcåäö"</code><br/><code>[6502]|lowercase('A') // 97</code></td> + </tr> +</table> + +When specifying a locale string in the string functions, these are the currently supported locales. + +<table> + <tr> + <th>Locale</th> + <th>Comment</th> + </tr> + <tr> + <td>default</td> + <td>This is the default locale. It uses the default C locale. It doesn't handle any characters other than A-Z.</td> + </tr> + <tr> + <td>english</td> + <td>This is the US English locale. This is much like the C locale.</td> + </tr> + <tr> + <td>swedish</td> + <td>This is the Swedish locale. Supports the åäö characters.</td> + </tr> +</table> + <div id="list-type"></div> ### List Type @@ 1905,7 2005,7 @@ Values can be of any type, but keys must <td><code>[6502]|set(key, value)</code></td> <td>boolean|integer|string, any</td> <td>Adds <code>[6502]|value</code> to be accessible by <code>[6502]|key</code> in the map.</td> - <td><code>[6502]|var aa = map()</code><br/><code>[6502]|aa.set("hi" = 0)</code></td> + <td><code>[6502]|var aa = map()</code><br/><code>[6502]|aa.set("hi", 0)</code></td> </tr> <tr> <td><code>[6502]|get(key)</code></td> @@ 2016,6 2116,15 @@ The memory storage data types store nega * `[6502]|word` is a 16 bit data type * `[6502]|long` is a 32 bit data type +The word storage type has a pair of properties to address the first and second byte in the word. These are `[6502]|lo` and `[6502]|hi`. + + [6502] + define word number = 5 + const high_addr = number.hi + const low_addr = number.lo + +These properties will take `[6502]|number` which points to the 5 i memory and return the offset to the high and low byte of the word respectively. + <div id="storage-conversions"></div> ## Storage Conversions @@ 2151,6 2260,12 @@ jAsm provides a number of mathematical f <td><code>[6502]|log10(100) // 2.0</code></td> </tr> <tr> + <td><code>[6502]|logn(x, n)</code></td> + <td>numeric, numeric</td> + <td>Returns the base-<code>[6502]|n</code> logarithm of <code>[6502]|x</code>.</td> + <td><code>[6502]|logn(243, 3) // 5.0</code></td> + </tr> + <tr> <td><code>[6502]|max(a, ...)</code></td> <td>numeric</td> <td>Returns the largest of the arguments.</td> @@ 2247,7 2362,11 @@ jAsm has a couple of predefined constant <div id="print-and-formatting"></div> ## Print and Formatting -There are two functions dedicated to formatting and printing, `[6502]|format` and `[6502]|print`. Both use the same arguments but `[6502]|format` returns the result and `[6502]|print` outputs it. Let's take `[6502]|format` as the example. +A `[6502]|print` function exists to output text when assembling. This can be useful when you want to know about locations or calculations made in the assembled code. + +_Note that in order to see the output you need to use at least verbose level `[text]|-v2`. See [Verboseness](#verboseness) for more information._ + +There are two functions dedicated to formatting and printing, `[6502]|format` and `[6502]|print`. Both use the same arguments but `[6502]|format` returns the result and `[6502]|print` outputs it. Let's take `[6502]|format` as the example when looking at the arguments. [6502] const WIDTH = 40 @@ 2386,6 2505,21 @@ An end address can be specified after th rts } +Sometimes you want the code to end at a position rather than start at a position. You can do this by setting the section start based on the end minus the length of the section data. The following example shows how it can be done and still enforce that the size must fit within two memory locations. + + [6502] + const .section_start = $8000 + const .section_end = $9000 + const .code_size = code_end - code_start + static_assert(.section_end - .code_size >= .section_start, "section overflow") + section code, "main", .section_end - .code_size, .section_end + { + code_start: + // code here + // ... + code_end: + } + <div id="sections-in-sections"></div> ### Sections in Sections @@ 2540,16 2674,18 @@ Sections can be used to build large cart section code, "image_1", $e000, $10000 { // code here - align $2000 + align $2000, $ff } section code, "image_2", $e000, $10000 { // code here - align $2000 + align $2000, $ff } // more sections } +The `[6502]|align` keyword is used here to fill up the rest of each bank up to where the next one begins. + An alternative is to use the [bank mode](#bank-mode) and place the sections in their own 64 kB address space. [6502] @@ 2558,12 2694,12 @@ An alternative is to use the [bank mode] section code, "image_1", $0e000, $10000 { // code here - align $2000 + align $2000, $ff } section code, "image_2", $1e000, $20000 { // code here - align $2000 + align $2000, $ff } // more sections } @@ 2824,7 2960,13 @@ To create a subroutine you really only n rts } -The label `[6502]|multiply_by_8` is automatically created. +A subroutine also has the property that it can be called like a macro without arguments. The two following lines are equivalent. + + [6502] + jsr multiply_by_8 + multiply_by_8() + +The macro style call has the advantage that a module can change a subroutine into a macro to inline the code, or the other way around, without changing the calling code. <div id="enumerations"></div> ## Enumerations @@ 3092,3 3234,47 @@ This will align the program counter so t align 256, 55 This will fill up the gap to next page boundary with the number 55. + +Sometimes it is necessary to ensure that a block of code or data is within a 256 byte page to avoid extra cycles being spent on indexing or branch instructions. The following macro can be used to verify that a memory block is within alignment. + + [6502] + // Check that the code/data between .start and .end won't cross an alignment border. + macro assert_within_alignment(.start, .end, .alignment) + { + static_assert(.end - .start >= 0, "Content wraps around") + static_assert(.end - .start <= .alignment, "Content too large for alignment") + if (.end - .start > 0) { + static_assert(.start/.alignment == (.end - 1)/.alignment, "Content crosses alignment") + } + } + +When a code block needs to be within a 256 byte page to work, this macro can be used to automatically add dummy data at the macro location until the code block (that needs to be placed later in the same section) is within the alignment boundaries. + + [6502] + // Makes sure the area between .start and .end is within an alignment block. + // It adds bytes of data at the macro position to make sure the area isn't + // crossing any alignment boundaries. + macro align_within_page(.start, .end, .alignment, .fill_byte) + { + const .size = .end - .start + static_assert(.relative_position <= .start, "Macro must be placed earlier in memory") + static_assert(.size >= 0, "Content wraps around") + static_assert(.size <= .alignment, "Content too large for alignment") + if (.size > 0) { + // This is quite tricky because the code cannot make calculations based + // on the aligned position since it will cause variable oscillation. Instead + // it is using the distance to the area to calculate the unaligned position + // and base the alignment size on that. + const .distance = .start - .relative_position + const .start_before = * + .distance + const .end_before = .start_before + .size + const is_aligned = .start_before/.alignment == (.end_before - 1)/.alignment + if (!is_aligned) { + repeat .alignment - modulo(.start_before, .alignment) { + define byte = .fill_byte + } + } + } + .relative_position: + } +
M jasm/docs/syntax_highlight.py +2 -2
@@ 44,8 44,8 @@ def replace_with_token(text, replace_map def syntax_highlight_code(code_class, text): keywords = re.compile(r'\b(address|align|basic|bss|byte|code|const|declare|define|dynamic|elif|else|enum|export|fill|for|function|if|import|incbin|include|long|macro|mapping|module|namespace|optimize|part|reserve|return|section|struct|subroutine|using|var|word)\b') - functions = re.compile(r'\b(abs|acos|asin|atan|atan2|ceil|clamp|cos|cosh|degrees|exp|float|floor|format|hexstring|int|lerp|log|log10|max|min|modulo|offsetof|pow|print|radians|remainder|round|select|sin|sinh|sizeof|sqrt|static_assert|string|symbol|tan|tanh|unicode)\b') - instructions_6502 = re.compile(r'\b(adc|and|asl|bcc|bcs|beq|bit|bmi|bne|bpl|brk|bvc|bvs|clc|cld|cli|clv|cmp|cpx|cpy|dec|dex|dey|eor|inc|inx|iny|jmp|jsr|lda|ldx|ldy|lsr|nop|ora|pha|php|pla|plp|rol|ror|rti|rts|sbc|sec|sed|sei|sta|stx|sty|tax|tay|tsx|txa|txs|tya)\b') + functions = re.compile(r'\b(abs|acos|asin|atan|atan2|ceil|clamp|cos|cosh|degrees|exp|float|floor|format|hexstring|int|lerp|log|log10|logn|max|min|modulo|offsetof|pow|print|radians|remainder|round|select|sin|sinh|sizeof|sqrt|static_assert|string|symbol|tan|tanh|unicode|uppercase|lowercase)\b') + instructions_6502 = re.compile(r'\b(adc|and|asl|bcc|bcs|beq|bit|bmi|bne|bpl|brk|bvc|bvs|clc|cld|cli|clv|cmp|cpx|cpy|dec|dex|dey|eor|inc|inx|iny|jmp|jsr|lda|ldx|ldy|lsr|nop|ora|pha|php|pla|plp|rol|ror|rti|rts|sbc|sec|sed|sei|sta|stx|sty|tax|tay|tsx|txa|txs|tya|bhs|blt)\b') instructions_z80 = re.compile(r'\b(adc|add|and|bit|call|ccf|cp|cpd|cpdr|cpi|cpir|cpl|daa|dec|di|djnz|ei|ex|exx|halt|im|in|inc|ind|indr|ini|inir|jp|jr|ld|ldd|lddr|ldi|ldir|neg|nop|or|otdr|otir|out|outd|outi|pop|push|res|ret|reti|retn|rl|rla|rlc|rlca|rld|rr|rra|rrc|rrca|rrd|rst|sbc|scf|set|sla|sra|srl|sub|xor)\b') operators = re.compile(r'(<<=|>>=|&&=|[|][|]=|!=|[+][+]|--|<<|>>|<=|>=|==|&&|[|][|]|[+]=|-=|[*]=|[/]=|&=|[|]=|\^=|::|!|~|[*]|[/]|[+]|-|<|>|&|\^|[|]|=|#|%)') special = re.compile(r'({|}|\(|\)|;|\[|\])')
M jasm/environment/command_line_args.cpp +120 -83
@@ 6,59 6,61 @@ namespace jasm { using namespace core; -CommandLineArgs::CommandLineArgs(std::wstring version) +CommandLineArgs::CommandLineArgs(std::string version) : verbose_level(ErrorLevel::Errors) , max_errors(20) , multiple_output_files(false) + , section_names_as_file_names(false) , load_addr_header(false) , multi_bank_mode(false) + , pseudo_instructions(false) , _version(std::move(version)) { // add current directory to includes - include_dirs.push_back(L"."); + include_dirs.push_back("."); } -bool CommandLineArgs::parse(int argc, const wchar_t* const argv[]) +bool CommandLineArgs::parse(int argc, const char * const argv[]) { - std::vector<std::wstring> non_flag_arguments; + std::vector<std::string> non_flag_arguments; for (int i = 1; i < argc; ++i) { - const std::wstring arg = argv[i]; + const std::string arg = argv[i]; if (arg[0] == '-') { if (arg.size() <= 1) { - error() << L"Invalid argument " << arg << L'\n'; + error() << "Invalid argument " << arg << '\n'; return false; } if (arg[1] == 'v') { if (!parse_verbose_flag(arg)) return false; - } else if (arg == L"-d" || arg == L"--define") { + } else if (arg == "-d" || arg == "--define") { ++i; if (i == argc) { - error() << L"Missing " << arg << L" flag argument\n"; + error() << "Missing " << arg << " flag argument\n"; print_usage(argv[0]); return false; } // verify that there is exactly one '=' in that string - std::wstring define = argv[i]; + std::string define = argv[i]; if (std::count(define.begin(), define.end(), L'=') != 1) { - error() << arg << L" option must have NAME=VALUE argument\n"; + error() << arg << " option must have NAME=VALUE argument\n"; print_usage(argv[0]); return false; } // split string on equal sign auto equal_position = std::find(define.begin(), define.end(), L'='); - std::wstring symbol(define.begin(), equal_position); - std::wstring value_str(equal_position + 1, define.end()); - bool boolean_true = value_str == L"true"; - bool boolean_false = value_str == L"false"; + std::string symbol(define.begin(), equal_position); + std::string value_str(equal_position + 1, define.end()); + bool boolean_true = value_str == "true"; + bool boolean_false = value_str == "false"; // determine type - bool is_integer = !value_str.empty() && std::count_if(value_str.begin(), value_str.end(), [](wchar_t c){ return c < L'0' || c > L'9'; }) == 0; + bool is_integer = !value_str.empty() && std::count_if(value_str.begin(), value_str.end(), [](char c){ return c < '0' || c > '9'; }) == 0; if (is_integer) { - int32_t value = std::stoi(&value_str[0]); + int32_t value = std::stoi(value_str); predefined_integers.push_back(std::make_pair(symbol, value)); } else if (boolean_true || boolean_false) { predefined_booleans.push_back(std::make_pair(symbol, boolean_true)); @@ 66,73 68,85 @@ bool CommandLineArgs::parse(int argc, co predefined_strings.push_back(std::make_pair(symbol, value_str)); } - } else if (arg == L"-i" || arg == L"--include-dir") { + } else if (arg == "-i" || arg == "--include-dir") { ++i; if (i == argc) { - error() << L"Missing " << arg << L" flag argument\n"; + error() << "Missing " << arg << " flag argument\n"; print_usage(argv[0]); return false; } include_dirs.push_back(argv[i]); - } else if (arg == L"-ds" || arg == L"--dump-symbols") { + } else if (arg == "-ds" || arg == "--dump-symbols") { ++i; if (i == argc) { - error() << L"Missing " << arg << L" argument\n"; + error() << "Missing " << arg << " argument\n"; print_usage(argv[0]); return false; } symbol_dump_file = argv[i]; - } else if (arg == L"-dv" || arg == L"--dump-vice-symbols") { + } else if (arg == "-dv" || arg == "--dump-vice-symbols") { ++i; if (i == argc) { - error() << L"Missing " << arg << L" argument\n"; + error() << "Missing " << arg << " argument\n"; print_usage(argv[0]); return false; } vice_dump_file = argv[i]; - } else if (arg == L"-dg" || arg == L"--dump-gba-symbols") { + } else if (arg == "-dg" || arg == "--dump-gba-symbols") { ++i; if (i == argc) { - error() << L"Missing " << arg << L" argument\n"; + error() << "Missing " << arg << " argument\n"; print_usage(argv[0]); return false; } gba_sym_dump_file = argv[i]; - } else if (arg == L"-os" || arg == L"--output-single-file") { + } else if (arg == "-os" || arg == "--output-single-file") { multiple_output_files = false; - } else if (arg == L"-om" || arg == L"--output-multiple-files") { + } else if (arg == "-om" || arg == "--output-multiple-files") { multiple_output_files = true; - } else if (arg == L"-hla" || arg == L"--header-little-endian-address") { + } else if (arg == "-hla" || arg == "--header-little-endian-address") { load_addr_header = true; - } else if (arg == L"-me" || arg == L"--max-errors") { + } else if (arg == "-me" || arg == "--max-errors") { ++i; if (i == argc) { - error() << L"Missing " << arg << L" flag argument\n"; + error() << "Missing " << arg << " flag argument\n"; print_usage(argv[0]); return false; } - std::wstring value_str = argv[i]; + std::string value_str = argv[i]; // determine type - bool is_integer = !value_str.empty() && std::count_if(value_str.begin(), value_str.end(), [](wchar_t c){ return c < L'0' || c > L'9'; }) == 0; + bool is_integer = !value_str.empty() && std::count_if(value_str.begin(), value_str.end(), [](char c){ return c < '0' || c > '9'; }) == 0; if (!is_integer) { - error() << L"Invalid number " << value_str << L" following -me flag\n"; + error() << "Invalid number " << value_str << " following -me flag\n"; print_usage(argv[0]); return false; } - max_errors = std::stoi(&value_str[0]); + max_errors = std::stoi(value_str); - } else if (arg == L"-bm" || arg == L"--bank-mode") { + } else if (arg == "-bm" || arg == "--bank-mode") { multi_bank_mode = true; + } else if (arg == "-ext" || arg == "--file-extension") { + ++i; + if (i == argc) { + error() << "Missing " << arg << " flag argument\n"; + print_usage(argv[0]); + return false; + } + file_extension = argv[i]; + + } else if (arg == "-pi" || arg == "--pseudo-instructions") { + pseudo_instructions = true; + } else { - error() << L"Invalid flag " << arg << L'\n'; + error() << "Invalid flag " << arg << '\n'; print_usage(argv[0]); return false; } @@ 140,19 154,35 @@ bool CommandLineArgs::parse(int argc, co non_flag_arguments.push_back(argv[i]); } } - if (non_flag_arguments.size() != 2) { - error() << L"Both input and output files needs to be specified\n"; + + if (!verify_arguments(non_flag_arguments)) { print_usage(argv[0]); return false; } - - input_file = non_flag_arguments[0]; - output_file = non_flag_arguments[1]; - + return true; } -bool CommandLineArgs::parse_verbose_flag(const std::wstring &arg) +bool CommandLineArgs::verify_arguments(const std::vector<std::string> &non_flag_arguments) +{ + bool correct_non_flag_arguments = (non_flag_arguments.size() == 2) || (multiple_output_files && non_flag_arguments.size() == 1); + if (!correct_non_flag_arguments) { + if (multiple_output_files) { + error() << "Either one or two arguments expected, an input file and optionally an output file\n"; + } else { + error() << "Two arguments expected, input and output files\n"; + } + return false; + } + + section_names_as_file_names = multiple_output_files && non_flag_arguments.size() == 1; + + input_file = non_flag_arguments[0]; + output_file = section_names_as_file_names ? std::string("") : non_flag_arguments[1]; + return true; +} + +bool CommandLineArgs::parse_verbose_flag(const std::string &arg) { // verbose flag if (arg.size() == 2) { @@ 160,7 190,7 @@ bool CommandLineArgs::parse_verbose_flag verbose_level = ErrorLevel::Warnings; } else { // a number sets the level - std::wstring warning_level_string = arg.substr(2); + std::string warning_level_string = arg.substr(2); try { const int level = std::stoi(warning_level_string); if (level < 0 || level > static_cast<int>(ErrorLevel::Debug)) @@ 168,57 198,64 @@ bool CommandLineArgs::parse_verbose_flag verbose_level = static_cast<ErrorLevel>(level); } catch (const std::invalid_argument &) { - error() << L"Invalid varning level " << warning_level_string << L'\n'; + error() << "Invalid varning level " << warning_level_string << '\n'; return false; } catch (const std::out_of_range &) { - error() << L"Invalid varning level " << warning_level_string << L'\n'; + error() << "Invalid varning level " << warning_level_string << '\n'; return false; } } return true; } -void CommandLineArgs::print_usage(const wchar_t *exe_path) +void CommandLineArgs::print_usage(const char *exe_path) { error() << _version; - error() << L"\n\nUsage:\n"; - error() << exe_path << L" [options] input_file output_file\n\n"; - error() << L"Options:\n"; - error() << L" -bm\n"; - error() << L" --bank-mode\n"; - error() << L" Turn on multi bank mode\n\n"; - error() << L" -d NAME=VALUE\n"; - error() << L" --define NAME=VALUE\n"; - error() << L" Add predefined symbol (integer, string or boolean value)\n\n"; - error() << L" -ds FILE\n"; - error() << L" --dump-symbols FILE\n"; - error() << L" Dump symbols to the specified file\n\n"; - error() << L" -dv FILE\n"; - error() << L" --dump-vice-symbols FILE\n"; - error() << L" Dump VICE symbol commands to the specified file\n\n"; - error() << L" -dg FILE\n"; - error() << L" --dump-gba-symbols FILE\n"; - error() << L" Dump No$GBA style symbols to the specified file\n\n"; - error() << L" -hla\n"; - error() << L" --header-little-endian-address\n"; - error() << L" Add file header with little endian load address header\n\n"; - error() << L" -i DIR\n"; - error() << L" --include-dir DIR\n"; - error() << L" Add include directory\n\n"; - error() << L" -me NUM\n"; - error() << L" --max-errors NUM\n"; - error() << L" Max number of errors before aborting assembler generation pass (default is 20)\n\n"; - error() << L" -om\n"; - error() << L" --output-multiple-files\n"; - error() << L" Assemble an output file per section\n\n"; - error() << L" -os\n"; - error() << L" --output-single-file\n"; - error() << L" Assemble a single output file (default)\n\n"; - error() << L" -v0 Show only errors in output (default)\n"; - error() << L" -v1, -v Show errors and warnings in output\n"; - error() << L" -v2 Show errors, warnings and information in output\n"; - error() << L" -v3 Show debugging output\n"; + error() << "\n\nUsage:\n"; + error() << exe_path << " [options] input_file [output_file]\n\n"; + error() << "Options:\n"; + error() << " -bm\n"; + error() << " --bank-mode\n"; + error() << " Turn on multi bank mode\n\n"; + error() << " -d NAME=VALUE\n"; + error() << " --define NAME=VALUE\n"; + error() << " Add predefined symbol (integer, string or boolean value)\n\n"; + error() << " -ds FILE\n"; + error() << " --dump-symbols FILE\n"; + error() << " Dump symbols to the specified file\n\n"; + error() << " -dv FILE\n"; + error() << " --dump-vice-symbols FILE\n"; + error() << " Dump VICE symbol commands to the specified file\n\n"; + error() << " -dg FILE\n"; + error() << " --dump-gba-symbols FILE\n"; + error() << " Dump No$GBA style symbols to the specified file\n\n"; + error() << " -ext EXT\n"; + error() << " --file-extension EXT\n"; + error() << " File extension to use when naming files after sections\n\n"; + error() << " -hla\n"; + error() << " --header-little-endian-address\n"; + error() << " Add file header with little endian load address header\n\n"; + error() << " -i DIR\n"; + error() << " --include-dir DIR\n"; + error() << " Add include directory\n\n"; + error() << " -me NUM\n"; + error() << " --max-errors NUM\n"; + error() << " Max number of errors before aborting assembler generation pass (default is 20)\n\n"; + error() << " -om\n"; + error() << " --output-multiple-files\n"; + error() << " Assemble an output file per section\n\n"; + error() << " -os\n"; + error() << " --output-single-file\n"; + error() << " Assemble a single output file (default)\n\n"; + error() << " -pi\n"; + error() << " --pseudo-instructions\n"; + error() << " Adds support for additional pseudo instructions or addressing modes to\n"; + error() << " simplify programming.\n\n"; + error() << " -v0 Show only errors in output (default)\n"; + error() << " -v1, -v Show errors and warnings in output\n"; + error() << " -v2 Show errors, warnings and information in output\n"; + error() << " -v3 Show debugging output\n"; } } // namespace jasm
M jasm/environment/command_line_args.h +18 -14
@@ 9,31 9,35 @@ namespace jasm class CommandLineArgs { public: - CommandLineArgs(std::wstring version); + CommandLineArgs(std::string version); /// @return True if successful. - bool parse(int argc, const wchar_t* const argv[]); + bool parse(int argc, const char * const argv[]); - std::wstring input_file; ///< Imput file with assembler source. - std::wstring output_file; ///< Output file to store binary in. - std::wstring symbol_dump_file; ///< File to dump symbols to, or empty. - std::wstring vice_dump_file; ///< File to dump VICE symbol commands to, or empty. - std::wstring gba_sym_dump_file; ///< File to dump NO$GBA style symbol to, or empty. - std::vector<std::wstring> include_dirs; ///< List of include directories. - std::vector<std::pair<std::wstring, bool>> predefined_booleans; ///< List of predefined constants and values. - std::vector<std::pair<std::wstring, int32_t>> predefined_integers; ///< List of predefined constants and values. - std::vector<std::pair<std::wstring, std::wstring>> predefined_strings; ///< List of predefined constants and values. + std::string input_file; ///< Imput file with assembler source. + std::string output_file; ///< Output file to store binary in. + std::string symbol_dump_file; ///< File to dump symbols to, or empty. + std::string vice_dump_file; ///< File to dump VICE symbol commands to, or empty. + std::string gba_sym_dump_file; ///< File to dump NO$GBA style symbol to, or empty. + std::string file_extension; ///< File extension to use if files are named after sections. + std::vector<std::string> include_dirs; ///< List of include directories. + std::vector<std::pair<std::string, bool>> predefined_booleans; ///< List of predefined constants and values. + std::vector<std::pair<std::string, int32_t>> predefined_integers; ///< List of predefined constants and values. + std::vector<std::pair<std::string, std::string>> predefined_strings; ///< List of predefined constants and values. core::ErrorLevel verbose_level; int32_t max_errors; ///< Max number of errors before aborting assembler generation pass. bool multiple_output_files; ///< True means use one file per section. + bool section_names_as_file_names; ///< True means name files after sections. bool load_addr_header; ///< True means add header with little endian load address. bool multi_bank_mode; ///< True means that the assembler will truncate addresses in instructions. + bool pseudo_instructions; ///< True means that some extra instructions/addressing modes are added as convenience. private: - bool parse_verbose_flag(const std::wstring &arg); - void print_usage(const wchar_t *exe_path); + bool verify_arguments(const std::vector<std::string> &non_flag_arguments); + bool parse_verbose_flag(const std::string &arg); + void print_usage(const char *exe_path); - std::wstring _version; ///< Version information string to print on errors. + std::string _version; ///< Version information string to print on errors. }; } // namespace jasm
M jasm/exceptions/assembly_exception.h +5 -5
@@ 13,14 13,14 @@ namespace jasm /// Assembler exception object. struct AssemblyException : public core::Exception { - AssemblyException(const std::wstring &msg) + AssemblyException(const std::string &msg) : Exception(msg) {} - AssemblyException(const std::wstring &file, unsigned row, unsigned column, AssemblyErrorCodes error, const std::wstring &msg) - : Exception(file + L"(" + std::to_wstring(row) + L"," + std::to_wstring(column) + L") : Error " + std::to_wstring(static_cast<unsigned>(error)) + L" : " + msg) + AssemblyException(const std::string &file, unsigned row, unsigned column, AssemblyErrorCodes error, const std::string &msg) + : Exception(file + "(" + std::to_string(row) + "," + std::to_string(column) + ") : Error " + std::to_string(static_cast<unsigned>(error)) + " : " + msg) {} - AssemblyException(const std::vector<std::wstring> &files, const SourceLocation &location, AssemblyErrorCodes error, const std::wstring &msg) - : Exception(files[location.file_index] + L"(" + std::to_wstring(location.row) + L"," + std::to_wstring(location.column) + L") : Error " + std::to_wstring(static_cast<unsigned>(error)) + L" : " + msg) + AssemblyException(const std::vector<std::string> &files, const SourceLocation &location, AssemblyErrorCodes error, const std::string &msg) + : Exception(files[location.file_index] + "(" + std::to_string(location.row) + "," + std::to_string(location.column) + ") : Error " + std::to_string(static_cast<unsigned>(error)) + " : " + msg) {} };
M jasm/exceptions/error_codes.h +5 -0
@@ 192,6 192,11 @@ enum class AssemblyErrorCodes StringConversionFailed, InvalidStringConversionFormatProperty, AmbiguousStringConversionProperty, + IntegerOrStringValueExpected, + UnsupportedLocaleName, + TooManyArguments, + ArgumentsPassedToSubroutineCall, + UseOfPseudoInstructionInStandardMode, // assembler warnings SubroutineFallthrough = 3500,
M jasm/io/data_reader.cpp +9 -15
@@ 12,7 12,7 @@ namespace jasm { using namespace core; -DataReader::DataReader(std::vector<std::wstring> include_dirs) +DataReader::DataReader(std::vector<std::string> include_dirs) : _include_dirs(std::move(include_dirs)) { } @@ 28,7 28,7 @@ DataReader::~DataReader() } -uint64_t DataReader::queue_load(const std::wstring_view &filename) +uint64_t DataReader::queue_load(const std::string_view &filename) { uint64_t handle = murmur_hash3_string_x64_64(filename); @@ 102,34 102,28 @@ void DataReader::load(FileInfo *file_inf { std::ifstream file; size_t size; - std::wstring file_path; + std::string file_path; #if defined(USE_THREADS) try { #endif // find file amongst include directories if (!match_include_dir_and_file(file_info->filename, _include_dirs, file_path)) { - std::wstringstream ss; - ss << L"Failed to find include file '" << file_info->filename << L"'"; + std::stringstream ss; + ss << "Failed to find include file '" << file_info->filename << "'"; throw FileException(ss.str()); } // open and get file size // open file and place read offset at end to measure size #if defined(_MSC_VER) - file.open(file_path, std::ios::in | std::ios::ate | std::ios::binary); + file.open(core::convert_utf8_to_wide(file_path), std::ios::in | std::ios::ate | std::ios::binary); #elif defined(__GNUC__) - char name_buffer[1024]; - size_t result = wcstombs(name_buffer, file_path.c_str(), 1024); - if (result == sizeof(name_buffer)) - throw FileException(L"Too long path: " + file_path); - if (result == static_cast<size_t>(-1)) - throw FileException(L"Path cannot be converted to utf8: " + file_path); - file.open(name_buffer, std::ios::in | std::ios::ate | std::ios::binary); + file.open(file_path, std::ios::in | std::ios::ate | std::ios::binary); #else #error "Platform not supported" #endif if (!file.is_open()) - throw FileException(L"Failed to open " + file_path); + throw FileException("Failed to open " + file_path); // get file size size = static_cast<size_t>(file.tellg()); @@ 159,7 153,7 @@ void DataReader::load(FileInfo *file_inf file.read(reinterpret_cast<char *>(file_info->data.data()), static_cast<int64_t>(size)); if (!file.good()) - throw FileException(L"Failed to read " + file_path); + throw FileException("Failed to read " + file_path); #if defined(USE_THREADS) // notify the caller of the data
M jasm/io/data_reader.h +4 -4
@@ 17,7 17,7 @@ namespace jasm { class DataReader { public: - DataReader(std::vector<std::wstring> include_dirs); + DataReader(std::vector<std::string> include_dirs); ~DataReader(); DataReader(const DataReader &) = delete; DataReader(DataReader &&) = delete; @@ 26,7 26,7 @@ public: /// Queue a load request. /// @return Handle to the load request. - uint64_t queue_load(const std::wstring_view &filename); + uint64_t queue_load(const std::string_view &filename); /// This will block until the size has been determined and then return it or a fail state. /// @throw An exception is thrown if a file error occurred. @@ 46,10 46,10 @@ private: /// Include directories to search. /// This is a copy just for safety, it could just as well be a reference. - const std::vector<std::wstring> _include_dirs; + const std::vector<std::string> _include_dirs; struct FileInfo { - std::wstring filename; + std::string filename; #if defined(USE_THREADS) std::promise<size_t> size_promise;
M jasm/jasm.cbp +3 -0
@@ 97,6 97,7 @@ <Unit filename="assembling/instructions.h" /> <Unit filename="assembling/instructions_6502.cpp" /> <Unit filename="assembling/instructions_6502.h" /> + <Unit filename="assembling/instructions_common.h" /> <Unit filename="assembling/instructions_z80.cpp" /> <Unit filename="assembling/instructions_z80.h" /> <Unit filename="assembling/method_pointer.h" /> @@ 149,6 150,8 @@ <Unit filename="strings/string_conversions.cpp" /> <Unit filename="strings/string_conversions.h" /> <Unit filename="strings/string_hasher.h" /> + <Unit filename="strings/string_locale.cpp" /> + <Unit filename="strings/string_locale.h" /> <Unit filename="strings/string_repository.cpp" /> <Unit filename="strings/string_repository.h" /> <Unit filename="version.h" />
M jasm/jasm.vcxproj +3 -0
@@ 279,6 279,7 @@ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release-hasher|x64'">Create</PrecompiledHeader> </ClCompile> <ClCompile Include="strings\string_conversions.cpp" /> + <ClCompile Include="strings\string_locale.cpp" /> <ClCompile Include="strings\string_repository.cpp" /> </ItemGroup> <ItemGroup> @@ 288,6 289,7 @@ <ClInclude Include="assembling\functions.h" /> <ClInclude Include="assembling\instructions.h" /> <ClInclude Include="assembling\instructions_6502.h" /> + <ClInclude Include="assembling\instructions_common.h" /> <ClInclude Include="assembling\instructions_z80.h" /> <ClInclude Include="assembling\method_pointer.h" /> <ClInclude Include="assembling\methods.h" /> @@ 317,6 319,7 @@ <ClInclude Include="pch.h" /> <ClInclude Include="strings\string_conversions.h" /> <ClInclude Include="strings\string_hasher.h" /> + <ClInclude Include="strings\string_locale.h" /> <ClInclude Include="strings\string_repository.h" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
M jasm/jasm.vcxproj.filters +9 -0
@@ 51,6 51,9 @@ <ClCompile Include="strings\string_conversions.cpp"> <Filter>strings</Filter> </ClCompile> + <ClCompile Include="strings\string_locale.cpp"> + <Filter>strings</Filter> + </ClCompile> <ClCompile Include="strings\string_repository.cpp"> <Filter>strings</Filter> </ClCompile> @@ 150,6 153,9 @@ <ClInclude Include="strings\string_conversions.h"> <Filter>strings</Filter> </ClInclude> + <ClInclude Include="strings\string_locale.h"> + <Filter>strings</Filter> + </ClInclude> <ClInclude Include="strings\string_hasher.h"> <Filter>strings</Filter> </ClInclude> @@ 174,6 180,9 @@ <ClInclude Include="assembling\instructions_6502.h"> <Filter>assembling</Filter> </ClInclude> + <ClInclude Include="assembling\instructions_common.h"> + <Filter>assembling</Filter> + </ClInclude> <ClInclude Include="assembling\instructions_z80.h"> <Filter>assembling</Filter> </ClInclude>
M jasm/main.cpp +59 -52
@@ 29,19 29,19 @@ static const int revision = #include <revision.h> ; /// This is controlled using the increase_revision.py script. -static const wchar_t *revision_hash = +static const char *revision_hash = #include <revision_hash.h> ; -void write_file(int32_t start_address, bool load_addr_header, bool multi_bank_mode, const Section &first_section, const std::wstring &output_file, const std::vector<uint8_t> &data, const StringRepository &strings, const std::vector<std::wstring> &used_files) +void write_file(int32_t start_address, bool load_addr_header, bool multi_bank_mode, const Section &first_section, const std::string &output_file, const std::vector<uint8_t> &data, const StringRepository &strings, const std::vector<std::string> &used_files) { FileWriter file; file.open(output_file); if (load_addr_header) { if (!multi_bank_mode) { if (start_address < 0 || start_address > 0xffff) { - std::wstringstream ss; - ss << L"Start address doesn't fit in the file header. Section " << strings.get(first_section.name) << L" starts at $" << core::to_hex_string(static_cast<uint32_t>(first_section.start_address)) << L"."; + std::stringstream ss; + ss << "Start address doesn't fit in the file header. Section " << strings.get(first_section.name) << " starts at $" << core::to_hex_string(static_cast<uint32_t>(first_section.start_address)) << '.'; throw AssemblyException(used_files, first_section.source_location, AssemblyErrorCodes::StartAddressTooLargeForFileHeader, ss.str()); } } @@ 54,7 54,7 @@ void write_file(int32_t start_address, b file.write(&data[0], static_cast<uint32_t>(data.size())); } -void merge_sections_and_write(CommandLineArgs &args, const std::vector<Section> §ions, const StringRepository &strings, const std::vector<std::wstring> &used_files) +void merge_sections_and_write(CommandLineArgs &args, const std::vector<Section> §ions, const StringRepository &strings, const std::vector<std::string> &used_files) { std::vector<uint8_t> all_section_data; @@ 64,8 64,8 @@ void merge_sections_and_write(CommandLin for(const Section §ion : sections) { // check for overlaps if (current_address > section.start_address) { - std::wstringstream ss; - ss << L"Section " << strings.get(section.name) << L" overlaps with section " << strings.get(last_section) << L"."; + std::stringstream ss; + ss << "Section " << strings.get(section.name) << " overlaps with section " << strings.get(last_section) << '.'; throw AssemblyException(used_files, section.source_location, AssemblyErrorCodes::OverlappingSections, ss.str()); } @@ 85,19 85,29 @@ void merge_sections_and_write(CommandLin } /// Insert @a ext into @a base, just before the extension in the file name. -std::wstring combine_filenames(const std::wstring &base, const std::wstring &ext) +std::string combine_filenames(const std::string &base, const std::string &ext) { - size_t period_position = base.find_last_of(L'.'); - if (period_position == std::wstring::npos) + size_t period_position = base.find_last_of('.'); + if (period_position == std::string::npos) return base + ext; - return std::wstring(base).insert(period_position, ext); + return std::string(base).insert(period_position, ext); } -void write_sections(CommandLineArgs &args, const std::vector<Section> §ions, const StringRepository &strings, const std::vector<std::wstring> &used_files) +void write_sections(CommandLineArgs &args, const std::vector<Section> §ions, const StringRepository &strings, const std::vector<std::string> &used_files) { for(const Section §ion : sections) { - write_file(section.start_address, args.load_addr_header, args.multi_bank_mode, section, combine_filenames(args.output_file, std::wstring(L"_") + std::wstring(strings.get(section.name))), section.generated_data(), strings, used_files); + std::string output_file; + if (args.section_names_as_file_names) { + if (args.file_extension.empty()) { + output_file = strings.get(section.name); + } else { + output_file = std::string(strings.get(section.name)) + std::string(".") + args.file_extension; + } + } else { + output_file = combine_filenames(args.output_file, std::string("_") + std::string(strings.get(section.name))); + } + write_file(section.start_address, args.load_addr_header, args.multi_bank_mode, section, output_file, section.generated_data(), strings, used_files); } } @@ 105,21 115,21 @@ void assemble(CommandLineArgs &args) { StringRepository strings; // repository to map hashes back to strings HashArrayRepository hash_arrays(128); // repository to replace hash array references with a fixed size handle - std::vector<std::wstring> used_files; // the files used in the source code, used to connect tokens to files + std::vector<std::string> used_files; // the files used in the source code, used to connect tokens to files DataReader data_reader(args.include_dirs); // this loads binary files in the background - auto tokens = tokenize(args.input_file, strings, args.include_dirs, used_files, data_reader); + auto tokens = tokenize(args.pseudo_instructions, args.input_file, strings, args.include_dirs, used_files, data_reader); auto syntax = parse_syntax(tokens, strings, hash_arrays, used_files, data_reader); - auto sections = assemble(args.multiple_output_files, args.multi_bank_mode, syntax, strings, hash_arrays, used_files, + auto sections = assemble(args.multiple_output_files, args.multi_bank_mode, args.pseudo_instructions, syntax, strings, hash_arrays, used_files, args.predefined_booleans, args.predefined_integers, args.predefined_strings, data_reader, args.max_errors, args.symbol_dump_file, args.vice_dump_file, args.gba_sym_dump_file); if (sections.empty()) { - warning() << L"No sections with data, so no file output.\n"; + warning() << "No sections with data, so no file output.\n"; return; } - TimerScope timer(L"Write files"); + TimerScope timer("Write files"); if (args.multiple_output_files) write_sections(args, sections, strings, used_files); else @@ 136,28 146,28 @@ bool is_little_endian() return u.c[0] == 1; } -const wchar_t *supported_processor() +const char *supported_processor() { - const std::array<const wchar_t *, NUM_PROCESSORS> processors {{ - L"6502", - L"z80", + const std::array<const char *, NUM_PROCESSORS> processors {{ + "6502", + "z80", }}; return processors[PROCESSOR]; } -std::wstring version_string() +std::string version_string() { - std::wstringstream ss; - ss << L"jAsm " << supported_processor() << L" assembler v" << version[0] << L"." << version[1] << L"." << revision << L" (" << revision_hash << L")"; + std::stringstream ss; + ss << "jAsm " << supported_processor() << " assembler v" << version[0] << "." << version[1] << "." << revision << " (" << revision_hash << ")"; return ss.str(); } -int safe_main(int argc, const wchar_t * const argv[]) +int safe_main(int argc, const char * const argv[]) { if (!is_little_endian()) - throw Exception(L"This program currently has to be built for a little endian system"); + throw Exception("This program currently has to be built for a little endian system"); - std::wstring version_str = version_string(); + std::string version_str = version_string(); CommandLineArgs args(version_str); if (!args.parse(argc, argv)) return 10; @@ 169,7 179,7 @@ int safe_main(int argc, const wchar_t * assemble(args); } catch (Exception &e) { - error() << e.message << L'\n'; + error() << e.message << '\n'; return_code = 10; } return return_code; @@ 179,37 189,34 @@ int safe_main(int argc, const wchar_t * int wmain(int argc, wchar_t *argv[]) { LogScope log; - int result = safe_main(argc, argv); + + int result; + try { + // make a temporary argv array with narrow char letters + std::vector<std::string> nargs; + std::vector<const char *> nargv; + nargs.reserve(static_cast<size_t>(argc)); + nargv.reserve(static_cast<size_t>(argc)); + for(int i = 0; i < argc; ++i) { + nargs.push_back(convert_wide_to_utf8(argv[i])); + nargv.push_back(nargs.back().c_str()); + } + + result = safe_main(argc, nargv.empty() ? nullptr : &nargv[0]); + } + catch (Exception &e) { + error() << e.message << '\n'; + result = 10; + } return result; } #elif defined(__GNUC__) int main(int argc, char *argv[]) { LogScope log; - // init the locale to make the utf8 conversion work - setlocale(LC_ALL, "en_US.UTF-8"); - int result; - try { - // make a temporary argv array with wide char letters - std::vector<std::wstring> wargs; - std::vector<const wchar_t *> wargv; - wargs.reserve(static_cast<size_t>(argc)); - wargv.reserve(static_cast<size_t>(argc)); - - for(int i = 0; i < argc; ++i) { - wargs.push_back(convert_utf8_to_wide(argv[i])); - wargv.push_back(wargs.back().c_str()); - } - - result = safe_main(argc, wargv.empty() ? nullptr : &wargv[0]); - } - catch (Exception &e) { - error() << e.message << L'\n'; - result = 10; - } - + int result = safe_main(argc, argv); return result; } #else
M jasm/parsing/keyword_finder.cpp +12 -5
@@ 2,6 2,7 @@ #include <algorithm> #include <core/strings/murmur_hash.h> +#include <core/strings/utf8.h> #include <parsing/keyword_finder.h> namespace jasm @@ 9,7 10,7 @@ namespace jasm using namespace core; -void KeywordFinder::set_keywords(const std::vector<std::wstring> &keywords) +void KeywordFinder::set_keywords(const std::vector<std::string> &keywords) { if (keywords.empty()) return; @@ 17,13 18,19 @@ void KeywordFinder::set_keywords(const s // build the character tree based on the keywords // we need a sorted keyword list to get similar characters' results close in memory - std::vector<std::wstring> sorted_keywords(keywords); + std::vector<std::string> sorted_keywords(keywords); std::sort(sorted_keywords.begin(), sorted_keywords.end()); // insert an empty node to free index 0 to mean "end" and one initial node because it simplifies the insert code assert(!sorted_keywords[0].empty()); // the first string cannot be empty, because the tree branch wouldn't have a letter - _keyword_character_tree.emplace_back(0); - _keyword_character_tree.emplace_back(sorted_keywords[0][0]); + _keyword_character_tree.emplace_back(L'0'); + const char *source = sorted_keywords[0].data(); + size_t source_size = sorted_keywords[0].size(); + wchar_t target = 0; + bool success = core::utf8_to_wide(source, source_size, target); + MARK_USE(success); + assert(success); + _keyword_character_tree.emplace_back(target); // insert a dummy hash to simplify the code and let 0 index mean no match _keyword_hashes.push_back(0); @@ 33,7 40,7 @@ void KeywordFinder::set_keywords(const s // add the keyword hash to the stored vector _keyword_hashes.push_back(murmur_hash3_string_x64_64(keyword)); - place_keyword(keyword); + place_keyword(core::utf8_to_wide(keyword)); } }
M jasm/parsing/keyword_finder.h +1 -1
@@ 11,7 11,7 @@ class KeywordFinder { public: /// Set the keywords to match. - void set_keywords(const std::vector<std::wstring> &keywords); + void set_keywords(const std::vector<std::string> &keywords); /// Check for a keyword match in a string view. /// "++hello" will not match "++" since it isn't exact.
M jasm/parsing/keywords.cpp +36 -36
@@ 4,40 4,40 @@ namespace jasm { -const std::wstring_view to_string(KeywordType type) +const std::string_view to_string(KeywordType type) { - static const std::wstring_view names[] = { - std::wstring_view(L"include"), - std::wstring_view(L"incbin"), - std::wstring_view(L"section"), - std::wstring_view(L"optimize"), - std::wstring_view(L"namespace"), - std::wstring_view(L"module"), - std::wstring_view(L"import"), - std::wstring_view(L"export"), - std::wstring_view(L"using"), - std::wstring_view(L"if"), - std::wstring_view(L"else"), - std::wstring_view(L"elif"), - std::wstring_view(L"for"), - std::wstring_view(L"macro"), - std::wstring_view(L"return"), - std::wstring_view(L"align"), - std::wstring_view(L"subroutine"), - std::wstring_view(L"function"), - std::wstring_view(L"struct"), - std::wstring_view(L"enum"), - std::wstring_view(L"declare"), - std::wstring_view(L"const"), - std::wstring_view(L"var"), - std::wstring_view(L"define"), - std::wstring_view(L"reserve"), - std::wstring_view(L"basic"), - std::wstring_view(L"dynamic"), - std::wstring_view(L"address"), - std::wstring_view(L"repeat"), + static const std::string_view names[] = { + std::string_view("include"), + std::string_view("incbin"), + std::string_view("section"), + std::string_view("optimize"), + std::string_view("namespace"), + std::string_view("module"), + std::string_view("import"), + std::string_view("export"), + std::string_view("using"), + std::string_view("if"), + std::string_view("else"), + std::string_view("elif"), + std::string_view("for"), + std::string_view("macro"), + std::string_view("return"), + std::string_view("align"), + std::string_view("subroutine"), + std::string_view("function"), + std::string_view("struct"), + std::string_view("enum"), + std::string_view("declare"), + std::string_view("const"), + std::string_view("var"), + std::string_view("define"), + std::string_view("reserve"), + std::string_view("basic"), + std::string_view("dynamic"), + std::string_view("address"), + std::string_view("repeat"), #if defined(_DEBUG) - std::wstring_view(L"_debug_"), + std::string_view("_debug_"), #endif }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(KeywordType::NumTypes), "Number of keywords doesn't match number of strings"); @@ 46,11 46,11 @@ const std::wstring_view to_string(Keywor return names[static_cast<size_t>(type)]; } -const std::wstring_view to_string(BooleanType type) +const std::string_view to_string(BooleanType type) { - static const std::wstring_view names[] = { - std::wstring_view(L"false"), - std::wstring_view(L"true"), + static const std::string_view names[] = { + std::string_view("false"), + std::string_view("true"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(BooleanType::NumTypes), "Number of booleans doesn't match number of strings");
M jasm/parsing/keywords.h +2 -2
@@ 49,8 49,8 @@ enum class BooleanType : uint8_t NumTypes, }; -const std::wstring_view to_string(KeywordType type); -const std::wstring_view to_string(BooleanType type); +const std::string_view to_string(KeywordType type); +const std::string_view to_string(BooleanType type); /// @}
M jasm/parsing/operators.cpp +60 -60
@@ 51,97 51,97 @@ static OperatorDesc operators[] = { }; -const std::wstring_view to_string(OperatorType type) +const std::string_view to_string(OperatorType type) { - static const std::wstring_view names[] = { - std::wstring_view(L"()"), // token not used in tokenizer but used to order functions in syntax parser - std::wstring_view(L"[]"), // token not used in tokenizer but used to order functions in syntax parser - std::wstring_view(L"."), + static const std::string_view names[] = { + std::string_view("()"), // token not used in tokenizer but used to order functions in syntax parser + std::string_view("[]"), // token not used in tokenizer but used to order functions in syntax parser + std::string_view("."), // operator precedence 3 - std::wstring_view(L"!"), - std::wstring_view(L"~"), + std::string_view("!"), + std::string_view("~"), - std::wstring_view(L"+"), // token not used in tokenizer but used to order functions in syntax parser - std::wstring_view(L"-"), // token not used in tokenizer but used to order functions in syntax parser - std::wstring_view(L"<"), // token not used in tokenizer but used to order functions in syntax parser - std::wstring_view(L">"), // token not used in tokenizer but used to order functions in syntax parser + std::string_view("+"), // token not used in tokenizer but used to order functions in syntax parser + std::string_view("-"), // token not used in tokenizer but used to order functions in syntax parser + std::string_view("<"), // token not used in tokenizer but used to order functions in syntax parser + std::string_view(">"), // token not used in tokenizer but used to order functions in syntax parser // operator precedence 4 - std::wstring_view(L"<<"), - std::wstring_view(L">>"), + std::string_view("<<"), + std::string_view(">>"), // operator precedence 5 - std::wstring_view(L"*"), - std::wstring_view(L"/"), + std::string_view("*"), + std::string_view("/"), // operator precedence 6 - std::wstring_view(L"+"), - std::wstring_view(L"-"), + std::string_view("+"), + std::string_view("-"), // operator precedence 7 - std::wstring_view(L"&"), + std::string_view("&"), // operator precedence 8 - std::wstring_view(L"^"), + std::string_view("^"), // operator precedence 9 - std::wstring_view(L"|"), + std::string_view("|"), // operator precedence 10 - std::wstring_view(L"<"), - std::wstring_view(L">"), - std::wstring_view(L"<="), - std::wstring_view(L">="), + std::string_view("<"), + std::string_view(">"), + std::string_view("<="), + std::string_view(">="), // operator precedence 11 - std::wstring_view(L"=="), - std::wstring_view(L"!="), + std::string_view("=="), + std::string_view("!="), // operator precedence 12 - std::wstring_view(L"&&"), + std::string_view("&&"), // operator precedence 13 - std::wstring_view(L"||"), + std::string_view("||"), // reference operators - std::wstring_view(L"="), - std::wstring_view(L"+="), - std::wstring_view(L"-="), - std::wstring_view(L"*="), - std::wstring_view(L"/="), - std::wstring_view(L"&&="), - std::wstring_view(L"||="), - std::wstring_view(L"&="), - std::wstring_view(L"|="), - std::wstring_view(L"^="), - std::wstring_view(L"<<="), - std::wstring_view(L">>="), + std::string_view("="), + std::string_view("+="), + std::string_view("-="), + std::string_view("*="), + std::string_view("/="), + std::string_view("&&="), + std::string_view("||="), + std::string_view("&="), + std::string_view("|="), + std::string_view("^="), + std::string_view("<<="), + std::string_view(">>="), // operator precedence 2 - std::wstring_view(L"++"), // token not used in tokenizer but used to order functions in syntax parser - std::wstring_view(L"--"), // token not used in tokenizer but used to order functions in syntax parser + std::string_view("++"), // token not used in tokenizer but used to order functions in syntax parser + std::string_view("--"), // token not used in tokenizer but used to order functions in syntax parser // operator precedence 3 - std::wstring_view(L"++"), // token not used in tokenizer but used to order functions in syntax parser - std::wstring_view(L"--"), // token not used in tokenizer but used to order functions in syntax parser + std::string_view("++"), // token not used in tokenizer but used to order functions in syntax parser + std::string_view("--"), // token not used in tokenizer but used to order functions in syntax parser // other operators - std::wstring_view(L":"), - std::wstring_view(L"::"), - std::wstring_view(L";"), - std::wstring_view(L","), - std::wstring_view(L"#"), - std::wstring_view(L"%%"), - std::wstring_view(L"("), - std::wstring_view(L")"), - std::wstring_view(L"["), - std::wstring_view(L"]"), - std::wstring_view(L"{"), - std::wstring_view(L"}"), - std::wstring_view(L"++"), - std::wstring_view(L"--"), - std::wstring_view(L"@"), - std::wstring_view(L"..."), + std::string_view(":"), + std::string_view("::"), + std::string_view(";"), + std::string_view(","), + std::string_view("#"), + std::string_view("%%"), + std::string_view("("), + std::string_view(")"), + std::string_view("["), + std::string_view("]"), + std::string_view("{"), + std::string_view("}"), + std::string_view("++"), + std::string_view("--"), + std::string_view("@"), + std::string_view("..."), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(OperatorType::NumTypes), "Number of operators doesn't match number of strings");
M jasm/parsing/operators.h +1 -1
@@ 119,7 119,7 @@ inline bool is_assignment(OperatorType t const OperatorDesc &operator_desc(OperatorType type); -const std::wstring_view to_string(OperatorType type); +const std::string_view to_string(OperatorType type); /// @}
M jasm/parsing/processor_keywords_6502.cpp +4 -4
@@ 7,12 7,12 @@ namespace jasm { -const std::wstring_view to_string(ProcessorKeywordType type) +const std::string_view to_string(ProcessorKeywordType type) { - static const std::wstring_view names[] = { + static const std::string_view names[] = { // instruction registers - std::wstring_view(L"x"), - std::wstring_view(L"y"), + std::string_view("x"), + std::string_view("y"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(ProcessorKeywordType::NumTypes), "Number of registers/conditions doesn't match number of strings");
M jasm/parsing/processor_keywords_6502.h +1 -1
@@ 17,7 17,7 @@ enum class ProcessorKeywordType : uint8_ NumTypes, }; -const std::wstring_view to_string(ProcessorKeywordType type); +const std::string_view to_string(ProcessorKeywordType type); /// @}
M jasm/parsing/processor_keywords_z80.cpp +26 -26
@@ 7,36 7,36 @@ namespace jasm { -const std::wstring_view to_string(ProcessorKeywordType type) +const std::string_view to_string(ProcessorKeywordType type) { - static const std::wstring_view names[] = { + static const std::string_view names[] = { - std::wstring_view(L"nz"), // non-zero - std::wstring_view(L"z"), // zero - std::wstring_view(L"nc"), // no carry - std::wstring_view(L"c"), // carry - std::wstring_view(L"po"), // parity odd - std::wstring_view(L"pe"), // parity even - std::wstring_view(L"p"), // sign positive - std::wstring_view(L"m"), // sign negative + std::string_view("nz"), // non-zero + std::string_view("z"), // zero + std::string_view("nc"), // no carry + std::string_view("c"), // carry + std::string_view("po"), // parity odd + std::string_view("pe"), // parity even + std::string_view("p"), // sign positive + std::string_view("m"), // sign negative // instruction registers - std::wstring_view(L"a"), - std::wstring_view(L"af"), - std::wstring_view(L"af'"), - std::wstring_view(L"b"), - std::wstring_view(L"bc"), - std::wstring_view(L"d"), - std::wstring_view(L"de"), - std::wstring_view(L"e"), - std::wstring_view(L"h"), - std::wstring_view(L"hl"), - std::wstring_view(L"l"), - std::wstring_view(L"ix"), - std::wstring_view(L"iy"), - std::wstring_view(L"i"), // Yes, this is horrible to have as a reserved keyword! - std::wstring_view(L"r"), - std::wstring_view(L"sp"), + std::string_view("a"), + std::string_view("af"), + std::string_view("af'"), + std::string_view("b"), + std::string_view("bc"), + std::string_view("d"), + std::string_view("de"), + std::string_view("e"), + std::string_view("h"), + std::string_view("hl"), + std::string_view("l"), + std::string_view("ix"), + std::string_view("iy"), + std::string_view("i"), // Yes, this is horrible to have as a reserved keyword! + std::string_view("r"), + std::string_view("sp"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(ProcessorKeywordType::NumTypes), "Number of registers/conditions doesn't match number of strings");
M jasm/parsing/processor_keywords_z80.h +1 -1
@@ 52,7 52,7 @@ inline bool is_register(ProcessorKeyword return type >= ProcessorKeywordType::NumBranchConditions || type == ProcessorKeywordType::C; } -const std::wstring_view to_string(ProcessorKeywordType type); +const std::string_view to_string(ProcessorKeywordType type); /// @}
M jasm/parsing/syntax_parser.cpp +169 -169
@@ 124,7 124,7 @@ class SyntaxParser friend class ChainIndexScope; public: - SyntaxParser(const TokenChain &input, std::vector<TokenChain> &output, const StringRepository &strings, HashArrayRepository &hash_arrays, const std::vector<std::wstring> &source_files, DataReader &data_reader); + SyntaxParser(const TokenChain &input, std::vector<TokenChain> &output, const StringRepository &strings, HashArrayRepository &hash_arrays, const std::vector<std::string> &source_files, DataReader &data_reader); SyntaxParser &operator=(const SyntaxParser &) = delete; @@ 226,7 226,7 @@ private: uint16_t try_parse_addressing_mode(const Token *t); /// Output add addressing modes in the mask to the output stream. - static void print_addressing_modes(std::wstringstream &ss, uint16_t addressing_mode_mask); + static void print_addressing_modes(std::stringstream &ss, uint16_t addressing_mode_mask); #endif #if SUPPORTS(Z80) @@ 370,7 370,7 @@ private: std::vector<TokenChain> &_output; const StringRepository &_strings; HashArrayRepository &_hash_arrays; - const std::vector<std::wstring> &_source_files; + const std::vector<std::string> &_source_files; DataReader &_data_reader; // syntax storage @@ 405,7 405,7 @@ ChainIndexScope::~ChainIndexScope() _parser._output_chain = &_parser._output[_parser._output_chain_index]; } -SyntaxParser::SyntaxParser(const TokenChain &input, std::vector<TokenChain> &output, const StringRepository &strings, HashArrayRepository &hash_arrays, const std::vector<std::wstring> &source_files, DataReader &data_reader) +SyntaxParser::SyntaxParser(const TokenChain &input, std::vector<TokenChain> &output, const StringRepository &strings, HashArrayRepository &hash_arrays, const std::vector<std::string> &source_files, DataReader &data_reader) : _output(output) , _strings(strings) , _hash_arrays(hash_arrays) @@ 491,8 491,8 @@ const Token *SyntaxParser::parse_global_ { t = skip_whitespaces(t); if (t->type != TokenType::Symbol || is_instruction(*t)) { - std::wstringstream ss; - ss << L"Expected symbol name but got " << *t; + std::stringstream ss; + ss << "Expected symbol name but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedSymbolAfterNamespaceKeyword, ss.str()); } symbol = static_cast<const SymbolToken *>(t)->symbol_hash; @@ 501,8 501,8 @@ const Token *SyntaxParser::parse_global_ // verify that we are not continuing with a namespace operator because that would give strange error messages later if (is_operator(t, OperatorType::Namespace)) { - std::wstringstream ss; - ss << L"Namespace operator " << to_string(OperatorType::Namespace) << L" not valid after symbol definition"; + std::stringstream ss; + ss << "Namespace operator " << to_string(OperatorType::Namespace) << " not valid after symbol definition"; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::NamespaceOperatorNotValidAfterSymbolDefinition, ss.str()); } @@ 521,8 521,8 @@ const Token *SyntaxParser::parse_symbol_ bool is_symbol = t->type == TokenType::Symbol && !(global && is_instruction(*t)); if (!is_symbol) { - std::wstringstream ss; - ss << L"Expected symbol name but got " << *t; + std::stringstream ss; + ss << "Expected symbol name but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedLocalOrGlobalSymbol, ss.str()); } @@ 533,8 533,8 @@ const Token *SyntaxParser::parse_symbol_ // verify that we are not continuing with a namespace operator because that would give strange error messages later if (is_operator(t, OperatorType::Namespace)) { - std::wstringstream ss; - ss << L"Namespace operator " << to_string(OperatorType::Namespace) << L" not valid after symbol definition"; + std::stringstream ss; + ss << "Namespace operator " << to_string(OperatorType::Namespace) << " not valid after symbol definition"; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::NamespaceOperatorNotValidAfterSymbolDefinition, ss.str()); } @@ 552,8 552,8 @@ const Token *SyntaxParser::parse_symbol_ t = consume_next_token(); if (t->type != TokenType::Symbol) { - std::wstringstream ss; - ss << L"Expected local symbol name but got " << *t; + std::stringstream ss; + ss << "Expected local symbol name but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedLocalOrGlobalSymbol, ss.str()); } @@ 562,8 562,8 @@ const Token *SyntaxParser::parse_symbol_ t = consume_next_token(); if (is_operator(t, OperatorType::Namespace)) { - std::wstringstream ss; - ss << L"Namespace operator " << to_string(OperatorType::Namespace) << L" not valid after local symbol reference"; + std::stringstream ss; + ss << "Namespace operator " << to_string(OperatorType::Namespace) << " not valid after local symbol reference"; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::NamespaceOperatorNotValidAfterLocalSymbolReference, ss.str()); } @@ 576,8 576,8 @@ const Token *SyntaxParser::parse_symbol_ t = consume_next_token(); if (t->type != TokenType::Symbol) { - std::wstringstream ss; - ss << L"Expected namespace or symbol after " << to_string(OperatorType::Namespace) << L" but got " << *t; + std::stringstream ss; + ss << "Expected namespace or symbol after " << to_string(OperatorType::Namespace) << " but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedSymbolOrNamespaceAfterColon, ss.str()); } } @@ 594,15 594,15 @@ const Token *SyntaxParser::parse_symbol_ // we expect the token after namespace separator to be a symbol t = consume_next_token(); if (t->type != TokenType::Symbol || is_instruction(*t)) { - std::wstringstream ss; - ss << L"Expected namespace or symbol after " << to_string(OperatorType::Namespace) << L" but got " << *t; + std::stringstream ss; + ss << "Expected namespace or symbol after " << to_string(OperatorType::Namespace) << " but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedSymbolOrNamespaceAfterColon, ss.str()); } // we got a symbol so we loop and see what follows } } else { - std::wstringstream ss; - ss << L"Expected local or global symbol but got " << *t; + std::stringstream ss; + ss << "Expected local or global symbol but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedLocalOrGlobalSymbol, ss.str()); } @@ 616,8 616,8 @@ const Token *SyntaxParser::parse_operato if (is_operator(t, expected_operator)) return consume_next_token(); - std::wstringstream ss; - ss << L"Expected operator " << to_string(expected_operator) << L" but got " << *t; + std::stringstream ss; + ss << "Expected operator " << to_string(expected_operator) << " but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedOperator, ss.str()); } @@ 628,16 628,16 @@ const Token *SyntaxParser::parse_keyword if (is_keyword(t, expected_keyword)) return consume_next_token(); - std::wstringstream ss; - ss << L"Expected keyword " << to_string(expected_keyword) << L" but got " << *t; + std::stringstream ss; + ss << "Expected keyword " << to_string(expected_keyword) << " but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedKeyword, ss.str()); } const Token *SyntaxParser::parse_namespace(const Token *t) { if (_state.macro_depth > 0) { - std::wstringstream ss; - ss << L"Namespaces are not allowed within macros"; + std::stringstream ss; + ss << "Namespaces are not allowed within macros"; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::NamespaceNotAllowedInMacros, ss.str()); } t = consume_next_token(); @@ 658,8 658,8 @@ const Token *SyntaxParser::parse_namespa const Token *SyntaxParser::parse_module(const Token *t) { if (_state.macro_depth > 0) { - std::wstringstream ss; - ss << L"Modules are not allowed within macros"; + std::stringstream ss; + ss << "Modules are not allowed within macros"; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ModulesNotAllowedInMacros, ss.str()); } t = consume_next_token(); @@ 814,14 814,14 @@ const Token *SyntaxParser::parse_value_i if (UNLIKELY(auto_symbol)) { bool allowed = false; uint64_t source_auto_symbols[] = { - hash_constant(0xe7ea7c19636d0f2aULL, L"loop"), - hash_constant(0xf9769a6fb36bbd0dULL, L"continue"), - hash_constant(0xa8cae8d87ab282a1ULL, L"i"), + hash_constant(0xcfcf631033a8ce0bULL, "loop"), + hash_constant(0xe3346b77faff7b33ULL, "continue"), + hash_constant(0x27de6b5e0ecaf3bdULL, "i"), }; uint64_t target_auto_symbols[] = { - hash_constant(0x9d60c3eb1644552dULL, L"@loop"), - hash_constant(0xdaa803af4141d0e8ULL, L"@continue"), - hash_constant(0x1ded7765ceceebccULL, L"@i"), + hash_constant(0xdb831a5e32f85dcfULL, "@loop"), + hash_constant(0x232e8dde60eefef3ULL, "@continue"), + hash_constant(0x2d8619a103210bb8ULL, "@i"), }; // find and convert names to symbol name including the @ character for(size_t i = 0; i < sizeof(source_auto_symbols)/sizeof(source_auto_symbols[0]); ++i) { @@ 832,14 832,14 @@ const Token *SyntaxParser::parse_value_i } } if (!allowed) { - std::wstringstream ss; - ss << L"Unsupported auto label @" << _strings.get(name) << L"."; + std::stringstream ss; + ss << "Unsupported auto label @" << _strings.get(name) << "."; throw AssemblyException(_source_files, symbol_start->source_location, AssemblyErrorCodes::UnsupportedAutoLabel, ss.str()); } - if (name == hash_constant(0x9d60c3eb1644552dULL, L"@loop")) { + if (name == hash_constant(0xdb831a5e32f85dcfULL, "@loop")) { mark_use_of_loop_variable(); - } else if (name == hash_constant(0xdaa803af4141d0e8ULL, L"@continue")) { + } else if (name == hash_constant(0x232e8dde60eefef3ULL, "@continue")) { mark_use_of_continue_variable(); } } @@ 919,14 919,14 @@ const Token *SyntaxParser::parse_value_i // move the operator to the output apply_operator_on_expression_stack(); } else { - std::wstringstream ss; - ss << L"Misplaced right parenthesis or parenthesis without something within"; + std::stringstream ss; + ss << "Misplaced right parenthesis or parenthesis without something within"; throw AssemblyException(_source_files, token->source_location, AssemblyErrorCodes::EmptyParenthesisContents, ss.str()); } } else { - std::wstringstream ss; - ss << L"Expected expression value but got " << *token; + std::stringstream ss; + ss << "Expected expression value but got " << *token; throw AssemblyException(_source_files, token->source_location, AssemblyErrorCodes::ExpectedExpressionValue, ss.str()); } @@ 982,8 982,8 @@ const Token *SyntaxParser::parse_after_v return token; } if (found_type != OperatorType::Call) { - std::wstringstream ss; - ss << L"Unexpected comma in expression"; + std::stringstream ss; + ss << "Unexpected comma in expression"; throw AssemblyException(_source_files, token->source_location, AssemblyErrorCodes::CommaInExpression, ss.str()); } @@ 1013,15 1013,15 @@ const Token *SyntaxParser::parse_after_v end_of_expression = true; return token; } - std::wstringstream ss; - ss << L"Unmatched right parenthesis in expression"; + std::stringstream ss; + ss << "Unmatched right parenthesis in expression"; throw AssemblyException(_source_files, token->source_location, AssemblyErrorCodes::UnmatchedRightParenthesis, ss.str()); } if (found_type == OperatorType::ArrayAccess) { // we have a mismatch between parenthesis, like this: ([) const ExpressionComponent &bracket = _component_storage[_operator_stack.back()]; - std::wstringstream ss; - ss << L"Unmatched left bracket in expression"; + std::stringstream ss; + ss << "Unmatched left bracket in expression"; throw AssemblyException(_source_files, bracket.source_location, AssemblyErrorCodes::UnmatchedLeftBracket, ss.str()); } // move the operator if it was a function call operator @@ 1047,15 1047,15 @@ const Token *SyntaxParser::parse_after_v return token; } - std::wstringstream ss; - ss << L"Unmatched right bracket in expression"; + std::stringstream ss; + ss << "Unmatched right bracket in expression"; throw AssemblyException(_source_files, token->source_location, AssemblyErrorCodes::UnmatchedRightParenthesis, ss.str()); } if (found_type != OperatorType::ArrayAccess) { // we have a mismatch between parenthesis, like this: [(] const ExpressionComponent &parenthesis = _component_storage[_operator_stack.back()]; - std::wstringstream ss; - ss << L"Unmatched left parenthesis in expression"; + std::stringstream ss; + ss << "Unmatched left parenthesis in expression"; throw AssemblyException(_source_files, parenthesis.source_location, AssemblyErrorCodes::UnmatchedLeftBracket, ss.str()); } // move the operator @@ 1241,12 1241,12 @@ const Token *SyntaxParser::parse_express ExpressionComponent &op = _component_storage[operator_index]; if (op.type == ExpressionComponentType::Operator) { if (op.operator_type == OperatorType::LeftParenthesis || op.operator_type == OperatorType::Call) { - std::wstringstream ss; - ss << L"Unmatched left parenthesis in expression"; + std::stringstream ss; + ss << "Unmatched left parenthesis in expression"; throw AssemblyException(_source_files, op.source_location, AssemblyErrorCodes::UnmatchedLeftParenthesis, ss.str()); } else if (op.operator_type == OperatorType::ArrayAccess) { - std::wstringstream ss; - ss << L"Unmatched left bracket in expression"; + std::stringstream ss; + ss << "Unmatched left bracket in expression"; throw AssemblyException(_source_files, op.source_location, AssemblyErrorCodes::UnmatchedLeftBracket, ss.str()); } } @@ 1367,7 1367,7 @@ bool SyntaxParser::range_for_loop_follow } // the 'in' word - bool in_matches = t->type == TokenType::Symbol && static_cast<const SymbolToken *>(t)->symbol_hash == hash_constant(0xed47e3eba8572b75ULL, L"in"); + bool in_matches = t->type == TokenType::Symbol && static_cast<const SymbolToken *>(t)->symbol_hash == hash_constant(0x6844b03e1cbc50b0ULL, "in"); return in_matches; } @@ 1413,8 1413,8 @@ uint16_t SyntaxParser::try_parse_address // verify that "x" follows next = skip_spaces_and_tabs(consume_next_token()); if (next->type != TokenType::ProcessorKeyword || next->processor_keyword_index != ProcessorKeywordType::X) { - std::wstringstream ss; - ss << L"Expected x for indirect addressing mode, but got " << *next; + std::stringstream ss; + ss << "Expected x for indirect addressing mode, but got " << *next; throw AssemblyException(_source_files, next->source_location, AssemblyErrorCodes::InvalidIndexRegisterInAddressingMode, ss.str()); } // (<expression>,x @@ 1422,8 1422,8 @@ uint16_t SyntaxParser::try_parse_address // verify that right parenthesis follows next = skip_spaces_and_tabs(consume_next_token()); if (next->type != TokenType::Operator || next->operator_index != OperatorType::RightParenthesis) { - std::wstringstream ss; - ss << L"Expected closing parenthesis in indirect addressing mode, but got " << *next; + std::stringstream ss; + ss << "Expected closing parenthesis in indirect addressing mode, but got " << *next; throw AssemblyException(_source_files, next->source_location, AssemblyErrorCodes::ExpectedEndingParenthesisInIndirectAddressingMode, ss.str()); } // (<expression>,x) @@ 1480,8 1480,8 @@ uint16_t SyntaxParser::try_parse_address 1 << static_cast<int>(AddressingModeType::AbsoluteIndexY); } // the index register is invalid - std::wstringstream ss; - ss << L"Invalid index register in addressing mode. Expected x or y but got " << *next; + std::stringstream ss; + ss << "Invalid index register in addressing mode. Expected x or y but got " << *next; throw AssemblyException(_source_files, next->source_location, AssemblyErrorCodes::InvalidIndexRegisterInAddressingMode, ss.str()); } // (<expression>)<operator><expression> @@ 1501,8 1501,8 @@ uint16_t SyntaxParser::try_parse_address return 1 << static_cast<int>(AddressingModeType::IndirectIndexY); } // the index register is invalid - std::wstringstream ss; - ss << L"Invalid index register in addressing mode. Expected y but got " << *next; + std::stringstream ss; + ss << "Invalid index register in addressing mode. Expected y but got " << *next; throw AssemblyException(_source_files, next->source_location, AssemblyErrorCodes::InvalidIndexRegisterInAddressingMode, ss.str()); } // (<expression>) @@ 1512,8 1512,8 @@ uint16_t SyntaxParser::try_parse_address } // no matching parenthesis was found - std::wstringstream ss; - ss << L"Unmatched left parenthesis in expression"; + std::stringstream ss; + ss << "Unmatched left parenthesis in expression"; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::UnmatchedLeftParenthesis, ss.str()); } @@ 1560,8 1560,8 @@ uint16_t SyntaxParser::try_parse_address 1 << static_cast<int>(AddressingModeType::AbsoluteIndexY); } // the index register is invalid - std::wstringstream ss; - ss << L"Invalid index register in addressing mode. Expected x or y but got " << *next; + std::stringstream ss; + ss << "Invalid index register in addressing mode. Expected x or y but got " << *next; throw AssemblyException(_source_files, next->source_location, AssemblyErrorCodes::InvalidIndexRegisterInAddressingMode, ss.str()); } // <expression> @@ 1573,11 1573,11 @@ uint16_t SyntaxParser::try_parse_address 1 << static_cast<int>(AddressingModeType::RelativeAddr); } -void SyntaxParser::print_addressing_modes(std::wstringstream &ss, uint16_t addressing_mode_mask) +void SyntaxParser::print_addressing_modes(std::stringstream &ss, uint16_t addressing_mode_mask) { for (int i = 0; i < static_cast<int>(AddressingModeType::NumAddressingModes); ++i) { if (((1 << i) & addressing_mode_mask) != 0) - ss << L"\n " << to_string(static_cast<AddressingModeType>(i)); + ss << "\n " << to_string(static_cast<AddressingModeType>(i)); } } @@ 1606,10 1606,10 @@ const Token *SyntaxParser::parse_instruc uint16_t possible_addressing_modes = addressing_modes(instruction); uint16_t selected_addressing_modes = parsed_addressing_modes & possible_addressing_modes; if (selected_addressing_modes == 0) { - std::wstringstream ss; - ss << L"Invalid addressing mode used. Code indicates one of the following:"; + std::stringstream ss; + ss << "Invalid addressing mode used. Code indicates one of the following:"; print_addressing_modes(ss, parsed_addressing_modes); - ss << L"\nbut possible addressing modes for " << to_string(instruction) << " are:"; + ss << "\nbut possible addressing modes for " << to_string(instruction) << " are:"; print_addressing_modes(ss, possible_addressing_modes); throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::InvalidAddressingMode, ss.str()); } @@ 1629,8 1629,8 @@ const Token *SyntaxParser::parse_instruc // now we should be able to parse the operand of the instruction if (selected_addressing_modes == Imp) { if (has_label_definition) { - std::wstringstream ss; - ss << L"Implied addressing modes cannot have label to instruction data. Add a newline or a semicolon before the label to resolve this."; + std::stringstream ss; + ss << "Implied addressing modes cannot have label to instruction data. Add a newline or a semicolon before the label to resolve this."; throw AssemblyException(_source_files, label_token->source_location, AssemblyErrorCodes::AddressingModeCannotHaveDataLabel, ss.str()); } return t; @@ 1764,8 1764,8 @@ InstructionArgumentType SyntaxParser::tr } } else { // invalid register or keyword - std::wstringstream ss; - ss << to_string(keyword) << L" cannot be used for indirect addessing."; + std::stringstream ss; + ss << to_string(keyword) << " cannot be used for indirect addessing."; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::KeywordCannotBeUsedForIndirectAddressing, ss.str()); } t = skip_spaces_and_tabs(t); @@ 1848,13 1848,13 @@ bool find_addressing_mode(AddressingMode return true; } -void print_addressing_mode(std::wstringstream &ss, InstructionType instruction, AddressingModeArguments args) +void print_addressing_mode(std::stringstream &ss, InstructionType instruction, AddressingModeArguments args) { ss << to_string(instruction); if (args.arg1 != InstructionArgumentType::None) { - ss << L' ' << to_string(args.arg1); + ss << ' ' << to_string(args.arg1); if (args.arg2 != InstructionArgumentType::None) { - ss << L", " << to_string(args.arg2); + ss << ", " << to_string(args.arg2); } } ss << '\n'; @@ 1977,7 1977,7 @@ const Token *SyntaxParser::parse_and_out case InstructionArgumentType::NumTypes: assert(false); - throw AssemblyException(L"Internal error"); + throw AssemblyException("Internal error"); }; return t; } @@ 1995,17 1995,17 @@ const Token *SyntaxParser::parse_instruc instruction_token.instruction = instruction; // determine used addressing mode - auto addressing_mode = try_parse_addressing_modes(t, instruction, instruction_token.has_instruction_data_label, instruction_token.global_data_label, instruction_token.address_label_location, instruction_token.data_label_symbol_hash); + AddressingModeArguments addressing_mode = try_parse_addressing_modes(t, instruction, instruction_token.has_instruction_data_label, instruction_token.global_data_label, instruction_token.address_label_location, instruction_token.data_label_symbol_hash); // search through the array of possible addressing modes for the instruction - auto &available_modes = addressing_modes(instruction); + const core::StaticArray<AddressingMode> &available_modes = addressing_modes(instruction); size_t found_index; if (UNLIKELY(!find_addressing_mode(addressing_mode, available_modes, found_index))) { - std::wstringstream ss; - ss << L"Invalid addressing mode used. Code indicates:\n"; + std::stringstream ss; + ss << "Invalid addressing mode used. Code indicates:\n"; print_addressing_mode(ss, instruction, addressing_mode); if (available_modes.size() <= max_addressing_mode_printout_lines) { - ss << L"but possible addressing modes are:\n"; + ss << "but possible addressing modes are:\n"; for(auto mode : available_modes) { print_addressing_mode(ss, instruction, mode.detailed); } @@ 2034,8 2034,8 @@ const Token *SyntaxParser::parse_using_s { t = skip_whitespaces(t); if (t->type != TokenType::Keyword || t->keyword_index != KeywordType::Namespace) { - std::wstringstream ss; - ss << L"Expected namespace keyword but got " << *t; + std::stringstream ss; + ss << "Expected namespace keyword but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedNamespaceKeyword, ss.str()); } @@ 2045,8 2045,8 @@ const Token *SyntaxParser::parse_using_s bool is_symbol = t->type == TokenType::Symbol && !is_instruction(*t); if (!is_symbol && !is_operator(t, OperatorType::Namespace)) { - std::wstringstream ss; - ss << L"Namespace expected in using statement, but got " << *t; + std::stringstream ss; + ss << "Namespace expected in using statement, but got " << *t; throw AssemblyException(_source_files, symbol_start->source_location, AssemblyErrorCodes::ExpectedNamespaceInUsingStatement, ss.str()); } @@ 2076,16 2076,16 @@ const Token *SyntaxParser::parse_section // read source name if (t->type != TokenType::String) { - std::wstringstream ss; - ss << L"Section mapping expects string literal but got " << to_string(t->type) << L"."; + std::stringstream ss; + ss << "Section mapping expects string literal but got " << to_string(t->type) << "."; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::SectionMappingExpectsStringLiteral, ss.str()); } uint64_t source_hash = static_cast<const StringToken *>(t)->value; // check for duplicated sources if (used_sources.find(source_hash) != used_sources.end()) { - std::wstringstream ss; - ss << L"Section mapping has same source " << _strings.get(source_hash) << L" used twice."; + std::stringstream ss; + ss << "Section mapping has same source " << _strings.get(source_hash) << " used twice."; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::SectionMappingHasDoubleSources, ss.str()); } @@ 2098,8 2098,8 @@ const Token *SyntaxParser::parse_section // read target name if (t->type != TokenType::String) { - std::wstringstream ss; - ss << L"Section mapping expects string literal but got " << to_string(t->type) << L"."; + std::stringstream ss; + ss << "Section mapping expects string literal but got " << to_string(t->type) << "."; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::SectionMappingExpectsStringLiteral, ss.str()); } uint64_t target_hash = static_cast<const StringToken *>(t)->value; @@ 2154,8 2154,8 @@ const Token *SyntaxParser::parse_section const Token *keyword_token = t; if (_state.macro_depth > 0) { - std::wstringstream ss; - ss << L"A section was defined within a macro"; + std::stringstream ss; + ss << "A section was defined within a macro"; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::SectionInMacro, ss.str()); } @@ 2165,18 2165,18 @@ const Token *SyntaxParser::parse_section SectionType section_type = SectionType::None; bool is_symbol = t->type == TokenType::Symbol; bool section_part = false; - if (is_symbol && static_cast<const SymbolToken *>(t)->symbol_hash == hash_constant(0x66c471157eed626fULL, L"code")) { + if (is_symbol && static_cast<const SymbolToken *>(t)->symbol_hash == hash_constant(0xe8443b5d4326e23aULL, "code")) { section_type = SectionType::Code; - } else if (is_symbol && static_cast<const SymbolToken *>(t)->symbol_hash == hash_constant(0xbb814bc3ed78e1eULL, L"bss")) { + } else if (is_symbol && static_cast<const SymbolToken *>(t)->symbol_hash == hash_constant(0x1a160cdedb256990ULL, "bss")) { section_type = SectionType::Bss; - } else if (is_symbol && static_cast<const SymbolToken *>(t)->symbol_hash == hash_constant(0xbf2dbfc9c1f4d88bULL, L"part")) { + } else if (is_symbol && static_cast<const SymbolToken *>(t)->symbol_hash == hash_constant(0x839745e36a8ea16cULL, "part")) { section_part = true; - } else if (is_symbol && static_cast<const SymbolToken *>(t)->symbol_hash == hash_constant(0xe2a6f83151dc3f8dULL, L"mapping")) { + } else if (is_symbol && static_cast<const SymbolToken *>(t)->symbol_hash == hash_constant(0x4def7bac3187bbd3ULL, "mapping")) { t = consume_next_token(); return parse_section_mapping(t); } else { - std::wstringstream ss; - ss << L"Expected code, bss, part or mapping keyword, but got " << *t; + std::stringstream ss; + ss << "Expected code, bss, part or mapping keyword, but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedCodeOrBssAfterSection, ss.str()); } @@ 2186,16 2186,16 @@ const Token *SyntaxParser::parse_section t = skip_whitespaces(t); if (t->type != TokenType::String) { - std::wstringstream ss; - ss << L"Expected section name as a quoted string, but got " << *t; + std::stringstream ss; + ss << "Expected section name as a quoted string, but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedSectionNameAsAQuotedString, ss.str()); } uint64_t name_hash = static_cast<const StringToken *>(t)->value; // detect empty section names - if (name_hash == hash_constant(0, L"")) { - std::wstringstream ss; - ss << L"Empty section name"; + if (name_hash == hash_constant(0, "")) { + std::stringstream ss; + ss << "Empty section name"; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::EmptySectionName, ss.str()); } @@ 2207,8 2207,8 @@ const Token *SyntaxParser::parse_section // detect duplicate section names if (_state.sections.find(name_hash) != _state.sections.end()) { - std::wstringstream ss; - ss << L"Duplicate section names '" << _strings.get(name_hash) << L"'"; + std::stringstream ss; + ss << "Duplicate section names '" << _strings.get(name_hash) << "'"; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::DuplicateSectionNames, ss.str()); } _state.sections.insert(name_hash); @@ 2245,10 2245,10 @@ const Token *SyntaxParser::parse_section OptimizerType SyntaxParser::string_to_optimizer_type(const StringToken *t) { static uint64_t optimizer_strings[] = { - hash_constant(0x6f37214ebe092566ULL, L"zero compare"), - hash_constant(0x08f1ff863c128d20ULL, L"tail recursion"), - hash_constant(0x8596120dfe420126ULL, L"double load"), - hash_constant(0x7deef6f1325f7717ULL, L"unused function"), + hash_constant(0xa13435ad5787c1f6ULL, "zero compare"), + hash_constant(0x768c31d8545cb539ULL, "tail recursion"), + hash_constant(0x9f67cc59c2c44a7aULL, "double load"), + hash_constant(0x8a155feb2a9d2ddeULL, "unused function"), }; static_assert(sizeof(optimizer_strings) / sizeof(uint64_t) == static_cast<int>(OptimizerType::NumTypes), "Number of optimizer modes doesn't match number of strings"); @@ 2257,8 2257,8 @@ OptimizerType SyntaxParser::string_to_op return static_cast<OptimizerType>(i); } - std::wstringstream ss; - ss << L"Unknown optimizer mode '" << _strings.get(t->value) << L"'"; + std::stringstream ss; + ss << "Unknown optimizer mode '" << _strings.get(t->value) << "'"; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::UnsupportedOptimizerMode, ss.str()); } @@ 2267,8 2267,8 @@ const Token *SyntaxParser::parse_optimiz t = skip_whitespaces(t); // check for complete on or off first - uint64_t on_symbol = hash_constant(0x1f5646d42de12e93ULL, L"on"); - uint64_t off_symbol = hash_constant(0xe7bb0a6c19508283ULL, L"off"); + uint64_t on_symbol = hash_constant(0x2dc975ff398a1ab9ULL, "on"); + uint64_t off_symbol = hash_constant(0x674313aceb22ee1dULL, "off"); if (t->type == TokenType::Symbol) { uint64_t symbol_hash = static_cast<const SymbolToken *>(t)->symbol_hash; if (symbol_hash == on_symbol || symbol_hash == off_symbol) { @@ 2284,8 2284,8 @@ const Token *SyntaxParser::parse_optimiz // not global on or off, so we are looking for an optimizer string now if (t->type != TokenType::String) { - std::wstringstream ss; - ss << L"Expected optimizer string or on/off keyword but got " << *t; + std::stringstream ss; + ss << "Expected optimizer string or on/off keyword but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedOptimizerString, ss.str()); } @@ 2303,8 2303,8 @@ const Token *SyntaxParser::parse_optimiz optimizer_token.enable = symbol_token->symbol_hash == on_symbol; optimizer_token.optimizer_type = optimizer_type; } else { - std::wstringstream ss; - ss << L"Expected on or off keyword but got " << *t; + std::stringstream ss; + ss << "Expected on or off keyword but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedOnOrOffOptimizerKeyword, ss.str()); } @@ 2370,22 2370,22 @@ const Token *SyntaxParser::parse_macro_s // all parameters are local symbols const Token *symbol_token = t; if (t->type != TokenType::Operator || t->operator_index != OperatorType::Period) { - std::wstringstream ss; - ss << L"Expected macro argument local symbol but got " << *t; + std::stringstream ss; + ss << "Expected macro argument local symbol but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedMacroArgumentLocalSymbol, ss.str()); } t = consume_next_token(); if (t->type != TokenType::Symbol) { - std::wstringstream ss; - ss << L"Expected macro argument local symbol but got a period and " << *t; + std::stringstream ss; + ss << "Expected macro argument local symbol but got a period and " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedMacroArgumentLocalSymbol, ss.str()); } // Linear search amongst the other arguments. // Arguments should be few so this should be the fastest way. uint64_t arg_hash = static_cast<const SymbolToken *>(t)->symbol_hash; if (std::find(_temp_hash_array.begin(), _temp_hash_array.end(), arg_hash) != _temp_hash_array.end()) { - std::wstringstream ss; - ss << L"Duplicate argument name ." << _strings.get(arg_hash); + std::stringstream ss; + ss << "Duplicate argument name ." << _strings.get(arg_hash); throw AssemblyException(_source_files, symbol_token->source_location, AssemblyErrorCodes::DuplicatedMacroArgumentNames, ss.str()); } _temp_hash_array.push_back(arg_hash); @@ 2437,8 2437,8 @@ const Token *SyntaxParser::parse_macro_s const Token *SyntaxParser::parse_return_statement(const Token *t) { if (_state.macro_depth == 0) { - std::wstringstream ss; - ss << L"Return statement only allowed in macro definition."; + std::stringstream ss; + ss << "Return statement only allowed in macro definition."; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ReturnMustBeInMacro, ss.str()); } @@ 2464,14 2464,14 @@ const Token *SyntaxParser::parse_subrout { // subroutines are not allowed in macros and cannot be nested if (_state.macro_depth > 0) { - std::wstringstream ss; - ss << L"Subroutine is not allowed in a macro definition."; + std::stringstream ss; + ss << "Subroutine is not allowed in a macro definition."; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::SubroutineNotAllowedInMacro, ss.str()); } // subroutines cannot be nested if (_state.subroutine_depth > 0) { - std::wstringstream ss; - ss << L"Subroutine can not be nested."; + std::stringstream ss; + ss << "Subroutine can not be nested."; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::SubroutinesCanNotBeNested, ss.str()); } @@ 2524,8 2524,8 @@ const Token *SyntaxParser::parse_type_re reference.type_namespace_handle = _hash_arrays.add(_temp_hash_array); } else { - std::wstringstream ss; - ss << L"Expected type but got " << *t; + std::stringstream ss; + ss << "Expected type but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedTypeInStruct, ss.str()); } @@ 2537,8 2537,8 @@ const Token *SyntaxParser::parse_type_re t = skip_whitespaces(consume_next_token()); if (is_operator(t, OperatorType::RightBracket)) { if (array_size_is_required) { - std::wstringstream ss; - ss << L"Array declaration must have a known size"; + std::stringstream ss; + ss << "Array declaration must have a known size"; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ArrayDeclarationMustHaveSize, ss.str()); } reference.array_flag = ArrayFlag::ArrayWithUnknownSize; @@ 2589,8 2589,8 @@ const Token *SyntaxParser::parse_struct_ t = skip_whitespaces(t); if (t->type != TokenType::Symbol) { - std::wstringstream ss; - ss << L"Expected struct member name but got " << *t; + std::stringstream ss; + ss << "Expected struct member name but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedStructMemberName, ss.str()); } @@ 2690,8 2690,8 @@ const Token *SyntaxParser::parse_define_ if (is_operator(t, OperatorType::Comma)) { // detect comma outside array definition if (_temp_pointer_array.empty()) { - std::wstringstream ss; - ss << L"Unexpected comma. Curly brackets are needed around groups of values."; + std::stringstream ss; + ss << "Unexpected comma. Curly brackets are needed around groups of values."; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::UnexpectedCommaInDefinition, ss.str()); } @@ 2793,8 2793,8 @@ const Token *SyntaxParser::parse_enum_de const Token *symbol_token = t; // this requires whitespaces to be skipped at this point! t = parse_global_symbol_definition(t, symbol); if (symbols.find(symbol) != symbols.end()) { - std::wstringstream ss; - ss << L"Duplicated enum member " << _strings.get(symbol); + std::stringstream ss; + ss << "Duplicated enum member " << _strings.get(symbol); throw AssemblyException(_source_files, symbol_token->source_location, AssemblyErrorCodes::DuplicatedEnumMemberName, ss.str()); } symbols.insert(symbol); @@ 2835,8 2835,8 @@ const Token *SyntaxParser::parse_enum_de break; if (!have_more_definitions) { - std::wstringstream ss; - ss << L"Expected comma or '}' in enum definition but got " << to_string(t->type) << L'.'; + std::stringstream ss; + ss << "Expected comma or '}' in enum definition but got " << to_string(t->type) << '.'; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedCommaOrRightCurlyInEnumDefinition, ss.str()); } } @@ 2898,7 2898,7 @@ const Token *SyntaxParser::parse_range_f loop_begin_token.key_location.clear(); } - assert(t->type == TokenType::Symbol && static_cast<const SymbolToken *>(t)->symbol_hash == hash_constant(0xed47e3eba8572b75ULL, L"in")); + assert(t->type == TokenType::Symbol && static_cast<const SymbolToken *>(t)->symbol_hash == hash_constant(0x6844b03e1cbc50b0ULL, "in")); t = consume_next_token(); // 'in' constexpr bool end_at_unmatched_right_parenthesis = true; @@ 3215,8 3215,8 @@ const Token *SyntaxParser::parse_keyword case KeywordType::Dynamic: case KeywordType::Import: { - std::wstringstream ss; - ss << L"Unexpected " << *t; + std::stringstream ss; + ss << "Unexpected " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::UnexpectedKeyword, ss.str()); } @@ 3224,8 3224,8 @@ const Token *SyntaxParser::parse_keyword case KeywordType::Basic: case KeywordType::NumTypes: { - std::wstringstream ss; - ss << L"Keyword " << *t << L" not implemented"; + std::stringstream ss; + ss << "Keyword " << *t << " not implemented"; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::NotImplemented, ss.str()); } @@ 3249,8 3249,8 @@ const Token *SyntaxParser::parse_name_de declare_token.source_location = t->source_location; if (!is_operator(t, OperatorType::Period)) { - std::wstringstream ss; - ss << L"Expected local symbol name but got " << *t; + std::stringstream ss; + ss << "Expected local symbol name but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedLocalSymbolName, ss.str()); } @@ 3305,8 3305,8 @@ const Token *SyntaxParser::parse_variabl // verify that we have an assignment as root const ExpressionComponent &root = _component_storage[_expression_stack[0]]; if (!is_operator(root, OperatorType::Assignment)) { - std::wstringstream ss; - ss << L"Missing assignment in dynamic const or variable definition"; + std::stringstream ss; + ss << "Missing assignment in dynamic const or variable definition"; throw AssemblyException(_source_files, expression_start->source_location, AssemblyErrorCodes::MissingAssignmentInVariableDefinition, ss.str()); } @@ 3380,8 3380,8 @@ const Token *SyntaxParser::parse_label_o symbol = consume_next_token(); if (symbol->type != TokenType::Symbol) { - std::wstringstream ss; - ss << L"Local symbol expected, but got a punction mark followed by " << *symbol; + std::stringstream ss; + ss << "Local symbol expected, but got a punction mark followed by " << *symbol; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::LocalSymbolExpected, ss.str()); } } @@ 3467,8 3467,8 @@ const Token *SyntaxParser::parse_inner_s case TokenType::ProcessorKeyword: { - std::wstringstream ss; - ss << L"Unexpected " << to_string(t->type); + std::stringstream ss; + ss << "Unexpected " << to_string(t->type); throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::UnexpectedProcessorKeyword, ss.str()); } @@ 3478,8 3478,8 @@ const Token *SyntaxParser::parse_inner_s case TokenType::NumTypes: { assert(false); - std::wstringstream ss; - ss << L"Internal error: unexpected token " << to_string(t->type); + std::stringstream ss; + ss << "Internal error: unexpected token " << to_string(t->type); throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::InternalError, ss.str()); } }; @@ 3538,8 3538,8 @@ void SyntaxParser::parse() t = parse_inner_scope(t); if (t->type != TokenType::End) { - std::wstringstream ss; - ss << L"Expected end of file but got " << *t; + std::stringstream ss; + ss << "Expected end of file but got " << *t; throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedEndOfFile, ss.str()); } @@ 3549,9 3549,9 @@ void SyntaxParser::parse() end_token.size = sizeof(SyntaxToken); } -std::vector<TokenChain> parse_syntax(const TokenChain &input, const StringRepository &strings, HashArrayRepository &hash_arrays, const std::vector<std::wstring> &source_files, DataReader &data_reader) +std::vector<TokenChain> parse_syntax(const TokenChain &input, const StringRepository &strings, HashArrayRepository &hash_arrays, const std::vector<std::string> &source_files, DataReader &data_reader) { - TimerScope timer(L"Syntax parser"); + TimerScope timer("Syntax parser"); std::vector<TokenChain> output; output.reserve(64);
M jasm/parsing/syntax_parser.h +1 -1
@@ 18,7 18,7 @@ class HashArrayRepository; /// @param hash_arrays A repository for hash arrays to make it possible to store references in constant size memory. /// @param source_files An array of files used to lookup source file name when printing error messages. /// @param data_reader An asynchronous data reader for incbin files. -std::vector<TokenChain> parse_syntax(const TokenChain &input, const StringRepository &strings, HashArrayRepository &hash_arrays, const std::vector<std::wstring> &source_files, DataReader &data_reader); +std::vector<TokenChain> parse_syntax(const TokenChain &input, const StringRepository &strings, HashArrayRepository &hash_arrays, const std::vector<std::string> &source_files, DataReader &data_reader); /// @}
M jasm/parsing/syntax_tokens.cpp +17 -17
@@ 5,12 5,12 @@ namespace jasm { -const std::wstring_view to_string(SectionType type) +const std::string_view to_string(SectionType type) { - static const std::wstring_view names[] = { - std::wstring_view(L"none"), - std::wstring_view(L"code"), - std::wstring_view(L"bss"), + static const std::string_view names[] = { + std::string_view("none"), + std::string_view("code"), + std::string_view("bss"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(SectionType::NumTypes), "Number of section types doesn't match number of strings"); @@ 18,19 18,19 @@ const std::wstring_view to_string(Sectio return names[static_cast<size_t>(type)]; } -const std::wstring_view to_string(ExpressionComponentType type) +const std::string_view to_string(ExpressionComponentType type) { - static const std::wstring_view names[] = { - std::wstring_view(L"bool"), - std::wstring_view(L"integer"), - std::wstring_view(L"float"), - std::wstring_view(L"string"), - std::wstring_view(L"typename"), - std::wstring_view(L"operator"), - std::wstring_view(L"global symbol"), - std::wstring_view(L"local symbol"), - std::wstring_view(L"auto symbol"), - std::wstring_view(L"program counter"), + static const std::string_view names[] = { + std::string_view("bool"), + std::string_view("integer"), + std::string_view("float"), + std::string_view("string"), + std::string_view("typename"), + std::string_view("operator"), + std::string_view("global symbol"), + std::string_view("local symbol"), + std::string_view("auto symbol"), + std::string_view("program counter"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(ExpressionComponentType::NumTypes), "Number of expression component types doesn't match number of strings");
M jasm/parsing/syntax_tokens.h +2 -2
@@ 541,8 541,8 @@ struct IncBinToken : public SyntaxToken // 8 byte aligned }; -const std::wstring_view to_string(SectionType type); -const std::wstring_view to_string(ExpressionComponentType type); +const std::string_view to_string(SectionType type); +const std::string_view to_string(ExpressionComponentType type); /// @}
M jasm/parsing/token_print.cpp +8 -8
@@ 6,10 6,10 @@ namespace jasm { -std::wostream& operator<<(std::wostream& out, const Token &t) +std::ostream& operator<<(std::ostream& out, const Token &t) { if (is_instruction(t)) { - out << L"instruction"; + out << "instruction"; } else { out << to_string(t.type); } @@ 28,29 28,29 @@ std::wostream& operator<<(std::wostream& case TokenType::Symbol: { if (t.instruction_index != InstructionType::NumTypes) { - out << L" " << to_string(t.instruction_index); + out << " " << to_string(t.instruction_index); } break; } case TokenType::Boolean: - out << L" " << to_string(t.boolean_index); + out << " " << to_string(t.boolean_index); break; case TokenType::Operator: - out << L" " << to_string(t.operator_index); + out << " " << to_string(t.operator_index); break; case TokenType::Keyword: - out << L" " << to_string(t.keyword_index); + out << " " << to_string(t.keyword_index); break; case TokenType::ProcessorKeyword: - out << L" " << to_string(t.processor_keyword_index); + out << " " << to_string(t.processor_keyword_index); break; case TokenType::Typename: - out << L" " << to_string(t.typename_index); + out << " " << to_string(t.typename_index); break; } return out;
M jasm/parsing/token_print.h +1 -1
@@ 10,7 10,7 @@ struct Token; /// @addtogroup tokenize /// @{ -std::wostream& operator<<(std::wostream& out, const Token &t); +std::ostream& operator<<(std::ostream& out, const Token &t); /// @}
M jasm/parsing/tokenizer.cpp +149 -131
@@ 8,6 8,7 @@ #include <core/io/file_id.h> #include <core/io/text_reader.h> #include <core/strings/murmur_hash.h> +#include <core/strings/utf8.h> #include <exceptions/assembly_exception.h> #include <io/data_reader.h> #include <locale> @@ 131,37 132,38 @@ class Tokenizer public: struct TokenData { - std::wstring name; + std::string name; TokenType token_type; uint8_t token_type_index; }; - Tokenizer(const std::vector<std::wstring> &include_dirs, std::vector<std::wstring> &used_files, DataReader &data_reader) - : _include_dirs(include_dirs) + Tokenizer(bool pseudo_instructions, const std::vector<std::string> &include_dirs, std::vector<std::string> &used_files, DataReader &data_reader) + : _pseudo_instructions(pseudo_instructions) + , _include_dirs(include_dirs) , _used_files(used_files) , _data_reader(data_reader) { } - void init(const std::wstring &file); + void init(const std::string &file); void tokenize(const size_t file_index, TokenChain &token_chain, StringRepository &strings); private: template<typename T> - void add_type_tokens(std::vector<std::wstring> &names, TokenType type) { + void add_type_tokens(std::vector<std::string> &names, TokenType type) { for (uint8_t i = 0; i < static_cast<uint8_t>(T::NumTypes); ++i) { - TokenData token { std::wstring(to_string(static_cast<T>(i))), type, i }; + TokenData token { std::string(to_string(static_cast<T>(i))), type, i }; names.push_back(token.name); _hash_to_token.insert(murmur_hash3_string_x64_64(token.name)) = token; } } /// Turn backslashes into frontslashes in a string. - static std::wstring to_front_slashes(const std::wstring &path); + static std::string to_front_slashes(const std::string &path); /// Add a file to the used list and return its index. - size_t add_used_file(const std::wstring &file); + size_t add_used_file(const std::string &file); /// Tokenize either an int or a floating point number. Use temp as string storage and read from tracker. void tokenize_int_or_float(const size_t file_index, PositionTracker &tracker, TokenChain &token_chain); @@ 178,14 180,17 @@ private: void parse_include(const size_t file_index, PositionTracker &tracker, TokenChain &token_chain, StringRepository &strings); void preparse_incbin(const size_t file_index, PositionTracker tracker); - /// Parse quoted string into _temp_string. + /// Parse quoted string into _temp_wstring. void parse_quoted_string(const size_t file_index, PositionTracker &tracker); - /// Get a string view of _temp_string. - std::wstring_view temp_view(); - /// Convert _temp_string into a string. - std::wstring temp_string() + /// Convert _temp_wstring into a string. + std::string temp_string() { - return std::wstring(temp_view()); + _temp_string = core::wide_to_utf8(std::wstring_view(_temp_wstring.data(), _temp_wstring.size())); + return _temp_string; + } + std::wstring_view temp_wview() + { + return std::wstring_view(_temp_wstring.data(), _temp_wstring.size()); } /// Parse one character in a string or character literal. Handles newline, tab, return, quote, single quote and backslash. @@ 193,7 198,9 @@ private: wchar_t parse_next_string_character(PositionTracker &tracker); /// Temporary string used when parsing. - std::vector<wchar_t> _temp_string; + std::vector<wchar_t> _temp_wstring; + /// Temporary string used when parsing. + std::string _temp_string; /// This is used to find a keyword in a string. KeywordFinder _keyword_finder; /// This is used to find an operator in a string. @@ 203,11 210,14 @@ private: /// An array of include file identifiers used to determine file recursion. std::vector<FileId> _include_id_history; /// An array of include files in the same order as @a _include_id_history to be able to print the history in error messages. - std::vector<std::wstring> _include_file_history; + std::vector<std::string> _include_file_history; + + /// True if extended instructions are used. + bool _pseudo_instructions; /// An array of include directories we must search in to find include files. - const std::vector<std::wstring> &_include_dirs; + const std::vector<std::string> &_include_dirs; /// This array is filled with the included filenames and is used outside to map tokens to filenames. - std::vector<std::wstring> &_used_files; + std::vector<std::string> &_used_files; /// This is used to trigger file loads in the background. DataReader &_data_reader; /// Lookup table from hashed instruction name to instruction type. @@ 215,12 225,12 @@ private: }; -void Tokenizer::init(const std::wstring &file) +void Tokenizer::init(const std::string &file) { FileId fid; if (!file_id(file, fid)) { - std::wstringstream ss; - ss << L"Failed to open '" << file << L"'"; + std::stringstream ss; + ss << "Failed to open '" << file << "'"; throw FileException(ss.str()); } @@ 228,10 238,10 @@ void Tokenizer::init(const std::wstring _include_file_history.push_back(file); add_used_file(file); - _temp_string.reserve(256); + _temp_wstring.reserve(256); // add token data for keywords - std::vector<std::wstring> keywords; + std::vector<std::string> keywords; add_type_tokens<KeywordType>(keywords, TokenType::Keyword); add_type_tokens<TypenameType>(keywords, TokenType::Typename); add_type_tokens<BooleanType>(keywords, TokenType::Boolean); @@ 293,9 303,9 @@ void Tokenizer::init(const std::wstring constexpr int num_generated_operators = 10; static_assert(sizeof(operators_types) / sizeof(operators_types[0]) + num_generated_operators == static_cast<int>(OperatorType::NumTypes), "Number of types doesn't match number of definitions"); - std::vector<std::wstring> operators; + std::vector<std::string> operators; for (size_t i = 0; i < sizeof(operators_types) / sizeof(operators_types[0]); ++i) { - TokenData token { std::wstring(to_string(operators_types[i])), TokenType::Operator, static_cast<uint8_t>(operators_types[i]) }; + TokenData token { std::string(to_string(operators_types[i])), TokenType::Operator, static_cast<uint8_t>(operators_types[i]) }; operators.push_back(token.name); _hash_to_token.insert(murmur_hash3_string_x64_64(token.name)) = token; } @@ 303,30 313,41 @@ void Tokenizer::init(const std::wstring _operator_finder.set_keywords(operators); // generate instruction lookup - for (uint8_t i = 0; i < static_cast<uint8_t>(InstructionType::NumTypes); ++i) { + uint8_t num_instructions = static_cast<uint8_t>(_pseudo_instructions ? InstructionType::NumTypes : InstructionType::NumStandard); + for (uint8_t i = 0; i < num_instructions; ++i) { InstructionType type = static_cast<InstructionType>(i); - const std::wstring_view name = to_string(type); + const std::string_view name = to_string(type); _instructions.insert(murmur_hash3_string_x64_64(name)) = type; } } void Tokenizer::tokenize(const size_t file_index, TokenChain &token_chain, StringRepository &strings) { - std::wstring contents; + std::string contents; try { contents = load_file(_used_files[file_index]); } catch (Exception &e) { - std::wstringstream ss; - ss << e.message << L"\nwhile loading '" << _used_files[file_index] << L"'"; + std::stringstream ss; + ss << e.message << "\nwhile loading '" << _used_files[file_index] << "'"; e.message = ss.str(); throw e; } + + // convert to wide strings to simplify the character classification + std::wstring wide_contents; + try { + wide_contents = core::utf8_to_wide(contents); + } catch (Exception &) { + throw FileException("File contents isn't utf8 encoded: " + _used_files[file_index]); + } + + // classify all characters std::vector<MaskType> char_masks; // The classification of each character in the string // make the mask array as big as the source including null termination - char_masks.resize(contents.size() + 1); + char_masks.resize(wide_contents.size() + 1); // generate character classification from locale - std::locale loc; - std::use_facet<std::ctype<wchar_t>>(loc).is(&contents[0], &contents[0] + contents.size(), &char_masks[0]); + std::locale loc("en_US.utf8"); + std::use_facet<std::ctype<wchar_t>>(loc).is(wide_contents.data(), wide_contents.data() + wide_contents.size(), char_masks.data()); // categorize the null termination as "whitespace" to simplify parsing. char_masks[contents.size()] = #if defined(_MSC_VER) @@ 337,7 358,7 @@ void Tokenizer::tokenize(const size_t fi #error "Compiler not supported" #endif - PositionTracker tracker(contents.c_str(), &char_masks[0]); + PositionTracker tracker(wide_contents.c_str(), char_masks.data()); uint64_t hash; // used as out parameter for finder::match while (tracker.peek_char() != 0) { if (tracker.is_space()) { @@ 386,19 407,19 @@ void Tokenizer::tokenize(const size_t fi tracker.consume(); } if (depth != 0) { - std::wstringstream ss; - ss << L"Multiline comment was not terminated."; + std::stringstream ss; + ss << "Multiline comment was not terminated."; throw AssemblyException(_used_files[file_index], row, column, AssemblyErrorCodes::MultilineCommentWasNotTerminated, ss.str()); } } else if (tracker.is_digit()) { // matched either an int or a floating point number - _temp_string.clear(); + _temp_wstring.clear(); tokenize_int_or_float(file_index, tracker, token_chain); } else if (tracker.peek_char() == L'.' && tracker.is_digit(1)) { // matched a floating point number - _temp_string.clear(); + _temp_wstring.clear(); tokenize_float(file_index, tracker, token_chain, tracker.column, tracker.row); } else if (tracker.peek_char() == L'$') { @@ 435,8 456,10 @@ void Tokenizer::tokenize(const size_t fi tokenize_string(file_index, tracker, token_chain, strings); } else { - std::wstringstream ss; - ss << L"Unexpected character '" << tracker.peek_char() << L"'"; + std::stringstream ss; + std::string narrow_character; + core::wide_to_utf8(tracker.peek_char(), narrow_character); + ss << "Unexpected character '" << narrow_character << "'"; throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::UnexpectedCharacter, ss.str()); } } @@ 454,14 477,14 @@ void Tokenizer::tokenize(const size_t fi } } -std::wstring Tokenizer::to_front_slashes(const std::wstring &path) +std::string Tokenizer::to_front_slashes(const std::string &path) { - std::wstring front_slash_path(path); + std::string front_slash_path(path); std::replace(front_slash_path.begin(), front_slash_path.end(), '\\', '/'); return front_slash_path; } -size_t Tokenizer::add_used_file(const std::wstring &file) +size_t Tokenizer::add_used_file(const std::string &file) { size_t index = _used_files.size(); // make sure that the file has front slashes to get the output from linux and pc unit tests match @@ 506,7 529,7 @@ void Tokenizer::tokenize_int_or_float(co uint32_t row = tracker.row; while (tracker.is_digit()) { - _temp_string.push_back(tracker.peek_char()); + _temp_wstring.push_back(tracker.peek_char()); tracker.consume(); } if (tracker.peek_char() == L'.' || tracker.peek_char() == L'e') { @@ 516,8 539,8 @@ void Tokenizer::tokenize_int_or_float(co // check for immediately following character, which is an error if (tracker.is_alpha()) { - std::wstringstream ss; - ss << L"Letter follows directly after integer number " << &_temp_string[0]; + std::stringstream ss; + ss << "Letter follows directly after integer number " << temp_string(); throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::AlphaFollowingNumberLiteral, ss.str()); } @@ 534,8 557,8 @@ void Tokenizer::tokenize_int_or_float(co t.value = value; } catch (std::out_of_range &) { - std::wstringstream ss; - ss << L"Integer number " << temp_view() << " out of range"; + std::stringstream ss; + ss << "Integer number " << temp_string() << " out of range"; throw AssemblyException(_used_files[file_index], row, column, AssemblyErrorCodes::IntegerOutOfRange, ss.str()); } } @@ 547,11 570,11 @@ void Tokenizer::tokenize_float(const siz bool parse_exp = tracker.peek_char() == L'e'; if (!parse_exp) { // parse period - _temp_string.push_back(tracker.peek_char()); + _temp_wstring.push_back(tracker.peek_char()); tracker.consume(); while (tracker.is_digit()) { - _temp_string.push_back(tracker.peek_char()); + _temp_wstring.push_back(tracker.peek_char()); tracker.consume(); } // exponent may follow decimal digits @@ 560,33 583,32 @@ void Tokenizer::tokenize_float(const siz if (parse_exp) { // parse 'e' - _temp_string.push_back(tracker.peek_char()); + _temp_wstring.push_back(tracker.peek_char()); tracker.consume(); // parse optional + or - if (tracker.peek_char() == L'-' || tracker.peek_char() == L'+') { - _temp_string.push_back(tracker.peek_char()); + _temp_wstring.push_back(tracker.peek_char()); tracker.consume(); } // parse exponent if (!tracker.is_digit()) { - _temp_string.push_back(0); - std::wstringstream ss; - ss << L"Floating point number " << &_temp_string[0] << " is missing exponent"; + std::stringstream ss; + ss << "Floating point number " << temp_string() << " is missing exponent"; throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::MissingExponentInFloatingPoint, ss.str()); } while (tracker.is_digit()) { - _temp_string.push_back(tracker.peek_char()); + _temp_wstring.push_back(tracker.peek_char()); tracker.consume(); } } // check for immediately following character, which is an error if (tracker.is_alpha()) { - std::wstringstream ss; - ss << L"Letter follows directly after floating point number " << &_temp_string[0]; + std::stringstream ss; + ss << "Letter follows directly after floating point number " << temp_string(); throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::AlphaFollowingNumberLiteral, ss.str()); } @@ 603,8 625,8 @@ void Tokenizer::tokenize_float(const siz t.value = value; } catch (std::out_of_range &) { - std::wstringstream ss; - ss << L"Floating point number " << temp_view() << " out of range"; + std::stringstream ss; + ss << "Floating point number " << temp_string() << " out of range"; throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::FloatOutOfRange, ss.str()); } } @@ 625,8 647,10 @@ void Tokenizer::tokenize_binary(const si else if (c == L'1') value = (value << 1) | 1; else { - std::wstringstream ss; - ss << L"Illegal character '" << c << "' in binary constant"; + std::stringstream ss; + std::string narrow_c; + core::wide_to_utf8(c, narrow_c); + ss << "Illegal character '" << narrow_c << "' in binary constant"; throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::IllegalCharacterInBinaryConstant, ss.str()); } tracker.consume(); @@ 654,8 678,10 @@ void Tokenizer::tokenize_hex(const size_ while (tracker.is_alpha_numeric()) { wchar_t c = tracker.peek_char(); if (!tracker.is_hex()) { - std::wstringstream ss; - ss << L"Illegal character '" << c << "' in hexadecimal constant"; + std::stringstream ss; + std::string narrow_c; + core::wide_to_utf8(c, narrow_c); + ss << "Illegal character '" << narrow_c << "' in hexadecimal constant"; throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::IllegalCharacterInHexConstant, ss.str()); } @@ 687,12 713,12 @@ void Tokenizer::tokenize_char(const size tracker.consume(); if (tracker.is_newline() || tracker.is_end() || tracker.peek_char() == L'\'') - throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::MissingCharacterConstant, L"Missing character in character constant"); + throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::MissingCharacterConstant, "Missing character in character constant"); wchar_t value = parse_next_string_character(tracker); if (tracker.peek_char() != L'\'') - throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::TooLongCharacterConstant, L"Character constant longer than one character."); + throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::TooLongCharacterConstant, "Character constant longer than one character."); tracker.consume(); CharToken &t = token_chain.reserve<CharToken>(); @@ 712,7 738,7 @@ void Tokenizer::tokenize_string(const si uint32_t row = tracker.row; parse_quoted_string(file_index, tracker); - std::wstring_view string = temp_view(); + std::string string = temp_string(); // hash characters uint64_t string_hash = murmur_hash3_string_x64_64(string); @@ 752,19 778,18 @@ void Tokenizer::tokenize_symbol_or_keywo uint32_t column = tracker.column; uint32_t row = tracker.row; - _temp_string.clear(); - _temp_string.push_back(tracker.peek_char()); + _temp_wstring.clear(); + _temp_wstring.push_back(tracker.peek_char()); tracker.consume(); while (tracker.is_symbol_content()) { - _temp_string.push_back(tracker.peek_char()); + _temp_wstring.push_back(tracker.peek_char()); tracker.consume(); } // check for matching keyword uint64_t hash; - std::wstring_view symbol = temp_view(); - if (allow_keyword && _keyword_finder.match(symbol, hash)) { + if (allow_keyword && _keyword_finder.match(temp_wview(), hash)) { // matched an instruction or keyword assert(_hash_to_token.find(hash) != _hash_to_token.end()); const TokenData *td = &_hash_to_token[hash]; @@ 780,29 805,29 @@ void Tokenizer::tokenize_symbol_or_keywo // it there because it will eat up unexpected combinations of characters. It is // better to handle this special case here and translate the tokens if needed. if (td->token_type == TokenType::ProcessorKeyword && tracker.peek_char() == L'\'') { - if (hash == hash_constant(0x96a698500b4e98bd, L"a")) { - hash = hash_constant(0x2d14b9e3bd84e605, L"a'"); + if (hash == hash_constant(0x85555565f6597889ULL, "a")) { + hash = hash_constant(0x45a6060b75dcb28bULL, "a'"); tracker.consume(); - } else if (hash == hash_constant(0x5df08d73320df439, L"af")) { - hash = hash_constant(0xad699ba01cd83ad5, L"af'"); + } else if (hash == hash_constant(0x3265a8a124914099ULL, "af")) { + hash = hash_constant(0x75f0ca5c1761bc10, "af'"); tracker.consume(); - } else if (hash == hash_constant(0x460ff648fb4f9af, L"b")) { - hash = hash_constant(0xd8d994859194734b, L"b'"); + } else if (hash == hash_constant(0x7a98a957b1d3d1ee, "b")) { + hash = hash_constant(0x4e710923ab8a5de3, "b'"); tracker.consume(); - } else if (hash == hash_constant(0x9dacc554688bbb8e, L"c")) { - hash = hash_constant(0xbfcad9bd313aadd4, L"c'"); + } else if (hash == hash_constant(0x8e38df6c4a1f74d7, "c")) { + hash = hash_constant(0x51f9b2208ed849be, "c'"); tracker.consume(); - } else if (hash == hash_constant(0x40450b58886d7bec, L"d")) { - hash = hash_constant(0xa1afbfe2e18ed463, L"d'"); + } else if (hash == hash_constant(0xcb72f2cd8447f776, "d")) { + hash = hash_constant(0x516d90c3787d85ce, "d'"); tracker.consume(); - } else if (hash == hash_constant(0x75ab3bf5e622731d, L"e")) { - hash = hash_constant(0x3010d292ace69890, L"e'"); + } else if (hash == hash_constant(0xc5b69249a3d5e994, "e")) { + hash = hash_constant(0x14115437bd14d165, "e'"); tracker.consume(); - } else if (hash == hash_constant(0x8231803c3a855f8f, L"h")) { - hash = hash_constant(0x5e6b28b5d70e3ea, L"h'"); + } else if (hash == hash_constant(0xd6fcb2bb61cb4523, "h")) { + hash = hash_constant(0x3a55eb6b0fcaef4f, "h'"); tracker.consume(); - } else if (hash == hash_constant(0x93a9a65257efcb8f, L"l")) { - hash = hash_constant(0x273e462b63a6a208, L"l'"); + } else if (hash == hash_constant(0xf539fdab7bdf9f62, "l")) { + hash = hash_constant(0x2729f07f03d07daa, "l'"); tracker.consume(); } td = &_hash_to_token[hash]; @@ 824,6 849,7 @@ void Tokenizer::tokenize_symbol_or_keywo } } else { + std::string symbol = temp_string(); // store string in string repository uint64_t symbol_hash = murmur_hash3_string_x64_64(symbol); strings.add(symbol_hash, symbol); @@ 852,30 878,22 @@ void Tokenizer::tokenize_symbol_or_keywo void Tokenizer::parse_quoted_string(const size_t file_index, PositionTracker &tracker) { // tracker is assumed to be pointing to the first quote in the string - _temp_string.clear(); + _temp_wstring.clear(); // consume quote tracker.consume(); while (tracker.peek_char() != L'\"') { if (tracker.is_newline() || tracker.is_end()) - throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::MissingClosingStringQuote, L"Missing closing string quote."); + throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::MissingClosingStringQuote, "Missing closing string quote."); wchar_t c = parse_next_string_character(tracker); - _temp_string.push_back(c); + _temp_wstring.push_back(c); } // consume quote tracker.consume(); } -std::wstring_view Tokenizer::temp_view() -{ - if (UNLIKELY(_temp_string.empty())) { - return std::wstring_view(); - } - return std::wstring_view(&_temp_string[0], _temp_string.size()); -} - void Tokenizer::parse_include(const size_t file_index, PositionTracker &tracker, TokenChain &token_chain, StringRepository &strings) { // we are past the include keyword and should parse a path string @@ 883,8 901,8 @@ void Tokenizer::parse_include(const size tracker.consume(); if (tracker.peek_char() != L'\"') { - std::wstringstream ss; - ss << L"Expected path string after include keyword."; + std::stringstream ss; + ss << "Expected path string after include keyword."; throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::ExpectedPathString, ss.str()); } @@ 894,24 912,24 @@ void Tokenizer::parse_include(const size parse_quoted_string(file_index, tracker); FileId fid; - std::wstring file_path; - std::wstring include_file(temp_string()); + std::string file_path; + std::string include_file(temp_string()); if (!match_include_dir_and_file(include_file, _include_dirs, file_path)) { - std::wstringstream ss; - ss << L"Failed to find include file '" << include_file << L"'"; + std::stringstream ss; + ss << "Failed to find include file '" << include_file << "'"; throw AssemblyException(_used_files[file_index], row, column, AssemblyErrorCodes::CantFindIncludeFile, ss.str()); } if (!file_id(file_path, fid)) { - std::wstringstream ss; - ss << L"Failed to open '" << temp_view() << L"'"; + std::stringstream ss; + ss << "Failed to open '" << temp_string() << "'"; throw FileException(ss.str()); } if (std::find(_include_id_history.begin(), _include_id_history.end(), fid) != _include_id_history.end()) { - std::wstringstream ss; - ss << L"Include file recursion. '" << _used_files[file_index] << L"' is included twice from:"; + std::stringstream ss; + ss << "Include file recursion. '" << _used_files[file_index] << "' is included twice from:"; for (auto it = _include_file_history.rbegin(); it != _include_file_history.rend(); ++it) - ss << L"\n " << to_front_slashes(*it); + ss << "\n " << to_front_slashes(*it); throw AssemblyException(_used_files[file_index], 1, 1, AssemblyErrorCodes::RecursiveIncludes, ss.str()); } @@ 934,32 952,32 @@ void Tokenizer::preparse_incbin(const si tracker.consume(); if (tracker.peek_char() != L'\"') { - std::wstringstream ss; - ss << L"Expected path string after incbin keyword."; + std::stringstream ss; + ss << "Expected path string after incbin keyword."; throw AssemblyException(_used_files[file_index], tracker.row, tracker.column, AssemblyErrorCodes::ExpectedPathString, ss.str()); } parse_quoted_string(file_index, tracker); - _data_reader.queue_load(temp_view()); + _data_reader.queue_load(temp_string()); } -const std::wstring_view to_string(TokenType type) +const std::string_view to_string(TokenType type) { - static const std::wstring_view names[] = { - std::wstring_view(L"whitespace"), - std::wstring_view(L"newline"), - std::wstring_view(L"boolean"), - std::wstring_view(L"char"), - std::wstring_view(L"integer"), - std::wstring_view(L"float"), - std::wstring_view(L"string"), - std::wstring_view(L"operator"), - std::wstring_view(L"keyword"), - std::wstring_view(L"type"), - std::wstring_view(L"symbol"), - std::wstring_view(L"end of file"), - std::wstring_view(L"processor keyword"), + static const std::string_view names[] = { + std::string_view("whitespace"), + std::string_view("newline"), + std::string_view("boolean"), + std::string_view("char"), + std::string_view("integer"), + std::string_view("float"), + std::string_view("string"), + std::string_view("operator"), + std::string_view("keyword"), + std::string_view("type"), + std::string_view("symbol"), + std::string_view("end of file"), + std::string_view("processor keyword"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(TokenType::NumTypes), "Number of tokens doesn't match number of strings"); @@ 986,10 1004,10 @@ bool is_instruction(const Token &t, Inst return true; } -TokenChain tokenize(const std::wstring &input_file, StringRepository &strings, const std::vector<std::wstring> &include_dirs, std::vector<std::wstring> &used_files, DataReader &data_reader) +TokenChain tokenize(bool pseudo_instructions, const std::string &input_file, StringRepository &strings, const std::vector<std::string> &include_dirs, std::vector<std::string> &used_files, DataReader &data_reader) { - TimerScope timer(L"Tokenizer"); - Tokenizer t(include_dirs, used_files, data_reader); + TimerScope timer("Tokenizer"); + Tokenizer t(pseudo_instructions, include_dirs, used_files, data_reader); TokenChain tc(4096); t.init(input_file); t.tokenize(0, tc, strings);
M jasm/parsing/tokenizer.h +2 -2
@@ 86,7 86,7 @@ bool is_instruction(const Token &t); /// Return true if the token is an instruction. bool is_instruction(const Token &t, InstructionType &type); -const std::wstring_view to_string(TokenType type); +const std::string_view to_string(TokenType type); /// Tokenize the source file and any included files to produce one single stream of tokens. /// The tokens have information about where in the source they are located to allow error @@ 94,7 94,7 @@ const std::wstring_view to_string(TokenT /// blocks which can be read in order by the syntax parser. /// @throw FileException is thrown if a file operation failed. /// @throw AssemblyException is thrown if assembly failed. -TokenChain tokenize(const std::wstring &input_file, StringRepository &strings, const std::vector<std::wstring> &include_dirs, std::vector<std::wstring> &used_files, DataReader &data_reader); +TokenChain tokenize(bool pseudo_instructions, const std::string &input_file, StringRepository &strings, const std::vector<std::string> &include_dirs, std::vector<std::string> &used_files, DataReader &data_reader); /// @}
M jasm/parsing/types.cpp +5 -5
@@ 4,12 4,12 @@ namespace jasm { -const std::wstring_view to_string(TypenameType type) +const std::string_view to_string(TypenameType type) { - static const std::wstring_view names[] = { - std::wstring_view(L"byte"), - std::wstring_view(L"word"), - std::wstring_view(L"long"), + static const std::string_view names[] = { + std::string_view("byte"), + std::string_view("word"), + std::string_view("long"), }; static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(TypenameType::NumTypes), "Number of typenames doesn't match number of strings");
M jasm/parsing/types.h +1 -1
@@ 13,7 13,7 @@ enum class TypenameType : uint8_t NumTypes, }; -const std::wstring_view to_string(TypenameType type); +const std::string_view to_string(TypenameType type); /// @}
M jasm/revision_hash.h +1 -1
M jasm/strings/string_conversions.cpp +66 -60
@@ 3,6 3,7 @@ #include <array> #include <core/collections/array_helper.h> #include <core/strings/murmur_hash.h> +#include <core/strings/utf8.h> #include <strings/string_conversions.h> #include <sstream> @@ 10,7 11,7 @@ namespace jasm { namespace { - void add_characters_impl(const unsigned int *conversions, size_t size, StringConversions::ConversionMap &map) + void add_characters_impl(const wchar_t *conversions, size_t size, StringConversions::ConversionMap &map) { for(size_t i = 0; i < size; ++i) { map[conversions[2*i]] = conversions[2*i + 1]; @@ 18,31 19,31 @@ namespace { } template<int N> - void add_characters(const unsigned int (&conversions)[N], StringConversions::ConversionMap &map) + void add_characters(const wchar_t (&conversions)[N], StringConversions::ConversionMap &map) { add_characters_impl(conversions, N/2, map); } } -const std::wstring_view StringConversions::_formats[static_cast<size_t>(StringConversions::Format::NumFormats)] = { - std::wstring_view(L"petscii"), - std::wstring_view(L"zx80"), - std::wstring_view(L"zx81"), +const std::string_view StringConversions::_formats[static_cast<size_t>(StringConversions::Format::NumFormats)] = { + std::string_view("petscii"), + std::string_view("zx80"), + std::string_view("zx81"), }; -const std::wstring_view StringConversions::_subformats[static_cast<size_t>(StringConversions::SubFormat::NumFormats)] = { - std::wstring_view(L"uppercase"), - std::wstring_view(L"lowercase"), - std::wstring_view(L"uppercase_screen"), - std::wstring_view(L"lowercase_screen"), +const std::string_view StringConversions::_subformats[static_cast<size_t>(StringConversions::SubFormat::NumFormats)] = { + std::string_view("uppercase"), + std::string_view("lowercase"), + std::string_view("uppercase_screen"), + std::string_view("lowercase_screen"), }; -const std::wstring_view StringConversions::_locales[static_cast<size_t>(StringConversions::Locale::NumLocales)] = { - std::wstring_view(L"english"), +const std::string_view StringConversions::_locales[static_cast<size_t>(StringConversions::Locale::NumLocales)] = { + std::string_view("english"), }; -const std::wstring_view StringConversions::_flags[static_cast<size_t>(StringConversions::NumFlags)] = { - std::wstring_view(L"high_bit_term"), +const std::string_view StringConversions::_flags[static_cast<size_t>(StringConversions::NumFlags)] = { + std::string_view("high_bit_term"), }; StringConversions::StringConversions() @@ 62,61 63,61 @@ StringConversions::StringConversions() { // fill petascii lowercase ConversionMap &map = _conversions.at(format_hash(Format::Petscii, SubFormat::Lowercase, Locale::English)); - for (unsigned int c = 0; c < 32; ++c) + for (wchar_t c = 0; c < 32; ++c) map[c + 32] = c + 32; map[L'@'] = 64; - for (unsigned int c = 0; c < 26; ++c) + for (wchar_t c = 0; c < 26; ++c) map[c + L'a'] = c + 65; map[L'['] = 91; - map[L'\163'] = 92; + map[L'\u00a3'] = 92; map[L']'] = 93; - for (unsigned int c = 0; c < 26; ++c) + for (wchar_t c = 0; c < 26; ++c) map[c + 'A'] = c + 97; } { // fill petascii uppercase ConversionMap &map = _conversions.at(format_hash(Format::Petscii, SubFormat::Uppercase, Locale::English)); - for (unsigned int c = 0; c < 32; ++c) + for (wchar_t c = 0; c < 32; ++c) map[c + 32] = c + 32; map[L'@'] = 64; - for (unsigned int c = 0; c < 26; ++c) + for (wchar_t c = 0; c < 26; ++c) map[c + L'A'] = c + 65; map[L'['] = 91; - map[L'\163'] = 92; + map[L'\u00a3'] = 92; map[L']'] = 93; } { // fill pet screencode lowercase ConversionMap &map = _conversions.at(format_hash(Format::Petscii, SubFormat::LowercaseScreen, Locale::English)); - for (unsigned int c = 0; c < 32; ++c) + for (wchar_t c = 0; c < 32; ++c) map[c + 32] = c + 32; map[L'@'] = 0; - for (unsigned int c = 0; c < 26; ++c) + for (wchar_t c = 0; c < 26; ++c) map[c + L'a'] = c + 1; map[L'['] = 27; - map[L'\163'] = 28; + map[L'\u00a3'] = 28; map[L']'] = 29; - for (unsigned int c = 0; c < 26; ++c) + for (wchar_t c = 0; c < 26; ++c) map[c + 'A'] = c + 65; } { // fill pet screencode uppercase ConversionMap &map = _conversions.at(format_hash(Format::Petscii, SubFormat::UppercaseScreen, Locale::English)); - for (unsigned int c = 0; c < 32; ++c) + for (wchar_t c = 0; c < 32; ++c) map[c + 32] = c + 32; map[L'@'] = 0; - for (unsigned int c = 0; c < 26; ++c) + for (wchar_t c = 0; c < 26; ++c) map[c + L'A'] = c + 1; map[L'['] = 27; - map[L'\163'] = 28; + map[L'\u00a3'] = 28; map[L']'] = 29; } { - const unsigned int conversions[] = { + const wchar_t conversions[] = { L'\u0020', 0, L'\u0022', 1, L'\u258c', 2, @@ 198,7 199,7 @@ StringConversions::StringConversions() } { - const unsigned int conversions[] = { + const wchar_t conversions[] = { L'\u0020', 0, L'\u2598', 1, L'\u259d', 2, @@ 281,10 282,10 @@ StringConversions::StringConversions() } template<typename F, size_t N> -bool is_match(const std::wstring_view &name, F &format, const std::wstring_view (&formats)[N]) +bool is_match(const std::string_view &name, F &format, const std::string_view (&formats)[N]) { uint8_t index = 0; - for(const std::wstring_view &format_name : formats) { + for(const std::string_view &format_name : formats) { if (format_name == name) { format = static_cast<F>(index); return true; @@ 294,22 295,22 @@ bool is_match(const std::wstring_view &n return false; } -bool StringConversions::is_format(const std::wstring_view &name, Format &format) +bool StringConversions::is_format(const std::string_view &name, Format &format) { return is_match(name, format, _formats); } -bool StringConversions::is_subformat(const std::wstring_view &name, SubFormat &subformat) +bool StringConversions::is_subformat(const std::string_view &name, SubFormat &subformat) { return is_match(name, subformat, _subformats); } -bool StringConversions::is_locale(const std::wstring_view &name, Locale &locale) +bool StringConversions::is_locale(const std::string_view &name, Locale &locale) { return is_match(name, locale, _locales); } -bool StringConversions::is_flag(const std::wstring_view &name, Flags &flag) +bool StringConversions::is_flag(const std::string_view &name, Flags &flag) { uint8_t bit = 0; bool match = is_match(name, bit, _flags); @@ 321,37 322,37 @@ bool StringConversions::is_flag(const st return match; } -std::vector<std::wstring_view> StringConversions::supported_formats() +std::vector<std::string_view> StringConversions::supported_formats() { - std::vector<std::wstring_view> result; - for(const std::wstring_view &format : _formats) { + std::vector<std::string_view> result; + for(const std::string_view &format : _formats) { result.push_back(format); } return result; } -std::vector<std::wstring_view> StringConversions::supported_subformats() +std::vector<std::string_view> StringConversions::supported_subformats() { - std::vector<std::wstring_view> result; - for(const std::wstring_view &format : _subformats) { + std::vector<std::string_view> result; + for(const std::string_view &format : _subformats) { result.push_back(format); } return result; } -std::vector<std::wstring_view> StringConversions::supported_locales() +std::vector<std::string_view> StringConversions::supported_locales() { - std::vector<std::wstring_view> result; - for(const std::wstring_view &locale : _locales) { + std::vector<std::string_view> result; + for(const std::string_view &locale : _locales) { result.push_back(locale); } return result; } -std::vector<std::wstring_view> StringConversions::supported_flags() +std::vector<std::string_view> StringConversions::supported_flags() { - std::vector<std::wstring_view> result; - for(const std::wstring_view &flag : _flags) { + std::vector<std::string_view> result; + for(const std::string_view &flag : _flags) { result.push_back(flag); } return result; @@ 362,7 363,7 @@ bool StringConversions::has_conversion(F return _conversions.has(format_hash(f, sf, l)); } -bool StringConversions::convert(const std::wstring &string, Format format, SubFormat sf, Locale locale, Flags flags, std::wstring &result, size_t &error_pos) +bool StringConversions::convert(const std::string &string, Format format, SubFormat sf, Locale locale, Flags flags, std::string &result, size_t &error_pos) { error_pos = 0; @@ 374,22 375,27 @@ bool StringConversions::convert(const st const ConversionMap &map = cit->second; - std::wstringstream ss; - for(wchar_t c : string) { - auto it = map.find(static_cast<unsigned int>(c)); + std::stringstream ss; + const char *source = string.data(); + size_t source_size = string.size(); + wchar_t target = 0; + while (source_size != 0) { + bool success = core::utf8_to_wide(source, source_size, target); + if (UNLIKELY(!success)) { + return false; + } + auto it = map.find(target); if (UNLIKELY(it == map.end())) { return false; } - ss.put(static_cast<wchar_t>(it->second)); - + target = it->second; + if (source_size == 0 && (flags & HighBitTermination) != 0) { + target |= 0x80; + } + core::wide_to_utf8(target, ss); ++error_pos; } result = ss.str(); - - if ((flags & HighBitTermination) != 0 && !result.empty()) { - result.back() |= 0x80; - } - return true; }
M jasm/strings/string_conversions.h +15 -15
@@ 12,7 12,7 @@ namespace jasm /// Hash functor for unicode characters. struct UnicodeHasher { - size_t operator()(unsigned int codepoint) const + size_t operator()(wchar_t codepoint) const { return static_cast<size_t>(core::murmur_hash3_x64_64(&codepoint, sizeof(codepoint))); } @@ 59,19 59,19 @@ public: StringConversions(); /// Returns true if the name matches a format type and in that case updates the format variable. - bool is_format(const std::wstring_view &name, Format &format); - bool is_subformat(const std::wstring_view &name, SubFormat &subformat); - bool is_locale(const std::wstring_view &name, Locale &locale); - bool is_flag(const std::wstring_view &name, Flags &flags); + bool is_format(const std::string_view &name, Format &format); + bool is_subformat(const std::string_view &name, SubFormat &subformat); + bool is_locale(const std::string_view &name, Locale &locale); + bool is_flag(const std::string_view &name, Flags &flags); /// Returns true if there is a string conversion for the specified format and locale. bool has_conversion(Format f, SubFormat sf, Locale l); /// Returns all supported conversion formats. - std::vector<std::wstring_view> supported_formats(); - std::vector<std::wstring_view> supported_subformats(); - std::vector<std::wstring_view> supported_locales(); - std::vector<std::wstring_view> supported_flags(); + std::vector<std::string_view> supported_formats(); + std::vector<std::string_view> supported_subformats(); + std::vector<std::string_view> supported_locales(); + std::vector<std::string_view> supported_flags(); /// Convert a string using a specific format. /// @param string String to convert. @@ 83,9 83,9 @@ public: /// @param error_pos In case of a failure this contains the zero-based index into the string /// where the error occurred. /// @return True if successful. - bool convert(const std::wstring &string, Format format, SubFormat sf, Locale locale, Flags flags, std::wstring &result, size_t &error_pos); + bool convert(const std::string &string, Format format, SubFormat sf, Locale locale, Flags flags, std::string &result, size_t &error_pos); - using ConversionMap = core::HashMap<unsigned int, unsigned int, UnicodeHasher>; + using ConversionMap = core::HashMap<wchar_t, wchar_t, UnicodeHasher>; using ConversionMaps = core::HashMap<uint64_t, ConversionMap, core::NullHashCompare<uint64_t>>; // map from format type hash to map private: @@ 94,10 94,10 @@ private: // The conversion maps for all platforms. ConversionMaps _conversions; - static const std::wstring_view _formats[static_cast<size_t>(StringConversions::Format::NumFormats)]; - static const std::wstring_view _subformats[static_cast<size_t>(StringConversions::SubFormat::NumFormats)]; - static const std::wstring_view _locales[static_cast<size_t>(StringConversions::Locale::NumLocales)]; - static const std::wstring_view _flags[static_cast<size_t>(StringConversions::Flags::NumFlags)]; + static const std::string_view _formats[static_cast<size_t>(StringConversions::Format::NumFormats)]; + static const std::string_view _subformats[static_cast<size_t>(StringConversions::SubFormat::NumFormats)]; + static const std::string_view _locales[static_cast<size_t>(StringConversions::Locale::NumLocales)]; + static const std::string_view _flags[static_cast<size_t>(StringConversions::Flags::NumFlags)]; }; /// @}
M jasm/strings/string_hasher.h +1 -1
@@ 11,7 11,7 @@ namespace jasm /// Hash functor for strings. struct StringHasher { - size_t operator()(const std::wstring &key) const + size_t operator()(const std::string &key) const { return static_cast<size_t>(murmur_hash3_string_x64_64(key, 0)); }
A => jasm/strings/string_locale.cpp +48 -0
@@ 0,0 1,48 @@ +#include <pch.h> + +#include <array> +#include <core/collections/array_helper.h> +#include <core/strings/utf8.h> +#include <strings/string_locale.h> +#include <sstream> + +namespace jasm +{ + +const std::string_view StringLocale::_names[static_cast<size_t>(StringLocale::Locale::NumLocales)] = { + std::string_view("default"), + std::string_view("english"), + std::string_view("swedish"), +}; +const std::string_view StringLocale::_locales[static_cast<size_t>(StringLocale::Locale::NumLocales)] = { + std::string_view(""), + std::string_view("en_US.utf8"), + std::string_view("sv_SE.utf8"), +}; + +bool StringLocale::is_locale(const std::string_view &name, Locale &locale) +{ + for(size_t i = 0; i < static_cast<size_t>(StringLocale::Locale::NumLocales); ++i) { + if (_names[i] == name) { + locale = static_cast<Locale>(i); + return true; + } + } + return false; +} + +std::vector<std::string_view> StringLocale::supported_locales() +{ + std::vector<std::string_view> result; + for(const std::string_view &name : _names) { + result.push_back(name); + } + return result; +} + +std::string_view StringLocale::std_locale_name(Locale locale) +{ + return _locales[static_cast<size_t>(locale)]; +} + +}
A => jasm/strings/string_locale.h +37 -0
@@ 0,0 1,37 @@ +#pragma once + +namespace jasm +{ + +/// @addtogroup strings +/// @{ + +/// This converts locale names to std::locale names. +class StringLocale +{ +public: + enum class Locale : uint8_t + { + Default = 0, + English, + Swedish, + NumLocales + }; + + /// Returns true if the name matches a format type and in that case updates the format variable. + static bool is_locale(const std::string_view &name, Locale &locale); + + /// Returns all supported conversion formats. + static std::vector<std::string_view> supported_locales(); + + /// Returns the name of a std::locale to use. + static std::string_view std_locale_name(Locale locale); + +private: + static const std::string_view _names[static_cast<size_t>(Locale::NumLocales)]; + static const std::string_view _locales[static_cast<size_t>(Locale::NumLocales)]; +}; + +/// @} + +}
M jasm/strings/string_repository.cpp +3 -3
@@ 10,7 10,7 @@ StringRepository::StringRepository() _string_data.reserve(65536); } -void StringRepository::add(uint64_t hash, const std::wstring_view &str) +void StringRepository::add(uint64_t hash, const std::string_view &str) { _string_indices[hash] = IndexAndSize{_string_data.size(), str.size()}; _string_data.insert(_string_data.end(), str.begin(), str.end()); @@ 21,11 21,11 @@ bool StringRepository::has(uint64_t hash return _string_indices.find(hash) != _string_indices.end(); } -std::wstring_view StringRepository::get(uint64_t hash) const +std::string_view StringRepository::get(uint64_t hash) const { auto it = _string_indices.find(hash); assert(it != _string_indices.end()); - return std::wstring_view(&_string_data[it->second.index], it->second.size); + return std::string_view(&_string_data[it->second.index], it->second.size); } } // namespace jasm
M jasm/strings/string_repository.h +3 -3
@@ 16,13 16,13 @@ public: StringRepository(); /// Add a string to the repository. - void add(uint64_t hash, const std::wstring_view &str); + void add(uint64_t hash, const std::string_view &str); /// Return true if a string exists for the hash. bool has(uint64_t hash) const; /// Get a string using the string hash. - std::wstring_view get(uint64_t hash) const; + std::string_view get(uint64_t hash) const; private: struct IndexAndSize @@ 32,7 32,7 @@ private: }; core::HashMap<uint64_t, IndexAndSize, core::NullHashCompare<uint64_t>> _string_indices; - std::vector<wchar_t> _string_data; + std::vector<char> _string_data; }; /// @}
M jasm/unit_tests/results/test_define_array_follows_references.bin +1 -1
A => jasm/unit_tests/results/test_function_logn.bin +0 -0
A => jasm/unit_tests/results/test_function_lowercase_default.bin +1 -0
A => jasm/unit_tests/results/test_function_lowercase_english.bin +1 -0
A => jasm/unit_tests/results/test_function_lowercase_invalid_type.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_function_lowercase_invalid_type.asm(4,27) : Error 3105 : Expected string or integer but got byte typename. +Assembly ended with errors.
A => jasm/unit_tests/results/test_function_lowercase_swedish.bin +1 -0
A => jasm/unit_tests/results/test_function_uppercase_default.bin +1 -0
A => jasm/unit_tests/results/test_function_uppercase_english.bin +1 -0
A => jasm/unit_tests/results/test_function_uppercase_invalid_type.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_function_uppercase_invalid_type.asm(4,27) : Error 3105 : Expected string or integer but got byte typename. +Assembly ended with errors.
A => jasm/unit_tests/results/test_function_uppercase_swedish.bin +1 -0
A => jasm/unit_tests/results/test_instruction_data_label_has_lo_hi_properties_6502.bin +1 -0
A => jasm/unit_tests/results/test_instruction_data_label_has_lo_hi_properties_z80.bin +1 -0
A => jasm/unit_tests/results/test_instruction_data_label_offsets_6502.bin +0 -0
A => jasm/unit_tests/results/test_instruction_data_label_sizes_6502.bin +0 -0
A => jasm/unit_tests/results/test_instruction_data_label_sizes_z80.bin +1 -0
@@ 0,0 1,1 @@ +ݎ݆ݦFFNNVV^^ffnnvv~~444444444ݾ554444444444480 (6wpqrstu6wpqrstu624C4S4"4"4"4s4~~:4>FFK44NNVV[44^^ff&*4!4*4!4*4!4nn.{414ݶݞ&&..>>ݖݮ No newline at end of file
A => jasm/unit_tests/results/test_lowercase_too_many_arguments.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_lowercase_too_many_arguments.asm(4,47) : Error 3107 : Too many arguments to function. +Assembly ended with errors.
M jasm/unit_tests/results/test_map_range_for_with_local_loop_variables.bin +1 -1
A => jasm/unit_tests/results/test_offset_word_has_lo_hi_property.bin +0 -0
A => jasm/unit_tests/results/test_pseudo_instructions_16_bit_register_load_z80.bin +1 -0
A => jasm/unit_tests/results/test_pseudo_instructions_for_branching_6502.bin +1 -0
A => jasm/unit_tests/results/test_pseudo_instructions_in_standard_mode_6502.stdout +1 -0
@@ 0,0 1,1 @@ +unit_tests/test_pseudo_instructions_in_standard_mode_6502.asm(7,1) : Error 2009 : Expected expression value but got operator }
A => jasm/unit_tests/results/test_pseudo_instructions_in_standard_mode_z80.stdout +7 -0
@@ 0,0 1,7 @@ +unit_tests/test_pseudo_instructions_in_standard_mode_z80.asm(5,2) : Error 3109 : Pseudo instructions require the pseudo instruction mode to be enabled. +unit_tests/test_pseudo_instructions_in_standard_mode_z80.asm(6,2) : Error 3109 : Pseudo instructions require the pseudo instruction mode to be enabled. +unit_tests/test_pseudo_instructions_in_standard_mode_z80.asm(7,2) : Error 3109 : Pseudo instructions require the pseudo instruction mode to be enabled. +unit_tests/test_pseudo_instructions_in_standard_mode_z80.asm(8,2) : Error 3109 : Pseudo instructions require the pseudo instruction mode to be enabled. +unit_tests/test_pseudo_instructions_in_standard_mode_z80.asm(9,2) : Error 3109 : Pseudo instructions require the pseudo instruction mode to be enabled. +unit_tests/test_pseudo_instructions_in_standard_mode_z80.asm(10,2) : Error 3109 : Pseudo instructions require the pseudo instruction mode to be enabled. +Assembly ended with errors.
A => jasm/unit_tests/results/test_pseudo_instructions_use_names_in_standard_mode_6502.bin +1 -0
A => jasm/unit_tests/results/test_section_child_exceeds_its_size.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_section_child_exceeds_its_size.asm(5,2) : Error 3011 : Section submain exceeds its max size. Section is 4 B and the maximum size is 3 B. +Fatal error, aborting assembly.
A => jasm/unit_tests/results/test_subroutine_call_6502.bin +1 -0
A => jasm/unit_tests/results/test_subroutine_call_must_be_in_code_section_6502.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_subroutine_call_must_be_in_code_section_6502.asm(3,5) : Error 3057 : Instructions must be in a code section. +Fatal error, aborting assembly.
A => jasm/unit_tests/results/test_subroutine_call_must_be_in_code_section_z80.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_subroutine_call_must_be_in_code_section_z80.asm(3,5) : Error 3057 : Instructions must be in a code section. +Fatal error, aborting assembly.
A => jasm/unit_tests/results/test_subroutine_call_negative_argument_6502.stdout +3 -0
@@ 0,0 1,3 @@ +unit_tests/test_subroutine_call_negative_argument_6502.asm(3,23) : Error 3013 : Section start cannot be negative. It is evaluated to -4. +unit_tests/test_subroutine_call_negative_argument_6502.asm(5,6) : Error 3006 : Addressing mode needs a positive argument. Argument value was evaluated to -1. +Assembly ended with errors.
A => jasm/unit_tests/results/test_subroutine_call_recursive_data_generation_6502.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_subroutine_call_recursive_data_generation_6502.asm(5,11) : Error 3092 : Recursive data generation isn't allowed. +Fatal error, aborting assembly.
A => jasm/unit_tests/results/test_subroutine_call_recursive_data_generation_z80.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_subroutine_call_recursive_data_generation_z80.asm(5,11) : Error 3092 : Recursive data generation isn't allowed. +Fatal error, aborting assembly.
A => jasm/unit_tests/results/test_subroutine_call_too_large_argument_6502.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_subroutine_call_too_large_argument_6502.asm(5,6) : Error 3008 : Addressing mode needs a word size argument. Argument was evaluated to 65536. +Assembly ended with errors.
A => jasm/unit_tests/results/test_subroutine_call_too_large_argument_z80.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_subroutine_call_too_large_argument_z80.asm(5,6) : Error 3008 : Addressing mode needs a word size argument. Argument was evaluated to 65536. +Assembly ended with errors.
A => jasm/unit_tests/results/test_subroutine_call_with_arguments_6502.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_subroutine_call_with_arguments_6502.asm(5,6) : Error 3108 : Subroutine calls don't support arguments. +Assembly ended with errors.
A => jasm/unit_tests/results/test_subroutine_call_with_arguments_z80.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_subroutine_call_with_arguments_z80.asm(5,6) : Error 3108 : Subroutine calls don't support arguments. +Assembly ended with errors.
A => jasm/unit_tests/results/test_subroutine_call_z80.bin +1 -0
A => jasm/unit_tests/results/test_uppercase_too_many_arguments.stdout +2 -0
@@ 0,0 1,2 @@ +unit_tests/test_uppercase_too_many_arguments.asm(4,47) : Error 3107 : Too many arguments to function. +Assembly ended with errors.
A => jasm/unit_tests/test_function_logn.asm +5 -0
@@ 0,0 1,5 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $1000, $2000 { + define long = int(16777216 * logn(243, 3) + 0.5) +}
A => jasm/unit_tests/test_function_lowercase_default.asm +6 -0
@@ 0,0 1,6 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $1000, $2000 { + define byte[] = { lowercase("abcABCåäöÅÄÖ012") } + define byte[] = { lowercase('a'), lowercase('A'), lowercase('å'), lowercase('Å'), lowercase('0')} +}
A => jasm/unit_tests/test_function_lowercase_english.asm +6 -0
@@ 0,0 1,6 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $1000, $2000 { + define byte[] = { lowercase("abcABCåäöÅÄÖ012", "english") } + define byte[] = { lowercase('a', "english"), lowercase('A', "english"), lowercase('å', "english"), lowercase('Å', "english"), lowercase('0', "english")} +}
A => jasm/unit_tests/test_function_lowercase_invalid_type.asm +5 -0
@@ 0,0 1,5 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $1000, $2000 { + const .value = lowercase(byte) +}
A => jasm/unit_tests/test_function_lowercase_swedish.asm +6 -0
@@ 0,0 1,6 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $1000, $2000 { + define byte[] = { lowercase("abcABCåäöÅÄÖ012", "swedish") } + define byte[] = { lowercase('a', "swedish"), lowercase('A', "swedish"), lowercase('å', "swedish"), lowercase('Å', "swedish"), lowercase('0', "swedish")} +}
A => jasm/unit_tests/test_function_uppercase_default.asm +6 -0
@@ 0,0 1,6 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $1000, $2000 { + define byte[] = { uppercase("abcABCåäöÅÄÖ012") } + define byte[] = { uppercase('a'), uppercase('A'), uppercase('å'), uppercase('Å'), uppercase('0')} +}
A => jasm/unit_tests/test_function_uppercase_english.asm +6 -0
@@ 0,0 1,6 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $1000, $2000 { + define byte[] = { uppercase("abcABCåäöÅÄÖ012", "english") } + define byte[] = { uppercase('a', "english"), uppercase('A', "english"), uppercase('å', "english"), uppercase('Å', "english"), uppercase('0', "english")} +}
A => jasm/unit_tests/test_function_uppercase_invalid_type.asm +5 -0
@@ 0,0 1,5 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $1000, $2000 { + const .value = uppercase(byte) +}
A => jasm/unit_tests/test_function_uppercase_swedish.asm +6 -0
@@ 0,0 1,6 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $1000, $2000 { + define byte[] = { uppercase("abcABCåäöÅÄÖ012", "swedish") } + define byte[] = { uppercase('a', "swedish"), uppercase('A', "swedish"), uppercase('å', "swedish"), uppercase('Å', "swedish"), uppercase('0', "swedish")} +}
A => jasm/unit_tests/test_instruction_data_label_has_lo_hi_properties_6502.asm +8 -0
@@ 0,0 1,8 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $8000 +{ + lda .lbl.lo + lda .lbl.hi + jmp .lbl:* +}
A => jasm/unit_tests/test_instruction_data_label_has_lo_hi_properties_z80.asm +9 -0
@@ 0,0 1,9 @@ +// assembler command line arguments: z80 [-v0] + +section code, "main", $8000 +{ + ld a, (.lbl.lo) // [3a n n] + ld a, (.lbl.hi) // [3a n n] + call .lbl:* // [cd n n] + ret +}
A => jasm/unit_tests/test_instruction_data_label_offsets_6502.asm +47 -0
@@ 0,0 1,47 @@ +// assembler command line arguments: 6502 [-v0] + +const n = 2 +const nn = $1234 + +section code, "main", $8000 { + { + static_assert(.lbl == * + 1, "wrong instruction data offset") + lda .lbl:#0 + } + { + static_assert(.lbl == * + 1, "wrong instruction data offset") + lda .lbl:n + } + { + static_assert(.lbl == * + 1, "wrong instruction data offset") + lda .lbl:n,x + } + { + static_assert(.lbl == * + 1, "wrong instruction data offset") + ldx .lbl:n,y + } + { + static_assert(.lbl == * + 1, "wrong instruction data offset") + lda .lbl:nn + } + { + static_assert(.lbl == * + 1, "wrong instruction data offset") + lda .lbl:nn,x + } + { + static_assert(.lbl == * + 1, "wrong instruction data offset") + lda .lbl:nn,y + } + { + static_assert(.lbl == * + 1, "wrong instruction data offset") + bcc .lbl:* + } + { + static_assert(.lbl == * + 1, "wrong instruction data offset") + lda .lbl:(n,x) + } + { + static_assert(.lbl == * + 1, "wrong instruction data offset") + lda .lbl:(n),y + } +}
A => jasm/unit_tests/test_instruction_data_label_sizes_6502.asm +47 -0
@@ 0,0 1,47 @@ +// assembler command line arguments: 6502 [-v0] + +const n = 2 +const nn = $1234 + +section code, "main", $8000 { + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + lda .lbl:#0 + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + lda .lbl:n + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + lda .lbl:n,x + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ldx .lbl:n,y + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + lda .lbl:nn + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + lda .lbl:nn,x + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + lda .lbl:nn,y + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bcc .lbl:* + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + lda .lbl:(n,x) + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + lda .lbl:(n),y + } +}
A => jasm/unit_tests/test_instruction_data_label_sizes_z80.asm +706 -0
@@ 0,0 1,706 @@ +// assembler command line arguments: z80 [-v0] + +const dd = 1 +const n = 2 +const nn = $1234 + +section code, "main", $8000 { + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + adc a, .lbl:(ix+dd) // [dd8e d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + adc a, .lbl:(iy+dd) // [fd8e d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + adc a, .lbl:n // [ce n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + add a, .lbl:(ix+dd) // [dd86 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + add a, .lbl:(iy+dd) // [fd86 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + add a, .lbl:n // [c6 n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + and .lbl:(ix+dd) // [dda6 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + and .lbl:(iy+dd) // [fda6 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + and .lbl:n // [e6 n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 0, .lbl:(ix+dd) // [ddcb d 46] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 0, .lbl:(iy+dd) // [fdcb d 46] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 1, .lbl:(ix+dd) // [ddcb d 4e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 1, .lbl:(iy+dd) // [fdcb d 4e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 2, .lbl:(ix+dd) // [ddcb d 56] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 2, .lbl:(iy+dd) // [fdcb d 56] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 3, .lbl:(ix+dd) // [ddcb d 5e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 3, .lbl:(iy+dd) // [fdcb d 5e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 4, .lbl:(ix+dd) // [ddcb d 66] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 4, .lbl:(iy+dd) // [fdcb d 66] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 5, .lbl:(ix+dd) // [ddcb d 6e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 5, .lbl:(iy+dd) // [fdcb d 6e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 6, .lbl:(ix+dd) // [ddcb d 76] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 6, .lbl:(iy+dd) // [fdcb d 76] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 7, .lbl:(ix+dd) // [ddcb d 7e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + bit 7, .lbl:(iy+dd) // [fdcb d 7e] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + call .lbl:nn // [cd n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + call c, .lbl:nn // [dc n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + call m, .lbl:nn // [fc n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + call nc, .lbl:nn // [d4 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + call nz, .lbl:nn // [c4 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + call p, .lbl:nn // [f4 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + call pe, .lbl:nn // [ec n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + call po, .lbl:nn // [e4 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + call z, .lbl:nn // [cc n n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + cp .lbl:(ix+dd) // [ddbe d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + cp .lbl:(iy+dd) // [fdbe d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + cp .lbl:n // [fe n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + dec .lbl:(ix+dd) // [dd35 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + dec .lbl:(iy+dd) // [fd35 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + djnz .lbl:* // [10 e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + in a, .lbl:(n) // [db n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + inc .lbl:(ix+dd) // [dd34 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + inc .lbl:(iy+dd) // [fd34 d] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + jp .lbl:nn // [c3 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + jp c, .lbl:nn // [da n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + jp m, .lbl:nn // [fa n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + jp nc, .lbl:nn // [d2 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + jp nz, .lbl:nn // [c2 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + jp p, .lbl:nn // [f2 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + jp pe, .lbl:nn // [ea n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + jp po, .lbl:nn // [e2 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + jp z, .lbl:nn // [ca n n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + jr .lbl:* // [18 e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + jr c, .lbl:* // [38 e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + jr nc, .lbl:* // [30 e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + jr nz, .lbl:* // [20 e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + jr z, .lbl:* // [28 e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld (hl), .lbl:n // [36 n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(ix+dd), a // [dd77 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(ix+dd), b // [dd70 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(ix+dd), c // [dd71 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(ix+dd), d // [dd72 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(ix+dd), e // [dd73 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(ix+dd), h // [dd74 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(ix+dd), l // [dd75 d] + } + { + static_assert(sizeof(.lbl1) == 1, "wrong instruction data size") + static_assert(sizeof(.lbl2) == 1, "wrong instruction data size") + ld .lbl1:(ix+dd), .lbl2:n // [dd36 d n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(iy+dd), a // [fd77 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(iy+dd), b // [fd70 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(iy+dd), c // [fd71 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(iy+dd), d // [fd72 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(iy+dd), e // [fd73 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(iy+dd), h // [fd74 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld .lbl:(iy+dd), l // [fd75 d] + } + { + static_assert(sizeof(.lbl1) == 1, "wrong instruction data size") + static_assert(sizeof(.lbl2) == 1, "wrong instruction data size") + ld .lbl1:(iy+dd), .lbl2:n // [fd36 d n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld .lbl:(nn), a // [32 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld .lbl:(nn), bc // [ed43 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld .lbl:(nn), de // [ed53 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld .lbl:(nn), hl // [22 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld .lbl:(nn), ix // [dd22 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld .lbl:(nn), iy // [fd22 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld .lbl:(nn), sp // [ed73 n n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld a, .lbl:(ix+dd) // [dd7e d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld a, .lbl:(iy+dd) // [fd7e d] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld a, .lbl:(nn) // [3a n n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld a, .lbl:n // [3e n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld b, .lbl:(ix+dd) // [dd46 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld b, .lbl:(iy+dd) // [fd46 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld b, .lbl:n // [06 n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld bc, .lbl:(nn) // [ed4b n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld bc, .lbl:nn // [01 n n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld c, .lbl:(ix+dd) // [dd4e d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld c, .lbl:(iy+dd) // [fd4e d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld c, .lbl:n // [0e n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld d, .lbl:(ix+dd) // [dd56 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld d, .lbl:(iy+dd) // [fd56 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld d, .lbl:n // [16 n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld de, .lbl:(nn) // [ed5b n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld de, .lbl:nn // [11 n n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld e, .lbl:(ix+dd) // [dd5e d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld e, .lbl:(iy+dd) // [fd5e d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld e, .lbl:n // [1e n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld h, .lbl:(ix+dd) // [dd66 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld h, .lbl:(iy+dd) // [fd66 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld h, .lbl:n // [26 n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld hl, .lbl:(nn) // [2a n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld hl, .lbl:nn // [21 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld ix, .lbl:(nn) // [dd2a n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld ix, .lbl:nn // [dd21 n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld iy, .lbl:(nn) // [fd2a n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld iy, .lbl:nn // [fd21 n n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld l, .lbl:(ix+dd) // [dd6e d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld l, .lbl:(iy+dd) // [fd6e d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + ld l, .lbl:n // [2e n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld sp, .lbl:(nn) // [ed7b n n] + } + { + static_assert(sizeof(.lbl) == 2, "wrong instruction data size") + ld sp, .lbl:nn // [31 n n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + or .lbl:(ix+dd) // [ddb6 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + or .lbl:(iy+dd) // [fdb6 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + or .lbl:n // [f6 n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + out .lbl:(n), a // [d3 n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 0, .lbl:(ix+dd) // [ddcb d 86] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 0, .lbl:(iy+dd) // [fdcb d 86] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 1, .lbl:(ix+dd) // [ddcb d 8e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 1, .lbl:(iy+dd) // [fdcb d 8e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 2, .lbl:(ix+dd) // [ddcb d 96] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 2, .lbl:(iy+dd) // [fdcb d 96] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 3, .lbl:(ix+dd) // [ddcb d 9e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 3, .lbl:(iy+dd) // [fdcb d 9e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 4, .lbl:(ix+dd) // [ddcb d a6] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 4, .lbl:(iy+dd) // [fdcb d a6] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 5, .lbl:(ix+dd) // [ddcb d ae] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 5, .lbl:(iy+dd) // [fdcb d ae] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 6, .lbl:(ix+dd) // [ddcb d b6] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 6, .lbl:(iy+dd) // [fdcb d b6] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 7, .lbl:(ix+dd) // [ddcb d be] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + res 7, .lbl:(iy+dd) // [fdcb d be] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + rl .lbl:(ix+dd) // [ddcb d 16] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + rl .lbl:(iy+dd) // [fdcb d 16] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + rlc .lbl:(ix+dd) // [ddcb d 06] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + rlc .lbl:(iy+dd) // [fdcb d 06] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + rr .lbl:(ix+dd) // [ddcb d 1e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + rr .lbl:(iy+dd) // [fdcb d 1e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + rrc .lbl:(ix+dd) // [ddcb d 0e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + rrc .lbl:(iy+dd) // [fdcb d 0e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + sbc a, .lbl:(ix+dd) // [dd9e d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + sbc a, .lbl:(iy+dd) // [fd9e d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + sbc a, .lbl:n // [de n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 0, .lbl:(ix+dd) // [ddcb d c6] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 0, .lbl:(iy+dd) // [fdcb d c6] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 1, .lbl:(ix+dd) // [ddcb d ce] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 1, .lbl:(iy+dd) // [fdcb d ce] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 2, .lbl:(ix+dd) // [ddcb d d6] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 2, .lbl:(iy+dd) // [fdcb d d6] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 3, .lbl:(ix+dd) // [ddcb d de] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 3, .lbl:(iy+dd) // [fdcb d de] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 4, .lbl:(ix+dd) // [ddcb d e6] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 4, .lbl:(iy+dd) // [fdcb d e6] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 5, .lbl:(ix+dd) // [ddcb d ee] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 5, .lbl:(iy+dd) // [fdcb d ee] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 6, .lbl:(ix+dd) // [ddcb d f6] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 6, .lbl:(iy+dd) // [fdcb d f6] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 7, .lbl:(ix+dd) // [ddcb d fe] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + set 7, .lbl:(iy+dd) // [fdcb d fe] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + sla .lbl:(ix+dd) // [ddcb d 26] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + sla .lbl:(iy+dd) // [fdcb d 26] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + sra .lbl:(ix+dd) // [ddcb d 2e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + sra .lbl:(iy+dd) // [fdcb d 2e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + srl .lbl:(ix+dd) // [ddcb d 3e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + srl .lbl:(iy+dd) // [fdcb d 3e] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + sub .lbl:(ix+dd) // [dd96 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + sub .lbl:(iy+dd) // [fd96 d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + sub .lbl:n // [d6 n] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + xor .lbl:(ix+dd) // [ddae d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + xor .lbl:(iy+dd) // [fdae d] + } + { + static_assert(sizeof(.lbl) == 1, "wrong instruction data size") + xor .lbl:n // [ee n] + } +}
A => jasm/unit_tests/test_lowercase_too_many_arguments.asm +5 -0
@@ 0,0 1,5 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $1000, $2000 { + define byte[] = {lowercase("ABC", "english", 1)} +}
A => jasm/unit_tests/test_offset_word_has_lo_hi_property.asm +13 -0
@@ 0,0 1,13 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $1000, $2000 { + lda test1.lo + lda test1.hi + lda test2[0].lo + lda test2[0].hi + lda test2[1].lo + lda test2[1].hi + + define word test1 = 257 + define word[2] test2 = {0, 65535} +}
A => jasm/unit_tests/test_pseudo_instructions_16_bit_register_load_z80.asm +24 -0
@@ 0,0 1,24 @@ +// assembler command line arguments: z80 [-v0 -pi] + +section code, "main", $8000 +{ + ld bc,de + ld bc,hl + ld de,bc + ld de,hl + ld hl,bc + ld hl,de + + ld b,d + ld c,e + ld b,h + ld c,l + ld d,b + ld e,c + ld d,h + ld e,l + ld h,b + ld l,c + ld h,d + ld l,e +}
A => jasm/unit_tests/test_pseudo_instructions_for_branching_6502.asm +7 -0
@@ 0,0 1,7 @@ +// assembler command line arguments: 6502 [-v0 -pi] + +section code, "main", $8000 +{ + bhs * + blt * +}
A => jasm/unit_tests/test_pseudo_instructions_in_standard_mode_6502.asm +7 -0
@@ 0,0 1,7 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $8000 +{ + bhs * + blt * +}
A => jasm/unit_tests/test_pseudo_instructions_in_standard_mode_z80.asm +11 -0
@@ 0,0 1,11 @@ +// assembler command line arguments: z80 [-v0] + +section code, "main", $8000 +{ + ld bc,de + ld bc,hl + ld de,bc + ld de,hl + ld hl,bc + ld hl,de +}
A => jasm/unit_tests/test_pseudo_instructions_use_names_in_standard_mode_6502.asm +7 -0
@@ 0,0 1,7 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $8000 +{ +bhs: + rts +}
A => jasm/unit_tests/test_section_child_exceeds_its_size.asm +12 -0
@@ 0,0 1,12 @@ +// assembler command line arguments: 6502 [-v0 -hla] + +section code, "main", $0801 +{ + section code, "submain", $1000, $1003 + { + nop + nop + nop + nop + } +} No newline at end of file
A => jasm/unit_tests/test_subroutine_call_6502.asm +11 -0
@@ 0,0 1,11 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $8000, $9000 +{ + test() + + subroutine test + { + rts + } +}
A => jasm/unit_tests/test_subroutine_call_must_be_in_code_section_6502.asm +11 -0
@@ 0,0 1,11 @@ +// assembler command line arguments: 6502 [-v0] + +test() + +section code, "main", $8000, $9000 +{ + subroutine test + { + rts + } +}
A => jasm/unit_tests/test_subroutine_call_must_be_in_code_section_z80.asm +11 -0
@@ 0,0 1,11 @@ +// assembler command line arguments: z80 [-v0] + +test() + +section code, "main", $8000, $9000 +{ + subroutine test + { + ret + } +}
A => jasm/unit_tests/test_subroutine_call_negative_argument_6502.asm +11 -0
@@ 0,0 1,11 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", -4, $9000 +{ + test() + + subroutine test + { + rts + } +}
A => jasm/unit_tests/test_subroutine_call_recursive_data_generation_6502.asm +11 -0
@@ 0,0 1,11 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $8000, $9000 +{ + lda #test() + + subroutine test + { + rts + } +}
A => jasm/unit_tests/test_subroutine_call_recursive_data_generation_z80.asm +11 -0
@@ 0,0 1,11 @@ +// assembler command line arguments: z80 [-v0] + +section code, "main", $8000, $9000 +{ + ld a,test() + + subroutine test + { + ret + } +}
A => jasm/unit_tests/test_subroutine_call_too_large_argument_6502.asm +11 -0
@@ 0,0 1,11 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $fffd +{ + test() + + subroutine test + { + rts + } +}
A => jasm/unit_tests/test_subroutine_call_too_large_argument_z80.asm +11 -0
@@ 0,0 1,11 @@ +// assembler command line arguments: z80 [-v0] + +section code, "main", $fffd +{ + test() + + subroutine test + { + ret + } +}
A => jasm/unit_tests/test_subroutine_call_with_arguments_6502.asm +11 -0
@@ 0,0 1,11 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $8000 +{ + test(1) + + subroutine test + { + rts + } +}
A => jasm/unit_tests/test_subroutine_call_with_arguments_z80.asm +11 -0
@@ 0,0 1,11 @@ +// assembler command line arguments: z80 [-v0] + +section code, "main", $8000 +{ + test(1) + + subroutine test + { + ret + } +}
A => jasm/unit_tests/test_subroutine_call_z80.asm +11 -0
@@ 0,0 1,11 @@ +// assembler command line arguments: z80 [-v0] + +section code, "main", $8000, $9000 +{ + test() + + subroutine test + { + ret + } +}
A => jasm/unit_tests/test_uppercase_too_many_arguments.asm +5 -0
@@ 0,0 1,5 @@ +// assembler command line arguments: 6502 [-v0] + +section code, "main", $1000, $2000 { + define byte[] = {uppercase("abc", "english", 1)} +}
M jasm/version.h +1 -1
M jasm/version.py +1 -1
@@ 56,4 56,4 @@ def update_revision(): with open("revision.h", "w") as f: f.write("%d\n" % revision) with open("revision_hash.h", "w") as f: - f.write("L\"%s\"\n" % revision_hash) + f.write("\"%s\"\n" % revision_hash)
M jasm/website/site/docs/index.html +199 -9
@@ 70,6 70,11 @@ <li><a href="#max-errors">Max Errors</a></li> <li><a href="#output-files-and-sections">Output Files and Sections</a></li> <li><a href="#verboseness">Verboseness</a></li> +<li><a href="#pseudo-instructions">Pseudo Instructions</a> +<ul> +<li><a href="#6502-pseudo-instructions">6502 Pseudo Instructions</a></li> +<li><a href="#z80-pseudo-instructions">Z80 Pseudo Instructions</a></li> +</ul></li> <li><a href="#return-codes">Return Codes</a></li> </ul></li> <li><a href="#language-reference">Language Reference</a> @@ 1156,13 1161,25 @@ jasm-6502 --define DEFAULT_NAME=bobo inp <h2>Output Files and Sections</h2> -<p>The default output mode will merge all code sections into one big binary and pad the inbetween space with zeros. With the flag <code>--output-multiple-files</code>, this can be changed to store one file per section instead.</p> +<p>The default output mode will merge all code sections into one big binary and pad the inbetween space with zero. With the flag <code>--output-multiple-files</code>, this can be changed to store one file per section instead. Each file will be named after the output file but add the section name before the file extension.</p> <pre><code>jasm-6502 --output-multiple-files input.jasm output.bin </code></pre> <p><em>A shortcut alternative is <code>-om</code>.</em></p> +<p>You can choose to have jAsm name the files after the sections by not specifying an output file name.</p> + +<pre><code>jasm-6502 --output-multiple-files input.jasm +</code></pre> + +<p>You may want to add an extension to the section names when using them as file names. Use the option <code>--file-extension</code> to do that.</p> + +<pre><code>jasm-6502 --output-multiple-files --file-extension prg input.jasm +</code></pre> + +<p><em>A shortcut alternative is <code>-ext</code>.</em></p> + <div id="verboseness"></div> <h2>Verboseness</h2> @@ 1176,10 1193,46 @@ jasm-6502 --define DEFAULT_NAME=bobo inp <tr><th>Flag</th><th>Meaning</th></tr> <tr><td><code>-v0</code></td><td>Show errors</td></tr> <tr><td><code>-v1</code></td><td>Show errors and warnings</td></tr> - <tr><td><code>-v2</code></td><td>Show errors, warnings and general information</td></tr> + <tr><td><code>-v2</code></td><td>Show errors, warnings, printouts and general information</td></tr> <tr><td><code>-v3</code></td><td>Show errors, warnings, general information and debugging information</td></tr> </table> +<div id="pseudo-instructions"></div> + +<h2>Pseudo Instructions</h2> + +<p>You can enable a number of extra instructions to simplify programming using the option <code>--pseudo-instructions</code>. The result differs depending on the processor.</p> + +<p><em>A shortcut alternative is <code>-pi</code>.</em></p> + +<div id="6502-pseudo-instructions"></div> + +<h3>6502 pseudo instructions</h3> + +<p>These are the pseudo instructions for 6502.</p> + +<pre><code><span class="instruction">bhs</span> addr <span class="comment">// branch if higher or same</span> +<span class="instruction">blt</span> addr <span class="comment">// branch if lower</span> +</code></pre> + +<p>These are equivalent to <code><span class="instruction">bcs</span></code> and <code><span class="instruction">bcc</span></code>, respectively.</p> + +<div id="z80-pseudo-instructions"></div> + +<h3>Z80 pseudo instructions</h3> + +<p>These are the pseudo instructions for Z80.</p> + +<pre><code><span class="instruction">ld</span> bc,de +<span class="instruction">ld</span> bc,hl +<span class="instruction">ld</span> de,bc +<span class="instruction">ld</span> de,hl +<span class="instruction">ld</span> hl,bc +<span class="instruction">ld</span> hl,de +</code></pre> + +<p>They are implemented using two instructions under the hood. First the high register part is loaded and then the low.</p> + <div id="return-codes"></div> <h2>Return Codes</h2> @@ 1277,6 1330,12 @@ a comment */</span> <span class="instruction">inc</span> <span class="special">(</span>hl<span class="special">)</span> <span class="comment">// increase index in instruction above</span> </code></pre> +<p>Instruction labels become <a href="#memory-storage-types">Memory Storage Types</a> and it means they have a defined size and the low and high parts of word addresses can be accessed directly through the lo and hi properties.</p> + +<pre><code><span class="instruction">lda</span> value:<span class="literal">$ffff</span> +<span class="instruction">inc</span> value.lo <span class="comment">// the low part of the previous instruction's argument</span> +</code></pre> + <p>Constant declarations look like this.</p> <pre><code><span class="keyword">const</span> NUM_LIVES <span class="operator">=</span> <span class="literal">5</span> <span class="comment">// constant declaration</span> @@ 1894,6 1953,52 @@ aa </tr> </table> +<h4>String Functions</h4> + +<p>There are a couple of functions specific to operating on string data or characters.</p> + +<table> + <tr> + <th>Function</th> + <th>Argument types</th> + <th>Description</th> + <th style="width: 35%;">Examples</th> + </tr> + <tr> + <td><code><span class="function">uppercase</span><span class="special">(</span>text <span class="special">[</span>, locale<span class="special">]</span><span class="special">)</span></code></td> + <td>string|integer, string</td> + <td>Returns an uppercase version of the string or character sent as the first argument.</td> + <td><code><span class="function">uppercase</span><span class="special">(</span><span class="literal">"Commodore"</span><span class="special">)</span> <span class="comment">// "COMMODORE"</span></code><br/><code><span class="function">uppercase</span><span class="special">(</span><span class="literal">"Cåmmodåre"</span>, <span class="literal">"swedish"</span><span class="special">)</span> <span class="comment">// "CÅMMODÅRE"</span></code><br/><code><span class="function">uppercase</span><span class="special">(</span><span class="literal">'a'</span><span class="special">)</span> <span class="comment">// 65</span></code></td> + </tr> + <tr> + <td><code><span class="function">lowercase</span><span class="special">(</span>text <span class="special">[</span>, locale<span class="special">]</span><span class="special">)</span></code></td> + <td>string|integer, string</td> + <td>Returns a lowercase version of the string or character sent as the first argument.</td> + <td><code><span class="function">lowercase</span><span class="special">(</span><span class="literal">"Commodore"</span><span class="special">)</span> <span class="comment">// "commodore"</span></code><br/><code><span class="function">lowercase</span><span class="special">(</span><span class="literal">"ABCÅÄÖ"</span>, <span class="literal">"swedish"</span><span class="special">)</span> <span class="comment">// "abcåäö"</span></code><br/><code><span class="function">lowercase</span><span class="special">(</span><span class="literal">'A'</span><span class="special">)</span> <span class="comment">// 97</span></code></td> + </tr> +</table> + +<p>When specifying a locale string in the string functions, these are the currently supported locales.</p> + +<table> + <tr> + <th>Locale</th> + <th>Comment</th> + </tr> + <tr> + <td>default</td> + <td>This is the default locale. It uses the default C locale. It doesn't handle any characters other than A-Z.</td> + </tr> + <tr> + <td>english</td> + <td>This is the US English locale. This is much like the C locale.</td> + </tr> + <tr> + <td>swedish</td> + <td>This is the Swedish locale. Supports the åäö characters.</td> + </tr> +</table> + <div id="list-type"></div> <h3>List Type</h3> @@ 1994,7 2099,7 @@ aa <td><code>set<span class="special">(</span>key, value<span class="special">)</span></code></td> <td>boolean|integer|string, any</td> <td>Adds <code>value</code> to be accessible by <code>key</code> in the map.</td> - <td><code><span class="keyword">var</span> aa <span class="operator">=</span> map<span class="special">(</span><span class="special">)</span></code><br/><code>aa.set<span class="special">(</span><span class="literal">"hi"</span> <span class="operator">=</span> <span class="literal">0</span><span class="special">)</span></code></td> + <td><code><span class="keyword">var</span> aa <span class="operator">=</span> map<span class="special">(</span><span class="special">)</span></code><br/><code>aa.set<span class="special">(</span><span class="literal">"hi"</span>, <span class="literal">0</span><span class="special">)</span></code></td> </tr> <tr> <td><code>get<span class="special">(</span>key<span class="special">)</span></code></td> @@ 2110,6 2215,15 @@ bb.pop<span class="special">(</span><spa <li><code><span class="keyword">long</span></code> is a 32 bit data type</li> </ul> +<p>The word storage type has a pair of properties to address the first and second byte in the word. These are <code>lo</code> and <code>hi</code>.</p> + +<pre><code><span class="keyword">define</span> <span class="keyword">word</span> number <span class="operator">=</span> <span class="literal">5</span> +<span class="keyword">const</span> high_addr <span class="operator">=</span> number.hi +<span class="keyword">const</span> low_addr <span class="operator">=</span> number.lo +</code></pre> + +<p>These properties will take <code>number</code> which points to the 5 i memory and return the offset to the high and low byte of the word respectively.</p> + <div id="storage-conversions"></div> <h2>Storage Conversions</h2> @@ 2247,6 2361,12 @@ bb.pop<span class="special">(</span><spa <td><code><span class="function">log10</span><span class="special">(</span><span class="literal">100</span><span class="special">)</span> <span class="comment">// 2.0</span></code></td> </tr> <tr> + <td><code><span class="function">logn</span><span class="special">(</span>x, n<span class="special">)</span></code></td> + <td>numeric, numeric</td> + <td>Returns the base-<code>n</code> logarithm of <code>x</code>.</td> + <td><code><span class="function">logn</span><span class="special">(</span><span class="literal">243</span>, <span class="literal">3</span><span class="special">)</span> <span class="comment">// 5.0</span></code></td> + </tr> + <tr> <td><code><span class="function">max</span><span class="special">(</span>a, ...<span class="special">)</span></code></td> <td>numeric</td> <td>Returns the largest of the arguments.</td> @@ 2345,7 2465,11 @@ bb.pop<span class="special">(</span><spa <h2>Print and Formatting</h2> -<p>There are two functions dedicated to formatting and printing, <code><span class="function">format</span></code> and <code><span class="function">print</span></code>. Both use the same arguments but <code><span class="function">format</span></code> returns the result and <code><span class="function">print</span></code> outputs it. Let's take <code><span class="function">format</span></code> as the example.</p> +<p>A <code><span class="function">print</span></code> function exists to output text when assembling. This can be useful when you want to know about locations or calculations made in the assembled code.</p> + +<p><em>Note that in order to see the output you need to use at least verbose level <code>-v2</code>. See <a href="#verboseness">Verboseness</a> for more information.</em></p> + +<p>There are two functions dedicated to formatting and printing, <code><span class="function">format</span></code> and <code><span class="function">print</span></code>. Both use the same arguments but <code><span class="function">format</span></code> returns the result and <code><span class="function">print</span></code> outputs it. Let's take <code><span class="function">format</span></code> as the example when looking at the arguments.</p> <pre><code><span class="keyword">const</span> WIDTH <span class="operator">=</span> <span class="literal">40</span> <span class="function">format</span><span class="special">(</span><span class="literal">"width: {}"</span>, WIDTH<span class="special">)</span> <span class="comment">// returns "width: 40"</span> @@ 2488,6 2612,21 @@ bb.pop<span class="special">(</span><spa <span class="special">}</span> </code></pre> +<p>Sometimes you want the code to end at a position rather than start at a position. You can do this by setting the section start based on the end minus the length of the section data. The following example shows how it can be done and still enforce that the size must fit within two memory locations.</p> + +<pre><code><span class="keyword">const</span> .section_start <span class="operator">=</span> <span class="literal">$8000</span> +<span class="keyword">const</span> .section_end <span class="operator">=</span> <span class="literal">$9000</span> +<span class="keyword">const</span> .code_size <span class="operator">=</span> code_end <span class="operator">-</span> code_start +<span class="function">static_assert</span><span class="special">(</span>.section_end <span class="operator">-</span> .code_size <span class="operator">></span><span class="operator">=</span> .section_start, <span class="literal">"section overflow"</span><span class="special">)</span> +<span class="keyword">section</span> <span class="keyword">code</span>, <span class="literal">"main"</span>, .section_end <span class="operator">-</span> .code_size, .section_end +<span class="special">{</span> +code_start: + <span class="comment">// code here</span> + <span class="comment">// ...</span> +code_end: +<span class="special">}</span> +</code></pre> + <div id="sections-in-sections"></div> <h3>Sections in Sections</h3> @@ 2646,17 2785,19 @@ end: <span class="keyword">section</span> <span class="keyword">code</span>, <span class="literal">"image_1"</span>, <span class="literal">$e000</span>, <span class="literal">$10000</span> <span class="special">{</span> <span class="comment">// code here</span> - <span class="keyword">align</span> <span class="literal">$2000</span> + <span class="keyword">align</span> <span class="literal">$2000</span>, <span class="literal">$ff</span> <span class="special">}</span> <span class="keyword">section</span> <span class="keyword">code</span>, <span class="literal">"image_2"</span>, <span class="literal">$e000</span>, <span class="literal">$10000</span> <span class="special">{</span> <span class="comment">// code here</span> - <span class="keyword">align</span> <span class="literal">$2000</span> + <span class="keyword">align</span> <span class="literal">$2000</span>, <span class="literal">$ff</span> <span class="special">}</span> <span class="comment">// more sections</span> <span class="special">}</span> </code></pre> +<p>The <code><span class="keyword">align</span></code> keyword is used here to fill up the rest of each bank up to where the next one begins.</p> + <p>An alternative is to use the <a href="#bank-mode">bank mode</a> and place the sections in their own 64 kB address space.</p> <pre><code><span class="keyword">section</span> <span class="keyword">code</span>, <span class="literal">"main"</span>, <span class="literal">0</span> <span class="comment">// start address will not be used</span> @@ 2664,12 2805,12 @@ end: <span class="keyword">section</span> <span class="keyword">code</span>, <span class="literal">"image_1"</span>, <span class="literal">$0e000</span>, <span class="literal">$10000</span> <span class="special">{</span> <span class="comment">// code here</span> - <span class="keyword">align</span> <span class="literal">$2000</span> + <span class="keyword">align</span> <span class="literal">$2000</span>, <span class="literal">$ff</span> <span class="special">}</span> <span class="keyword">section</span> <span class="keyword">code</span>, <span class="literal">"image_2"</span>, <span class="literal">$1e000</span>, <span class="literal">$20000</span> <span class="special">{</span> <span class="comment">// code here</span> - <span class="keyword">align</span> <span class="literal">$2000</span> + <span class="keyword">align</span> <span class="literal">$2000</span>, <span class="literal">$ff</span> <span class="special">}</span> <span class="comment">// more sections</span> <span class="special">}</span> @@ 2938,7 3079,13 @@ end: <span class="special">}</span> </code></pre> -<p>The label <code>multiply_by_8</code> is automatically created.</p> +<p>A subroutine also has the property that it can be called like a macro without arguments. The two following lines are equivalent.</p> + +<pre><code><span class="instruction">jsr</span> multiply_by_8 +multiply_by_8<span class="special">(</span><span class="special">)</span> +</code></pre> + +<p>The macro style call has the advantage that a module can change a subroutine into a macro to inline the code, or the other way around, without changing the calling code.</p> <div id="enumerations"></div> @@ 3213,6 3360,49 @@ repeat <span class="literal">10</span> </code></pre> <p>This will fill up the gap to next page boundary with the number 55.</p> + +<p>Sometimes it is necessary to ensure that a block of code or data is within a 256 byte page to avoid extra cycles being spent on indexing or branch instructions. The following macro can be used to verify that a memory block is within alignment.</p> + +<pre><code><span class="comment">// Check that the code/data between .start and .end won't cross an alignment border.</span> +<span class="keyword">macro</span> assert_within_alignment<span class="special">(</span>.start, .end, .alignment<span class="special">)</span> +<span class="special">{</span> + <span class="function">static_assert</span><span class="special">(</span>.end <span class="operator">-</span> .start <span class="operator">></span><span class="operator">=</span> <span class="literal">0</span>, <span class="literal">"Content wraps around"</span><span class="special">)</span> + <span class="function">static_assert</span><span class="special">(</span>.end <span class="operator">-</span> .start <span class="operator"><</span><span class="operator">=</span> .alignment, <span class="literal">"Content too large for alignment"</span><span class="special">)</span> + <span class="keyword">if</span> <span class="special">(</span>.end <span class="operator">-</span> .start <span class="operator">></span> <span class="literal">0</span><span class="special">)</span> <span class="special">{</span> + <span class="function">static_assert</span><span class="special">(</span>.start<span class="operator">/</span>.alignment <span class="operator">==</span> <span class="special">(</span>.end <span class="operator">-</span> <span class="literal">1</span><span class="special">)</span><span class="operator">/</span>.alignment, <span class="literal">"Content crosses alignment"</span><span class="special">)</span> + <span class="special">}</span> +<span class="special">}</span> +</code></pre> + +<p>When a code block needs to be within a 256 byte page to work, this macro can be used to automatically add dummy data at the macro location until the code block (that needs to be placed later in the same section) is within the alignment boundaries.</p> + +<pre><code><span class="comment">// Makes sure the area between .start and .end is within an alignment block.</span> +<span class="comment">// It adds bytes of data at the macro position to make sure the area isn't</span> +<span class="comment">// crossing any alignment boundaries.</span> +<span class="keyword">macro</span> align_within_page<span class="special">(</span>.start, .end, .alignment, .fill_byte<span class="special">)</span> +<span class="special">{</span> + <span class="keyword">const</span> .size <span class="operator">=</span> .end <span class="operator">-</span> .start + <span class="function">static_assert</span><span class="special">(</span>.relative_position <span class="operator"><</span><span class="operator">=</span> .start, <span class="literal">"Macro must be placed earlier in memory"</span><span class="special">)</span> + <span class="function">static_assert</span><span class="special">(</span>.size <span class="operator">></span><span class="operator">=</span> <span class="literal">0</span>, <span class="literal">"Content wraps around"</span><span class="special">)</span> + <span class="function">static_assert</span><span class="special">(</span>.size <span class="operator"><</span><span class="operator">=</span> .alignment, <span class="literal">"Content too large for alignment"</span><span class="special">)</span> + <span class="keyword">if</span> <span class="special">(</span>.size <span class="operator">></span> <span class="literal">0</span><span class="special">)</span> <span class="special">{</span> + <span class="comment">// This is quite tricky because the code cannot make calculations based</span> + <span class="comment">// on the aligned position since it will cause variable oscillation. Instead</span> + <span class="comment">// it is using the distance to the area to calculate the unaligned position</span> + <span class="comment">// and base the alignment size on that.</span> + <span class="keyword">const</span> .distance <span class="operator">=</span> .start <span class="operator">-</span> .relative_position + <span class="keyword">const</span> .start_before <span class="operator">=</span> <span class="operator">*</span> <span class="operator">+</span> .distance + <span class="keyword">const</span> .end_before <span class="operator">=</span> .start_before <span class="operator">+</span> .size + <span class="keyword">const</span> is_aligned <span class="operator">=</span> .start_before<span class="operator">/</span>.alignment <span class="operator">==</span> <span class="special">(</span>.end_before <span class="operator">-</span> <span class="literal">1</span><span class="special">)</span><span class="operator">/</span>.alignment + <span class="keyword">if</span> <span class="special">(</span><span class="operator">!</span>is_aligned<span class="special">)</span> <span class="special">{</span> + repeat .alignment <span class="operator">-</span> <span class="function">modulo</span><span class="special">(</span>.start_before, .alignment<span class="special">)</span> <span class="special">{</span> + <span class="keyword">define</span> <span class="keyword">byte</span> <span class="operator">=</span> .fill_byte + <span class="special">}</span> + <span class="special">}</span> + <span class="special">}</span> +.relative_position: +<span class="special">}</span> +</code></pre> </body> </html>
M jasm/website/site/index.html +19 -2
@@ 4,6 4,7 @@ <title>jAsm</title> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta name="description" content="This is the official home for the jAsm assembler."> + <meta name="keywords" content="jAsm, 6502, z80, assembler, asm, cross-assembler"> <link rel="shortcut icon" href="images/favicon.ico"> <style> @@ 79,8 80,10 @@ <h1>The Binaries</h1> <ul> <li> - <a href="binaries/jasm_1.23_linux64.7z">jAsm 1.23 for 64-bit Linux</a> - <a href="binaries/jasm_1.23_win64.7z">jAsm 1.23 for 64-bit Windows</a> + <a href="binaries/jasm_1.24_linux64.7z">jAsm 1.24 for 64-bit Linux</a> + </li> + <li> + <a href="binaries/jasm_1.24_win64.7z">jAsm 1.24 for 64-bit Windows</a> </li> </ul> <h1>The Source</h1> @@ 95,6 98,20 @@ <h1>Version History</h1> <ul> <li> + 1.24 + <ul> + <li>Added pseudo instructions for 6502 and Z80.</li> + <li>Added the ability to call a subroutine with a macro call style.</li> + <li>Improved documentation regarding alignment.</li> + <li>Added hi and lo properties on word storage types.</li> + <li>Added logn function.</li> + <li>Added uppercase and lowercase conversion functions.</li> + <li>Added an option to name output files entirely after sections.</li> + <li>Fixed a bug the section size limit wasn't enforced for child sections.</li> + <li>Fixed a bug where 's' became a pound character in Petscii conversions.</li> + </ul> + </li> + <li> 1.23 <ul> <li>Strings can now contain the zero character (previously mistaken as the end of the string).</li>
M release.py +2 -0
@@ 25,6 25,7 @@ def build_mingw(version): print("MingW building") # remove build directory contents print(" cleaning") + os.makedirs("build", exist_ok=True) shutil.rmtree("build") # make sure there is a build directory @@ 69,6 70,7 @@ def build_linux(version): print("Linux building") # remove build directory contents print(" cleaning") + os.makedirs("build", exist_ok=True) shutil.rmtree("build") # make sure there is a build directory
M sublime/m6502/jAsm.sublime-syntax +2 -2
@@ 153,9 153,9 @@ contexts: scope: keyword.control.jasm - match: \b(bss|code|mapping|part)\b scope: keyword.control.jasm - - match: \b(abs|acos|asin|atan|atan2|ceil|clamp|cos|cosh|degrees|exp|float|floor|format|hexstring|int|lerp|log|log10|map|max|min|modulo|offsetof|pow|print|radians|remainder|round|select|sin|sinh|sizeof|sqrt|static_assert|string|symbol|tan|tanh|unicode)\b + - match: \b(abs|acos|asin|atan|atan2|ceil|clamp|cos|cosh|degrees|exp|float|floor|format|hexstring|int|lerp|log|log10|logn|map|max|min|modulo|offsetof|pow|print|radians|remainder|round|select|sin|sinh|sizeof|sqrt|static_assert|string|symbol|tan|tanh|unicode|uppercase|lowercase)\b scope: support.function.jasm - - match: \b(adc|and|asl|bcc|bcs|beq|bit|bmi|bne|bpl|brk|bvc|bvs|clc|cld|cli|clv|cmp|cpx|cpy|dec|dex|dey|eor|inc|inx|iny|jmp|jsr|lda|ldx|ldy|lsr|nop|ora|pha|php|pla|plp|rol|ror|rti|rts|sbc|sec|sed|sei|sta|stx|sty|tax|tay|tsx|txa|txs|tya)\b + - match: \b(adc|and|asl|bcc|bcs|beq|bit|bmi|bne|bpl|brk|bvc|bvs|clc|cld|cli|clv|cmp|cpx|cpy|dec|dex|dey|eor|inc|inx|iny|jmp|jsr|lda|ldx|ldy|lsr|nop|ora|pha|php|pla|plp|rol|ror|rti|rts|sbc|sec|sed|sei|sta|stx|sty|tax|tay|tsx|txa|txs|tya|bhs|blt)\b scope: support.class.jasm - match: \b(true|false)\b scope: constant.language.jasm
M sublime/z80/jAsm.sublime-syntax +1 -1
@@ 155,7 155,7 @@ contexts: scope: keyword.control.jasm - match: \b(bss|code|mapping|part)\b scope: keyword.control.jasm - - match: \b(abs|acos|asin|atan|atan2|ceil|clamp|cos|cosh|degrees|exp|float|floor|format|hexstring|int|lerp|log|log10|map|max|min|modulo|offsetof|pow|print|radians|remainder|round|select|sin|sinh|sizeof|sqrt|static_assert|string|symbol|tan|tanh|unicode)\b + - match: \b(abs|acos|asin|atan|atan2|ceil|clamp|cos|cosh|degrees|exp|float|floor|format|hexstring|int|lerp|log|log10|logn|map|max|min|modulo|offsetof|pow|print|radians|remainder|round|select|sin|sinh|sizeof|sqrt|static_assert|string|symbol|tan|tanh|unicode|uppercase|lowercase)\b scope: support.function.jasm - match: \b(adc|add|and|bit|call|ccf|cp|cpd|cpdr|cpi|cpir|cpl|daa|dec|di|djnz|ei|ex|exx|halt|im|in|inc|ind|indr|ini|inir|jp|jr|ld|ldd|lddr|ldi|ldir|neg|nop|or|otdr|otir|out|outd|outi|pop|push|res|ret|reti|retn|rl|rla|rlc|rlca|rld|rr|rra|rrc|rrca|rrd|rst|sbc|scf|set|sla|sra|srl|sub|xor)\b scope: support.class.jasm