M jasm/assemble/assembler_impl/assembler_impl.cpp +30 -15
@@ 518,22 518,33 @@ void Assembler::report_warning(const Sou
void Assembler::report_error(const SourceLocation &location, AssemblyErrorCodes error_code, const std::string &msg, bool fatal)
{
+ // print previous potential warnings to indicate missing files in case the error is related to that
+ if (fatal) {
+ for(const ErrorInfo &info : _potential_warnings) {
+ warning() << _used_files[info.error_location.file_index] << "(" << info.error_location.row << "," << info.error_location.column << ") : Warning " << static_cast<unsigned>(info.error_code) << " : " << info.error_message << '\n';
+ }
+ }
+
// avoid reporting same error/location again
- if (!fatal && _reported_error_locations.find(location) != _reported_error_locations.end())
+ if (!fatal && _reported_error_locations.find(location) != _reported_error_locations.end()) {
return;
+ }
_reported_error_locations.insert(location);
error() << _used_files[location.file_index] << "(" << location.row << "," << location.column << ") : Error " << static_cast<unsigned>(error_code) << " : " << msg << '\n';
// print previous macro invocation locations backwards from the stack
- for(auto it = _location_stack.crbegin(); it != _location_stack.crend(); ++it)
+ for(auto it = _location_stack.crbegin(); it != _location_stack.crend(); ++it) {
error() << _used_files[it->file_index] << "(" << it->row << "," << it->column << ") : Invoked from here\n";
+ }
++_num_errors;
- if (fatal)
+ if (fatal) {
throw AssemblyException("Fatal error, aborting assembly.");
- if (_num_errors >= _max_errors)
+ }
+ if (_num_errors >= _max_errors) {
throw AssemblyException("Too many errors, aborting assembly.");
+ }
}
void propagate_data(Section &parent)
@@ 594,6 605,8 @@ void Assembler::run_assembly_pass(bool g
_processor = _catalogue.processor(_processor_type);
_processor_stack.clear();
_processor_stack.push_back(_processor_type);
+
+ _potential_warnings.clear();
// reset scopes since we may place things directly inside the global scope
// and these things will not be reset otherwise
@@ 647,9 660,11 @@ void Assembler::parse_file(bool generate
const SyntaxResult &syntax_result = _syntax_results[file_index];
- if (syntax_result.error_code != AssemblyErrorCodes::Ok) {
+ if (syntax_result.error_info.error_code != AssemblyErrorCodes::Ok) {
if (generate) {
- report_error(syntax_result.error_location, syntax_result.error_code, syntax_result.error_message);
+ report_error(syntax_result.error_info.error_location, syntax_result.error_info.error_code, syntax_result.error_info.error_message);
+ } else {
+ _potential_warnings.push_back(syntax_result.error_info);
}
return;
}
@@ 710,23 725,23 @@ size_t Assembler::syntax_analyze(const s
SyntaxResult result;
result.file_id = fid;
- result.error_code = AssemblyErrorCodes::CantFindIncludeFile;
+ result.error_info.error_code = AssemblyErrorCodes::CantFindIncludeFile;
result.token_chain_index = 0;
std::stringstream ss;
ss << "Failed to open '" << filename << "'";
- result.error_message = ss.str();
+ result.error_info.error_message = ss.str();
if (include_location == nullptr) {
// this is the main file
- result.error_location.file_index = static_cast<uint32_t>(file_index);
- result.error_location.column = 1;
- result.error_location.row = 1;
+ result.error_info.error_location.file_index = static_cast<uint32_t>(file_index);
+ result.error_info.error_location.column = 1;
+ result.error_info.error_location.row = 1;
} else {
// we came from an include statement
- result.error_location.file_index = include_location->file_index;
- result.error_location.column = include_location->column;
- result.error_location.row = include_location->row;
+ result.error_info.error_location.file_index = include_location->file_index;
+ result.error_info.error_location.column = include_location->column;
+ result.error_info.error_location.row = include_location->row;
}
_syntax_results.emplace_back(std::move(result));
return file_index;
@@ 749,7 764,7 @@ size_t Assembler::syntax_analyze(const s
}
SyntaxResult &syntax_result = _syntax_results.back();
syntax_result.file_id = fid;
- syntax_result.error_code = AssemblyErrorCodes::Ok;
+ syntax_result.error_info.error_code = AssemblyErrorCodes::Ok;
syntax_result.token_chain_index = _input.size();
// tokenize
M jasm/assemble/assembler_impl/assembler_impl.h +13 -6
@@ 1095,17 1095,23 @@ private:
/// Cache with map from path to index into _used_files and _syntax_results.
core::HashMap<std::string, size_t, core::StringHashFunctor> _file_to_index;
+
+ struct ErrorInfo
+ {
+ /// Error code, or 0 if syntax analysis was successful.
+ AssemblyErrorCodes error_code;
+ /// Location of error, if any.
+ SourceLocation error_location;
+ /// Empty if no error occurred and the message in case there was a problem with loading, tokenizing or syntax analysis.
+ std::string error_message;
+ };
struct SyntaxResult
{
/// ID of file to be able to find same files with different names.
core::FileId file_id;
- /// Error code, or 0 if syntax analysis was successful.
- AssemblyErrorCodes error_code;
- /// Empty if no error occurred and the message in case there was a problem with loading, tokenizing or syntax analysis.
- std::string error_message;
- /// Location of error, if any.
- SourceLocation error_location;
+ /// Location and message.
+ ErrorInfo error_info;
/// Token chain where the syntax output is stored.
size_t token_chain_index;
};
@@ 1189,6 1195,7 @@ private:
Value _return_value; ///< Return value from macro, stored while the scopes unwind.
+ std::vector<ErrorInfo> _potential_warnings; ///< Warnings to issue if assembling is aborted before the generation pass. This helps printing warnings about missing files.
std::set<SourceLocation> _reported_error_locations; ///< Keep track of reported error positions to avoid duplicated errors in a loop construction.
int32_t _num_errors; ///< Errors encountered in the generation pass so far.
M jasm/assemble/assembler_impl/symbols_impl.cpp +5 -1
@@ 323,7 323,11 @@ bool Assembler::parse_symbol_string(cons
std::wstring wide_symbol = core::utf8_to_wide(symbol);
using MaskType = std::ctype<wchar_t>::mask;
- std::locale locale("en_US.utf8");
+ #if defined(_WIN32)
+ std::locale locale("C");
+ #else
+ std::locale locale("en_US.utf8");
+ #endif
const std::ctype<wchar_t> &facet(std::use_facet<std::ctype<wchar_t>>(locale));
// determine character types
M jasm/docs/jasm.md +2 -2
@@ 1698,7 1698,7 @@ jAsm supports a number of operators, sim
<table>
<tr><th>Operator</th><th>Type</th><th>Types</th><th>Example</th></tr>
- <tr><td><code>[6502]|()</code></td><td>call operator</td><td>macro</td><td><code>[6502]|mac(aa,bb)</code></td></tr>
+ <tr><td><code>[6502]|()</code></td><td>call operator</td><td>macro, subroutine</td><td><code>[6502]|mac(aa,bb)</code></td></tr>
<tr><td><code>[6502]|[]</code></td><td>array indexing operator</td><td>string, list</td><td><code>[6502]|aa[3]</code></td></tr>
<tr><td><code>[6502]|.</code></td><td>property operator</td><td>string, list, map</td><td><code>[6502]|aa.length</code></td></tr>
<tr><td><code>[6502]|++</code></td><td>postfix increment</td><td>integer</td><td><code>[6502]|aa++</code></td></tr>
@@ 1734,7 1734,7 @@ jAsm supports a number of operators, sim
<tr><td><code>[6502]|*=</code></td><td>multiply and assign</td><td>integer, float</td><td><code>[6502]|aa *= 2</code></td></tr>
<tr><td><code>[6502]|/=</code></td><td>divide and assign</td><td>integer, float</td><td><code>[6502]|aa /= 2</code></td></tr>
<tr><td><code>[6502]|&&=</code></td><td>boolean and, and assign</td><td>boolean</td><td><code>[6502]|aa &&= bb</code></td></tr>
- <tr><td><code>[6502]|||=</code></td><td>boolean or and assign</td><td>boolean</td><td><code>[6502]|aa ||= bb</code></td></tr>
+ <tr><td><code>[6502]|||=</code></td><td>boolean or, and assign</td><td>boolean</td><td><code>[6502]|aa ||= bb</code></td></tr>
<tr><td><code>[6502]|&=</code></td><td>bitwise and, and assign</td><td>integer</td><td><code>[6502]|aa &= bb</code></td></tr>
<tr><td><code>[6502]||=</code></td><td>bitwise or, and assign</td><td>integer</td><td><code>[6502]|aa |= bb</code></td></tr>
<tr><td><code>[6502]|^=</code></td><td>bitwise exclusive or, and assign</td><td>integer</td><td><code>[6502]|aa ^= bb</code></td></tr>
M jasm/exceptions/error_codes.h +2 -1
@@ 26,7 26,7 @@ enum class AssemblyErrorCodes
Unused1, // not used!
IllegalCharacterInBinaryConstant,
IllegalCharacterInHexConstant,
- CantFindIncludeFile,
+ Unused2, // not used!
UnmatchedProcessorPop,
InvalidProcessorName,
ExpectedProcessorNameOrPop,
@@ 203,6 203,7 @@ enum class AssemblyErrorCodes
UseOfPseudoInstructionInStandardMode,
ExpectedPathString,
RecursiveIncludes,
+ CantFindIncludeFile,
// assembler warnings
SubroutineFallthrough = 3500,
M jasm/strings/string_locale.cpp +9 -3
@@ 15,9 15,15 @@ const std::string_view StringLocale::_na
std::string_view("swedish"),
};
const std::string_view StringLocale::_locales[static_cast<size_t>(StringLocale::Locale::NumLocales)] = {
- std::string_view(""),
- std::string_view("en_US.utf8"),
- std::string_view("sv_SE.utf8"),
+ #if defined(_WIN32)
+ std::string_view(""),
+ std::string_view("C"),
+ std::string_view("C"),
+ #else
+ std::string_view(""),
+ std::string_view("en_US.utf8"),
+ std::string_view("sv_SE.utf8"),
+ #endif
};
bool StringLocale::is_locale(const std::string_view &name, Locale &locale)
M jasm/tokenize/tokenizer.cpp +6 -2
@@ 64,8 64,12 @@ void Tokenizer::tokenize(uint32_t file_i
// make the mask array as big as the source including null termination
char_masks.resize(wide_contents.size() + 1);
// generate character classification from locale
- std::locale loc("en_US.utf8");
- std::use_facet<std::ctype<wchar_t>>(loc).is(wide_contents.data(), wide_contents.data() + wide_contents.size(), char_masks.data());
+ #if defined(_WIN32)
+ std::locale locale("C");
+ #else
+ std::locale locale("en_US.utf8");
+ #endif
+ std::use_facet<std::ctype<wchar_t>>(locale).is(wide_contents.data(), wide_contents.data() + wide_contents.size(), char_masks.data());
// categorize the null termination as "whitespace" to simplify parsing.
char_masks[wide_contents.size()] =
#if defined(_MSC_VER)
A => jasm/unit_tests/results/test_include_missing_file_becomes_warning_in_fatal_errors.stdout +3 -0
@@ 0,0 1,3 @@
+unit_tests/test_include_missing_file_becomes_warning_in_fatal_errors.asm(7,9) : Warning 3112 : Failed to open 'missing_file'
+unit_tests/test_include_missing_file_becomes_warning_in_fatal_errors.asm(9,1) : Error 3054 : Section part 'add' mapped to 'add' must refer to a previously defined section.
+Fatal error, aborting assembly.
M jasm/unit_tests/results/test_missing_include_file_error.stdout +1 -1
@@ 1,2 1,2 @@
-unit_tests/test_missing_include_file_error.asm(2,9) : Error 1011 : Failed to open 'missing.asm'
+unit_tests/test_missing_include_file_error.asm(2,9) : Error 3112 : Failed to open 'missing.asm'
Assembly ended with errors.
A => jasm/unit_tests/test_include_missing_file_becomes_warning_in_fatal_errors.asm +12 -0
@@ 0,0 1,12 @@
+// assembler command line arguments: 6502 [-v2]
+
+section code, "main", 0
+{
+}
+
+include "missing_file" // this could potentially have defined the 'add' section
+
+section part, "add"
+{
+ rts
+}
No newline at end of file
M jasm/version.h +1 -1
@@ 1,1 1,1 @@
-1,25
+1,26
M jasm/website/site/docs/index.html +9 -9
@@ 82,8 82,8 @@
</ul></li>
<li><a href="#language-reference">Language Reference</a>
<ul>
+<li><a href="#input-format">Input Format</a></li>
<li><a href="#selecting-processor">Selecting Processor</a></li>
-<li><a href="#input-format">Input Format</a></li>
<li><a href="#comments">Comments</a></li>
<li><a href="#assembler-instruction-syntax">Assembler Instruction Syntax</a></li>
<li><a href="#constants">Constants</a></li>
@@ 1331,6 1331,12 @@ jasm --define DEFAULT_NAME=bobo input.ja
<p>This section documents the entire syntax. Have a look at the starter guide first to get a grasp of the basics before digging into this.</p>
+<div id="input-format"></div>
+
+<h2>Input Format</h2>
+
+<p>jAsm uses Unicode utf-8 encoded text files only. If you provide something that can't be interpreted as utf-8, an error will be returned.</p>
+
<div id="selecting-processor"></div>
<p>To assemble instructions jAsm needs to know what processor to target. This is done by either specifying the processor using <a href="#default-processor">command line flags</a> or by a keyword in the source code. Specify the processor in a source file like this.</p>
@@ 1380,12 1386,6 @@ rts
<p>When including <code>test.jasm</code>, the <code><span class="instruction">rts</span></code> instruction is assembled using 6502 because it was inherited from <code>main.jasm</code>. The <code><span class="instruction">ret</span></code> instruction is assembled as z80 since the processor was changed in the included file before the instruction. After the included file the processor is 6502 since the included file won't affect the file it is included from.</p>
-<div id="input-format"></div>
-
-<h2>Input Format</h2>
-
-<p>jAsm uses Unicode utf-8 encoded text files only. If you provide something that can't be interpreted as utf-8, an error will be returned.</p>
-
<div id="comments"></div>
<h2>Comments</h2>
@@ 1784,7 1784,7 @@ aa <span class="operator">=</span> bb <s
<table>
<tr><th>Operator</th><th>Type</th><th>Types</th><th>Example</th></tr>
- <tr><td><code><span class="special">(</span><span class="special">)</span></code></td><td>call operator</td><td>macro</td><td><code>mac<span class="special">(</span>aa,bb<span class="special">)</span></code></td></tr>
+ <tr><td><code><span class="special">(</span><span class="special">)</span></code></td><td>call operator</td><td>macro, subroutine</td><td><code>mac<span class="special">(</span>aa,bb<span class="special">)</span></code></td></tr>
<tr><td><code><span class="special">[</span><span class="special">]</span></code></td><td>array indexing operator</td><td>string, list</td><td><code>aa<span class="special">[</span><span class="literal">3</span><span class="special">]</span></code></td></tr>
<tr><td><code>.</code></td><td>property operator</td><td>string, list, map</td><td><code>aa.length</code></td></tr>
<tr><td><code><span class="operator">++</span></code></td><td>postfix increment</td><td>integer</td><td><code>aa<span class="operator">++</span></code></td></tr>
@@ 1820,7 1820,7 @@ aa <span class="operator">=</span> bb <s
<tr><td><code><span class="operator">*=</span></code></td><td>multiply and assign</td><td>integer, float</td><td><code>aa <span class="operator">*=</span> <span class="literal">2</span></code></td></tr>
<tr><td><code><span class="operator">/=</span></code></td><td>divide and assign</td><td>integer, float</td><td><code>aa <span class="operator">/=</span> <span class="literal">2</span></code></td></tr>
<tr><td><code><span class="operator">&&=</span></code></td><td>boolean and, and assign</td><td>boolean</td><td><code>aa <span class="operator">&&=</span> bb</code></td></tr>
- <tr><td><code><span class="operator">||=</span></code></td><td>boolean or and assign</td><td>boolean</td><td><code>aa <span class="operator">||=</span> bb</code></td></tr>
+ <tr><td><code><span class="operator">||=</span></code></td><td>boolean or, and assign</td><td>boolean</td><td><code>aa <span class="operator">||=</span> bb</code></td></tr>
<tr><td><code><span class="operator">&=</span></code></td><td>bitwise and, and assign</td><td>integer</td><td><code>aa <span class="operator">&=</span> bb</code></td></tr>
<tr><td><code><span class="operator">|=</span></code></td><td>bitwise or, and assign</td><td>integer</td><td><code>aa <span class="operator">|=</span> bb</code></td></tr>
<tr><td><code><span class="operator">^=</span></code></td><td>bitwise exclusive or, and assign</td><td>integer</td><td><code>aa <span class="operator">^=</span> bb</code></td></tr>
M jasm/website/site/index.html +9 -2
@@ 81,10 81,10 @@
<h1>The Binaries</h1>
<ul>
<li>
- <a href="binaries/jasm_1.25_linux64.7z">jAsm 1.25 for 64-bit Linux</a>
+ <a href="binaries/jasm_1.26_linux64.7z">jAsm 1.26 for 64-bit Linux</a>
</li>
<li>
- <a href="binaries/jasm_1.25_win64.7z">jAsm 1.25 for 64-bit Windows</a>
+ <a href="binaries/jasm_1.26_win64.7z">jAsm 1.26 for 64-bit Windows</a>
</li>
</ul>
<h1>The Source</h1>
@@ 99,6 99,13 @@
<h1>Version History</h1>
<ul>
<li>
+ 1.26
+ <ul>
+ <li>Locale support was broken in v1.25. This is now reverted to the C locale in Windows.</li>
+ <li>Missing files are printed as warnings if errors are detected during tokenizing or syntax analysis to avoid confusing errors.</li>
+ </ul>
+ </li>
+ <li>
1.25
<ul>
<li>Fixed a serious memory overwrite bug when multibyte characters are used in the source code.</li>