/* Pawn compiler - Error message system * In fact a very simple system, using only 'panic mode'. * * Copyright (c) ITB CompuPhase, 1997-2005 * * This software is provided "as-is", without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software in * a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #if defined __WIN32__ || defined _WIN32 || defined __MSDOS__ #include #endif #if defined LINUX || defined __APPLE__ || defined __GNUC__ #include #endif #include #include #include /* ANSI standardized variable argument list functions */ #include #if defined FORTIFY #include "fortify.h" #endif #include "sc.h" #if defined _MSC_VER #pragma warning(push) #pragma warning(disable:4125) /* decimal digit terminates octal escape sequence */ #endif #include #if defined _MSC_VER #pragma warning(pop) #endif #define NUM_WARNINGS (sizeof warnmsg / sizeof warnmsg[0]) static unsigned char warndisable[(NUM_WARNINGS + 7) / 8]; /* 8 flags in a char */ static int errflag; static int errfile; static int errstart; /* line number at which the instruction started */ static int errline; /* forced line number for the error message */ /* error * * Outputs an error message (note: msg is passed optionally). * If an error is found, the variable "errflag" is set and subsequent * errors are ignored until lex() finds a semicolumn or a keyword * (lex() resets "errflag" in that case). * * Global references: inpfname (reffered to only) * fline (reffered to only) * fcurrent (reffered to only) * errflag (altered) */ SC_FUNC int error(int number,...) { static char *prefix[3]={ "error", "fatal error", "warning" }; static int lastline,errorcount; static short lastfile; char *msg,*pre,*filename; va_list argptr; char string[128]; /* errflag is reset on each semicolon. * In a two-pass compiler, an error should not be reported twice. Therefore * the error reporting is enabled only in the second pass (and only when * actually producing output). Fatal errors may never be ignored. */ if ((errflag || sc_status!=statWRITE) && (number<100 || number>=200)) return 0; /* also check for disabled warnings */ if (number>=200) { int index=(number-200)/8; int mask=1 << ((number-200)%8); if ((warndisable[index] & mask)!=0) return 0; } /* if */ if (number<100){ msg=errmsg[number-1]; pre=prefix[0]; errflag=TRUE; /* set errflag (skip rest of erroneous expression) */ errnum++; } else if (number<200){ msg=fatalmsg[number-100]; pre=prefix[1]; errnum++; /* a fatal error also counts as an error */ } else { msg=warnmsg[number-200]; pre=prefix[2]; warnnum++; } /* if */ strexpand(string,(unsigned char *)msg,sizeof string,SCPACK_TABLE); if (errline>0) errstart=errline; /* forced error position, set single line destination */ else errline=fline; /* normal error, errstart may (or may not) have been marked, endpoint is current line */ if (errstart>errline) errstart=errline; /* special case: error found at end of included file */ if (errfile>=0) filename=get_inputfile(errfile);/* forced filename */ else filename=inpfname; /* current file */ assert(filename!=NULL); va_start(argptr,number); if (strlen(errfname)==0) { int start= (errstart==errline) ? -1 : errstart; if (pc_error((int)number,string,filename,start,errline,argptr)) { if (outf!=NULL) { pc_closeasm(outf,TRUE); outf=NULL; } /* if */ longjmp(errbuf,3); /* user abort */ } /* if */ } else { FILE *fp=fopen(errfname,"a"); if (fp!=NULL) { if (errstart>=0 && errstart!=errline) fprintf(fp,"%s(%d -- %d) : %s %03d: ",filename,errstart,errline,pre,number); else fprintf(fp,"%s(%d) : %s %03d: ",filename,errline,pre,number); vfprintf(fp,string,argptr); fclose(fp); } /* if */ } /* if */ va_end(argptr); if ((number>=100 && number<200) || errnum>25){ if (strlen(errfname)==0) { va_start(argptr,number); pc_error(0,"\nCompilation aborted.",NULL,0,0,argptr); va_end(argptr); } /* if */ if (outf!=NULL) { pc_closeasm(outf,TRUE); outf=NULL; } /* if */ longjmp(errbuf,2); /* fatal error, quit */ } /* if */ errline=-1; errfile=-1; /* check whether we are seeing many errors on the same line */ if ((errstart<0 && lastline!=fline) || lastlinefline || fcurrent!=lastfile) errorcount=0; lastline=fline; lastfile=fcurrent; if (number<200) errorcount++; if (errorcount>=3) error(107); /* too many error/warning messages on one line */ return 0; } SC_FUNC void errorset(int code,int line) { switch (code) { case sRESET: errflag=FALSE; /* start reporting errors */ break; case sFORCESET: errflag=TRUE; /* stop reporting errors */ break; case sEXPRMARK: errstart=fline; /* save start line number */ break; case sEXPRRELEASE: errstart=-1; /* forget start line number */ errline=-1; errfile=-1; break; case sSETLINE: errstart=-1; /* force error line number, forget start line */ errline=line; break; case sSETFILE: errfile=line; break; } /* switch */ } /* sc_enablewarning() * Enables or disables a warning (errors cannot be disabled). * Initially all warnings are enabled. The compiler does this by setting bits * for the *disabled* warnings and relying on the array to be zero-initialized. * * Parameter enable can be: * o 0 for disable * o 1 for enable * o 2 for toggle */ int pc_enablewarning(int number,int enable) { int index; unsigned char mask; if (number<200) return FALSE; /* errors and fatal errors cannot be disabled */ number -= 200; if (number>=NUM_WARNINGS) return FALSE; index=number/8; mask=(unsigned char)(1 << (number%8)); switch (enable) { case 0: warndisable[index] |= mask; break; case 1: warndisable[index] &= (unsigned char)~mask; break; case 2: warndisable[index] ^= mask; break; } /* switch */ return TRUE; } #undef SCPACK_TABLE