OSDN Git Service

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