OSDN Git Service

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