M .hgignore +1 -0
@@ 20,3 20,4 @@ hasher/bin/**/*
jasm/bin/**/*
jasm/output.bin
jasm/test.asm
+build/**/*
A => .kdev4/jasm.kdev4 +69 -0
@@ 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
M README.md +3 -3
@@ 4,13 4,13 @@ jAsm currently compiles with CMake for L
# 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
A => jasm.kdev4 +4 -0
@@ 0,0 1,4 @@
+[Project]
+CreatedFrom=CMakeLists.txt
+Manager=KDevCMakeManager
+Name=jasm
M jasm.sublime-project +1 -1
@@ 26,7 26,7 @@
[
{
"name": "Make",
- "cmd": [ "make" ],
+ "cmd": [ "make", "-j4" ],
"working_dir": "${project_path}/build",
"file_regex": "^(.+):(\\d+):(\\d+):\\s+\\w+:\\s+(.*)$"
},
R jasm.workspace => +0 -12
@@ 1,12 0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-<CodeBlocks_workspace_file>
- <Workspace title="Workspace">
- <Project filename="core/core.cbp" />
- <Project filename="jasm/jasm.cbp">
- <Depends filename="core/core.cbp" />
- </Project>
- <Project filename="hasher/hasher.cbp">
- <Depends filename="core/core.cbp" />
- </Project>
- </Workspace>
-</CodeBlocks_workspace_file>
No newline at end of file
M jasm/assembling/assembler_impl/assembler_impl.cpp +188 -78
@@ 40,8 40,9 @@ Assembler::Assembler(bool multiple_outpu
, _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 @@ Assembler::Assembler(bool multiple_outpu
// 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::fill_type_array_operator
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 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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<uint32_t>(StringProperties::NumProperties);
TypeDescriptionWithPayload &type = reserve_type(num_properties);
type.type = ValueType::StringValue;
@@ 212,7 212,7 @@ void Assembler::setup_fundamental_types(
_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<uint32_t>(StringProperties::NumProperties);
TypeDescriptionWithPayload &type = reserve_type(num_properties);
type.type = ValueType::StringReference;
@@ 231,7 231,7 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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<uint32_t>(ListProperties::NumProperties);
TypeDescriptionWithPayload &type = reserve_type(num_properties);
type.type = ValueType::ListReference;
@@ 345,7 345,7 @@ void Assembler::setup_fundamental_types(
_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 @@ void Assembler::setup_fundamental_types(
_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<uint32_t>(MapProperties::NumProperties);
TypeDescriptionWithPayload &type = reserve_type(num_properties);
type.type = ValueType::MapReference;
@@ 375,7 375,7 @@ uint64_t Assembler::add_array_type_descr
{
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 @@ void Assembler::setup_predefined_constan
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 @@ void Assembler::setup_predefined_constan
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 @@ void Assembler::setup_predefined_constan
_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 @@ void Assembler::propagate_children_data_
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 @@ void Assembler::run_assembly_pass(bool g
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 @@ void Assembler::run_assembly_pass(bool g
// 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 *>();
+ void *&null_padding = _current_pass.types.reserve<void *>();
null_padding = nullptr;
// constants uses fundamental types so the order matters
@@ 579,25 601,6 @@ void Assembler::run_assembly_pass(bool g
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 @@ Section *Assembler::find_section(uint64_
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 @@ bool Assembler::progress_was_made()
// 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 @@ struct SymbolInformation
, 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 @@ struct SymbolInformation
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<SymbolInformation> symbol_list;
+ symbol_list.reserve(_current_pass.value_lookup.size() + 100);
+
+ // find symbols in either pass
+ core::HashMap<uint64_t, bool, core::NullHashCompare<uint64_t>> used_symbols;
+ std::wstring no_name = L"<no name>";
+ for(const auto &pair : _current_pass.value_lookup) {
+ uint64_t hash = pair.first;
+ size_t value_index = pair.second;
+ const Value &value = _current_pass.values[value_index];
+ auto it = _symbol_names.find(hash);
+ const std::wstring &symbol_name = it == _symbol_names.end() ? no_name : it->second;
+ 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"<missing>" << 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"<missing>" << 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<SymbolInformation> 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"<no name>" : it->second, to_string(_strings, value), value.storage_type != StorageType::Variable, value.type);
}
@@ 791,16 884,16 @@ void Assembler::dump_vice_symbols(const
std::set<uint32_t> breakpoints;
std::set<uint32_t> r_breakpoints;
std::set<uint32_t> 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 @@ void Assembler::dump_gba_symbols(const s
{
// extract all relevant symbol information
std::vector<SimpleSymbolInformation> 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 @@ void Assembler::assemble()
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 @@ void Assembler::assemble()
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.");
}
M jasm/assembling/assembler_impl/assembler_impl.h +32 -23
@@ 88,8 88,8 @@ private:
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 @@ private:
}
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 @@ private:
/// 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<TypeDescriptionWithPayload *>(_current_pass_types.reserve(type_size));
+ TypeDescriptionWithPayload &type = *static_cast<TypeDescriptionWithPayload *>(_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 @@ private:
/// 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 @@ private:
/// Remove the bss sections to only leave the ones producing output.
void cleanup_sections();
+ using TypeMap = core::HashMap<uint64_t, TokenReadPosition, core::NullHashCompare<uint64_t>>;
+ using HashSet = std::set<uint64_t>;
+
+ 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 @@ private:
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<uint64_t, TokenReadPosition, core::NullHashCompare<uint64_t>>;
- 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<uint64_t>;
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<uint64_t> _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.
M jasm/assembling/assembler_impl/symbols_impl.cpp +32 -32
@@ 320,13 320,13 @@ void Assembler::store_symbol_string_in_r
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 @@ void Assembler::store_symbol_value(uint6
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 @@ const Value *Assembler::find_local_symbo
// 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 @@ const Value *Assembler::find_local_symbo
// 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 @@ const Value *Assembler::find_local_symbo
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 @@ void Assembler::evaluate_symbol(bool gen
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<TypeDescriptionWithPayload>(it->second);
+ return _current_pass.type_reader.next_type<TypeDescriptionWithPayload>(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<TypeDescriptionWithPayload>(it->second);
+ return _previous_pass.type_reader.next_type<TypeDescriptionWithPayload>(it->second);
}
void Assembler::enter_variable_scope(uint64_t local_hash, bool add_loop_variable)
@@ 703,7 703,7 @@ uint64_t Assembler::enter_namespace(uint
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 @@ bool Assembler::create_label(bool genera
// 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 @@ bool Assembler::create_label(bool genera
}
// 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 @@ bool Assembler::create_label(bool genera
// 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_unique_label(ui
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 &Assembler::create_combined_unique
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
M jasm/assembling/assembler_impl/syntax_impl.cpp +27 -27
@@ 444,7 444,7 @@ const SyntaxToken *Assembler::parse_decl
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 @@ const SyntaxToken *Assembler::parse_inst
}
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 @@ const SyntaxToken *Assembler::parse_inst
}
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 @@ const SyntaxToken *Assembler::parse_rese
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 @@ const SyntaxToken *Assembler::parse_defi
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 @@ const SyntaxToken *Assembler::parse_macr
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 @@ const SyntaxToken *Assembler::parse_rang
// 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 @@ const SyntaxToken *Assembler::parse_rang
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 @@ const SyntaxToken *Assembler::parse_rang
// 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 @@ const SyntaxToken *Assembler::parse_rang
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 @@ const SyntaxToken *Assembler::parse_for_
// 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 @@ const SyntaxToken *Assembler::parse_for_
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 @@ const SyntaxToken *Assembler::parse_enum
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 @@ const SyntaxToken *Assembler::parse_enum
// 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 @@ const SyntaxToken *Assembler::parse_usin
// 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 @@ const SyntaxToken *Assembler::parse_modu
// 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 @@ const SyntaxToken *Assembler::parse_subr
// 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)
M jasm/docs/jasm.md +5 -12
@@ 42,7 42,6 @@ This documentation covers the language a
* [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 @@ Now you know the basics of jAsm and shou
## Fetching Source Code
</a>
-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 @@ jAsm compiles using CMake and Clang or u
## Compiling Using CMake
</a>
-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 @@ Clone the repository into a directory ca
cmake -DCMAKE_BUILD_TYPE=Release ..
sudo make install
-<a name="compiling-using-codeblocks">
-## Compiling Using Code::Blocks
-</a>
-
-jAsm compiles using Clang under Linux in Code::Blocks. Open the jasm.workspace file, select the release configuration for a desired processor and build.
-
<a name="compiling-using-vs">
## Compiling Using Visual Studio
</a>
M jasm/unit_tests/results/test_unstable_variable_state.stdout +5 -6
@@ 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.
M jasm/version.h +1 -1
@@ 1,1 1,1 @@
-1,21
+1,22
M jasm/version.py +18 -18
@@ 27,26 27,26 @@ def source_revision():
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."""
M jasm/website/site/docs/index.html +7 -16
@@ 59,7 59,6 @@
<ul>
<li><a href="#fetching-source-code">Fetching Source Code</a></li>
<li><a href="#compiling-using-cmake">Compiling Using CMake</a></li>
-<li><a href="#compiling-using-codeblocks">Compiling Using Code::Blocks</a></li>
<li><a href="#compiling-using-vs">Compiling Using Visual Studio</a></li>
</ul></li>
<li><a href="#starting-jasm">Starting jAsm</a>
@@ 1030,9 1029,9 @@ main.jasm(25,7) : Error 3004 : Reference
<p></a></p>
-<p>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.</p>
-
-<pre><code>git clone https://bitbucket.org/bjonte/jasm.git jasm
+<p>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.</p>
+
+<pre><code>hg clone ssh://hg@bitbucket.org/bjonte/jasm
</code></pre>
<p>jAsm compiles using CMake and Clang or using Code::Blocks or Visual Studio.</p>
@@ 1043,14 1042,14 @@ main.jasm(25,7) : Error 3004 : Reference
<p></a></p>
-<p>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.</p>
-
-<pre><code>sudo apt-get install cmake clang git python3
+<p>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.</p>
+
+<pre><code>sudo apt-get install cmake clang mercurial python3
</code></pre>
<p>Clone the repository into a directory called 'jasm' and build it like this.</p>
-<pre><code>git clone https://bitbucket.org/bjonte/jasm.git jasm
+<pre><code>hg clone ssh://hg@bitbucket.org/bjonte/jasm
cd jasm
export CXX=/usr/bin/clang++
mkdir build
@@ 1059,14 1058,6 @@ cmake -DCMAKE_BUILD_TYPE=Release ..
sudo make install
</code></pre>
-<p><a name="compiling-using-codeblocks"></p>
-
-<h2>Compiling Using Code::Blocks</h2>
-
-<p></a></p>
-
-<p>jAsm compiles using Clang under Linux in Code::Blocks. Open the jasm.workspace file, select the release configuration for a desired processor and build.</p>
-
<p><a name="compiling-using-vs"></p>
<h2>Compiling Using Visual Studio</h2>
M jasm/website/site/index.html +9 -1
@@ 81,7 81,7 @@
<p>
Windows binaries requires the <a href="http://www.microsoft.com/en-us/download/details.aspx?id=48145">C++ Redistributable for VS2015</a> to be installed.
<ul>
- <li><a href="binaries/jasm_1.21_win64.7z">jAsm 1.21 for 64-bit Windows</a></li>
+ <li><a href="binaries/jasm_1.22_win64.7z">jAsm 1.22 for 64-bit Windows</a></li>
</ul>
</p>
<h1>The Source</h1>
@@ 97,6 97,14 @@
<p>
<ul>
<li>
+ 1.22
+ <ul>
+ <li>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.</li>
+ <li>Removed CodeBlocks project in favor of KDevelop.</li>
+ <li>Migrated from Git to Mercurial.</li>
+ </ul>
+ </li>
+ <li>
1.21
<ul>
<li>Fixed broken instruction data labels on Z80.</li>