OSDN Git Service

- Removed pcode escalation with -h since the only thing is does is confuse people...
[zandronum/zandronum-acc.git] / error.c
1 \r
2 //**************************************************************************\r
3 //**\r
4 //** error.c\r
5 //**\r
6 //**************************************************************************\r
7 \r
8 // HEADER FILES ------------------------------------------------------------\r
9 \r
10 #include <stdio.h>\r
11 #include <stdlib.h>\r
12 #include <stdarg.h>\r
13 #include <string.h>\r
14 #include "common.h"\r
15 #include "error.h"\r
16 #include "token.h"\r
17 #include "misc.h"\r
18 \r
19 // MACROS ------------------------------------------------------------------\r
20 \r
21 #define ERROR_FILE_NAME "acs.err"\r
22 \r
23 // TYPES -------------------------------------------------------------------\r
24 \r
25 typedef enum\r
26 {\r
27         ERRINFO_GCC,\r
28         ERRINFO_VCC\r
29 } errorInfo_e;\r
30 \r
31 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------\r
32 \r
33 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------\r
34 \r
35 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------\r
36 \r
37 static char *ErrorText(error_t error);\r
38 static char *ErrorFileName(void);\r
39 static void eprintf(const char *fmt, ...);\r
40 static void veprintf(const char *fmt, va_list args);\r
41 \r
42 // EXTERNAL DATA DECLARATIONS ----------------------------------------------\r
43 \r
44 extern char acs_SourceFileName[MAX_FILE_NAME_LENGTH];\r
45 \r
46 // PUBLIC DATA DEFINITIONS -------------------------------------------------\r
47 \r
48 // PRIVATE DATA DEFINITIONS ------------------------------------------------\r
49 \r
50 static struct\r
51 {\r
52         error_t number;\r
53         char *name;\r
54 } ErrorNames[] =\r
55 {\r
56         { ERR_MISSING_SEMICOLON, "Missing semicolon." },\r
57         { ERR_MISSING_LPAREN, "Missing '('." },\r
58         { ERR_MISSING_RPAREN, "Missing ')'." },\r
59         { ERR_MISSING_LBRACE, "Missing '{'." },\r
60         { ERR_MISSING_SCRIPT_NUMBER, "Missing script number." },\r
61         { ERR_IDENTIFIER_TOO_LONG, "Identifier too long." },\r
62         { ERR_STRING_TOO_LONG, "String too long." },\r
63         { ERR_FILE_NAME_TOO_LONG, "File name too long.\nFile: \"%s\"" },\r
64         { ERR_BAD_CHARACTER, "Bad character in script text." },\r
65         { ERR_BAD_CHARACTER_CONSTANT, "Bad character constant in script text." },\r
66         { ERR_ALLOC_PCODE_BUFFER, "Failed to allocate PCODE buffer." },\r
67         { ERR_PCODE_BUFFER_OVERFLOW, "PCODE buffer overflow." },\r
68         { ERR_TOO_MANY_SCRIPTS, "Too many scripts." },\r
69         { ERR_TOO_MANY_FUNCTIONS, "Too many functions." },\r
70         { ERR_SAVE_OBJECT_FAILED, "Couldn't save object file." },\r
71         { ERR_MISSING_LPAREN_SCR, "Missing '(' in script definition." },\r
72         { ERR_INVALID_IDENTIFIER, "Invalid identifier." },\r
73         { ERR_REDEFINED_IDENTIFIER, "%s : Redefined identifier." },\r
74         { ERR_MISSING_COMMA, "Missing comma." },\r
75         { ERR_BAD_VAR_TYPE, "Invalid variable type." },\r
76         { ERR_BAD_RETURN_TYPE, "Invalid return type." },\r
77         { ERR_TOO_MANY_SCRIPT_ARGS, "Too many script arguments." },\r
78         { ERR_MISSING_LBRACE_SCR, "Missing opening '{' in script definition." },\r
79         { ERR_MISSING_RBRACE_SCR, "Missing closing '}' in script definition." },\r
80         { ERR_TOO_MANY_MAP_VARS, "Too many map variables." },\r
81         { ERR_TOO_MANY_SCRIPT_VARS, "Too many script variables." },\r
82         { ERR_TOO_MANY_FUNCTION_VARS, "Too many function variables." },\r
83         { ERR_MISSING_WVAR_INDEX, "Missing index in world variable declaration." },\r
84         { ERR_MISSING_GVAR_INDEX, "Missing index in global variable declaration." },\r
85         { ERR_BAD_WVAR_INDEX, "World variable index out of range." },\r
86         { ERR_MISSING_WVAR_COLON, "Missing colon in world variable declaration." },\r
87         { ERR_MISSING_GVAR_COLON, "Missing colon in global variable declaration." },\r
88         { ERR_MISSING_SPEC_VAL, "Missing value in special declaration." },\r
89         { ERR_MISSING_SPEC_COLON, "Missing colon in special declaration." },\r
90         { ERR_MISSING_SPEC_ARGC, "Missing argument count in special declaration." },\r
91         { ERR_CANT_READ_FILE, "Couldn't read file.\nFile: \"%s\"" },\r
92         { ERR_CANT_OPEN_FILE, "Couldn't open file.\nFile: \"%s\"" },\r
93         { ERR_CANT_OPEN_DBGFILE, "Couldn't open debug file." },\r
94         { ERR_INVALID_DIRECTIVE, "Invalid directive." },\r
95         { ERR_BAD_DEFINE, "Non-numeric constant found in #define." },\r
96         { ERR_INCL_NESTING_TOO_DEEP, "Include nesting too deep.\nUnable to include file \"%s\"." },\r
97         { ERR_STRING_LIT_NOT_FOUND, "String literal not found." },\r
98         { ERR_INVALID_DECLARATOR, "Invalid declarator." },\r
99         { ERR_BAD_LSPEC_ARG_COUNT, "Incorrect number of special arguments." },\r
100         { ERR_BAD_ARG_COUNT, "Incorrect number of arguments." },\r
101         { ERR_UNKNOWN_IDENTIFIER, "%s : Identifier has not been declared." },\r
102         { ERR_MISSING_COLON, "Missing colon." },\r
103         { ERR_BAD_EXPR, "Syntax error in expression." },\r
104         { ERR_BAD_CONST_EXPR, "Syntax error in constant expression." },\r
105         { ERR_NO_DIRECT_VER, "Internal function has no direct version." },\r
106         { ERR_ILLEGAL_EXPR_IDENT, "%s : Illegal identifier in expression." },\r
107         { ERR_EXPR_FUNC_NO_RET_VAL, "Function call in expression has no return value." },\r
108         { ERR_MISSING_ASSIGN_OP, "Missing assignment operator." },\r
109         { ERR_INCDEC_OP_ON_NON_VAR, "'++' or '--' used on a non-variable." },\r
110         { ERR_MISSING_RBRACE, "Missing '}' at end of compound statement." },\r
111         { ERR_INVALID_STATEMENT, "Invalid statement." },\r
112         { ERR_BAD_DO_STATEMENT, "Do statement not followed by 'while' or 'until'." },\r
113         { ERR_BAD_SCRIPT_DECL, "Bad script declaration." },\r
114         { ERR_CASE_OVERFLOW, "Internal Error: Case stack overflow." },\r
115         { ERR_BREAK_OVERFLOW, "Internal Error: Break stack overflow." },\r
116         { ERR_CONTINUE_OVERFLOW, "Internal Error: Continue stack overflow." },\r
117         { ERR_STATEMENT_OVERFLOW, "Internal Error: Statement overflow." },\r
118         { ERR_MISPLACED_BREAK, "Misplaced BREAK statement." },\r
119         { ERR_MISPLACED_CONTINUE, "Misplaced CONTINUE statement." },\r
120         { ERR_CASE_NOT_IN_SWITCH, "CASE must appear in switch statement." },\r
121         { ERR_DEFAULT_NOT_IN_SWITCH, "DEFAULT must appear in switch statement." },\r
122         { ERR_MULTIPLE_DEFAULT, "Only 1 DEFAULT per switch allowed." },\r
123         { ERR_EXPR_STACK_OVERFLOW, "Expression stack overflow." },\r
124         { ERR_EXPR_STACK_EMPTY, "Tried to POP empty expression stack." },\r
125         { ERR_UNKNOWN_CONST_EXPR_PCD, "Unknown PCD in constant expression." },\r
126         { ERR_BAD_RADIX_CONSTANT, "Radix out of range in integer constant." },\r
127         { ERR_BAD_ASSIGNMENT, "Syntax error in multiple assignment statement." },\r
128         { ERR_OUT_OF_MEMORY, "Out of memory." },\r
129         { ERR_TOO_MANY_STRINGS, "Too many strings. Current max is %d" },\r
130         { ERR_UNKNOWN_PRTYPE, "Unknown cast type in print statement." },\r
131         { ERR_SCRIPT_OUT_OF_RANGE, "Script number must be between 1 and 32767." },\r
132         { ERR_MISSING_PARAM, "Missing required argument." },\r
133         { ERR_SCRIPT_ALREADY_DEFINED, "Script already has a body." },\r
134         { ERR_FUNCTION_ALREADY_DEFINED, "Function already has a body." },\r
135         { ERR_PARM_MUST_BE_VAR, "Parameter must be a variable." },\r
136         { ERR_LANGCODE_SIZE, "Language code must be 2 or 3 characters long." },\r
137         { ERR_MISSING_LBRACE_LOC, "Missing opening '{' in localization definition." },\r
138         { ERR_MISSING_RBRACE_LOC, "Missing closing '}' in localization definition." },\r
139         { ERR_MISSING_LOCALIZED, "Missing localized string." },\r
140         { ERR_BAD_LANGCODE, "Language code must be all letters." },\r
141         { ERR_MISSING_LANGCODE, "Missing language code in localization definiton." },\r
142         { ERR_MISSING_FONT_NAME, "Missing font name." },\r
143         { ERR_MISSING_LBRACE_FONTS, "Missing opening '{' in font list." },\r
144         { ERR_MISSING_RBRACE_FONTS, "Missing closing '}' in font list." },\r
145         { ERR_NOCOMPACT_NOT_HERE, "#nocompact must appear before any scripts." },\r
146         { ERR_MISSING_ASSIGN, "Missing '='." },\r
147         { ERR_PREVIOUS_NOT_VOID, "Previous use of function expected a return value." },\r
148         { ERR_MUST_RETURN_A_VALUE, "Function must return a value." },\r
149         { ERR_MUST_NOT_RETURN_A_VALUE, "Void functions cannot return a value." },\r
150         { ERR_SUSPEND_IN_FUNCTION, "Suspend cannot be used inside a function." },\r
151         { ERR_TERMINATE_IN_FUNCTION, "Terminate cannot be used inside a function." },\r
152         { ERR_RESTART_IN_FUNCTION, "Restart cannot be used inside a function." },\r
153         { ERR_RETURN_OUTSIDE_FUNCTION, "Return can only be used inside a function." },\r
154         { ERR_FUNC_ARGUMENT_COUNT, "Function %s should have %d argument%s." },\r
155         { ERR_EOF, "Unexpected end of file." },\r
156         { ERR_UNDEFINED_FUNC, "Function %s is used but not defined." },\r
157         { ERR_TOO_MANY_ARRAY_DIMS, "Too many array dimensions." },\r
158         { ERR_TOO_MANY_ARRAY_INIT, "Too many initializers for array." },\r
159         { ERR_MISSING_LBRACKET, "Missing '['." },\r
160         { ERR_MISSING_RBRACKET, "Missing ']'." },\r
161         { ERR_ZERO_DIMENSION, "Arrays cannot have a dimension of zero." },\r
162         { ERR_TOO_MANY_DIM_USED, "%s only has %d dimensions." },\r
163         { ERR_ARRAY_MAPVAR_ONLY, "Only map variables can be arrays." },\r
164         { ERR_NOT_AN_ARRAY, "%s is not an array." },\r
165         { ERR_MISSING_LBRACE_ARR, "Missing opening '{' in array initializer." },\r
166         { ERR_MISSING_RBRACE_ARR, "Missing closing '}' in array initializer." },\r
167         { ERR_LATENT_IN_FUNC, "Latent functions cannot be used inside functions." },\r
168         { ERR_LOCAL_VAR_SHADOWED, "A global identifier already has this name." },\r
169         { ERR_MULTIPLE_IMPORTS, "You can only #import one file." },\r
170         { ERR_IMPORT_IN_EXPORT, "You cannot #import from inside an imported file." },\r
171         { ERR_EXPORTER_NOT_FLAGGED, "A file that you #import must have an #imported line." },\r
172         { ERR_TOO_MANY_IMPORTS, "Too many files imported." },\r
173         { ERR_NO_NEED_ARRAY_SIZE, "Only map arrays need a size." },\r
174         { ERR_NO_MULTIDIMENSIONS, "Only map arrays can have more than one dimension." },\r
175         { ERR_NEED_ARRAY_SIZE, "Missing array size." },\r
176         { ERR_DISCONNECT_NEEDS_1_ARG, "Disconnect scripts must have 1 argument." },\r
177         { ERR_UNCLOSED_WITH_ARGS, "Most special scripts must not have arguments." },\r
178         { ERR_NOT_A_CHAR_ARRAY, "%s has %d dimensions. Use %d subscripts to get a char array." },\r
179         { ERR_CANT_FIND_INCLUDE, "Couldn't find include file \"%s\"." },\r
180         { ERR_SCRIPT_NAMED_NONE, "Scripts may not be named \"None\"." },\r
181         { ERR_HEXEN_COMPAT, "Attempt to use feature not supported by Hexen pcode with -h specified." },\r
182         { ERR_NONE, NULL }\r
183 };\r
184 \r
185 static FILE *ErrorFile;\r
186 static int ErrorCount;\r
187 static errorInfo_e ErrorFormat;\r
188 static char *ErrorSourceName;\r
189 static int ErrorSourceLine;\r
190 \r
191 // CODE --------------------------------------------------------------------\r
192 \r
193 //==========================================================================\r
194 //\r
195 // ERR_ErrorAt\r
196 //\r
197 //==========================================================================\r
198 \r
199 void ERR_ErrorAt(char *source, int line)\r
200 {\r
201         ErrorSourceName = source;\r
202         ErrorSourceLine = line;\r
203 }\r
204 \r
205 //==========================================================================\r
206 //\r
207 // ERR_Error\r
208 //\r
209 //==========================================================================\r
210 \r
211 void ERR_Error(error_t error, boolean info, ...)\r
212 {\r
213         va_list args;\r
214         va_start(args, info);\r
215         ERR_ErrorV(error, info, args);\r
216         va_end(args);\r
217 }\r
218 \r
219 //==========================================================================\r
220 //\r
221 // ERR_Exit\r
222 //\r
223 //==========================================================================\r
224 \r
225 void ERR_Exit(error_t error, boolean info, ...)\r
226 {\r
227         va_list args;\r
228         va_start(args, info);\r
229         ERR_ErrorV(error, info, args);\r
230         va_end(args);\r
231         ERR_Finish();\r
232 }\r
233 \r
234 //==========================================================================\r
235 //\r
236 // ERR_Finish\r
237 //\r
238 //==========================================================================\r
239 \r
240 void ERR_Finish(void)\r
241 {\r
242         if(ErrorFile)\r
243         {\r
244                 fclose(ErrorFile);\r
245                 ErrorFile = NULL;\r
246         }\r
247         if(ErrorCount)\r
248         {\r
249                 exit(1);\r
250         }\r
251 }\r
252 \r
253 //==========================================================================\r
254 //\r
255 // ShowError\r
256 //\r
257 //==========================================================================\r
258 \r
259 void ERR_ErrorV(error_t error, boolean info, va_list args)\r
260 {\r
261         char *text;\r
262         boolean showLine = NO;\r
263         static boolean showedInfo = NO;\r
264 \r
265         if(!ErrorFile)\r
266         {\r
267                 ErrorFile = fopen(ErrorFileName(), "w");\r
268         }\r
269         if(ErrorCount == 0)\r
270         {\r
271                 fprintf(stderr, "\n**** ERROR ****\n");\r
272         }\r
273         else if(ErrorCount == 100)\r
274         {\r
275                 eprintf("More than 100 errors. Can't continue.\n");\r
276                 ERR_Finish();\r
277         }\r
278         ErrorCount++;\r
279         if(info == YES)\r
280         {\r
281                 char *source;\r
282                 int line;\r
283 \r
284                 if(ErrorSourceName)\r
285                 {\r
286                         source = ErrorSourceName;\r
287                         line = ErrorSourceLine;\r
288                         ErrorSourceName = NULL;\r
289                 }\r
290                 else\r
291                 {\r
292                         source = tk_SourceName;\r
293                         line = tk_Line;\r
294                         showLine = YES;\r
295                 }\r
296                 if(showedInfo == NO)\r
297                 { // Output info compatible with older ACCs\r
298                   // for editors that expect it.\r
299                         showedInfo = YES;\r
300                         eprintf("Line %d in file \"%s\" ...\n", line, source);\r
301                 }\r
302                 if(ErrorFormat == ERRINFO_GCC)\r
303                 {\r
304                         eprintf("%s:%d: ", source, line);\r
305                 }\r
306                 else\r
307                 {\r
308                         eprintf("%s(%d) : ", source, line);\r
309                         if(error != ERR_NONE)\r
310                         {\r
311                                 eprintf("error %04d: ", error);\r
312                         }\r
313                 }\r
314         }\r
315         if(error != ERR_NONE)\r
316         {\r
317                 text = ErrorText(error);\r
318                 if(text != NULL)\r
319                 {\r
320                         veprintf(text, args);\r
321                 }\r
322                 eprintf("\n");\r
323                 if(showLine)\r
324                 {\r
325                         // deal with master source line and position indicator - Ty 07jan2000\r
326                         MasterSourceLine[MasterSourcePos] = '\0';  // pre-incremented already\r
327                         eprintf("> %s\n", MasterSourceLine);  // the string \r
328                         eprintf(">%*s\n", MasterSourcePos, "^");  // pointer to error\r
329                 }\r
330         }\r
331 #if 0\r
332         else\r
333         {\r
334                 va_list args2;\r
335                 va_start(va_arg(args,char*), args2);\r
336                 veprintf(va_arg(args,char*), args2);\r
337                 va_end(args2);\r
338         }\r
339 #endif\r
340 }\r
341 \r
342 //==========================================================================\r
343 //\r
344 // ERR_RemoveErrorFile\r
345 //\r
346 //==========================================================================\r
347 \r
348 void ERR_RemoveErrorFile(void)\r
349 {\r
350         remove(ErrorFileName());\r
351 }\r
352 \r
353 //==========================================================================\r
354 //\r
355 // ERR_ErrorFileName\r
356 //\r
357 //==========================================================================\r
358 \r
359 static char *ErrorFileName(void)\r
360 {\r
361         static char errFileName[MAX_FILE_NAME_LENGTH];\r
362 \r
363         strcpy(errFileName, acs_SourceFileName);\r
364         if(MS_StripFilename(errFileName) == NO)\r
365         {\r
366                 strcpy(errFileName, ERROR_FILE_NAME);\r
367         }\r
368         else\r
369         {\r
370                 strcat(errFileName, ERROR_FILE_NAME);\r
371         }\r
372         return errFileName;\r
373 }\r
374 \r
375 //==========================================================================\r
376 //\r
377 // ErrorText\r
378 //\r
379 //==========================================================================\r
380 \r
381 static char *ErrorText(error_t error)\r
382 {\r
383         int i;\r
384 \r
385         for(i = 0; ErrorNames[i].number != ERR_NONE; i++)\r
386         {\r
387                 if(error == ErrorNames[i].number)\r
388                 {\r
389                         return ErrorNames[i].name;\r
390                 }\r
391         }\r
392         return NULL;\r
393 }\r
394 \r
395 //==========================================================================\r
396 //\r
397 // eprintf\r
398 //\r
399 //==========================================================================\r
400 \r
401 static void eprintf(const char *fmt, ...)\r
402 {\r
403         va_list args;\r
404         va_start(args, fmt);\r
405         veprintf(fmt, args);\r
406         va_end(args);\r
407 }\r
408 \r
409 //==========================================================================\r
410 //\r
411 // veprintf\r
412 //\r
413 //==========================================================================\r
414 \r
415 static void veprintf(const char *fmt, va_list args)\r
416 {\r
417 #ifdef va_copy\r
418         va_list copy;\r
419         va_copy(copy, args);\r
420 #endif\r
421         vfprintf(stderr, fmt, args);\r
422         if(ErrorFile)\r
423         {\r
424 #ifdef va_copy\r
425                 vfprintf(ErrorFile, fmt, copy);\r
426 #else\r
427                 vfprintf(ErrorFile, fmt, args);\r
428 #endif\r
429         }\r
430 #ifdef va_copy\r
431         va_end(copy);\r
432 #endif\r
433 }\r