/* Error handling for gpasm Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 James Bowman, Craig Franklin This file is part of gputils. gputils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. gputils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with gputils; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdhdr.h" #include "libgputils.h" #include "gpasm.h" #include "gperror.h" #include "lst.h" struct error_list { int value; struct error_list *next; }; static struct error_list *errorcodes_list = NULL; void add_code(int code) { struct error_list *new; struct error_list *list; if ((code <= -100) && (code >= -199)) { gpwarning(GPW_DISABLE_ERROR, NULL); } else { new = (struct error_list *)malloc(sizeof(*new)); new->value = code; new->next = NULL; if (errorcodes_list) { /* the list has been started, scan the list for the end */ list = errorcodes_list; while(list->next) { list = list->next; } list->next = new; /* append the new value to the end of list */ } else { errorcodes_list = new; /* new list */ } } } static int check_code(int code) { struct error_list *p; int print = 1; p = errorcodes_list; while(p) { if (p->value == code){ print = 1; } else if (p->value == -(code)) { print = 0; } p = p->next; } return print; } char *gp_geterror(unsigned int code) { switch(code) { case GPE_OPENPAR: return "Unmatched ("; case GPE_CLOSEPAR: return "Unmatched )"; case GPE_BADCHAR: return "Illegal character."; case GPE_NOSYM: return "Symbol not previously defined."; case GPE_DIVBY0: return "Divide by zero."; case GPE_DUPLAB: return "Duplicate label or redefining symbol that cannot be redefined."; case GPE_DIFFLAB: return "Address label duplicated or different in second pass."; case GPE_ADDROVF: return "Address wrapped around 0. "; case GPE_ADDROVR: return "Overwriting previous address contents."; case GPE_BAD_CALL_ADDR: return "Call or jump not allowed at this address (must be in low half of page)"; case GPE_ILLEGAL_LABEL: return "Illegal label."; case GPE_ILLEGAL_DIR: return "Illegal directive (Not Valid for this processor)."; case GPE_ILLEGAL_ARGU: return "Illegal argument."; case GPE_ILLEGAL_COND: return "Illegal condition."; case GPE_RANGE: return "Argument out of range."; case GPE_TOO_MANY_ARGU: return "Too many arguments."; case GPE_MISSING_ARGU: return "Missing argument(s)."; case GPE_EXPECTED: return "Expected"; case GPE_EXTRA_PROC: return "Processor type previously defined."; case GPE_UNDEF_PROC: return "Processor type is undefined."; case GPE_UNKNOWN_PROC: return "Unknown processor."; case GPE_IHEX: return "Hex file format INHX32 required."; case GPE_NO_MACRO_NAME: return "Macro name missing."; case GPE_DUPLICATE_MACRO: return "Duplicate macro name."; case GPE_BAD_WHILE_LOOP: return "WHILE must terminate within 256 iterations."; case GPE_ILLEGAL_NESTING: return "Illegal nesting."; case GPE_UNMATCHED_ENDM: return "Unmatched ENDM."; case GPE_OBJECT_ONLY: return "Directive only allowed when generating an object file."; case GPE_UNRESOLVABLE: return "Operand contains unresolvable labels or is too complex."; case GPE_WRONG_SECTION: return "Executable code and data must be defined in an appropriate section."; case GPE_CONTIG_SECTION: return "Each object file section must be contiguous."; case GPE_MUST_BE_LABEL: return "Operand must be an address label."; case GPE_FILL_ODD: return "Cannot use FILL Directive with odd number of bytes."; case GPE_CONTIG_CONFIG: return "__CONFIG directives must be contiguous."; case GPE_CONTIG_IDLOC: return "__IDLOC directives must be contiguous."; case GPE_MISSING_BRACKET: return "Square brackets required around offset operand."; case GPE_UNKNOWN: default: return "UNKNOWN"; } } void gperror(unsigned int code, char *message) { char full_message[BUFSIZ]; if (state.pass == 2) { if(message == NULL) message = gp_geterror(code); #ifndef GP_USER_ERROR /* standard output */ if (!state.quiet) { if (state.src) snprintf(full_message, sizeof(full_message), "%s:%d:Error [%03d] %s", state.src->name, state.src->line_number, code, message); else snprintf(full_message, sizeof(full_message), "Error [%03d] %s", code, message); printf("%s\n", full_message); } #else user_error(code, message); #endif /* list file output */ snprintf(full_message, sizeof(full_message), "Error [%03d] : %s", code, message); lst_line(full_message); state.num.errors++; } } char *gp_getwarning(unsigned int code) { switch(code) { case GPW_NOT_DEFINED: return "Symbol not previously defined."; case GPW_RANGE: return "Argument out of range. Least significant bits used."; case GPW_OP_COLUMN_ONE: return "Found opcode in column 1."; case GPW_DIR_COLUMN_ONE: return "Found directive in column 1."; case GPW_MACRO_COLUMN_ONE: return "Found call to macro in column 1."; case GPW_LABEL_COLUMN: return "Found label after column 1."; case GPW_MISSING_QUOTE: return "Missing quote."; case GPW_EXTRANEOUS: return "Extraneous arguments on the line."; case GPW_EXPECTED: return "Expected."; case GPW_CMDLINE_PROC: return "Processor superseded by command line."; case GPW_CMDLINE_RADIX: return "Radix superseded by command line."; case GPW_CMDLINE_HEXFMT: return "Hex file format specified on command line."; case GPW_RADIX: return "Expected dec, oct, hex. Will use hex."; case GPW_INVALID_RAM: return "Invalid RAM location specified."; case GPW_DISABLE_ERROR: return "Error messages cannot be disabled."; case GPW_REDEFINING_PROC: return "Redefining processor."; case GPW_NOT_RECOMMENDED: return "Use of this instruction is not recommended."; case GPW_INVALID_ROM: return "Invalid ROM location specified."; case GPW_UNKNOWN: default: return "UNKNOWN"; } } void gpwarning(unsigned int code, char *message) { char full_message[BUFSIZ]; if (state.pass ==2) { if ((state.error_level <= 1) && check_code(code)) { if(message == NULL) message = gp_getwarning(code); #ifndef GP_USER_WARNING /* standard output */ if (!state.quiet) { if (state.src) snprintf(full_message, sizeof(full_message), "%s:%d:Warning [%03d] %s", state.src->name, state.src->line_number, code, message); else snprintf(full_message, sizeof(full_message), "Warning [%03d] %s", code, message); printf("%s\n", full_message); } #else user_warning(code, message); #endif /* list file output */ snprintf(full_message, sizeof(full_message), "Warning [%03d] : %s", code, message); lst_line(full_message); state.num.warnings++; } else { state.num.warnings_suppressed++; } } } char *gp_getmessage(unsigned int code) { switch(code) { case GPM_USER: return "MESSAGE:"; case GPM_BANK: return "Register in operand not in bank 0. Ensure bank bits are correct."; case GPM_RANGE: return "Program word too large. Truncated to core size."; case GPM_IDLOC: return "ID Locations value too large. Last four hex digits used."; case GPM_NOF: return "Using default destination of 1 (file)."; case GPM_PAGE: return "Crossing page boundary -- ensure page bits are set."; case GPM_PAGEBITS: return "Setting page bits."; case GPM_SUPVAL: return "Warning level superceded by command line value."; case GPM_SUPLIN: return "Macro expansion superceded by command line value."; case GPM_SUPRAM: return "Superceding current maximum RAM and RAM map."; case GPM_EXTPAGE: return "Page or Bank selection not needed for this device."; case GPM_CBLOCK: return "CBLOCK will begin at address 0."; case GPM_W_MODIFIED: return "W Register modified."; case GPM_SPECIAL_MNEMONIC: return "Special Instruction Mnemonic used."; case GPM_UNKNOWN: default: return "UNKNOWN MESSAGE"; } } void gpmessage(unsigned int code, char *message) { char full_message[BUFSIZ]; if (state.pass==2) { if ((state.error_level == 0) && check_code(code)){ if(message == NULL) message = gp_getmessage(code); #ifndef GP_USER_MESSAGE /* standard output */ if (!state.quiet) { if (state.src) snprintf(full_message, sizeof(full_message), "%s:%d:Message [%03d] %s", state.src->name, state.src->line_number, code, message); else snprintf(full_message, sizeof(full_message), "Message [%03d] %s", code, message); printf("%s\n", full_message); } #else user_message(code, message); #endif /* list file output */ snprintf(full_message, sizeof(full_message), "Message [%03d] : %s", code, message); lst_line(full_message); state.num.messages++; } else { state.num.messages_suppressed++; } } }