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