# 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.