OSDN Git Service

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