# HG changeset patch # User Jonas Hultén # Date 1546336491 -3600 # Tue Jan 01 10:54:51 2019 +0100 # Node ID f7c4f5b70ca566d72c662a10379652cb359c31eb # Parent b16768016b2f53ab0ffe85b9f94ae76be9760409 # Parent c48fa534da717d59af982cfddb39bfe40c01adf5 Merge diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -20,3 +20,4 @@ jasm/bin/**/* jasm/output.bin jasm/test.asm +build/**/* diff --git a/.kdev4/jasm.kdev4 b/.kdev4/jasm.kdev4 new file mode 100644 --- /dev/null +++ b/.kdev4/jasm.kdev4 @@ -0,0 +1,69 @@ +[Buildset] +BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x08\x00j\x00a\x00s\x00m) + +[CMake] +Build Directory Count=1 +Current Build Directory Index-Host System=0 + +[CMake][CMake Build Directory 0] +Build Directory Path=/home/jonas/dev/c64/jasm/build +Build Type=Debug +CMake Binary=/usr/bin/cmake +CMake Executable=/usr/bin/cmake +Environment Profile= +Extra Arguments= +Install Directory=/usr/local +Runtime=Host System + +[Launch] +Launch Configurations=Launch Configuration 0,Launch Configuration 1,Launch Configuration 2 + +[Launch][Launch Configuration 0] +Configured Launch Modes=execute +Configured Launchers=nativeAppLauncher +Name=jasm-6502 +Type=Native Application + +[Launch][Launch Configuration 0][Data] +Arguments=test.jasm -v3 test.prg +Dependencies=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x03\x00\x00\x00\x08\x00j\x00a\x00s\x00m\x00\x00\x00\x12\x00j\x00a\x00s\x00m\x00-\x006\x005\x000\x002\x00\x00\x00\x12\x00j\x00a\x00s\x00m\x00-\x006\x005\x000\x002) +Dependency Action=Build +EnvironmentGroup= +Executable=file:///home/jonas/dev/c64/jasm +External Terminal=konsole --noclose --workdir %workdir -e %exe +Project Target=jasm,jasm-6502,jasm-6502 +Use External Terminal=false +Working Directory=file:///home/jonas/dev/c64/jasm/jasm/test +isExecutable=false + +[Launch][Launch Configuration 1] +Configured Launch Modes=execute +Configured Launchers=nativeAppLauncher +Name=jasm-z80 +Type=Native Application + +[Launch][Launch Configuration 1][Data] +Arguments=test.jasm -v3 test.prg +Dependencies=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x03\x00\x00\x00\x08\x00j\x00a\x00s\x00m\x00\x00\x00\x10\x00j\x00a\x00s\x00m\x00-\x00z\x008\x000\x00\x00\x00\x10\x00j\x00a\x00s\x00m\x00-\x00z\x008\x000) +Dependency Action=Build +EnvironmentGroup= +Executable=file:///home/jonas/dev/c64/jasm +External Terminal=konsole --noclose --workdir %workdir -e %exe +Project Target=jasm,jasm-z80,jasm-z80 +Use External Terminal=false +Working Directory=file:///home/jonas/dev/c64/jasm/jasm/test +isExecutable=false + +[Launch][Launch Configuration 2] +Configured Launch Modes=execute +Configured Launchers=nativeAppLauncher +Name=hasher +Type=Native Application + +[Launch][Launch Configuration 2][Data] +Dependencies=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x03\x00\x00\x00\x08\x00j\x00a\x00s\x00m\x00\x00\x00\x0c\x00h\x00a\x00s\x00h\x00e\x00r\x00\x00\x00\x0c\x00h\x00a\x00s\x00h\x00e\x00r) +Dependency Action=Build +Project Target=jasm,hasher,hasher + +[Project] +VersionControlSupport=kdevgit diff --git a/README.md b/README.md --- a/README.md +++ b/README.md @@ -4,13 +4,13 @@ # Command line build with CMake in Linux -To build with CMake you need CMake 3.5, Clang, git and python3 installed. On Debian, Ubuntu or Mint systems you can use apt-get to fetch the dependencies like this. +To build with CMake you need CMake 3.5, Clang, Mercurial and python3 installed. On Debian, Ubuntu or Mint systems you can use apt-get to fetch the dependencies like this. - sudo apt-get install cmake clang git python3 + sudo apt-get install cmake clang mercurial python3 Clone the repository into a directory called 'jasm' and build it like this. - git clone https://bitbucket.org/bjonte/jasm.git jasm + hg clone ssh://hg@bitbucket.org/bjonte/jasm cd jasm export CXX=/usr/bin/clang++ mkdir build diff --git a/jasm.kdev4 b/jasm.kdev4 new file mode 100644 --- /dev/null +++ b/jasm.kdev4 @@ -0,0 +1,4 @@ +[Project] +CreatedFrom=CMakeLists.txt +Manager=KDevCMakeManager +Name=jasm diff --git a/jasm.sublime-project b/jasm.sublime-project --- a/jasm.sublime-project +++ b/jasm.sublime-project @@ -26,7 +26,7 @@ [ { "name": "Make", - "cmd": [ "make" ], + "cmd": [ "make", "-j4" ], "working_dir": "${project_path}/build", "file_regex": "^(.+):(\\d+):(\\d+):\\s+\\w+:\\s+(.*)$" }, diff --git a/jasm.workspace b/jasm.workspace deleted file mode 100644 --- a/jasm.workspace +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/jasm/assembling/assembler_impl/assembler_impl.cpp b/jasm/assembling/assembler_impl/assembler_impl.cpp --- a/jasm/assembling/assembler_impl/assembler_impl.cpp +++ b/jasm/assembling/assembler_impl/assembler_impl.cpp @@ -40,8 +40,9 @@ , _vice_dump_file(vice_dump_file) , _gba_dump_file(gba_dump_file) , _dump_symbols(!symbol_dump_file.empty() || !vice_dump_file.empty() || !gba_dump_file.empty()) - , _current_pass_types(token_chain_type_buffer_size) - , _previous_pass_types(token_chain_type_buffer_size) + , _current_pass(token_chain_type_buffer_size) + , _previous_pass(token_chain_type_buffer_size) + , _oscillating_state(false) , _last_pass_hash(0) , _static_none_type(0) , _static_unknown_type(0) @@ -85,8 +86,7 @@ // add empty string for zero hash because the root namespace has hash 0 _strings.add(0, L""); - if (_dump_symbols) - _symbol_names[0] = L""; + _symbol_names[0] = L""; } void Assembler::fill_type_integer_operators(TypeDescription &type) @@ -134,21 +134,21 @@ void Assembler::setup_fundamental_types() { { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::None; _static_none_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::Unknown; _static_unknown_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::BoolValue; @@ -162,7 +162,7 @@ _static_bool_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::IntegerValue; @@ -170,7 +170,7 @@ _static_integer_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::FloatValue; @@ -193,7 +193,7 @@ _static_float_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = static_cast(StringProperties::NumProperties); TypeDescriptionWithPayload &type = reserve_type(num_properties); type.type = ValueType::StringValue; @@ -212,7 +212,7 @@ _static_string_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = static_cast(StringProperties::NumProperties); TypeDescriptionWithPayload &type = reserve_type(num_properties); type.type = ValueType::StringReference; @@ -231,7 +231,7 @@ _static_string_reference_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::RangeValue; @@ -239,7 +239,7 @@ _static_range_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::ByteOffset; @@ -248,7 +248,7 @@ _static_byte_offset_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::WordOffset; @@ -257,7 +257,7 @@ _static_word_offset_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::LongOffset; @@ -266,7 +266,7 @@ _static_long_offset_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::ValueReference; @@ -274,7 +274,7 @@ _static_value_reference_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::FunctionReference; @@ -282,7 +282,7 @@ _static_function_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::ByteTypename; @@ -291,7 +291,7 @@ _static_byte_type_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::WordTypename; @@ -300,7 +300,7 @@ _static_word_type_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::LongTypename; @@ -309,7 +309,7 @@ _static_long_type_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::MacroReference; @@ -317,7 +317,7 @@ _static_macro_reference = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::MethodClosure; @@ -325,7 +325,7 @@ _static_method_closure_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = static_cast(ListProperties::NumProperties); TypeDescriptionWithPayload &type = reserve_type(num_properties); type.type = ValueType::ListReference; @@ -345,7 +345,7 @@ _static_list_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); type.type = ValueType::ListElementReference; @@ -353,7 +353,7 @@ _static_list_element_type = add_type_to_type_map(type, p); } { - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = static_cast(MapProperties::NumProperties); TypeDescriptionWithPayload &type = reserve_type(num_properties); type.type = ValueType::MapReference; @@ -375,7 +375,7 @@ { const TypeDescription &underlying_type = find_type(underlying_type_hash); - TokenReadPosition p = _current_pass_types.position(); + TokenReadPosition p = _current_pass.types.position(); uint32_t num_properties = 0; TypeDescription &type = reserve_type(num_properties); @@ -436,7 +436,7 @@ if (!_strings.has(symbol_hash)) _strings.add(symbol_hash, pair.first); if (create_label(generate, symbol_hash, is_global, StorageType::Constant, beginning)) { - Value &new_value = _current_pass_values.back(); + Value &new_value = _current_pass.values.back(); set_boolean(new_value, pair.second); } } @@ -445,7 +445,7 @@ if (!_strings.has(symbol_hash)) _strings.add(symbol_hash, pair.first); if (create_label(generate, symbol_hash, is_global, StorageType::Constant, beginning)) { - Value &new_value = _current_pass_values.back(); + Value &new_value = _current_pass.values.back(); set_integer(new_value, pair.second); } } @@ -458,7 +458,7 @@ _strings.add(string_hash, pair.second); if (create_label(generate, symbol_hash, is_global, StorageType::Constant, beginning)) { - Value &new_value = _current_pass_values.back(); + Value &new_value = _current_pass.values.back(); set_string(new_value, string_hash); } } @@ -519,6 +519,28 @@ propagate_data(section); } +void Assembler::prepare_next_assembly_pass() +{ + // store this pass' section part sizes for next pass + collect_section_sizes(_sections); + + // move current pass symbol information to previous pass + std::swap(_current_pass.values, _previous_pass.values); + _current_pass.values.clear(); + + _previous_pass.types = std::move(_current_pass.types); + _current_pass.types = TokenChain(token_chain_type_buffer_size); + + std::swap(_current_pass.value_lookup, _previous_pass.value_lookup); + _current_pass.value_lookup.clear(); + + std::swap(_current_pass.type_lookup, _previous_pass.type_lookup); + _current_pass.type_lookup.clear(); + + std::swap(_current_pass.namespaces, _previous_pass.namespaces); + _current_pass.namespaces.clear(); +} + void Assembler::run_assembly_pass(bool generate, int pass) { debug() << L"Assemble pass " << pass << L'\n'; @@ -527,8 +549,8 @@ assert(_data_generation_depth == 0); _input_reader = TokenReader(_input[0]); - _current_pass_type_reader = TokenReader(_current_pass_types); - _previous_pass_type_reader = TokenReader(_previous_pass_types); + _current_pass.type_reader = TokenReader(_current_pass.types); + _previous_pass.type_reader = TokenReader(_previous_pass.types); _sections.clear(); _section = nullptr; @@ -541,7 +563,7 @@ // allocated first 8 bytes to be sure that 0 is unused. It may come in handy // as a null pointer. static_assert(sizeof(void *) == 8, "Pointer is expected to be 8 bytes"); - void *&null_padding = _current_pass_types.reserve(); + void *&null_padding = _current_pass.types.reserve(); null_padding = nullptr; // constants uses fundamental types so the order matters @@ -579,25 +601,6 @@ dump_symbols(base_name(_symbol_dump_file) + std::to_wstring(pass) + file_extension(_symbol_dump_file)); } #endif - - // store this pass' section part sizes for next pass - collect_section_sizes(_sections); - - // move current pass symbol information to previous pass - std::swap(_current_pass_values, _previous_pass_values); - _current_pass_values.clear(); - - _previous_pass_types = std::move(_current_pass_types); - _current_pass_types = TokenChain(token_chain_type_buffer_size); - - std::swap(_current_pass_value_lookup, _previous_pass_value_lookup); - _current_pass_value_lookup.clear(); - - std::swap(_current_pass_type_lookup, _previous_pass_type_lookup); - _current_pass_type_lookup.clear(); - - std::swap(_current_pass_namespaces, _previous_pass_namespaces); - _current_pass_namespaces.clear(); } } @@ -643,9 +646,9 @@ bool Assembler::progress_was_made() { // hash types - uint64_t storage_hash = _previous_pass_types.hash(); + uint64_t storage_hash = _current_pass.types.hash(); // hash values - for(const auto &value : _previous_pass_values) { + for(const auto &value : _current_pass.values) { storage_hash = value.hash(storage_hash); } // TODO: hash variable map @@ -669,19 +672,18 @@ // The variables are oscillating and doesn't stabilize! // This will go on forever so we must exit and warn the // user that the result will not assemble. - SourceLocation location; - location.file_index = 0; - location.column = 1; - location.row = 1; - const wchar_t * const message = - L"The variable state doesn't stabilize!\n" - L"This is an indication that the source code contains conflicting conditional\n" - L"code. Try disabling the latest changes in conditional blocks or code referring\n" - L"to 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"; - const bool fatal = true; - report_error(location, AssemblyErrorCodes::UnstableVariableState, message, fatal); + _oscillating_state = true; + + if (_dump_symbols) { + // We have already done a pass with dump symbols turned on (to collect a reverse + // lookup for symbol names so report no more progress. + return false; + } else { + // Turn on dump symbols flag to start storing reverse lookups for symbols in the next pass. + _dump_symbols = true; + // Fake progress to get another pass + return true; + } } return false; @@ -695,6 +697,17 @@ , name(std::move(name_)) , value(std::move(value_)) , constant(constant_) + , current_pass(true) + , type(type_) + {} + + SymbolInformation(uint64_t hash_, size_t index_, std::wstring name_, std::wstring value_, bool constant_, bool current_pass_, ValueType type_) + : hash(hash_) + , index(index_) + , name(std::move(name_)) + , value(std::move(value_)) + , constant(constant_) + , current_pass(current_pass_) , type(type_) {} @@ -710,19 +723,99 @@ std::wstring name; ///< Readable symbol name. std::wstring 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) +{ + // collect and sort symbol names + std::vector symbol_list; + symbol_list.reserve(_current_pass.value_lookup.size() + 100); + + // find symbols in either pass + core::HashMap> used_symbols; + std::wstring no_name = L""; + 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; + symbol_list.emplace_back(hash, value_index, symbol_name, to_string(_strings, value), value.storage_type != StorageType::Variable, value.type); + used_symbols[hash] = true; + } + for(const auto &pair : _previous_pass.value_lookup) { + uint64_t hash = pair.first; + if (UNLIKELY(!used_symbols.has(hash))) { + 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; + 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; + } + } + std::sort(symbol_list.begin(), symbol_list.end()); + + // compare values with previous pass and print differences + for(const SymbolInformation &symbol : symbol_list) { + if (symbol.current_pass) { + // first check if the symbol exists in the other pass + auto it = _previous_pass.value_lookup.find(symbol.hash); + if (it != _previous_pass.value_lookup.end()) { + const Value ¤t = _current_pass.values[symbol.index]; + const Value &previous = _previous_pass.values[it->second]; + if (current.hash(0) == previous.hash(0)) { + // they are actually the same, so skip printing this + continue; + } else { + ss << std::setw(16) << to_string(_strings, previous) << std::setw(0); + ss << L" | "; + ss << std::setw(16) << symbol.value << std::setw(0); + } + } else { + ss << std::setw(16) << L"" << std::setw(0); + ss << L" | "; + ss << std::setw(16) << symbol.value << std::setw(0); + } + + } else { + // first check if the symbol exists in the other pass + auto it = _current_pass.value_lookup.find(symbol.hash); + if (it != _current_pass.value_lookup.end()) { + const Value ¤t = _current_pass.values[it->second]; + const Value &previous = _previous_pass.values[symbol.index]; + if (current.hash(0) == previous.hash(0)) { + // they are actually the same, so skip printing this + continue; + } else { + ss << std::setw(16) << symbol.value << std::setw(0); + ss << L" | "; + 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"" << std::setw(0); + } + } + + ss << L" | "; + ss << symbol.name << L'\n'; + } +} + void Assembler::dump_symbols(const std::wstring &filename) { // extract all relevant symbol information std::vector symbol_list; - symbol_list.reserve(_current_pass_value_lookup.size()); + symbol_list.reserve(_current_pass.value_lookup.size()); - for(const auto &pair : _current_pass_value_lookup) { + 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]; + 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"" : it->second, to_string(_strings, value), value.storage_type != StorageType::Variable, value.type); } @@ -791,16 +884,16 @@ std::set breakpoints; std::set r_breakpoints; std::set w_breakpoints; - symbol_list.reserve(_current_pass_value_lookup.size()); + 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"; - for(const auto &pair : _current_pass_value_lookup) { + 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]; + const Value &value = _current_pass.values[value_index]; auto it = _symbol_hash_names.find(hash); // only add constants which we have stored names for @@ -897,12 +990,12 @@ { // extract all relevant symbol information std::vector symbol_list; - symbol_list.reserve(_current_pass_value_lookup.size()); + symbol_list.reserve(_current_pass.value_lookup.size()); - for(const auto &pair : _current_pass_value_lookup) { + 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]; + const Value &value = _current_pass.values[value_index]; auto it = _symbol_hash_names.find(hash); // only add constants which we have stored names for @@ -1035,8 +1128,9 @@ int pass = 1; while (true) { TimerScope timer(L"Assemble pass"); - constexpr bool place_labels = false; - run_assembly_pass(place_labels, pass); + prepare_next_assembly_pass(); + constexpr bool generate_code = false; + run_assembly_pass(generate_code, pass); ++pass; @@ -1044,11 +1138,27 @@ break; } + 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"; + + std::wstringstream ss; + ss << L"Differing symbols in last two passes:\n"; + create_difference_report(ss); + debug() << ss.str(); + } + { TimerScope timer(L"Generate pass"); + prepare_next_assembly_pass(); constexpr bool generate_code = true; run_assembly_pass(generate_code, pass); - if (_num_errors != 0) + if (_num_errors != 0 || _oscillating_state) throw AssemblyException(L"Assembly ended with errors."); } diff --git a/jasm/assembling/assembler_impl/assembler_impl.h b/jasm/assembling/assembler_impl/assembler_impl.h --- a/jasm/assembling/assembler_impl/assembler_impl.h +++ b/jasm/assembling/assembler_impl/assembler_impl.h @@ -88,8 +88,8 @@ inline Value &get_value(bool current_pass, uint64_t combined_hash) { - ImmovableValueVector &vv = current_pass ? _current_pass_values : _previous_pass_values; - const ValueMap &vm = current_pass ? _current_pass_value_lookup : _previous_pass_value_lookup; + ImmovableValueVector &vv = current_pass ? _current_pass.values : _previous_pass.values; + const ValueMap &vm = current_pass ? _current_pass.value_lookup : _previous_pass.value_lookup; auto it = vm.find(combined_hash); assert(it != vm.end()); auto variable_index = it->second; @@ -97,8 +97,8 @@ } inline const Value &get_value(bool current_pass, uint64_t combined_hash) const { - const ImmovableValueVector &vv = current_pass ? _current_pass_values : _previous_pass_values; - const ValueMap &vm = current_pass ? _current_pass_value_lookup : _previous_pass_value_lookup; + const ImmovableValueVector &vv = current_pass ? _current_pass.values : _previous_pass.values; + const ValueMap &vm = current_pass ? _current_pass.value_lookup : _previous_pass.value_lookup; auto it = vm.find(combined_hash); assert(it != vm.end()); auto variable_index = it->second; @@ -333,14 +333,14 @@ /// 2) Generate a hash to use as a type reference (add_type_to_type_map) inline TypeDescriptionWithPayload &reserve_type(uint32_t num_properties) { uint32_t type_size = type_description_size(num_properties); - TypeDescriptionWithPayload &type = *static_cast(_current_pass_types.reserve(type_size)); + TypeDescriptionWithPayload &type = *static_cast(_current_pass.types.reserve(type_size)); memset(&type, 0, type_size); return type; } inline uint64_t add_type_to_type_map(const TypeDescription &type, TokenReadPosition position, uint64_t seed = 0) { uint64_t hash = type.hash(seed); - _current_pass_type_lookup[hash] = position; + _current_pass.type_lookup[hash] = position; return hash; } @@ -975,6 +975,12 @@ /// Log any type of error. void report_error(const SourceLocation &location, AssemblyErrorCodes error_code, const std::wstring &msg, bool fatal); + /// Create a report of the difference between current and previous pass. + void create_difference_report(std::wstringstream &ss); + + /// Move state from current pass to previous pass. + void prepare_next_assembly_pass(); + void run_assembly_pass(bool generate, int pass); bool progress_was_made(); @@ -1005,6 +1011,23 @@ /// Remove the bss sections to only leave the ones producing output. void cleanup_sections(); + using TypeMap = core::HashMap>; + using HashSet = std::set; + + struct Pass + { + Pass(uint32_t type_buffer_size) + : types(type_buffer_size) + {} + + ImmovableValueVector values; ///< Variable values in the assembly pass. + TokenChain types; ///< Type information data for the assembly pass. + TokenReader type_reader; ///< Reads the static type information. + TypeMap type_lookup; ///< Map from type hash to index for type information in 'types'. + ValueMap value_lookup; ///< Map from global namespace+symbol hash or local instance+symbol hash to value array index. + HashSet namespaces; ///< Combined hashes for pass namespaces. This is used to determine uses of undeclared namespaces. + }; + // 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. @@ -1025,27 +1048,13 @@ StringConversions _string_conversions; ///< Converts strings to platform specific formats. TokenReader _input_reader; ///< Reads the syntax input tokens. - ImmovableValueVector _current_pass_values; ///< Variable values in the current assembly pass. - ImmovableValueVector _previous_pass_values; ///< Variable values in the previous assembly pass. - TokenChain _current_pass_types; ///< Type information data for the current assembly pass. - TokenChain _previous_pass_types; ///< Type information data for the previous assembly pass. - TokenReader _current_pass_type_reader; ///< Reads the static type information. - TokenReader _previous_pass_type_reader; ///< Reads the static type information. + Pass _current_pass; + Pass _previous_pass; + bool _oscillating_state; - using TypeMap = core::HashMap>; - TypeMap _current_pass_type_lookup; ///< Map from type hash to index for type information in _current_pass_types. - TypeMap _previous_pass_type_lookup; ///< Map from type hash to index for type information in _previous_pass_types. - - ValueMap _current_pass_value_lookup; ///< Map from global namespace+symbol hash or local instance+symbol hash to value array index. - ValueMap _previous_pass_value_lookup; ///< Map from global namespace+symbol hash or local instance+symbol hash to value array index. - - using HashSet = std::set; HashSet _symbol_storage_hashes; ///< Hashes for previous symbol storage snapshots. This is used to determine loops in assembly state. uint64_t _last_pass_hash; ///< The state hash of the previous pass. This is used to determine if the state has stabilized or loops. - HashSet _previous_pass_namespaces; ///< Combined hashes for previous pass namespaces. This is used to determine uses of undeclared namespaces. - HashSet _current_pass_namespaces; ///< Combined hashes for current pass namespaces. This is used to determine uses of undeclared namespaces. - SymbolEnvironment _symbol_environment; ///< Information about the current scope. std::vector _section_mappings; ///< This contains pairs of source and target section names used in section parts to remap sections. This is searched back to front (in pairs) to get overrides to work. diff --git a/jasm/assembling/assembler_impl/symbols_impl.cpp b/jasm/assembling/assembler_impl/symbols_impl.cpp --- a/jasm/assembling/assembler_impl/symbols_impl.cpp +++ b/jasm/assembling/assembler_impl/symbols_impl.cpp @@ -320,13 +320,13 @@ void Assembler::store_symbol_value(uint64_t symbol_hash, const Value &value, bool global, bool is_address, StorageType type) { - size_t value_index = _current_pass_values.size(); - _current_pass_values.push_back(value); + size_t value_index = _current_pass.values.size(); + _current_pass.values.push_back(value); // store hash and value index - _current_pass_value_lookup.insert(symbol_hash) = value_index; + _current_pass.value_lookup.insert(symbol_hash) = value_index; - Value &new_value = _current_pass_values.back(); + Value &new_value = _current_pass.values.back(); new_value.global = global; new_value.set_contains_address(is_address); new_value.storage_type = type; @@ -338,21 +338,21 @@ bool Assembler::find_global_symbol_in_passes(uint64_t combined_hash, bool &found_in_current_pass, Value *&found_value) { - ValueMap::const_iterator it = _current_pass_value_lookup.find(combined_hash); - if (it != _current_pass_value_lookup.end()) { + ValueMap::const_iterator it = _current_pass.value_lookup.find(combined_hash); + if (it != _current_pass.value_lookup.end()) { found_in_current_pass = true; - found_value = &_current_pass_values[it->second]; + found_value = &_current_pass.values[it->second]; return true; } // Not found in current pass so we must look in the previous pass - it = _previous_pass_value_lookup.find(combined_hash); - if (it != _previous_pass_value_lookup.end()) { - const Value &previous_value = _previous_pass_values[it->second]; + it = _previous_pass.value_lookup.find(combined_hash); + if (it != _previous_pass.value_lookup.end()) { + const Value &previous_value = _previous_pass.values[it->second]; // variables can't use previous pass if (previous_value.storage_type != StorageType::Variable) { found_in_current_pass = false; - found_value = &_previous_pass_values[it->second]; + found_value = &_previous_pass.values[it->second]; return true; } } @@ -554,7 +554,7 @@ // a) another instance is matched in the previous pass const Value *value; - bool found = find_local_symbol_in_pass(symbol_hash, _current_pass_value_lookup, _current_pass_values, result_hash, value); + bool found = find_local_symbol_in_pass(symbol_hash, _current_pass.value_lookup, _current_pass.values, result_hash, value); if (found) { if (value->storage_type == StorageType::Variable) { found_in_current_pass = true; @@ -563,7 +563,7 @@ // check case a) for another instance matched in the previous pass uint64_t previous_pass_hash; const Value *previous_value; - found = find_local_symbol_in_pass(symbol_hash, _previous_pass_value_lookup, _previous_pass_values, previous_pass_hash, previous_value); + found = find_local_symbol_in_pass(symbol_hash, _previous_pass.value_lookup, _previous_pass.values, previous_pass_hash, previous_value); if (found && previous_pass_hash != result_hash) { // a) is satisfied found_in_current_pass = false; @@ -574,7 +574,7 @@ found_in_current_pass = true; return value; } - found = find_local_symbol_in_pass(symbol_hash, _previous_pass_value_lookup, _previous_pass_values, result_hash, value); + found = find_local_symbol_in_pass(symbol_hash, _previous_pass.value_lookup, _previous_pass.values, result_hash, value); if (found) { // variables can't use previous pass if (value->storage_type != StorageType::Variable) { @@ -636,16 +636,16 @@ const TypeDescriptionWithPayload &Assembler::find_type(uint64_t type_hash) const { - auto it = _current_pass_type_lookup.find(type_hash); - if (it != _current_pass_type_lookup.end()) { + auto it = _current_pass.type_lookup.find(type_hash); + if (it != _current_pass.type_lookup.end()) { // found in current pass - return _current_pass_type_reader.next_type(it->second); + return _current_pass.type_reader.next_type(it->second); } - it = _previous_pass_type_lookup.find(type_hash); - assert(it != _previous_pass_type_lookup.end()); + it = _previous_pass.type_lookup.find(type_hash); + assert(it != _previous_pass.type_lookup.end()); // found in previous pass - return _previous_pass_type_reader.next_type(it->second); + return _previous_pass.type_reader.next_type(it->second); } void Assembler::enter_variable_scope(uint64_t local_hash, bool add_loop_variable) @@ -703,7 +703,7 @@ store_namespace_string(combined_hash, _symbol_environment.namespace_names_scope_stack); // remember all namespaces to detect using statements with undefined namespaces - _current_pass_namespaces.insert(combined_hash); + _current_pass.namespaces.insert(combined_hash); return combined_hash; } @@ -801,8 +801,8 @@ // verify uniqueness bool unique = true; // check for duplicate names - ValueMap::iterator it = _current_pass_value_lookup.find(symbol_hash); - if (it != _current_pass_value_lookup.end()) { + ValueMap::iterator it = _current_pass.value_lookup.find(symbol_hash); + if (it != _current_pass.value_lookup.end()) { // The symbol already exists. This can in rare cases be valid in early // passes so we need to let it go unnoticed by skipping the declaration. // However, in the generation pass this is a fatal error. @@ -828,10 +828,10 @@ } // The symbol is unique. Create a new symbol value. - size_t value_index = _current_pass_values.size(); - _current_pass_values.emplace_back(); + size_t value_index = _current_pass.values.size(); + _current_pass.values.emplace_back(); - Value &value = _current_pass_values.back(); + Value &value = _current_pass.values.back(); value.global = global; value.storage_type = storage_type; value.owning_module = _symbol_environment.module_namespace_stack.back(); @@ -840,7 +840,7 @@ // store hash and value index if (unique) - _current_pass_value_lookup.insert(symbol_hash) = value_index; + _current_pass.value_lookup.insert(symbol_hash) = value_index; return unique; } @@ -861,10 +861,10 @@ Value &Assembler::create_combined_unique_label(uint64_t combined_hash, bool global) { // Create a new symbol - size_t value_index = _current_pass_values.size(); - _current_pass_values.emplace_back(); + size_t value_index = _current_pass.values.size(); + _current_pass.values.emplace_back(); - Value &value = _current_pass_values.back(); + Value &value = _current_pass.values.back(); value.global = global; value.storage_type = StorageType::Constant; value.owning_module = _symbol_environment.module_namespace_stack.back(); @@ -872,8 +872,8 @@ value.set_is_public(true); // store hash and value index - _current_pass_value_lookup.insert(combined_hash) = value_index; - return _current_pass_values.back(); + _current_pass.value_lookup.insert(combined_hash) = value_index; + return _current_pass.values.back(); } } // namespace jasm diff --git a/jasm/assembling/assembler_impl/syntax_impl.cpp b/jasm/assembling/assembler_impl/syntax_impl.cpp --- a/jasm/assembling/assembler_impl/syntax_impl.cpp +++ b/jasm/assembling/assembler_impl/syntax_impl.cpp @@ -444,7 +444,7 @@ if (create_label(generate, symbol_hash, global, def_token->storage_type, def_token->source_location)) { // The symbol is unique. Store evaluated expression. - Value &value = _current_pass_values.back(); + Value &value = _current_pass.values.back(); // parse and store value const Value value_or_ref = evaluate_expression(generate, t); @@ -524,7 +524,7 @@ } 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(); + 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) { @@ -692,7 +692,7 @@ } 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(); + Value &new_label = _current_pass.values.back(); set_integer(new_label, _program_counter.integer_value + argument_data_offset(i, opcode_data)); new_label.set_contains_address(true); if (export_enabled) { @@ -1009,9 +1009,9 @@ if (reserve.named) create_label(generate, reserve.name_hash, reserve.global, StorageType::Constant, reserve.source_location); // ignoring if it was unique... else - _current_pass_values.emplace_back(); // create a dummy value to simplify code below - - Value &value = _current_pass_values.back(); + _current_pass.values.emplace_back(); // create a dummy value to simplify code below + + Value &value = _current_pass.values.back(); value.set_contains_address(true); // mark as address if (export_enabled) value.set_is_public(true); @@ -1406,9 +1406,9 @@ if (define.named) create_label(generate, define.name_hash, define.global, StorageType::Constant, define.source_location); // ignoring if it was unique... else - _current_pass_values.emplace_back(); // create a dummy value to simplify code below - - Value &value = _current_pass_values.back(); + _current_pass.values.emplace_back(); // create a dummy value to simplify code below + + Value &value = _current_pass.values.back(); value.set_contains_address(true); // mark as address if (export_enabled) value.set_is_public(true); @@ -1481,7 +1481,7 @@ create_label(generate, macro.name_hash, macro.global, StorageType::Constant, macro.source_location); // ignoring if it was unique... - Value &value = _current_pass_values.back(); + Value &value = _current_pass.values.back(); value.type = ValueType::MacroReference; value.type_hash = _static_macro_reference; value.macro_chain_index = macro.chain_index; @@ -1539,8 +1539,8 @@ // create a new variable create_label(generate, loop_token.loop_value_hash, loop_token.global_value, StorageType::Variable, loop_token.value_location); // return value is ignored here since it is ok to use the dummy value - Value &loop_value = _current_pass_values.back(); - size_t new_variable_index = _current_pass_values.size() - 1; + Value &loop_value = _current_pass.values.back(); + size_t new_variable_index = _current_pass.values.size() - 1; // make a copy of the loop vector to avoid all kinds of iteration problems since the list can be // modified while iterating @@ -1575,7 +1575,7 @@ uint64_t symbol_hash = murmur_hash3_x64_64(&loop_token.loop_value_hash, sizeof(loop_token.loop_value_hash), scope_hash); if (UNLIKELY(_dump_symbols)) combine_and_store_hash_name(scope_hash, symbol_hash, variable_name(loop_token.loop_value_hash, loop_token.global_value)); - _current_pass_value_lookup[symbol_hash] = new_variable_index; + _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"); @@ -1610,13 +1610,13 @@ // create key variable create_label(generate, loop_token.loop_key_hash, loop_token.global_key, StorageType::Variable, loop_token.key_location); // return value is ignored here since it is ok to use the dummy value - Value &loop_key = _current_pass_values.back(); - size_t new_key_index = _current_pass_values.size() - 1; + Value &loop_key = _current_pass.values.back(); + size_t new_key_index = _current_pass.values.size() - 1; // create value variable create_label(generate, loop_token.loop_value_hash, loop_token.global_value, StorageType::Variable, loop_token.value_location); // return value is ignored here since it is ok to use the dummy value - Value &loop_value = _current_pass_values.back(); - size_t new_variable_index = _current_pass_values.size() - 1; + Value &loop_value = _current_pass.values.back(); + size_t new_variable_index = _current_pass.values.size() - 1; // make a copy of the loop vector to avoid all kinds of iteration problems since the map can be // modified while iterating @@ -1652,13 +1652,13 @@ uint64_t key_symbol_hash = murmur_hash3_x64_64(&loop_token.loop_key_hash, sizeof(loop_token.loop_key_hash), key_scope_hash); if (UNLIKELY(_dump_symbols)) combine_and_store_hash_name(key_scope_hash, key_symbol_hash, variable_name(loop_token.loop_key_hash, loop_token.global_key)); - _current_pass_value_lookup[key_symbol_hash] = new_key_index; + _current_pass.value_lookup[key_symbol_hash] = new_key_index; uint64_t scope_hash = loop_token.global_value ? _symbol_environment.namespace_scope_stack.back() : _symbol_environment.local_symbol_scope_stack.back(); uint64_t symbol_hash = murmur_hash3_x64_64(&loop_token.loop_value_hash, sizeof(loop_token.loop_value_hash), scope_hash); if (UNLIKELY(_dump_symbols)) combine_and_store_hash_name(scope_hash, symbol_hash, variable_name(loop_token.loop_value_hash, loop_token.global_value)); - _current_pass_value_lookup[symbol_hash] = new_variable_index; + _current_pass.value_lookup[symbol_hash] = new_variable_index; }; t = parse_scope(generate, t, early_return, inject_variable); @@ -1725,7 +1725,7 @@ // to solve the problem of generating an error when the variable is redeclared // in the loop body. A symbol link is injected in the scope below pointing to this // value. - size_t new_variable_index = _current_pass_values.size(); + size_t new_variable_index = _current_pass.values.size(); if (loop_token->has_pre_statement) { t = parse_statement(generate, t, early_return); assert(!early_return); // return not allowed in for loop pre statement @@ -1789,7 +1789,7 @@ uint64_t symbol_hash = murmur_hash3_x64_64(&loop_token->loop_variable_hash, sizeof(loop_token->loop_variable_hash), scope_hash); if (UNLIKELY(_dump_symbols)) combine_and_store_hash_name(scope_hash, symbol_hash, variable_name(loop_token->loop_variable_hash, loop_token->global)); - _current_pass_value_lookup[symbol_hash] = new_variable_index; + _current_pass.value_lookup[symbol_hash] = new_variable_index; }; t = parse_scope(generate, t, early_return, inject_variable); } else { @@ -1911,7 +1911,7 @@ t = consume_next_token(); // create a new type description - TokenReadPosition position = _current_pass_types.position(); + TokenReadPosition position = _current_pass.types.position(); TypeDescriptionWithPayload &type_desc = reserve_type(enum_def.num_definitions); type_desc.type = ValueType::EnumReference; type_desc.num_properties = enum_def.num_definitions; @@ -1983,7 +1983,7 @@ // now create a real value and assign the temporary value to it create_label(generate, enum_def.name_hash, enum_def.global, StorageType::Constant, enum_def.source_location); // ignoring if it was unique... - Value &value = _current_pass_values.back(); + Value &value = _current_pass.values.back(); value = std::move(temp_value); return t; @@ -2136,7 +2136,7 @@ // detect using missing namespace 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()) { + if (_previous_pass.namespaces.find(combined_hash) == _previous_pass.namespaces.end()) { std::wstringstream ss; ss << L"Using an undefined namespace."; report_error(using_token.source_location, AssemblyErrorCodes::UsingUndefinedNamespace, ss.str()); @@ -2211,8 +2211,8 @@ // for the, say, 10 first imports with minimal work. constexpr bool global = true; if (create_label(generate, import_hash, global, StorageType::Constant, mt.imports_location)) { - assert(_current_pass_value_lookup.has(import_combined_hash)); - Value &new_import_value = _current_pass_values[_current_pass_value_lookup[import_combined_hash]]; + assert(_current_pass.value_lookup.has(import_combined_hash)); + Value &new_import_value = _current_pass.values[_current_pass.value_lookup[import_combined_hash]]; set_unknown(new_import_value); new_import_value.set_is_module_import(true); new_import_value.set_is_public(true); @@ -2303,7 +2303,7 @@ // create the label after parsing to be able to construct the value with the size of the range create_label(generate, subroutine.name_hash, subroutine.global, StorageType::Constant, subroutine.source_location); // ignore if it was unique - Value &value = _current_pass_values.back(); + Value &value = _current_pass.values.back(); set_range(value, start_address, _program_counter.integer_value - start_address); value.set_contains_address(true); // mark as address if (export_enabled) diff --git a/jasm/docs/jasm.md b/jasm/docs/jasm.md --- a/jasm/docs/jasm.md +++ b/jasm/docs/jasm.md @@ -42,7 +42,6 @@ * [Compiling jAsm](#compiling-jasm) * [Fetching Source Code](#fetching-source-code) * [Compiling Using CMake](#compiling-using-cmake) - * [Compiling Using Code::Blocks](#compiling-using-codeblocks) * [Compiling Using Visual Studio](#compiling-using-vs) * [Starting jAsm](#starting-jasm) * [Bank Mode](#bank-mode) @@ -955,10 +954,10 @@ ## Fetching Source Code -You need to fetch the source code from BitBucket to get started. If you have a command line git client you can clone the repository like this. +You need to fetch the source code from BitBucket to get started. If you have a command line Mercurial client you can clone the repository like this. [text] - git clone https://bitbucket.org/bjonte/jasm.git jasm + hg clone ssh://hg@bitbucket.org/bjonte/jasm jAsm compiles using CMake and Clang or using Code::Blocks or Visual Studio. @@ -966,15 +965,15 @@ ## Compiling Using CMake -To build with CMake you need CMake 3.5, Clang, git and python3 installed. On Debian, Ubuntu or Mint systems you can use apt-get to fetch the dependencies like this. +To build with CMake you need CMake 3.5, Clang, Mercurial and python3 installed. On Debian, Ubuntu or Mint systems you can use apt-get to fetch the dependencies like this. [text] - sudo apt-get install cmake clang git python3 + sudo apt-get install cmake clang mercurial python3 Clone the repository into a directory called 'jasm' and build it like this. [text] - git clone https://bitbucket.org/bjonte/jasm.git jasm + hg clone ssh://hg@bitbucket.org/bjonte/jasm cd jasm export CXX=/usr/bin/clang++ mkdir build @@ -982,12 +981,6 @@ cmake -DCMAKE_BUILD_TYPE=Release .. sudo make install - -## Compiling Using Code::Blocks - - -jAsm compiles using Clang under Linux in Code::Blocks. Open the jasm.workspace file, select the release configuration for a desired processor and build. - ## Compiling Using Visual Studio diff --git a/jasm/unit_tests/results/test_unstable_variable_state.stdout b/jasm/unit_tests/results/test_unstable_variable_state.stdout --- a/jasm/unit_tests/results/test_unstable_variable_state.stdout +++ b/jasm/unit_tests/results/test_unstable_variable_state.stdout @@ -1,8 +1,7 @@ -unit_tests/test_unstable_variable_state.asm(1,1) : Error 3093 : The variable state doesn't stabilize! -This is an indication that the source code contains conflicting conditional -code. Try disabling the latest changes in conditional blocks or code referring -to conditional blocks to see what triggers this condition. Unfortunately it is +The variable state doesn't stabilize! +This may indicate that the source code contains conflicting conditional code. +Try disabling the latest changes in conditional blocks or code referring to +conditional blocks to see what triggers this condition. Unfortunately it is not possible right now to get detailed information about exactly where the problem is. - -Fatal error, aborting assembly. +Assembly ended with errors. diff --git a/jasm/version.h b/jasm/version.h --- a/jasm/version.h +++ b/jasm/version.h @@ -1,1 +1,1 @@ -1,21 +1,22 diff --git a/jasm/version.py b/jasm/version.py --- a/jasm/version.py +++ b/jasm/version.py @@ -27,26 +27,26 @@ Returns a tuple with revision (as int) and hash (as string).""" # Code for Mercurial - #hg_output = subprocess.check_output(["hg", "summary"]) - #hg_output = hg_output.decode("latin1") - #for line in hg_output.splitlines(): - # m = re.match(r"parent:\s*(\d+):([0-9a-zA-Z]+)\s+.*", line) - # if m: - # return (int(m.group(1)), m.group(2)) + hg_output = subprocess.check_output(["hg", "summary"]) + hg_output = hg_output.decode("latin1") + for line in hg_output.splitlines(): + m = re.match(r"parent:\s*(\d+):([0-9a-zA-Z]+)\s+.*", line) + if m: + return (int(m.group(1)), m.group(2)) # Code for Git - current_branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).decode("utf-8").strip() - revs_in_master = int(subprocess.check_output(["git", "rev-list", current_branch, "--count"])) - revs_in_branch = int(subprocess.check_output(["git", "rev-list", current_branch+"..", "--count"])) - if revs_in_branch == 0: - rev = revs_in_master - else: - revs_from_branch_to_master = int(subprocess.check_output(["git", "rev-list", current_branch+"...", "--count"])) - revs_to_branch = revs_in_master - (revs_from_branch_to_master - revs_in_branch) - rev = revs_to_branch + revs_in_branch - - hsh = subprocess.check_output(["git", "rev-parse", "HEAD"]).strip().decode('utf-8-sig') - return (rev, hsh) + #current_branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).decode("utf-8").strip() + #revs_in_master = int(subprocess.check_output(["git", "rev-list", current_branch, "--count"])) + #revs_in_branch = int(subprocess.check_output(["git", "rev-list", current_branch+"..", "--count"])) + #if revs_in_branch == 0: + # rev = revs_in_master + #else: + # revs_from_branch_to_master = int(subprocess.check_output(["git", "rev-list", current_branch+"...", "--count"])) + # revs_to_branch = revs_in_master - (revs_from_branch_to_master - revs_in_branch) + # rev = revs_to_branch + revs_in_branch + # + #hsh = subprocess.check_output(["git", "rev-parse", "HEAD"]).strip().decode('utf-8-sig') + #return (rev, hsh) def update_revision(): """Get source code revision and update revision and hash files.""" diff --git a/jasm/website/site/docs/index.html b/jasm/website/site/docs/index.html --- a/jasm/website/site/docs/index.html +++ b/jasm/website/site/docs/index.html @@ -59,7 +59,6 @@
  • Starting jAsm @@ -1030,9 +1029,9 @@

    -

    You need to fetch the source code from BitBucket to get started. If you have a command line git client you can clone the repository like this.

    - -
    git clone https://bitbucket.org/bjonte/jasm.git jasm
    +

    You need to fetch the source code from BitBucket to get started. If you have a command line Mercurial client you can clone the repository like this.

    + +
    hg clone ssh://hg@bitbucket.org/bjonte/jasm
     

    jAsm compiles using CMake and Clang or using Code::Blocks or Visual Studio.

    @@ -1043,14 +1042,14 @@

    -

    To build with CMake you need CMake 3.5, Clang, git and python3 installed. On Debian, Ubuntu or Mint systems you can use apt-get to fetch the dependencies like this.

    - -
    sudo apt-get install cmake clang git python3
    +

    To build with CMake you need CMake 3.5, Clang, Mercurial and python3 installed. On Debian, Ubuntu or Mint systems you can use apt-get to fetch the dependencies like this.

    + +
    sudo apt-get install cmake clang mercurial python3
     

    Clone the repository into a directory called 'jasm' and build it like this.

    -
    git clone https://bitbucket.org/bjonte/jasm.git jasm
    +
    hg clone ssh://hg@bitbucket.org/bjonte/jasm
     cd jasm
     export CXX=/usr/bin/clang++
     mkdir build
    @@ -1059,14 +1058,6 @@
     sudo make install
     
    -

    - -

    Compiling Using Code::Blocks

    - -

    - -

    jAsm compiles using Clang under Linux in Code::Blocks. Open the jasm.workspace file, select the release configuration for a desired processor and build.

    -

    Compiling Using Visual Studio

    diff --git a/jasm/website/site/index.html b/jasm/website/site/index.html --- a/jasm/website/site/index.html +++ b/jasm/website/site/index.html @@ -81,7 +81,7 @@

    Windows binaries requires the C++ Redistributable for VS2015 to be installed.

    The Source

    @@ -97,6 +97,14 @@

    • + 1.22 +
        +
      • Symbol difference dump added at debug verbosity when an oscillating state occurs. Also the generation pass is run to give more error information if that happens.
      • +
      • Removed CodeBlocks project in favor of KDevelop.
      • +
      • Migrated from Git to Mercurial.
      • +
      +
    • +
    • 1.21
      • Fixed broken instruction data labels on Z80.