OSDN Git Service

- Moved Sqrt, FixedSqrt, and VectorLength to zspecial.acs.
[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_TOO_FEW_DIM_USED, "%s access needs %d more dimensions." },\r
164         { ERR_ARRAY_MAPVAR_ONLY, "Only map variables can be arrays." },\r
165         { ERR_NOT_AN_ARRAY, "%s is not an array." },\r
166         { ERR_MISSING_LBRACE_ARR, "Missing opening '{' in array initializer." },\r
167         { ERR_MISSING_RBRACE_ARR, "Missing closing '}' in array initializer." },\r
168         { ERR_LATENT_IN_FUNC, "Latent functions cannot be used inside functions." },\r
169         { ERR_LOCAL_VAR_SHADOWED, "A global identifier already has this name." },\r
170         { ERR_MULTIPLE_IMPORTS, "You can only #import one file." },\r
171         { ERR_IMPORT_IN_EXPORT, "You cannot #import from inside an imported file." },\r
172         { ERR_EXPORTER_NOT_FLAGGED, "A file that you #import must have a #library line." },\r
173         { ERR_TOO_MANY_IMPORTS, "Too many files imported." },\r
174         { ERR_NO_NEED_ARRAY_SIZE, "Only map arrays need a size." },\r
175         { ERR_NO_MULTIDIMENSIONS, "Only map arrays can have more than one dimension." },\r
176         { ERR_NEED_ARRAY_SIZE, "Missing array size." },\r
177         { ERR_DISCONNECT_NEEDS_1_ARG, "Disconnect scripts must have 1 argument." },\r
178         { ERR_UNCLOSED_WITH_ARGS, "Most special scripts must not have arguments." },\r
179         { ERR_NOT_A_CHAR_ARRAY, "%s has %d dimensions. Use %d subscripts to get a char array." },\r
180         { ERR_CANT_FIND_INCLUDE, "Couldn't find include file \"%s\"." },\r
181         { ERR_SCRIPT_NAMED_NONE, "Scripts may not be named \"None\"." },\r
182         { ERR_HEXEN_COMPAT, "Attempt to use feature not supported by Hexen." },\r
183         { ERR_NOT_HEXEN, "Cannot save; new features are not compatible with Hexen." },\r
184         { ERR_SPECIAL_RANGE, "Line specials with values higher than 255 require #nocompact." },\r
185         { ERR_NONE, NULL }\r
186 };\r
187 \r
188 static FILE *ErrorFile;\r
189 static int ErrorCount;\r
190 static errorInfo_e ErrorFormat;\r
191 static char *ErrorSourceName;\r
192 static int ErrorSourceLine;\r
193 \r
194 // CODE --------------------------------------------------------------------\r
195 \r
196 //==========================================================================\r
197 //\r
198 // ERR_ErrorAt\r
199 //\r
200 //==========================================================================\r
201 \r
202 void ERR_ErrorAt(char *source, int line)\r
203 {\r
204         ErrorSourceName = source;\r
205         ErrorSourceLine = line;\r
206 }\r
207 \r
208 //==========================================================================\r
209 //\r
210 // ERR_Error\r
211 //\r
212 //==========================================================================\r
213 \r
214 void ERR_Error(error_t error, boolean info, ...)\r
215 {\r
216         va_list args;\r
217         va_start(args, info);\r
218         ERR_ErrorV(error, info, args);\r
219         va_end(args);\r
220 }\r
221 \r
222 //==========================================================================\r
223 //\r
224 // ERR_Exit\r
225 //\r
226 //==========================================================================\r
227 \r
228 void ERR_Exit(error_t error, boolean info, ...)\r
229 {\r
230         va_list args;\r
231         va_start(args, info);\r
232         ERR_ErrorV(error, info, args);\r
233         va_end(args);\r
234         ERR_Finish();\r
235 }\r
236 \r
237 //==========================================================================\r
238 //\r
239 // ERR_Finish\r
240 //\r
241 //==========================================================================\r
242 \r
243 void ERR_Finish(void)\r
244 {\r
245         if(ErrorFile)\r
246         {\r
247                 fclose(ErrorFile);\r
248                 ErrorFile = NULL;\r
249         }\r
250         if(ErrorCount)\r
251         {\r
252                 exit(1);\r
253         }\r
254 }\r
255 \r
256 //==========================================================================\r
257 //\r
258 // ShowError\r
259 //\r
260 //==========================================================================\r
261 \r
262 void ERR_ErrorV(error_t error, boolean info, va_list args)\r
263 {\r
264         char *text;\r
265         boolean showLine = NO;\r
266         static boolean showedInfo = NO;\r
267 \r
268         if(!ErrorFile)\r
269         {\r
270                 ErrorFile = fopen(ErrorFileName(), "w");\r
271         }\r
272         if(ErrorCount == 0)\r
273         {\r
274                 fprintf(stderr, "\n**** ERROR ****\n");\r
275         }\r
276         else if(ErrorCount == 100)\r
277         {\r
278                 eprintf("More than 100 errors. Can't continue.\n");\r
279                 ERR_Finish();\r
280         }\r
281         ErrorCount++;\r
282         if(info == YES)\r
283         {\r
284                 char *source;\r
285                 int line;\r
286 \r
287                 if(ErrorSourceName)\r
288                 {\r
289                         source = ErrorSourceName;\r
290                         line = ErrorSourceLine;\r
291                         ErrorSourceName = NULL;\r
292                 }\r
293                 else\r
294                 {\r
295                         source = tk_SourceName;\r
296                         line = tk_Line;\r
297                         showLine = YES;\r
298                 }\r
299                 if(showedInfo == NO)\r
300                 { // Output info compatible with older ACCs\r
301                   // for editors that expect it.\r
302                         showedInfo = YES;\r
303                         eprintf("Line %d in file \"%s\" ...\n", line, source);\r
304                 }\r
305                 if(ErrorFormat == ERRINFO_GCC)\r
306                 {\r
307                         eprintf("%s:%d: ", source, line);\r
308                 }\r
309                 else\r
310                 {\r
311                         eprintf("%s(%d) : ", source, line);\r
312                         if(error != ERR_NONE)\r
313                         {\r
314                                 eprintf("error %04d: ", error);\r
315                         }\r
316                 }\r
317         }\r
318         if(error != ERR_NONE)\r
319         {\r
320                 text = ErrorText(error);\r
321                 if(text != NULL)\r
322                 {\r
323                         veprintf(text, args);\r
324                 }\r
325                 eprintf("\n");\r
326                 if(showLine)\r
327                 {\r
328                         // deal with master source line and position indicator - Ty 07jan2000\r
329                         MasterSourceLine[MasterSourcePos] = '\0';  // pre-incremented already\r
330                         eprintf("> %s\n", MasterSourceLine);  // the string \r
331                         eprintf(">%*s\n", MasterSourcePos, "^");  // pointer to error\r
332                 }\r
333         }\r
334 #if 0\r
335         else\r
336         {\r
337                 va_list args2;\r
338                 va_start(va_arg(args,char*), args2);\r
339                 veprintf(va_arg(args,char*), args2);\r
340                 va_end(args2);\r
341         }\r
342 #endif\r
343 }\r
344 \r
345 //==========================================================================\r
346 //\r
347 // ERR_RemoveErrorFile\r
348 //\r
349 //==========================================================================\r
350 \r
351 void ERR_RemoveErrorFile(void)\r
352 {\r
353         remove(ErrorFileName());\r
354 }\r
355 \r
356 //==========================================================================\r
357 //\r
358 // ERR_ErrorFileName\r
359 //\r
360 //==========================================================================\r
361 \r
362 static char *ErrorFileName(void)\r
363 {\r
364         static char errFileName[MAX_FILE_NAME_LENGTH];\r
365 \r
366         strcpy(errFileName, acs_SourceFileName);\r
367         if(MS_StripFilename(errFileName) == NO)\r
368         {\r
369                 strcpy(errFileName, ERROR_FILE_NAME);\r
370         }\r
371         else\r
372         {\r
373                 strcat(errFileName, ERROR_FILE_NAME);\r
374         }\r
375         return errFileName;\r
376 }\r
377 \r
378 //==========================================================================\r
379 //\r
380 // ErrorText\r
381 //\r
382 //==========================================================================\r
383 \r
384 static char *ErrorText(error_t error)\r
385 {\r
386         int i;\r
387 \r
388         for(i = 0; ErrorNames[i].number != ERR_NONE; i++)\r
389         {\r
390                 if(error == ErrorNames[i].number)\r
391                 {\r
392                         return ErrorNames[i].name;\r
393                 }\r
394         }\r
395         return NULL;\r
396 }\r
397 \r
398 //==========================================================================\r
399 //\r
400 // eprintf\r
401 //\r
402 //==========================================================================\r
403 \r
404 static void eprintf(const char *fmt, ...)\r
405 {\r
406         va_list args;\r
407         va_start(args, fmt);\r
408         veprintf(fmt, args);\r
409         va_end(args);\r
410 }\r
411 \r
412 //==========================================================================\r
413 //\r
414 // veprintf\r
415 //\r
416 //==========================================================================\r
417 \r
418 static void veprintf(const char *fmt, va_list args)\r
419 {\r
420 #ifdef va_copy\r
421         va_list copy;\r
422         va_copy(copy, args);\r
423 #endif\r
424         vfprintf(stderr, fmt, args);\r
425         if(ErrorFile)\r
426         {\r
427 #ifdef va_copy\r
428                 vfprintf(ErrorFile, fmt, copy);\r
429 #else\r
430                 vfprintf(ErrorFile, fmt, args);\r
431 #endif\r
432         }\r
433 #ifdef va_copy\r
434         va_end(copy);\r
435 #endif\r
436 }\r