OSDN Git Service

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