OSDN Git Service

added SetActivatorToPlayer to zspecial.acs
[zandronum/zandronum-acc.git] / parse.c
1 \r
2 //**************************************************************************\r
3 //**\r
4 //** parse.c\r
5 //**\r
6 //**************************************************************************\r
7 \r
8 // HEADER FILES ------------------------------------------------------------\r
9 \r
10 #include <stdlib.h>\r
11 #include <string.h>\r
12 #include <ctype.h>\r
13 #include <malloc.h>\r
14 #include <stdio.h>\r
15 #include <assert.h>\r
16 \r
17 #include "common.h"\r
18 #include "parse.h"\r
19 #include "symbol.h"\r
20 #include "pcode.h"\r
21 #include "token.h"\r
22 #include "error.h"\r
23 #include "misc.h"\r
24 #include "strlist.h"\r
25 \r
26 // MACROS ------------------------------------------------------------------\r
27 \r
28 #define MAX_STATEMENT_DEPTH 128\r
29 #define MAX_BREAK 128\r
30 #define MAX_CONTINUE 128\r
31 #define MAX_CASE 128\r
32 #define EXPR_STACK_DEPTH 64\r
33 \r
34 // TYPES -------------------------------------------------------------------\r
35 \r
36 typedef enum\r
37 {\r
38         STMT_SCRIPT,\r
39         STMT_IF,\r
40         STMT_ELSE,\r
41         STMT_DO,\r
42         STMT_WHILEUNTIL,\r
43         STMT_SWITCH,\r
44         STMT_FOR\r
45 } statement_t;\r
46 \r
47 typedef struct\r
48 {\r
49         int level;\r
50         int addressPtr;\r
51 } breakInfo_t;\r
52 \r
53 typedef struct\r
54 {\r
55         int level;\r
56         int addressPtr;\r
57 } continueInfo_t;\r
58 \r
59 typedef struct\r
60 {\r
61         int level;\r
62         int value;\r
63         boolean isDefault;\r
64         int address;\r
65 } caseInfo_t;\r
66 \r
67 typedef struct prefunc_s\r
68 {\r
69         struct prefunc_s *next;\r
70         symbolNode_t *sym;\r
71         int address;\r
72         int argcount;\r
73         int line;\r
74         char *source;\r
75 } prefunc_t;\r
76 \r
77 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------\r
78 \r
79 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------\r
80 \r
81 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------\r
82 \r
83 static void CountScript(int type);\r
84 static void Outside(void);\r
85 static void OuterScript(void);\r
86 static void OuterFunction(void);\r
87 static void OuterMapVar(boolean local);\r
88 static void OuterWorldVar(boolean isGlobal);\r
89 static void OuterSpecialDef(void);\r
90 static void OuterDefine(boolean force);\r
91 static void OuterInclude(void);\r
92 static void OuterImport(void);\r
93 static boolean ProcessStatement(statement_t owner);\r
94 static void LeadingCompoundStatement(statement_t owner);\r
95 static void LeadingVarDeclare(void);\r
96 static void LeadingLineSpecial(boolean executewait);\r
97 static void LeadingFunction(boolean executewait);\r
98 static void LeadingIdentifier(void);\r
99 static void BuildPrintString(void);\r
100 static void ActionOnCharRange(boolean write);\r
101 static void LeadingStrcpy(void);\r
102 static void LeadingPrint(void);\r
103 static void LeadingHudMessage(void);\r
104 static void LeadingVarAssign(symbolNode_t *sym);\r
105 static pcd_t GetAssignPCD(tokenType_t token, symbolType_t symbol);\r
106 static void LeadingInternFunc(symbolNode_t *sym);\r
107 static void LeadingScriptFunc(symbolNode_t *sym);\r
108 static void LeadingSuspend(void);\r
109 static void LeadingTerminate(void);\r
110 static void LeadingRestart(void);\r
111 static void LeadingReturn(void);\r
112 static void LeadingIf(void);\r
113 static void LeadingFor(void);\r
114 static void LeadingWhileUntil(void);\r
115 static void LeadingDo(void);\r
116 static void LeadingSwitch(void);\r
117 static void LeadingCase(void);\r
118 static void LeadingDefault(void);\r
119 static void LeadingBreak(void);\r
120 static void LeadingContinue(void);\r
121 static void LeadingCreateTranslation(void);\r
122 static void LeadingIncDec(int token);\r
123 static void PushCase(int value, boolean isDefault);\r
124 static caseInfo_t *GetCaseInfo(void);\r
125 static int CaseInfoCmp(const void *a, const void *b);\r
126 static boolean DefaultInCurrent(void);\r
127 static void PushBreak(void);\r
128 static void WriteBreaks(void);\r
129 static boolean BreakAncestor(void);\r
130 static void PushContinue(void);\r
131 static void WriteContinues(int address);\r
132 static boolean ContinueAncestor(void);\r
133 static void ProcessInternFunc(symbolNode_t *sym);\r
134 static void ProcessScriptFunc(symbolNode_t *sym, boolean discardReturn);\r
135 static void EvalExpression(void);\r
136 static void ExprLevX(int level);\r
137 static void ExprLevA(void);\r
138 static void ExprFactor(void);\r
139 static void ConstExprFactor(void);\r
140 static void SendExprCommand(pcd_t pcd);\r
141 static void PushExStk(int value);\r
142 static int PopExStk(void);\r
143 static pcd_t TokenToPCD(tokenType_t token);\r
144 static pcd_t GetPushVarPCD(symbolType_t symType);\r
145 static pcd_t GetIncDecPCD(tokenType_t token, symbolType_t symbol);\r
146 static int EvalConstExpression(void);\r
147 static void ParseArrayIndices(symbolNode_t *sym, int requiredIndices);\r
148 static void InitializeArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS], int size);\r
149 static symbolNode_t *DemandSymbol(char *name);\r
150 static symbolNode_t *SpeculateSymbol(char *name, boolean hasReturn);\r
151 static symbolNode_t *SpeculateFunction(const char *name, boolean hasReturn);\r
152 static void UnspeculateFunction(symbolNode_t *sym);\r
153 static void AddScriptFuncRef(symbolNode_t *sym, int address, int argcount);\r
154 static void CheckForUndefinedFunctions(void);\r
155 static void SkipBraceBlock(int depth);\r
156 \r
157 // EXTERNAL DATA DECLARATIONS ----------------------------------------------\r
158 \r
159 // PUBLIC DATA DEFINITIONS -------------------------------------------------\r
160 \r
161 int pa_ScriptCount;\r
162 struct ScriptTypes *pa_TypedScriptCounts;\r
163 int pa_MapVarCount;\r
164 int pa_WorldVarCount;\r
165 int pa_GlobalVarCount;\r
166 int pa_WorldArrayCount;\r
167 int pa_GlobalArrayCount;\r
168 enum ImportModes ImportMode = IMPORT_None;\r
169 boolean ExporterFlagged;\r
170 boolean pa_ConstExprIsString;\r
171 \r
172 // PRIVATE DATA DEFINITIONS ------------------------------------------------\r
173 \r
174 static int ScriptVarCount;\r
175 static statement_t StatementHistory[MAX_STATEMENT_DEPTH];\r
176 static int StatementIndex;\r
177 static breakInfo_t BreakInfo[MAX_BREAK];\r
178 static int BreakIndex;\r
179 static continueInfo_t ContinueInfo[MAX_CONTINUE];\r
180 static int ContinueIndex;\r
181 static caseInfo_t CaseInfo[MAX_CASE];\r
182 static int CaseIndex;\r
183 static int StatementLevel;\r
184 static int ExprStack[EXPR_STACK_DEPTH];\r
185 static int ExprStackIndex;\r
186 static boolean ConstantExpression;\r
187 static symbolNode_t *InsideFunction;\r
188 static prefunc_t *FillinFunctions;\r
189 static prefunc_t **FillinFunctionsLatest = &FillinFunctions;\r
190 static boolean ArrayHasStrings;\r
191 \r
192 static int AdjustStmtLevel[] =\r
193 {\r
194         0,              // STMT_SCRIPT\r
195         0,              // STMT_IF\r
196         0,              // STMT_ELSE\r
197         1,              // STMT_DO\r
198         1,              // STMT_WHILEUNTIL\r
199         1,              // STMT_SWITCH\r
200         1               // STMT_FOR\r
201 };\r
202 \r
203 static boolean IsBreakRoot[] =\r
204 {\r
205         NO,             // STMT_SCRIPT\r
206         NO,             // STMT_IF\r
207         NO,             // STMT_ELSE\r
208         YES,    // STMT_DO\r
209         YES,    // STMT_WHILEUNTIL\r
210         YES,    // STMT_SWITCH\r
211         YES             // STMT_FOR\r
212 };\r
213 \r
214 static boolean IsContinueRoot[] =\r
215 {\r
216         NO,             // STMT_SCRIPT\r
217         NO,             // STMT_IF\r
218         NO,             // STMT_ELSE\r
219         YES,    // STMT_DO\r
220         YES,    // STMT_WHILEUNTIL\r
221         NO,             // STMT_SWITCH\r
222         YES             // STMT_FOR\r
223 };\r
224 \r
225 static tokenType_t LevAOps[] =\r
226 {\r
227         TK_ORLOGICAL,\r
228         TK_NONE\r
229 };\r
230 \r
231 static tokenType_t LevBOps[] =\r
232 {\r
233         TK_ANDLOGICAL,\r
234         TK_NONE\r
235 };\r
236 \r
237 static tokenType_t LevCOps[] =\r
238 {\r
239         TK_ORBITWISE,\r
240         TK_NONE\r
241 };\r
242 \r
243 static tokenType_t LevDOps[] =\r
244 {\r
245         TK_EORBITWISE,\r
246         TK_NONE\r
247 };\r
248 \r
249 static tokenType_t LevEOps[] =\r
250 {\r
251         TK_ANDBITWISE,\r
252         TK_NONE\r
253 };\r
254 \r
255 static tokenType_t LevFOps[] =\r
256 {\r
257         TK_EQ,\r
258         TK_NE,\r
259         TK_NONE\r
260 };\r
261 \r
262 static tokenType_t LevGOps[] =\r
263 {\r
264         TK_LT,\r
265         TK_LE,\r
266         TK_GT,\r
267         TK_GE,\r
268         TK_NONE\r
269 };\r
270 \r
271 static tokenType_t LevHOps[] =\r
272 {\r
273         TK_LSHIFT,\r
274         TK_RSHIFT,\r
275         TK_NONE\r
276 };\r
277 \r
278 static tokenType_t LevIOps[] =\r
279 {\r
280         TK_PLUS,\r
281         TK_MINUS,\r
282         TK_NONE\r
283 };\r
284 \r
285 static tokenType_t LevJOps[] =\r
286 {\r
287         TK_ASTERISK,\r
288         TK_SLASH,\r
289         TK_PERCENT,\r
290         TK_NONE\r
291 };\r
292 \r
293 static tokenType_t *OpsList[] =\r
294 {\r
295         LevAOps,\r
296         LevBOps,\r
297         LevCOps,\r
298         LevDOps,\r
299         LevEOps,\r
300         LevFOps,\r
301         LevGOps,\r
302         LevHOps,\r
303         LevIOps,\r
304         LevJOps,\r
305         NULL\r
306 };\r
307 \r
308 static tokenType_t AssignOps[] =\r
309 {\r
310         TK_ASSIGN,\r
311         TK_ADDASSIGN,\r
312         TK_SUBASSIGN,\r
313         TK_MULASSIGN,\r
314         TK_DIVASSIGN,\r
315         TK_MODASSIGN,\r
316         TK_ANDASSIGN,\r
317         TK_EORASSIGN,\r
318         TK_ORASSIGN,\r
319         TK_LSASSIGN,\r
320         TK_RSASSIGN,\r
321         TK_NONE\r
322 };\r
323 \r
324 static struct ScriptTypes ScriptCounts[] =\r
325 {\r
326         { "closed",                     0,                                                      0 },\r
327         { "open",                       OPEN_SCRIPTS_BASE,                      0 },\r
328         { "respawn",            RESPAWN_SCRIPTS_BASE,           0 },\r
329         { "death",                      DEATH_SCRIPTS_BASE,                     0 },\r
330         { "enter",                      ENTER_SCRIPTS_BASE,                     0 },\r
331         { "pickup",                     PICKUP_SCRIPTS_BASE,            0 },\r
332         { "bluereturn",         BLUE_RETURN_SCRIPTS_BASE,       0 },\r
333         { "redreturn",          RED_RETURN_SCRIPTS_BASE,        0 },\r
334         { "whitereturn",        WHITE_RETURN_SCRIPTS_BASE,      0 },\r
335         { "lightning",          LIGHTNING_SCRIPTS_BASE,         0 },\r
336         { "disconnect",         DISCONNECT_SCRIPTS_BASE,        0 },\r
337         { "unloading",          UNLOADING_SCRIPTS_BASE,         0 },\r
338         { "return",                     RETURN_SCRIPTS_BASE,            0 },\r
339         { "event",                      EVENT_SCRIPTS_BASE,                     0 },\r
340         { NULL,                         -1,                                                     0 }\r
341 };\r
342 \r
343 // CODE --------------------------------------------------------------------\r
344 \r
345 //==========================================================================\r
346 //\r
347 // PA_Parse\r
348 //\r
349 //==========================================================================\r
350 \r
351 void PA_Parse(void)\r
352 {\r
353         int i;\r
354 \r
355         pa_ScriptCount = 0;\r
356         pa_TypedScriptCounts = ScriptCounts;\r
357         for (i = 0; ScriptCounts[i].TypeName != NULL; i++)\r
358         {\r
359                 ScriptCounts[i].TypeCount = 0;\r
360         }\r
361         pa_MapVarCount = 0;\r
362         pa_WorldVarCount = 0;\r
363         pa_GlobalVarCount = 0;\r
364         pa_WorldArrayCount = 0;\r
365         pa_GlobalArrayCount = 0;\r
366         TK_NextToken();\r
367         Outside();\r
368         CheckForUndefinedFunctions();\r
369         ERR_Finish();\r
370 }\r
371 \r
372 //==========================================================================\r
373 //\r
374 // CountScript\r
375 //\r
376 //==========================================================================\r
377 \r
378 static void CountScript(int type)\r
379 {\r
380         int i;\r
381 \r
382         for (i = 0; ScriptCounts[i].TypeName != NULL; i++)\r
383         {\r
384                 if (ScriptCounts[i].TypeBase == type)\r
385                 {\r
386                         if (type != 0)\r
387                         {\r
388                                 MS_Message(MSG_DEBUG, "Script type: %s\n",\r
389                                         ScriptCounts[i].TypeName);\r
390                         }\r
391                         ScriptCounts[i].TypeCount++;\r
392                         return;\r
393                 }\r
394         }\r
395         return;\r
396 }\r
397 \r
398 //==========================================================================\r
399 //\r
400 // Outside\r
401 //\r
402 //==========================================================================\r
403 \r
404 static void Outside(void)\r
405 {\r
406         boolean done;\r
407 \r
408         done = NO;\r
409         while(done == NO)\r
410         {\r
411                 switch(tk_Token)\r
412                 {\r
413                 case TK_EOF:\r
414 \r
415                         done = YES;\r
416                         break;\r
417                 case TK_SCRIPT:\r
418                         OuterScript();\r
419                         break;\r
420                 case TK_FUNCTION:\r
421                         OuterFunction();\r
422                         break;\r
423                 case TK_INT:\r
424                 case TK_STR:\r
425                 case TK_BOOL:\r
426                         OuterMapVar(NO);\r
427                         break;\r
428                 case TK_WORLD:\r
429                         OuterWorldVar(NO);\r
430                         break;\r
431                 case TK_GLOBAL:\r
432                         OuterWorldVar(YES);\r
433                         break;\r
434                 case TK_SPECIAL:\r
435                         OuterSpecialDef();\r
436                         break;\r
437                 case TK_NUMBERSIGN:\r
438                         TK_NextToken();\r
439                         switch(tk_Token)\r
440                         {\r
441                         case TK_DEFINE:\r
442                                 OuterDefine(NO);\r
443                                 break;\r
444                         case TK_LIBDEFINE:\r
445                                 OuterDefine(YES);\r
446                                 break;\r
447                         case TK_INCLUDE:\r
448                                 OuterInclude();\r
449                                 break;\r
450                         case TK_NOCOMPACT:\r
451                                 if(ImportMode != IMPORT_Importing)\r
452                                 {\r
453                                         if(pc_Address != 8)\r
454                                         {\r
455                                                 ERR_Error(ERR_NOCOMPACT_NOT_HERE, YES);\r
456                                         }\r
457                                         MS_Message(MSG_DEBUG, "Forcing NoShrink\n");\r
458                                         pc_NoShrink = TRUE;\r
459                                 }\r
460                                 TK_NextToken();\r
461                                 break;\r
462                         case TK_WADAUTHOR:\r
463                                 if(ImportMode != IMPORT_Importing)\r
464                                 {\r
465                                         MS_Message(MSG_DEBUG, "Will write WadAuthor-compatible object\n");\r
466                                         MS_Message(MSG_NORMAL, "You don't need to use #wadauthor anymore.\n");\r
467                                         pc_WadAuthor = TRUE;\r
468                                 }\r
469                                 TK_NextToken();\r
470                                 break;\r
471                         case TK_NOWADAUTHOR:\r
472                                 if(ImportMode != IMPORT_Importing)\r
473                                 {\r
474                                         MS_Message(MSG_DEBUG, "Will write WadAuthor-incompatible object\n");\r
475                                         pc_WadAuthor = FALSE;\r
476                                 }\r
477                                 TK_NextToken();\r
478                                 break;\r
479                         case TK_ENCRYPTSTRINGS:\r
480                                 if(ImportMode != IMPORT_Importing)\r
481                                 {\r
482                                         MS_Message(MSG_DEBUG, "Strings will be encrypted\n");\r
483                                         pc_EncryptStrings = TRUE;\r
484                                         if(pc_EnforceHexen)\r
485                                         {\r
486                                                 ERR_Error(ERR_HEXEN_COMPAT, YES);\r
487                                         }\r
488                                 }\r
489                                 TK_NextToken();\r
490                                 break;\r
491                         case TK_IMPORT:\r
492                                 OuterImport();\r
493                                 break;\r
494                         case TK_LIBRARY:\r
495                                 TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND);\r
496                                 if(ImportMode == IMPORT_None)\r
497                                 {\r
498                                         MS_Message(MSG_DEBUG, "Allocations modified for exporting\n");\r
499                                         ImportMode = IMPORT_Exporting;\r
500                                 }\r
501                                 else if(ImportMode == IMPORT_Importing)\r
502                                 {\r
503                                         PC_AddImport(tk_String);\r
504                                         ExporterFlagged = YES;\r
505                                 }\r
506                                 TK_NextToken();\r
507                                 break;\r
508                         default:\r
509                                 ERR_Error(ERR_INVALID_DIRECTIVE, YES);\r
510                                 TK_SkipLine();\r
511                                 break;\r
512                         }\r
513                         break;\r
514                 default:\r
515                         ERR_Exit(ERR_INVALID_DECLARATOR, YES, NULL);\r
516                         break;\r
517                 }\r
518         }\r
519 }\r
520 \r
521 //==========================================================================\r
522 //\r
523 // OuterScript\r
524 //\r
525 //==========================================================================\r
526 \r
527 static void OuterScript(void)\r
528 {\r
529         int scriptNumber;\r
530         symbolNode_t *sym;\r
531         int scriptType, scriptFlags;\r
532 \r
533         MS_Message(MSG_DEBUG, "---- OuterScript ----\n");\r
534         BreakIndex = 0;\r
535         CaseIndex = 0;\r
536         StatementLevel = 0;\r
537         ScriptVarCount = 0;\r
538         SY_FreeLocals();\r
539         TK_NextToken();\r
540 \r
541         if(ImportMode == IMPORT_Importing)\r
542         {\r
543                 // When importing, the script number is not recorded, because\r
544                 // it might be a #define that is not included by the main .acs\r
545                 // file, so processing it would generate a syntax error.\r
546                 SkipBraceBlock(0);\r
547                 TK_NextToken();\r
548                 return;\r
549         }\r
550 \r
551         // [RH] If you want to use script 0, it must be written as <<0>>.\r
552         // This is to avoid using it accidentally, since ZDoom uses script\r
553         // 0 to implement many of the Strife-specific line specials.\r
554 \r
555         if(tk_Token == TK_LSHIFT)\r
556         {\r
557                 TK_NextTokenMustBe(TK_NUMBER, ERR_SCRIPT_OUT_OF_RANGE);\r
558                 if(tk_Number != 0)\r
559                 {\r
560                         ERR_Exit(ERR_SCRIPT_OUT_OF_RANGE, YES, NULL);\r
561                 }\r
562                 TK_NextTokenMustBe(TK_RSHIFT, ERR_SCRIPT_OUT_OF_RANGE);\r
563                 TK_NextToken();\r
564                 scriptNumber = 0;\r
565         }\r
566         else if(tk_Token == TK_STRING)\r
567         { // Named scripts start counting at -1 and go down from there.\r
568                 if(strcasecmp("None", tk_String) == 0)\r
569                 {\r
570                         ERR_Error(ERR_SCRIPT_NAMED_NONE, YES, NULL);\r
571                 }\r
572                 scriptNumber = -1 - STR_FindInListInsensitive(STRLIST_NAMEDSCRIPTS, tk_String);\r
573                 TK_NextToken();\r
574         }\r
575         else\r
576         {\r
577                 scriptNumber = EvalConstExpression();\r
578                 if(scriptNumber < 1 || scriptNumber > 32767)\r
579                 {\r
580                         TK_Undo();\r
581                         ERR_Error(ERR_SCRIPT_OUT_OF_RANGE, YES, NULL);\r
582                         SkipBraceBlock(0);\r
583                         TK_NextToken();\r
584                         return;\r
585                 }\r
586         }\r
587         if (scriptNumber >= 0)\r
588         {\r
589                 MS_Message(MSG_DEBUG, "Script number: %d\n", scriptNumber);\r
590         }\r
591         else\r
592         {\r
593                 MS_Message(MSG_DEBUG, "Script name: %s (%d)\n",\r
594                         STR_GetString(STRLIST_NAMEDSCRIPTS, -scriptNumber - 1),\r
595                         scriptNumber);\r
596         }\r
597         scriptType = 0;\r
598         scriptFlags = 0;\r
599         if(tk_Token == TK_LPAREN)\r
600         {\r
601                 if(TK_NextToken() == TK_VOID)\r
602                 {\r
603                         TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
604                 }\r
605                 else\r
606                 {\r
607                         TK_Undo();\r
608                         do\r
609                         {\r
610                                 TK_NextTokenMustBe(TK_INT, ERR_BAD_VAR_TYPE);\r
611                                 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);\r
612                                 if(ScriptVarCount == 4)\r
613                                 {\r
614                                         ERR_Error(ERR_TOO_MANY_SCRIPT_ARGS, YES);\r
615                                 }\r
616                                 if(SY_FindLocal(tk_String) != NULL)\r
617                                 { // Redefined\r
618                                         ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);\r
619                                 }\r
620                                 else if(ScriptVarCount < 4)\r
621                                 {\r
622                                         sym = SY_InsertLocal(tk_String, SY_SCRIPTVAR);\r
623                                         sym->info.var.index = ScriptVarCount;\r
624                                         ScriptVarCount++;\r
625                                 }\r
626                                 TK_NextToken();\r
627                         } while(tk_Token == TK_COMMA);\r
628                         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
629                 }\r
630                 TK_NextToken();\r
631                 switch(tk_Token)\r
632                 {\r
633                 case TK_DISCONNECT:\r
634                         scriptType = DISCONNECT_SCRIPTS_BASE;\r
635                         if(ScriptVarCount != 1)\r
636                         {\r
637                                 ERR_Error(ERR_DISCONNECT_NEEDS_1_ARG, YES);\r
638                         }\r
639                         break;\r
640 \r
641                 case TK_OPEN:\r
642                 case TK_RESPAWN:\r
643                 case TK_DEATH:\r
644                 case TK_ENTER:\r
645                 case TK_PICKUP:\r
646                 case TK_BLUERETURN:\r
647                 case TK_REDRETURN:\r
648                 case TK_WHITERETURN:\r
649                 case TK_LIGHTNING:\r
650                 case TK_UNLOADING:\r
651                 case TK_RETURN:\r
652                         ERR_Error(ERR_UNCLOSED_WITH_ARGS, YES);\r
653                         break;\r
654 \r
655                 case TK_EVENT:\r
656                         scriptType = EVENT_SCRIPTS_BASE;\r
657                         if(ScriptVarCount != 3)\r
658                         {\r
659                                 ERR_Error(ERR_EVENT_NEEDS_3_ARG, YES);\r
660                         }\r
661                         break;\r
662 \r
663                 default:\r
664                         TK_Undo();\r
665                 }\r
666                 MS_Message(MSG_DEBUG, "Script type: %s (%d %s)\n",\r
667                         scriptType == 0 ? "closed" : "disconnect",\r
668                         ScriptVarCount, ScriptVarCount == 1 ? "arg" : "args");\r
669         }\r
670         else switch (tk_Token)\r
671         {\r
672         case TK_OPEN:\r
673                 scriptType = OPEN_SCRIPTS_BASE;\r
674                 break;\r
675 \r
676         case TK_RESPAWN:        // [BC]\r
677                 scriptType = RESPAWN_SCRIPTS_BASE;\r
678                 break;\r
679 \r
680         case TK_DEATH:          // [BC]\r
681                 scriptType = DEATH_SCRIPTS_BASE;\r
682                 break;\r
683 \r
684         case TK_ENTER:          // [BC]\r
685                 scriptType = ENTER_SCRIPTS_BASE;\r
686                 break;\r
687 \r
688         case TK_RETURN:\r
689                 scriptType = RETURN_SCRIPTS_BASE;\r
690                 break;\r
691 \r
692         case TK_PICKUP:         // [BC]\r
693                 scriptType = PICKUP_SCRIPTS_BASE;\r
694                 break;\r
695 \r
696         case TK_BLUERETURN:     // [BC]\r
697                 scriptType = BLUE_RETURN_SCRIPTS_BASE;\r
698                 break;\r
699 \r
700         case TK_REDRETURN:      // [BC]\r
701                 scriptType = RED_RETURN_SCRIPTS_BASE;\r
702                 break;\r
703 \r
704         case TK_WHITERETURN:    // [BC]\r
705                 scriptType = WHITE_RETURN_SCRIPTS_BASE;\r
706                 break;\r
707 \r
708         case TK_LIGHTNING:\r
709                 scriptType = LIGHTNING_SCRIPTS_BASE;\r
710                 break;\r
711 \r
712         case TK_UNLOADING:\r
713                 scriptType = UNLOADING_SCRIPTS_BASE;\r
714                 break;\r
715 \r
716         case TK_DISCONNECT:\r
717                 scriptType = DISCONNECT_SCRIPTS_BASE;\r
718                 ERR_Error (ERR_DISCONNECT_NEEDS_1_ARG, YES);\r
719                 break;\r
720 \r
721         case TK_EVENT:  // [BB]\r
722                 scriptType = EVENT_SCRIPTS_BASE;\r
723                 ERR_Error (ERR_EVENT_NEEDS_3_ARG, YES);\r
724                 break;\r
725 \r
726         default:\r
727                 ERR_Error(ERR_BAD_SCRIPT_DECL, YES);\r
728                 SkipBraceBlock(0);\r
729                 TK_NextToken();\r
730                 return;\r
731         }\r
732         TK_NextToken();\r
733         if(tk_Token == TK_NET)\r
734         {\r
735                 scriptFlags |= NET_SCRIPT_FLAG;\r
736                 TK_NextToken();\r
737         }\r
738         // [BB] If NET and CLIENTSIDE are specified, this construction can only parse\r
739         // "NET CLIENTSIDE" but not "CLIENTSIDE NET".\r
740         if(tk_Token == TK_CLIENTSIDE)\r
741         {\r
742                 scriptFlags |= CLIENTSIDE_SCRIPT_FLAG;\r
743                 TK_NextToken();\r
744         }\r
745         CountScript(scriptType);\r
746         PC_AddScript(scriptNumber, scriptType, scriptFlags, ScriptVarCount);\r
747         pc_LastAppendedCommand = PCD_NOP;\r
748         if(ProcessStatement(STMT_SCRIPT) == NO)\r
749         {\r
750                 ERR_Error(ERR_INVALID_STATEMENT, YES);\r
751         }\r
752         if(pc_LastAppendedCommand != PCD_TERMINATE)\r
753         {\r
754                 PC_AppendCmd(PCD_TERMINATE);\r
755         }\r
756         PC_SetScriptVarCount(scriptNumber, scriptType, ScriptVarCount);\r
757         pa_ScriptCount++;\r
758 }\r
759 \r
760 //==========================================================================\r
761 //\r
762 // OuterFunction\r
763 //\r
764 //==========================================================================\r
765 \r
766 static void OuterFunction(void)\r
767 {\r
768         enum ImportModes importing;\r
769         boolean hasReturn;\r
770         symbolNode_t *sym;\r
771         int defLine;\r
772 \r
773         MS_Message(MSG_DEBUG, "---- OuterFunction ----\n");\r
774         importing = ImportMode;\r
775         BreakIndex = 0;\r
776         CaseIndex = 0;\r
777         StatementLevel = 0;\r
778         ScriptVarCount = 0;\r
779         SY_FreeLocals();\r
780         TK_NextToken();\r
781         if(tk_Token != TK_STR && tk_Token != TK_INT &&\r
782                 tk_Token != TK_VOID && tk_Token != TK_BOOL)\r
783         {\r
784                 ERR_Error(ERR_BAD_RETURN_TYPE, YES);\r
785                 tk_Token = TK_VOID;\r
786         }\r
787         hasReturn = tk_Token != TK_VOID;\r
788         TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);\r
789         sym = SY_FindGlobal(tk_String);\r
790         if(sym != NULL)\r
791         {\r
792                 if(sym->type != SY_SCRIPTFUNC)\r
793                 { // Redefined\r
794                         ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);\r
795                         SkipBraceBlock(0);\r
796                         TK_NextToken();\r
797                         return;\r
798                 }\r
799                 if(!sym->info.scriptFunc.predefined)\r
800                 {\r
801                         ERR_Error(ERR_FUNCTION_ALREADY_DEFINED, YES);\r
802                         ERR_ErrorAt(sym->info.scriptFunc.sourceName, sym->info.scriptFunc.sourceLine);\r
803                         ERR_Error(ERR_NONE, YES, "Previous definition was here.");\r
804                         SkipBraceBlock(0);\r
805                         TK_NextToken();\r
806                         return;\r
807                 }\r
808                 if(sym->info.scriptFunc.hasReturnValue && !hasReturn)\r
809                 {\r
810                         ERR_Error(ERR_PREVIOUS_NOT_VOID, YES);\r
811                         ERR_ErrorAt(sym->info.scriptFunc.sourceName, sym->info.scriptFunc.sourceLine);\r
812                         ERR_Error(ERR_NONE, YES, "Previous use was here.");\r
813                 }\r
814         }\r
815         else\r
816         {\r
817                 sym = SY_InsertGlobal(tk_String, SY_SCRIPTFUNC);\r
818                 sym->info.scriptFunc.address = (importing == IMPORT_Importing ? 0 : pc_Address);\r
819                 sym->info.scriptFunc.predefined = NO;\r
820         }\r
821         defLine = tk_Line;\r
822 \r
823         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
824         if(TK_NextToken() == TK_VOID)\r
825         {\r
826                 TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
827         }\r
828         else\r
829         {\r
830                 TK_Undo();\r
831                 do\r
832                 {\r
833                         symbolType_t type;\r
834                         symbolNode_t *local;\r
835 \r
836                         TK_NextToken();\r
837 /*                      if(tk_Token != TK_INT && tk_Token != TK_STR && tk_Token != TK_BOOL)\r
838                         {\r
839                                 ERR_Error(ERR_BAD_VAR_TYPE, YES);\r
840                                 tk_Token = TK_INT;\r
841                         }\r
842 */                      if(tk_Token == TK_INT || tk_Token == TK_BOOL)\r
843                         {\r
844                                 if(TK_NextToken() == TK_LBRACKET)\r
845                                 {\r
846                                         TK_NextTokenMustBe(TK_RBRACKET, ERR_BAD_VAR_TYPE);\r
847                                         type = SY_SCRIPTALIAS;\r
848                                 }\r
849                                 else\r
850                                 {\r
851                                         TK_Undo();\r
852                                         type = SY_SCRIPTVAR;\r
853                                 }\r
854                         }\r
855                         else if(tk_Token == TK_STR)\r
856                         {\r
857                                 type = SY_SCRIPTVAR;\r
858                         }\r
859                         else\r
860                         {\r
861                                 type = SY_SCRIPTVAR;\r
862                                 ERR_Error(ERR_BAD_VAR_TYPE, YES);\r
863                                 tk_Token = TK_INT;\r
864                         }\r
865                         TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);\r
866                         if(SY_FindLocal(tk_String) != NULL)\r
867                         { // Redefined\r
868                                 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);\r
869                         }\r
870                         else\r
871                         {\r
872                                 local = SY_InsertLocal(tk_String, type);\r
873                                 local->info.var.index = ScriptVarCount;\r
874                                 ScriptVarCount++;\r
875                         }\r
876                         TK_NextToken();\r
877                 } while(tk_Token == TK_COMMA);\r
878                 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
879         }\r
880 \r
881         sym->info.scriptFunc.sourceLine = defLine;\r
882         sym->info.scriptFunc.sourceName = tk_SourceName;\r
883         sym->info.scriptFunc.argCount = ScriptVarCount;\r
884         sym->info.scriptFunc.address = (importing == IMPORT_Importing) ? 0 : pc_Address;\r
885         sym->info.scriptFunc.hasReturnValue = hasReturn;\r
886 \r
887         if(importing == IMPORT_Importing)\r
888         {\r
889                 SkipBraceBlock(0);\r
890                 TK_NextToken();\r
891                 sym->info.scriptFunc.predefined = NO;\r
892                 sym->info.scriptFunc.varCount = ScriptVarCount;\r
893                 return;\r
894         }\r
895 \r
896         TK_NextToken();\r
897         InsideFunction = sym;\r
898         pc_LastAppendedCommand = PCD_NOP;\r
899 \r
900         // If we just call ProcessStatement(STMT_SCRIPT), and this function\r
901         // needs to return a value but the last pcode output was not a return,\r
902         // then the line number given in the error can be confusing because it\r
903         // is beyond the end of the function. To avoid this, we process the\r
904         // compound statement ourself and check if it returned something\r
905         // before checking for the '}'. If a return is required, then the error\r
906         // line will be shown as the one that contains the '}' (if present).\r
907 \r
908         TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE);\r
909         TK_NextToken();\r
910         do {} while(ProcessStatement(STMT_SCRIPT) == YES);\r
911 \r
912         if(pc_LastAppendedCommand != PCD_RETURNVOID &&\r
913            pc_LastAppendedCommand != PCD_RETURNVAL)\r
914         {\r
915                 if(hasReturn)\r
916                 {\r
917                         TK_Undo();\r
918                         ERR_Error(ERR_MUST_RETURN_A_VALUE, YES, NULL);\r
919                 }\r
920                 PC_AppendCmd(PCD_RETURNVOID);\r
921         }\r
922 \r
923         TK_TokenMustBe(TK_RBRACE, ERR_INVALID_STATEMENT);\r
924         TK_NextToken();\r
925 \r
926         sym->info.scriptFunc.predefined = NO;\r
927         sym->info.scriptFunc.varCount = ScriptVarCount -\r
928                 sym->info.scriptFunc.argCount;\r
929         PC_AddFunction(sym);\r
930         UnspeculateFunction(sym);\r
931         InsideFunction = NULL;\r
932 }\r
933 \r
934 //==========================================================================\r
935 //\r
936 // OuterMapVar\r
937 //\r
938 //==========================================================================\r
939 \r
940 static void OuterMapVar(boolean local)\r
941 {\r
942         symbolNode_t *sym = NULL;\r
943         int index, i;\r
944 \r
945         MS_Message(MSG_DEBUG, "---- %s ----\n", local ? "LeadingStaticVarDeclare" : "OuterMapVar");\r
946         do\r
947         {\r
948                 if(pa_MapVarCount >= MAX_MAP_VARIABLES)\r
949                 {\r
950                         ERR_Error(ERR_TOO_MANY_MAP_VARS, YES);\r
951                         index = MAX_MAP_VARIABLES;\r
952                 }\r
953                 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);\r
954                 sym = local ? SY_FindLocal(tk_String)\r
955                                         : SY_FindGlobal(tk_String);\r
956                 if(sym != NULL)\r
957                 { // Redefined\r
958                         ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);\r
959                         index = MAX_MAP_VARIABLES;\r
960                 }\r
961                 else\r
962                 {\r
963                         sym = local ? SY_InsertLocal(tk_String, SY_MAPVAR)\r
964                                                 : SY_InsertGlobal(tk_String, SY_MAPVAR);\r
965                         if(ImportMode == IMPORT_Importing)\r
966                         {\r
967                                 sym->info.var.index = index = 0;\r
968                         }\r
969                         else\r
970                         {\r
971                                 sym->info.var.index = index = pa_MapVarCount;\r
972                                 if (!local)\r
973                                 { // Local variables are not exported\r
974                                         PC_NameMapVariable(index, sym);\r
975                                 }\r
976                                 pa_MapVarCount++;\r
977                         }\r
978                 }\r
979                 TK_NextToken();\r
980                 if(tk_Token == TK_ASSIGN)\r
981                 {\r
982                         if(ImportMode != IMPORT_Importing)\r
983                         {\r
984                                 TK_NextToken();\r
985                                 PC_PutMapVariable (index, EvalConstExpression());\r
986                         }\r
987                         else\r
988                         {\r
989                                 // When importing, skip the initializer, because we don't care.\r
990                                 do\r
991                                 {\r
992                                         TK_NextToken();\r
993                                 } while(tk_Token != TK_COMMA && tk_Token != TK_SEMICOLON);\r
994                         }\r
995                 }\r
996                 else if(tk_Token == TK_LBRACKET)\r
997                 {\r
998                         int size = 0;\r
999                         int ndim = 0;\r
1000                         int dims[MAX_ARRAY_DIMS];\r
1001 \r
1002                         memset(dims, 0, sizeof(dims));\r
1003 \r
1004                         while(tk_Token == TK_LBRACKET)\r
1005                         {\r
1006                                 if(ndim == MAX_ARRAY_DIMS)\r
1007                                 {\r
1008                                         ERR_Error(ERR_TOO_MANY_ARRAY_DIMS, YES);\r
1009                                         do\r
1010                                         {\r
1011                                                 TK_NextToken();\r
1012                                         } while(tk_Token != TK_COMMA && tk_Token != TK_SEMICOLON);\r
1013                                         break;\r
1014                                 }\r
1015                                 TK_NextToken();\r
1016                                 if (tk_Token == TK_RBRACKET)\r
1017                                 {\r
1018                                         ERR_Error(ERR_NEED_ARRAY_SIZE, YES);\r
1019                                 }\r
1020                                 else\r
1021                                 {\r
1022                                         dims[ndim] = EvalConstExpression();\r
1023                                         if(dims[ndim] == 0)\r
1024                                         {\r
1025                                                 ERR_Error(ERR_ZERO_DIMENSION, YES);\r
1026                                                 dims[ndim] = 1;\r
1027                                         }\r
1028                                         if(ndim == 0)\r
1029                                         {\r
1030                                                 size = dims[ndim];\r
1031                                         }\r
1032                                         else\r
1033                                         {\r
1034                                                 size *= dims[ndim];\r
1035                                         }\r
1036                                 }\r
1037                                 ndim++;\r
1038                                 TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET);\r
1039                                 TK_NextToken();\r
1040                         }\r
1041                         if(sym != NULL)\r
1042                         {\r
1043                                 if(ImportMode != IMPORT_Importing)\r
1044                                 {\r
1045                                         PC_AddArray(index, size);\r
1046                                 }\r
1047                                 MS_Message(MSG_DEBUG, "%s changed to an array of size %d\n", sym->name, size);\r
1048                                 sym->type = SY_MAPARRAY;\r
1049                                 sym->info.array.index = index;\r
1050                                 sym->info.array.ndim = ndim;\r
1051                                 sym->info.array.size = size;\r
1052                                 if(ndim > 0)\r
1053                                 {\r
1054                                         sym->info.array.dimensions[ndim-1] = 1;\r
1055                                         for(i = ndim - 2; i >= 0; --i)\r
1056                                         {\r
1057                                                 sym->info.array.dimensions[i] =\r
1058                                                         sym->info.array.dimensions[i+1] * dims[i+1];\r
1059                                         }\r
1060                                 }\r
1061                                 MS_Message(MSG_DEBUG, " - with multipliers ");\r
1062                                 for(i = 0; i < ndim; ++i)\r
1063                                 {\r
1064                                         MS_Message(MSG_DEBUG, "[%d]", sym->info.array.dimensions[i]);\r
1065                                 }\r
1066                                 MS_Message(MSG_DEBUG, "\n");\r
1067                                 if(tk_Token == TK_ASSIGN)\r
1068                                 {\r
1069                                         InitializeArray(sym, dims, size);\r
1070                                 }\r
1071                         }\r
1072                 }\r
1073         } while(tk_Token == TK_COMMA);\r
1074         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1075         TK_NextToken();\r
1076 }\r
1077 \r
1078 //==========================================================================\r
1079 //\r
1080 // OuterWorldVar\r
1081 //\r
1082 //==========================================================================\r
1083 \r
1084 static void OuterWorldVar(boolean isGlobal)\r
1085 {\r
1086         int index;\r
1087         symbolNode_t *sym;\r
1088 \r
1089         MS_Message(MSG_DEBUG, "---- Outer%sVar ----\n", isGlobal ? "Global" : "World");\r
1090         if(TK_NextToken() != TK_INT)\r
1091         {\r
1092                 if(tk_Token != TK_BOOL)\r
1093                 {\r
1094                         TK_TokenMustBe(TK_STR, ERR_BAD_VAR_TYPE);\r
1095                 }\r
1096         }\r
1097         do\r
1098         {\r
1099                 TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_WVAR_INDEX);\r
1100                 if(tk_Number >= (isGlobal ? MAX_GLOBAL_VARIABLES : MAX_WORLD_VARIABLES))\r
1101                 {\r
1102                         ERR_Error(ERR_BAD_WVAR_INDEX+isGlobal, YES);\r
1103                         index = 0;\r
1104                 }\r
1105                 else\r
1106                 {\r
1107                         index = tk_Number;\r
1108                 }\r
1109                 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_WVAR_COLON+isGlobal);\r
1110                 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);\r
1111                 if(SY_FindGlobal(tk_String) != NULL)\r
1112                 { // Redefined\r
1113                         ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);\r
1114                 }\r
1115                 else\r
1116                 {\r
1117                         TK_NextToken();\r
1118                         if(tk_Token == TK_LBRACKET)\r
1119                         {\r
1120                                 TK_NextToken ();\r
1121                                 if(tk_Token != TK_RBRACKET)\r
1122                                 {\r
1123                                         ERR_Error(ERR_NO_NEED_ARRAY_SIZE, YES);\r
1124                                         TK_SkipPast(TK_RBRACKET);\r
1125                                 }\r
1126                                 else\r
1127                                 {\r
1128                                         TK_NextToken();\r
1129                                 }\r
1130                                 if(tk_Token == TK_LBRACKET)\r
1131                                 {\r
1132                                         ERR_Error(ERR_NO_MULTIDIMENSIONS, YES);\r
1133                                         do\r
1134                                         {\r
1135                                                 TK_SkipPast(TK_RBRACKET);\r
1136                                         }\r
1137                                         while(tk_Token == TK_LBRACKET);\r
1138                                 }\r
1139                                 sym = SY_InsertGlobal(tk_String, isGlobal ? SY_GLOBALARRAY : SY_WORLDARRAY);\r
1140                                 sym->info.array.index = index;\r
1141                                 sym->info.array.ndim = 1;\r
1142                                 sym->info.array.size = 0x7fffffff;      // not used\r
1143                                 memset(sym->info.array.dimensions, 0, sizeof(sym->info.array.dimensions));\r
1144 \r
1145                                 if (isGlobal)\r
1146                                         pa_GlobalArrayCount++;\r
1147                                 else\r
1148                                         pa_WorldArrayCount++;\r
1149                         }\r
1150                         else\r
1151                         {\r
1152                                 sym = SY_InsertGlobal(tk_String, isGlobal ? SY_GLOBALVAR : SY_WORLDVAR);\r
1153                                 sym->info.var.index = index;\r
1154                                 if (isGlobal)\r
1155                                         pa_GlobalVarCount++;\r
1156                                 else\r
1157                                         pa_WorldVarCount++;\r
1158                         }\r
1159                 }\r
1160         } while(tk_Token == TK_COMMA);\r
1161         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1162         TK_NextToken();\r
1163 }\r
1164 \r
1165 //==========================================================================\r
1166 //\r
1167 // OuterSpecialDef\r
1168 //\r
1169 //==========================================================================\r
1170 \r
1171 static void OuterSpecialDef(void)\r
1172 {\r
1173         int special;\r
1174         symbolNode_t *sym;\r
1175 \r
1176         MS_Message(MSG_DEBUG, "---- OuterSpecialDef ----\n");\r
1177         if(ImportMode == IMPORT_Importing)\r
1178         {\r
1179                 // No need to process special definitions when importing.\r
1180                 TK_SkipPast(TK_SEMICOLON);\r
1181         }\r
1182         else\r
1183         {\r
1184                 do\r
1185                 {\r
1186                         if (TK_NextToken() == TK_MINUS)\r
1187                         {\r
1188                                 TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_VAL);\r
1189                                 special = -tk_Number;\r
1190                         }\r
1191                         else\r
1192                         {\r
1193                                 TK_TokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_VAL);\r
1194                                 special = tk_Number;\r
1195                         }\r
1196                         TK_NextTokenMustBe(TK_COLON, ERR_MISSING_SPEC_COLON);\r
1197                         TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);\r
1198                         sym = SY_InsertGlobalUnique(tk_String, SY_SPECIAL);\r
1199                         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
1200                         TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_ARGC);\r
1201                         sym->info.special.value = special;\r
1202                         sym->info.special.argCount = tk_Number | (tk_Number << 16);\r
1203                         TK_NextToken();\r
1204                         if(tk_Token == TK_COMMA)\r
1205                         { // Get maximum arg count\r
1206                                 TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_ARGC);\r
1207                                 sym->info.special.argCount =\r
1208                                         (sym->info.special.argCount & 0xffff) | (tk_Number << 16);\r
1209                         }\r
1210                         else\r
1211                         {\r
1212                                 TK_Undo ();\r
1213                         }\r
1214                         TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
1215                         TK_NextToken();\r
1216                 } while(tk_Token == TK_COMMA);\r
1217                 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1218                 TK_NextToken();\r
1219         }\r
1220 }\r
1221 \r
1222 //==========================================================================\r
1223 //\r
1224 // OuterDefine\r
1225 //\r
1226 //==========================================================================\r
1227 \r
1228 static void OuterDefine(boolean force)\r
1229 {\r
1230         int value;\r
1231         symbolNode_t *sym;\r
1232 \r
1233         MS_Message(MSG_DEBUG, "---- OuterDefine %s----\n",\r
1234                 force ? "(forced) " : "");\r
1235         TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);\r
1236         sym = SY_InsertGlobalUnique(tk_String, SY_CONSTANT);\r
1237         TK_NextToken();\r
1238         value = EvalConstExpression();\r
1239         MS_Message(MSG_DEBUG, "Constant value: %d\n", value);\r
1240         sym->info.constant.value = value;\r
1241         // Defines inside an import are deleted when the import is popped.\r
1242         if(ImportMode != IMPORT_Importing || force)\r
1243         {\r
1244                 sym->info.constant.fileDepth = 0;\r
1245         }\r
1246         else\r
1247         {\r
1248                 sym->info.constant.fileDepth = TK_GetDepth();\r
1249         }\r
1250 }\r
1251 \r
1252 //==========================================================================\r
1253 //\r
1254 // OuterInclude\r
1255 //\r
1256 //==========================================================================\r
1257 \r
1258 static void OuterInclude(void)\r
1259 {\r
1260         // Don't include inside an import\r
1261         if(ImportMode != IMPORT_Importing)\r
1262         {\r
1263                 MS_Message(MSG_DEBUG, "---- OuterInclude ----\n");\r
1264                 TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND);\r
1265                 TK_Include(tk_String);\r
1266         }\r
1267         else\r
1268         {\r
1269                 TK_NextToken();\r
1270         }\r
1271         TK_NextToken();\r
1272 }\r
1273 \r
1274 //==========================================================================\r
1275 //\r
1276 // OuterImport\r
1277 //\r
1278 //==========================================================================\r
1279 \r
1280 static void OuterImport(void)\r
1281 {\r
1282 \r
1283         MS_Message(MSG_DEBUG, "---- OuterImport ----\n");\r
1284         if(ImportMode == IMPORT_Importing)\r
1285         {\r
1286                 // Don't import inside an import\r
1287                 TK_NextToken();\r
1288         }\r
1289         else\r
1290         {\r
1291                 MS_Message(MSG_DEBUG, "Importing a file\n");\r
1292                 TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND);\r
1293                 TK_Import(tk_String, ImportMode);\r
1294         }\r
1295         TK_NextToken();\r
1296 }\r
1297 \r
1298 //==========================================================================\r
1299 //\r
1300 // ProcessStatement\r
1301 //\r
1302 //==========================================================================\r
1303 \r
1304 static boolean ProcessStatement(statement_t owner)\r
1305 {\r
1306         if(StatementIndex == MAX_STATEMENT_DEPTH)\r
1307         {\r
1308                 ERR_Exit(ERR_STATEMENT_OVERFLOW, YES);\r
1309         }\r
1310         StatementHistory[StatementIndex++] = owner;\r
1311         StatementLevel += AdjustStmtLevel[owner];\r
1312         switch(tk_Token)\r
1313         {\r
1314                 case TK_INT:\r
1315                 case TK_STR:\r
1316                 case TK_BOOL:\r
1317                 case TK_STATIC:\r
1318                         LeadingVarDeclare();\r
1319                         break;\r
1320                 case TK_LINESPECIAL:\r
1321                         if (tk_SpecialValue >= 0)\r
1322                         {\r
1323                                 LeadingLineSpecial(NO);\r
1324                         }\r
1325                         else\r
1326                         {\r
1327                                 LeadingFunction(NO);\r
1328                         }\r
1329                         break;\r
1330                 case TK_ACSEXECUTEWAIT:\r
1331                         tk_SpecialArgCount = 1 | (5<<16);\r
1332                         tk_SpecialValue = 80;\r
1333                         LeadingLineSpecial(YES);\r
1334                         break;\r
1335                 case TK_ACSNAMEDEXECUTEWAIT:\r
1336                         tk_SpecialArgCount = 1 | (5<<16);\r
1337                         tk_SpecialValue = -39;\r
1338                         LeadingFunction(YES);\r
1339                         break;\r
1340                 case TK_RESTART:\r
1341                         LeadingRestart();\r
1342                         break;\r
1343                 case TK_SUSPEND:\r
1344                         LeadingSuspend();\r
1345                         break;\r
1346                 case TK_TERMINATE:\r
1347                         LeadingTerminate();\r
1348                         break;\r
1349                 case TK_RETURN:\r
1350                         LeadingReturn();\r
1351                         break;\r
1352                 case TK_IDENTIFIER:\r
1353                         LeadingIdentifier();\r
1354                         break;\r
1355                 case TK_PRINT:\r
1356                 case TK_PRINTBOLD:\r
1357                 case TK_LOG:\r
1358                         LeadingPrint();\r
1359                         break;\r
1360 \r
1361                 case TK_STRPARAM_EVAL:\r
1362                         LeadingPrint();\r
1363                         PC_AppendCmd(PCD_DROP);\r
1364                         /* Duplicate code: LeadingPrint() post-processing: */\r
1365                         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1366                         TK_NextToken();\r
1367                         break;\r
1368 \r
1369                 case TK_STRCPY:\r
1370                         LeadingStrcpy();\r
1371                         PC_AppendCmd(PCD_DROP);\r
1372                         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1373                         TK_NextToken();\r
1374                         break;\r
1375 \r
1376                 case TK_HUDMESSAGE:\r
1377                 case TK_HUDMESSAGEBOLD:\r
1378                         LeadingHudMessage();\r
1379                         break;\r
1380                 case TK_IF:\r
1381                         LeadingIf();\r
1382                         break;\r
1383                 case TK_FOR:\r
1384                         LeadingFor();\r
1385                         break;\r
1386                 case TK_WHILE:\r
1387                 case TK_UNTIL:\r
1388                         LeadingWhileUntil();\r
1389                         break;\r
1390                 case TK_DO:\r
1391                         LeadingDo();\r
1392                         break;\r
1393                 case TK_SWITCH:\r
1394                         LeadingSwitch();\r
1395                         break;\r
1396                 case TK_CASE:\r
1397                         if(owner != STMT_SWITCH)\r
1398                         {\r
1399                                 ERR_Error(ERR_CASE_NOT_IN_SWITCH, YES);\r
1400                                 TK_SkipPast(TK_COLON);\r
1401                         }\r
1402                         else\r
1403                         {\r
1404                                 LeadingCase();\r
1405                         }\r
1406                         break;\r
1407                 case TK_DEFAULT:\r
1408                         if(owner != STMT_SWITCH)\r
1409                         {\r
1410                                 ERR_Error(ERR_DEFAULT_NOT_IN_SWITCH, YES);\r
1411                                 TK_SkipPast(TK_COLON);\r
1412                         }\r
1413                         else if(DefaultInCurrent() == YES)\r
1414                         {\r
1415                                 ERR_Error(ERR_MULTIPLE_DEFAULT, YES);\r
1416                                 TK_SkipPast(TK_COLON);\r
1417                         }\r
1418                         else\r
1419                         {\r
1420                                 LeadingDefault();\r
1421                         }\r
1422                         break;\r
1423                 case TK_BREAK:\r
1424                         if(BreakAncestor() == NO)\r
1425                         {\r
1426                                 ERR_Error(ERR_MISPLACED_BREAK, YES);\r
1427                                 TK_SkipPast(TK_SEMICOLON);\r
1428                         }\r
1429                         else\r
1430                         {\r
1431                                 LeadingBreak();\r
1432                         }\r
1433                         break;\r
1434                 case TK_CONTINUE:\r
1435                         if(ContinueAncestor() == NO)\r
1436                         {\r
1437                                 ERR_Error(ERR_MISPLACED_CONTINUE, YES);\r
1438                                 TK_SkipPast(TK_SEMICOLON);\r
1439                         }\r
1440                         else\r
1441                         {\r
1442                                 LeadingContinue();\r
1443                         }\r
1444                         break;\r
1445                 case TK_CREATETRANSLATION:\r
1446                         LeadingCreateTranslation();\r
1447                         break;\r
1448                 case TK_LBRACE:\r
1449                         LeadingCompoundStatement(owner);\r
1450                         break;\r
1451                 case TK_SEMICOLON:\r
1452                         TK_NextToken();\r
1453                         break;\r
1454                 case TK_INC:\r
1455                 case TK_DEC:\r
1456                         LeadingIncDec(tk_Token);\r
1457                         break;\r
1458 \r
1459                 default:\r
1460                         StatementIndex--;\r
1461                         StatementLevel -= AdjustStmtLevel[owner];\r
1462                         return NO;\r
1463                         break;\r
1464         }\r
1465         StatementIndex--;\r
1466         StatementLevel -= AdjustStmtLevel[owner];\r
1467         return YES;\r
1468 }\r
1469 \r
1470 //==========================================================================\r
1471 //\r
1472 // LeadingCompoundStatement\r
1473 //\r
1474 //==========================================================================\r
1475 \r
1476 static void LeadingCompoundStatement(statement_t owner)\r
1477 {\r
1478         //StatementLevel += AdjustStmtLevel[owner];\r
1479         TK_NextToken(); // Eat the TK_LBRACE\r
1480         do {} while(ProcessStatement(owner) == YES);\r
1481         TK_TokenMustBe(TK_RBRACE, ERR_INVALID_STATEMENT);\r
1482         TK_NextToken();\r
1483         //StatementLevel -= AdjustStmtLevel[owner];\r
1484 }\r
1485 \r
1486 //==========================================================================\r
1487 //\r
1488 // LeadingVarDeclare\r
1489 //\r
1490 //==========================================================================\r
1491 \r
1492 static void LeadingVarDeclare(void)\r
1493 {\r
1494         symbolNode_t *sym = NULL;\r
1495 \r
1496         if(tk_Token == TK_STATIC)\r
1497         {\r
1498                 TK_NextToken();\r
1499                 if(tk_Token != TK_INT && tk_Token != TK_STR && tk_Token != TK_BOOL)\r
1500                 {\r
1501                         ERR_Error(ERR_BAD_VAR_TYPE, YES);\r
1502                         TK_Undo();\r
1503                 }\r
1504                 OuterMapVar(YES);\r
1505                 return;\r
1506         }\r
1507 \r
1508         MS_Message(MSG_DEBUG, "---- LeadingVarDeclare ----\n");\r
1509         do\r
1510         {\r
1511                 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);\r
1512 #if 0\r
1513                 if(ScriptVarCount == MAX_SCRIPT_VARIABLES)\r
1514                 {\r
1515                         ERR_Error(InsideFunction\r
1516                                 ? ERR_TOO_MANY_FUNCTION_VARS\r
1517                                 : ERR_TOO_MANY_SCRIPT_VARS,\r
1518                                 YES, NULL);\r
1519                         ScriptVarCount++;\r
1520                 }\r
1521                 else\r
1522 #endif \r
1523                 if(SY_FindLocal(tk_String) != NULL)\r
1524                 { // Redefined\r
1525                         ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);\r
1526                 }\r
1527                 else\r
1528                 {\r
1529                         sym = SY_InsertLocal(tk_String, SY_SCRIPTVAR);\r
1530                         sym->info.var.index = ScriptVarCount;\r
1531                         ScriptVarCount++;\r
1532                 }\r
1533                 TK_NextToken();\r
1534                 if(tk_Token == TK_LBRACKET)\r
1535                 {\r
1536                         ERR_Error(ERR_ARRAY_MAPVAR_ONLY, YES);\r
1537                         do {} while(TK_NextToken() != TK_COMMA && tk_Token != TK_SEMICOLON);\r
1538                 }\r
1539                 else if(tk_Token == TK_ASSIGN)\r
1540                 {\r
1541                         TK_NextToken();\r
1542                         EvalExpression();\r
1543                         if(sym != NULL)\r
1544                         {\r
1545                                 PC_AppendCmd(PCD_ASSIGNSCRIPTVAR);\r
1546                                 PC_AppendShrink(sym->info.var.index);\r
1547                         }\r
1548                 }\r
1549         } while(tk_Token == TK_COMMA);\r
1550         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1551         TK_NextToken();\r
1552 }\r
1553 \r
1554 //==========================================================================\r
1555 //\r
1556 // LeadingLineSpecial\r
1557 //\r
1558 //==========================================================================\r
1559 \r
1560 static void LeadingLineSpecial(boolean executewait)\r
1561 {\r
1562         int i;\r
1563         int argCount;\r
1564         int argCountMin;\r
1565         int argCountMax;\r
1566         int argSave[8];\r
1567         U_INT specialValue;\r
1568         boolean direct;\r
1569 \r
1570         MS_Message(MSG_DEBUG, "---- LeadingLineSpecial ----\n");\r
1571         argCountMin = tk_SpecialArgCount & 0xffff;\r
1572         argCountMax = tk_SpecialArgCount >> 16;\r
1573         specialValue = tk_SpecialValue;\r
1574         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
1575         i = 0;\r
1576         if(argCountMax > 0)\r
1577         {\r
1578                 if(TK_NextToken() == TK_CONST)\r
1579                 {\r
1580                         TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
1581                         direct = YES;\r
1582                 }\r
1583                 else\r
1584                 {\r
1585                         TK_Undo();\r
1586                         direct = NO;\r
1587                 }\r
1588                 do\r
1589                 {\r
1590                         if(i == argCountMax)\r
1591                         {\r
1592                                 ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES);\r
1593                                 i = argCountMax+1;\r
1594                         }\r
1595                         TK_NextToken();\r
1596                         if(direct == YES)\r
1597                         {\r
1598                                 argSave[i] = EvalConstExpression();\r
1599                         }\r
1600                         else\r
1601                         {\r
1602                                 EvalExpression();\r
1603                                 if (i == 0 && executewait)\r
1604                                 {\r
1605                                         PC_AppendCmd(PCD_DUP);\r
1606                                 }\r
1607                         }\r
1608                         if(i < argCountMax)\r
1609                         {\r
1610                                 i++;\r
1611                         }\r
1612                 } while(tk_Token == TK_COMMA);\r
1613                 if(i < argCountMin)\r
1614                 {\r
1615                         ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES);\r
1616                         TK_SkipPast(TK_SEMICOLON);\r
1617                         return;\r
1618                 }\r
1619                 argCount = i;\r
1620         }\r
1621         else\r
1622         {\r
1623                 // [RH] I added some zero-argument specials without realizing that\r
1624                 // ACS won't allow for less than one, so fake them as one-argument\r
1625                 // specials with a parameter of 0.\r
1626                 argCount = 1;\r
1627                 direct = YES;\r
1628                 argSave[0] = 0;\r
1629                 TK_NextToken ();\r
1630         }\r
1631         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
1632         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1633         if(direct == NO)\r
1634         {\r
1635                 PC_AppendCmd(PCD_LSPEC1+(argCount-1));\r
1636                 if(pc_NoShrink)\r
1637                 {\r
1638                         PC_AppendInt(specialValue);\r
1639                 }\r
1640                 else\r
1641                 {\r
1642                         if (specialValue > 255)\r
1643                         {\r
1644                                 ERR_Error(ERR_SPECIAL_RANGE, YES);\r
1645                         }\r
1646                         PC_AppendByte((U_BYTE)specialValue);\r
1647                 }\r
1648                 if(executewait)\r
1649                 {\r
1650                         PC_AppendCmd(PCD_SCRIPTWAIT);\r
1651                 }\r
1652         }\r
1653         else\r
1654         {\r
1655                 boolean useintform;\r
1656 \r
1657                 if(pc_NoShrink)\r
1658                 {\r
1659                         PC_AppendCmd(PCD_LSPEC1DIRECT+(argCount-1));\r
1660                         PC_AppendInt(specialValue);\r
1661                         useintform = YES;\r
1662                 }\r
1663                 else\r
1664                 {\r
1665                         useintform = NO;\r
1666                         for (i = 0; i < argCount; i++)\r
1667                         {\r
1668                                 if ((U_INT)argSave[i] > 255)\r
1669                                 {\r
1670                                         useintform = YES;\r
1671                                         break;\r
1672                                 }\r
1673                         }\r
1674                         PC_AppendCmd((argCount-1)+(useintform?PCD_LSPEC1DIRECT:PCD_LSPEC1DIRECTB));\r
1675                         PC_AppendByte((U_BYTE)specialValue);\r
1676                 }\r
1677                 if (useintform)\r
1678                 {\r
1679                         for (i = 0; i < argCount; i++)\r
1680                         {\r
1681                                 PC_AppendInt(argSave[i]);\r
1682                         }\r
1683                 }\r
1684                 else\r
1685                 {\r
1686                         for (i = 0; i < argCount; i++)\r
1687                         {\r
1688                                 PC_AppendByte((U_BYTE)argSave[i]);\r
1689                         }\r
1690                 }\r
1691                 if(executewait)\r
1692                 {\r
1693                         PC_AppendCmd(PCD_SCRIPTWAITDIRECT);\r
1694                         PC_AppendInt(argSave[0]);\r
1695                 }\r
1696         }\r
1697         TK_NextToken();\r
1698 }\r
1699 \r
1700 //==========================================================================\r
1701 //\r
1702 // LeadingLineSpecial\r
1703 //\r
1704 //==========================================================================\r
1705 \r
1706 static void LeadingFunction(boolean executewait)\r
1707 {\r
1708         int i;\r
1709         int argCount;\r
1710         int argCountMin;\r
1711         int argCountMax;\r
1712         int specialValue;\r
1713 \r
1714         MS_Message(MSG_DEBUG, "---- LeadingFunction ----\n");\r
1715         argCountMin = tk_SpecialArgCount & 0xffff;\r
1716         argCountMax = tk_SpecialArgCount >> 16;\r
1717         specialValue = -tk_SpecialValue;\r
1718         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
1719         i = 0;\r
1720         if(argCountMax > 0)\r
1721         {\r
1722                 if(TK_NextToken() == TK_CONST)\r
1723                 {\r
1724                         // Just skip const declarators\r
1725                         TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
1726                 }\r
1727                 else\r
1728                 {\r
1729                         TK_Undo();\r
1730                 }\r
1731                 do\r
1732                 {\r
1733                         if(i == argCountMax)\r
1734                         {\r
1735                                 ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
1736                                 i = argCountMax+1;\r
1737                         }\r
1738                         TK_NextToken();\r
1739                         EvalExpression();\r
1740                         if (i == 0 && executewait)\r
1741                         {\r
1742                                 PC_AppendCmd(PCD_DUP);\r
1743                         }\r
1744                         if(i < argCountMax)\r
1745                         {\r
1746                                 i++;\r
1747                         }\r
1748                 } while(tk_Token == TK_COMMA);\r
1749                 if(i < argCountMin)\r
1750                 {\r
1751                         ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
1752                         TK_SkipPast(TK_SEMICOLON);\r
1753                         return;\r
1754                 }\r
1755                 argCount = i;\r
1756         }\r
1757         else\r
1758         {\r
1759                 argCount = 0;\r
1760                 TK_NextToken ();\r
1761         }\r
1762         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
1763         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1764         PC_AppendCmd(PCD_CALLFUNC);\r
1765         if(pc_NoShrink)\r
1766         {\r
1767                 PC_AppendInt(argCount);\r
1768                 PC_AppendInt(specialValue);\r
1769         }\r
1770         else\r
1771         {\r
1772                 PC_AppendByte((U_BYTE)argCount);\r
1773                 PC_AppendWord((U_WORD)specialValue);\r
1774         }\r
1775         PC_AppendCmd(PCD_DROP);\r
1776         if(executewait)\r
1777         {\r
1778                 PC_AppendCmd(PCD_SCRIPTWAITNAMED);\r
1779         }\r
1780         TK_NextToken();\r
1781 }\r
1782 \r
1783 //==========================================================================\r
1784 //\r
1785 // LeadingIdentifier\r
1786 //\r
1787 //==========================================================================\r
1788 \r
1789 static void LeadingIdentifier(void)\r
1790 {\r
1791         symbolNode_t *sym;\r
1792 \r
1793         sym = SpeculateSymbol(tk_String, NO);\r
1794         switch(sym->type)\r
1795         {\r
1796                 case SY_MAPARRAY:\r
1797                 case SY_SCRIPTVAR:\r
1798                 case SY_SCRIPTALIAS:\r
1799                 case SY_MAPVAR:\r
1800                 case SY_WORLDVAR:\r
1801                 case SY_GLOBALVAR:\r
1802                 case SY_WORLDARRAY:\r
1803                 case SY_GLOBALARRAY:\r
1804                         LeadingVarAssign(sym);\r
1805                         break;\r
1806                 case SY_INTERNFUNC:\r
1807                         LeadingInternFunc(sym);\r
1808                         break;\r
1809                 case SY_SCRIPTFUNC:\r
1810                         LeadingScriptFunc(sym);\r
1811                         break;\r
1812                 default:\r
1813                         break;\r
1814         }\r
1815 }\r
1816 \r
1817 //==========================================================================\r
1818 //\r
1819 // LeadingInternFunc\r
1820 //\r
1821 //==========================================================================\r
1822 \r
1823 static void LeadingInternFunc(symbolNode_t *sym)\r
1824 {\r
1825         if(InsideFunction && sym->info.internFunc.latent)\r
1826         {\r
1827                 ERR_Error(ERR_LATENT_IN_FUNC, YES);\r
1828         }\r
1829         ProcessInternFunc(sym);\r
1830         if(sym->info.internFunc.hasReturnValue == YES)\r
1831         {\r
1832                 PC_AppendCmd(PCD_DROP);\r
1833         }\r
1834         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1835         TK_NextToken();\r
1836 }\r
1837 \r
1838 //==========================================================================\r
1839 //\r
1840 // ProcessInternFunc\r
1841 //\r
1842 //==========================================================================\r
1843 \r
1844 static void ProcessInternFunc(symbolNode_t *sym)\r
1845 {\r
1846         int i;\r
1847         int argCount;\r
1848         int optMask;\r
1849         int outMask;\r
1850         boolean direct;\r
1851         boolean specialDirect;\r
1852         int argSave[8];\r
1853 \r
1854         MS_Message(MSG_DEBUG, "---- ProcessInternFunc ----\n");\r
1855         argCount = sym->info.internFunc.argCount;\r
1856         optMask = sym->info.internFunc.optMask;\r
1857         outMask = sym->info.internFunc.outMask;\r
1858         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
1859         if(TK_NextToken() == TK_CONST)\r
1860         {\r
1861                 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
1862                 if(sym->info.internFunc.directCommand == PCD_NOP)\r
1863                 {\r
1864                         ERR_Error(ERR_NO_DIRECT_VER, YES, NULL);\r
1865                         direct = NO;\r
1866                         specialDirect = NO;\r
1867                 }\r
1868                 else\r
1869                 {\r
1870                         direct = YES;\r
1871                         if (pc_NoShrink || argCount > 2 ||\r
1872                                 (sym->info.internFunc.directCommand != PCD_DELAYDIRECT &&\r
1873                                  sym->info.internFunc.directCommand != PCD_RANDOMDIRECT))\r
1874                         {\r
1875                                 specialDirect = NO;\r
1876                                 PC_AppendCmd(sym->info.internFunc.directCommand);\r
1877                         }\r
1878                         else\r
1879                         {\r
1880                                 specialDirect = YES;\r
1881                         }\r
1882                 }\r
1883                 TK_NextToken();\r
1884         }\r
1885         else\r
1886         {\r
1887                 direct = NO;\r
1888                 specialDirect = NO;     // keep GCC quiet\r
1889         }\r
1890         i = 0;\r
1891         if(argCount > 0)\r
1892         {\r
1893                 if(tk_Token == TK_RPAREN)\r
1894                 {\r
1895                         ERR_Error(ERR_MISSING_PARAM, YES);\r
1896                 }\r
1897                 else\r
1898                 {\r
1899                         TK_Undo(); // Adjust for first expression\r
1900                         do\r
1901                         {\r
1902                                 if(i == argCount)\r
1903                                 {\r
1904                                         ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
1905                                         TK_SkipTo(TK_SEMICOLON);\r
1906                                         TK_Undo();\r
1907                                         return;\r
1908                                 }\r
1909                                 TK_NextToken();\r
1910                                 if(direct == YES)\r
1911                                 {\r
1912                                         if (tk_Token != TK_COMMA)\r
1913                                         {\r
1914                                                 if (specialDirect)\r
1915                                                 {\r
1916                                                         argSave[i] = EvalConstExpression();\r
1917                                                 }\r
1918                                                 else\r
1919                                                 {\r
1920                                                         PC_AppendInt(EvalConstExpression());\r
1921                                                 }\r
1922                                         }\r
1923                                         else\r
1924                                         {\r
1925                                                 if (optMask & 1)\r
1926                                                 {\r
1927                                                         if (specialDirect)\r
1928                                                         {\r
1929                                                                 argSave[i] = 0;\r
1930                                                         }\r
1931                                                         else\r
1932                                                         {\r
1933                                                                 PC_AppendInt(0);\r
1934                                                         }\r
1935                                                 }\r
1936                                                 else\r
1937                                                 {\r
1938                                                         ERR_Error(ERR_MISSING_PARAM, YES);\r
1939                                                 }\r
1940                                         }\r
1941                                 }\r
1942                                 else\r
1943                                 {\r
1944                                         if (tk_Token != TK_COMMA)\r
1945                                         {\r
1946                                                 if (!(outMask & 1))\r
1947                                                 {\r
1948                                                         EvalExpression();\r
1949                                                 }\r
1950                                                 else if (tk_Token != TK_IDENTIFIER)\r
1951                                                 {\r
1952                                                         ERR_Error (ERR_PARM_MUST_BE_VAR, YES);\r
1953                                                         do\r
1954                                                         {\r
1955                                                                 TK_NextToken();\r
1956                                                         } while (tk_Token != TK_COMMA && tk_Token != TK_RPAREN);\r
1957                                                 }\r
1958                                                 else\r
1959                                                 {\r
1960                                                         symbolNode_t *sym = DemandSymbol (tk_String);\r
1961                                                         PC_AppendCmd (PCD_PUSHNUMBER);\r
1962                                                         switch (sym->type)\r
1963                                                         {\r
1964                                                         case SY_SCRIPTVAR:\r
1965                                                                 PC_AppendInt(sym->info.var.index | OUTVAR_SCRIPT_SPEC);\r
1966                                                                 break;\r
1967                                                         case SY_MAPVAR:\r
1968                                                                 PC_AppendInt(sym->info.var.index | OUTVAR_MAP_SPEC);\r
1969                                                                 break;\r
1970                                                         case SY_WORLDVAR:\r
1971                                                                 PC_AppendInt(sym->info.var.index | OUTVAR_WORLD_SPEC);\r
1972                                                                 break;\r
1973                                                         case SY_GLOBALVAR:\r
1974                                                                 PC_AppendInt(sym->info.var.index | OUTVAR_GLOBAL_SPEC);\r
1975                                                                 break;\r
1976                                                         default:\r
1977                                                                 ERR_Error (ERR_PARM_MUST_BE_VAR, YES);\r
1978                                                                 do\r
1979                                                                 {\r
1980                                                                         TK_NextToken();\r
1981                                                                 } while (tk_Token != TK_COMMA && tk_Token != TK_RPAREN);\r
1982                                                                 break;\r
1983                                                         }\r
1984                                                         TK_NextToken ();\r
1985                                                 }\r
1986                                         }\r
1987                                         else\r
1988                                         {\r
1989                                                 if (optMask & 1)\r
1990                                                 {\r
1991                                                         PC_AppendPushVal(0);\r
1992                                                 }\r
1993                                                 else\r
1994                                                 {\r
1995                                                         ERR_Error(ERR_MISSING_PARAM, YES);\r
1996                                                 }\r
1997                                         }\r
1998                                 }\r
1999                                 i++;\r
2000                                 optMask >>= 1;\r
2001                                 outMask >>= 1;\r
2002                         } while(tk_Token == TK_COMMA);\r
2003                 }\r
2004         }\r
2005         while (i < argCount && (optMask & 1))\r
2006         {\r
2007                 if (direct == YES)\r
2008                 {\r
2009                         if (specialDirect)\r
2010                         {\r
2011                                 argSave[i] = 0;\r
2012                         }\r
2013                         else\r
2014                         {\r
2015                                 PC_AppendInt(0);\r
2016                         }\r
2017                 }\r
2018                 else\r
2019                 {\r
2020                         PC_AppendPushVal(0);\r
2021                 }\r
2022                 i++;\r
2023                 optMask >>= 1;\r
2024         }\r
2025         if(i != argCount && i > 0)\r
2026         {\r
2027                 ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
2028         }\r
2029         TK_TokenMustBe(TK_RPAREN, argCount > 0 ? ERR_MISSING_RPAREN : ERR_BAD_ARG_COUNT);\r
2030         if(direct == NO)\r
2031         {\r
2032                 PC_AppendCmd(sym->info.internFunc.stackCommand);\r
2033         }\r
2034         else if (specialDirect)\r
2035         {\r
2036                 boolean useintform = NO;\r
2037                 pcd_t shortpcd;\r
2038 \r
2039                 switch (sym->info.internFunc.directCommand)\r
2040                 {\r
2041                 case PCD_DELAYDIRECT:\r
2042                         shortpcd = PCD_DELAYDIRECTB;\r
2043                         break;\r
2044                 case PCD_RANDOMDIRECT:\r
2045                         shortpcd = PCD_RANDOMDIRECTB;\r
2046                         break;\r
2047                 default:\r
2048                         useintform = YES;\r
2049                         shortpcd = PCD_NOP;\r
2050                         break;\r
2051                 }\r
2052 \r
2053                 if (!useintform)\r
2054                 {\r
2055                         for (i = 0; i < argCount; i++)\r
2056                         {\r
2057                                 if ((U_INT)argSave[i] > 255)\r
2058                                 {\r
2059                                         useintform = YES;\r
2060                                         break;\r
2061                                 }\r
2062                         }\r
2063                 }\r
2064 \r
2065                 if (useintform)\r
2066                 {\r
2067                         PC_AppendCmd(sym->info.internFunc.directCommand);\r
2068                         for (i = 0; i < argCount; i++)\r
2069                         {\r
2070                                 PC_AppendInt (argSave[i]);\r
2071                         }\r
2072                 }\r
2073                 else\r
2074                 {\r
2075                         PC_AppendCmd (shortpcd);\r
2076                         for (i = 0; i < argCount; i++)\r
2077                         {\r
2078                                 PC_AppendByte ((U_BYTE)argSave[i]);\r
2079                         }\r
2080                 }\r
2081         }\r
2082         TK_NextToken();\r
2083 }\r
2084 \r
2085 //==========================================================================\r
2086 //\r
2087 // LeadingScriptFunc\r
2088 //\r
2089 //==========================================================================\r
2090 \r
2091 static void LeadingScriptFunc(symbolNode_t *sym)\r
2092 {\r
2093         ProcessScriptFunc(sym, YES);\r
2094         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2095         TK_NextToken();\r
2096 }\r
2097 \r
2098 \r
2099 //==========================================================================\r
2100 //\r
2101 // ProcessScriptFunc\r
2102 //\r
2103 //==========================================================================\r
2104 \r
2105 static void ProcessScriptFunc(symbolNode_t *sym, boolean discardReturn)\r
2106 {\r
2107         int i;\r
2108         int argCount;\r
2109 \r
2110         MS_Message(MSG_DEBUG, "---- ProcessScriptFunc ----\n");\r
2111         argCount = sym->info.scriptFunc.argCount;\r
2112         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2113         i = 0;\r
2114         if(argCount == 0)\r
2115         {\r
2116                 TK_NextTokenMustBe(TK_RPAREN, ERR_BAD_ARG_COUNT);\r
2117         }\r
2118         else if(argCount > 0)\r
2119         {\r
2120                 TK_NextToken();\r
2121                 if(tk_Token == TK_RPAREN)\r
2122                 {\r
2123                         ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
2124                         TK_SkipTo(TK_SEMICOLON);\r
2125                         return;\r
2126                 }\r
2127                 TK_Undo();\r
2128                 do\r
2129                 {\r
2130                         if(i == argCount)\r
2131                         {\r
2132                                 ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
2133                                 TK_SkipTo(TK_SEMICOLON);\r
2134                                 return;\r
2135                         }\r
2136                         TK_NextToken();\r
2137                         if (tk_Token != TK_COMMA)\r
2138                         {\r
2139                                 EvalExpression();\r
2140                         }\r
2141                         else\r
2142                         {\r
2143                                 ERR_Error(ERR_MISSING_PARAM, YES);\r
2144                                 TK_SkipTo(TK_SEMICOLON);\r
2145                                 return;\r
2146                         }\r
2147                         i++;\r
2148                 } while(tk_Token == TK_COMMA);\r
2149         }\r
2150         if(argCount < 0)\r
2151         { // Function has not been defined yet, so assume arg count is correct\r
2152                 TK_NextToken();\r
2153                 while (tk_Token != TK_RPAREN)\r
2154                 {\r
2155                         EvalExpression();\r
2156                         i++;\r
2157                         if (tk_Token == TK_COMMA)\r
2158                         {\r
2159                                 TK_NextToken();\r
2160                         }\r
2161                         else if (tk_Token != TK_RPAREN)\r
2162                         {\r
2163                                 ERR_Error(ERR_MISSING_PARAM, YES);\r
2164                                 TK_SkipTo(TK_SEMICOLON);\r
2165                                 return;\r
2166                         }\r
2167                 }\r
2168         }\r
2169         else if(i != argCount)\r
2170         {\r
2171                 ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
2172                 TK_SkipTo(TK_SEMICOLON);\r
2173                 return;\r
2174         }\r
2175         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2176         PC_AppendCmd(discardReturn ? PCD_CALLDISCARD : PCD_CALL);\r
2177         if(sym->info.scriptFunc.predefined && ImportMode != IMPORT_Importing)\r
2178         {\r
2179                 AddScriptFuncRef(sym, pc_Address, i);\r
2180         }\r
2181         if (pc_NoShrink)\r
2182         {\r
2183                 PC_AppendInt(sym->info.scriptFunc.funcNumber);\r
2184         }\r
2185         else\r
2186         {\r
2187                 PC_AppendByte((U_BYTE)sym->info.scriptFunc.funcNumber);\r
2188         }\r
2189         TK_NextToken();\r
2190 }\r
2191 \r
2192 //==========================================================================\r
2193 //\r
2194 // BuildPrintString\r
2195 //\r
2196 //==========================================================================\r
2197 \r
2198 static void BuildPrintString(void)\r
2199 {\r
2200         pcd_t printCmd;\r
2201 \r
2202         do\r
2203         {\r
2204                 switch(TK_NextCharacter())\r
2205                 {\r
2206                         case 'a': // character array support [JB]\r
2207                                 ActionOnCharRange(NO);\r
2208                                 continue;\r
2209                         case 's': // string\r
2210                                 printCmd = PCD_PRINTSTRING;\r
2211                                 break;\r
2212                         case 'l': // [RH] localized string\r
2213                                 printCmd = PCD_PRINTLOCALIZED;\r
2214                                 break;\r
2215                         case 'i': // integer\r
2216                         case 'd': // decimal\r
2217                                 printCmd = PCD_PRINTNUMBER;\r
2218                                 break;\r
2219                         case 'c': // character\r
2220                                 printCmd = PCD_PRINTCHARACTER;\r
2221                                 break;\r
2222                         case 'n': // [BC] name\r
2223                                 printCmd = PCD_PRINTNAME;\r
2224                                 break;\r
2225                         case 'f': // [RH] fixed point\r
2226                                 printCmd = PCD_PRINTFIXED;\r
2227                                 break;\r
2228                         case 'k': // [GRB] key binding\r
2229                                 printCmd = PCD_PRINTBIND;\r
2230                                 break;\r
2231                         case 'b': // [RH] binary integer\r
2232                                 printCmd = PCD_PRINTBINARY;\r
2233                                 break;\r
2234                         case 'x': // [RH] hexadecimal integer\r
2235                                 printCmd = PCD_PRINTHEX;\r
2236                                 break;\r
2237                         default:\r
2238                                 printCmd = PCD_PRINTSTRING;\r
2239                                 ERR_Error(ERR_UNKNOWN_PRTYPE, YES);\r
2240                                 break;\r
2241                 }\r
2242                 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2243                 TK_NextToken();\r
2244                 EvalExpression();\r
2245                 PC_AppendCmd(printCmd);\r
2246         } while(tk_Token == TK_COMMA);\r
2247 }\r
2248 \r
2249 //==========================================================================\r
2250 //\r
2251 // ActionOnCharRange // FDARI (mutation of PrintCharArray // JB)\r
2252 //\r
2253 //==========================================================================\r
2254 \r
2255 static void ActionOnCharRange(boolean write)\r
2256 {\r
2257         boolean rangeConstraints;\r
2258         symbolNode_t *sym;\r
2259         TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2260         TK_NextToken();\r
2261 \r
2262         if (tk_Token == TK_LPAREN)\r
2263         {\r
2264                 rangeConstraints = YES;\r
2265                 TK_NextToken();\r
2266         }\r
2267         else\r
2268         {\r
2269                 rangeConstraints = NO;\r
2270         }\r
2271 \r
2272         sym = SpeculateSymbol(tk_String, NO);\r
2273         if((sym->type != SY_MAPARRAY) && (sym->type != SY_WORLDARRAY)\r
2274                 && (sym->type != SY_GLOBALARRAY))\r
2275         {\r
2276                 ERR_Error(ERR_NOT_AN_ARRAY, YES);\r
2277         }\r
2278         TK_NextToken();\r
2279         if(sym->info.array.ndim > 1)\r
2280         {\r
2281                 ParseArrayIndices(sym, sym->info.array.ndim-1);\r
2282         }\r
2283         else\r
2284         {\r
2285                 PC_AppendPushVal(0);\r
2286         }\r
2287 \r
2288         PC_AppendPushVal(sym->info.array.index);\r
2289 \r
2290         \r
2291         if (rangeConstraints)\r
2292         {\r
2293                 switch (tk_Token)\r
2294                 {\r
2295                 case TK_RPAREN:\r
2296                         rangeConstraints = NO;\r
2297                         TK_NextToken();\r
2298                         break;\r
2299                 case TK_COMMA:\r
2300                         TK_NextToken();\r
2301                         EvalExpression();\r
2302 \r
2303                         switch (tk_Token)\r
2304                         {\r
2305                         case TK_RPAREN:\r
2306                                 TK_NextToken();\r
2307                                 PC_AppendPushVal(0x7FFFFFFF); \r
2308                                 break;\r
2309                         case TK_COMMA:\r
2310                                 TK_NextToken();\r
2311                                 EvalExpression(); // limit on capacity\r
2312                                 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2313                                 TK_NextToken();\r
2314                                 break;\r
2315                         default:\r
2316                                 ERR_Error(ERR_MISSING_RPAREN, YES);\r
2317                                 break;\r
2318                         }\r
2319 \r
2320                         break;\r
2321                 default:\r
2322                         ERR_Error(ERR_MISSING_RPAREN, YES);\r
2323                         break;\r
2324                 }\r
2325         }\r
2326 \r
2327         if (write)\r
2328         {\r
2329                 if (!rangeConstraints)\r
2330                 {\r
2331                         PC_AppendPushVal(0);\r
2332                         PC_AppendPushVal(0x7FFFFFFF);\r
2333                 }\r
2334 \r
2335                 TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA);\r
2336                 TK_NextToken();\r
2337                 EvalExpression();\r
2338 \r
2339                 if (tk_Token == TK_COMMA)\r
2340                 {\r
2341                         TK_NextToken();\r
2342                         EvalExpression();\r
2343                 }\r
2344                 else\r
2345                 {\r
2346                         PC_AppendPushVal(0);\r
2347                 }\r
2348         }\r
2349 \r
2350         if(sym->type == SY_MAPARRAY)\r
2351         {\r
2352                 if (write) PC_AppendCmd(PCD_STRCPYTOMAPCHRANGE);\r
2353                 else PC_AppendCmd( rangeConstraints ? PCD_PRINTMAPCHRANGE : PCD_PRINTMAPCHARARRAY );\r
2354         }\r
2355         else if(sym->type == SY_WORLDARRAY)\r
2356         {\r
2357                 if (write) PC_AppendCmd(PCD_STRCPYTOWORLDCHRANGE);\r
2358                 else PC_AppendCmd( rangeConstraints ? PCD_PRINTWORLDCHRANGE : PCD_PRINTWORLDCHARARRAY );\r
2359         }\r
2360         else // if(sym->type == SY_GLOBALARRAY)\r
2361         {\r
2362                 if (write) PC_AppendCmd(PCD_STRCPYTOGLOBALCHRANGE);\r
2363                 else PC_AppendCmd( rangeConstraints ? PCD_PRINTGLOBALCHRANGE : PCD_PRINTGLOBALCHARARRAY );\r
2364         }\r
2365 }\r
2366 \r
2367 //==========================================================================\r
2368 //\r
2369 // LeadingStrcpy\r
2370 //\r
2371 //==========================================================================\r
2372 \r
2373 static void LeadingStrcpy(void)\r
2374 {\r
2375         MS_Message(MSG_DEBUG, "---- LeadingStrcpy ----\n");\r
2376         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2377         \r
2378         switch(TK_NextCharacter()) // structure borrowed from printbuilder\r
2379         {\r
2380                 case 'a':\r
2381                         ActionOnCharRange(YES);\r
2382                         break;\r
2383 \r
2384                 default:\r
2385                         ERR_Error(ERR_UNKNOWN_PRTYPE, YES);\r
2386                         break;\r
2387         }\r
2388 \r
2389         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2390 }\r
2391 \r
2392 //==========================================================================\r
2393 //\r
2394 // LeadingPrint\r
2395 //\r
2396 //==========================================================================\r
2397 \r
2398 static void LeadingPrint(void)\r
2399 {\r
2400         tokenType_t stmtToken;\r
2401 \r
2402         MS_Message(MSG_DEBUG, "---- LeadingPrint ----\n");\r
2403         stmtToken = tk_Token; // Will be TK_PRINT or TK_PRINTBOLD, TK_LOG or TK_STRPARAM_EVAL [FDARI]\r
2404         PC_AppendCmd(PCD_BEGINPRINT);\r
2405         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2406         BuildPrintString();\r
2407         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2408 \r
2409         switch (stmtToken)\r
2410         {\r
2411         case TK_PRINT:\r
2412                 PC_AppendCmd(PCD_ENDPRINT);\r
2413                 break;\r
2414 \r
2415         case TK_PRINTBOLD:\r
2416                 PC_AppendCmd(PCD_ENDPRINTBOLD);\r
2417                 break;\r
2418 \r
2419         case TK_STRPARAM_EVAL:\r
2420                 PC_AppendCmd(PCD_SAVESTRING);\r
2421                 return; // THE CALLER MUST DO THE POST-PROCESSING\r
2422 \r
2423         case TK_LOG:\r
2424         default:\r
2425                 PC_AppendCmd(PCD_ENDLOG);\r
2426                 break;\r
2427         }\r
2428 \r
2429         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2430         TK_NextToken();\r
2431 }\r
2432 \r
2433 //==========================================================================\r
2434 //\r
2435 // LeadingHudMessage\r
2436 //\r
2437 // hudmessage(str text; int type, int id, int color, fixed x, fixed y, fixed holdtime, ...)\r
2438 //\r
2439 //==========================================================================\r
2440 \r
2441 static void LeadingHudMessage(void)\r
2442 {\r
2443         tokenType_t stmtToken;\r
2444         int i;\r
2445 \r
2446         MS_Message(MSG_DEBUG, "---- LeadingHudMessage ----\n");\r
2447         stmtToken = tk_Token; // Will be TK_HUDMESSAGE or TK_HUDMESSAGEBOLD\r
2448         PC_AppendCmd(PCD_BEGINPRINT);\r
2449         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2450         BuildPrintString();\r
2451         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_PARAM);\r
2452         PC_AppendCmd(PCD_MOREHUDMESSAGE);\r
2453         for (i = 6; i > 0; i--)\r
2454         {\r
2455                 TK_NextToken();\r
2456                 EvalExpression();\r
2457                 if (i > 1)\r
2458                         TK_TokenMustBe(TK_COMMA, ERR_MISSING_PARAM);\r
2459         }\r
2460         if (tk_Token == TK_COMMA)\r
2461         { // HUD message has optional parameters\r
2462                 PC_AppendCmd(PCD_OPTHUDMESSAGE);\r
2463                 do\r
2464                 {\r
2465                         TK_NextToken();\r
2466                         EvalExpression();\r
2467                 } while (tk_Token == TK_COMMA);\r
2468         }\r
2469         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2470         PC_AppendCmd(stmtToken == TK_HUDMESSAGE ? \r
2471                 PCD_ENDHUDMESSAGE : PCD_ENDHUDMESSAGEBOLD);\r
2472         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2473         TK_NextToken();\r
2474 }\r
2475 \r
2476 //==========================================================================\r
2477 //\r
2478 // LeadingCreateTranslation\r
2479 //\r
2480 // Simple grammar:\r
2481 //\r
2482 // tranlationstmt: CreateTranslation ( exp opt_args ) ;\r
2483 // opt_args: /* empty: just reset the translation */ | , arglist\r
2484 // arglist: arg | arglist arg\r
2485 // arg: range = replacement\r
2486 // range: exp : exp\r
2487 // replacement: palrep | colorrep\r
2488 // palrep: exp : exp\r
2489 // colorrep: [exp,exp,exp]:[exp,exp,exp]\r
2490 // desatrep: %colorrep\r
2491 //==========================================================================\r
2492 \r
2493 static void LeadingCreateTranslation(void)\r
2494 {\r
2495         MS_Message(MSG_DEBUG, "---- LeadingCreateTranslation ----\n");\r
2496         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2497         TK_NextToken();\r
2498         EvalExpression();\r
2499         PC_AppendCmd(PCD_STARTTRANSLATION);\r
2500         while (tk_Token == TK_COMMA)\r
2501         {\r
2502                 pcd_t translationcode;\r
2503 \r
2504                 TK_NextToken();\r
2505                 EvalExpression();       // Get first palette entry in range\r
2506                 TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2507                 TK_NextToken();\r
2508                 EvalExpression();       // Get second palette entry in range\r
2509                 TK_TokenMustBe(TK_ASSIGN, ERR_MISSING_ASSIGN);\r
2510 \r
2511                 TK_NextToken();\r
2512                 if(tk_Token == TK_PERCENT)\r
2513                 {\r
2514                         translationcode = PCD_TRANSLATIONRANGE3;\r
2515                         TK_NextTokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET);\r
2516                 }\r
2517                 else\r
2518                 {\r
2519                         translationcode = PCD_TRANSLATIONRANGE2;\r
2520                 }\r
2521                 if(tk_Token == TK_LBRACKET)\r
2522                 { // Replacement is color range\r
2523                         int i, j;\r
2524 \r
2525                         TK_NextToken();\r
2526 \r
2527                         for(j = 2; j != 0; --j)\r
2528                         {\r
2529                                 for(i = 3; i != 0; --i)\r
2530                                 {\r
2531                                         EvalExpression();\r
2532                                         if(i != 1)\r
2533                                         {\r
2534                                                 TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA);\r
2535                                         }\r
2536                                         else\r
2537                                         {\r
2538                                                 TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET);\r
2539                                         }\r
2540                                         TK_NextToken();\r
2541                                 }\r
2542                                 if(j == 2)\r
2543                                 {\r
2544                                         TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2545                                         TK_NextTokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET);\r
2546                                         TK_NextToken();\r
2547                                 }\r
2548                         }\r
2549                 }\r
2550                 else\r
2551                 { // Replacement is palette range\r
2552                         EvalExpression();\r
2553                         TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2554                         TK_NextToken();\r
2555                         EvalExpression();\r
2556                         translationcode = PCD_TRANSLATIONRANGE1;\r
2557                 }\r
2558                 PC_AppendCmd(translationcode);\r
2559         }\r
2560         PC_AppendCmd(PCD_ENDTRANSLATION);\r
2561         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2562         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2563         TK_NextToken();\r
2564 }\r
2565 \r
2566 //==========================================================================\r
2567 //\r
2568 // LeadingIf\r
2569 //\r
2570 //==========================================================================\r
2571 \r
2572 static void LeadingIf(void)\r
2573 {\r
2574         int jumpAddrPtr1;\r
2575         int jumpAddrPtr2;\r
2576 \r
2577         MS_Message(MSG_DEBUG, "---- LeadingIf ----\n");\r
2578         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2579         TK_NextToken();\r
2580         EvalExpression();\r
2581         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2582         PC_AppendCmd(PCD_IFNOTGOTO);\r
2583         jumpAddrPtr1 = pc_Address;\r
2584         PC_SkipInt();\r
2585         TK_NextToken();\r
2586         if(ProcessStatement(STMT_IF) == NO)\r
2587         {\r
2588                 ERR_Error(ERR_INVALID_STATEMENT, YES);\r
2589         }\r
2590         if(tk_Token == TK_ELSE)\r
2591         {\r
2592                 PC_AppendCmd(PCD_GOTO);\r
2593                 jumpAddrPtr2 = pc_Address;\r
2594                 PC_SkipInt();\r
2595                 PC_WriteInt(pc_Address, jumpAddrPtr1);\r
2596                 TK_NextToken();\r
2597                 if(ProcessStatement(STMT_ELSE) == NO)\r
2598                 {\r
2599                         ERR_Error(ERR_INVALID_STATEMENT, YES);\r
2600                 }\r
2601                 PC_WriteInt(pc_Address, jumpAddrPtr2);\r
2602         }\r
2603         else\r
2604         {\r
2605                 PC_WriteInt(pc_Address, jumpAddrPtr1);\r
2606         }\r
2607 }\r
2608 \r
2609 //==========================================================================\r
2610 //\r
2611 // LeadingFor\r
2612 //\r
2613 //==========================================================================\r
2614 \r
2615 static void LeadingFor(void)\r
2616 {\r
2617         int exprAddr;\r
2618         int incAddr;\r
2619         int ifgotoAddr;\r
2620         int     gotoAddr;\r
2621 \r
2622         MS_Message(MSG_DEBUG, "---- LeadingFor ----\n");\r
2623         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2624         TK_NextToken();\r
2625         if(ProcessStatement(STMT_IF) == NO)\r
2626         {\r
2627                 ERR_Error(ERR_INVALID_STATEMENT, YES);\r
2628         }\r
2629         exprAddr = pc_Address;\r
2630         EvalExpression();\r
2631         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2632         TK_NextToken();\r
2633         PC_AppendCmd(PCD_IFGOTO);\r
2634         ifgotoAddr = pc_Address;\r
2635         PC_SkipInt();\r
2636         PC_AppendCmd(PCD_GOTO);\r
2637         gotoAddr = pc_Address;\r
2638         PC_SkipInt();\r
2639         incAddr = pc_Address;\r
2640         forSemicolonHack = TRUE;\r
2641         if(ProcessStatement(STMT_IF) == NO)\r
2642         {\r
2643                 ERR_Error(ERR_INVALID_STATEMENT, YES);\r
2644         }\r
2645         forSemicolonHack = FALSE;\r
2646         PC_AppendCmd(PCD_GOTO);\r
2647         PC_AppendInt(exprAddr);\r
2648         PC_WriteInt(pc_Address,ifgotoAddr);\r
2649         if(ProcessStatement(STMT_FOR) == NO)\r
2650         {\r
2651                 ERR_Error(ERR_INVALID_STATEMENT, YES);\r
2652         }\r
2653         PC_AppendCmd(PCD_GOTO);\r
2654         PC_AppendInt(incAddr);\r
2655         WriteContinues(incAddr);\r
2656         WriteBreaks();\r
2657         PC_WriteInt(pc_Address,gotoAddr);\r
2658 }\r
2659 \r
2660 //==========================================================================\r
2661 //\r
2662 // LeadingWhileUntil\r
2663 //\r
2664 //==========================================================================\r
2665 \r
2666 static void LeadingWhileUntil(void)\r
2667 {\r
2668         tokenType_t stmtToken;\r
2669         int topAddr;\r
2670         int outAddrPtr;\r
2671 \r
2672         MS_Message(MSG_DEBUG, "---- LeadingWhileUntil ----\n");\r
2673         stmtToken = tk_Token;\r
2674         topAddr = pc_Address;\r
2675         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2676         TK_NextToken();\r
2677         EvalExpression();\r
2678         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2679         PC_AppendCmd(stmtToken == TK_WHILE ? PCD_IFNOTGOTO : PCD_IFGOTO);\r
2680         outAddrPtr = pc_Address;\r
2681         PC_SkipInt();\r
2682         TK_NextToken();\r
2683         if(ProcessStatement(STMT_WHILEUNTIL) == NO)\r
2684         {\r
2685                 ERR_Error(ERR_INVALID_STATEMENT, YES);\r
2686         }\r
2687         PC_AppendCmd(PCD_GOTO);\r
2688         PC_AppendInt(topAddr);\r
2689 \r
2690         PC_WriteInt(pc_Address, outAddrPtr);\r
2691 \r
2692         WriteContinues(topAddr);\r
2693         WriteBreaks();\r
2694 }\r
2695 \r
2696 //==========================================================================\r
2697 //\r
2698 // LeadingDo\r
2699 //\r
2700 //==========================================================================\r
2701 \r
2702 static void LeadingDo(void)\r
2703 {\r
2704         int topAddr;\r
2705         int exprAddr;\r
2706         tokenType_t stmtToken;\r
2707 \r
2708         MS_Message(MSG_DEBUG, "---- LeadingDo ----\n");\r
2709         topAddr = pc_Address;\r
2710         TK_NextToken();\r
2711         if(ProcessStatement(STMT_DO) == NO)\r
2712         {\r
2713                 ERR_Error(ERR_INVALID_STATEMENT, YES, NULL);\r
2714         }\r
2715         if(tk_Token != TK_WHILE && tk_Token != TK_UNTIL)\r
2716         {\r
2717                 ERR_Error(ERR_BAD_DO_STATEMENT, YES, NULL);\r
2718                 TK_SkipPast(TK_SEMICOLON);\r
2719                 return;\r
2720         }\r
2721         stmtToken = tk_Token;\r
2722         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2723         exprAddr = pc_Address;\r
2724         TK_NextToken();\r
2725         EvalExpression();\r
2726         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2727         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2728         PC_AppendCmd(stmtToken == TK_WHILE ? PCD_IFGOTO : PCD_IFNOTGOTO);\r
2729         PC_AppendInt(topAddr);\r
2730         WriteContinues(exprAddr);\r
2731         WriteBreaks();\r
2732         TK_NextToken();\r
2733 }\r
2734 \r
2735 //==========================================================================\r
2736 //\r
2737 // LeadingSwitch\r
2738 //\r
2739 //==========================================================================\r
2740 \r
2741 static void LeadingSwitch(void)\r
2742 {\r
2743         int switcherAddrPtr;\r
2744         int outAddrPtr;\r
2745         caseInfo_t *cInfo;\r
2746         int defaultAddress;\r
2747 \r
2748         MS_Message(MSG_DEBUG, "---- LeadingSwitch ----\n");\r
2749 \r
2750         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2751         TK_NextToken();\r
2752         EvalExpression();\r
2753         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2754 \r
2755         PC_AppendCmd(PCD_GOTO);\r
2756         switcherAddrPtr = pc_Address;\r
2757         PC_SkipInt();\r
2758 \r
2759         TK_NextToken();\r
2760         if(ProcessStatement(STMT_SWITCH) == NO)\r
2761         {\r
2762                 ERR_Error(ERR_INVALID_STATEMENT, YES, NULL);\r
2763         }\r
2764 \r
2765         PC_AppendCmd(PCD_GOTO);\r
2766         outAddrPtr = pc_Address;\r
2767         PC_SkipInt();\r
2768 \r
2769         PC_WriteInt(pc_Address, switcherAddrPtr);\r
2770         defaultAddress = 0;\r
2771 \r
2772         if(pc_HexenCase)\r
2773         {\r
2774                 while((cInfo = GetCaseInfo()) != NULL)\r
2775                 {\r
2776                         if(cInfo->isDefault == YES)\r
2777                         {\r
2778                                 defaultAddress = cInfo->address;\r
2779                                 continue;\r
2780                         }\r
2781                         PC_AppendCmd(PCD_CASEGOTO);\r
2782                         PC_AppendInt(cInfo->value);\r
2783                         PC_AppendInt(cInfo->address);\r
2784                 }\r
2785         }\r
2786         else if(CaseIndex != 0)\r
2787         {\r
2788                 caseInfo_t *maxCase = &CaseInfo[CaseIndex];\r
2789                 caseInfo_t *minCase = maxCase;\r
2790 \r
2791                 // [RH] Sort cases so that the VM can handle them with\r
2792                 // a quick binary search.\r
2793                 while((cInfo = GetCaseInfo()) != NULL)\r
2794                 {\r
2795                         minCase = cInfo;\r
2796                 }\r
2797                 qsort(minCase, maxCase - minCase, sizeof(caseInfo_t), CaseInfoCmp);\r
2798                 if(minCase->isDefault == YES)\r
2799                 {\r
2800                         defaultAddress = minCase->address;\r
2801                         minCase++;\r
2802                 }\r
2803                 if (minCase < maxCase)\r
2804                 {\r
2805                         PC_AppendCmd(PCD_CASEGOTOSORTED);\r
2806                         if(pc_Address%4 != 0)\r
2807                         { // Align to a 4-byte boundary\r
2808                                 U_INT pad = 0;\r
2809                                 PC_Append((void *)&pad, 4-(pc_Address%4));\r
2810                         }\r
2811                         PC_AppendInt(maxCase - minCase);\r
2812                         for(; minCase < maxCase; ++minCase)\r
2813                         {\r
2814                                 PC_AppendInt(minCase->value);\r
2815                                 PC_AppendInt(minCase->address);\r
2816                         }\r
2817                 }\r
2818         }\r
2819         PC_AppendCmd(PCD_DROP);\r
2820 \r
2821         if(defaultAddress != 0)\r
2822         {\r
2823                 PC_AppendCmd(PCD_GOTO);\r
2824                 PC_AppendInt(defaultAddress);\r
2825         }\r
2826 \r
2827         PC_WriteInt(pc_Address, outAddrPtr);\r
2828 \r
2829         WriteBreaks();\r
2830 }\r
2831 \r
2832 //==========================================================================\r
2833 //\r
2834 // LeadingCase\r
2835 //\r
2836 //==========================================================================\r
2837 \r
2838 static void LeadingCase(void)\r
2839 {\r
2840         MS_Message(MSG_DEBUG, "---- LeadingCase ----\n");\r
2841         TK_NextToken();\r
2842         PushCase(EvalConstExpression(), NO);\r
2843         TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2844         TK_NextToken();\r
2845 }\r
2846 \r
2847 //==========================================================================\r
2848 //\r
2849 // LeadingDefault\r
2850 //\r
2851 //==========================================================================\r
2852 \r
2853 static void LeadingDefault(void)\r
2854 {\r
2855         MS_Message(MSG_DEBUG, "---- LeadingDefault ----\n");\r
2856         TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2857         PushCase(0, YES);\r
2858         TK_NextToken();\r
2859 }\r
2860 \r
2861 //==========================================================================\r
2862 //\r
2863 // PushCase\r
2864 //\r
2865 //==========================================================================\r
2866 \r
2867 static void PushCase(int value, boolean isDefault)\r
2868 {\r
2869         if(CaseIndex == MAX_CASE)\r
2870         {\r
2871                 ERR_Exit(ERR_CASE_OVERFLOW, YES);\r
2872         }\r
2873         CaseInfo[CaseIndex].level = StatementLevel;\r
2874         CaseInfo[CaseIndex].value = value;\r
2875         CaseInfo[CaseIndex].isDefault = isDefault;\r
2876         CaseInfo[CaseIndex].address = pc_Address;\r
2877         CaseIndex++;\r
2878 }\r
2879 \r
2880 //==========================================================================\r
2881 //\r
2882 // GetCaseInfo\r
2883 //\r
2884 //==========================================================================\r
2885 \r
2886 static caseInfo_t *GetCaseInfo(void)\r
2887 {\r
2888         if(CaseIndex == 0)\r
2889         {\r
2890                 return NULL;\r
2891         }\r
2892         if(CaseInfo[CaseIndex-1].level > StatementLevel)\r
2893         {\r
2894                 return &CaseInfo[--CaseIndex];\r
2895         }\r
2896         return NULL;\r
2897 }\r
2898 \r
2899 //==========================================================================\r
2900 //\r
2901 // CaseInfoCmp\r
2902 //\r
2903 //==========================================================================\r
2904 \r
2905 static int CaseInfoCmp (const void *a, const void *b)\r
2906 {\r
2907         const caseInfo_t *ca = (const caseInfo_t *)a;\r
2908         const caseInfo_t *cb = (const caseInfo_t *)b;\r
2909 \r
2910         // The default case always gets moved to the front.\r
2911         if(ca->isDefault)\r
2912         {\r
2913                 return -1;\r
2914         }\r
2915         if(cb->isDefault)\r
2916         {\r
2917                 return 1;\r
2918         }\r
2919         return ca->value - cb->value;\r
2920 }\r
2921 \r
2922 //==========================================================================\r
2923 //\r
2924 // DefaultInCurrent\r
2925 //\r
2926 //==========================================================================\r
2927 \r
2928 static boolean DefaultInCurrent(void)\r
2929 {\r
2930         int i;\r
2931 \r
2932         for(i = 0; i < CaseIndex; i++)\r
2933         {\r
2934                 if(CaseInfo[i].isDefault == YES\r
2935                         && CaseInfo[i].level == StatementLevel)\r
2936                 {\r
2937                         return YES;\r
2938                 }\r
2939         }\r
2940         return NO;\r
2941 }\r
2942 \r
2943 //==========================================================================\r
2944 //\r
2945 // LeadingBreak\r
2946 //\r
2947 //==========================================================================\r
2948 \r
2949 static void LeadingBreak(void)\r
2950 {\r
2951         MS_Message(MSG_DEBUG, "---- LeadingBreak ----\n");\r
2952         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2953         PC_AppendCmd(PCD_GOTO);\r
2954         PushBreak();\r
2955         PC_SkipInt();\r
2956         TK_NextToken();\r
2957 }\r
2958 \r
2959 //==========================================================================\r
2960 //\r
2961 // PushBreak\r
2962 //\r
2963 //==========================================================================\r
2964 \r
2965 static void PushBreak(void)\r
2966 {\r
2967         if(BreakIndex == MAX_CASE)\r
2968         {\r
2969                 ERR_Exit(ERR_BREAK_OVERFLOW, YES);\r
2970         }\r
2971         BreakInfo[BreakIndex].level = StatementLevel;\r
2972         BreakInfo[BreakIndex].addressPtr = pc_Address;\r
2973         BreakIndex++;\r
2974 }\r
2975 \r
2976 //==========================================================================\r
2977 //\r
2978 // WriteBreaks\r
2979 //\r
2980 //==========================================================================\r
2981 \r
2982 static void WriteBreaks(void)\r
2983 {\r
2984         while(BreakIndex && BreakInfo[BreakIndex-1].level > StatementLevel)\r
2985         {\r
2986                 PC_WriteInt(pc_Address, BreakInfo[--BreakIndex].addressPtr);\r
2987         }\r
2988 }\r
2989 \r
2990 //==========================================================================\r
2991 //\r
2992 // BreakAncestor\r
2993 //\r
2994 // Returns YES if the current statement history contains a break root\r
2995 // statement.\r
2996 //\r
2997 //==========================================================================\r
2998 \r
2999 static boolean BreakAncestor(void)\r
3000 {\r
3001         int i;\r
3002 \r
3003         for(i = 0; i < StatementIndex; i++)\r
3004         {\r
3005                 if(IsBreakRoot[StatementHistory[i]])\r
3006                 {\r
3007                         return YES;\r
3008                 }\r
3009         }\r
3010         return NO;\r
3011 }\r
3012 \r
3013 //==========================================================================\r
3014 //\r
3015 // LeadingContinue\r
3016 //\r
3017 //==========================================================================\r
3018 \r
3019 static void LeadingContinue(void)\r
3020 {\r
3021         MS_Message(MSG_DEBUG, "---- LeadingContinue ----\n");\r
3022         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3023         PC_AppendCmd(PCD_GOTO);\r
3024         PushContinue();\r
3025         PC_SkipInt();\r
3026         TK_NextToken();\r
3027 }\r
3028 \r
3029 //==========================================================================\r
3030 //\r
3031 // PushContinue\r
3032 //\r
3033 //==========================================================================\r
3034 \r
3035 static void PushContinue(void)\r
3036 {\r
3037         if(ContinueIndex == MAX_CONTINUE)\r
3038         {\r
3039                 ERR_Exit(ERR_CONTINUE_OVERFLOW, YES);\r
3040         }\r
3041         ContinueInfo[ContinueIndex].level = StatementLevel;\r
3042         ContinueInfo[ContinueIndex].addressPtr = pc_Address;\r
3043         ContinueIndex++;\r
3044 }\r
3045 \r
3046 //==========================================================================\r
3047 //\r
3048 // WriteContinues\r
3049 //\r
3050 //==========================================================================\r
3051 \r
3052 static void WriteContinues(int address)\r
3053 {\r
3054         if(ContinueIndex == 0)\r
3055         {\r
3056                 return;\r
3057         }\r
3058         while(ContinueInfo[ContinueIndex-1].level > StatementLevel)\r
3059         {\r
3060                 PC_WriteInt(address, ContinueInfo[--ContinueIndex].addressPtr);\r
3061         }\r
3062 }\r
3063 \r
3064 //==========================================================================\r
3065 //\r
3066 // ContinueAncestor\r
3067 //\r
3068 //==========================================================================\r
3069 \r
3070 static boolean ContinueAncestor(void)\r
3071 {\r
3072         int i;\r
3073 \r
3074         for(i = 0; i < StatementIndex; i++)\r
3075         {\r
3076                 if(IsContinueRoot[StatementHistory[i]])\r
3077                 {\r
3078                         return YES;\r
3079                 }\r
3080         }\r
3081         return NO;\r
3082 }\r
3083 \r
3084 //==========================================================================\r
3085 //\r
3086 // LeadingIncDec\r
3087 //\r
3088 //==========================================================================\r
3089 \r
3090 static void LeadingIncDec(int token)\r
3091 {\r
3092         symbolNode_t *sym;\r
3093 \r
3094         MS_Message(MSG_DEBUG, "---- LeadingIncDec ----\n");\r
3095         TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INCDEC_OP_ON_NON_VAR);\r
3096         sym = DemandSymbol(tk_String);\r
3097         if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR\r
3098                 && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR\r
3099                 && sym->type != SY_MAPARRAY && sym->type != SY_GLOBALARRAY\r
3100                 && sym->type != SY_WORLDARRAY && sym->type != SY_SCRIPTALIAS)\r
3101         {\r
3102                 ERR_Error(ERR_INCDEC_OP_ON_NON_VAR, YES);\r
3103                 TK_SkipPast(TK_SEMICOLON);\r
3104                 return;\r
3105         }\r
3106         TK_NextToken();\r
3107         if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY\r
3108                 || sym->type == SY_GLOBALARRAY)\r
3109         {\r
3110                 ParseArrayIndices(sym, sym->info.array.ndim);\r
3111         }\r
3112         else if(tk_Token == TK_LBRACKET)\r
3113         {\r
3114                 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);\r
3115                 while(tk_Token == TK_LBRACKET)\r
3116                 {\r
3117                         TK_SkipPast(TK_RBRACKET);\r
3118                 }\r
3119         }\r
3120         PC_AppendCmd(GetIncDecPCD(token, sym->type));\r
3121         PC_AppendShrink(sym->info.var.index);\r
3122         if(forSemicolonHack)\r
3123         {\r
3124                 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
3125         }\r
3126         else\r
3127         {\r
3128                 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3129         }\r
3130         TK_NextToken();\r
3131 }\r
3132 \r
3133 //==========================================================================\r
3134 //\r
3135 // LeadingVarAssign\r
3136 //\r
3137 //==========================================================================\r
3138 \r
3139 static void LeadingVarAssign(symbolNode_t *sym)\r
3140 {\r
3141         boolean done;\r
3142         tokenType_t assignToken;\r
3143 \r
3144         MS_Message(MSG_DEBUG, "---- LeadingVarAssign ----\n");\r
3145         done = NO;\r
3146         do\r
3147         {\r
3148                 TK_NextToken(); // Fetch assignment operator\r
3149                 if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY\r
3150                         || sym->type == SY_GLOBALARRAY)\r
3151                 {\r
3152                         ParseArrayIndices(sym, sym->info.array.ndim);\r
3153                 }\r
3154                 else if(tk_Token == TK_LBRACKET)\r
3155                 {\r
3156                         ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);\r
3157                         while(tk_Token == TK_LBRACKET)\r
3158                         {\r
3159                                 TK_SkipPast(TK_RBRACKET);\r
3160                         }\r
3161                 }\r
3162                 if(tk_Token == TK_INC || tk_Token == TK_DEC)\r
3163                 { // Postfix increment or decrement\r
3164                         PC_AppendCmd(GetIncDecPCD(tk_Token, sym->type));\r
3165                         if (pc_NoShrink)\r
3166                         {\r
3167                                 PC_AppendInt(sym->info.var.index);\r
3168                         }\r
3169                         else\r
3170                         {\r
3171                                 PC_AppendByte(sym->info.var.index);\r
3172                         }\r
3173                         TK_NextToken();\r
3174                 }\r
3175                 else\r
3176                 { // Normal operator\r
3177                         if(TK_Member(AssignOps) == NO)\r
3178                         {\r
3179                                 ERR_Error(ERR_MISSING_ASSIGN_OP, YES);\r
3180                                 TK_SkipPast(TK_SEMICOLON);\r
3181                                 return;\r
3182                         }\r
3183                         assignToken = tk_Token;\r
3184                         TK_NextToken();\r
3185                         EvalExpression();\r
3186                         PC_AppendCmd(GetAssignPCD(assignToken, sym->type));\r
3187                         PC_AppendShrink(sym->info.var.index);\r
3188                 }\r
3189                 if(tk_Token == TK_COMMA)\r
3190                 {\r
3191                         TK_NextTokenMustBe(TK_IDENTIFIER, ERR_BAD_ASSIGNMENT);\r
3192                         sym = DemandSymbol(tk_String);\r
3193                         if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR\r
3194                                 && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR\r
3195                                 && sym->type != SY_WORLDARRAY && sym->type != SY_GLOBALARRAY\r
3196                                 && sym->type != SY_SCRIPTALIAS)\r
3197                         {\r
3198                                 ERR_Error(ERR_BAD_ASSIGNMENT, YES);\r
3199                                 TK_SkipPast(TK_SEMICOLON);\r
3200                                 return;\r
3201                         }\r
3202                 }\r
3203                 else\r
3204                 {\r
3205                         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3206                         TK_NextToken();\r
3207                         done = YES;\r
3208                 }\r
3209         } while(done == NO);\r
3210 }\r
3211 \r
3212 //==========================================================================\r
3213 //\r
3214 // GetAssignPCD\r
3215 //\r
3216 //==========================================================================\r
3217 \r
3218 static pcd_t GetAssignPCD(tokenType_t token, symbolType_t symbol)\r
3219 {\r
3220         size_t i, j;\r
3221         static tokenType_t tokenLookup[] =\r
3222         {\r
3223                 TK_ASSIGN, TK_ADDASSIGN, TK_SUBASSIGN,\r
3224                 TK_MULASSIGN, TK_DIVASSIGN, TK_MODASSIGN,\r
3225                 TK_ANDASSIGN, TK_EORASSIGN, TK_ORASSIGN,\r
3226                 TK_LSASSIGN, TK_RSASSIGN\r
3227         };\r
3228         static symbolType_t symbolLookup[] =\r
3229         {\r
3230                 SY_SCRIPTVAR, SY_MAPVAR, SY_WORLDVAR, SY_GLOBALVAR, SY_MAPARRAY,\r
3231                 SY_WORLDARRAY, SY_GLOBALARRAY\r
3232         };\r
3233         static pcd_t assignmentLookup[11][7] =\r
3234         {\r
3235                 { PCD_ASSIGNSCRIPTVAR, PCD_ASSIGNMAPVAR, PCD_ASSIGNWORLDVAR, PCD_ASSIGNGLOBALVAR, PCD_ASSIGNMAPARRAY, PCD_ASSIGNWORLDARRAY, PCD_ASSIGNGLOBALARRAY },\r
3236                 { PCD_ADDSCRIPTVAR, PCD_ADDMAPVAR, PCD_ADDWORLDVAR, PCD_ADDGLOBALVAR, PCD_ADDMAPARRAY, PCD_ADDWORLDARRAY, PCD_ADDGLOBALARRAY },\r
3237                 { PCD_SUBSCRIPTVAR, PCD_SUBMAPVAR, PCD_SUBWORLDVAR, PCD_SUBGLOBALVAR, PCD_SUBMAPARRAY, PCD_SUBWORLDARRAY, PCD_SUBGLOBALARRAY },\r
3238                 { PCD_MULSCRIPTVAR, PCD_MULMAPVAR, PCD_MULWORLDVAR, PCD_MULGLOBALVAR, PCD_MULMAPARRAY, PCD_MULWORLDARRAY, PCD_MULGLOBALARRAY },\r
3239                 { PCD_DIVSCRIPTVAR, PCD_DIVMAPVAR, PCD_DIVWORLDVAR, PCD_DIVGLOBALVAR, PCD_DIVMAPARRAY, PCD_DIVWORLDARRAY, PCD_DIVGLOBALARRAY },\r
3240                 { PCD_MODSCRIPTVAR, PCD_MODMAPVAR, PCD_MODWORLDVAR, PCD_MODGLOBALVAR, PCD_MODMAPARRAY, PCD_MODWORLDARRAY, PCD_MODGLOBALARRAY },\r
3241                 { PCD_ANDSCRIPTVAR, PCD_ANDMAPVAR, PCD_ANDWORLDVAR, PCD_ANDGLOBALVAR, PCD_ANDMAPARRAY, PCD_ANDWORLDARRAY, PCD_ANDGLOBALARRAY },\r
3242                 { PCD_EORSCRIPTVAR, PCD_EORMAPVAR, PCD_EORWORLDVAR, PCD_EORGLOBALVAR, PCD_EORMAPARRAY, PCD_EORWORLDARRAY, PCD_EORGLOBALARRAY },\r
3243                 { PCD_ORSCRIPTVAR, PCD_ORMAPVAR, PCD_ORWORLDVAR, PCD_ORGLOBALVAR, PCD_ORMAPARRAY, PCD_ORWORLDARRAY, PCD_ORGLOBALARRAY },\r
3244                 { PCD_LSSCRIPTVAR, PCD_LSMAPVAR, PCD_LSWORLDVAR, PCD_LSGLOBALVAR, PCD_LSMAPARRAY, PCD_LSWORLDARRAY, PCD_LSGLOBALARRAY },\r
3245                 { PCD_RSSCRIPTVAR, PCD_RSMAPVAR, PCD_RSWORLDVAR, PCD_RSGLOBALVAR, PCD_RSMAPARRAY, PCD_RSWORLDARRAY, PCD_RSGLOBALARRAY }\r
3246         };\r
3247 \r
3248         for(i = 0; i < ARRAY_SIZE(tokenLookup); ++i)\r
3249         {\r
3250                 if(tokenLookup[i] == token)\r
3251                 {\r
3252                         for(j = 0; j < ARRAY_SIZE(symbolLookup); ++j)\r
3253                         {\r
3254                                 if (symbolLookup[j] == symbol)\r
3255                                 {\r
3256                                         return assignmentLookup[i][j];\r
3257                                 }\r
3258                         }\r
3259                         break;\r
3260                 }\r
3261         }\r
3262         return PCD_NOP;\r
3263 }\r
3264 \r
3265 //==========================================================================\r
3266 //\r
3267 // LeadingSuspend\r
3268 //\r
3269 //==========================================================================\r
3270 \r
3271 static void LeadingSuspend(void)\r
3272 {\r
3273         MS_Message(MSG_DEBUG, "---- LeadingSuspend ----\n");\r
3274         if(InsideFunction)\r
3275         {\r
3276                 ERR_Error(ERR_SUSPEND_IN_FUNCTION, YES);\r
3277         }\r
3278         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3279         PC_AppendCmd(PCD_SUSPEND);\r
3280         TK_NextToken();\r
3281 }\r
3282 \r
3283 //==========================================================================\r
3284 //\r
3285 // LeadingTerminate\r
3286 //\r
3287 //==========================================================================\r
3288 \r
3289 static void LeadingTerminate(void)\r
3290 {\r
3291         MS_Message(MSG_DEBUG, "---- LeadingTerminate ----\n");\r
3292         if(InsideFunction)\r
3293         {\r
3294                 ERR_Error(ERR_TERMINATE_IN_FUNCTION, YES);\r
3295         }\r
3296         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3297         PC_AppendCmd(PCD_TERMINATE);\r
3298         TK_NextToken();\r
3299 }\r
3300 \r
3301 //==========================================================================\r
3302 //\r
3303 // LeadingRestart\r
3304 //\r
3305 //==========================================================================\r
3306 \r
3307 static void LeadingRestart(void)\r
3308 {\r
3309         MS_Message(MSG_DEBUG, "---- LeadingRestart ----\n");\r
3310         if(InsideFunction)\r
3311         {\r
3312                 ERR_Error(ERR_RESTART_IN_FUNCTION, YES);\r
3313         }\r
3314         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3315         PC_AppendCmd(PCD_RESTART);\r
3316         TK_NextToken();\r
3317 }\r
3318 \r
3319 //==========================================================================\r
3320 //\r
3321 // LeadingReturn\r
3322 //\r
3323 //==========================================================================\r
3324 \r
3325 static void LeadingReturn(void)\r
3326 {\r
3327         MS_Message(MSG_DEBUG, "---- LeadingReturn ----\n");\r
3328         if(!InsideFunction)\r
3329         {\r
3330                 ERR_Error(ERR_RETURN_OUTSIDE_FUNCTION, YES);\r
3331                 while (TK_NextToken () != TK_SEMICOLON)\r
3332                 {\r
3333                         if (tk_Token == TK_EOF)\r
3334                                 break;\r
3335                 }\r
3336         }\r
3337         else\r
3338         {\r
3339                 TK_NextToken();\r
3340                 if(tk_Token == TK_SEMICOLON)\r
3341                 {\r
3342                         if(InsideFunction->info.scriptFunc.hasReturnValue)\r
3343                         {\r
3344                                 ERR_Error(ERR_MUST_RETURN_A_VALUE, YES);\r
3345                         }\r
3346                         PC_AppendCmd(PCD_RETURNVOID);\r
3347                 }\r
3348                 else\r
3349                 {\r
3350                         if(!InsideFunction->info.scriptFunc.hasReturnValue)\r
3351                         {\r
3352                                 ERR_Error(ERR_MUST_NOT_RETURN_A_VALUE, YES);\r
3353                         }\r
3354                         EvalExpression();\r
3355                         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3356                         PC_AppendCmd(PCD_RETURNVAL);\r
3357                 }\r
3358                 TK_NextToken();\r
3359         }\r
3360 }\r
3361 \r
3362 //==========================================================================\r
3363 //\r
3364 // EvalConstExpression\r
3365 //\r
3366 //==========================================================================\r
3367 \r
3368 static int EvalConstExpression(void)\r
3369 {\r
3370         pa_ConstExprIsString = NO;      // Used by PC_PutMapVariable\r
3371         ExprStackIndex = 0;\r
3372         ConstantExpression = YES;\r
3373         ExprLevA();\r
3374         if(ExprStackIndex != 1)\r
3375         {\r
3376                 ERR_Error(ERR_BAD_CONST_EXPR, YES, NULL);\r
3377                 ExprStack[0] = 0;\r
3378                 ExprStackIndex = 1;\r
3379         }\r
3380         return PopExStk();\r
3381 }\r
3382 \r
3383 //==========================================================================\r
3384 //\r
3385 // EvalExpression\r
3386 //\r
3387 // [RH] Rewrote all the ExprLevA - ExprLevJ functions in favor of a single\r
3388 // table-driven parser function.\r
3389 //\r
3390 //==========================================================================\r
3391 \r
3392 static void EvalExpression(void)\r
3393 {\r
3394         ConstantExpression = NO;\r
3395         ExprLevA();\r
3396 }\r
3397 \r
3398 static void ExprLevA(void)\r
3399 {\r
3400         ExprLevX(0);\r
3401 }\r
3402 \r
3403 // Operator precedence levels:\r
3404 // Operator: ||\r
3405 // Operator: &&\r
3406 // Operator: |\r
3407 // Operator: ^\r
3408 // Operator: &\r
3409 // Operators: == !=\r
3410 // Operators: < <= > >=\r
3411 // Operators: << >>\r
3412 // Operators: + -\r
3413 // Operators: * / %\r
3414 \r
3415 static void ExprLevX(int level)\r
3416 {\r
3417         if(OpsList[level] == NULL)\r
3418         {\r
3419                 boolean unaryMinus;\r
3420 \r
3421                 unaryMinus = FALSE;\r
3422                 if(tk_Token == TK_MINUS)\r
3423                 {\r
3424                         unaryMinus = TRUE;\r
3425                         TK_NextToken();\r
3426                 }\r
3427                 if(tk_Token == TK_PLUS)\r
3428                 {\r
3429                         // Completely ignore unary plus\r
3430                         TK_NextToken();\r
3431                 }\r
3432                 if(ConstantExpression == YES)\r
3433                 {\r
3434                         ConstExprFactor();\r
3435                 }\r
3436                 else\r
3437                 {\r
3438                         ExprFactor();\r
3439                 }\r
3440                 if(unaryMinus == TRUE)\r
3441                 {\r
3442                         SendExprCommand(PCD_UNARYMINUS);\r
3443                 }\r
3444         }\r
3445         else\r
3446         {\r
3447                 ExprLevX(level + 1);\r
3448                 while(TK_Member(OpsList[level]))\r
3449                 {\r
3450                         tokenType_t token = tk_Token;\r
3451                         TK_NextToken();\r
3452                         ExprLevX(level + 1);\r
3453                         SendExprCommand(TokenToPCD(token));\r
3454                 }\r
3455         }\r
3456 }\r
3457 \r
3458 static void ExprLineSpecial(void)\r
3459 {\r
3460         int argCountMin = tk_SpecialArgCount & 0xffff;\r
3461         int argCountMax = tk_SpecialArgCount >> 16;\r
3462         int specialValue = tk_SpecialValue;\r
3463 \r
3464         // There are two ways to use a special in an expression:\r
3465         // 1. The special name by itself returns the special's number.\r
3466         // 2. The special followed by parameters actually executes the special.\r
3467         TK_NextToken();\r
3468         if(tk_Token != TK_LPAREN)\r
3469         {\r
3470                 PC_AppendPushVal(specialValue);\r
3471         }\r
3472         else\r
3473         {\r
3474                 int argCount = 0;\r
3475 \r
3476                 TK_NextToken();\r
3477                 if(tk_Token != TK_RPAREN)\r
3478                 {\r
3479                         TK_Undo();\r
3480                         do\r
3481                         {\r
3482                                 TK_NextToken();\r
3483                                 EvalExpression();\r
3484                                 argCount++;\r
3485                         } while(tk_Token == TK_COMMA);\r
3486                 }\r
3487                 if(argCount < argCountMin || argCount > argCountMax)\r
3488                 {\r
3489                         ERR_Error(specialValue >=0? ERR_BAD_LSPEC_ARG_COUNT : ERR_BAD_ARG_COUNT, YES);\r
3490                         return;\r
3491                 }\r
3492                 if (specialValue >= 0)\r
3493                 {\r
3494                         for(; argCount < 5; ++argCount)\r
3495                         {\r
3496                                 PC_AppendPushVal(0);\r
3497                         }\r
3498                         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
3499                         TK_NextToken();\r
3500                         PC_AppendCmd(PCD_LSPEC5RESULT);\r
3501                         if(pc_NoShrink)\r
3502                         {\r
3503                                 PC_AppendInt(specialValue);\r
3504                         }\r
3505                         else\r
3506                         {\r
3507                                 PC_AppendByte((U_BYTE)specialValue);\r
3508                         }\r
3509                 }\r
3510                 else\r
3511                 {\r
3512                         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
3513                         TK_NextToken();\r
3514                         PC_AppendCmd(PCD_CALLFUNC);\r
3515                         if(pc_NoShrink)\r
3516                         {\r
3517                                 PC_AppendInt(argCount);\r
3518                                 PC_AppendInt(-specialValue);\r
3519                         }\r
3520                         else\r
3521                         {\r
3522                                 PC_AppendByte((U_BYTE)argCount);\r
3523                                 PC_AppendWord((U_WORD)-specialValue);\r
3524                         }\r
3525                 }\r
3526         }\r
3527 }\r
3528 \r
3529 static void ExprFactor(void)\r
3530 {\r
3531         symbolNode_t *sym;\r
3532         tokenType_t opToken;\r
3533 \r
3534         switch(tk_Token)\r
3535         {\r
3536         case TK_STRING:\r
3537                 if (ImportMode != IMPORT_Importing)\r
3538                 {\r
3539                         tk_Number = STR_Find(tk_String);\r
3540                         PC_AppendPushVal(tk_Number);\r
3541                         if (ImportMode == IMPORT_Exporting)\r
3542                         {\r
3543                                 // The VM identifies strings by storing a library ID in the\r
3544                                 // high word of the string index. The library ID is not\r
3545                                 // known until the script actually gets loaded into the game,\r
3546                                 // so we need to use this p-code to tack the ID of the\r
3547                                 // currently running library to the index of the string that\r
3548                                 // just got pushed onto the stack.\r
3549                                 //\r
3550                                 // Simply assuming that a string is from the current library\r
3551                                 // is not good enough, because they can be passed around\r
3552                                 // between libraries and the map's behavior. Thus, we need\r
3553                                 // to know which object file a particular string belongs to.\r
3554                                 //\r
3555                                 // A specific example:\r
3556                                 // A map's behavior calls a function in a library and passes\r
3557                                 // a string:\r
3558                                 //\r
3559                                 //    LibFunc ("The library will do something with this string.");\r
3560                                 //\r
3561                                 // The library function needs to know that the string originated\r
3562                                 // outside the library. Similarly, if a library function returns\r
3563                                 // a string, the caller needs to know that the string did not\r
3564                                 // originate from the same object file.\r
3565                                 //\r
3566                                 // And that's why strings have library IDs tacked onto them.\r
3567                                 // The map's main behavior (i.e. an object that is not a library)\r
3568                                 // always uses library ID 0 to identify its strings, so its\r
3569                                 // strings don't need to be tagged.\r
3570                                 PC_AppendCmd(PCD_TAGSTRING);\r
3571                         }\r
3572                 }\r
3573                 TK_NextToken();\r
3574                 break;\r
3575         case TK_NUMBER:\r
3576                 PC_AppendPushVal(tk_Number);\r
3577                 TK_NextToken();\r
3578                 break;\r
3579         case TK_LPAREN:\r
3580                 TK_NextToken();\r
3581                 ExprLevA();\r
3582                 if(tk_Token != TK_RPAREN)\r
3583                 {\r
3584                         ERR_Error(ERR_BAD_EXPR, YES, NULL);\r
3585                         TK_SkipPast(TK_RPAREN);\r
3586                 }\r
3587                 else\r
3588                 {\r
3589                         TK_NextToken();\r
3590                 }\r
3591                 break;\r
3592         case TK_NOT:\r
3593                 TK_NextToken();\r
3594                 ExprFactor();\r
3595                 PC_AppendCmd(PCD_NEGATELOGICAL);\r
3596                 break;\r
3597         case TK_TILDE:\r
3598                 TK_NextToken();\r
3599                 ExprFactor();\r
3600                 PC_AppendCmd(PCD_NEGATEBINARY);\r
3601                 break;\r
3602         case TK_INC:\r
3603         case TK_DEC:\r
3604                 opToken = tk_Token;\r
3605                 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INCDEC_OP_ON_NON_VAR);\r
3606                 sym = DemandSymbol(tk_String);\r
3607                 if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR\r
3608                         && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR\r
3609                         && sym->type != SY_MAPARRAY && sym->type != SY_WORLDARRAY\r
3610                         && sym->type != SY_GLOBALARRAY)\r
3611                 {\r
3612                         ERR_Error(ERR_INCDEC_OP_ON_NON_VAR, YES);\r
3613                 }\r
3614                 else\r
3615                 {\r
3616                         TK_NextToken();\r
3617                         if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY\r
3618                                 || sym->type == SY_GLOBALARRAY)\r
3619                         {\r
3620                                 ParseArrayIndices(sym, sym->info.array.ndim);\r
3621                                 PC_AppendCmd(PCD_DUP);\r
3622                         }\r
3623                         else if(tk_Token == TK_LBRACKET)\r
3624                         {\r
3625                                 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);\r
3626                                 while(tk_Token == TK_LBRACKET)\r
3627                                 {\r
3628                                         TK_SkipPast(TK_RBRACKET);\r
3629                                 }\r
3630                         }\r
3631                         PC_AppendCmd(GetIncDecPCD(opToken, sym->type));\r
3632                         PC_AppendShrink(sym->info.var.index);\r
3633                         PC_AppendCmd(GetPushVarPCD(sym->type));\r
3634                         PC_AppendShrink(sym->info.var.index);\r
3635                 }\r
3636                 break;\r
3637         case TK_IDENTIFIER:\r
3638                 sym = SpeculateSymbol(tk_String, YES);\r
3639                 switch(sym->type)\r
3640                 {\r
3641                         case SY_SCRIPTALIAS:\r
3642                                 // FIXME\r
3643                                 break;\r
3644                         case SY_MAPARRAY:\r
3645                         case SY_WORLDARRAY:\r
3646                         case SY_GLOBALARRAY:\r
3647                                 TK_NextToken();\r
3648                                 ParseArrayIndices(sym, sym->info.array.ndim);\r
3649                                 // fallthrough\r
3650                         case SY_SCRIPTVAR:\r
3651                         case SY_MAPVAR:\r
3652                         case SY_WORLDVAR:\r
3653                         case SY_GLOBALVAR:\r
3654                                 if(sym->type != SY_MAPARRAY && sym->type != SY_WORLDARRAY\r
3655                                         && sym->type != SY_GLOBALARRAY)\r
3656                                 {\r
3657                                         TK_NextToken();\r
3658                                         if(tk_Token == TK_LBRACKET)\r
3659                                         {\r
3660                                                 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);\r
3661                                                 while(tk_Token == TK_LBRACKET)\r
3662                                                 {\r
3663                                                         TK_SkipPast(TK_RBRACKET);\r
3664                                                 }\r
3665                                         }\r
3666                                 }\r
3667                                 if((tk_Token == TK_INC || tk_Token == TK_DEC)\r
3668                                         && (sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY\r
3669                                                 || sym->type == SY_GLOBALARRAY))\r
3670                                 {\r
3671                                         PC_AppendCmd(PCD_DUP);\r
3672                                 }\r
3673                                 PC_AppendCmd(GetPushVarPCD(sym->type));\r
3674                                 PC_AppendShrink(sym->info.var.index);\r
3675                                 if(tk_Token == TK_INC || tk_Token == TK_DEC)\r
3676                                 {\r
3677                                         if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY\r
3678                                                 || sym->type == SY_GLOBALARRAY)\r
3679                                         {\r
3680                                                 PC_AppendCmd(PCD_SWAP);\r
3681                                         }\r
3682                                         PC_AppendCmd(GetIncDecPCD(tk_Token, sym->type));\r
3683                                         PC_AppendShrink(sym->info.var.index);\r
3684                                         TK_NextToken();\r
3685                                 }\r
3686                                 break;\r
3687                         case SY_INTERNFUNC:\r
3688                                 if(sym->info.internFunc.hasReturnValue == NO)\r
3689                                 {\r
3690                                         ERR_Error(ERR_EXPR_FUNC_NO_RET_VAL, YES);\r
3691                                 }\r
3692                                 ProcessInternFunc(sym);\r
3693                                 break;\r
3694                         case SY_SCRIPTFUNC:\r
3695                                 if(sym->info.scriptFunc.hasReturnValue == NO)\r
3696                                 {\r
3697                                         ERR_Error(ERR_EXPR_FUNC_NO_RET_VAL, YES);\r
3698                                 }\r
3699                                 ProcessScriptFunc(sym, NO);\r
3700                                 break;\r
3701                         default:\r
3702                                 ERR_Error(ERR_ILLEGAL_EXPR_IDENT, YES, tk_String);\r
3703                                 TK_NextToken();\r
3704                                 break;\r
3705                 }\r
3706                 break;\r
3707         case TK_LINESPECIAL:\r
3708                 ExprLineSpecial();\r
3709                 break;\r
3710         case TK_STRPARAM_EVAL:\r
3711                 LeadingPrint();\r
3712                 TK_NextToken();\r
3713                 break;\r
3714         case TK_STRCPY:\r
3715                 LeadingStrcpy();\r
3716                 TK_NextToken();\r
3717                 break;\r
3718         default:\r
3719                 ERR_Error(ERR_BAD_EXPR, YES);\r
3720                 TK_NextToken();\r
3721                 break;\r
3722         }\r
3723 }\r
3724 \r
3725 static void ConstExprFactor(void)\r
3726 {\r
3727         switch(tk_Token)\r
3728         {\r
3729         case TK_STRING:\r
3730                 if (ImportMode != IMPORT_Importing)\r
3731                 {\r
3732                         int strnum = STR_Find(tk_String);\r
3733                         if (ImportMode == IMPORT_Exporting)\r
3734                         {\r
3735                                 pa_ConstExprIsString = YES;\r
3736                         }\r
3737                         PushExStk(strnum);\r
3738                 }\r
3739                 else\r
3740                 {\r
3741                         // Importing, so it doesn't matter\r
3742                         PushExStk(0);\r
3743                 }\r
3744                 TK_NextToken();\r
3745                 break;\r
3746         case TK_NUMBER:\r
3747                 PushExStk(tk_Number);\r
3748                 TK_NextToken();\r
3749                 break;\r
3750         case TK_LPAREN:\r
3751                 TK_NextToken();\r
3752                 ExprLevA();\r
3753                 if(tk_Token != TK_RPAREN)\r
3754                 {\r
3755                         ERR_Error(ERR_BAD_CONST_EXPR, YES);\r
3756                         TK_SkipPast(TK_RPAREN);\r
3757                 }\r
3758                 else\r
3759                 {\r
3760                         TK_NextToken();\r
3761                 }\r
3762                 break;\r
3763         case TK_NOT:\r
3764                 TK_NextToken();\r
3765                 ConstExprFactor();\r
3766                 SendExprCommand(PCD_NEGATELOGICAL);\r
3767                 break;\r
3768         case TK_TILDE:\r
3769                 TK_NextToken();\r
3770                 ConstExprFactor();\r
3771                 SendExprCommand(PCD_NEGATEBINARY);\r
3772                 break;\r
3773         default:\r
3774                 ERR_Error(ERR_BAD_CONST_EXPR, YES);\r
3775                 PushExStk(0);\r
3776                 while(tk_Token != TK_COMMA &&\r
3777                         tk_Token != TK_SEMICOLON &&\r
3778                         tk_Token != TK_RPAREN)\r
3779                 {\r
3780                         if(tk_Token == TK_EOF)\r
3781                         {\r
3782                                 ERR_Exit(ERR_EOF, YES);\r
3783                         }\r
3784                         TK_NextToken();\r
3785                 }\r
3786                 break;\r
3787         }\r
3788 }\r
3789 \r
3790 //==========================================================================\r
3791 //\r
3792 // SendExprCommand\r
3793 //\r
3794 //==========================================================================\r
3795 \r
3796 static void SendExprCommand(pcd_t pcd)\r
3797 {\r
3798         int operand1, operand2;\r
3799 \r
3800         if(ConstantExpression == NO)\r
3801         {\r
3802                 PC_AppendCmd(pcd);\r
3803                 return;\r
3804         }\r
3805         switch(pcd)\r
3806         {\r
3807                 case PCD_ADD:\r
3808                         PushExStk(PopExStk()+PopExStk());\r
3809                         break;\r
3810                 case PCD_SUBTRACT:\r
3811                         operand2 = PopExStk();\r
3812                         PushExStk(PopExStk()-operand2);\r
3813                         break;\r
3814                 case PCD_MULTIPLY:\r
3815                         PushExStk(PopExStk()*PopExStk());\r
3816                         break;\r
3817                 case PCD_DIVIDE:\r
3818                         operand2 = PopExStk();\r
3819                         PushExStk(PopExStk()/operand2);\r
3820                         break;\r
3821                 case PCD_MODULUS:\r
3822                         operand2 = PopExStk();\r
3823                         PushExStk(PopExStk()%operand2);\r
3824                         break;\r
3825                 case PCD_EQ:\r
3826                         PushExStk(PopExStk() == PopExStk());\r
3827                         break;\r
3828                 case PCD_NE:\r
3829                         PushExStk(PopExStk() != PopExStk());\r
3830                         break;\r
3831                 case PCD_LT:\r
3832                         operand2 = PopExStk();\r
3833                         PushExStk(PopExStk() < operand2);\r
3834                         break;\r
3835                 case PCD_GT:\r
3836                         operand2 = PopExStk();\r
3837                         PushExStk(PopExStk() > operand2);\r
3838                         break;\r
3839                 case PCD_LE:\r
3840                         operand2 = PopExStk();\r
3841                         PushExStk(PopExStk() <= operand2);\r
3842                         break;\r
3843                 case PCD_GE:\r
3844                         operand2 = PopExStk();\r
3845                         PushExStk(PopExStk() >= operand2);\r
3846                         break;\r
3847                 case PCD_ANDLOGICAL:\r
3848                         operand2 = PopExStk();\r
3849                         operand1 = PopExStk();\r
3850                         PushExStk(operand1 && operand2);\r
3851                         break;\r
3852                 case PCD_ORLOGICAL:\r
3853                         operand2 = PopExStk();\r
3854                         operand1 = PopExStk();\r
3855                         PushExStk(operand1 || operand2);\r
3856                         break;\r
3857                 case PCD_ANDBITWISE:\r
3858                         PushExStk(PopExStk()&PopExStk());\r
3859                         break;\r
3860                 case PCD_ORBITWISE:\r
3861                         PushExStk(PopExStk()|PopExStk());\r
3862                         break;\r
3863                 case PCD_EORBITWISE:\r
3864                         PushExStk(PopExStk()^PopExStk());\r
3865                         break;\r
3866                 case PCD_NEGATELOGICAL:\r
3867                         PushExStk(!PopExStk());\r
3868                         break;\r
3869                 case PCD_NEGATEBINARY:\r
3870                         PushExStk(~PopExStk());\r
3871                         break;\r
3872                 case PCD_LSHIFT:\r
3873                         operand2 = PopExStk();\r
3874                         PushExStk(PopExStk()<<operand2);\r
3875                         break;\r
3876                 case PCD_RSHIFT:\r
3877                         operand2 = PopExStk();\r
3878                         PushExStk(PopExStk()>>operand2);\r
3879                         break;\r
3880                 case PCD_UNARYMINUS:\r
3881                         PushExStk(-PopExStk());\r
3882                         break;\r
3883                 default:\r
3884                         ERR_Exit(ERR_UNKNOWN_CONST_EXPR_PCD, YES);\r
3885                         break;\r
3886         }\r
3887 }\r
3888 \r
3889 //==========================================================================\r
3890 //\r
3891 // PushExStk\r
3892 //\r
3893 //==========================================================================\r
3894 \r
3895 static void PushExStk(int value)\r
3896 {\r
3897         if(ExprStackIndex == EXPR_STACK_DEPTH)\r
3898         {\r
3899                 ERR_Exit(ERR_EXPR_STACK_OVERFLOW, YES);\r
3900         }\r
3901         ExprStack[ExprStackIndex++] = value;\r
3902 }\r
3903 \r
3904 //==========================================================================\r
3905 //\r
3906 // PopExStk\r
3907 //\r
3908 //==========================================================================\r
3909 \r
3910 static int PopExStk(void)\r
3911 {\r
3912         if(ExprStackIndex < 1)\r
3913         {\r
3914                 ERR_Error(ERR_EXPR_STACK_EMPTY, YES);\r
3915                 return 0;\r
3916         }\r
3917         return ExprStack[--ExprStackIndex];\r
3918 }\r
3919 \r
3920 //==========================================================================\r
3921 //\r
3922 // TokenToPCD\r
3923 //\r
3924 //==========================================================================\r
3925 \r
3926 static pcd_t TokenToPCD(tokenType_t token)\r
3927 {\r
3928         int i;\r
3929         static struct\r
3930         {\r
3931                 tokenType_t token;\r
3932                 pcd_t pcd;\r
3933         }  operatorLookup[] =\r
3934         {\r
3935                 { TK_ORLOGICAL,         PCD_ORLOGICAL },\r
3936                 { TK_ANDLOGICAL,        PCD_ANDLOGICAL },\r
3937                 { TK_ORBITWISE,         PCD_ORBITWISE },\r
3938                 { TK_EORBITWISE,        PCD_EORBITWISE },\r
3939                 { TK_ANDBITWISE,        PCD_ANDBITWISE },\r
3940                 { TK_EQ,                        PCD_EQ },\r
3941                 { TK_NE,                        PCD_NE },\r
3942                 { TK_LT,                        PCD_LT },\r
3943                 { TK_LE,                        PCD_LE },\r
3944                 { TK_GT,                        PCD_GT },\r
3945                 { TK_GE,                        PCD_GE },\r
3946                 { TK_LSHIFT,            PCD_LSHIFT },\r
3947                 { TK_RSHIFT,            PCD_RSHIFT },\r
3948                 { TK_PLUS,                      PCD_ADD },\r
3949                 { TK_MINUS,                     PCD_SUBTRACT },\r
3950                 { TK_ASTERISK,          PCD_MULTIPLY },\r
3951                 { TK_SLASH,                     PCD_DIVIDE },\r
3952                 { TK_PERCENT,           PCD_MODULUS },\r
3953                 { TK_NONE,                      PCD_NOP }\r
3954         };\r
3955 \r
3956         for(i = 0; operatorLookup[i].token != TK_NONE; i++)\r
3957         {\r
3958                 if(operatorLookup[i].token == token)\r
3959                 {\r
3960                         return operatorLookup[i].pcd;\r
3961                 }\r
3962         }\r
3963         return PCD_NOP;\r
3964 }\r
3965 \r
3966 //==========================================================================\r
3967 //\r
3968 // GetPushVarPCD\r
3969 //\r
3970 //==========================================================================\r
3971 \r
3972 static pcd_t GetPushVarPCD(symbolType_t symType)\r
3973 {\r
3974         switch(symType)\r
3975         {\r
3976                 case SY_SCRIPTVAR:\r
3977                         return PCD_PUSHSCRIPTVAR;\r
3978                 case SY_MAPVAR:\r
3979                         return PCD_PUSHMAPVAR;\r
3980                 case SY_WORLDVAR:\r
3981                         return PCD_PUSHWORLDVAR;\r
3982                 case SY_GLOBALVAR:\r
3983                         return PCD_PUSHGLOBALVAR;\r
3984                 case SY_MAPARRAY:\r
3985                         return PCD_PUSHMAPARRAY;\r
3986                 case SY_WORLDARRAY:\r
3987                         return PCD_PUSHWORLDARRAY;\r
3988                 case SY_GLOBALARRAY:\r
3989                         return PCD_PUSHGLOBALARRAY;\r
3990                 default:\r
3991                         break;\r
3992         }\r
3993         return PCD_NOP;\r
3994 }\r
3995 \r
3996 //==========================================================================\r
3997 //\r
3998 // GetIncDecPCD\r
3999 //\r
4000 //==========================================================================\r
4001 \r
4002 static pcd_t GetIncDecPCD(tokenType_t token, symbolType_t symbol)\r
4003 {\r
4004         int i;\r
4005         static struct\r
4006         {\r
4007                 tokenType_t token;\r
4008                 symbolType_t symbol;\r
4009                 pcd_t pcd;\r
4010         }  incDecLookup[] =\r
4011         {\r
4012                 { TK_INC, SY_SCRIPTVAR, PCD_INCSCRIPTVAR },\r
4013                 { TK_INC, SY_MAPVAR, PCD_INCMAPVAR },\r
4014                 { TK_INC, SY_WORLDVAR, PCD_INCWORLDVAR },\r
4015                 { TK_INC, SY_GLOBALVAR, PCD_INCGLOBALVAR },\r
4016                 { TK_INC, SY_MAPARRAY, PCD_INCMAPARRAY },\r
4017                 { TK_INC, SY_WORLDARRAY, PCD_INCWORLDARRAY },\r
4018                 { TK_INC, SY_GLOBALARRAY, PCD_INCGLOBALARRAY },\r
4019 \r
4020                 { TK_DEC, SY_SCRIPTVAR, PCD_DECSCRIPTVAR },\r
4021                 { TK_DEC, SY_MAPVAR, PCD_DECMAPVAR },\r
4022                 { TK_DEC, SY_WORLDVAR, PCD_DECWORLDVAR },\r
4023                 { TK_DEC, SY_GLOBALVAR, PCD_DECGLOBALVAR },\r
4024                 { TK_DEC, SY_MAPARRAY, PCD_DECMAPARRAY },\r
4025                 { TK_DEC, SY_WORLDARRAY, PCD_DECWORLDARRAY },\r
4026                 { TK_DEC, SY_GLOBALARRAY, PCD_DECGLOBALARRAY },\r
4027 \r
4028                 { TK_NONE, SY_DUMMY, PCD_NOP }\r
4029         };\r
4030 \r
4031         for(i = 0; incDecLookup[i].token != TK_NONE; i++)\r
4032         {\r
4033                 if(incDecLookup[i].token == token\r
4034                         && incDecLookup[i].symbol == symbol)\r
4035                 {\r
4036                         return incDecLookup[i].pcd;\r
4037                 }\r
4038         }\r
4039         return PCD_NOP;\r
4040 }\r
4041 \r
4042 //==========================================================================\r
4043 //\r
4044 // ParseArrayIndices\r
4045 //\r
4046 //==========================================================================\r
4047 \r
4048 static void ParseArrayIndices(symbolNode_t *sym, int requiredIndices)\r
4049 {\r
4050         boolean warned = NO;\r
4051         int i;\r
4052 \r
4053         if(requiredIndices > 0)\r
4054         {\r
4055                 TK_TokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET);\r
4056         }\r
4057         i = 0;\r
4058         while(tk_Token == TK_LBRACKET)\r
4059         {\r
4060                 TK_NextToken();\r
4061                 if((sym->type == SY_MAPARRAY && i == requiredIndices) ||\r
4062                         (sym->type != SY_MAPARRAY && i > 0))\r
4063                 {\r
4064                         if (!warned)\r
4065                         {\r
4066                                 warned = YES;\r
4067                                 if(sym->info.array.ndim == requiredIndices)\r
4068                                 {\r
4069                                         ERR_Error(ERR_TOO_MANY_DIM_USED, YES,\r
4070                                                 sym->name, sym->info.array.ndim);\r
4071                                 }\r
4072                                 else\r
4073                                 {\r
4074                                         ERR_Error(ERR_NOT_A_CHAR_ARRAY, YES, sym->name,\r
4075                                                 sym->info.array.ndim, requiredIndices);\r
4076                                 }\r
4077                         }\r
4078                 }\r
4079                 EvalExpression();\r
4080                 if(i < sym->info.array.ndim - 1 && sym->info.array.dimensions[i] > 1)\r
4081                 {\r
4082                         PC_AppendPushVal(sym->info.array.dimensions[i]);\r
4083                         PC_AppendCmd(PCD_MULTIPLY);\r
4084                 }\r
4085                 if(i > 0)\r
4086                 {\r
4087                         PC_AppendCmd(PCD_ADD);\r
4088                 }\r
4089                 i++;\r
4090                 TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET);\r
4091                 TK_NextToken();\r
4092         }\r
4093         if(i < requiredIndices)\r
4094         {\r
4095                 ERR_Error(ERR_TOO_FEW_DIM_USED, YES,\r
4096                         sym->name, requiredIndices - i);\r
4097         }\r
4098         // if there were unspecified indices, multiply the offset by their sizes [JB]\r
4099         if(requiredIndices < sym->info.array.ndim - 1)\r
4100         {\r
4101                 int i, mult = 1;\r
4102                 for(i = 0; i < sym->info.array.ndim - requiredIndices - 1; ++i)\r
4103                 {\r
4104                         mult *= sym->info.array.dimensions[sym->info.array.ndim - 2 - i];\r
4105                 }\r
4106                 if(mult > 1)\r
4107                 {\r
4108                         PC_AppendPushVal(mult);\r
4109                         PC_AppendCmd(PCD_MULTIPLY);\r
4110                 }\r
4111         }\r
4112 }\r
4113 \r
4114 static void ProcessArrayLevel(int level, int *entry, int ndim,\r
4115         int dims[MAX_ARRAY_DIMS], int muls[MAX_ARRAY_DIMS], char *name)\r
4116 {\r
4117         int warned_too_many = NO;\r
4118         int i;\r
4119 \r
4120         for(i = 0; ; ++i)\r
4121         {\r
4122                 if(tk_Token == TK_COMMA)\r
4123                 {\r
4124                         entry += muls[level-1];\r
4125                         TK_NextToken();\r
4126                 }\r
4127                 else if(tk_Token == TK_RBRACE)\r
4128                 {\r
4129                         TK_NextToken();\r
4130                         return;\r
4131                 }\r
4132                 else\r
4133                 {\r
4134                         if(level == ndim)\r
4135                         {\r
4136                                 if(tk_Token == TK_LBRACE)\r
4137                                 {\r
4138                                         ERR_Error(ERR_TOO_MANY_DIM_USED, YES, name, ndim);\r
4139                                         SkipBraceBlock(0);\r
4140                                         TK_NextToken();\r
4141                                         entry++;\r
4142                                 }\r
4143                                 else\r
4144                                 {\r
4145                                         int val;\r
4146 \r
4147                                         if (i >= dims[level - 1] && !warned_too_many)\r
4148                                         {\r
4149                                                 warned_too_many = YES;\r
4150                                                 ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES);\r
4151                                         }\r
4152                                         val = EvalConstExpression();\r
4153                                         ArrayHasStrings |= pa_ConstExprIsString;\r
4154                                         if (i < dims[level - 1])\r
4155                                         {\r
4156                                                 entry[i] = val;\r
4157                                         }\r
4158                                 }\r
4159                         }\r
4160                         else\r
4161                         {\r
4162                                 //Bugfix for r3226 by Zom-B\r
4163                                 if (i >= dims[level - 1])\r
4164                                 {\r
4165                                         if (!warned_too_many)\r
4166                                         {\r
4167                                                 warned_too_many = YES;\r
4168                                                 ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES);\r
4169                                         }\r
4170                                         // Allow execution to continue without stray memory access\r
4171                                         entry -= muls[level-1];\r
4172                                 }\r
4173                                 TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR);\r
4174                                 TK_NextToken();\r
4175                                 ProcessArrayLevel(level+1, entry, ndim, dims, muls, name);\r
4176                                 assert(level > 0);\r
4177                                 entry += muls[level-1];\r
4178                         }\r
4179                         if(i < dims[level-1]-1)\r
4180                         {\r
4181                                 if(tk_Token != TK_RBRACE)\r
4182                                 {\r
4183                                         TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA);\r
4184                                         TK_NextToken();\r
4185                                 }\r
4186                         }\r
4187                         else\r
4188                         {\r
4189                                 if(tk_Token != TK_COMMA)\r
4190                                 {\r
4191                                         TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR);\r
4192                                 }\r
4193                                 else\r
4194                                 {\r
4195                                         TK_NextToken();\r
4196                                 }\r
4197                         }\r
4198                 }\r
4199         }\r
4200         TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR);\r
4201         TK_NextToken();\r
4202 }\r
4203 \r
4204 //==========================================================================\r
4205 //\r
4206 // InitializeArray\r
4207 //\r
4208 //==========================================================================\r
4209 \r
4210 static void InitializeArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS], int size)\r
4211 {\r
4212         static int *entries = NULL;\r
4213         static int lastsize = -1;\r
4214 \r
4215         if(lastsize < size)\r
4216         {\r
4217                 entries = MS_Realloc(entries, sizeof(int)*size, ERR_OUT_OF_MEMORY);\r
4218                 lastsize = size;\r
4219         }\r
4220         memset(entries, 0, sizeof(int)*size);\r
4221 \r
4222         TK_NextTokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR);\r
4223         TK_NextToken();\r
4224         ArrayHasStrings = NO;\r
4225         ProcessArrayLevel(1, entries, sym->info.array.ndim, dims,\r
4226                 sym->info.array.dimensions, sym->name);\r
4227         if(ImportMode != IMPORT_Importing)\r
4228         {\r
4229                 PC_InitArray(sym->info.array.index, entries, ArrayHasStrings);\r
4230         }\r
4231 }\r
4232 \r
4233 //==========================================================================\r
4234 //\r
4235 // DemandSymbol\r
4236 //\r
4237 //==========================================================================\r
4238 \r
4239 static symbolNode_t *DemandSymbol(char *name)\r
4240 {\r
4241         symbolNode_t *sym;\r
4242 \r
4243         if((sym = SY_Find(name)) == NULL)\r
4244         {\r
4245                 ERR_Exit(ERR_UNKNOWN_IDENTIFIER, YES, name);\r
4246         }\r
4247         return sym;\r
4248 }\r
4249 \r
4250 //==========================================================================\r
4251 //\r
4252 // SpeculateSymbol\r
4253 //\r
4254 //==========================================================================\r
4255 \r
4256 static symbolNode_t *SpeculateSymbol(char *name, boolean hasReturn)\r
4257 {\r
4258         symbolNode_t *sym;\r
4259 \r
4260         sym = SY_Find(name);\r
4261         if(sym == NULL)\r
4262         {\r
4263                 char name[MAX_IDENTIFIER_LENGTH];\r
4264 \r
4265                 strcpy (name, tk_String);\r
4266                 TK_NextToken();\r
4267                 if(tk_Token == TK_LPAREN)\r
4268                 { // Looks like a function call\r
4269                         sym = SpeculateFunction(name, hasReturn);\r
4270                         TK_Undo();\r
4271                 }\r
4272                 else\r
4273                 {\r
4274                         ERR_Exit(ERR_UNKNOWN_IDENTIFIER, YES, name);\r
4275                 }\r
4276         }\r
4277         return sym;\r
4278 }\r
4279 \r
4280 //==========================================================================\r
4281 //\r
4282 // SpeculateFunction\r
4283 //\r
4284 // Add a temporary symbol for a function that is used before it is defined.\r
4285 //\r
4286 //==========================================================================\r
4287 \r
4288 static symbolNode_t *SpeculateFunction(const char *name, boolean hasReturn)\r
4289 {\r
4290         symbolNode_t *sym;\r
4291         \r
4292         MS_Message(MSG_DEBUG, "---- SpeculateFunction %s ----\n", name);\r
4293         sym = SY_InsertGlobal(tk_String, SY_SCRIPTFUNC);\r
4294         sym->info.scriptFunc.predefined = YES;\r
4295         sym->info.scriptFunc.hasReturnValue = hasReturn;\r
4296         sym->info.scriptFunc.sourceLine = tk_Line;\r
4297         sym->info.scriptFunc.sourceName = tk_SourceName;\r
4298         sym->info.scriptFunc.argCount = -1;\r
4299         sym->info.scriptFunc.funcNumber = 0;\r
4300         return sym;\r
4301 }\r
4302 \r
4303 //==========================================================================\r
4304 //\r
4305 // UnspeculateFunction\r
4306 //\r
4307 // Fills in function calls that were made before this function was defined.\r
4308 //\r
4309 //==========================================================================\r
4310 \r
4311 static void UnspeculateFunction(symbolNode_t *sym)\r
4312 {\r
4313         prefunc_t *fillin;\r
4314         prefunc_t **prev;\r
4315 \r
4316         prev = &FillinFunctions;\r
4317         fillin = FillinFunctions;\r
4318         while(fillin != NULL)\r
4319         {\r
4320                 prefunc_t *next = fillin->next;\r
4321                 if(fillin->sym == sym)\r
4322                 {\r
4323                         if(fillin->argcount != sym->info.scriptFunc.argCount)\r
4324                         {\r
4325                                 ERR_ErrorAt(fillin->source, fillin->line);\r
4326                                 ERR_Error(ERR_FUNC_ARGUMENT_COUNT, YES, sym->name,\r
4327                                         sym->info.scriptFunc.argCount,\r
4328                                         sym->info.scriptFunc.argCount == 1 ? "" : "s");\r
4329                         }\r
4330 \r
4331                         if(pc_NoShrink)\r
4332                         {\r
4333                                 PC_WriteInt(sym->info.scriptFunc.funcNumber, fillin->address);\r
4334                         }\r
4335                         else\r
4336                         {\r
4337                                 PC_WriteByte((U_BYTE)sym->info.scriptFunc.funcNumber, fillin->address);\r
4338                         }\r
4339                         if(FillinFunctionsLatest == &fillin->next)\r
4340                         {\r
4341                                 FillinFunctionsLatest = prev;\r
4342                         }\r
4343                         free (fillin);\r
4344                         *prev = next;\r
4345                 }\r
4346                 else\r
4347                 {\r
4348                         prev = &fillin->next;\r
4349                 }\r
4350                 fillin = next;\r
4351         }\r
4352 }\r
4353 \r
4354 //==========================================================================\r
4355 //\r
4356 // AddScriptFuncRef\r
4357 //\r
4358 //==========================================================================\r
4359 \r
4360 static void AddScriptFuncRef(symbolNode_t *sym, int address, int argcount)\r
4361 {\r
4362         prefunc_t *fillin = MS_Alloc(sizeof(*fillin), ERR_OUT_OF_MEMORY);\r
4363         fillin->next = NULL;\r
4364         fillin->sym = sym;\r
4365         fillin->address = address;\r
4366         fillin->argcount = argcount;\r
4367         fillin->line = tk_Line;\r
4368         fillin->source = tk_SourceName;\r
4369         *FillinFunctionsLatest = fillin;\r
4370         FillinFunctionsLatest = &fillin->next;\r
4371 }\r
4372 \r
4373 //==========================================================================\r
4374 //\r
4375 // Check for undefined functions\r
4376 //\r
4377 //==========================================================================\r
4378 \r
4379 static void CheckForUndefinedFunctions(void)\r
4380 {\r
4381         prefunc_t *fillin = FillinFunctions;\r
4382 \r
4383         while(fillin != NULL)\r
4384         {\r
4385                 ERR_ErrorAt(fillin->source, fillin->line);\r
4386                 ERR_Error(ERR_UNDEFINED_FUNC, YES, fillin->sym->name);\r
4387                 fillin = fillin->next;\r
4388         }\r
4389 }\r
4390 \r
4391 //==========================================================================\r
4392 //\r
4393 // SkipBraceBlock\r
4394 //\r
4395 // If depth is 0, it scans for the first { and then starts going from there.\r
4396 // At exit, the terminating } is left as the current token.\r
4397 //\r
4398 //==========================================================================\r
4399 \r
4400 void SkipBraceBlock(int depth)\r
4401 {\r
4402         if (depth == 0)\r
4403         {\r
4404                 // Find first {\r
4405                 while(tk_Token != TK_LBRACE)\r
4406                 {\r
4407                         if(tk_Token == TK_EOF)\r
4408                         {\r
4409                                 ERR_Exit(ERR_EOF, NO);\r
4410                         }\r
4411                         TK_NextToken();\r
4412                 }\r
4413                 depth = 1;\r
4414         }\r
4415         // Match it with a }\r
4416         do\r
4417         {\r
4418                 TK_NextToken();\r
4419                 if(tk_Token == TK_EOF)\r
4420                 {\r
4421                         ERR_Exit(ERR_EOF, NO);\r
4422                 }\r
4423                 else if (tk_Token == TK_LBRACE)\r
4424                 {\r
4425                         depth++;\r
4426                 }\r
4427                 else if (tk_Token == TK_RBRACE)\r
4428                 {\r
4429                         depth--;\r
4430                 }\r
4431         } while (depth > 0);\r
4432 }\r