| 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 |
|
|
}
|