1 |
58 |
Agner |
/**************************** error.cpp **********************************
|
2 |
|
|
* Author: Agner Fog
|
3 |
|
|
* Date created: 2017-11-03
|
4 |
|
|
* Last modified: 2021-03-30
|
5 |
|
|
* Version: 1.11
|
6 |
|
|
* Project: Binary tools for ForwardCom instruction set
|
7 |
|
|
* Module: error.cpp
|
8 |
|
|
* Description:
|
9 |
|
|
* Standard procedure for error reporting to stderr
|
10 |
|
|
*
|
11 |
|
|
* Copyright 2006-2021 GNU General Public License http://www.gnu.org/licenses
|
12 |
|
|
******************************************************************************
|
13 |
|
|
|
14 |
|
|
You may set breakpoints here to trace errors (use stack trace)
|
15 |
|
|
|
16 |
|
|
Runtime errors during emulation are not going here, but to
|
17 |
|
|
CThread::interrupt in emulator6.cpp
|
18 |
|
|
|
19 |
|
|
*****************************************************************************/
|
20 |
|
|
|
21 |
|
|
#include "stdafx.h"
|
22 |
|
|
|
23 |
|
|
// Make and initialize error reporter object
|
24 |
|
|
CErrorReporter err;
|
25 |
|
|
|
26 |
|
|
// General error messages
|
27 |
|
|
|
28 |
|
|
// to do: remove unused error messages!
|
29 |
|
|
|
30 |
|
|
SErrorText errorTexts[] = {
|
31 |
|
|
// Unknown error
|
32 |
|
|
{0, 2, "Unknown error!"},
|
33 |
|
|
|
34 |
|
|
// Warning messages
|
35 |
|
|
{ERR_EMPTY_OPTION, 1, "Empty command line option"},
|
36 |
|
|
{ERR_UNKNOWN_OPTION, 2, "Unknown command line option: %s"},
|
37 |
|
|
{ERR_UNKNOWN_ERROR_NUM, 1, "Unknown warning/error number: %i"},
|
38 |
|
|
{ERR_OUTFILE_IGNORED, 1, "Output file name ignored"},
|
39 |
|
|
{ERR_MEMBER_NOT_FOUND_EXTRACT, 1, "Library member %s not found. Extraction failed"},
|
40 |
|
|
{ERR_MEMBER_NOT_FOUND_DEL, 1, "Library member %s not found. Deletion failed"},
|
41 |
|
|
{ERR_DUPLICATE_NAME_COMMANDL, 1, "Library member %s specified more than once"}, // duplicate name on command line
|
42 |
|
|
{ERR_DUPLICATE_NAME_IN_LIB, 1, "Library has more than one members named %s"}, // duplicate name in library
|
43 |
|
|
{ERR_DUPLICATE_SYMBOL_IN_LIB, 1, "More than one symbol named %s in modules %s"}, // duplicate symbol in library
|
44 |
|
|
{ERR_NO_SYMTAB_IN_LIB, 2, "No ForwardCom symbol table found in library"}, // probably wrong library type
|
45 |
|
|
{ERR_ABS_RELOCATION_WARN, 1, "Code at line %i is position dependent because it contains absolute address of symbol: %s"}, // warn if absolute address
|
46 |
|
|
|
47 |
|
|
|
48 |
|
|
{ERR_LIBRARY_FILE_TYPE, 2, "Library file has wrong type: %s"}, // expecting library file
|
49 |
|
|
{ERR_LIBRARY_FILE_CORRUPT, 2, "Library file is corrupt"}, // index out of range in library file
|
50 |
|
|
{ERR_LIBRARY_LIST_ONLY, 2, "Library list command cannnot be combined with other commands"}, // conflicting commands
|
51 |
|
|
{ERR_LIBRARY_MEMBER_TYPE, 2, "Library member %s has wrong type: %s"}, // expecting ForwardCom object file
|
52 |
|
|
|
53 |
|
|
{ERR_LINK_LIST_ONLY, 2, "Linker list command cannnot be combined with other commands"}, // conflicting commands
|
54 |
|
|
{ERR_LINK_FILE_TYPE, 2, "Wrong file type. Expecting ForwardCom object file: %s"}, // wrong file type to linker
|
55 |
|
|
{ERR_LINK_FILE_TYPE_LIB, 2, "Wrong file type. Expecting ForwardCom library file: %s"}, // wrong file type to linker
|
56 |
|
|
{ERR_LINK_FILE_TYPE_EXE, 2, "Wrong file type. Expecting ForwardCom executable file: %s"}, // wrong file type to emulator
|
57 |
|
|
{ERR_LINK_COMMUNAL, 1, "Communal section %s has different sizes in modules %s"}, // communal sections not identical
|
58 |
|
|
{ERR_LINK_DUPLICATE_SYMBOL, 1, "More than one symbol named %s in modules %s"}, // duplicate symbol encountered during linking
|
59 |
|
|
{ERR_LINK_DIFFERENT_BASE, 2, "Link source and target use different base pointers. Cannot link from module %s to symbol %s in module %s"}, // link source and target use different base pointers
|
60 |
|
|
{ERR_LINK_MISALIGNED_TARGET, 2, "Link target is misaligned. Scaling failed when linking from module %s to symbol %s in module %s"}, // link target alignment does not fit scale factor
|
61 |
|
|
{ERR_LINK_OVERFLOW, 2, "Address overflow when linking from module %s to symbol %s in module %s"}, // relocation overflow
|
62 |
|
|
{ERR_LINK_RELOCATION_OVERFLOW, 2, "Address overflow when linking to symbol %s"}, // relocation overflow
|
63 |
|
|
{ERR_LINK_REGUSE, 2, "Mismatched register use when linking from module %s to symbol %s. Missing registers: %s"}, // register use mismatch
|
64 |
|
|
{ERR_LINK_MODULE_NOT_FOUND, 2, "Module %s not found in library %s"}, // cannot find explicitly specified library module
|
65 |
|
|
{ERR_EVENT_SIZE, 1, "Wrong size of event handler records in module %s"}, // event section size not divisible by event record size
|
66 |
|
|
{ERR_REL_SYMBOL_NOT_FOUND, 2, "Relocated symbol not found"}, // relocation failed. should not occur
|
67 |
|
|
{ERR_CANT_RELINK_MODULE, 2, "Module %s is not relinkable. Cannot remove or replace"}, // attempt to delete or replace non-relinkable module
|
68 |
|
|
{ERR_CANT_RELINK_LIBRARY, 2, "Library %s is not relinkable. Cannot remove or replace"}, // attempt to delete or replace non-relinkable library
|
69 |
|
|
{ERR_RELINK_MODULE_NOT_FOUND, 1, "Module %s not found in input file. Cannot remove or replace"}, // attempt to delete or replace non-existing module
|
70 |
|
|
{ERR_RELINK_LIBRARY_NOT_FOUND, 1, "Library %s not found in input file. Cannot remove or replace"}, // attempt to delete or replace non-existing library
|
71 |
|
|
{ERR_RELINK_BASE_POINTER_MOD, 2, "Base pointer overridden during relinking. Relative addresses may be wrong"}, // base pointer has been overridden during relinking
|
72 |
|
|
{ERR_INPUT_NOT_RELINKABLE, 2, "File %s is not relinkable"}, // attempt to relink non-relinkable file
|
73 |
|
|
{ERR_LINK_UNRESOLVED, 2, "Unresolved external symbol %s in module %s"}, // symbol not found in any module or library
|
74 |
|
|
{ERR_LINK_UNRESOLVED_WARN, 1, "Unresolved external symbol %s in module %s"}, // symbol not found. warn only because incomplete output allowed
|
75 |
|
|
|
76 |
|
|
// Error messages
|
77 |
|
|
{ERR_MULTIPLE_IO_FILES, 2, "No more than one input file and one output file can be specified"}, //?
|
78 |
|
|
{ERR_MULTIPLE_COMMANDS, 2, "More than one command specified on command line: %s"},
|
79 |
|
|
{ERR_UNKNOWN_OPTION, 2, "Unknown command line option: %s"},
|
80 |
|
|
{ERR_FILES_SAME_NAME, 2, "Input file and output file cannot have same name: %s"},
|
81 |
|
|
{ERR_DUMP_NOT_SUPPORTED, 2, "Sorry. Dump of file type %s is not supported"},
|
82 |
|
|
{ERR_INDEX_OUT_OF_RANGE, 2, "Index out of range"},
|
83 |
|
|
|
84 |
|
|
{ERR_ELF_RECORD_SIZE, 2, "Error in ELF file. Record size wrong"},
|
85 |
|
|
{ERR_ELF_SYMTAB_MISSING, 2, "Symbol table not found in ELF file"},
|
86 |
|
|
{ERR_ELF_INDEX_RANGE, 2, "Index out of range in object file"},
|
87 |
|
|
{ERR_ELF_UNKNOWN_SECTION, 2, "Unknown section index in ELF file: %i"},
|
88 |
|
|
{ERR_ELF_STRING_TABLE, 2, "String table corrupt"},
|
89 |
|
|
{ERR_ELF_NO_SECTIONS, 2, "File with absolute constants must have at least one section, even if empty"},
|
90 |
|
|
|
91 |
|
|
{ERR_CONTAINER_INDEX, 2, "Index out of range in internal container"},
|
92 |
|
|
{ERR_CONTAINER_OVERFLOW, 2, "Overflow of internal container"},
|
93 |
|
|
|
94 |
|
|
{ERR_INPUT_FILE, 2, "Cannot read input file %s"},
|
95 |
|
|
{ERR_OUTPUT_FILE, 2, "Cannot write output file %s"},
|
96 |
|
|
{ERR_UNKNOWN_FILE_TYPE, 2, "Unknown file type %i: %s"},
|
97 |
|
|
{ERR_FILE_SIZE, 2, "Wrong size of file %s"},
|
98 |
|
|
|
99 |
|
|
{ERR_TOO_MANY_RESP_FILES, 2, "Too many response files"},
|
100 |
|
|
{ERR_FILE_NAME_LONG, 2, "File name %s too long"},
|
101 |
|
|
{ERR_INSTRUCTION_LIST_SYNTAX, 2, "Syntax error in instruction list: %s"},
|
102 |
|
|
{ERR_INSTRUCTION_LIST_QUOTE, 2, "Unmatched quote in instruction list, line %i"}, //?
|
103 |
|
|
|
104 |
|
|
// Fatal errors makes the program stop immediately:
|
105 |
|
|
{ERR_INTERNAL, 9, "Objconv program internal inconsistency"}, // table fault, etc.
|
106 |
|
|
{ERR_TOO_MANY_ERRORS, 9, "Too many errors. Aborting"},
|
107 |
|
|
{ERR_BIG_ENDIAN, 9, "This machine has big-endian memory organization or other incompatibility. Program cannot be compiled on this machine."},
|
108 |
|
|
{ERR_MEMORY_ALLOCATION, 9, "Memory allocation failed"},
|
109 |
|
|
|
110 |
|
|
// Mark end of list
|
111 |
|
|
{9999, 9999, "End of error text list"}
|
112 |
|
|
};
|
113 |
|
|
|
114 |
|
|
|
115 |
|
|
// Error messages for assembly file
|
116 |
|
|
SErrorText assemErrorTexts[] = {
|
117 |
|
|
// the status number indicates if an extra string is required
|
118 |
|
|
{0, 0, "misplaced unknown token"},
|
119 |
|
|
{TOK_NAM, 1, "unknown name: "},
|
120 |
|
|
{TOK_LAB, 1, "misplaced label: "},
|
121 |
|
|
{TOK_VAR, 1, "misplaced variable: "},
|
122 |
|
|
{TOK_SEC, 1, "misplaced section name: "},
|
123 |
|
|
{TOK_INS, 1, "misplaced instruction: "},
|
124 |
|
|
{TOK_OPR, 1, "misplaced operator: "},
|
125 |
|
|
{TOK_NUM, 1, "misplaced number: "},
|
126 |
|
|
{TOK_FLT, 1, "misplaced floating point number: "},
|
127 |
|
|
{TOK_CHA, 1, "misplaced character constant: "},
|
128 |
|
|
{TOK_STR, 1, "misplaced string: "},
|
129 |
|
|
{TOK_DIR, 1, "misplaced directive: "},
|
130 |
|
|
{TOK_ATT, 1, "misplaced attribute: "},
|
131 |
|
|
{TOK_TYP, 1, "misplaced type name: "},
|
132 |
|
|
{TOK_OPT, 1, "misplaced option: "},
|
133 |
|
|
{TOK_REG, 1, "misplaced register: "},
|
134 |
|
|
{TOK_SYM, 1, "misplaced symbol: "},
|
135 |
|
|
{TOK_XPR, 1, "misplaced expression: "},
|
136 |
|
|
{TOK_HLL, 1, "misplaced keyword: "},
|
137 |
|
|
|
138 |
|
|
{ERR_CONTROL_CHAR, 1, "illegal control character: "},
|
139 |
|
|
{ERR_ILLEGAL_CHAR, 1, "illegal character: "},
|
140 |
|
|
{ERR_COMMENT_BEGIN, 0, "unmatched comment begin: /*"},
|
141 |
|
|
{ERR_COMMENT_END, 0, "unmatched comment end: */"},
|
142 |
|
|
{ERR_BRACKET_BEGIN, 1, "unmatched begin bracket: "},
|
143 |
|
|
{ERR_BRACKET_END, 1, "unmatched end bracket: "},
|
144 |
|
|
{ERR_QUOTE_BEGIN, 1, "unmatched begin quote: "},
|
145 |
|
|
{ERR_QUESTION_MARK, 0, "unmatched '?'"},
|
146 |
|
|
{ERR_COLON, 0, "unmatched ':'"},
|
147 |
|
|
{ERR_SYMBOL_DEFINED, 1, "symbol already defined, cannot redefine: "},
|
148 |
|
|
{ERR_SYMBOL_UNDEFINED, 1, "symbol not defined: "},
|
149 |
|
|
{ERR_MULTIDIMENSIONAL, 1, "multidimensional array not allowed: "},
|
150 |
|
|
{ERR_UNFINISHED_VAR, 1, "unfinished variable declaration: "},
|
151 |
|
|
{ERR_MISSING_EXPR, 1, "expecting expression: "},
|
152 |
|
|
{ERR_CONFLICT_ARRAYSZ, 1, "conflicting array size: "},
|
153 |
|
|
{ERR_CONFLICT_TYPE, 1, "conflicting type of symbol: "},
|
154 |
|
|
{ERR_CONDITION, 1, "expression cannot be used for condition: "},
|
155 |
|
|
{ERR_OVERFLOW, 1, "expression overflow: "},
|
156 |
|
|
{ERR_WRONG_TYPE, 1, "wrong operand type for operator: "},
|
157 |
|
|
{ERR_WRONG_TYPE_VAR, 1, "wrong or mismatched type for variable (must be int64, double, string, register, or memory operand): "},
|
158 |
|
|
{ERR_WRONG_OPERANDS, 1, "wrong operands for this instruction: "},
|
159 |
|
|
{ERR_MISSING_DESTINATION,1, "this instruction needs a destination: "},
|
160 |
|
|
{ERR_NO_DESTINATION, 1, "this instruction should not have a destination: "},
|
161 |
|
|
{ERR_NOT_OP_AMBIGUOUS, 0, "'!' operator is ambiguous. For booleans and masks replace !A by A^1. For numeric operands replace !A by A==0"},
|
162 |
|
|
{ERR_TOO_COMPLEX, 1, "expression does not fit into a single instruction: "},
|
163 |
|
|
{ERR_MASK_NOT_REGISTER, 1, "mask must be a register: "},
|
164 |
|
|
{ERR_FALLBACK_WRONG, 1, "fallback must be a register 0-30 or zero: "},
|
165 |
|
|
{ERR_CONSTANT_TOO_LARGE, 1, "constant too large for specified type: "},
|
166 |
|
|
{ERR_ALIGNMENT, 1, "alignment must be a power of 2, not higher than 4096: "}, // maximum alignment value must equal MAX_ALIGN in assem.h
|
167 |
|
|
{ERR_SECTION_DIFFERENT_TYPE,1, "redefinition of section is different type: "},
|
168 |
|
|
{ERR_EXPECT_COLON, 1, "expecting colon after label: "},
|
169 |
|
|
{ERR_STRING_TYPE, 1, "string must have type int8: "},
|
170 |
|
|
{ERR_NONZERO_IN_BSS, 1, "data in uninitialized section must be zero: "},
|
171 |
|
|
{ERR_SYMBOL_REDEFINED, 1, "symbol has been assigned more than one value: "},
|
172 |
|
|
{ERR_EXPORT_EXPRESSION, 1, "cannot export expression: "},
|
173 |
|
|
{ERR_CANNOT_EXPORT, 1, "cannot export: "},
|
174 |
|
|
{ERR_CODE_WO_SECTION, 1, "code without section: "},
|
175 |
|
|
{ERR_DATA_WO_SECTION, 1, "data without section: "},
|
176 |
|
|
{ERR_MIX_DATA_AND_CODE, 1, "code and data in same section: "},
|
177 |
|
|
{ERR_MUST_BE_CONSTANT, 1, "value must be constant: "},
|
178 |
|
|
{ERR_MEM_COMPONENT_TWICE,1, "component of memory operand specified twice: "},
|
179 |
|
|
{ERR_SCALE_FACTOR, 1, "wrong scale factor for this instruction: "},
|
180 |
|
|
{ERR_MUST_BE_GP, 1, "vector length must be general purpose register: "},
|
181 |
|
|
{ERR_LIMIT_AND_OFFSET, 1, "memory operand cannot have both limit and offset: "},
|
182 |
|
|
{ERR_NOT_INSIDE_MEM, 1, "this option is not allowed inside memory operand: "},
|
183 |
|
|
{ERR_TOO_MANY_OPERANDS, 1, "too many operands: "},
|
184 |
|
|
{ERR_TOO_FEW_OPERANDS, 1, "not enough operands: "},
|
185 |
|
|
{ERR_OPERANDS_WRONG_ORDER,1, "operands in wrong order. register operands must come first: "},
|
186 |
|
|
{ERR_BOTH_MEM_AND_IMMEDIATE, 1, "this instruction cannot have both a memory operand and immediate constant: "}, // except store in format 2.7B and VARIANT_M1
|
187 |
|
|
{ERR_BOTH_MEM_AND_OPTIONS, 1, "this instruction cannot have both a memory operand and options: "},
|
188 |
|
|
{ERR_UNFINISHED_INSTRUCTION, 1, "unfinished instruction: "},
|
189 |
|
|
{ERR_TYPE_MISSING, 1, "type must be specified: "},
|
190 |
|
|
{ERR_MASK_FALLBACK_TYPE, 0, "mask and fallback must have same register type as destination"},
|
191 |
|
|
{ERR_NEG_INDEX_LENGTH, 0, "length register must be the same as negative index register"},
|
192 |
|
|
{ERR_INDEX_AND_LENGTH, 0, "memory operand cannot have length or broadcast with positive index"},
|
193 |
|
|
{ERR_MASK_REGISTER, 0, "mask must be register 0-6"},
|
194 |
|
|
{ERR_LIMIT_TOO_HIGH, 1, "limit on memory index cannot exceed 0xFFFF: "},
|
195 |
|
|
{ERR_NO_INSTRUCTION_FIT, 1, "no version of this instruction fits the specified operands: "},
|
196 |
|
|
{ERR_CANNOT_SWAP_VECT, 0, "cannot change the order of vector registers. if the vectors have the same length then put the register operands before the constant or memory operand"},
|
197 |
|
|
{ERR_EXPECT_JUMP_TARGET, 1, "expecting jump target: "},
|
198 |
|
|
{ERR_JUMP_TARGET_MISALIGN, 1, "jump target offset must be divisible by 4: "},
|
199 |
|
|
{ERR_ABS_RELOCATION, 1, "absolute address not possible here: "},
|
200 |
|
|
{ERR_RELOCATION_DOMAIN, 1, "cannot calculate difference between two symbols in different domains: "},
|
201 |
|
|
{ERR_WRONG_REG_TYPE, 1, "wrong type for register operand: "},
|
202 |
|
|
{ERR_CONFLICT_OPTIONS, 1, "conflicting options: "},
|
203 |
|
|
{ERR_VECTOR_OPTION, 1, "vector option applied to non-vector operands: "},
|
204 |
|
|
{ERR_LENGTH_OPTION_MISS, 1, "vector memory operand must have scalar, length, or broadcast option: "},
|
205 |
|
|
{ERR_DEST_BROADCAST, 0, "memory destination cannot have broadcast"},
|
206 |
|
|
{ERR_OFFSET_TOO_LARGE, 1, "address offset too large: "},
|
207 |
|
|
{ERR_LIMIT_TOO_LARGE, 1, "limit too large: "},
|
208 |
|
|
{ERR_IMMEDIATE_TOO_LARGE,1, "instruction format does not have space for full-size constant and option/signbits: "},
|
209 |
|
|
{ERR_TOO_LARGE_FOR_JUMP, 1, "conditional jump does not have space for 64-bit constant: "},
|
210 |
|
|
{ERR_CANNOT_HAVE_OPTION, 1, "this instruction cannot have options: "},
|
211 |
|
|
{ERR_CANNOT_HAVEFALLBACK1, 1, "this instruction cannot have a fallback register: "},
|
212 |
|
|
{ERR_CANNOT_HAVEFALLBACK2, 1, "the fallback must be the same as the first source operand when there is a memory operand with index or vector: "},
|
213 |
|
|
{ERR_3OP_AND_FALLBACK, 1, "the fallback must be the same as the first source operand on instructions with three operands: "},
|
214 |
|
|
{ERR_3OP_AND_MEM, 1, "the first source register must be the same as the destination when there is a memory operand with index or vector: "},
|
215 |
|
|
{ERR_R28_30_BASE, 1, "cannot use r28-r30 as base pointer with more than 8 bits offset: "},
|
216 |
|
|
{ERR_NO_BASE, 1, "memory operand has no base pointer: "},
|
217 |
|
|
{ERR_MEM_WO_BRACKET, 1, "memory operand requires [] bracket: "},
|
218 |
|
|
{ERR_UNKNOWN, 1, "unknown assembly error"},
|
219 |
|
|
{ERR_UNMATCHED_END, 0, "unmatched end"},
|
220 |
|
|
{ERR_SECTION_MISS_END, 1, "missing end of section: "},
|
221 |
|
|
{ERR_FUNCTION_MISS_END, 1, "missing end of function: "},
|
222 |
|
|
{ERR_ELSE_WO_IF, 1, "else without if: "},
|
223 |
|
|
{ERR_EXPECT_PARENTHESIS, 1, "expecting parenthesis: "},
|
224 |
|
|
{ERR_EXPECT_BRACKET, 1, "expecting '{' bracket: "},
|
225 |
|
|
{ERR_EXPECT_LOGICAL, 1, "expecting logical expression: "},
|
226 |
|
|
{ERR_MEM_NOT_ALLOWED, 1, "cannot have memory operand: "},
|
227 |
|
|
//{ERR_MUST_BE_POW2, 1, "constant must have only one bit set: "},
|
228 |
|
|
{ERR_WHILE_EXPECTED, 1, "'do' statement requires a 'while' here: "},
|
229 |
|
|
{ERR_MISPLACED_BREAK, 1, "nothing: to break out of: "},
|
230 |
|
|
{ERR_MISPLACED_CONTINUE, 1, "no loop to continue: "}
|
231 |
|
|
};
|
232 |
|
|
|
233 |
|
|
// buffer for text strings (this cannot be member of CMemoryBuffer because CErrorReporter must be defined before CMemoryBuffer)
|
234 |
|
|
static CMemoryBuffer strings;
|
235 |
|
|
|
236 |
|
|
// Members of class CErrorReporter: reporting of general errors
|
237 |
|
|
|
238 |
|
|
// Constructor for CErrorReporter
|
239 |
|
|
CErrorReporter::CErrorReporter() {
|
240 |
|
|
numErrors = numWarnings = worstError = 0;
|
241 |
|
|
maxWarnings = 50; // Max number of warning messages to pring
|
242 |
|
|
maxErrors = 50; // Max number of error messages to print
|
243 |
|
|
}
|
244 |
|
|
|
245 |
|
|
SErrorText * CErrorReporter::FindError(int ErrorNumber) {
|
246 |
|
|
// Search for error in ErrorTexts
|
247 |
|
|
int e;
|
248 |
|
|
const int ErrorTextsLength = sizeof(errorTexts) / sizeof(errorTexts[0]);
|
249 |
|
|
for (e = 0; e < ErrorTextsLength; e++) {
|
250 |
|
|
if (errorTexts[e].errorNumber == ErrorNumber) return errorTexts + e;
|
251 |
|
|
}
|
252 |
|
|
// Error number not found
|
253 |
|
|
static SErrorText UnknownErr = errorTexts[0];
|
254 |
|
|
UnknownErr.errorNumber = ErrorNumber;
|
255 |
|
|
UnknownErr.status = 0x102; // Unknown error
|
256 |
|
|
return &UnknownErr;
|
257 |
|
|
}
|
258 |
|
|
|
259 |
|
|
|
260 |
|
|
void CErrorReporter::submit(int ErrorNumber) {
|
261 |
|
|
// Print error message with no extra info
|
262 |
|
|
SErrorText * err = FindError(ErrorNumber);
|
263 |
|
|
handleError(err, err->text);
|
264 |
|
|
}
|
265 |
|
|
|
266 |
|
|
void CErrorReporter::submit(int ErrorNumber, int extra) {
|
267 |
|
|
// Print error message with extra numeric info
|
268 |
|
|
// ErrorTexts[ErrorNumber] must contain %i where extra is to be inserted
|
269 |
|
|
SErrorText * err = FindError(ErrorNumber);
|
270 |
|
|
strings.setSize((uint32_t)strlen(err->text) + 10);
|
271 |
|
|
sprintf((char*)strings.buf(), err->text, extra);
|
272 |
|
|
handleError(err, (char*)strings.buf());
|
273 |
|
|
}
|
274 |
|
|
|
275 |
|
|
void CErrorReporter::submit(int ErrorNumber, int extra1, int extra2) {
|
276 |
|
|
// Print error message with 2 extra numeric values inserted
|
277 |
|
|
// ErrorTexts[ErrorNumber] must contain two %i fields where extra numbers are to be inserted
|
278 |
|
|
SErrorText * err = FindError(ErrorNumber);
|
279 |
|
|
strings.setSize((uint32_t)strlen(err->text) + 20);
|
280 |
|
|
sprintf((char*)strings.buf(), err->text, extra1, extra2);
|
281 |
|
|
handleError(err, (char*)strings.buf());
|
282 |
|
|
}
|
283 |
|
|
|
284 |
|
|
void CErrorReporter::submit(int ErrorNumber, char const * extra) {
|
285 |
|
|
// Print error message with extra text info
|
286 |
|
|
// ErrorTexts[ErrorNumber] must contain %s where extra is to be inserted
|
287 |
|
|
if (extra == 0) extra = "???";
|
288 |
|
|
SErrorText * err = FindError(ErrorNumber);
|
289 |
|
|
strings.setSize((uint32_t)strlen(err->text) + (uint32_t)strlen(extra));
|
290 |
|
|
sprintf((char*)strings.buf(), err->text, extra);
|
291 |
|
|
handleError(err, (char*)strings.buf());
|
292 |
|
|
}
|
293 |
|
|
|
294 |
|
|
void CErrorReporter::submit(int ErrorNumber, char const * extra1, char const * extra2) {
|
295 |
|
|
// Print error message with two extra text info fields
|
296 |
|
|
// ErrorTexts[ErrorNumber] must contain %s where extra texts are to be inserted
|
297 |
|
|
if (extra1 == 0) extra1 = "???";
|
298 |
|
|
if (extra2 == 0) extra2 = "???";
|
299 |
|
|
SErrorText * err = FindError(ErrorNumber);
|
300 |
|
|
strings.setSize((uint32_t)strlen(err->text) + (uint32_t)strlen(extra1) + (uint32_t)strlen(extra2));
|
301 |
|
|
sprintf((char*)strings.buf(), err->text, extra1, extra2);
|
302 |
|
|
handleError(err, (char*)strings.buf());
|
303 |
|
|
}
|
304 |
|
|
|
305 |
|
|
void CErrorReporter::submit(int ErrorNumber, char const * extra1, char const * extra2, char const * extra3) {
|
306 |
|
|
// Print error message with three extra text info fields
|
307 |
|
|
// ErrorTexts[ErrorNumber] must contain %s where extra texts are to be inserted
|
308 |
|
|
if (extra1 == 0) extra1 = "???";
|
309 |
|
|
if (extra2 == 0) extra2 = "???";
|
310 |
|
|
if (extra3 == 0) extra3 = "???";
|
311 |
|
|
SErrorText * err = FindError(ErrorNumber);
|
312 |
|
|
strings.setSize((uint32_t)strlen(err->text) + (uint32_t)strlen(extra1) + (uint32_t)strlen(extra2) + (uint32_t)strlen(extra3));
|
313 |
|
|
sprintf((char*)strings.buf(), err->text, extra1, extra2, extra3);
|
314 |
|
|
handleError(err, (char*)strings.buf());
|
315 |
|
|
}
|
316 |
|
|
|
317 |
|
|
void CErrorReporter::submit(int ErrorNumber, int extra1, char const * extra2) {
|
318 |
|
|
// Print error message with two extra text fields inserted
|
319 |
|
|
// ErrorTexts[ErrorNumber] must contain %i and %s where extra texts are to be inserted
|
320 |
|
|
if (extra2 == 0) extra2 = "???";
|
321 |
|
|
SErrorText * err = FindError(ErrorNumber);
|
322 |
|
|
strings.setSize((uint32_t)strlen(err->text) + 10 + (uint32_t)strlen(extra2));
|
323 |
|
|
sprintf((char*)strings.buf(), err->text, extra1, extra2);
|
324 |
|
|
handleError(err, (char*)strings.buf());
|
325 |
|
|
}
|
326 |
|
|
|
327 |
|
|
// Write an error message.
|
328 |
|
|
// To trace a runtime error message: set a breakpoint here !½
|
329 |
|
|
void CErrorReporter::handleError(SErrorText * err, char const * text) {
|
330 |
|
|
// HandleError is used by submit functions
|
331 |
|
|
// check severity
|
332 |
|
|
int severity = err->status & 0x0F;
|
333 |
|
|
if (severity == 0) {
|
334 |
|
|
return; // Ignore message
|
335 |
|
|
}
|
336 |
|
|
if (severity > 1 && err->errorNumber > worstError) {
|
337 |
|
|
// Store highest error number
|
338 |
|
|
worstError = err->errorNumber;
|
339 |
|
|
}
|
340 |
|
|
if (severity == 1) {
|
341 |
|
|
// Treat message as warning
|
342 |
|
|
if (++numWarnings > maxWarnings) return; // Maximum number of warnings has been printed
|
343 |
|
|
// Treat message as warning
|
344 |
|
|
fprintf(stderr, "\nWarning %i: %s", err->errorNumber, text);
|
345 |
|
|
if (numWarnings == maxWarnings) {
|
346 |
|
|
// Maximum number reached
|
347 |
|
|
fprintf(stderr, "\nSupressing further warning messages");
|
348 |
|
|
}
|
349 |
|
|
}
|
350 |
|
|
else {
|
351 |
|
|
// Treat message as error
|
352 |
|
|
if (++numErrors > maxErrors) return; // Maximum number of warnings has been printed
|
353 |
|
|
fprintf(stderr, "\nError %i: %s", err->errorNumber, text);
|
354 |
|
|
if (numErrors == maxErrors) {
|
355 |
|
|
// Maximum number reached
|
356 |
|
|
fprintf(stderr, "\nSupressing further warning messages");
|
357 |
|
|
}
|
358 |
|
|
}
|
359 |
|
|
if (severity == 9) {
|
360 |
|
|
// Abortion required
|
361 |
|
|
fprintf(stderr, "\nAborting\n");
|
362 |
|
|
exit(err->errorNumber);
|
363 |
|
|
}
|
364 |
|
|
}
|
365 |
|
|
|
366 |
|
|
int CErrorReporter::number() {
|
367 |
|
|
// Get number of fatal errors
|
368 |
|
|
return numErrors;
|
369 |
|
|
}
|
370 |
|
|
|
371 |
|
|
int CErrorReporter::getWorstError() {
|
372 |
|
|
// Get highest warning or error number encountered
|
373 |
|
|
return worstError;
|
374 |
|
|
}
|
375 |
|
|
|
376 |
|
|
void CErrorReporter::clearError(int ErrorNumber) {
|
377 |
|
|
// Ignore further occurrences of this error
|
378 |
|
|
int e;
|
379 |
|
|
const int ErrorTextsLength = sizeof(errorTexts) / sizeof(errorTexts[0]);
|
380 |
|
|
for (e = 0; e < ErrorTextsLength; e++) {
|
381 |
|
|
if (errorTexts[e].errorNumber == ErrorNumber) break;
|
382 |
|
|
}
|
383 |
|
|
if (e < ErrorTextsLength) {
|
384 |
|
|
errorTexts[e].status = 0;
|
385 |
|
|
}
|
386 |
|
|
}
|
387 |
|
|
|
388 |
|
|
|
389 |
|
|
|
390 |
|
|
// Members of class CAssemErrors: reporting of errors in assembly file
|
391 |
|
|
CAssemErrors::CAssemErrors() { // Constructor
|
392 |
|
|
maxErrors = cmd.maxErrors;
|
393 |
|
|
}
|
394 |
|
|
|
395 |
|
|
void CAssemErrors::setOwner(CAssembler * a) {
|
396 |
|
|
// Give access to CAssembler
|
397 |
|
|
owner = a;
|
398 |
|
|
}
|
399 |
|
|
|
400 |
|
|
uint32_t CAssemErrors::numErrors() {
|
401 |
|
|
// Return number of errors
|
402 |
|
|
return list.numEntries();
|
403 |
|
|
}
|
404 |
|
|
|
405 |
|
|
bool CAssemErrors::tooMany() {
|
406 |
|
|
// true if too many errors
|
407 |
|
|
return list.numEntries() >= maxErrors;
|
408 |
|
|
}
|
409 |
|
|
|
410 |
|
|
// Report an error in assembly file
|
411 |
|
|
// To trace an assembly error: set a breakpoint here ½
|
412 |
|
|
void CAssemErrors::report(uint32_t position, uint32_t stringLength, uint32_t num) {
|
413 |
|
|
// position: position in input file
|
414 |
|
|
// stringLength: length of token
|
415 |
|
|
// num = index into assemErrorTexts or token type
|
416 |
|
|
owner->lineError = true; // avoid reporting multiple errors on same line
|
417 |
|
|
uint32_t linei = owner->linei;
|
418 |
|
|
if (linei < owner->lines.numEntries()) {
|
419 |
|
|
owner->lines[owner->linei].type = LINE_ERROR; // mark current line as error
|
420 |
|
|
}
|
421 |
|
|
if (tooMany()) return;
|
422 |
|
|
|
423 |
|
|
SAssemError e;
|
424 |
|
|
e.pos = position;
|
425 |
|
|
e.stringLength = stringLength;
|
426 |
|
|
e.file = owner->filei;
|
427 |
|
|
e.num = num;
|
428 |
|
|
e.pass = owner->pass;
|
429 |
|
|
|
430 |
|
|
// save error record
|
431 |
|
|
list.push(e);
|
432 |
|
|
}
|
433 |
|
|
|
434 |
|
|
// Report a misplaced token
|
435 |
|
|
void CAssemErrors::report(SToken const & token) {
|
436 |
|
|
report(token.pos, token.stringLength, token.type);
|
437 |
|
|
}
|
438 |
|
|
|
439 |
|
|
// Report an error in current line
|
440 |
|
|
void CAssemErrors::reportLine(uint32_t num) {
|
441 |
|
|
int tokenB = owner->lines[owner->linei].firstToken;
|
442 |
|
|
int tokenN = owner->lines[owner->linei].numTokens;
|
443 |
|
|
if (tokenB <= 0 || tokenN <= 0) {
|
444 |
|
|
num = ERR_UNKNOWN;
|
445 |
|
|
tokenB = 0;
|
446 |
|
|
tokenN = 1;
|
447 |
|
|
}
|
448 |
|
|
report(owner->tokens[tokenB].pos,
|
449 |
|
|
owner->tokens[tokenB + tokenN - 1].pos + owner->tokens[tokenB + tokenN - 1].stringLength - owner->tokens[tokenB].pos, num);
|
450 |
|
|
}
|
451 |
|
|
|
452 |
|
|
void CAssemErrors::outputErrors() {
|
453 |
|
|
// Output errors to STDERR
|
454 |
|
|
const uint32_t tabstops = 8; // default position of tabstops
|
455 |
|
|
|
456 |
|
|
if (list.numEntries() == 0) return;
|
457 |
|
|
const char * text1;
|
458 |
|
|
char text2[256];
|
459 |
|
|
const char * filename = cmd.getFilename(cmd.inputFile); // owner->fileName; // to do: support include filenames
|
460 |
|
|
const uint32_t errorTextsLength = TableSize(assemErrorTexts);
|
461 |
|
|
uint32_t i, j, texti;
|
462 |
|
|
|
463 |
|
|
uint32_t lastPass = 0;
|
464 |
|
|
for (i = 0; i < list.numEntries() && i < maxErrors; i++) {
|
465 |
|
|
// tell which pass if verbose option
|
466 |
|
|
if (list[i].pass != lastPass && cmd.verbose) {
|
467 |
|
|
printf("\n\nDuring pass %i:", list[i].pass);
|
468 |
|
|
lastPass = list[i].pass;
|
469 |
|
|
}
|
470 |
|
|
|
471 |
|
|
// find line containing error
|
472 |
|
|
uint32_t line;
|
473 |
|
|
uint32_t numLines = owner->lines.numEntries();
|
474 |
|
|
uint32_t pos = list[i].pos;
|
475 |
|
|
for (line = 0; line < numLines; line++) {
|
476 |
|
|
if (pos < owner->lines[line].beginPos) break;
|
477 |
|
|
}
|
478 |
|
|
line--;
|
479 |
|
|
// if this line has multiple records in lines[] then find the first one
|
480 |
|
|
j = line;
|
481 |
|
|
while (j > 0 && owner->lines[j - 1].linenum == owner->lines[line].linenum) j--;
|
482 |
|
|
line = j;
|
483 |
|
|
|
484 |
|
|
// find column
|
485 |
|
|
uint32_t pos1 = owner->lines[line].beginPos;
|
486 |
|
|
uint32_t stringLength = list[i].stringLength;
|
487 |
|
|
uint32_t column = pos - pos1;
|
488 |
|
|
// count UTF-8 multibyte characters in line up to error position
|
489 |
|
|
int32_t extraBytes = 0;
|
490 |
|
|
int8_t c; // current character
|
491 |
|
|
for (uint32_t pp = pos1; pp < pos1 + column; pp++) {
|
492 |
|
|
if (pp >= owner->dataSize()) break;
|
493 |
|
|
c = *(owner->buf() + pp);
|
494 |
|
|
if ((c & 0xC0) == 0xC0) extraBytes--; // count UTF-8 continuation bytes
|
495 |
|
|
if (c == '\t') {
|
496 |
|
|
uint32_t pos2 = (pp + tabstops) % tabstops; // find next tabstop
|
497 |
|
|
extraBytes += pos2 - pp - 1;
|
498 |
|
|
}
|
499 |
|
|
}
|
500 |
|
|
// adjust column number to 1-based. count UTF-8 characters as one
|
501 |
|
|
column += extraBytes + 1;
|
502 |
|
|
|
503 |
|
|
// find text
|
504 |
|
|
texti = list[i].num;
|
505 |
|
|
for (j = 0; j < errorTextsLength; j++) {
|
506 |
|
|
if ((uint32_t)assemErrorTexts[j].errorNumber == texti) break;
|
507 |
|
|
}
|
508 |
|
|
if (j >= errorTextsLength) j = 0;
|
509 |
|
|
text1 = assemErrorTexts[j].text;
|
510 |
|
|
if (assemErrorTexts[j].status && stringLength < sizeof(text2)) {
|
511 |
|
|
// extra text required
|
512 |
|
|
memcpy(text2, owner->buf() + pos, stringLength);
|
513 |
|
|
text2[stringLength] = 0;
|
514 |
|
|
}
|
515 |
|
|
else text2[0] = 0;
|
516 |
|
|
|
517 |
|
|
if (filename) {
|
518 |
|
|
fprintf(stderr, "\n%s:", filename);
|
519 |
|
|
}
|
520 |
|
|
else {
|
521 |
|
|
fprintf(stderr, "\n");
|
522 |
|
|
}
|
523 |
|
|
fprintf(stderr, "%i:%i: %s%s", owner->lines[line].linenum, column, text1, text2);
|
524 |
|
|
}
|
525 |
|
|
}
|