OpenCores
URL https://opencores.org/ocsvn/forwardcom/forwardcom/trunk

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [error.cpp] - Rev 58

Compare with Previous | Blame | View Log

/****************************   error.cpp   **********************************
* Author:        Agner Fog
* Date created:  2017-11-03
* Last modified: 2021-03-30
* Version:       1.11
* Project:       Binary tools for ForwardCom instruction set
* Module:        error.cpp
* Description:
* Standard procedure for error reporting to stderr
*
* Copyright 2006-2021 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);
    }
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.