OSDN Git Service

- added new AProps to ACC headers.
[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();\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();\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_RESTART:\r
1322                         LeadingRestart();\r
1323                         break;\r
1324                 case TK_SUSPEND:\r
1325                         LeadingSuspend();\r
1326                         break;\r
1327                 case TK_TERMINATE:\r
1328                         LeadingTerminate();\r
1329                         break;\r
1330                 case TK_RETURN:\r
1331                         LeadingReturn();\r
1332                         break;\r
1333                 case TK_IDENTIFIER:\r
1334                         LeadingIdentifier();\r
1335                         break;\r
1336                 case TK_PRINT:\r
1337                 case TK_PRINTBOLD:\r
1338                 case TK_LOG:\r
1339                         LeadingPrint();\r
1340                         break;\r
1341 \r
1342                 case TK_STRPARAM_EVAL:\r
1343                         LeadingPrint();\r
1344                         PC_AppendCmd(PCD_DROP);\r
1345                         /* Duplicate code: LeadingPrint() post-processing: */\r
1346                         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1347                         TK_NextToken();\r
1348                         break;\r
1349 \r
1350                 case TK_STRCPY:\r
1351                         LeadingStrcpy();\r
1352                         PC_AppendCmd(PCD_DROP);\r
1353                         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1354                         TK_NextToken();\r
1355                         break;\r
1356 \r
1357                 case TK_HUDMESSAGE:\r
1358                 case TK_HUDMESSAGEBOLD:\r
1359                         LeadingHudMessage();\r
1360                         break;\r
1361                 case TK_IF:\r
1362                         LeadingIf();\r
1363                         break;\r
1364                 case TK_FOR:\r
1365                         LeadingFor();\r
1366                         break;\r
1367                 case TK_WHILE:\r
1368                 case TK_UNTIL:\r
1369                         LeadingWhileUntil();\r
1370                         break;\r
1371                 case TK_DO:\r
1372                         LeadingDo();\r
1373                         break;\r
1374                 case TK_SWITCH:\r
1375                         LeadingSwitch();\r
1376                         break;\r
1377                 case TK_CASE:\r
1378                         if(owner != STMT_SWITCH)\r
1379                         {\r
1380                                 ERR_Error(ERR_CASE_NOT_IN_SWITCH, YES);\r
1381                                 TK_SkipPast(TK_COLON);\r
1382                         }\r
1383                         else\r
1384                         {\r
1385                                 LeadingCase();\r
1386                         }\r
1387                         break;\r
1388                 case TK_DEFAULT:\r
1389                         if(owner != STMT_SWITCH)\r
1390                         {\r
1391                                 ERR_Error(ERR_DEFAULT_NOT_IN_SWITCH, YES);\r
1392                                 TK_SkipPast(TK_COLON);\r
1393                         }\r
1394                         else if(DefaultInCurrent() == YES)\r
1395                         {\r
1396                                 ERR_Error(ERR_MULTIPLE_DEFAULT, YES);\r
1397                                 TK_SkipPast(TK_COLON);\r
1398                         }\r
1399                         else\r
1400                         {\r
1401                                 LeadingDefault();\r
1402                         }\r
1403                         break;\r
1404                 case TK_BREAK:\r
1405                         if(BreakAncestor() == NO)\r
1406                         {\r
1407                                 ERR_Error(ERR_MISPLACED_BREAK, YES);\r
1408                                 TK_SkipPast(TK_SEMICOLON);\r
1409                         }\r
1410                         else\r
1411                         {\r
1412                                 LeadingBreak();\r
1413                         }\r
1414                         break;\r
1415                 case TK_CONTINUE:\r
1416                         if(ContinueAncestor() == NO)\r
1417                         {\r
1418                                 ERR_Error(ERR_MISPLACED_CONTINUE, YES);\r
1419                                 TK_SkipPast(TK_SEMICOLON);\r
1420                         }\r
1421                         else\r
1422                         {\r
1423                                 LeadingContinue();\r
1424                         }\r
1425                         break;\r
1426                 case TK_CREATETRANSLATION:\r
1427                         LeadingCreateTranslation();\r
1428                         break;\r
1429                 case TK_LBRACE:\r
1430                         LeadingCompoundStatement(owner);\r
1431                         break;\r
1432                 case TK_SEMICOLON:\r
1433                         TK_NextToken();\r
1434                         break;\r
1435                 case TK_INC:\r
1436                 case TK_DEC:\r
1437                         LeadingIncDec(tk_Token);\r
1438                         break;\r
1439 \r
1440                 default:\r
1441                         StatementIndex--;\r
1442                         StatementLevel -= AdjustStmtLevel[owner];\r
1443                         return NO;\r
1444                         break;\r
1445         }\r
1446         StatementIndex--;\r
1447         StatementLevel -= AdjustStmtLevel[owner];\r
1448         return YES;\r
1449 }\r
1450 \r
1451 //==========================================================================\r
1452 //\r
1453 // LeadingCompoundStatement\r
1454 //\r
1455 //==========================================================================\r
1456 \r
1457 static void LeadingCompoundStatement(statement_t owner)\r
1458 {\r
1459         //StatementLevel += AdjustStmtLevel[owner];\r
1460         TK_NextToken(); // Eat the TK_LBRACE\r
1461         do {} while(ProcessStatement(owner) == YES);\r
1462         TK_TokenMustBe(TK_RBRACE, ERR_INVALID_STATEMENT);\r
1463         TK_NextToken();\r
1464         //StatementLevel -= AdjustStmtLevel[owner];\r
1465 }\r
1466 \r
1467 //==========================================================================\r
1468 //\r
1469 // LeadingVarDeclare\r
1470 //\r
1471 //==========================================================================\r
1472 \r
1473 static void LeadingVarDeclare(void)\r
1474 {\r
1475         symbolNode_t *sym = NULL;\r
1476 \r
1477         if(tk_Token == TK_STATIC)\r
1478         {\r
1479                 TK_NextToken();\r
1480                 if(tk_Token != TK_INT && tk_Token != TK_STR && tk_Token != TK_BOOL)\r
1481                 {\r
1482                         ERR_Error(ERR_BAD_VAR_TYPE, YES);\r
1483                         TK_Undo();\r
1484                 }\r
1485                 OuterMapVar(YES);\r
1486                 return;\r
1487         }\r
1488 \r
1489         MS_Message(MSG_DEBUG, "---- LeadingVarDeclare ----\n");\r
1490         do\r
1491         {\r
1492                 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);\r
1493 #if 0\r
1494                 if(ScriptVarCount == MAX_SCRIPT_VARIABLES)\r
1495                 {\r
1496                         ERR_Error(InsideFunction\r
1497                                 ? ERR_TOO_MANY_FUNCTION_VARS\r
1498                                 : ERR_TOO_MANY_SCRIPT_VARS,\r
1499                                 YES, NULL);\r
1500                         ScriptVarCount++;\r
1501                 }\r
1502                 else\r
1503 #endif \r
1504                 if(SY_FindLocal(tk_String) != NULL)\r
1505                 { // Redefined\r
1506                         ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);\r
1507                 }\r
1508                 else\r
1509                 {\r
1510                         sym = SY_InsertLocal(tk_String, SY_SCRIPTVAR);\r
1511                         sym->info.var.index = ScriptVarCount;\r
1512                         ScriptVarCount++;\r
1513                 }\r
1514                 TK_NextToken();\r
1515                 if(tk_Token == TK_LBRACKET)\r
1516                 {\r
1517                         ERR_Error(ERR_ARRAY_MAPVAR_ONLY, YES);\r
1518                         do {} while(TK_NextToken() != TK_COMMA && tk_Token != TK_SEMICOLON);\r
1519                 }\r
1520                 else if(tk_Token == TK_ASSIGN)\r
1521                 {\r
1522                         TK_NextToken();\r
1523                         EvalExpression();\r
1524                         if(sym != NULL)\r
1525                         {\r
1526                                 PC_AppendCmd(PCD_ASSIGNSCRIPTVAR);\r
1527                                 PC_AppendShrink(sym->info.var.index);\r
1528                         }\r
1529                 }\r
1530         } while(tk_Token == TK_COMMA);\r
1531         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1532         TK_NextToken();\r
1533 }\r
1534 \r
1535 //==========================================================================\r
1536 //\r
1537 // LeadingLineSpecial\r
1538 //\r
1539 //==========================================================================\r
1540 \r
1541 static void LeadingLineSpecial(boolean executewait)\r
1542 {\r
1543         int i;\r
1544         int argCount;\r
1545         int argCountMin;\r
1546         int argCountMax;\r
1547         int argSave[8];\r
1548         U_INT specialValue;\r
1549         boolean direct;\r
1550 \r
1551         MS_Message(MSG_DEBUG, "---- LeadingLineSpecial ----\n");\r
1552         argCountMin = tk_SpecialArgCount & 0xffff;\r
1553         argCountMax = tk_SpecialArgCount >> 16;\r
1554         specialValue = tk_SpecialValue;\r
1555         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
1556         i = 0;\r
1557         if(argCountMax > 0)\r
1558         {\r
1559                 if(TK_NextToken() == TK_CONST)\r
1560                 {\r
1561                         TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
1562                         direct = YES;\r
1563                 }\r
1564                 else\r
1565                 {\r
1566                         TK_Undo();\r
1567                         direct = NO;\r
1568                 }\r
1569                 do\r
1570                 {\r
1571                         if(i == argCountMax)\r
1572                         {\r
1573                                 ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES);\r
1574                                 i = argCountMax+1;\r
1575                         }\r
1576                         TK_NextToken();\r
1577                         if(direct == YES)\r
1578                         {\r
1579                                 argSave[i] = EvalConstExpression();\r
1580                         }\r
1581                         else\r
1582                         {\r
1583                                 EvalExpression();\r
1584                                 if (i == 0 && executewait)\r
1585                                 {\r
1586                                         PC_AppendCmd(PCD_DUP);\r
1587                                 }\r
1588                         }\r
1589                         if(i < argCountMax)\r
1590                         {\r
1591                                 i++;\r
1592                         }\r
1593                 } while(tk_Token == TK_COMMA);\r
1594                 if(i < argCountMin)\r
1595                 {\r
1596                         ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES);\r
1597                         TK_SkipPast(TK_SEMICOLON);\r
1598                         return;\r
1599                 }\r
1600                 argCount = i;\r
1601         }\r
1602         else\r
1603         {\r
1604                 // [RH] I added some zero-argument specials without realizing that\r
1605                 // ACS won't allow for less than one, so fake them as one-argument\r
1606                 // specials with a parameter of 0.\r
1607                 argCount = 1;\r
1608                 direct = YES;\r
1609                 argSave[0] = 0;\r
1610                 TK_NextToken ();\r
1611         }\r
1612         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
1613         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1614         if(direct == NO)\r
1615         {\r
1616                 PC_AppendCmd(PCD_LSPEC1+(argCount-1));\r
1617                 if(pc_NoShrink)\r
1618                 {\r
1619                         PC_AppendInt(specialValue);\r
1620                 }\r
1621                 else\r
1622                 {\r
1623                         if (specialValue > 255)\r
1624                         {\r
1625                                 ERR_Error(ERR_SPECIAL_RANGE, YES);\r
1626                         }\r
1627                         PC_AppendByte(specialValue);\r
1628                 }\r
1629                 if(executewait)\r
1630                 {\r
1631                         PC_AppendCmd(PCD_SCRIPTWAIT);\r
1632                 }\r
1633         }\r
1634         else\r
1635         {\r
1636                 boolean useintform;\r
1637 \r
1638                 if(pc_NoShrink)\r
1639                 {\r
1640                         PC_AppendCmd(PCD_LSPEC1DIRECT+(argCount-1));\r
1641                         PC_AppendInt(specialValue);\r
1642                         useintform = YES;\r
1643                 }\r
1644                 else\r
1645                 {\r
1646                         useintform = NO;\r
1647                         for (i = 0; i < argCount; i++)\r
1648                         {\r
1649                                 if ((U_INT)argSave[i] > 255)\r
1650                                 {\r
1651                                         useintform = YES;\r
1652                                         break;\r
1653                                 }\r
1654                         }\r
1655                         PC_AppendCmd((argCount-1)+(useintform?PCD_LSPEC1DIRECT:PCD_LSPEC1DIRECTB));\r
1656                         PC_AppendByte(specialValue);\r
1657                 }\r
1658                 if (useintform)\r
1659                 {\r
1660                         for (i = 0; i < argCount; i++)\r
1661                         {\r
1662                                 PC_AppendInt(argSave[i]);\r
1663                         }\r
1664                 }\r
1665                 else\r
1666                 {\r
1667                         for (i = 0; i < argCount; i++)\r
1668                         {\r
1669                                 PC_AppendByte((U_BYTE)argSave[i]);\r
1670                         }\r
1671                 }\r
1672                 if(executewait)\r
1673                 {\r
1674                         PC_AppendCmd(PCD_SCRIPTWAITDIRECT);\r
1675                         PC_AppendInt(argSave[0]);\r
1676                 }\r
1677         }\r
1678         TK_NextToken();\r
1679 }\r
1680 \r
1681 //==========================================================================\r
1682 //\r
1683 // LeadingLineSpecial\r
1684 //\r
1685 //==========================================================================\r
1686 \r
1687 static void LeadingFunction()\r
1688 {\r
1689         int i;\r
1690         int argCount;\r
1691         int argCountMin;\r
1692         int argCountMax;\r
1693         int specialValue;\r
1694 \r
1695         MS_Message(MSG_DEBUG, "---- LeadingFunction ----\n");\r
1696         argCountMin = tk_SpecialArgCount & 0xffff;\r
1697         argCountMax = tk_SpecialArgCount >> 16;\r
1698         specialValue = -tk_SpecialValue;\r
1699         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
1700         i = 0;\r
1701         if(argCountMax > 0)\r
1702         {\r
1703                 if(TK_NextToken() == TK_CONST)\r
1704                 {\r
1705                         // Just skip const declarators\r
1706                         TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
1707                 }\r
1708                 else\r
1709                 {\r
1710                         TK_Undo();\r
1711                 }\r
1712                 do\r
1713                 {\r
1714                         if(i == argCountMax)\r
1715                         {\r
1716                                 ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
1717                                 i = argCountMax+1;\r
1718                         }\r
1719                         TK_NextToken();\r
1720                         EvalExpression();\r
1721                         if(i < argCountMax)\r
1722                         {\r
1723                                 i++;\r
1724                         }\r
1725                 } while(tk_Token == TK_COMMA);\r
1726                 if(i < argCountMin)\r
1727                 {\r
1728                         ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
1729                         TK_SkipPast(TK_SEMICOLON);\r
1730                         return;\r
1731                 }\r
1732                 argCount = i;\r
1733         }\r
1734         else\r
1735         {\r
1736                 argCount = 0;\r
1737                 TK_NextToken ();\r
1738         }\r
1739         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
1740         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1741         PC_AppendCmd(PCD_CALLFUNC);\r
1742         if(pc_NoShrink)\r
1743         {\r
1744                 PC_AppendInt(argCount);\r
1745                 PC_AppendInt(specialValue);\r
1746         }\r
1747         else\r
1748         {\r
1749                 PC_AppendByte((U_BYTE)argCount);\r
1750                 PC_AppendWord((U_WORD)specialValue);\r
1751         }\r
1752         PC_AppendCmd(PCD_DROP);\r
1753         TK_NextToken();\r
1754 }\r
1755 \r
1756 //==========================================================================\r
1757 //\r
1758 // LeadingIdentifier\r
1759 //\r
1760 //==========================================================================\r
1761 \r
1762 static void LeadingIdentifier(void)\r
1763 {\r
1764         symbolNode_t *sym;\r
1765 \r
1766         sym = SpeculateSymbol(tk_String, NO);\r
1767         switch(sym->type)\r
1768         {\r
1769                 case SY_MAPARRAY:\r
1770                 case SY_SCRIPTVAR:\r
1771                 case SY_SCRIPTALIAS:\r
1772                 case SY_MAPVAR:\r
1773                 case SY_WORLDVAR:\r
1774                 case SY_GLOBALVAR:\r
1775                 case SY_WORLDARRAY:\r
1776                 case SY_GLOBALARRAY:\r
1777                         LeadingVarAssign(sym);\r
1778                         break;\r
1779                 case SY_INTERNFUNC:\r
1780                         LeadingInternFunc(sym);\r
1781                         break;\r
1782                 case SY_SCRIPTFUNC:\r
1783                         LeadingScriptFunc(sym);\r
1784                         break;\r
1785                 default:\r
1786                         break;\r
1787         }\r
1788 }\r
1789 \r
1790 //==========================================================================\r
1791 //\r
1792 // LeadingInternFunc\r
1793 //\r
1794 //==========================================================================\r
1795 \r
1796 static void LeadingInternFunc(symbolNode_t *sym)\r
1797 {\r
1798         if(InsideFunction && sym->info.internFunc.latent)\r
1799         {\r
1800                 ERR_Error(ERR_LATENT_IN_FUNC, YES);\r
1801         }\r
1802         ProcessInternFunc(sym);\r
1803         if(sym->info.internFunc.hasReturnValue == YES)\r
1804         {\r
1805                 PC_AppendCmd(PCD_DROP);\r
1806         }\r
1807         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
1808         TK_NextToken();\r
1809 }\r
1810 \r
1811 //==========================================================================\r
1812 //\r
1813 // ProcessInternFunc\r
1814 //\r
1815 //==========================================================================\r
1816 \r
1817 static void ProcessInternFunc(symbolNode_t *sym)\r
1818 {\r
1819         int i;\r
1820         int argCount;\r
1821         int optMask;\r
1822         int outMask;\r
1823         boolean direct;\r
1824         boolean specialDirect;\r
1825         int argSave[8];\r
1826 \r
1827         MS_Message(MSG_DEBUG, "---- ProcessInternFunc ----\n");\r
1828         argCount = sym->info.internFunc.argCount;\r
1829         optMask = sym->info.internFunc.optMask;\r
1830         outMask = sym->info.internFunc.outMask;\r
1831         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
1832         if(TK_NextToken() == TK_CONST)\r
1833         {\r
1834                 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
1835                 if(sym->info.internFunc.directCommand == PCD_NOP)\r
1836                 {\r
1837                         ERR_Error(ERR_NO_DIRECT_VER, YES, NULL);\r
1838                         direct = NO;\r
1839                         specialDirect = NO;\r
1840                 }\r
1841                 else\r
1842                 {\r
1843                         direct = YES;\r
1844                         if (pc_NoShrink || argCount > 2 ||\r
1845                                 (sym->info.internFunc.directCommand != PCD_DELAYDIRECT &&\r
1846                                  sym->info.internFunc.directCommand != PCD_RANDOMDIRECT))\r
1847                         {\r
1848                                 specialDirect = NO;\r
1849                                 PC_AppendCmd(sym->info.internFunc.directCommand);\r
1850                         }\r
1851                         else\r
1852                         {\r
1853                                 specialDirect = YES;\r
1854                         }\r
1855                 }\r
1856                 TK_NextToken();\r
1857         }\r
1858         else\r
1859         {\r
1860                 direct = NO;\r
1861                 specialDirect = NO;     // keep GCC quiet\r
1862         }\r
1863         i = 0;\r
1864         if(argCount > 0)\r
1865         {\r
1866                 if(tk_Token == TK_RPAREN)\r
1867                 {\r
1868                         ERR_Error(ERR_MISSING_PARAM, YES);\r
1869                 }\r
1870                 else\r
1871                 {\r
1872                         TK_Undo(); // Adjust for first expression\r
1873                         do\r
1874                         {\r
1875                                 if(i == argCount)\r
1876                                 {\r
1877                                         ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
1878                                         TK_SkipTo(TK_SEMICOLON);\r
1879                                         TK_Undo();\r
1880                                         return;\r
1881                                 }\r
1882                                 TK_NextToken();\r
1883                                 if(direct == YES)\r
1884                                 {\r
1885                                         if (tk_Token != TK_COMMA)\r
1886                                         {\r
1887                                                 if (specialDirect)\r
1888                                                 {\r
1889                                                         argSave[i] = EvalConstExpression();\r
1890                                                 }\r
1891                                                 else\r
1892                                                 {\r
1893                                                         PC_AppendInt(EvalConstExpression());\r
1894                                                 }\r
1895                                         }\r
1896                                         else\r
1897                                         {\r
1898                                                 if (optMask & 1)\r
1899                                                 {\r
1900                                                         if (specialDirect)\r
1901                                                         {\r
1902                                                                 argSave[i] = 0;\r
1903                                                         }\r
1904                                                         else\r
1905                                                         {\r
1906                                                                 PC_AppendInt(0);\r
1907                                                         }\r
1908                                                 }\r
1909                                                 else\r
1910                                                 {\r
1911                                                         ERR_Error(ERR_MISSING_PARAM, YES);\r
1912                                                 }\r
1913                                         }\r
1914                                 }\r
1915                                 else\r
1916                                 {\r
1917                                         if (tk_Token != TK_COMMA)\r
1918                                         {\r
1919                                                 if (!(outMask & 1))\r
1920                                                 {\r
1921                                                         EvalExpression();\r
1922                                                 }\r
1923                                                 else if (tk_Token != TK_IDENTIFIER)\r
1924                                                 {\r
1925                                                         ERR_Error (ERR_PARM_MUST_BE_VAR, YES);\r
1926                                                         do\r
1927                                                         {\r
1928                                                                 TK_NextToken();\r
1929                                                         } while (tk_Token != TK_COMMA && tk_Token != TK_RPAREN);\r
1930                                                 }\r
1931                                                 else\r
1932                                                 {\r
1933                                                         symbolNode_t *sym = DemandSymbol (tk_String);\r
1934                                                         PC_AppendCmd (PCD_PUSHNUMBER);\r
1935                                                         switch (sym->type)\r
1936                                                         {\r
1937                                                         case SY_SCRIPTVAR:\r
1938                                                                 PC_AppendInt(sym->info.var.index | OUTVAR_SCRIPT_SPEC);\r
1939                                                                 break;\r
1940                                                         case SY_MAPVAR:\r
1941                                                                 PC_AppendInt(sym->info.var.index | OUTVAR_MAP_SPEC);\r
1942                                                                 break;\r
1943                                                         case SY_WORLDVAR:\r
1944                                                                 PC_AppendInt(sym->info.var.index | OUTVAR_WORLD_SPEC);\r
1945                                                                 break;\r
1946                                                         case SY_GLOBALVAR:\r
1947                                                                 PC_AppendInt(sym->info.var.index | OUTVAR_GLOBAL_SPEC);\r
1948                                                                 break;\r
1949                                                         default:\r
1950                                                                 ERR_Error (ERR_PARM_MUST_BE_VAR, YES);\r
1951                                                                 do\r
1952                                                                 {\r
1953                                                                         TK_NextToken();\r
1954                                                                 } while (tk_Token != TK_COMMA && tk_Token != TK_RPAREN);\r
1955                                                                 break;\r
1956                                                         }\r
1957                                                         TK_NextToken ();\r
1958                                                 }\r
1959                                         }\r
1960                                         else\r
1961                                         {\r
1962                                                 if (optMask & 1)\r
1963                                                 {\r
1964                                                         PC_AppendPushVal(0);\r
1965                                                 }\r
1966                                                 else\r
1967                                                 {\r
1968                                                         ERR_Error(ERR_MISSING_PARAM, YES);\r
1969                                                 }\r
1970                                         }\r
1971                                 }\r
1972                                 i++;\r
1973                                 optMask >>= 1;\r
1974                                 outMask >>= 1;\r
1975                         } while(tk_Token == TK_COMMA);\r
1976                 }\r
1977         }\r
1978         while (i < argCount && (optMask & 1))\r
1979         {\r
1980                 if (direct == YES)\r
1981                 {\r
1982                         if (specialDirect)\r
1983                         {\r
1984                                 argSave[i] = 0;\r
1985                         }\r
1986                         else\r
1987                         {\r
1988                                 PC_AppendInt(0);\r
1989                         }\r
1990                 }\r
1991                 else\r
1992                 {\r
1993                         PC_AppendPushVal(0);\r
1994                 }\r
1995                 i++;\r
1996                 optMask >>= 1;\r
1997         }\r
1998         if(i != argCount && i > 0)\r
1999         {\r
2000                 ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
2001         }\r
2002         TK_TokenMustBe(TK_RPAREN, argCount > 0 ? ERR_MISSING_RPAREN : ERR_BAD_ARG_COUNT);\r
2003         if(direct == NO)\r
2004         {\r
2005                 PC_AppendCmd(sym->info.internFunc.stackCommand);\r
2006         }\r
2007         else if (specialDirect)\r
2008         {\r
2009                 boolean useintform = NO;\r
2010                 pcd_t shortpcd;\r
2011 \r
2012                 switch (sym->info.internFunc.directCommand)\r
2013                 {\r
2014                 case PCD_DELAYDIRECT:\r
2015                         shortpcd = PCD_DELAYDIRECTB;\r
2016                         break;\r
2017                 case PCD_RANDOMDIRECT:\r
2018                         shortpcd = PCD_RANDOMDIRECTB;\r
2019                         break;\r
2020                 default:\r
2021                         useintform = YES;\r
2022                         shortpcd = PCD_NOP;\r
2023                         break;\r
2024                 }\r
2025 \r
2026                 if (!useintform)\r
2027                 {\r
2028                         for (i = 0; i < argCount; i++)\r
2029                         {\r
2030                                 if ((U_INT)argSave[i] > 255)\r
2031                                 {\r
2032                                         useintform = YES;\r
2033                                         break;\r
2034                                 }\r
2035                         }\r
2036                 }\r
2037 \r
2038                 if (useintform)\r
2039                 {\r
2040                         PC_AppendCmd(sym->info.internFunc.directCommand);\r
2041                         for (i = 0; i < argCount; i++)\r
2042                         {\r
2043                                 PC_AppendInt (argSave[i]);\r
2044                         }\r
2045                 }\r
2046                 else\r
2047                 {\r
2048                         PC_AppendCmd (shortpcd);\r
2049                         for (i = 0; i < argCount; i++)\r
2050                         {\r
2051                                 PC_AppendByte ((U_BYTE)argSave[i]);\r
2052                         }\r
2053                 }\r
2054         }\r
2055         TK_NextToken();\r
2056 }\r
2057 \r
2058 //==========================================================================\r
2059 //\r
2060 // LeadingScriptFunc\r
2061 //\r
2062 //==========================================================================\r
2063 \r
2064 static void LeadingScriptFunc(symbolNode_t *sym)\r
2065 {\r
2066         ProcessScriptFunc(sym, YES);\r
2067         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2068         TK_NextToken();\r
2069 }\r
2070 \r
2071 \r
2072 //==========================================================================\r
2073 //\r
2074 // ProcessScriptFunc\r
2075 //\r
2076 //==========================================================================\r
2077 \r
2078 static void ProcessScriptFunc(symbolNode_t *sym, boolean discardReturn)\r
2079 {\r
2080         int i;\r
2081         int argCount;\r
2082 \r
2083         MS_Message(MSG_DEBUG, "---- ProcessScriptFunc ----\n");\r
2084         argCount = sym->info.scriptFunc.argCount;\r
2085         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2086         i = 0;\r
2087         if(argCount == 0)\r
2088         {\r
2089                 TK_NextTokenMustBe(TK_RPAREN, ERR_BAD_ARG_COUNT);\r
2090         }\r
2091         else if(argCount > 0)\r
2092         {\r
2093                 TK_NextToken();\r
2094                 if(tk_Token == TK_RPAREN)\r
2095                 {\r
2096                         ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
2097                         TK_SkipTo(TK_SEMICOLON);\r
2098                         return;\r
2099                 }\r
2100                 TK_Undo();\r
2101                 do\r
2102                 {\r
2103                         if(i == argCount)\r
2104                         {\r
2105                                 ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
2106                                 TK_SkipTo(TK_SEMICOLON);\r
2107                                 return;\r
2108                         }\r
2109                         TK_NextToken();\r
2110                         if (tk_Token != TK_COMMA)\r
2111                         {\r
2112                                 EvalExpression();\r
2113                         }\r
2114                         else\r
2115                         {\r
2116                                 ERR_Error(ERR_MISSING_PARAM, YES);\r
2117                                 TK_SkipTo(TK_SEMICOLON);\r
2118                                 return;\r
2119                         }\r
2120                         i++;\r
2121                 } while(tk_Token == TK_COMMA);\r
2122         }\r
2123         if(argCount < 0)\r
2124         { // Function has not been defined yet, so assume arg count is correct\r
2125                 TK_NextToken();\r
2126                 while (tk_Token != TK_RPAREN)\r
2127                 {\r
2128                         EvalExpression();\r
2129                         i++;\r
2130                         if (tk_Token == TK_COMMA)\r
2131                         {\r
2132                                 TK_NextToken();\r
2133                         }\r
2134                         else if (tk_Token != TK_RPAREN)\r
2135                         {\r
2136                                 ERR_Error(ERR_MISSING_PARAM, YES);\r
2137                                 TK_SkipTo(TK_SEMICOLON);\r
2138                                 return;\r
2139                         }\r
2140                 }\r
2141         }\r
2142         else if(i != argCount)\r
2143         {\r
2144                 ERR_Error(ERR_BAD_ARG_COUNT, YES);\r
2145                 TK_SkipTo(TK_SEMICOLON);\r
2146                 return;\r
2147         }\r
2148         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2149         PC_AppendCmd(discardReturn ? PCD_CALLDISCARD : PCD_CALL);\r
2150         if(sym->info.scriptFunc.predefined && ImportMode != IMPORT_Importing)\r
2151         {\r
2152                 AddScriptFuncRef(sym, pc_Address, i);\r
2153         }\r
2154         if (pc_NoShrink)\r
2155         {\r
2156                 PC_AppendInt(sym->info.scriptFunc.funcNumber);\r
2157         }\r
2158         else\r
2159         {\r
2160                 PC_AppendByte((U_BYTE)sym->info.scriptFunc.funcNumber);\r
2161         }\r
2162         TK_NextToken();\r
2163 }\r
2164 \r
2165 //==========================================================================\r
2166 //\r
2167 // BuildPrintString\r
2168 //\r
2169 //==========================================================================\r
2170 \r
2171 static void BuildPrintString(void)\r
2172 {\r
2173         pcd_t printCmd;\r
2174 \r
2175         do\r
2176         {\r
2177                 switch(TK_NextCharacter())\r
2178                 {\r
2179                         case 'a': // character array support [JB]\r
2180                                 ActionOnCharRange(NO);\r
2181                                 continue;\r
2182                         case 's': // string\r
2183                                 printCmd = PCD_PRINTSTRING;\r
2184                                 break;\r
2185                         case 'l': // [RH] localized string\r
2186                                 printCmd = PCD_PRINTLOCALIZED;\r
2187                                 break;\r
2188                         case 'i': // integer\r
2189                         case 'd': // decimal\r
2190                                 printCmd = PCD_PRINTNUMBER;\r
2191                                 break;\r
2192                         case 'c': // character\r
2193                                 printCmd = PCD_PRINTCHARACTER;\r
2194                                 break;\r
2195                         case 'n': // [BC] name\r
2196                                 printCmd = PCD_PRINTNAME;\r
2197                                 break;\r
2198                         case 'f': // [RH] fixed point\r
2199                                 printCmd = PCD_PRINTFIXED;\r
2200                                 break;\r
2201                         case 'k': // [GRB] key binding\r
2202                                 printCmd = PCD_PRINTBIND;\r
2203                                 break;\r
2204                         case 'b': // [RH] binary integer\r
2205                                 printCmd = PCD_PRINTBINARY;\r
2206                                 break;\r
2207                         case 'x': // [RH] hexadecimal integer\r
2208                                 printCmd = PCD_PRINTHEX;\r
2209                                 break;\r
2210                         default:\r
2211                                 printCmd = PCD_PRINTSTRING;\r
2212                                 ERR_Error(ERR_UNKNOWN_PRTYPE, YES);\r
2213                                 break;\r
2214                 }\r
2215                 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2216                 TK_NextToken();\r
2217                 EvalExpression();\r
2218                 PC_AppendCmd(printCmd);\r
2219         } while(tk_Token == TK_COMMA);\r
2220 }\r
2221 \r
2222 //==========================================================================\r
2223 //\r
2224 // ActionOnCharRange // FDARI (mutation of PrintCharArray // JB)\r
2225 //\r
2226 //==========================================================================\r
2227 \r
2228 static void ActionOnCharRange(boolean write)\r
2229 {\r
2230         boolean rangeConstraints;\r
2231         symbolNode_t *sym;\r
2232         TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2233         TK_NextToken();\r
2234 \r
2235         if (tk_Token == TK_LPAREN)\r
2236         {\r
2237                 rangeConstraints = YES;\r
2238                 TK_NextToken();\r
2239         }\r
2240         else\r
2241         {\r
2242                 rangeConstraints = NO;\r
2243         }\r
2244 \r
2245         sym = SpeculateSymbol(tk_String, NO);\r
2246         if((sym->type != SY_MAPARRAY) && (sym->type != SY_WORLDARRAY)\r
2247                 && (sym->type != SY_GLOBALARRAY))\r
2248         {\r
2249                 ERR_Error(ERR_NOT_AN_ARRAY, YES);\r
2250         }\r
2251         TK_NextToken();\r
2252         if(sym->info.array.ndim > 1)\r
2253         {\r
2254                 ParseArrayIndices(sym, sym->info.array.ndim-1);\r
2255         }\r
2256         else\r
2257         {\r
2258                 PC_AppendPushVal(0);\r
2259         }\r
2260 \r
2261         PC_AppendPushVal(sym->info.array.index);\r
2262 \r
2263         \r
2264         if (rangeConstraints)\r
2265         {\r
2266                 switch (tk_Token)\r
2267                 {\r
2268                 case TK_RPAREN:\r
2269                         rangeConstraints = NO;\r
2270                         TK_NextToken();\r
2271                         break;\r
2272                 case TK_COMMA:\r
2273                         TK_NextToken();\r
2274                         EvalExpression();\r
2275 \r
2276                         switch (tk_Token)\r
2277                         {\r
2278                         case TK_RPAREN:\r
2279                                 TK_NextToken();\r
2280                                 PC_AppendPushVal(0x7FFFFFFF); \r
2281                                 break;\r
2282                         case TK_COMMA:\r
2283                                 TK_NextToken();\r
2284                                 EvalExpression(); // limit on capacity\r
2285                                 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2286                                 TK_NextToken();\r
2287                                 break;\r
2288                         default:\r
2289                                 ERR_Error(ERR_MISSING_RPAREN, YES);\r
2290                                 break;\r
2291                         }\r
2292 \r
2293                         break;\r
2294                 default:\r
2295                         ERR_Error(ERR_MISSING_RPAREN, YES);\r
2296                         break;\r
2297                 }\r
2298         }\r
2299 \r
2300         if (write)\r
2301         {\r
2302                 if (!rangeConstraints)\r
2303                 {\r
2304                         PC_AppendPushVal(0);\r
2305                         PC_AppendPushVal(0x7FFFFFFF);\r
2306                 }\r
2307 \r
2308                 TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA);\r
2309                 TK_NextToken();\r
2310                 EvalExpression();\r
2311 \r
2312                 if (tk_Token == TK_COMMA)\r
2313                 {\r
2314                         TK_NextToken();\r
2315                         EvalExpression();\r
2316                 }\r
2317                 else\r
2318                 {\r
2319                         PC_AppendPushVal(0);\r
2320                 }\r
2321         }\r
2322 \r
2323         if(sym->type == SY_MAPARRAY)\r
2324         {\r
2325                 if (write) PC_AppendCmd(PCD_STRCPYTOMAPCHRANGE);\r
2326                 else PC_AppendCmd( rangeConstraints ? PCD_PRINTMAPCHRANGE : PCD_PRINTMAPCHARARRAY );\r
2327         }\r
2328         else if(sym->type == SY_WORLDARRAY)\r
2329         {\r
2330                 if (write) PC_AppendCmd(PCD_STRCPYTOWORLDCHRANGE);\r
2331                 else PC_AppendCmd( rangeConstraints ? PCD_PRINTWORLDCHRANGE : PCD_PRINTWORLDCHARARRAY );\r
2332         }\r
2333         else // if(sym->type == SY_GLOBALARRAY)\r
2334         {\r
2335                 if (write) PC_AppendCmd(PCD_STRCPYTOGLOBALCHRANGE);\r
2336                 else PC_AppendCmd( rangeConstraints ? PCD_PRINTGLOBALCHRANGE : PCD_PRINTGLOBALCHARARRAY );\r
2337         }\r
2338 }\r
2339 \r
2340 //==========================================================================\r
2341 //\r
2342 // LeadingStrcpy\r
2343 //\r
2344 //==========================================================================\r
2345 \r
2346 static void LeadingStrcpy(void)\r
2347 {\r
2348         MS_Message(MSG_DEBUG, "---- LeadingStrcpy ----\n");\r
2349         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2350         \r
2351         switch(TK_NextCharacter()) // structure borrowed from printbuilder\r
2352         {\r
2353                 case 'a':\r
2354                         ActionOnCharRange(YES);\r
2355                         break;\r
2356 \r
2357                 default:\r
2358                         ERR_Error(ERR_UNKNOWN_PRTYPE, YES);\r
2359                         break;\r
2360         }\r
2361 \r
2362         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2363 }\r
2364 \r
2365 //==========================================================================\r
2366 //\r
2367 // LeadingPrint\r
2368 //\r
2369 //==========================================================================\r
2370 \r
2371 static void LeadingPrint(void)\r
2372 {\r
2373         tokenType_t stmtToken;\r
2374 \r
2375         MS_Message(MSG_DEBUG, "---- LeadingPrint ----\n");\r
2376         stmtToken = tk_Token; // Will be TK_PRINT or TK_PRINTBOLD, TK_LOG or TK_STRPARAM_EVAL [FDARI]\r
2377         PC_AppendCmd(PCD_BEGINPRINT);\r
2378         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2379         BuildPrintString();\r
2380         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2381 \r
2382         switch (stmtToken)\r
2383         {\r
2384         case TK_PRINT:\r
2385                 PC_AppendCmd(PCD_ENDPRINT);\r
2386                 break;\r
2387 \r
2388         case TK_PRINTBOLD:\r
2389                 PC_AppendCmd(PCD_ENDPRINTBOLD);\r
2390                 break;\r
2391 \r
2392         case TK_STRPARAM_EVAL:\r
2393                 PC_AppendCmd(PCD_SAVESTRING);\r
2394                 return; // THE CALLER MUST DO THE POST-PROCESSING\r
2395 \r
2396         case TK_LOG:\r
2397         default:\r
2398                 PC_AppendCmd(PCD_ENDLOG);\r
2399                 break;\r
2400         }\r
2401 \r
2402         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2403         TK_NextToken();\r
2404 }\r
2405 \r
2406 //==========================================================================\r
2407 //\r
2408 // LeadingHudMessage\r
2409 //\r
2410 // hudmessage(str text; int type, int id, int color, fixed x, fixed y, fixed holdtime, ...)\r
2411 //\r
2412 //==========================================================================\r
2413 \r
2414 static void LeadingHudMessage(void)\r
2415 {\r
2416         tokenType_t stmtToken;\r
2417         int i;\r
2418 \r
2419         MS_Message(MSG_DEBUG, "---- LeadingHudMessage ----\n");\r
2420         stmtToken = tk_Token; // Will be TK_HUDMESSAGE or TK_HUDMESSAGEBOLD\r
2421         PC_AppendCmd(PCD_BEGINPRINT);\r
2422         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2423         BuildPrintString();\r
2424         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_PARAM);\r
2425         PC_AppendCmd(PCD_MOREHUDMESSAGE);\r
2426         for (i = 6; i > 0; i--)\r
2427         {\r
2428                 TK_NextToken();\r
2429                 EvalExpression();\r
2430                 if (i > 1)\r
2431                         TK_TokenMustBe(TK_COMMA, ERR_MISSING_PARAM);\r
2432         }\r
2433         if (tk_Token == TK_COMMA)\r
2434         { // HUD message has optional parameters\r
2435                 PC_AppendCmd(PCD_OPTHUDMESSAGE);\r
2436                 do\r
2437                 {\r
2438                         TK_NextToken();\r
2439                         EvalExpression();\r
2440                 } while (tk_Token == TK_COMMA);\r
2441         }\r
2442         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2443         PC_AppendCmd(stmtToken == TK_HUDMESSAGE ? \r
2444                 PCD_ENDHUDMESSAGE : PCD_ENDHUDMESSAGEBOLD);\r
2445         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2446         TK_NextToken();\r
2447 }\r
2448 \r
2449 //==========================================================================\r
2450 //\r
2451 // LeadingCreateTranslation\r
2452 //\r
2453 // Simple grammar:\r
2454 //\r
2455 // tranlationstmt: CreateTranslation ( exp opt_args ) ;\r
2456 // opt_args: /* empty: just reset the translation */ | , arglist\r
2457 // arglist: arg | arglist arg\r
2458 // arg: range = replacement\r
2459 // range: exp : exp\r
2460 // replacement: palrep | colorrep\r
2461 // palrep: exp : exp\r
2462 // colorrep: [exp,exp,exp]:[exp,exp,exp]\r
2463 //==========================================================================\r
2464 \r
2465 static void LeadingCreateTranslation(void)\r
2466 {\r
2467         MS_Message(MSG_DEBUG, "---- LeadingCreateTranslation ----\n");\r
2468         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2469         TK_NextToken();\r
2470         EvalExpression();\r
2471         PC_AppendCmd(PCD_STARTTRANSLATION);\r
2472         while (tk_Token == TK_COMMA)\r
2473         {\r
2474                 TK_NextToken();\r
2475                 EvalExpression();       // Get first palette entry in range\r
2476                 TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2477                 TK_NextToken();\r
2478                 EvalExpression();       // Get second palette entry in range\r
2479                 TK_TokenMustBe(TK_ASSIGN, ERR_MISSING_ASSIGN);\r
2480 \r
2481                 TK_NextToken();\r
2482                 if(tk_Token == TK_LBRACKET)\r
2483                 { // Replacement is color range\r
2484                         int i, j;\r
2485 \r
2486                         TK_NextToken();\r
2487 \r
2488                         for(j = 2; j != 0; --j)\r
2489                         {\r
2490                                 for(i = 3; i != 0; --i)\r
2491                                 {\r
2492                                         EvalExpression();\r
2493                                         if(i != 1)\r
2494                                         {\r
2495                                                 TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA);\r
2496                                         }\r
2497                                         else\r
2498                                         {\r
2499                                                 TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET);\r
2500                                         }\r
2501                                         TK_NextToken();\r
2502                                 }\r
2503                                 if(j == 2)\r
2504                                 {\r
2505                                         TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2506                                         TK_NextTokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET);\r
2507                                         TK_NextToken();\r
2508                                 }\r
2509                         }\r
2510                         PC_AppendCmd(PCD_TRANSLATIONRANGE2);\r
2511                 }\r
2512                 else\r
2513                 { // Replacement is palette range\r
2514                         EvalExpression();\r
2515                         TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2516                         TK_NextToken();\r
2517                         EvalExpression();\r
2518                         PC_AppendCmd(PCD_TRANSLATIONRANGE1);\r
2519                 }\r
2520         }\r
2521         PC_AppendCmd(PCD_ENDTRANSLATION);\r
2522         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2523         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2524         TK_NextToken();\r
2525 }\r
2526 \r
2527 //==========================================================================\r
2528 //\r
2529 // LeadingIf\r
2530 //\r
2531 //==========================================================================\r
2532 \r
2533 static void LeadingIf(void)\r
2534 {\r
2535         int jumpAddrPtr1;\r
2536         int jumpAddrPtr2;\r
2537 \r
2538         MS_Message(MSG_DEBUG, "---- LeadingIf ----\n");\r
2539         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2540         TK_NextToken();\r
2541         EvalExpression();\r
2542         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2543         PC_AppendCmd(PCD_IFNOTGOTO);\r
2544         jumpAddrPtr1 = pc_Address;\r
2545         PC_SkipInt();\r
2546         TK_NextToken();\r
2547         if(ProcessStatement(STMT_IF) == NO)\r
2548         {\r
2549                 ERR_Error(ERR_INVALID_STATEMENT, YES);\r
2550         }\r
2551         if(tk_Token == TK_ELSE)\r
2552         {\r
2553                 PC_AppendCmd(PCD_GOTO);\r
2554                 jumpAddrPtr2 = pc_Address;\r
2555                 PC_SkipInt();\r
2556                 PC_WriteInt(pc_Address, jumpAddrPtr1);\r
2557                 TK_NextToken();\r
2558                 if(ProcessStatement(STMT_ELSE) == NO)\r
2559                 {\r
2560                         ERR_Error(ERR_INVALID_STATEMENT, YES);\r
2561                 }\r
2562                 PC_WriteInt(pc_Address, jumpAddrPtr2);\r
2563         }\r
2564         else\r
2565         {\r
2566                 PC_WriteInt(pc_Address, jumpAddrPtr1);\r
2567         }\r
2568 }\r
2569 \r
2570 //==========================================================================\r
2571 //\r
2572 // LeadingFor\r
2573 //\r
2574 //==========================================================================\r
2575 \r
2576 static void LeadingFor(void)\r
2577 {\r
2578         int exprAddr;\r
2579         int incAddr;\r
2580         int ifgotoAddr;\r
2581         int     gotoAddr;\r
2582 \r
2583         MS_Message(MSG_DEBUG, "---- LeadingFor ----\n");\r
2584         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2585         TK_NextToken();\r
2586         if(ProcessStatement(STMT_IF) == NO)\r
2587         {\r
2588                 ERR_Error(ERR_INVALID_STATEMENT, YES);\r
2589         }\r
2590         exprAddr = pc_Address;\r
2591         EvalExpression();\r
2592         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2593         TK_NextToken();\r
2594         PC_AppendCmd(PCD_IFGOTO);\r
2595         ifgotoAddr = pc_Address;\r
2596         PC_SkipInt();\r
2597         PC_AppendCmd(PCD_GOTO);\r
2598         gotoAddr = pc_Address;\r
2599         PC_SkipInt();\r
2600         incAddr = pc_Address;\r
2601         forSemicolonHack = TRUE;\r
2602         if(ProcessStatement(STMT_IF) == NO)\r
2603         {\r
2604                 ERR_Error(ERR_INVALID_STATEMENT, YES);\r
2605         }\r
2606         forSemicolonHack = FALSE;\r
2607         PC_AppendCmd(PCD_GOTO);\r
2608         PC_AppendInt(exprAddr);\r
2609         PC_WriteInt(pc_Address,ifgotoAddr);\r
2610         if(ProcessStatement(STMT_FOR) == NO)\r
2611         {\r
2612                 ERR_Error(ERR_INVALID_STATEMENT, YES);\r
2613         }\r
2614         PC_AppendCmd(PCD_GOTO);\r
2615         PC_AppendInt(incAddr);\r
2616         WriteContinues(incAddr);\r
2617         WriteBreaks();\r
2618         PC_WriteInt(pc_Address,gotoAddr);\r
2619 }\r
2620 \r
2621 //==========================================================================\r
2622 //\r
2623 // LeadingWhileUntil\r
2624 //\r
2625 //==========================================================================\r
2626 \r
2627 static void LeadingWhileUntil(void)\r
2628 {\r
2629         tokenType_t stmtToken;\r
2630         int topAddr;\r
2631         int outAddrPtr;\r
2632 \r
2633         MS_Message(MSG_DEBUG, "---- LeadingWhileUntil ----\n");\r
2634         stmtToken = tk_Token;\r
2635         topAddr = pc_Address;\r
2636         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2637         TK_NextToken();\r
2638         EvalExpression();\r
2639         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2640         PC_AppendCmd(stmtToken == TK_WHILE ? PCD_IFNOTGOTO : PCD_IFGOTO);\r
2641         outAddrPtr = pc_Address;\r
2642         PC_SkipInt();\r
2643         TK_NextToken();\r
2644         if(ProcessStatement(STMT_WHILEUNTIL) == NO)\r
2645         {\r
2646                 ERR_Error(ERR_INVALID_STATEMENT, YES);\r
2647         }\r
2648         PC_AppendCmd(PCD_GOTO);\r
2649         PC_AppendInt(topAddr);\r
2650 \r
2651         PC_WriteInt(pc_Address, outAddrPtr);\r
2652 \r
2653         WriteContinues(topAddr);\r
2654         WriteBreaks();\r
2655 }\r
2656 \r
2657 //==========================================================================\r
2658 //\r
2659 // LeadingDo\r
2660 //\r
2661 //==========================================================================\r
2662 \r
2663 static void LeadingDo(void)\r
2664 {\r
2665         int topAddr;\r
2666         int exprAddr;\r
2667         tokenType_t stmtToken;\r
2668 \r
2669         MS_Message(MSG_DEBUG, "---- LeadingDo ----\n");\r
2670         topAddr = pc_Address;\r
2671         TK_NextToken();\r
2672         if(ProcessStatement(STMT_DO) == NO)\r
2673         {\r
2674                 ERR_Error(ERR_INVALID_STATEMENT, YES, NULL);\r
2675         }\r
2676         if(tk_Token != TK_WHILE && tk_Token != TK_UNTIL)\r
2677         {\r
2678                 ERR_Error(ERR_BAD_DO_STATEMENT, YES, NULL);\r
2679                 TK_SkipPast(TK_SEMICOLON);\r
2680                 return;\r
2681         }\r
2682         stmtToken = tk_Token;\r
2683         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2684         exprAddr = pc_Address;\r
2685         TK_NextToken();\r
2686         EvalExpression();\r
2687         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2688         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2689         PC_AppendCmd(stmtToken == TK_WHILE ? PCD_IFGOTO : PCD_IFNOTGOTO);\r
2690         PC_AppendInt(topAddr);\r
2691         WriteContinues(exprAddr);\r
2692         WriteBreaks();\r
2693         TK_NextToken();\r
2694 }\r
2695 \r
2696 //==========================================================================\r
2697 //\r
2698 // LeadingSwitch\r
2699 //\r
2700 //==========================================================================\r
2701 \r
2702 static void LeadingSwitch(void)\r
2703 {\r
2704         int switcherAddrPtr;\r
2705         int outAddrPtr;\r
2706         caseInfo_t *cInfo;\r
2707         int defaultAddress;\r
2708 \r
2709         MS_Message(MSG_DEBUG, "---- LeadingSwitch ----\n");\r
2710 \r
2711         TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);\r
2712         TK_NextToken();\r
2713         EvalExpression();\r
2714         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
2715 \r
2716         PC_AppendCmd(PCD_GOTO);\r
2717         switcherAddrPtr = pc_Address;\r
2718         PC_SkipInt();\r
2719 \r
2720         TK_NextToken();\r
2721         if(ProcessStatement(STMT_SWITCH) == NO)\r
2722         {\r
2723                 ERR_Error(ERR_INVALID_STATEMENT, YES, NULL);\r
2724         }\r
2725 \r
2726         PC_AppendCmd(PCD_GOTO);\r
2727         outAddrPtr = pc_Address;\r
2728         PC_SkipInt();\r
2729 \r
2730         PC_WriteInt(pc_Address, switcherAddrPtr);\r
2731         defaultAddress = 0;\r
2732 \r
2733         if(pc_HexenCase)\r
2734         {\r
2735                 while((cInfo = GetCaseInfo()) != NULL)\r
2736                 {\r
2737                         if(cInfo->isDefault == YES)\r
2738                         {\r
2739                                 defaultAddress = cInfo->address;\r
2740                                 continue;\r
2741                         }\r
2742                         PC_AppendCmd(PCD_CASEGOTO);\r
2743                         PC_AppendInt(cInfo->value);\r
2744                         PC_AppendInt(cInfo->address);\r
2745                 }\r
2746         }\r
2747         else if(CaseIndex != 0)\r
2748         {\r
2749                 caseInfo_t *maxCase = &CaseInfo[CaseIndex];\r
2750                 caseInfo_t *minCase = maxCase;\r
2751 \r
2752                 // [RH] Sort cases so that the VM can handle them with\r
2753                 // a quick binary search.\r
2754                 while((cInfo = GetCaseInfo()) != NULL)\r
2755                 {\r
2756                         minCase = cInfo;\r
2757                 }\r
2758                 qsort(minCase, maxCase - minCase, sizeof(caseInfo_t), CaseInfoCmp);\r
2759                 if(minCase->isDefault == YES)\r
2760                 {\r
2761                         defaultAddress = minCase->address;\r
2762                         minCase++;\r
2763                 }\r
2764                 if (minCase < maxCase)\r
2765                 {\r
2766                         PC_AppendCmd(PCD_CASEGOTOSORTED);\r
2767                         if(pc_Address%4 != 0)\r
2768                         { // Align to a 4-byte boundary\r
2769                                 U_INT pad = 0;\r
2770                                 PC_Append((void *)&pad, 4-(pc_Address%4));\r
2771                         }\r
2772                         PC_AppendInt(maxCase - minCase);\r
2773                         for(; minCase < maxCase; ++minCase)\r
2774                         {\r
2775                                 PC_AppendInt(minCase->value);\r
2776                                 PC_AppendInt(minCase->address);\r
2777                         }\r
2778                 }\r
2779         }\r
2780         PC_AppendCmd(PCD_DROP);\r
2781 \r
2782         if(defaultAddress != 0)\r
2783         {\r
2784                 PC_AppendCmd(PCD_GOTO);\r
2785                 PC_AppendInt(defaultAddress);\r
2786         }\r
2787 \r
2788         PC_WriteInt(pc_Address, outAddrPtr);\r
2789 \r
2790         WriteBreaks();\r
2791 }\r
2792 \r
2793 //==========================================================================\r
2794 //\r
2795 // LeadingCase\r
2796 //\r
2797 //==========================================================================\r
2798 \r
2799 static void LeadingCase(void)\r
2800 {\r
2801         MS_Message(MSG_DEBUG, "---- LeadingCase ----\n");\r
2802         TK_NextToken();\r
2803         PushCase(EvalConstExpression(), NO);\r
2804         TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2805         TK_NextToken();\r
2806 }\r
2807 \r
2808 //==========================================================================\r
2809 //\r
2810 // LeadingDefault\r
2811 //\r
2812 //==========================================================================\r
2813 \r
2814 static void LeadingDefault(void)\r
2815 {\r
2816         MS_Message(MSG_DEBUG, "---- LeadingDefault ----\n");\r
2817         TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);\r
2818         PushCase(0, YES);\r
2819         TK_NextToken();\r
2820 }\r
2821 \r
2822 //==========================================================================\r
2823 //\r
2824 // PushCase\r
2825 //\r
2826 //==========================================================================\r
2827 \r
2828 static void PushCase(int value, boolean isDefault)\r
2829 {\r
2830         if(CaseIndex == MAX_CASE)\r
2831         {\r
2832                 ERR_Exit(ERR_CASE_OVERFLOW, YES);\r
2833         }\r
2834         CaseInfo[CaseIndex].level = StatementLevel;\r
2835         CaseInfo[CaseIndex].value = value;\r
2836         CaseInfo[CaseIndex].isDefault = isDefault;\r
2837         CaseInfo[CaseIndex].address = pc_Address;\r
2838         CaseIndex++;\r
2839 }\r
2840 \r
2841 //==========================================================================\r
2842 //\r
2843 // GetCaseInfo\r
2844 //\r
2845 //==========================================================================\r
2846 \r
2847 static caseInfo_t *GetCaseInfo(void)\r
2848 {\r
2849         if(CaseIndex == 0)\r
2850         {\r
2851                 return NULL;\r
2852         }\r
2853         if(CaseInfo[CaseIndex-1].level > StatementLevel)\r
2854         {\r
2855                 return &CaseInfo[--CaseIndex];\r
2856         }\r
2857         return NULL;\r
2858 }\r
2859 \r
2860 //==========================================================================\r
2861 //\r
2862 // CaseInfoCmp\r
2863 //\r
2864 //==========================================================================\r
2865 \r
2866 static int CaseInfoCmp (const void *a, const void *b)\r
2867 {\r
2868         const caseInfo_t *ca = (const caseInfo_t *)a;\r
2869         const caseInfo_t *cb = (const caseInfo_t *)b;\r
2870 \r
2871         // The default case always gets moved to the front.\r
2872         if(ca->isDefault)\r
2873         {\r
2874                 return -1;\r
2875         }\r
2876         if(cb->isDefault)\r
2877         {\r
2878                 return 1;\r
2879         }\r
2880         return ca->value - cb->value;\r
2881 }\r
2882 \r
2883 //==========================================================================\r
2884 //\r
2885 // DefaultInCurrent\r
2886 //\r
2887 //==========================================================================\r
2888 \r
2889 static boolean DefaultInCurrent(void)\r
2890 {\r
2891         int i;\r
2892 \r
2893         for(i = 0; i < CaseIndex; i++)\r
2894         {\r
2895                 if(CaseInfo[i].isDefault == YES\r
2896                         && CaseInfo[i].level == StatementLevel)\r
2897                 {\r
2898                         return YES;\r
2899                 }\r
2900         }\r
2901         return NO;\r
2902 }\r
2903 \r
2904 //==========================================================================\r
2905 //\r
2906 // LeadingBreak\r
2907 //\r
2908 //==========================================================================\r
2909 \r
2910 static void LeadingBreak(void)\r
2911 {\r
2912         MS_Message(MSG_DEBUG, "---- LeadingBreak ----\n");\r
2913         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2914         PC_AppendCmd(PCD_GOTO);\r
2915         PushBreak();\r
2916         PC_SkipInt();\r
2917         TK_NextToken();\r
2918 }\r
2919 \r
2920 //==========================================================================\r
2921 //\r
2922 // PushBreak\r
2923 //\r
2924 //==========================================================================\r
2925 \r
2926 static void PushBreak(void)\r
2927 {\r
2928         if(BreakIndex == MAX_CASE)\r
2929         {\r
2930                 ERR_Exit(ERR_BREAK_OVERFLOW, YES);\r
2931         }\r
2932         BreakInfo[BreakIndex].level = StatementLevel;\r
2933         BreakInfo[BreakIndex].addressPtr = pc_Address;\r
2934         BreakIndex++;\r
2935 }\r
2936 \r
2937 //==========================================================================\r
2938 //\r
2939 // WriteBreaks\r
2940 //\r
2941 //==========================================================================\r
2942 \r
2943 static void WriteBreaks(void)\r
2944 {\r
2945         while(BreakIndex && BreakInfo[BreakIndex-1].level > StatementLevel)\r
2946         {\r
2947                 PC_WriteInt(pc_Address, BreakInfo[--BreakIndex].addressPtr);\r
2948         }\r
2949 }\r
2950 \r
2951 //==========================================================================\r
2952 //\r
2953 // BreakAncestor\r
2954 //\r
2955 // Returns YES if the current statement history contains a break root\r
2956 // statement.\r
2957 //\r
2958 //==========================================================================\r
2959 \r
2960 static boolean BreakAncestor(void)\r
2961 {\r
2962         int i;\r
2963 \r
2964         for(i = 0; i < StatementIndex; i++)\r
2965         {\r
2966                 if(IsBreakRoot[StatementHistory[i]])\r
2967                 {\r
2968                         return YES;\r
2969                 }\r
2970         }\r
2971         return NO;\r
2972 }\r
2973 \r
2974 //==========================================================================\r
2975 //\r
2976 // LeadingContinue\r
2977 //\r
2978 //==========================================================================\r
2979 \r
2980 static void LeadingContinue(void)\r
2981 {\r
2982         MS_Message(MSG_DEBUG, "---- LeadingContinue ----\n");\r
2983         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
2984         PC_AppendCmd(PCD_GOTO);\r
2985         PushContinue();\r
2986         PC_SkipInt();\r
2987         TK_NextToken();\r
2988 }\r
2989 \r
2990 //==========================================================================\r
2991 //\r
2992 // PushContinue\r
2993 //\r
2994 //==========================================================================\r
2995 \r
2996 static void PushContinue(void)\r
2997 {\r
2998         if(ContinueIndex == MAX_CONTINUE)\r
2999         {\r
3000                 ERR_Exit(ERR_CONTINUE_OVERFLOW, YES);\r
3001         }\r
3002         ContinueInfo[ContinueIndex].level = StatementLevel;\r
3003         ContinueInfo[ContinueIndex].addressPtr = pc_Address;\r
3004         ContinueIndex++;\r
3005 }\r
3006 \r
3007 //==========================================================================\r
3008 //\r
3009 // WriteContinues\r
3010 //\r
3011 //==========================================================================\r
3012 \r
3013 static void WriteContinues(int address)\r
3014 {\r
3015         if(ContinueIndex == 0)\r
3016         {\r
3017                 return;\r
3018         }\r
3019         while(ContinueInfo[ContinueIndex-1].level > StatementLevel)\r
3020         {\r
3021                 PC_WriteInt(address, ContinueInfo[--ContinueIndex].addressPtr);\r
3022         }\r
3023 }\r
3024 \r
3025 //==========================================================================\r
3026 //\r
3027 // ContinueAncestor\r
3028 //\r
3029 //==========================================================================\r
3030 \r
3031 static boolean ContinueAncestor(void)\r
3032 {\r
3033         int i;\r
3034 \r
3035         for(i = 0; i < StatementIndex; i++)\r
3036         {\r
3037                 if(IsContinueRoot[StatementHistory[i]])\r
3038                 {\r
3039                         return YES;\r
3040                 }\r
3041         }\r
3042         return NO;\r
3043 }\r
3044 \r
3045 //==========================================================================\r
3046 //\r
3047 // LeadingIncDec\r
3048 //\r
3049 //==========================================================================\r
3050 \r
3051 static void LeadingIncDec(int token)\r
3052 {\r
3053         symbolNode_t *sym;\r
3054 \r
3055         MS_Message(MSG_DEBUG, "---- LeadingIncDec ----\n");\r
3056         TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INCDEC_OP_ON_NON_VAR);\r
3057         sym = DemandSymbol(tk_String);\r
3058         if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR\r
3059                 && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR\r
3060                 && sym->type != SY_MAPARRAY && sym->type != SY_GLOBALARRAY\r
3061                 && sym->type != SY_WORLDARRAY && sym->type != SY_SCRIPTALIAS)\r
3062         {\r
3063                 ERR_Error(ERR_INCDEC_OP_ON_NON_VAR, YES);\r
3064                 TK_SkipPast(TK_SEMICOLON);\r
3065                 return;\r
3066         }\r
3067         TK_NextToken();\r
3068         if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY\r
3069                 || sym->type == SY_GLOBALARRAY)\r
3070         {\r
3071                 ParseArrayIndices(sym, sym->info.array.ndim);\r
3072         }\r
3073         else if(tk_Token == TK_LBRACKET)\r
3074         {\r
3075                 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);\r
3076                 while(tk_Token == TK_LBRACKET)\r
3077                 {\r
3078                         TK_SkipPast(TK_RBRACKET);\r
3079                 }\r
3080         }\r
3081         PC_AppendCmd(GetIncDecPCD(token, sym->type));\r
3082         PC_AppendShrink(sym->info.var.index);\r
3083         if(forSemicolonHack)\r
3084         {\r
3085                 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
3086         }\r
3087         else\r
3088         {\r
3089                 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3090         }\r
3091         TK_NextToken();\r
3092 }\r
3093 \r
3094 //==========================================================================\r
3095 //\r
3096 // LeadingVarAssign\r
3097 //\r
3098 //==========================================================================\r
3099 \r
3100 static void LeadingVarAssign(symbolNode_t *sym)\r
3101 {\r
3102         boolean done;\r
3103         tokenType_t assignToken;\r
3104 \r
3105         MS_Message(MSG_DEBUG, "---- LeadingVarAssign ----\n");\r
3106         done = NO;\r
3107         do\r
3108         {\r
3109                 TK_NextToken(); // Fetch assignment operator\r
3110                 if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY\r
3111                         || sym->type == SY_GLOBALARRAY)\r
3112                 {\r
3113                         ParseArrayIndices(sym, sym->info.array.ndim);\r
3114                 }\r
3115                 else if(tk_Token == TK_LBRACKET)\r
3116                 {\r
3117                         ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);\r
3118                         while(tk_Token == TK_LBRACKET)\r
3119                         {\r
3120                                 TK_SkipPast(TK_RBRACKET);\r
3121                         }\r
3122                 }\r
3123                 if(tk_Token == TK_INC || tk_Token == TK_DEC)\r
3124                 { // Postfix increment or decrement\r
3125                         PC_AppendCmd(GetIncDecPCD(tk_Token, sym->type));\r
3126                         if (pc_NoShrink)\r
3127                         {\r
3128                                 PC_AppendInt(sym->info.var.index);\r
3129                         }\r
3130                         else\r
3131                         {\r
3132                                 PC_AppendByte(sym->info.var.index);\r
3133                         }\r
3134                         TK_NextToken();\r
3135                 }\r
3136                 else\r
3137                 { // Normal operator\r
3138                         if(TK_Member(AssignOps) == NO)\r
3139                         {\r
3140                                 ERR_Error(ERR_MISSING_ASSIGN_OP, YES);\r
3141                                 TK_SkipPast(TK_SEMICOLON);\r
3142                                 return;\r
3143                         }\r
3144                         assignToken = tk_Token;\r
3145                         TK_NextToken();\r
3146                         EvalExpression();\r
3147                         PC_AppendCmd(GetAssignPCD(assignToken, sym->type));\r
3148                         PC_AppendShrink(sym->info.var.index);\r
3149                 }\r
3150                 if(tk_Token == TK_COMMA)\r
3151                 {\r
3152                         TK_NextTokenMustBe(TK_IDENTIFIER, ERR_BAD_ASSIGNMENT);\r
3153                         sym = DemandSymbol(tk_String);\r
3154                         if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR\r
3155                                 && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR\r
3156                                 && sym->type != SY_WORLDARRAY && sym->type != SY_GLOBALARRAY\r
3157                                 && sym->type != SY_SCRIPTALIAS)\r
3158                         {\r
3159                                 ERR_Error(ERR_BAD_ASSIGNMENT, YES);\r
3160                                 TK_SkipPast(TK_SEMICOLON);\r
3161                                 return;\r
3162                         }\r
3163                 }\r
3164                 else\r
3165                 {\r
3166                         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3167                         TK_NextToken();\r
3168                         done = YES;\r
3169                 }\r
3170         } while(done == NO);\r
3171 }\r
3172 \r
3173 //==========================================================================\r
3174 //\r
3175 // GetAssignPCD\r
3176 //\r
3177 //==========================================================================\r
3178 \r
3179 static pcd_t GetAssignPCD(tokenType_t token, symbolType_t symbol)\r
3180 {\r
3181         size_t i, j;\r
3182         static tokenType_t tokenLookup[] =\r
3183         {\r
3184                 TK_ASSIGN, TK_ADDASSIGN, TK_SUBASSIGN,\r
3185                 TK_MULASSIGN, TK_DIVASSIGN, TK_MODASSIGN,\r
3186                 TK_ANDASSIGN, TK_EORASSIGN, TK_ORASSIGN,\r
3187                 TK_LSASSIGN, TK_RSASSIGN\r
3188         };\r
3189         static symbolType_t symbolLookup[] =\r
3190         {\r
3191                 SY_SCRIPTVAR, SY_MAPVAR, SY_WORLDVAR, SY_GLOBALVAR, SY_MAPARRAY,\r
3192                 SY_WORLDARRAY, SY_GLOBALARRAY\r
3193         };\r
3194         static pcd_t assignmentLookup[11][7] =\r
3195         {\r
3196                 { PCD_ASSIGNSCRIPTVAR, PCD_ASSIGNMAPVAR, PCD_ASSIGNWORLDVAR, PCD_ASSIGNGLOBALVAR, PCD_ASSIGNMAPARRAY, PCD_ASSIGNWORLDARRAY, PCD_ASSIGNGLOBALARRAY },\r
3197                 { PCD_ADDSCRIPTVAR, PCD_ADDMAPVAR, PCD_ADDWORLDVAR, PCD_ADDGLOBALVAR, PCD_ADDMAPARRAY, PCD_ADDWORLDARRAY, PCD_ADDGLOBALARRAY },\r
3198                 { PCD_SUBSCRIPTVAR, PCD_SUBMAPVAR, PCD_SUBWORLDVAR, PCD_SUBGLOBALVAR, PCD_SUBMAPARRAY, PCD_SUBWORLDARRAY, PCD_SUBGLOBALARRAY },\r
3199                 { PCD_MULSCRIPTVAR, PCD_MULMAPVAR, PCD_MULWORLDVAR, PCD_MULGLOBALVAR, PCD_MULMAPARRAY, PCD_MULWORLDARRAY, PCD_MULGLOBALARRAY },\r
3200                 { PCD_DIVSCRIPTVAR, PCD_DIVMAPVAR, PCD_DIVWORLDVAR, PCD_DIVGLOBALVAR, PCD_DIVMAPARRAY, PCD_DIVWORLDARRAY, PCD_DIVGLOBALARRAY },\r
3201                 { PCD_MODSCRIPTVAR, PCD_MODMAPVAR, PCD_MODWORLDVAR, PCD_MODGLOBALVAR, PCD_MODMAPARRAY, PCD_MODWORLDARRAY, PCD_MODGLOBALARRAY },\r
3202                 { PCD_ANDSCRIPTVAR, PCD_ANDMAPVAR, PCD_ANDWORLDVAR, PCD_ANDGLOBALVAR, PCD_ANDMAPARRAY, PCD_ANDWORLDARRAY, PCD_ANDGLOBALARRAY },\r
3203                 { PCD_EORSCRIPTVAR, PCD_EORMAPVAR, PCD_EORWORLDVAR, PCD_EORGLOBALVAR, PCD_EORMAPARRAY, PCD_EORWORLDARRAY, PCD_EORGLOBALARRAY },\r
3204                 { PCD_ORSCRIPTVAR, PCD_ORMAPVAR, PCD_ORWORLDVAR, PCD_ORGLOBALVAR, PCD_ORMAPARRAY, PCD_ORWORLDARRAY, PCD_ORGLOBALARRAY },\r
3205                 { PCD_LSSCRIPTVAR, PCD_LSMAPVAR, PCD_LSWORLDVAR, PCD_LSGLOBALVAR, PCD_LSMAPARRAY, PCD_LSWORLDARRAY, PCD_LSGLOBALARRAY },\r
3206                 { PCD_RSSCRIPTVAR, PCD_RSMAPVAR, PCD_RSWORLDVAR, PCD_RSGLOBALVAR, PCD_RSMAPARRAY, PCD_RSWORLDARRAY, PCD_RSGLOBALARRAY }\r
3207         };\r
3208 \r
3209         for(i = 0; i < ARRAY_SIZE(tokenLookup); ++i)\r
3210         {\r
3211                 if(tokenLookup[i] == token)\r
3212                 {\r
3213                         for(j = 0; j < ARRAY_SIZE(symbolLookup); ++j)\r
3214                         {\r
3215                                 if (symbolLookup[j] == symbol)\r
3216                                 {\r
3217                                         return assignmentLookup[i][j];\r
3218                                 }\r
3219                         }\r
3220                         break;\r
3221                 }\r
3222         }\r
3223         return PCD_NOP;\r
3224 }\r
3225 \r
3226 //==========================================================================\r
3227 //\r
3228 // LeadingSuspend\r
3229 //\r
3230 //==========================================================================\r
3231 \r
3232 static void LeadingSuspend(void)\r
3233 {\r
3234         MS_Message(MSG_DEBUG, "---- LeadingSuspend ----\n");\r
3235         if(InsideFunction)\r
3236         {\r
3237                 ERR_Error(ERR_SUSPEND_IN_FUNCTION, YES);\r
3238         }\r
3239         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3240         PC_AppendCmd(PCD_SUSPEND);\r
3241         TK_NextToken();\r
3242 }\r
3243 \r
3244 //==========================================================================\r
3245 //\r
3246 // LeadingTerminate\r
3247 //\r
3248 //==========================================================================\r
3249 \r
3250 static void LeadingTerminate(void)\r
3251 {\r
3252         MS_Message(MSG_DEBUG, "---- LeadingTerminate ----\n");\r
3253         if(InsideFunction)\r
3254         {\r
3255                 ERR_Error(ERR_TERMINATE_IN_FUNCTION, YES);\r
3256         }\r
3257         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3258         PC_AppendCmd(PCD_TERMINATE);\r
3259         TK_NextToken();\r
3260 }\r
3261 \r
3262 //==========================================================================\r
3263 //\r
3264 // LeadingRestart\r
3265 //\r
3266 //==========================================================================\r
3267 \r
3268 static void LeadingRestart(void)\r
3269 {\r
3270         MS_Message(MSG_DEBUG, "---- LeadingRestart ----\n");\r
3271         if(InsideFunction)\r
3272         {\r
3273                 ERR_Error(ERR_RESTART_IN_FUNCTION, YES);\r
3274         }\r
3275         TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3276         PC_AppendCmd(PCD_RESTART);\r
3277         TK_NextToken();\r
3278 }\r
3279 \r
3280 //==========================================================================\r
3281 //\r
3282 // LeadingReturn\r
3283 //\r
3284 //==========================================================================\r
3285 \r
3286 static void LeadingReturn(void)\r
3287 {\r
3288         MS_Message(MSG_DEBUG, "---- LeadingReturn ----\n");\r
3289         if(!InsideFunction)\r
3290         {\r
3291                 ERR_Error(ERR_RETURN_OUTSIDE_FUNCTION, YES);\r
3292                 while (TK_NextToken () != TK_SEMICOLON)\r
3293                 {\r
3294                         if (tk_Token == TK_EOF)\r
3295                                 break;\r
3296                 }\r
3297         }\r
3298         else\r
3299         {\r
3300                 TK_NextToken();\r
3301                 if(tk_Token == TK_SEMICOLON)\r
3302                 {\r
3303                         if(InsideFunction->info.scriptFunc.hasReturnValue)\r
3304                         {\r
3305                                 ERR_Error(ERR_MUST_RETURN_A_VALUE, YES);\r
3306                         }\r
3307                         PC_AppendCmd(PCD_RETURNVOID);\r
3308                 }\r
3309                 else\r
3310                 {\r
3311                         if(!InsideFunction->info.scriptFunc.hasReturnValue)\r
3312                         {\r
3313                                 ERR_Error(ERR_MUST_NOT_RETURN_A_VALUE, YES);\r
3314                         }\r
3315                         EvalExpression();\r
3316                         TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);\r
3317                         PC_AppendCmd(PCD_RETURNVAL);\r
3318                 }\r
3319                 TK_NextToken();\r
3320         }\r
3321 }\r
3322 \r
3323 //==========================================================================\r
3324 //\r
3325 // EvalConstExpression\r
3326 //\r
3327 //==========================================================================\r
3328 \r
3329 static int EvalConstExpression(void)\r
3330 {\r
3331         pa_ConstExprIsString = NO;      // Used by PC_PutMapVariable\r
3332         ExprStackIndex = 0;\r
3333         ConstantExpression = YES;\r
3334         ExprLevA();\r
3335         if(ExprStackIndex != 1)\r
3336         {\r
3337                 ERR_Error(ERR_BAD_CONST_EXPR, YES, NULL);\r
3338                 ExprStack[0] = 0;\r
3339                 ExprStackIndex = 1;\r
3340         }\r
3341         return PopExStk();\r
3342 }\r
3343 \r
3344 //==========================================================================\r
3345 //\r
3346 // EvalExpression\r
3347 //\r
3348 // [RH] Rewrote all the ExprLevA - ExprLevJ functions in favor of a single\r
3349 // table-driven parser function.\r
3350 //\r
3351 //==========================================================================\r
3352 \r
3353 static void EvalExpression(void)\r
3354 {\r
3355         ConstantExpression = NO;\r
3356         ExprLevA();\r
3357 }\r
3358 \r
3359 static void ExprLevA(void)\r
3360 {\r
3361         ExprLevX(0);\r
3362 }\r
3363 \r
3364 // Operator precedence levels:\r
3365 // Operator: ||\r
3366 // Operator: &&\r
3367 // Operator: |\r
3368 // Operator: ^\r
3369 // Operator: &\r
3370 // Operators: == !=\r
3371 // Operators: < <= > >=\r
3372 // Operators: << >>\r
3373 // Operators: + -\r
3374 // Operators: * / %\r
3375 \r
3376 static void ExprLevX(int level)\r
3377 {\r
3378         if(OpsList[level] == NULL)\r
3379         {\r
3380                 boolean unaryMinus;\r
3381 \r
3382                 unaryMinus = FALSE;\r
3383                 if(tk_Token == TK_MINUS)\r
3384                 {\r
3385                         unaryMinus = TRUE;\r
3386                         TK_NextToken();\r
3387                 }\r
3388                 if(ConstantExpression == YES)\r
3389                 {\r
3390                         ConstExprFactor();\r
3391                 }\r
3392                 else\r
3393                 {\r
3394                         ExprFactor();\r
3395                 }\r
3396                 if(unaryMinus == TRUE)\r
3397                 {\r
3398                         SendExprCommand(PCD_UNARYMINUS);\r
3399                 }\r
3400         }\r
3401         else\r
3402         {\r
3403                 ExprLevX(level + 1);\r
3404                 while(TK_Member(OpsList[level]))\r
3405                 {\r
3406                         tokenType_t token = tk_Token;\r
3407                         TK_NextToken();\r
3408                         ExprLevX(level + 1);\r
3409                         SendExprCommand(TokenToPCD(token));\r
3410                 }\r
3411         }\r
3412 }\r
3413 \r
3414 static void ExprLineSpecial(void)\r
3415 {\r
3416         int argCountMin = tk_SpecialArgCount & 0xffff;\r
3417         int argCountMax = tk_SpecialArgCount >> 16;\r
3418         int specialValue = tk_SpecialValue;\r
3419 \r
3420         // There are two ways to use a special in an expression:\r
3421         // 1. The special name by itself returns the special's number.\r
3422         // 2. The special followed by parameters actually executes the special.\r
3423         TK_NextToken();\r
3424         if(tk_Token != TK_LPAREN)\r
3425         {\r
3426                 PC_AppendPushVal(specialValue);\r
3427         }\r
3428         else\r
3429         {\r
3430                 int argCount = 0;\r
3431 \r
3432                 TK_NextToken();\r
3433                 if(tk_Token != TK_RPAREN)\r
3434                 {\r
3435                         TK_Undo();\r
3436                         do\r
3437                         {\r
3438                                 TK_NextToken();\r
3439                                 EvalExpression();\r
3440                                 argCount++;\r
3441                         } while(tk_Token == TK_COMMA);\r
3442                 }\r
3443                 if(argCount < argCountMin || argCount > argCountMax)\r
3444                 {\r
3445                         ERR_Error(specialValue >=0? ERR_BAD_LSPEC_ARG_COUNT : ERR_BAD_ARG_COUNT, YES);\r
3446                         return;\r
3447                 }\r
3448                 if (specialValue >= 0)\r
3449                 {\r
3450                         for(; argCount < 5; ++argCount)\r
3451                         {\r
3452                                 PC_AppendPushVal(0);\r
3453                         }\r
3454                         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
3455                         TK_NextToken();\r
3456                         PC_AppendCmd(PCD_LSPEC5RESULT);\r
3457                         if(pc_NoShrink)\r
3458                         {\r
3459                                 PC_AppendInt(specialValue);\r
3460                         }\r
3461                         else\r
3462                         {\r
3463                                 PC_AppendByte((U_BYTE)specialValue);\r
3464                         }\r
3465                 }\r
3466                 else\r
3467                 {\r
3468                         TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);\r
3469                         TK_NextToken();\r
3470                         PC_AppendCmd(PCD_CALLFUNC);\r
3471                         if(pc_NoShrink)\r
3472                         {\r
3473                                 PC_AppendInt(argCount);\r
3474                                 PC_AppendInt(-specialValue);\r
3475                         }\r
3476                         else\r
3477                         {\r
3478                                 PC_AppendByte((U_BYTE)argCount);\r
3479                                 PC_AppendWord((U_WORD)-specialValue);\r
3480                         }\r
3481                 }\r
3482         }\r
3483 }\r
3484 \r
3485 static void ExprFactor(void)\r
3486 {\r
3487         symbolNode_t *sym;\r
3488         tokenType_t opToken;\r
3489 \r
3490         switch(tk_Token)\r
3491         {\r
3492         case TK_STRING:\r
3493                 if (ImportMode != IMPORT_Importing)\r
3494                 {\r
3495                         tk_Number = STR_Find(tk_String);\r
3496                         PC_AppendPushVal(tk_Number);\r
3497                         if (ImportMode == IMPORT_Exporting)\r
3498                         {\r
3499                                 // The VM identifies strings by storing a library ID in the\r
3500                                 // high word of the string index. The library ID is not\r
3501                                 // known until the script actually gets loaded into the game,\r
3502                                 // so we need to use this p-code to tack the ID of the\r
3503                                 // currently running library to the index of the string that\r
3504                                 // just got pushed onto the stack.\r
3505                                 //\r
3506                                 // Simply assuming that a string is from the current library\r
3507                                 // is not good enough, because they can be passed around\r
3508                                 // between libraries and the map's behavior. Thus, we need\r
3509                                 // to know which object file a particular string belongs to.\r
3510                                 //\r
3511                                 // A specific example:\r
3512                                 // A map's behavior calls a function in a library and passes\r
3513                                 // a string:\r
3514                                 //\r
3515                                 //    LibFunc ("The library will do something with this string.");\r
3516                                 //\r
3517                                 // The library function needs to know that the string originated\r
3518                                 // outside the library. Similarly, if a library function returns\r
3519                                 // a string, the caller needs to know that the string did not\r
3520                                 // originate from the same object file.\r
3521                                 //\r
3522                                 // And that's why strings have library IDs tacked onto them.\r
3523                                 // The map's main behavior (i.e. an object that is not a library)\r
3524                                 // always uses library ID 0 to identify its strings, so its\r
3525                                 // strings don't need to be tagged.\r
3526                                 PC_AppendCmd(PCD_TAGSTRING);\r
3527                         }\r
3528                 }\r
3529                 TK_NextToken();\r
3530                 break;\r
3531         case TK_NUMBER:\r
3532                 PC_AppendPushVal(tk_Number);\r
3533                 TK_NextToken();\r
3534                 break;\r
3535         case TK_LPAREN:\r
3536                 TK_NextToken();\r
3537                 ExprLevA();\r
3538                 if(tk_Token != TK_RPAREN)\r
3539                 {\r
3540                         ERR_Error(ERR_BAD_EXPR, YES, NULL);\r
3541                         TK_SkipPast(TK_RPAREN);\r
3542                 }\r
3543                 else\r
3544                 {\r
3545                         TK_NextToken();\r
3546                 }\r
3547                 break;\r
3548         case TK_NOT:\r
3549                 TK_NextToken();\r
3550                 ExprFactor();\r
3551                 PC_AppendCmd(PCD_NEGATELOGICAL);\r
3552                 break;\r
3553         case TK_TILDE:\r
3554                 TK_NextToken();\r
3555                 ExprFactor();\r
3556                 PC_AppendCmd(PCD_NEGATEBINARY);\r
3557                 break;\r
3558         case TK_INC:\r
3559         case TK_DEC:\r
3560                 opToken = tk_Token;\r
3561                 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INCDEC_OP_ON_NON_VAR);\r
3562                 sym = DemandSymbol(tk_String);\r
3563                 if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR\r
3564                         && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR\r
3565                         && sym->type != SY_MAPARRAY && sym->type != SY_WORLDARRAY\r
3566                         && sym->type != SY_GLOBALARRAY)\r
3567                 {\r
3568                         ERR_Error(ERR_INCDEC_OP_ON_NON_VAR, YES);\r
3569                 }\r
3570                 else\r
3571                 {\r
3572                         TK_NextToken();\r
3573                         if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY\r
3574                                 || sym->type == SY_GLOBALARRAY)\r
3575                         {\r
3576                                 ParseArrayIndices(sym, sym->info.array.ndim);\r
3577                                 PC_AppendCmd(PCD_DUP);\r
3578                         }\r
3579                         else if(tk_Token == TK_LBRACKET)\r
3580                         {\r
3581                                 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);\r
3582                                 while(tk_Token == TK_LBRACKET)\r
3583                                 {\r
3584                                         TK_SkipPast(TK_RBRACKET);\r
3585                                 }\r
3586                         }\r
3587                         PC_AppendCmd(GetIncDecPCD(opToken, sym->type));\r
3588                         PC_AppendShrink(sym->info.var.index);\r
3589                         PC_AppendCmd(GetPushVarPCD(sym->type));\r
3590                         PC_AppendShrink(sym->info.var.index);\r
3591                 }\r
3592                 break;\r
3593         case TK_IDENTIFIER:\r
3594                 sym = SpeculateSymbol(tk_String, YES);\r
3595                 switch(sym->type)\r
3596                 {\r
3597                         case SY_SCRIPTALIAS:\r
3598                                 // FIXME\r
3599                                 break;\r
3600                         case SY_MAPARRAY:\r
3601                         case SY_WORLDARRAY:\r
3602                         case SY_GLOBALARRAY:\r
3603                                 TK_NextToken();\r
3604                                 ParseArrayIndices(sym, sym->info.array.ndim);\r
3605                                 // fallthrough\r
3606                         case SY_SCRIPTVAR:\r
3607                         case SY_MAPVAR:\r
3608                         case SY_WORLDVAR:\r
3609                         case SY_GLOBALVAR:\r
3610                                 if(sym->type != SY_MAPARRAY && sym->type != SY_WORLDARRAY\r
3611                                         && sym->type != SY_GLOBALARRAY)\r
3612                                 {\r
3613                                         TK_NextToken();\r
3614                                         if(tk_Token == TK_LBRACKET)\r
3615                                         {\r
3616                                                 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);\r
3617                                                 while(tk_Token == TK_LBRACKET)\r
3618                                                 {\r
3619                                                         TK_SkipPast(TK_RBRACKET);\r
3620                                                 }\r
3621                                         }\r
3622                                 }\r
3623                                 if((tk_Token == TK_INC || tk_Token == TK_DEC)\r
3624                                         && (sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY\r
3625                                                 || sym->type == SY_GLOBALARRAY))\r
3626                                 {\r
3627                                         PC_AppendCmd(PCD_DUP);\r
3628                                 }\r
3629                                 PC_AppendCmd(GetPushVarPCD(sym->type));\r
3630                                 PC_AppendShrink(sym->info.var.index);\r
3631                                 if(tk_Token == TK_INC || tk_Token == TK_DEC)\r
3632                                 {\r
3633                                         if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY\r
3634                                                 || sym->type == SY_GLOBALARRAY)\r
3635                                         {\r
3636                                                 PC_AppendCmd(PCD_SWAP);\r
3637                                         }\r
3638                                         PC_AppendCmd(GetIncDecPCD(tk_Token, sym->type));\r
3639                                         PC_AppendShrink(sym->info.var.index);\r
3640                                         TK_NextToken();\r
3641                                 }\r
3642                                 break;\r
3643                         case SY_INTERNFUNC:\r
3644                                 if(sym->info.internFunc.hasReturnValue == NO)\r
3645                                 {\r
3646                                         ERR_Error(ERR_EXPR_FUNC_NO_RET_VAL, YES);\r
3647                                 }\r
3648                                 ProcessInternFunc(sym);\r
3649                                 break;\r
3650                         case SY_SCRIPTFUNC:\r
3651                                 if(sym->info.scriptFunc.hasReturnValue == NO)\r
3652                                 {\r
3653                                         ERR_Error(ERR_EXPR_FUNC_NO_RET_VAL, YES);\r
3654                                 }\r
3655                                 ProcessScriptFunc(sym, NO);\r
3656                                 break;\r
3657                         default:\r
3658                                 ERR_Error(ERR_ILLEGAL_EXPR_IDENT, YES, tk_String);\r
3659                                 TK_NextToken();\r
3660                                 break;\r
3661                 }\r
3662                 break;\r
3663         case TK_LINESPECIAL:\r
3664                 ExprLineSpecial();\r
3665                 break;\r
3666         case TK_STRPARAM_EVAL:\r
3667                 LeadingPrint();\r
3668                 TK_NextToken();\r
3669                 break;\r
3670         case TK_STRCPY:\r
3671                 LeadingStrcpy();\r
3672                 TK_NextToken();\r
3673                 break;\r
3674         default:\r
3675                 ERR_Error(ERR_BAD_EXPR, YES);\r
3676                 TK_NextToken();\r
3677                 break;\r
3678         }\r
3679 }\r
3680 \r
3681 static void ConstExprFactor(void)\r
3682 {\r
3683         switch(tk_Token)\r
3684         {\r
3685         case TK_STRING:\r
3686                 if (ImportMode != IMPORT_Importing)\r
3687                 {\r
3688                         int strnum = STR_Find(tk_String);\r
3689                         if (ImportMode == IMPORT_Exporting)\r
3690                         {\r
3691                                 pa_ConstExprIsString = YES;\r
3692                         }\r
3693                         PushExStk(strnum);\r
3694                 }\r
3695                 else\r
3696                 {\r
3697                         // Importing, so it doesn't matter\r
3698                         PushExStk(0);\r
3699                 }\r
3700                 TK_NextToken();\r
3701                 break;\r
3702         case TK_NUMBER:\r
3703                 PushExStk(tk_Number);\r
3704                 TK_NextToken();\r
3705                 break;\r
3706         case TK_LPAREN:\r
3707                 TK_NextToken();\r
3708                 ExprLevA();\r
3709                 if(tk_Token != TK_RPAREN)\r
3710                 {\r
3711                         ERR_Error(ERR_BAD_CONST_EXPR, YES);\r
3712                         TK_SkipPast(TK_RPAREN);\r
3713                 }\r
3714                 else\r
3715                 {\r
3716                         TK_NextToken();\r
3717                 }\r
3718                 break;\r
3719         case TK_NOT:\r
3720                 TK_NextToken();\r
3721                 ConstExprFactor();\r
3722                 SendExprCommand(PCD_NEGATELOGICAL);\r
3723                 break;\r
3724         default:\r
3725                 ERR_Error(ERR_BAD_CONST_EXPR, YES);\r
3726                 PushExStk(0);\r
3727                 while(tk_Token != TK_COMMA &&\r
3728                         tk_Token != TK_SEMICOLON &&\r
3729                         tk_Token != TK_RPAREN)\r
3730                 {\r
3731                         if(tk_Token == TK_EOF)\r
3732                         {\r
3733                                 ERR_Exit(ERR_EOF, YES);\r
3734                         }\r
3735                         TK_NextToken();\r
3736                 }\r
3737                 break;\r
3738         }\r
3739 }\r
3740 \r
3741 //==========================================================================\r
3742 //\r
3743 // SendExprCommand\r
3744 //\r
3745 //==========================================================================\r
3746 \r
3747 static void SendExprCommand(pcd_t pcd)\r
3748 {\r
3749         int operand2;\r
3750 \r
3751         if(ConstantExpression == NO)\r
3752         {\r
3753                 PC_AppendCmd(pcd);\r
3754                 return;\r
3755         }\r
3756         switch(pcd)\r
3757         {\r
3758                 case PCD_ADD:\r
3759                         PushExStk(PopExStk()+PopExStk());\r
3760                         break;\r
3761                 case PCD_SUBTRACT:\r
3762                         operand2 = PopExStk();\r
3763                         PushExStk(PopExStk()-operand2);\r
3764                         break;\r
3765                 case PCD_MULTIPLY:\r
3766                         PushExStk(PopExStk()*PopExStk());\r
3767                         break;\r
3768                 case PCD_DIVIDE:\r
3769                         operand2 = PopExStk();\r
3770                         PushExStk(PopExStk()/operand2);\r
3771                         break;\r
3772                 case PCD_MODULUS:\r
3773                         operand2 = PopExStk();\r
3774                         PushExStk(PopExStk()%operand2);\r
3775                         break;\r
3776                 case PCD_EQ:\r
3777                         PushExStk(PopExStk() == PopExStk());\r
3778                         break;\r
3779                 case PCD_NE:\r
3780                         PushExStk(PopExStk() != PopExStk());\r
3781                         break;\r
3782                 case PCD_LT:\r
3783                         operand2 = PopExStk();\r
3784                         PushExStk(PopExStk() >= operand2);\r
3785                         break;\r
3786                 case PCD_GT:\r
3787                         operand2 = PopExStk();\r
3788                         PushExStk(PopExStk() <= operand2);\r
3789                         break;\r
3790                 case PCD_LE:\r
3791                         operand2 = PopExStk();\r
3792                         PushExStk(PopExStk() > operand2);\r
3793                         break;\r
3794                 case PCD_GE:\r
3795                         operand2 = PopExStk();\r
3796                         PushExStk(PopExStk() < operand2);\r
3797                         break;\r
3798                 case PCD_ANDLOGICAL:\r
3799                         PushExStk(PopExStk() && PopExStk());\r
3800                         break;\r
3801                 case PCD_ORLOGICAL:\r
3802                         PushExStk(PopExStk() || PopExStk());\r
3803                         break;\r
3804                 case PCD_ANDBITWISE:\r
3805                         PushExStk(PopExStk()&PopExStk());\r
3806                         break;\r
3807                 case PCD_ORBITWISE:\r
3808                         PushExStk(PopExStk()|PopExStk());\r
3809                         break;\r
3810                 case PCD_EORBITWISE:\r
3811                         PushExStk(PopExStk()^PopExStk());\r
3812                         break;\r
3813                 case PCD_NEGATELOGICAL:\r
3814                         PushExStk(!PopExStk());\r
3815                         break;\r
3816                 case PCD_LSHIFT:\r
3817                         operand2 = PopExStk();\r
3818                         PushExStk(PopExStk()<<operand2);\r
3819                         break;\r
3820                 case PCD_RSHIFT:\r
3821                         operand2 = PopExStk();\r
3822                         PushExStk(PopExStk()>>operand2);\r
3823                         break;\r
3824                 case PCD_UNARYMINUS:\r
3825                         PushExStk(-PopExStk());\r
3826                         break;\r
3827                 default:\r
3828                         ERR_Exit(ERR_UNKNOWN_CONST_EXPR_PCD, YES);\r
3829                         break;\r
3830         }\r
3831 }\r
3832 \r
3833 //==========================================================================\r
3834 //\r
3835 // PushExStk\r
3836 //\r
3837 //==========================================================================\r
3838 \r
3839 static void PushExStk(int value)\r
3840 {\r
3841         if(ExprStackIndex == EXPR_STACK_DEPTH)\r
3842         {\r
3843                 ERR_Exit(ERR_EXPR_STACK_OVERFLOW, YES);\r
3844         }\r
3845         ExprStack[ExprStackIndex++] = value;\r
3846 }\r
3847 \r
3848 //==========================================================================\r
3849 //\r
3850 // PopExStk\r
3851 //\r
3852 //==========================================================================\r
3853 \r
3854 static int PopExStk(void)\r
3855 {\r
3856         if(ExprStackIndex < 1)\r
3857         {\r
3858                 ERR_Error(ERR_EXPR_STACK_EMPTY, YES);\r
3859                 return 0;\r
3860         }\r
3861         return ExprStack[--ExprStackIndex];\r
3862 }\r
3863 \r
3864 //==========================================================================\r
3865 //\r
3866 // TokenToPCD\r
3867 //\r
3868 //==========================================================================\r
3869 \r
3870 static pcd_t TokenToPCD(tokenType_t token)\r
3871 {\r
3872         int i;\r
3873         static struct\r
3874         {\r
3875                 tokenType_t token;\r
3876                 pcd_t pcd;\r
3877         }  operatorLookup[] =\r
3878         {\r
3879                 { TK_ORLOGICAL,         PCD_ORLOGICAL },\r
3880                 { TK_ANDLOGICAL,        PCD_ANDLOGICAL },\r
3881                 { TK_ORBITWISE,         PCD_ORBITWISE },\r
3882                 { TK_EORBITWISE,        PCD_EORBITWISE },\r
3883                 { TK_ANDBITWISE,        PCD_ANDBITWISE },\r
3884                 { TK_EQ,                        PCD_EQ },\r
3885                 { TK_NE,                        PCD_NE },\r
3886                 { TK_LT,                        PCD_LT },\r
3887                 { TK_LE,                        PCD_LE },\r
3888                 { TK_GT,                        PCD_GT },\r
3889                 { TK_GE,                        PCD_GE },\r
3890                 { TK_LSHIFT,            PCD_LSHIFT },\r
3891                 { TK_RSHIFT,            PCD_RSHIFT },\r
3892                 { TK_PLUS,                      PCD_ADD },\r
3893                 { TK_MINUS,                     PCD_SUBTRACT },\r
3894                 { TK_ASTERISK,          PCD_MULTIPLY },\r
3895                 { TK_SLASH,                     PCD_DIVIDE },\r
3896                 { TK_PERCENT,           PCD_MODULUS },\r
3897                 { TK_NONE,                      PCD_NOP }\r
3898         };\r
3899 \r
3900         for(i = 0; operatorLookup[i].token != TK_NONE; i++)\r
3901         {\r
3902                 if(operatorLookup[i].token == token)\r
3903                 {\r
3904                         return operatorLookup[i].pcd;\r
3905                 }\r
3906         }\r
3907         return PCD_NOP;\r
3908 }\r
3909 \r
3910 //==========================================================================\r
3911 //\r
3912 // GetPushVarPCD\r
3913 //\r
3914 //==========================================================================\r
3915 \r
3916 static pcd_t GetPushVarPCD(symbolType_t symType)\r
3917 {\r
3918         switch(symType)\r
3919         {\r
3920                 case SY_SCRIPTVAR:\r
3921                         return PCD_PUSHSCRIPTVAR;\r
3922                 case SY_MAPVAR:\r
3923                         return PCD_PUSHMAPVAR;\r
3924                 case SY_WORLDVAR:\r
3925                         return PCD_PUSHWORLDVAR;\r
3926                 case SY_GLOBALVAR:\r
3927                         return PCD_PUSHGLOBALVAR;\r
3928                 case SY_MAPARRAY:\r
3929                         return PCD_PUSHMAPARRAY;\r
3930                 case SY_WORLDARRAY:\r
3931                         return PCD_PUSHWORLDARRAY;\r
3932                 case SY_GLOBALARRAY:\r
3933                         return PCD_PUSHGLOBALARRAY;\r
3934                 default:\r
3935                         break;\r
3936         }\r
3937         return PCD_NOP;\r
3938 }\r
3939 \r
3940 //==========================================================================\r
3941 //\r
3942 // GetIncDecPCD\r
3943 //\r
3944 //==========================================================================\r
3945 \r
3946 static pcd_t GetIncDecPCD(tokenType_t token, symbolType_t symbol)\r
3947 {\r
3948         int i;\r
3949         static struct\r
3950         {\r
3951                 tokenType_t token;\r
3952                 symbolType_t symbol;\r
3953                 pcd_t pcd;\r
3954         }  incDecLookup[] =\r
3955         {\r
3956                 { TK_INC, SY_SCRIPTVAR, PCD_INCSCRIPTVAR },\r
3957                 { TK_INC, SY_MAPVAR, PCD_INCMAPVAR },\r
3958                 { TK_INC, SY_WORLDVAR, PCD_INCWORLDVAR },\r
3959                 { TK_INC, SY_GLOBALVAR, PCD_INCGLOBALVAR },\r
3960                 { TK_INC, SY_MAPARRAY, PCD_INCMAPARRAY },\r
3961                 { TK_INC, SY_WORLDARRAY, PCD_INCWORLDARRAY },\r
3962                 { TK_INC, SY_GLOBALARRAY, PCD_INCGLOBALARRAY },\r
3963 \r
3964                 { TK_DEC, SY_SCRIPTVAR, PCD_DECSCRIPTVAR },\r
3965                 { TK_DEC, SY_MAPVAR, PCD_DECMAPVAR },\r
3966                 { TK_DEC, SY_WORLDVAR, PCD_DECWORLDVAR },\r
3967                 { TK_DEC, SY_GLOBALVAR, PCD_DECGLOBALVAR },\r
3968                 { TK_DEC, SY_MAPARRAY, PCD_DECMAPARRAY },\r
3969                 { TK_DEC, SY_WORLDARRAY, PCD_DECWORLDARRAY },\r
3970                 { TK_DEC, SY_GLOBALARRAY, PCD_DECGLOBALARRAY },\r
3971 \r
3972                 { TK_NONE, SY_DUMMY, PCD_NOP }\r
3973         };\r
3974 \r
3975         for(i = 0; incDecLookup[i].token != TK_NONE; i++)\r
3976         {\r
3977                 if(incDecLookup[i].token == token\r
3978                         && incDecLookup[i].symbol == symbol)\r
3979                 {\r
3980                         return incDecLookup[i].pcd;\r
3981                 }\r
3982         }\r
3983         return PCD_NOP;\r
3984 }\r
3985 \r
3986 //==========================================================================\r
3987 //\r
3988 // ParseArrayIndices\r
3989 //\r
3990 //==========================================================================\r
3991 \r
3992 static void ParseArrayIndices(symbolNode_t *sym, int requiredIndices)\r
3993 {\r
3994         boolean warned = NO;\r
3995         int i;\r
3996 \r
3997         if(requiredIndices > 0)\r
3998         {\r
3999                 TK_TokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET);\r
4000         }\r
4001         i = 0;\r
4002         while(tk_Token == TK_LBRACKET)\r
4003         {\r
4004                 TK_NextToken();\r
4005                 if((sym->type == SY_MAPARRAY && i == requiredIndices) ||\r
4006                         (sym->type != SY_MAPARRAY && i > 0))\r
4007                 {\r
4008                         if (!warned)\r
4009                         {\r
4010                                 warned = YES;\r
4011                                 if(sym->info.array.ndim == requiredIndices)\r
4012                                 {\r
4013                                         ERR_Error(ERR_TOO_MANY_DIM_USED, YES,\r
4014                                                 sym->name, sym->info.array.ndim);\r
4015                                 }\r
4016                                 else\r
4017                                 {\r
4018                                         ERR_Error(ERR_NOT_A_CHAR_ARRAY, YES, sym->name,\r
4019                                                 sym->info.array.ndim, requiredIndices);\r
4020                                 }\r
4021                         }\r
4022                 }\r
4023                 EvalExpression();\r
4024                 if(i < sym->info.array.ndim - 1 && sym->info.array.dimensions[i] > 1)\r
4025                 {\r
4026                         PC_AppendPushVal(sym->info.array.dimensions[i]);\r
4027                         PC_AppendCmd(PCD_MULTIPLY);\r
4028                 }\r
4029                 if(i > 0)\r
4030                 {\r
4031                         PC_AppendCmd(PCD_ADD);\r
4032                 }\r
4033                 i++;\r
4034                 TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET);\r
4035                 TK_NextToken();\r
4036         }\r
4037         if(i < requiredIndices)\r
4038         {\r
4039                 ERR_Error(ERR_TOO_FEW_DIM_USED, YES,\r
4040                         sym->name, requiredIndices - i);\r
4041         }\r
4042         // if there were unspecified indices, multiply the offset by their sizes [JB]\r
4043         if(requiredIndices < sym->info.array.ndim - 1)\r
4044         {\r
4045                 int i, mult = 1;\r
4046                 for(i = 0; i < sym->info.array.ndim - requiredIndices - 1; ++i)\r
4047                 {\r
4048                         mult *= sym->info.array.dimensions[sym->info.array.ndim - 2 - i];\r
4049                 }\r
4050                 if(mult > 1)\r
4051                 {\r
4052                         PC_AppendPushVal(mult);\r
4053                         PC_AppendCmd(PCD_MULTIPLY);\r
4054                 }\r
4055         }\r
4056 }\r
4057 \r
4058 static void ProcessArrayLevel(int level, int *entry, int ndim,\r
4059         int dims[MAX_ARRAY_DIMS], int muls[MAX_ARRAY_DIMS], char *name)\r
4060 {\r
4061         int warned_too_many = NO;\r
4062         int i;\r
4063 \r
4064         for(i = 0; ; ++i)\r
4065         {\r
4066                 if(tk_Token == TK_COMMA)\r
4067                 {\r
4068                         entry += muls[level-1];\r
4069                         TK_NextToken();\r
4070                 }\r
4071                 else if(tk_Token == TK_RBRACE)\r
4072                 {\r
4073                         TK_NextToken();\r
4074                         return;\r
4075                 }\r
4076                 else\r
4077                 {\r
4078                         if(level == ndim)\r
4079                         {\r
4080                                 if(tk_Token == TK_LBRACE)\r
4081                                 {\r
4082                                         ERR_Error(ERR_TOO_MANY_DIM_USED, YES, name, ndim);\r
4083                                         SkipBraceBlock(0);\r
4084                                         TK_NextToken();\r
4085                                         entry++;\r
4086                                 }\r
4087                                 else\r
4088                                 {\r
4089                                         int val;\r
4090 \r
4091                                         if (i >= dims[level - 1] && !warned_too_many)\r
4092                                         {\r
4093                                                 warned_too_many = YES;\r
4094                                                 ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES);\r
4095                                         }\r
4096                                         val = EvalConstExpression();\r
4097                                         ArrayHasStrings |= pa_ConstExprIsString;\r
4098                                         if (i < dims[level - 1])\r
4099                                         {\r
4100                                                 entry[i] = val;\r
4101                                         }\r
4102                                 }\r
4103                         }\r
4104                         else\r
4105                         {\r
4106                                 //Bugfix for r3226 by Zom-B\r
4107                                 if (i >= dims[level - 1])\r
4108                                 {\r
4109                                         if (!warned_too_many)\r
4110                                         {\r
4111                                                 warned_too_many = YES;\r
4112                                                 ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES);\r
4113                                         }\r
4114                                         // Allow execution to continue without stray memory access\r
4115                                         entry -= muls[level-1];\r
4116                                 }\r
4117                                 TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR);\r
4118                                 TK_NextToken();\r
4119                                 ProcessArrayLevel(level+1, entry, ndim, dims, muls, name);\r
4120                                 assert(level > 0);\r
4121                                 entry += muls[level-1];\r
4122                         }\r
4123                         if(i < dims[level-1]-1)\r
4124                         {\r
4125                                 if(tk_Token != TK_RBRACE)\r
4126                                 {\r
4127                                         TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA);\r
4128                                         TK_NextToken();\r
4129                                 }\r
4130                         }\r
4131                         else\r
4132                         {\r
4133                                 if(tk_Token != TK_COMMA)\r
4134                                 {\r
4135                                         TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR);\r
4136                                 }\r
4137                                 else\r
4138                                 {\r
4139                                         TK_NextToken();\r
4140                                 }\r
4141                         }\r
4142                 }\r
4143         }\r
4144         TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR);\r
4145         TK_NextToken();\r
4146 }\r
4147 \r
4148 //==========================================================================\r
4149 //\r
4150 // InitializeArray\r
4151 //\r
4152 //==========================================================================\r
4153 \r
4154 static void InitializeArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS], int size)\r
4155 {\r
4156         static int *entries = NULL;\r
4157         static int lastsize = -1;\r
4158 \r
4159         if(lastsize < size)\r
4160         {\r
4161                 entries = MS_Realloc(entries, sizeof(int)*size, ERR_OUT_OF_MEMORY);\r
4162                 lastsize = size;\r
4163         }\r
4164         memset(entries, 0, sizeof(int)*size);\r
4165 \r
4166         TK_NextTokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR);\r
4167         TK_NextToken();\r
4168         ArrayHasStrings = NO;\r
4169         ProcessArrayLevel(1, entries, sym->info.array.ndim, dims,\r
4170                 sym->info.array.dimensions, sym->name);\r
4171         if(ImportMode != IMPORT_Importing)\r
4172         {\r
4173                 PC_InitArray(sym->info.array.index, entries, ArrayHasStrings);\r
4174         }\r
4175 }\r
4176 \r
4177 //==========================================================================\r
4178 //\r
4179 // DemandSymbol\r
4180 //\r
4181 //==========================================================================\r
4182 \r
4183 static symbolNode_t *DemandSymbol(char *name)\r
4184 {\r
4185         symbolNode_t *sym;\r
4186 \r
4187         if((sym = SY_Find(name)) == NULL)\r
4188         {\r
4189                 ERR_Exit(ERR_UNKNOWN_IDENTIFIER, YES, name);\r
4190         }\r
4191         return sym;\r
4192 }\r
4193 \r
4194 //==========================================================================\r
4195 //\r
4196 // SpeculateSymbol\r
4197 //\r
4198 //==========================================================================\r
4199 \r
4200 static symbolNode_t *SpeculateSymbol(char *name, boolean hasReturn)\r
4201 {\r
4202         symbolNode_t *sym;\r
4203 \r
4204         sym = SY_Find(name);\r
4205         if(sym == NULL)\r
4206         {\r
4207                 char name[MAX_IDENTIFIER_LENGTH];\r
4208 \r
4209                 strcpy (name, tk_String);\r
4210                 TK_NextToken();\r
4211                 if(tk_Token == TK_LPAREN)\r
4212                 { // Looks like a function call\r
4213                         sym = SpeculateFunction(name, hasReturn);\r
4214                         TK_Undo();\r
4215                 }\r
4216                 else\r
4217                 {\r
4218                         ERR_Exit(ERR_UNKNOWN_IDENTIFIER, YES, name);\r
4219                 }\r
4220         }\r
4221         return sym;\r
4222 }\r
4223 \r
4224 //==========================================================================\r
4225 //\r
4226 // SpeculateFunction\r
4227 //\r
4228 // Add a temporary symbol for a function that is used before it is defined.\r
4229 //\r
4230 //==========================================================================\r
4231 \r
4232 static symbolNode_t *SpeculateFunction(const char *name, boolean hasReturn)\r
4233 {\r
4234         symbolNode_t *sym;\r
4235         \r
4236         MS_Message(MSG_DEBUG, "---- SpeculateFunction %s ----\n", name);\r
4237         sym = SY_InsertGlobal(tk_String, SY_SCRIPTFUNC);\r
4238         sym->info.scriptFunc.predefined = YES;\r
4239         sym->info.scriptFunc.hasReturnValue = hasReturn;\r
4240         sym->info.scriptFunc.sourceLine = tk_Line;\r
4241         sym->info.scriptFunc.sourceName = tk_SourceName;\r
4242         sym->info.scriptFunc.argCount = -1;\r
4243         sym->info.scriptFunc.funcNumber = 0;\r
4244         return sym;\r
4245 }\r
4246 \r
4247 //==========================================================================\r
4248 //\r
4249 // UnspeculateFunction\r
4250 //\r
4251 // Fills in function calls that were made before this function was defined.\r
4252 //\r
4253 //==========================================================================\r
4254 \r
4255 static void UnspeculateFunction(symbolNode_t *sym)\r
4256 {\r
4257         prefunc_t *fillin;\r
4258         prefunc_t **prev;\r
4259 \r
4260         prev = &FillinFunctions;\r
4261         fillin = FillinFunctions;\r
4262         while(fillin != NULL)\r
4263         {\r
4264                 prefunc_t *next = fillin->next;\r
4265                 if(fillin->sym == sym)\r
4266                 {\r
4267                         if(fillin->argcount != sym->info.scriptFunc.argCount)\r
4268                         {\r
4269                                 ERR_ErrorAt(fillin->source, fillin->line);\r
4270                                 ERR_Error(ERR_FUNC_ARGUMENT_COUNT, YES, sym->name,\r
4271                                         sym->info.scriptFunc.argCount,\r
4272                                         sym->info.scriptFunc.argCount == 1 ? "" : "s");\r
4273                         }\r
4274 \r
4275                         if(pc_NoShrink)\r
4276                         {\r
4277                                 PC_WriteInt(sym->info.scriptFunc.funcNumber, fillin->address);\r
4278                         }\r
4279                         else\r
4280                         {\r
4281                                 PC_WriteByte((U_BYTE)sym->info.scriptFunc.funcNumber, fillin->address);\r
4282                         }\r
4283                         if(FillinFunctionsLatest == &fillin->next)\r
4284                         {\r
4285                                 FillinFunctionsLatest = prev;\r
4286                         }\r
4287                         free (fillin);\r
4288                         *prev = next;\r
4289                 }\r
4290                 else\r
4291                 {\r
4292                         prev = &fillin->next;\r
4293                 }\r
4294                 fillin = next;\r
4295         }\r
4296 }\r
4297 \r
4298 //==========================================================================\r
4299 //\r
4300 // AddScriptFuncRef\r
4301 //\r
4302 //==========================================================================\r
4303 \r
4304 static void AddScriptFuncRef(symbolNode_t *sym, int address, int argcount)\r
4305 {\r
4306         prefunc_t *fillin = MS_Alloc(sizeof(*fillin), ERR_OUT_OF_MEMORY);\r
4307         fillin->next = NULL;\r
4308         fillin->sym = sym;\r
4309         fillin->address = address;\r
4310         fillin->argcount = argcount;\r
4311         fillin->line = tk_Line;\r
4312         fillin->source = tk_SourceName;\r
4313         *FillinFunctionsLatest = fillin;\r
4314         FillinFunctionsLatest = &fillin->next;\r
4315 }\r
4316 \r
4317 //==========================================================================\r
4318 //\r
4319 // Check for undefined functions\r
4320 //\r
4321 //==========================================================================\r
4322 \r
4323 static void CheckForUndefinedFunctions(void)\r
4324 {\r
4325         prefunc_t *fillin = FillinFunctions;\r
4326 \r
4327         while(fillin != NULL)\r
4328         {\r
4329                 ERR_ErrorAt(fillin->source, fillin->line);\r
4330                 ERR_Error(ERR_UNDEFINED_FUNC, YES, fillin->sym->name);\r
4331                 fillin = fillin->next;\r
4332         }\r
4333 }\r
4334 \r
4335 //==========================================================================\r
4336 //\r
4337 // SkipBraceBlock\r
4338 //\r
4339 // If depth is 0, it scans for the first { and then starts going from there.\r
4340 // At exit, the terminating } is left as the current token.\r
4341 //\r
4342 //==========================================================================\r
4343 \r
4344 void SkipBraceBlock(int depth)\r
4345 {\r
4346         if (depth == 0)\r
4347         {\r
4348                 // Find first {\r
4349                 while(tk_Token != TK_LBRACE)\r
4350                 {\r
4351                         if(tk_Token == TK_EOF)\r
4352                         {\r
4353                                 ERR_Exit(ERR_EOF, NO);\r
4354                         }\r
4355                         TK_NextToken();\r
4356                 }\r
4357                 depth = 1;\r
4358         }\r
4359         // Match it with a }\r
4360         do\r
4361         {\r
4362                 TK_NextToken();\r
4363                 if(tk_Token == TK_EOF)\r
4364                 {\r
4365                         ERR_Exit(ERR_EOF, NO);\r
4366                 }\r
4367                 else if (tk_Token == TK_LBRACE)\r
4368                 {\r
4369                         depth++;\r
4370                 }\r
4371                 else if (tk_Token == TK_RBRACE)\r
4372                 {\r
4373                         depth--;\r
4374                 }\r
4375         } while (depth > 0);\r
4376 }\r