2 //**************************************************************************
\r
6 //**************************************************************************
\r
8 // HEADER FILES ------------------------------------------------------------
\r
23 #include "strlist.h"
\r
25 // MACROS ------------------------------------------------------------------
\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
33 // TYPES -------------------------------------------------------------------
\r
66 typedef struct prefunc_s
\r
68 struct prefunc_s *next;
\r
76 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
\r
78 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
\r
80 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
\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
154 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
\r
156 // PUBLIC DATA DEFINITIONS -------------------------------------------------
\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
169 // PRIVATE DATA DEFINITIONS ------------------------------------------------
\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
189 static int AdjustStmtLevel[] =
\r
195 1, // STMT_WHILEUNTIL
\r
200 static boolean IsBreakRoot[] =
\r
206 YES, // STMT_WHILEUNTIL
\r
207 YES, // STMT_SWITCH
\r
211 static boolean IsContinueRoot[] =
\r
217 YES, // STMT_WHILEUNTIL
\r
222 static tokenType_t LevAOps[] =
\r
228 static tokenType_t LevBOps[] =
\r
234 static tokenType_t LevCOps[] =
\r
240 static tokenType_t LevDOps[] =
\r
246 static tokenType_t LevEOps[] =
\r
252 static tokenType_t LevFOps[] =
\r
259 static tokenType_t LevGOps[] =
\r
268 static tokenType_t LevHOps[] =
\r
275 static tokenType_t LevIOps[] =
\r
282 static tokenType_t LevJOps[] =
\r
290 static tokenType_t *OpsList[] =
\r
305 static tokenType_t AssignOps[] =
\r
321 static struct ScriptTypes ScriptCounts[] =
\r
323 { "closed", 0, 0 },
\r
324 { "open", OPEN_SCRIPTS_BASE, 0 },
\r
325 { "respawn", RESPAWN_SCRIPTS_BASE, 0 },
\r
326 { "death", DEATH_SCRIPTS_BASE, 0 },
\r
327 { "enter", ENTER_SCRIPTS_BASE, 0 },
\r
328 { "pickup", PICKUP_SCRIPTS_BASE, 0 },
\r
329 { "bluereturn", BLUE_RETURN_SCRIPTS_BASE, 0 },
\r
330 { "redreturn", RED_RETURN_SCRIPTS_BASE, 0 },
\r
331 { "whitereturn", WHITE_RETURN_SCRIPTS_BASE, 0 },
\r
332 { "lightning", LIGHTNING_SCRIPTS_BASE, 0 },
\r
333 { "disconnect", DISCONNECT_SCRIPTS_BASE, 0 },
\r
334 { "unloading", UNLOADING_SCRIPTS_BASE, 0 },
\r
335 { "return", RETURN_SCRIPTS_BASE, 0 },
\r
339 // CODE --------------------------------------------------------------------
\r
341 //==========================================================================
\r
345 //==========================================================================
\r
347 void PA_Parse(void)
\r
351 pa_ScriptCount = 0;
\r
352 pa_TypedScriptCounts = ScriptCounts;
\r
353 for (i = 0; ScriptCounts[i].TypeName != NULL; i++)
\r
355 ScriptCounts[i].TypeCount = 0;
\r
357 pa_MapVarCount = 0;
\r
358 pa_WorldVarCount = 0;
\r
359 pa_GlobalVarCount = 0;
\r
360 pa_WorldArrayCount = 0;
\r
361 pa_GlobalArrayCount = 0;
\r
364 CheckForUndefinedFunctions();
\r
368 //==========================================================================
\r
372 //==========================================================================
\r
374 static void CountScript(int type)
\r
378 for (i = 0; ScriptCounts[i].TypeName != NULL; i++)
\r
380 if (ScriptCounts[i].TypeBase == type)
\r
384 MS_Message(MSG_DEBUG, "Script type: %s\n",
\r
385 ScriptCounts[i].TypeName);
\r
387 ScriptCounts[i].TypeCount++;
\r
394 //==========================================================================
\r
398 //==========================================================================
\r
400 static void Outside(void)
\r
428 OuterWorldVar(YES);
\r
433 case TK_NUMBERSIGN:
\r
447 if(ImportMode != IMPORT_Importing)
\r
449 if(pc_Address != 8)
\r
451 ERR_Error(ERR_NOCOMPACT_NOT_HERE, YES);
\r
453 MS_Message(MSG_DEBUG, "Forcing NoShrink\n");
\r
454 pc_NoShrink = TRUE;
\r
459 if(ImportMode != IMPORT_Importing)
\r
461 MS_Message(MSG_DEBUG, "Will write WadAuthor-compatible object\n");
\r
462 MS_Message(MSG_NORMAL, "You don't need to use #wadauthor anymore.\n");
\r
463 pc_WadAuthor = TRUE;
\r
467 case TK_NOWADAUTHOR:
\r
468 if(ImportMode != IMPORT_Importing)
\r
470 MS_Message(MSG_DEBUG, "Will write WadAuthor-incompatible object\n");
\r
471 pc_WadAuthor = FALSE;
\r
475 case TK_ENCRYPTSTRINGS:
\r
476 if(ImportMode != IMPORT_Importing)
\r
478 MS_Message(MSG_DEBUG, "Strings will be encrypted\n");
\r
479 pc_EncryptStrings = TRUE;
\r
487 TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND);
\r
488 if(ImportMode == IMPORT_None)
\r
490 MS_Message(MSG_DEBUG, "Allocations modified for exporting\n");
\r
491 ImportMode = IMPORT_Exporting;
\r
493 else if(ImportMode == IMPORT_Importing)
\r
495 PC_AddImport(tk_String);
\r
496 ExporterFlagged = YES;
\r
501 ERR_Error(ERR_INVALID_DIRECTIVE, YES);
\r
507 ERR_Exit(ERR_INVALID_DECLARATOR, YES, NULL);
\r
513 //==========================================================================
\r
517 //==========================================================================
\r
519 static void OuterScript(void)
\r
525 MS_Message(MSG_DEBUG, "---- OuterScript ----\n");
\r
528 StatementLevel = 0;
\r
529 ScriptVarCount = 0;
\r
533 if(ImportMode == IMPORT_Importing)
\r
535 // When importing, the script number is not recorded, because
\r
536 // it might be a #define that is not included by the main .acs
\r
537 // file, so processing it would generate a syntax error.
\r
543 // [RH] If you want to use script 0, it must be written as <<0>>.
\r
544 // This is to avoid using it accidentally, since ZDoom uses script
\r
545 // 0 to implement many of the Strife-specific line specials.
\r
547 if(tk_Token == TK_LSHIFT)
\r
549 TK_NextTokenMustBe(TK_NUMBER, ERR_SCRIPT_OUT_OF_RANGE);
\r
552 ERR_Exit(ERR_SCRIPT_OUT_OF_RANGE, YES, NULL);
\r
554 TK_NextTokenMustBe(TK_RSHIFT, ERR_SCRIPT_OUT_OF_RANGE);
\r
560 scriptNumber = EvalConstExpression();
\r
561 if(scriptNumber < 1 || scriptNumber > 999)
\r
564 ERR_Error(ERR_SCRIPT_OUT_OF_RANGE, YES, NULL);
\r
570 MS_Message(MSG_DEBUG, "Script number: %d\n", scriptNumber);
\r
572 if(tk_Token == TK_LPAREN)
\r
574 if(TK_NextToken() == TK_VOID)
\r
576 TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
583 TK_NextTokenMustBe(TK_INT, ERR_BAD_VAR_TYPE);
\r
584 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
585 if(ScriptVarCount == 3)
\r
587 ERR_Error(ERR_TOO_MANY_SCRIPT_ARGS, YES);
\r
589 if(SY_FindLocal(tk_String) != NULL)
\r
591 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);
\r
593 else if(ScriptVarCount < 3)
\r
595 sym = SY_InsertLocal(tk_String, SY_SCRIPTVAR);
\r
596 sym->info.var.index = ScriptVarCount;
\r
600 } while(tk_Token == TK_COMMA);
\r
601 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
606 case TK_DISCONNECT:
\r
607 scriptType = DISCONNECT_SCRIPTS_BASE;
\r
608 if(ScriptVarCount != 1)
\r
610 ERR_Error(ERR_DISCONNECT_NEEDS_1_ARG, YES);
\r
619 case TK_BLUERETURN:
\r
621 case TK_WHITERETURN:
\r
625 ERR_Error(ERR_UNCLOSED_WITH_ARGS, YES);
\r
631 MS_Message(MSG_DEBUG, "Script type: %s (%d %s)\n",
\r
632 scriptType == 0 ? "closed" : "disconnect",
\r
633 ScriptVarCount, ScriptVarCount == 1 ? "arg" : "args");
\r
635 else switch (tk_Token)
\r
638 scriptType = OPEN_SCRIPTS_BASE;
\r
641 case TK_RESPAWN: // [BC]
\r
642 scriptType = RESPAWN_SCRIPTS_BASE;
\r
645 case TK_DEATH: // [BC]
\r
646 scriptType = DEATH_SCRIPTS_BASE;
\r
649 case TK_ENTER: // [BC]
\r
650 scriptType = ENTER_SCRIPTS_BASE;
\r
654 scriptType = RETURN_SCRIPTS_BASE;
\r
657 case TK_PICKUP: // [BC]
\r
658 scriptType = PICKUP_SCRIPTS_BASE;
\r
661 case TK_BLUERETURN: // [BC]
\r
662 scriptType = BLUE_RETURN_SCRIPTS_BASE;
\r
665 case TK_REDRETURN: // [BC]
\r
666 scriptType = RED_RETURN_SCRIPTS_BASE;
\r
669 case TK_WHITERETURN: // [BC]
\r
670 scriptType = WHITE_RETURN_SCRIPTS_BASE;
\r
674 scriptType = LIGHTNING_SCRIPTS_BASE;
\r
678 scriptType = UNLOADING_SCRIPTS_BASE;
\r
681 case TK_DISCONNECT:
\r
682 scriptType = DISCONNECT_SCRIPTS_BASE;
\r
683 ERR_Error (ERR_DISCONNECT_NEEDS_1_ARG, YES);
\r
687 ERR_Error(ERR_BAD_SCRIPT_DECL, YES);
\r
693 if(tk_Token == TK_NET)
\r
695 scriptNumber += NET_SCRIPT_FLAG;
\r
698 CountScript(scriptType);
\r
699 PC_AddScript(scriptNumber + scriptType, ScriptVarCount);
\r
700 pc_LastAppendedCommand = PCD_NOP;
\r
701 if(ProcessStatement(STMT_SCRIPT) == NO)
\r
703 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
705 if(pc_LastAppendedCommand != PCD_TERMINATE)
\r
707 PC_AppendCmd(PCD_TERMINATE);
\r
709 PC_SetScriptVarCount(scriptNumber + scriptType, ScriptVarCount);
\r
713 //==========================================================================
\r
717 //==========================================================================
\r
719 static void OuterFunction(void)
\r
721 enum ImportModes importing;
\r
726 MS_Message(MSG_DEBUG, "---- OuterFunction ----\n");
\r
727 importing = ImportMode;
\r
730 StatementLevel = 0;
\r
731 ScriptVarCount = 0;
\r
734 if(tk_Token != TK_STR && tk_Token != TK_INT &&
\r
735 tk_Token != TK_VOID && tk_Token != TK_BOOL)
\r
737 ERR_Error(ERR_BAD_RETURN_TYPE, YES);
\r
738 tk_Token = TK_VOID;
\r
740 hasReturn = tk_Token != TK_VOID;
\r
741 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
742 sym = SY_FindGlobal(tk_String);
\r
745 if(sym->type != SY_SCRIPTFUNC)
\r
747 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);
\r
752 if(!sym->info.scriptFunc.predefined)
\r
754 ERR_Error(ERR_FUNCTION_ALREADY_DEFINED, YES);
\r
755 ERR_ErrorAt(sym->info.scriptFunc.sourceName, sym->info.scriptFunc.sourceLine);
\r
756 ERR_Error(ERR_NONE, YES, "Previous definition was here.");
\r
761 if(sym->info.scriptFunc.hasReturnValue && !hasReturn)
\r
763 ERR_Error(ERR_PREVIOUS_NOT_VOID, YES);
\r
764 ERR_ErrorAt(sym->info.scriptFunc.sourceName, sym->info.scriptFunc.sourceLine);
\r
765 ERR_Error(ERR_NONE, YES, "Previous use was here.");
\r
770 sym = SY_InsertGlobal(tk_String, SY_SCRIPTFUNC);
\r
771 sym->info.scriptFunc.address = (importing == IMPORT_Importing ? 0 : pc_Address);
\r
772 sym->info.scriptFunc.predefined = NO;
\r
776 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
777 if(TK_NextToken() == TK_VOID)
\r
779 TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
787 symbolNode_t *local;
\r
790 /* if(tk_Token != TK_INT && tk_Token != TK_STR && tk_Token != TK_BOOL)
\r
792 ERR_Error(ERR_BAD_VAR_TYPE, YES);
\r
795 */ if(tk_Token == TK_INT || tk_Token == TK_BOOL)
\r
797 if(TK_NextToken() == TK_LBRACKET)
\r
799 TK_NextTokenMustBe(TK_RBRACKET, ERR_BAD_VAR_TYPE);
\r
800 type = SY_SCRIPTALIAS;
\r
805 type = SY_SCRIPTVAR;
\r
808 else if(tk_Token == TK_STR)
\r
810 type = SY_SCRIPTVAR;
\r
814 type = SY_SCRIPTVAR;
\r
815 ERR_Error(ERR_BAD_VAR_TYPE, YES);
\r
818 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
819 if(SY_FindLocal(tk_String) != NULL)
\r
821 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);
\r
825 local = SY_InsertLocal(tk_String, type);
\r
826 local->info.var.index = ScriptVarCount;
\r
830 } while(tk_Token == TK_COMMA);
\r
831 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
834 sym->info.scriptFunc.sourceLine = defLine;
\r
835 sym->info.scriptFunc.sourceName = tk_SourceName;
\r
836 sym->info.scriptFunc.argCount = ScriptVarCount;
\r
837 sym->info.scriptFunc.address = (importing == IMPORT_Importing) ? 0 : pc_Address;
\r
838 sym->info.scriptFunc.hasReturnValue = hasReturn;
\r
840 if(importing == IMPORT_Importing)
\r
844 sym->info.scriptFunc.predefined = NO;
\r
845 sym->info.scriptFunc.varCount = ScriptVarCount;
\r
850 InsideFunction = sym;
\r
851 pc_LastAppendedCommand = PCD_NOP;
\r
853 // If we just call ProcessStatement(STMT_SCRIPT), and this function
\r
854 // needs to return a value but the last pcode output was not a return,
\r
855 // then the line number given in the error can be confusing because it
\r
856 // is beyond the end of the function. To avoid this, we process the
\r
857 // compound statement ourself and check if it returned something
\r
858 // before checking for the '}'. If a return is required, then the error
\r
859 // line will be shown as the one that contains the '}' (if present).
\r
861 TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE);
\r
863 do ; while(ProcessStatement(STMT_SCRIPT) == YES);
\r
865 if(pc_LastAppendedCommand != PCD_RETURNVOID &&
\r
866 pc_LastAppendedCommand != PCD_RETURNVAL)
\r
871 ERR_Error(ERR_MUST_RETURN_A_VALUE, YES, NULL);
\r
873 PC_AppendCmd(PCD_RETURNVOID);
\r
876 TK_TokenMustBe(TK_RBRACE, ERR_INVALID_STATEMENT);
\r
879 sym->info.scriptFunc.predefined = NO;
\r
880 sym->info.scriptFunc.varCount = ScriptVarCount -
\r
881 sym->info.scriptFunc.argCount;
\r
882 PC_AddFunction(sym);
\r
883 UnspeculateFunction(sym);
\r
884 InsideFunction = NULL;
\r
887 //==========================================================================
\r
891 //==========================================================================
\r
893 static void OuterMapVar(boolean local)
\r
895 symbolNode_t *sym = NULL;
\r
898 MS_Message(MSG_DEBUG, "---- %s ----\n", local ? "LeadingStaticVarDeclare" : "OuterMapVar");
\r
901 if(pa_MapVarCount >= MAX_MAP_VARIABLES)
\r
903 ERR_Error(ERR_TOO_MANY_MAP_VARS, YES);
\r
904 index = MAX_MAP_VARIABLES;
\r
906 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
907 sym = local ? SY_FindLocal(tk_String)
\r
908 : SY_FindGlobal(tk_String);
\r
911 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);
\r
912 index = MAX_MAP_VARIABLES;
\r
916 sym = local ? SY_InsertLocal(tk_String, SY_MAPVAR)
\r
917 : SY_InsertGlobal(tk_String, SY_MAPVAR);
\r
918 if(ImportMode == IMPORT_Importing)
\r
920 sym->info.var.index = index = 0;
\r
924 sym->info.var.index = index = pa_MapVarCount;
\r
926 { // Local variables are not exported
\r
927 PC_NameMapVariable(index, sym);
\r
933 if(tk_Token == TK_ASSIGN)
\r
935 if(ImportMode != IMPORT_Importing)
\r
938 PC_PutMapVariable (index, EvalConstExpression());
\r
942 // When importing, skip the initializer, because we don't care.
\r
946 } while(tk_Token != TK_COMMA && tk_Token != TK_SEMICOLON);
\r
949 else if(tk_Token == TK_LBRACKET)
\r
953 int dims[MAX_ARRAY_DIMS];
\r
955 memset(dims, 0, sizeof(dims));
\r
957 while(tk_Token == TK_LBRACKET)
\r
959 if(ndim == MAX_ARRAY_DIMS)
\r
961 ERR_Error(ERR_TOO_MANY_ARRAY_DIMS, YES);
\r
965 } while(tk_Token != TK_COMMA && tk_Token != TK_SEMICOLON);
\r
969 if (tk_Token == TK_RBRACKET)
\r
971 ERR_Error(ERR_NEED_ARRAY_SIZE, YES);
\r
975 dims[ndim] = EvalConstExpression();
\r
976 if(dims[ndim] == 0)
\r
978 ERR_Error(ERR_ZERO_DIMENSION, YES);
\r
987 size *= dims[ndim];
\r
991 TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET);
\r
996 if(ImportMode != IMPORT_Importing)
\r
998 PC_AddArray(index, size);
\r
1000 MS_Message(MSG_DEBUG, "%s changed to an array of size %d\n", sym->name, size);
\r
1001 sym->type = SY_MAPARRAY;
\r
1002 sym->info.array.index = index;
\r
1003 sym->info.array.ndim = ndim;
\r
1004 sym->info.array.size = size;
\r
1007 sym->info.array.dimensions[ndim-1] = 1;
\r
1008 for(i = ndim - 2; i >= 0; --i)
\r
1010 sym->info.array.dimensions[i] =
\r
1011 sym->info.array.dimensions[i+1] * dims[i+1];
\r
1014 MS_Message(MSG_DEBUG, " - with multipliers ");
\r
1015 for(i = 0; i < ndim; ++i)
\r
1017 MS_Message(MSG_DEBUG, "[%d]", sym->info.array.dimensions[i]);
\r
1019 MS_Message(MSG_DEBUG, "\n");
\r
1020 if(tk_Token == TK_ASSIGN)
\r
1022 InitializeArray(sym, dims, size);
\r
1026 } while(tk_Token == TK_COMMA);
\r
1027 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1031 //==========================================================================
\r
1035 //==========================================================================
\r
1037 static void OuterWorldVar(boolean isGlobal)
\r
1040 symbolNode_t *sym;
\r
1042 MS_Message(MSG_DEBUG, "---- Outer%sVar ----\n", isGlobal ? "Global" : "World");
\r
1043 if(TK_NextToken() != TK_INT)
\r
1045 if(tk_Token != TK_BOOL)
\r
1047 TK_TokenMustBe(TK_STR, ERR_BAD_VAR_TYPE);
\r
1052 TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_WVAR_INDEX);
\r
1053 if(tk_Number >= (isGlobal ? MAX_GLOBAL_VARIABLES : MAX_WORLD_VARIABLES))
\r
1055 ERR_Error(ERR_BAD_WVAR_INDEX+isGlobal, YES);
\r
1060 index = tk_Number;
\r
1062 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_WVAR_COLON+isGlobal);
\r
1063 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
1064 if(SY_FindGlobal(tk_String) != NULL)
\r
1066 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);
\r
1071 if(tk_Token == TK_LBRACKET)
\r
1074 if(tk_Token != TK_RBRACKET)
\r
1076 ERR_Error(ERR_NO_NEED_ARRAY_SIZE, YES);
\r
1077 TK_SkipPast(TK_RBRACKET);
\r
1083 if(tk_Token == TK_LBRACKET)
\r
1085 ERR_Error(ERR_NO_MULTIDIMENSIONS, YES);
\r
1088 TK_SkipPast(TK_RBRACKET);
\r
1090 while(tk_Token == TK_LBRACKET);
\r
1092 sym = SY_InsertGlobal(tk_String, isGlobal ? SY_GLOBALARRAY : SY_WORLDARRAY);
\r
1093 sym->info.array.index = index;
\r
1094 sym->info.array.ndim = 1;
\r
1095 sym->info.array.size = 0x7fffffff; // not used
\r
1096 memset(sym->info.array.dimensions, 0, sizeof(sym->info.array.dimensions));
\r
1099 pa_GlobalArrayCount++;
\r
1101 pa_WorldArrayCount++;
\r
1105 sym = SY_InsertGlobal(tk_String, isGlobal ? SY_GLOBALVAR : SY_WORLDVAR);
\r
1106 sym->info.var.index = index;
\r
1108 pa_GlobalVarCount++;
\r
1110 pa_WorldVarCount++;
\r
1113 } while(tk_Token == TK_COMMA);
\r
1114 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1118 //==========================================================================
\r
1120 // OuterSpecialDef
\r
1122 //==========================================================================
\r
1124 static void OuterSpecialDef(void)
\r
1127 symbolNode_t *sym;
\r
1129 MS_Message(MSG_DEBUG, "---- OuterSpecialDef ----\n");
\r
1130 if(ImportMode == IMPORT_Importing)
\r
1132 // No need to process special definitions when importing.
\r
1133 TK_SkipPast(TK_SEMICOLON);
\r
1139 TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_VAL);
\r
1140 special = tk_Number;
\r
1141 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_SPEC_COLON);
\r
1142 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
1143 sym = SY_InsertGlobalUnique(tk_String, SY_SPECIAL);
\r
1144 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
1145 TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_ARGC);
\r
1146 sym->info.special.value = special;
\r
1147 sym->info.special.argCount = tk_Number | (tk_Number << 16);
\r
1149 if(tk_Token == TK_COMMA)
\r
1150 { // Get maximum arg count
\r
1151 TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_ARGC);
\r
1152 sym->info.special.argCount =
\r
1153 (sym->info.special.argCount & 0xffff) | (tk_Number << 16);
\r
1159 TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
1161 } while(tk_Token == TK_COMMA);
\r
1162 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1167 //==========================================================================
\r
1171 //==========================================================================
\r
1173 static void OuterDefine(boolean force)
\r
1176 symbolNode_t *sym;
\r
1178 MS_Message(MSG_DEBUG, "---- OuterDefine %s----\n",
\r
1179 force ? "(forced) " : "");
\r
1180 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
1181 sym = SY_InsertGlobalUnique(tk_String, SY_CONSTANT);
\r
1183 value = EvalConstExpression();
\r
1184 MS_Message(MSG_DEBUG, "Constant value: %d\n", value);
\r
1185 sym->info.constant.value = value;
\r
1186 // Defines inside an import are deleted when the import is popped.
\r
1187 if(ImportMode != IMPORT_Importing || force)
\r
1189 sym->info.constant.fileDepth = 0;
\r
1193 sym->info.constant.fileDepth = TK_GetDepth();
\r
1197 //==========================================================================
\r
1201 //==========================================================================
\r
1203 static void OuterInclude(void)
\r
1205 // Don't include inside an import
\r
1206 if(ImportMode != IMPORT_Importing)
\r
1208 MS_Message(MSG_DEBUG, "---- OuterInclude ----\n");
\r
1209 TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND);
\r
1210 TK_Include(tk_String);
\r
1219 //==========================================================================
\r
1223 //==========================================================================
\r
1225 static void OuterImport(void)
\r
1228 MS_Message(MSG_DEBUG, "---- OuterImport ----\n");
\r
1229 if(ImportMode == IMPORT_Importing)
\r
1231 // Don't import inside an import
\r
1236 MS_Message(MSG_DEBUG, "Importing a file\n");
\r
1237 TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND);
\r
1238 TK_Import(tk_String, ImportMode);
\r
1243 //==========================================================================
\r
1245 // ProcessStatement
\r
1247 //==========================================================================
\r
1249 static boolean ProcessStatement(statement_t owner)
\r
1251 if(StatementIndex == MAX_STATEMENT_DEPTH)
\r
1253 ERR_Exit(ERR_STATEMENT_OVERFLOW, YES);
\r
1255 StatementHistory[StatementIndex++] = owner;
\r
1262 LeadingVarDeclare();
\r
1264 case TK_LINESPECIAL:
\r
1265 LeadingLineSpecial(NO);
\r
1267 case TK_ACSEXECUTEWAIT:
\r
1268 tk_SpecialArgCount = 1 | (5<<16);
\r
1269 tk_SpecialValue = 80;
\r
1270 LeadingLineSpecial(YES);
\r
1278 case TK_TERMINATE:
\r
1279 LeadingTerminate();
\r
1284 case TK_IDENTIFIER:
\r
1285 LeadingIdentifier();
\r
1288 case TK_PRINTBOLD:
\r
1292 case TK_HUDMESSAGE:
\r
1293 case TK_HUDMESSAGEBOLD:
\r
1294 LeadingHudMessage();
\r
1304 LeadingWhileUntil();
\r
1313 if(owner != STMT_SWITCH)
\r
1315 ERR_Error(ERR_CASE_NOT_IN_SWITCH, YES);
\r
1316 TK_SkipPast(TK_COLON);
\r
1324 if(owner != STMT_SWITCH)
\r
1326 ERR_Error(ERR_DEFAULT_NOT_IN_SWITCH, YES);
\r
1327 TK_SkipPast(TK_COLON);
\r
1329 else if(DefaultInCurrent() == YES)
\r
1331 ERR_Error(ERR_MULTIPLE_DEFAULT, YES);
\r
1332 TK_SkipPast(TK_COLON);
\r
1340 if(BreakAncestor() == NO)
\r
1342 ERR_Error(ERR_MISPLACED_BREAK, YES);
\r
1343 TK_SkipPast(TK_SEMICOLON);
\r
1351 if(ContinueAncestor() == NO)
\r
1353 ERR_Error(ERR_MISPLACED_CONTINUE, YES);
\r
1354 TK_SkipPast(TK_SEMICOLON);
\r
1358 LeadingContinue();
\r
1361 case TK_CREATETRANSLATION:
\r
1362 LeadingCreateTranslation();
\r
1365 LeadingCompoundStatement(owner);
\r
1367 case TK_SEMICOLON:
\r
1372 LeadingIncDec(tk_Token);
\r
1383 //==========================================================================
\r
1385 // LeadingCompoundStatement
\r
1387 //==========================================================================
\r
1389 static void LeadingCompoundStatement(statement_t owner)
\r
1391 StatementLevel += AdjustStmtLevel[owner];
\r
1392 TK_NextToken(); // Eat the TK_LBRACE
\r
1393 do ; while(ProcessStatement(owner) == YES);
\r
1394 TK_TokenMustBe(TK_RBRACE, ERR_INVALID_STATEMENT);
\r
1396 StatementLevel -= AdjustStmtLevel[owner];
\r
1399 //==========================================================================
\r
1401 // LeadingVarDeclare
\r
1403 //==========================================================================
\r
1405 static void LeadingVarDeclare(void)
\r
1407 symbolNode_t *sym = NULL;
\r
1409 if(tk_Token == TK_STATIC)
\r
1412 if(tk_Token != TK_INT && tk_Token != TK_STR && tk_Token != TK_BOOL)
\r
1414 ERR_Error(ERR_BAD_VAR_TYPE, YES);
\r
1421 MS_Message(MSG_DEBUG, "---- LeadingVarDeclare ----\n");
\r
1424 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
1426 if(ScriptVarCount == MAX_SCRIPT_VARIABLES)
\r
1428 ERR_Error(InsideFunction
\r
1429 ? ERR_TOO_MANY_FUNCTION_VARS
\r
1430 : ERR_TOO_MANY_SCRIPT_VARS,
\r
1436 if(SY_FindLocal(tk_String) != NULL)
\r
1438 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);
\r
1442 sym = SY_InsertLocal(tk_String, SY_SCRIPTVAR);
\r
1443 sym->info.var.index = ScriptVarCount;
\r
1447 if(tk_Token == TK_LBRACKET)
\r
1449 ERR_Error(ERR_ARRAY_MAPVAR_ONLY, YES);
\r
1450 do ; while(TK_NextToken() != TK_COMMA && tk_Token != TK_SEMICOLON);
\r
1452 else if(tk_Token == TK_ASSIGN)
\r
1458 PC_AppendCmd(PCD_ASSIGNSCRIPTVAR);
\r
1459 PC_AppendShrink(sym->info.var.index);
\r
1462 } while(tk_Token == TK_COMMA);
\r
1463 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1467 //==========================================================================
\r
1469 // LeadingLineSpecial
\r
1471 //==========================================================================
\r
1473 static void LeadingLineSpecial(boolean executewait)
\r
1480 U_BYTE specialValue;
\r
1483 MS_Message(MSG_DEBUG, "---- LeadingLineSpecial ----\n");
\r
1484 argCountMin = tk_SpecialArgCount & 0xffff;
\r
1485 argCountMax = tk_SpecialArgCount >> 16;
\r
1486 specialValue = tk_SpecialValue;
\r
1487 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
1489 if(argCountMax > 0)
\r
1491 if(TK_NextToken() == TK_CONST)
\r
1493 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
1503 if(i == argCountMax)
\r
1505 ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES);
\r
1506 i = argCountMax+1;
\r
1511 argSave[i] = EvalConstExpression();
\r
1516 if (i == 0 && executewait)
\r
1518 PC_AppendCmd(PCD_DUP);
\r
1521 if(i < argCountMax)
\r
1525 } while(tk_Token == TK_COMMA);
\r
1526 if(i < argCountMin)
\r
1528 ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES);
\r
1529 TK_SkipPast(TK_SEMICOLON);
\r
1536 // [RH] I added some zero-argument specials without realizing that
\r
1537 // ACS won't allow for less than one, so fake them as one-argument
\r
1538 // specials with a parameter of 0.
\r
1544 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
1545 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1548 PC_AppendCmd(PCD_LSPEC1+(argCount-1));
\r
1551 PC_AppendLong(specialValue);
\r
1555 PC_AppendByte(specialValue);
\r
1559 PC_AppendCmd(PCD_SCRIPTWAIT);
\r
1564 boolean uselongform;
\r
1568 PC_AppendCmd(PCD_LSPEC1DIRECT+(argCount-1));
\r
1569 PC_AppendLong(specialValue);
\r
1570 uselongform = YES;
\r
1575 for (i = 0; i < argCount; i++)
\r
1577 if ((unsigned int)argSave[i] > 255)
\r
1579 uselongform = YES;
\r
1583 PC_AppendCmd((argCount-1)+(uselongform?PCD_LSPEC1DIRECT:PCD_LSPEC1DIRECTB));
\r
1584 PC_AppendByte(specialValue);
\r
1588 for (i = 0; i < argCount; i++)
\r
1590 PC_AppendLong(argSave[i]);
\r
1595 for (i = 0; i < argCount; i++)
\r
1597 PC_AppendByte((U_BYTE)argSave[i]);
\r
1602 PC_AppendCmd(PCD_SCRIPTWAITDIRECT);
\r
1603 PC_AppendLong(argSave[0]);
\r
1609 //==========================================================================
\r
1611 // LeadingIdentifier
\r
1613 //==========================================================================
\r
1615 static void LeadingIdentifier(void)
\r
1617 symbolNode_t *sym;
\r
1619 sym = SpeculateSymbol(tk_String, NO);
\r
1623 case SY_SCRIPTVAR:
\r
1624 case SY_SCRIPTALIAS:
\r
1627 case SY_GLOBALVAR:
\r
1628 case SY_WORLDARRAY:
\r
1629 case SY_GLOBALARRAY:
\r
1630 LeadingVarAssign(sym);
\r
1632 case SY_INTERNFUNC:
\r
1633 LeadingInternFunc(sym);
\r
1635 case SY_SCRIPTFUNC:
\r
1636 LeadingScriptFunc(sym);
\r
1643 //==========================================================================
\r
1645 // LeadingInternFunc
\r
1647 //==========================================================================
\r
1649 static void LeadingInternFunc(symbolNode_t *sym)
\r
1651 if(InsideFunction && sym->info.internFunc.latent)
\r
1653 ERR_Error(ERR_LATENT_IN_FUNC, YES);
\r
1655 ProcessInternFunc(sym);
\r
1656 if(sym->info.internFunc.hasReturnValue == YES)
\r
1658 PC_AppendCmd(PCD_DROP);
\r
1660 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1664 //==========================================================================
\r
1666 // ProcessInternFunc
\r
1668 //==========================================================================
\r
1670 static void ProcessInternFunc(symbolNode_t *sym)
\r
1677 boolean specialDirect;
\r
1680 MS_Message(MSG_DEBUG, "---- ProcessInternFunc ----\n");
\r
1681 argCount = sym->info.internFunc.argCount;
\r
1682 optMask = sym->info.internFunc.optMask;
\r
1683 outMask = sym->info.internFunc.outMask;
\r
1684 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
1685 if(TK_NextToken() == TK_CONST)
\r
1687 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
1688 if(sym->info.internFunc.directCommand == PCD_NOP)
\r
1690 ERR_Error(ERR_NO_DIRECT_VER, YES, NULL);
\r
1692 specialDirect = NO;
\r
1697 if (pc_NoShrink || argCount > 2 ||
\r
1698 (sym->info.internFunc.directCommand != PCD_DELAYDIRECT &&
\r
1699 sym->info.internFunc.directCommand != PCD_RANDOMDIRECT))
\r
1701 specialDirect = NO;
\r
1702 PC_AppendCmd(sym->info.internFunc.directCommand);
\r
1706 specialDirect = YES;
\r
1714 specialDirect = NO; // keep GCC quiet
\r
1719 if(tk_Token == TK_RPAREN)
\r
1721 ERR_Error(ERR_MISSING_PARAM, YES);
\r
1725 TK_Undo(); // Adjust for first expression
\r
1730 ERR_Error(ERR_BAD_ARG_COUNT, YES);
\r
1731 TK_SkipTo(TK_SEMICOLON);
\r
1738 if (tk_Token != TK_COMMA)
\r
1740 if (specialDirect)
\r
1742 argSave[i] = EvalConstExpression();
\r
1746 PC_AppendLong(EvalConstExpression());
\r
1753 if (specialDirect)
\r
1764 ERR_Error(ERR_MISSING_PARAM, YES);
\r
1770 if (tk_Token != TK_COMMA)
\r
1772 if (!(outMask & 1))
\r
1776 else if (tk_Token != TK_IDENTIFIER)
\r
1778 ERR_Error (ERR_PARM_MUST_BE_VAR, YES);
\r
1782 } while (tk_Token != TK_COMMA && tk_Token != TK_RPAREN);
\r
1786 symbolNode_t *sym = DemandSymbol (tk_String);
\r
1787 PC_AppendCmd (PCD_PUSHNUMBER);
\r
1788 switch (sym->type)
\r
1790 case SY_SCRIPTVAR:
\r
1791 PC_AppendLong(sym->info.var.index | OUTVAR_SCRIPT_SPEC);
\r
1794 PC_AppendLong(sym->info.var.index | OUTVAR_MAP_SPEC);
\r
1797 PC_AppendLong(sym->info.var.index | OUTVAR_WORLD_SPEC);
\r
1799 case SY_GLOBALVAR:
\r
1800 PC_AppendLong(sym->info.var.index | OUTVAR_GLOBAL_SPEC);
\r
1803 ERR_Error (ERR_PARM_MUST_BE_VAR, YES);
\r
1807 } while (tk_Token != TK_COMMA && tk_Token != TK_RPAREN);
\r
1817 PC_AppendPushVal(0);
\r
1821 ERR_Error(ERR_MISSING_PARAM, YES);
\r
1828 } while(tk_Token == TK_COMMA);
\r
1831 while (i < argCount && (optMask & 1))
\r
1833 if (direct == YES)
\r
1835 if (specialDirect)
\r
1846 PC_AppendPushVal(0);
\r
1851 if(i != argCount && i > 0)
\r
1853 ERR_Error(ERR_BAD_ARG_COUNT, YES);
\r
1855 TK_TokenMustBe(TK_RPAREN, argCount > 0 ? ERR_MISSING_RPAREN : ERR_BAD_ARG_COUNT);
\r
1858 PC_AppendCmd(sym->info.internFunc.stackCommand);
\r
1860 else if (specialDirect)
\r
1862 boolean uselongform = NO;
\r
1865 switch (sym->info.internFunc.directCommand)
\r
1867 case PCD_DELAYDIRECT:
\r
1868 shortpcd = PCD_DELAYDIRECTB;
\r
1870 case PCD_RANDOMDIRECT:
\r
1871 shortpcd = PCD_RANDOMDIRECTB;
\r
1874 uselongform = YES;
\r
1875 shortpcd = PCD_NOP;
\r
1881 for (i = 0; i < argCount; i++)
\r
1883 if ((unsigned int)argSave[i] > 255)
\r
1885 uselongform = YES;
\r
1893 PC_AppendCmd(sym->info.internFunc.directCommand);
\r
1894 for (i = 0; i < argCount; i++)
\r
1896 PC_AppendLong (argSave[i]);
\r
1901 PC_AppendCmd (shortpcd);
\r
1902 for (i = 0; i < argCount; i++)
\r
1904 PC_AppendByte ((U_BYTE)argSave[i]);
\r
1911 //==========================================================================
\r
1913 // LeadingScriptFunc
\r
1915 //==========================================================================
\r
1917 static void LeadingScriptFunc(symbolNode_t *sym)
\r
1919 ProcessScriptFunc(sym, YES);
\r
1920 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1925 //==========================================================================
\r
1927 // ProcessScriptFunc
\r
1929 //==========================================================================
\r
1931 static void ProcessScriptFunc(symbolNode_t *sym, boolean discardReturn)
\r
1936 MS_Message(MSG_DEBUG, "---- ProcessScriptFunc ----\n");
\r
1937 argCount = sym->info.scriptFunc.argCount;
\r
1938 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
1942 TK_NextTokenMustBe(TK_RPAREN, ERR_BAD_ARG_COUNT);
\r
1944 else if(argCount > 0)
\r
1947 if(tk_Token == TK_RPAREN)
\r
1949 ERR_Error(ERR_BAD_ARG_COUNT, YES);
\r
1950 TK_SkipTo(TK_SEMICOLON);
\r
1958 ERR_Error(ERR_BAD_ARG_COUNT, YES);
\r
1959 TK_SkipTo(TK_SEMICOLON);
\r
1963 if (tk_Token != TK_COMMA)
\r
1969 ERR_Error(ERR_MISSING_PARAM, YES);
\r
1970 TK_SkipTo(TK_SEMICOLON);
\r
1974 } while(tk_Token == TK_COMMA);
\r
1977 { // Function has not been defined yet, so assume arg count is correct
\r
1979 while (tk_Token != TK_RPAREN)
\r
1983 if (tk_Token == TK_COMMA)
\r
1987 else if (tk_Token != TK_RPAREN)
\r
1989 ERR_Error(ERR_MISSING_PARAM, YES);
\r
1990 TK_SkipTo(TK_SEMICOLON);
\r
1995 else if(i != argCount)
\r
1997 ERR_Error(ERR_BAD_ARG_COUNT, YES);
\r
1998 TK_SkipTo(TK_SEMICOLON);
\r
2001 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2002 PC_AppendCmd(discardReturn ? PCD_CALLDISCARD : PCD_CALL);
\r
2003 if(sym->info.scriptFunc.predefined && ImportMode != IMPORT_Importing)
\r
2005 AddScriptFuncRef(sym, pc_Address, i);
\r
2009 PC_AppendLong(sym->info.scriptFunc.funcNumber);
\r
2013 PC_AppendByte((U_BYTE)sym->info.scriptFunc.funcNumber);
\r
2018 //==========================================================================
\r
2020 // BuildPrintString
\r
2022 //==========================================================================
\r
2024 static void BuildPrintString(void)
\r
2030 switch(TK_NextCharacter())
\r
2032 case 'a': // character array support [JB]
\r
2035 case 's': // string
\r
2036 printCmd = PCD_PRINTSTRING;
\r
2038 case 'l': // [RH] localized string
\r
2039 printCmd = PCD_PRINTLOCALIZED;
\r
2041 case 'i': // integer
\r
2042 case 'd': // decimal
\r
2043 printCmd = PCD_PRINTNUMBER;
\r
2045 case 'c': // character
\r
2046 printCmd = PCD_PRINTCHARACTER;
\r
2048 case 'n': // [BC] name
\r
2049 printCmd = PCD_PRINTNAME;
\r
2051 case 'f': // [RH] fixed point
\r
2052 printCmd = PCD_PRINTFIXED;
\r
2054 case 'k': // [GRB] key binding
\r
2055 printCmd = PCD_PRINTBIND;
\r
2058 printCmd = PCD_PRINTSTRING;
\r
2059 ERR_Error(ERR_UNKNOWN_PRTYPE, YES);
\r
2062 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2065 PC_AppendCmd(printCmd);
\r
2066 } while(tk_Token == TK_COMMA);
\r
2069 //==========================================================================
\r
2071 // PrintCharArray // JB
\r
2073 //==========================================================================
\r
2075 static void PrintCharArray(void)
\r
2077 symbolNode_t *sym;
\r
2078 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2080 sym = SpeculateSymbol(tk_String, NO);
\r
2081 if((sym->type != SY_MAPARRAY) && (sym->type != SY_WORLDARRAY)
\r
2082 && (sym->type != SY_GLOBALARRAY))
\r
2084 ERR_Error(ERR_NOT_AN_ARRAY, YES);
\r
2087 if(sym->info.array.ndim > 1)
\r
2089 ParseArrayIndices(sym, sym->info.array.ndim-1);
\r
2093 PC_AppendPushVal(0);
\r
2096 PC_AppendPushVal(sym->info.array.index);
\r
2097 if(sym->type == SY_MAPARRAY)
\r
2099 PC_AppendCmd(PCD_PRINTMAPCHARARRAY);
\r
2101 else if(sym->type == SY_WORLDARRAY)
\r
2103 PC_AppendCmd(PCD_PRINTWORLDCHARARRAY);
\r
2105 else // if(sym->type == SY_GLOBALARRAY)
\r
2107 PC_AppendCmd(PCD_PRINTGLOBALCHARARRAY);
\r
2111 //==========================================================================
\r
2115 //==========================================================================
\r
2117 static void LeadingPrint(void)
\r
2119 tokenType_t stmtToken;
\r
2121 MS_Message(MSG_DEBUG, "---- LeadingPrint ----\n");
\r
2122 stmtToken = tk_Token; // Will be TK_PRINT or TK_PRINTBOLD or TK_LOG
\r
2123 PC_AppendCmd(PCD_BEGINPRINT);
\r
2124 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2125 BuildPrintString();
\r
2126 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2127 if(stmtToken == TK_PRINT)
\r
2129 PC_AppendCmd(PCD_ENDPRINT);
\r
2131 else if(stmtToken == TK_PRINTBOLD)
\r
2133 PC_AppendCmd(PCD_ENDPRINTBOLD);
\r
2137 PC_AppendCmd(PCD_ENDLOG);
\r
2139 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2143 //==========================================================================
\r
2145 // LeadingHudMessage
\r
2147 // hudmessage(str text; int type, int id, int color, fixed x, fixed y, fixed holdtime, ...)
\r
2149 //==========================================================================
\r
2151 static void LeadingHudMessage(void)
\r
2153 tokenType_t stmtToken;
\r
2156 MS_Message(MSG_DEBUG, "---- LeadingHudMessage ----\n");
\r
2157 stmtToken = tk_Token; // Will be TK_HUDMESSAGE or TK_HUDMESSAGEBOLD
\r
2158 PC_AppendCmd(PCD_BEGINPRINT);
\r
2159 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2160 BuildPrintString();
\r
2161 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_PARAM);
\r
2162 PC_AppendCmd(PCD_MOREHUDMESSAGE);
\r
2163 for (i = 6; i > 0; i--)
\r
2168 TK_TokenMustBe(TK_COMMA, ERR_MISSING_PARAM);
\r
2170 if (tk_Token == TK_COMMA)
\r
2171 { // HUD message has optional parameters
\r
2172 PC_AppendCmd(PCD_OPTHUDMESSAGE);
\r
2177 } while (tk_Token == TK_COMMA);
\r
2179 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2180 PC_AppendCmd(stmtToken == TK_HUDMESSAGE ?
\r
2181 PCD_ENDHUDMESSAGE : PCD_ENDHUDMESSAGEBOLD);
\r
2182 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2186 //==========================================================================
\r
2188 // LeadingCreateTranslation
\r
2190 // Simple grammar:
\r
2192 // tranlationstmt: CreateTranslation ( exp opt_args ) ;
\r
2193 // opt_args: /* empty: just reset the translation */ | , arglist
\r
2194 // arglist: arg | arglist arg
\r
2195 // arg: range = replacement
\r
2196 // range: exp : exp
\r
2197 // replacement: palrep | colorrep
\r
2198 // palrep: exp : exp
\r
2199 // colorrep: [exp,exp,exp]:[exp,exp,exp]
\r
2200 //==========================================================================
\r
2202 static void LeadingCreateTranslation(void)
\r
2204 MS_Message(MSG_DEBUG, "---- LeadingCreateTranslation ----\n");
\r
2205 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2208 PC_AppendCmd(PCD_STARTTRANSLATION);
\r
2209 while (tk_Token == TK_COMMA)
\r
2212 EvalExpression(); // Get first palette entry in range
\r
2213 TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2215 EvalExpression(); // Get second palette entry in range
\r
2216 TK_TokenMustBe(TK_ASSIGN, ERR_MISSING_ASSIGN);
\r
2219 if(tk_Token == TK_LBRACKET)
\r
2220 { // Replacement is color range
\r
2225 for(j = 2; j != 0; --j)
\r
2227 for(i = 3; i != 0; --i)
\r
2232 TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA);
\r
2236 TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET);
\r
2242 TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2243 TK_NextTokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET);
\r
2247 PC_AppendCmd(PCD_TRANSLATIONRANGE2);
\r
2250 { // Replacement is palette range
\r
2252 TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2255 PC_AppendCmd(PCD_TRANSLATIONRANGE1);
\r
2258 PC_AppendCmd(PCD_ENDTRANSLATION);
\r
2259 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2260 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2264 //==========================================================================
\r
2268 //==========================================================================
\r
2270 static void LeadingIf(void)
\r
2275 MS_Message(MSG_DEBUG, "---- LeadingIf ----\n");
\r
2276 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2279 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2280 PC_AppendCmd(PCD_IFNOTGOTO);
\r
2281 jumpAddrPtr1 = pc_Address;
\r
2284 if(ProcessStatement(STMT_IF) == NO)
\r
2286 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
2288 if(tk_Token == TK_ELSE)
\r
2290 PC_AppendCmd(PCD_GOTO);
\r
2291 jumpAddrPtr2 = pc_Address;
\r
2293 PC_WriteLong(pc_Address, jumpAddrPtr1);
\r
2295 if(ProcessStatement(STMT_ELSE) == NO)
\r
2297 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
2299 PC_WriteLong(pc_Address, jumpAddrPtr2);
\r
2303 PC_WriteLong(pc_Address, jumpAddrPtr1);
\r
2307 //==========================================================================
\r
2311 //==========================================================================
\r
2313 static void LeadingFor(void)
\r
2320 MS_Message(MSG_DEBUG, "---- LeadingFor ----\n");
\r
2321 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2323 if(ProcessStatement(STMT_FOR) == NO)
\r
2325 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
2327 exprAddr = pc_Address;
\r
2329 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2331 PC_AppendCmd(PCD_IFGOTO);
\r
2332 ifgotoAddr = pc_Address;
\r
2334 PC_AppendCmd(PCD_GOTO);
\r
2335 gotoAddr = pc_Address;
\r
2337 incAddr = pc_Address;
\r
2338 forSemicolonHack = TRUE;
\r
2339 if(ProcessStatement(STMT_FOR) == NO)
\r
2341 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
2343 forSemicolonHack = FALSE;
\r
2344 PC_AppendCmd(PCD_GOTO);
\r
2345 PC_AppendLong(exprAddr);
\r
2346 PC_WriteLong(pc_Address,ifgotoAddr);
\r
2347 if(ProcessStatement(STMT_FOR) == NO)
\r
2349 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
2351 PC_AppendCmd(PCD_GOTO);
\r
2352 PC_AppendLong(incAddr);
\r
2353 WriteContinues(incAddr);
\r
2355 PC_WriteLong(pc_Address,gotoAddr);
\r
2358 //==========================================================================
\r
2360 // LeadingWhileUntil
\r
2362 //==========================================================================
\r
2364 static void LeadingWhileUntil(void)
\r
2366 tokenType_t stmtToken;
\r
2370 MS_Message(MSG_DEBUG, "---- LeadingWhileUntil ----\n");
\r
2371 stmtToken = tk_Token;
\r
2372 topAddr = pc_Address;
\r
2373 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2376 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2377 PC_AppendCmd(stmtToken == TK_WHILE ? PCD_IFNOTGOTO : PCD_IFGOTO);
\r
2378 outAddrPtr = pc_Address;
\r
2381 if(ProcessStatement(STMT_WHILEUNTIL) == NO)
\r
2383 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
2385 PC_AppendCmd(PCD_GOTO);
\r
2386 PC_AppendLong(topAddr);
\r
2388 PC_WriteLong(pc_Address, outAddrPtr);
\r
2390 WriteContinues(topAddr);
\r
2394 //==========================================================================
\r
2398 //==========================================================================
\r
2400 static void LeadingDo(void)
\r
2404 tokenType_t stmtToken;
\r
2406 MS_Message(MSG_DEBUG, "---- LeadingDo ----\n");
\r
2407 topAddr = pc_Address;
\r
2409 if(ProcessStatement(STMT_DO) == NO)
\r
2411 ERR_Error(ERR_INVALID_STATEMENT, YES, NULL);
\r
2413 if(tk_Token != TK_WHILE && tk_Token != TK_UNTIL)
\r
2415 ERR_Error(ERR_BAD_DO_STATEMENT, YES, NULL);
\r
2416 TK_SkipPast(TK_SEMICOLON);
\r
2419 stmtToken = tk_Token;
\r
2420 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2421 exprAddr = pc_Address;
\r
2424 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2425 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2426 PC_AppendCmd(stmtToken == TK_WHILE ? PCD_IFGOTO : PCD_IFNOTGOTO);
\r
2427 PC_AppendLong(topAddr);
\r
2428 WriteContinues(exprAddr);
\r
2433 //==========================================================================
\r
2437 //==========================================================================
\r
2439 static void LeadingSwitch(void)
\r
2441 int switcherAddrPtr;
\r
2443 caseInfo_t *cInfo;
\r
2444 int defaultAddress;
\r
2446 MS_Message(MSG_DEBUG, "---- LeadingSwitch ----\n");
\r
2448 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2451 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2453 PC_AppendCmd(PCD_GOTO);
\r
2454 switcherAddrPtr = pc_Address;
\r
2458 if(ProcessStatement(STMT_SWITCH) == NO)
\r
2460 ERR_Error(ERR_INVALID_STATEMENT, YES, NULL);
\r
2463 PC_AppendCmd(PCD_GOTO);
\r
2464 outAddrPtr = pc_Address;
\r
2467 PC_WriteLong(pc_Address, switcherAddrPtr);
\r
2468 defaultAddress = 0;
\r
2472 while((cInfo = GetCaseInfo()) != NULL)
\r
2474 if(cInfo->isDefault == YES)
\r
2476 defaultAddress = cInfo->address;
\r
2479 PC_AppendCmd(PCD_CASEGOTO);
\r
2480 PC_AppendLong(cInfo->value);
\r
2481 PC_AppendLong(cInfo->address);
\r
2484 else if(CaseIndex != 0)
\r
2486 caseInfo_t *maxCase = &CaseInfo[CaseIndex];
\r
2487 caseInfo_t *minCase = maxCase;
\r
2489 // [RH] Sort cases so that the VM can handle them with
\r
2490 // a quick binary search.
\r
2491 while((cInfo = GetCaseInfo()) != NULL)
\r
2495 qsort(minCase, maxCase - minCase, sizeof(caseInfo_t), CaseInfoCmp);
\r
2496 if(minCase->isDefault == YES)
\r
2498 defaultAddress = minCase->address;
\r
2501 if (minCase < maxCase)
\r
2503 PC_AppendCmd(PCD_CASEGOTOSORTED);
\r
2504 if(pc_Address%4 != 0)
\r
2505 { // Align to a 4-byte boundary
\r
2507 PC_Append((void *)&pad, 4-(pc_Address%4));
\r
2509 PC_AppendLong(maxCase - minCase);
\r
2510 for(; minCase < maxCase; ++minCase)
\r
2512 PC_AppendLong(minCase->value);
\r
2513 PC_AppendLong(minCase->address);
\r
2517 PC_AppendCmd(PCD_DROP);
\r
2519 if(defaultAddress != 0)
\r
2521 PC_AppendCmd(PCD_GOTO);
\r
2522 PC_AppendLong(defaultAddress);
\r
2525 PC_WriteLong(pc_Address, outAddrPtr);
\r
2530 //==========================================================================
\r
2534 //==========================================================================
\r
2536 static void LeadingCase(void)
\r
2538 MS_Message(MSG_DEBUG, "---- LeadingCase ----\n");
\r
2540 PushCase(EvalConstExpression(), NO);
\r
2541 TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2545 //==========================================================================
\r
2549 //==========================================================================
\r
2551 static void LeadingDefault(void)
\r
2553 MS_Message(MSG_DEBUG, "---- LeadingDefault ----\n");
\r
2554 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2559 //==========================================================================
\r
2563 //==========================================================================
\r
2565 static void PushCase(int value, boolean isDefault)
\r
2567 if(CaseIndex == MAX_CASE)
\r
2569 ERR_Exit(ERR_CASE_OVERFLOW, YES);
\r
2571 CaseInfo[CaseIndex].level = StatementLevel;
\r
2572 CaseInfo[CaseIndex].value = value;
\r
2573 CaseInfo[CaseIndex].isDefault = isDefault;
\r
2574 CaseInfo[CaseIndex].address = pc_Address;
\r
2578 //==========================================================================
\r
2582 //==========================================================================
\r
2584 static caseInfo_t *GetCaseInfo(void)
\r
2586 if(CaseIndex == 0)
\r
2590 if(CaseInfo[CaseIndex-1].level > StatementLevel)
\r
2592 return &CaseInfo[--CaseIndex];
\r
2597 //==========================================================================
\r
2601 //==========================================================================
\r
2603 static int CaseInfoCmp (const void *a, const void *b)
\r
2605 const caseInfo_t *ca = (const caseInfo_t *)a;
\r
2606 const caseInfo_t *cb = (const caseInfo_t *)b;
\r
2608 // The default case always gets moved to the front.
\r
2617 return ca->value - cb->value;
\r
2620 //==========================================================================
\r
2622 // DefaultInCurrent
\r
2624 //==========================================================================
\r
2626 static boolean DefaultInCurrent(void)
\r
2630 for(i = 0; i < CaseIndex; i++)
\r
2632 if(CaseInfo[i].isDefault == YES
\r
2633 && CaseInfo[i].level == StatementLevel)
\r
2641 //==========================================================================
\r
2645 //==========================================================================
\r
2647 static void LeadingBreak(void)
\r
2649 MS_Message(MSG_DEBUG, "---- LeadingBreak ----\n");
\r
2650 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2651 PC_AppendCmd(PCD_GOTO);
\r
2657 //==========================================================================
\r
2661 //==========================================================================
\r
2663 static void PushBreak(void)
\r
2665 if(BreakIndex == MAX_CASE)
\r
2667 ERR_Exit(ERR_BREAK_OVERFLOW, YES);
\r
2669 BreakInfo[BreakIndex].level = StatementLevel;
\r
2670 BreakInfo[BreakIndex].addressPtr = pc_Address;
\r
2674 //==========================================================================
\r
2678 //==========================================================================
\r
2680 static void WriteBreaks(void)
\r
2682 while(BreakIndex && BreakInfo[BreakIndex-1].level > StatementLevel)
\r
2684 PC_WriteLong(pc_Address, BreakInfo[--BreakIndex].addressPtr);
\r
2688 //==========================================================================
\r
2692 // Returns YES if the current statement history contains a break root
\r
2695 //==========================================================================
\r
2697 static boolean BreakAncestor(void)
\r
2701 for(i = 0; i < StatementIndex; i++)
\r
2703 if(IsBreakRoot[StatementHistory[i]])
\r
2711 //==========================================================================
\r
2713 // LeadingContinue
\r
2715 //==========================================================================
\r
2717 static void LeadingContinue(void)
\r
2719 MS_Message(MSG_DEBUG, "---- LeadingContinue ----\n");
\r
2720 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2721 PC_AppendCmd(PCD_GOTO);
\r
2727 //==========================================================================
\r
2731 //==========================================================================
\r
2733 static void PushContinue(void)
\r
2735 if(ContinueIndex == MAX_CONTINUE)
\r
2737 ERR_Exit(ERR_CONTINUE_OVERFLOW, YES);
\r
2739 ContinueInfo[ContinueIndex].level = StatementLevel;
\r
2740 ContinueInfo[ContinueIndex].addressPtr = pc_Address;
\r
2744 //==========================================================================
\r
2748 //==========================================================================
\r
2750 static void WriteContinues(int address)
\r
2752 if(ContinueIndex == 0)
\r
2756 while(ContinueInfo[ContinueIndex-1].level > StatementLevel)
\r
2758 PC_WriteLong(address, ContinueInfo[--ContinueIndex].addressPtr);
\r
2762 //==========================================================================
\r
2764 // ContinueAncestor
\r
2766 //==========================================================================
\r
2768 static boolean ContinueAncestor(void)
\r
2772 for(i = 0; i < StatementIndex; i++)
\r
2774 if(IsContinueRoot[StatementHistory[i]])
\r
2782 //==========================================================================
\r
2786 //==========================================================================
\r
2788 static void LeadingIncDec(int token)
\r
2790 symbolNode_t *sym;
\r
2792 MS_Message(MSG_DEBUG, "---- LeadingIncDec ----\n");
\r
2793 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INCDEC_OP_ON_NON_VAR);
\r
2794 sym = DemandSymbol(tk_String);
\r
2795 if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR
\r
2796 && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR
\r
2797 && sym->type != SY_MAPARRAY && sym->type != SY_GLOBALARRAY
\r
2798 && sym->type != SY_WORLDARRAY && sym->type != SY_SCRIPTALIAS)
\r
2800 ERR_Error(ERR_INCDEC_OP_ON_NON_VAR, YES);
\r
2801 TK_SkipPast(TK_SEMICOLON);
\r
2805 if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY
\r
2806 || sym->type == SY_GLOBALARRAY)
\r
2808 ParseArrayIndices(sym, sym->info.array.ndim);
\r
2810 else if(tk_Token == TK_LBRACKET)
\r
2812 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);
\r
2813 while(tk_Token == TK_LBRACKET)
\r
2815 TK_SkipPast(TK_RBRACKET);
\r
2818 PC_AppendCmd(GetIncDecPCD(token, sym->type));
\r
2819 PC_AppendShrink(sym->info.var.index);
\r
2820 if(forSemicolonHack)
\r
2822 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2826 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2831 //==========================================================================
\r
2833 // LeadingVarAssign
\r
2835 //==========================================================================
\r
2837 static void LeadingVarAssign(symbolNode_t *sym)
\r
2840 tokenType_t assignToken;
\r
2842 MS_Message(MSG_DEBUG, "---- LeadingVarAssign ----\n");
\r
2846 TK_NextToken(); // Fetch assignment operator
\r
2847 if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY
\r
2848 || sym->type == SY_GLOBALARRAY)
\r
2850 ParseArrayIndices(sym, sym->info.array.ndim);
\r
2852 else if(tk_Token == TK_LBRACKET)
\r
2854 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);
\r
2855 while(tk_Token == TK_LBRACKET)
\r
2857 TK_SkipPast(TK_RBRACKET);
\r
2860 if(tk_Token == TK_INC || tk_Token == TK_DEC)
\r
2861 { // Postfix increment or decrement
\r
2862 PC_AppendCmd(GetIncDecPCD(tk_Token, sym->type));
\r
2865 PC_AppendLong(sym->info.var.index);
\r
2869 PC_AppendByte(sym->info.var.index);
\r
2874 { // Normal operator
\r
2875 if(TK_Member(AssignOps) == NO)
\r
2877 ERR_Error(ERR_MISSING_ASSIGN_OP, YES);
\r
2878 TK_SkipPast(TK_SEMICOLON);
\r
2881 assignToken = tk_Token;
\r
2884 PC_AppendCmd(GetAssignPCD(assignToken, sym->type));
\r
2885 PC_AppendShrink(sym->info.var.index);
\r
2887 if(tk_Token == TK_COMMA)
\r
2889 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_BAD_ASSIGNMENT);
\r
2890 sym = DemandSymbol(tk_String);
\r
2891 if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR
\r
2892 && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR
\r
2893 && sym->type != SY_WORLDARRAY && sym->type != SY_GLOBALARRAY
\r
2894 && sym->type != SY_SCRIPTALIAS)
\r
2896 ERR_Error(ERR_BAD_ASSIGNMENT, YES);
\r
2897 TK_SkipPast(TK_SEMICOLON);
\r
2903 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2907 } while(done == NO);
\r
2910 //==========================================================================
\r
2914 //==========================================================================
\r
2916 static pcd_t GetAssignPCD(tokenType_t token, symbolType_t symbol)
\r
2919 static tokenType_t tokenLookup[] =
\r
2921 TK_ASSIGN, TK_ADDASSIGN, TK_SUBASSIGN,
\r
2922 TK_MULASSIGN, TK_DIVASSIGN, TK_MODASSIGN,
\r
2923 TK_ANDASSIGN, TK_EORASSIGN, TK_ORASSIGN,
\r
2924 TK_LSASSIGN, TK_RSASSIGN
\r
2926 static symbolType_t symbolLookup[] =
\r
2928 SY_SCRIPTVAR, SY_MAPVAR, SY_WORLDVAR, SY_GLOBALVAR, SY_MAPARRAY,
\r
2929 SY_WORLDARRAY, SY_GLOBALARRAY
\r
2931 static pcd_t assignmentLookup[11][7] =
\r
2933 { PCD_ASSIGNSCRIPTVAR, PCD_ASSIGNMAPVAR, PCD_ASSIGNWORLDVAR, PCD_ASSIGNGLOBALVAR, PCD_ASSIGNMAPARRAY, PCD_ASSIGNWORLDARRAY, PCD_ASSIGNGLOBALARRAY },
\r
2934 { PCD_ADDSCRIPTVAR, PCD_ADDMAPVAR, PCD_ADDWORLDVAR, PCD_ADDGLOBALVAR, PCD_ADDMAPARRAY, PCD_ADDWORLDARRAY, PCD_ADDGLOBALARRAY },
\r
2935 { PCD_SUBSCRIPTVAR, PCD_SUBMAPVAR, PCD_SUBWORLDVAR, PCD_SUBGLOBALVAR, PCD_SUBMAPARRAY, PCD_SUBWORLDARRAY, PCD_SUBGLOBALARRAY },
\r
2936 { PCD_MULSCRIPTVAR, PCD_MULMAPVAR, PCD_MULWORLDVAR, PCD_MULGLOBALVAR, PCD_MULMAPARRAY, PCD_MULWORLDARRAY, PCD_MULGLOBALARRAY },
\r
2937 { PCD_DIVSCRIPTVAR, PCD_DIVMAPVAR, PCD_DIVWORLDVAR, PCD_DIVGLOBALVAR, PCD_DIVMAPARRAY, PCD_DIVWORLDARRAY, PCD_DIVGLOBALARRAY },
\r
2938 { PCD_MODSCRIPTVAR, PCD_MODMAPVAR, PCD_MODWORLDVAR, PCD_MODGLOBALVAR, PCD_MODMAPARRAY, PCD_MODWORLDARRAY, PCD_MODGLOBALARRAY },
\r
2939 { PCD_ANDSCRIPTVAR, PCD_ANDMAPVAR, PCD_ANDWORLDVAR, PCD_ANDGLOBALVAR, PCD_ANDMAPARRAY, PCD_ANDWORLDARRAY, PCD_ANDGLOBALARRAY },
\r
2940 { PCD_EORSCRIPTVAR, PCD_EORMAPVAR, PCD_EORWORLDVAR, PCD_EORGLOBALVAR, PCD_EORMAPARRAY, PCD_EORWORLDARRAY, PCD_EORGLOBALARRAY },
\r
2941 { PCD_ORSCRIPTVAR, PCD_ORMAPVAR, PCD_ORWORLDVAR, PCD_ORGLOBALVAR, PCD_ORMAPARRAY, PCD_ORWORLDARRAY, PCD_ORGLOBALARRAY },
\r
2942 { PCD_LSSCRIPTVAR, PCD_LSMAPVAR, PCD_LSWORLDVAR, PCD_LSGLOBALVAR, PCD_LSMAPARRAY, PCD_LSWORLDARRAY, PCD_LSGLOBALARRAY },
\r
2943 { PCD_RSSCRIPTVAR, PCD_RSMAPVAR, PCD_RSWORLDVAR, PCD_RSGLOBALVAR, PCD_RSMAPARRAY, PCD_RSWORLDARRAY, PCD_RSGLOBALARRAY }
\r
2946 for(i = 0; i < ARRAY_SIZE(tokenLookup); ++i)
\r
2948 if(tokenLookup[i] == token)
\r
2950 for(j = 0; j < ARRAY_SIZE(symbolLookup); ++j)
\r
2952 if (symbolLookup[j] == symbol)
\r
2954 return assignmentLookup[i][j];
\r
2963 //==========================================================================
\r
2967 //==========================================================================
\r
2969 static void LeadingSuspend(void)
\r
2971 MS_Message(MSG_DEBUG, "---- LeadingSuspend ----\n");
\r
2972 if(InsideFunction)
\r
2974 ERR_Error(ERR_SUSPEND_IN_FUNCTION, YES);
\r
2976 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2977 PC_AppendCmd(PCD_SUSPEND);
\r
2981 //==========================================================================
\r
2983 // LeadingTerminate
\r
2985 //==========================================================================
\r
2987 static void LeadingTerminate(void)
\r
2989 MS_Message(MSG_DEBUG, "---- LeadingTerminate ----\n");
\r
2990 if(InsideFunction)
\r
2992 ERR_Error(ERR_TERMINATE_IN_FUNCTION, YES);
\r
2994 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2995 PC_AppendCmd(PCD_TERMINATE);
\r
2999 //==========================================================================
\r
3003 //==========================================================================
\r
3005 static void LeadingRestart(void)
\r
3007 MS_Message(MSG_DEBUG, "---- LeadingRestart ----\n");
\r
3008 if(InsideFunction)
\r
3010 ERR_Error(ERR_RESTART_IN_FUNCTION, YES);
\r
3012 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
3013 PC_AppendCmd(PCD_RESTART);
\r
3017 //==========================================================================
\r
3021 //==========================================================================
\r
3023 static void LeadingReturn(void)
\r
3025 MS_Message(MSG_DEBUG, "---- LeadingReturn ----\n");
\r
3026 if(!InsideFunction)
\r
3028 ERR_Error(ERR_RETURN_OUTSIDE_FUNCTION, YES);
\r
3029 while (TK_NextToken () != TK_SEMICOLON)
\r
3031 if (tk_Token == TK_EOF)
\r
3038 if(tk_Token == TK_SEMICOLON)
\r
3040 if(InsideFunction->info.scriptFunc.hasReturnValue)
\r
3042 ERR_Error(ERR_MUST_RETURN_A_VALUE, YES);
\r
3044 PC_AppendCmd(PCD_RETURNVOID);
\r
3048 if(!InsideFunction->info.scriptFunc.hasReturnValue)
\r
3050 ERR_Error(ERR_MUST_NOT_RETURN_A_VALUE, YES);
\r
3053 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
3054 PC_AppendCmd(PCD_RETURNVAL);
\r
3060 //==========================================================================
\r
3062 // EvalConstExpression
\r
3064 //==========================================================================
\r
3066 static int EvalConstExpression(void)
\r
3068 pa_ConstExprIsString = NO; // Used by PC_PutMapVariable
\r
3069 ExprStackIndex = 0;
\r
3070 ConstantExpression = YES;
\r
3072 if(ExprStackIndex != 1)
\r
3074 ERR_Error(ERR_BAD_CONST_EXPR, YES, NULL);
\r
3076 ExprStackIndex = 1;
\r
3078 return PopExStk();
\r
3081 //==========================================================================
\r
3085 // [RH] Rewrote all the ExprLevA - ExprLevJ functions in favor of a single
\r
3086 // table-driven parser function.
\r
3088 //==========================================================================
\r
3090 static void EvalExpression(void)
\r
3092 ConstantExpression = NO;
\r
3096 static void ExprLevA(void)
\r
3101 // Operator precedence levels:
\r
3107 // Operators: == !=
\r
3108 // Operators: < <= > >=
\r
3109 // Operators: << >>
\r
3111 // Operators: * / %
\r
3113 static void ExprLevX(int level)
\r
3115 if(OpsList[level] == NULL)
\r
3117 boolean unaryMinus;
\r
3119 unaryMinus = FALSE;
\r
3120 if(tk_Token == TK_MINUS)
\r
3122 unaryMinus = TRUE;
\r
3125 if(ConstantExpression == YES)
\r
3127 ConstExprFactor();
\r
3133 if(unaryMinus == TRUE)
\r
3135 SendExprCommand(PCD_UNARYMINUS);
\r
3140 ExprLevX(level + 1);
\r
3141 while(TK_Member(OpsList[level]))
\r
3143 tokenType_t token = tk_Token;
\r
3145 ExprLevX(level + 1);
\r
3146 SendExprCommand(TokenToPCD(token));
\r
3151 static void ExprLineSpecial(void)
\r
3153 U_BYTE specialValue = tk_SpecialValue;
\r
3154 int argCountMin = tk_SpecialArgCount & 0xffff;
\r
3155 int argCountMax = tk_SpecialArgCount >> 16;
\r
3157 // There are two ways to use a special in an expression:
\r
3158 // 1. The special name by itself returns the special's number.
\r
3159 // 2. The special followed by parameters actually executes the special.
\r
3161 if(tk_Token != TK_LPAREN)
\r
3163 PC_AppendPushVal(tk_SpecialValue);
\r
3170 if(tk_Token != TK_RPAREN)
\r
3178 } while(tk_Token == TK_COMMA);
\r
3180 if(argCount < argCountMin || argCount > argCountMax)
\r
3182 ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES);
\r
3185 for(; argCount < 5; ++argCount)
\r
3187 PC_AppendPushVal(0);
\r
3189 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
3191 PC_AppendCmd(PCD_LSPEC5RESULT);
\r
3194 PC_AppendLong(specialValue);
\r
3198 PC_AppendByte(specialValue);
\r
3203 static void ExprFactor(void)
\r
3205 symbolNode_t *sym;
\r
3206 tokenType_t opToken;
\r
3211 if (ImportMode != IMPORT_Importing)
\r
3213 tk_Number = STR_Find(tk_String);
\r
3214 PC_AppendPushVal(tk_Number);
\r
3215 if (ImportMode == IMPORT_Exporting)
\r
3217 // The VM identifies strings by storing a library ID in the
\r
3218 // high word of the string index. The library ID is not
\r
3219 // known until the script actually gets loaded into the game,
\r
3220 // so we need to use this p-code to tack the ID of the
\r
3221 // currently running library to the index of the string that
\r
3222 // just got pushed onto the stack.
\r
3224 // Simply assuming that a string is from the current library
\r
3225 // is not good enough, because they can be passed around
\r
3226 // between libraries and the map's behavior. Thus, we need
\r
3227 // to know which object file a particular string belongs to.
\r
3229 // A specific example:
\r
3230 // A map's behavior calls a function in a library and passes
\r
3233 // LibFunc ("The library will do something with this string.");
\r
3235 // The library function needs to know that the string originated
\r
3236 // outside the library. Similarly, if a library function returns
\r
3237 // a string, the caller needs to know that the string did not
\r
3238 // originate from the same object file.
\r
3240 // And that's why strings have library IDs tacked onto them.
\r
3241 // The map's main behavior (i.e. an object that is not a library)
\r
3242 // always uses library ID 0 to identify its strings, so its
\r
3243 // strings don't need to be tagged.
\r
3244 PC_AppendCmd(PCD_TAGSTRING);
\r
3250 PC_AppendPushVal(tk_Number);
\r
3256 if(tk_Token != TK_RPAREN)
\r
3258 ERR_Error(ERR_BAD_EXPR, YES, NULL);
\r
3259 TK_SkipPast(TK_RPAREN);
\r
3269 PC_AppendCmd(PCD_NEGATELOGICAL);
\r
3274 PC_AppendCmd(PCD_NEGATEBINARY);
\r
3278 opToken = tk_Token;
\r
3279 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INCDEC_OP_ON_NON_VAR);
\r
3280 sym = DemandSymbol(tk_String);
\r
3281 if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR
\r
3282 && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR
\r
3283 && sym->type != SY_MAPARRAY && sym->type != SY_WORLDARRAY
\r
3284 && sym->type != SY_GLOBALARRAY)
\r
3286 ERR_Error(ERR_INCDEC_OP_ON_NON_VAR, YES);
\r
3291 if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY
\r
3292 || sym->type == SY_GLOBALARRAY)
\r
3294 ParseArrayIndices(sym, sym->info.array.ndim);
\r
3295 PC_AppendCmd(PCD_DUP);
\r
3297 else if(tk_Token == TK_LBRACKET)
\r
3299 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);
\r
3300 while(tk_Token == TK_LBRACKET)
\r
3302 TK_SkipPast(TK_RBRACKET);
\r
3305 PC_AppendCmd(GetIncDecPCD(opToken, sym->type));
\r
3306 PC_AppendShrink(sym->info.var.index);
\r
3307 PC_AppendCmd(GetPushVarPCD(sym->type));
\r
3308 PC_AppendShrink(sym->info.var.index);
\r
3311 case TK_IDENTIFIER:
\r
3312 sym = SpeculateSymbol(tk_String, YES);
\r
3315 case SY_SCRIPTALIAS:
\r
3319 case SY_WORLDARRAY:
\r
3320 case SY_GLOBALARRAY:
\r
3322 ParseArrayIndices(sym, sym->info.array.ndim);
\r
3324 case SY_SCRIPTVAR:
\r
3327 case SY_GLOBALVAR:
\r
3328 if(sym->type != SY_MAPARRAY && sym->type != SY_WORLDARRAY
\r
3329 && sym->type != SY_GLOBALARRAY)
\r
3332 if(tk_Token == TK_LBRACKET)
\r
3334 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);
\r
3335 while(tk_Token == TK_LBRACKET)
\r
3337 TK_SkipPast(TK_RBRACKET);
\r
3341 if((tk_Token == TK_INC || tk_Token == TK_DEC)
\r
3342 && (sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY
\r
3343 || sym->type == SY_GLOBALARRAY))
\r
3345 PC_AppendCmd(PCD_DUP);
\r
3347 PC_AppendCmd(GetPushVarPCD(sym->type));
\r
3348 PC_AppendShrink(sym->info.var.index);
\r
3349 if(tk_Token == TK_INC || tk_Token == TK_DEC)
\r
3351 if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY
\r
3352 || sym->type == SY_GLOBALARRAY)
\r
3354 PC_AppendCmd(PCD_SWAP);
\r
3356 PC_AppendCmd(GetIncDecPCD(tk_Token, sym->type));
\r
3357 PC_AppendShrink(sym->info.var.index);
\r
3361 case SY_INTERNFUNC:
\r
3362 if(sym->info.internFunc.hasReturnValue == NO)
\r
3364 ERR_Error(ERR_EXPR_FUNC_NO_RET_VAL, YES);
\r
3366 ProcessInternFunc(sym);
\r
3368 case SY_SCRIPTFUNC:
\r
3369 if(sym->info.scriptFunc.hasReturnValue == NO)
\r
3371 ERR_Error(ERR_EXPR_FUNC_NO_RET_VAL, YES);
\r
3373 ProcessScriptFunc(sym, NO);
\r
3376 ERR_Error(ERR_ILLEGAL_EXPR_IDENT, YES, tk_String);
\r
3381 case TK_LINESPECIAL:
\r
3382 ExprLineSpecial();
\r
3385 ERR_Error(ERR_BAD_EXPR, YES);
\r
3391 static void ConstExprFactor(void)
\r
3396 if (ImportMode != IMPORT_Importing)
\r
3398 int strnum = STR_Find(tk_String);
\r
3399 if (ImportMode == IMPORT_Exporting)
\r
3401 pa_ConstExprIsString = YES;
\r
3403 PushExStk(strnum);
\r
3407 // Importing, so it doesn't matter
\r
3413 PushExStk(tk_Number);
\r
3419 if(tk_Token != TK_RPAREN)
\r
3421 ERR_Error(ERR_BAD_CONST_EXPR, YES);
\r
3422 TK_SkipPast(TK_RPAREN);
\r
3431 ConstExprFactor();
\r
3432 SendExprCommand(PCD_NEGATELOGICAL);
\r
3435 ERR_Error(ERR_BAD_CONST_EXPR, YES);
\r
3437 while(tk_Token != TK_COMMA &&
\r
3438 tk_Token != TK_SEMICOLON &&
\r
3439 tk_Token != TK_RPAREN)
\r
3441 if(tk_Token == TK_EOF)
\r
3443 ERR_Exit(ERR_EOF, YES);
\r
3451 //==========================================================================
\r
3453 // SendExprCommand
\r
3455 //==========================================================================
\r
3457 static void SendExprCommand(pcd_t pcd)
\r
3461 if(ConstantExpression == NO)
\r
3463 PC_AppendCmd(pcd);
\r
3469 PushExStk(PopExStk()+PopExStk());
\r
3471 case PCD_SUBTRACT:
\r
3472 operand2 = PopExStk();
\r
3473 PushExStk(PopExStk()-operand2);
\r
3475 case PCD_MULTIPLY:
\r
3476 PushExStk(PopExStk()*PopExStk());
\r
3479 operand2 = PopExStk();
\r
3480 PushExStk(PopExStk()/operand2);
\r
3483 operand2 = PopExStk();
\r
3484 PushExStk(PopExStk()%operand2);
\r
3487 PushExStk(PopExStk() == PopExStk());
\r
3490 PushExStk(PopExStk() != PopExStk());
\r
3493 operand2 = PopExStk();
\r
3494 PushExStk(PopExStk() >= operand2);
\r
3497 operand2 = PopExStk();
\r
3498 PushExStk(PopExStk() <= operand2);
\r
3501 operand2 = PopExStk();
\r
3502 PushExStk(PopExStk() > operand2);
\r
3505 operand2 = PopExStk();
\r
3506 PushExStk(PopExStk() < operand2);
\r
3508 case PCD_ANDLOGICAL:
\r
3509 PushExStk(PopExStk() && PopExStk());
\r
3511 case PCD_ORLOGICAL:
\r
3512 PushExStk(PopExStk() || PopExStk());
\r
3514 case PCD_ANDBITWISE:
\r
3515 PushExStk(PopExStk()&PopExStk());
\r
3517 case PCD_ORBITWISE:
\r
3518 PushExStk(PopExStk()|PopExStk());
\r
3520 case PCD_EORBITWISE:
\r
3521 PushExStk(PopExStk()^PopExStk());
\r
3523 case PCD_NEGATELOGICAL:
\r
3524 PushExStk(!PopExStk());
\r
3527 operand2 = PopExStk();
\r
3528 PushExStk(PopExStk()<<operand2);
\r
3531 operand2 = PopExStk();
\r
3532 PushExStk(PopExStk()>>operand2);
\r
3534 case PCD_UNARYMINUS:
\r
3535 PushExStk(-PopExStk());
\r
3538 ERR_Exit(ERR_UNKNOWN_CONST_EXPR_PCD, YES);
\r
3543 //==========================================================================
\r
3547 //==========================================================================
\r
3549 static void PushExStk(int value)
\r
3551 if(ExprStackIndex == EXPR_STACK_DEPTH)
\r
3553 ERR_Exit(ERR_EXPR_STACK_OVERFLOW, YES);
\r
3555 ExprStack[ExprStackIndex++] = value;
\r
3558 //==========================================================================
\r
3562 //==========================================================================
\r
3564 static int PopExStk(void)
\r
3566 if(ExprStackIndex < 1)
\r
3568 ERR_Error(ERR_EXPR_STACK_EMPTY, YES);
\r
3571 return ExprStack[--ExprStackIndex];
\r
3574 //==========================================================================
\r
3578 //==========================================================================
\r
3580 static pcd_t TokenToPCD(tokenType_t token)
\r
3585 tokenType_t token;
\r
3587 } operatorLookup[] =
\r
3589 { TK_ORLOGICAL, PCD_ORLOGICAL },
\r
3590 { TK_ANDLOGICAL, PCD_ANDLOGICAL },
\r
3591 { TK_ORBITWISE, PCD_ORBITWISE },
\r
3592 { TK_EORBITWISE, PCD_EORBITWISE },
\r
3593 { TK_ANDBITWISE, PCD_ANDBITWISE },
\r
3594 { TK_EQ, PCD_EQ },
\r
3595 { TK_NE, PCD_NE },
\r
3596 { TK_LT, PCD_LT },
\r
3597 { TK_LE, PCD_LE },
\r
3598 { TK_GT, PCD_GT },
\r
3599 { TK_GE, PCD_GE },
\r
3600 { TK_LSHIFT, PCD_LSHIFT },
\r
3601 { TK_RSHIFT, PCD_RSHIFT },
\r
3602 { TK_PLUS, PCD_ADD },
\r
3603 { TK_MINUS, PCD_SUBTRACT },
\r
3604 { TK_ASTERISK, PCD_MULTIPLY },
\r
3605 { TK_SLASH, PCD_DIVIDE },
\r
3606 { TK_PERCENT, PCD_MODULUS },
\r
3607 { TK_NONE, PCD_NOP }
\r
3610 for(i = 0; operatorLookup[i].token != TK_NONE; i++)
\r
3612 if(operatorLookup[i].token == token)
\r
3614 return operatorLookup[i].pcd;
\r
3620 //==========================================================================
\r
3624 //==========================================================================
\r
3626 static pcd_t GetPushVarPCD(symbolType_t symType)
\r
3630 case SY_SCRIPTVAR:
\r
3631 return PCD_PUSHSCRIPTVAR;
\r
3633 return PCD_PUSHMAPVAR;
\r
3635 return PCD_PUSHWORLDVAR;
\r
3636 case SY_GLOBALVAR:
\r
3637 return PCD_PUSHGLOBALVAR;
\r
3639 return PCD_PUSHMAPARRAY;
\r
3640 case SY_WORLDARRAY:
\r
3641 return PCD_PUSHWORLDARRAY;
\r
3642 case SY_GLOBALARRAY:
\r
3643 return PCD_PUSHGLOBALARRAY;
\r
3650 //==========================================================================
\r
3654 //==========================================================================
\r
3656 static pcd_t GetIncDecPCD(tokenType_t token, symbolType_t symbol)
\r
3661 tokenType_t token;
\r
3662 symbolType_t symbol;
\r
3664 } incDecLookup[] =
\r
3666 { TK_INC, SY_SCRIPTVAR, PCD_INCSCRIPTVAR },
\r
3667 { TK_INC, SY_MAPVAR, PCD_INCMAPVAR },
\r
3668 { TK_INC, SY_WORLDVAR, PCD_INCWORLDVAR },
\r
3669 { TK_INC, SY_GLOBALVAR, PCD_INCGLOBALVAR },
\r
3670 { TK_INC, SY_MAPARRAY, PCD_INCMAPARRAY },
\r
3671 { TK_INC, SY_WORLDARRAY, PCD_INCWORLDARRAY },
\r
3672 { TK_INC, SY_GLOBALARRAY, PCD_INCGLOBALARRAY },
\r
3674 { TK_DEC, SY_SCRIPTVAR, PCD_DECSCRIPTVAR },
\r
3675 { TK_DEC, SY_MAPVAR, PCD_DECMAPVAR },
\r
3676 { TK_DEC, SY_WORLDVAR, PCD_DECWORLDVAR },
\r
3677 { TK_DEC, SY_GLOBALVAR, PCD_DECGLOBALVAR },
\r
3678 { TK_DEC, SY_MAPARRAY, PCD_DECMAPARRAY },
\r
3679 { TK_DEC, SY_WORLDARRAY, PCD_DECWORLDARRAY },
\r
3680 { TK_DEC, SY_GLOBALARRAY, PCD_DECGLOBALARRAY },
\r
3682 { TK_NONE, SY_DUMMY, PCD_NOP }
\r
3685 for(i = 0; incDecLookup[i].token != TK_NONE; i++)
\r
3687 if(incDecLookup[i].token == token
\r
3688 && incDecLookup[i].symbol == symbol)
\r
3690 return incDecLookup[i].pcd;
\r
3696 //==========================================================================
\r
3698 // ParseArrayIndices
\r
3700 //==========================================================================
\r
3702 static void ParseArrayIndices(symbolNode_t *sym, int requiredIndices)
\r
3704 boolean warned = NO;
\r
3707 if(requiredIndices > 0)
\r
3709 TK_TokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET);
\r
3712 while(tk_Token == TK_LBRACKET)
\r
3715 if((sym->type == SY_MAPARRAY && i == requiredIndices) ||
\r
3716 (sym->type != SY_MAPARRAY && i > 0))
\r
3721 if(sym->info.array.ndim == requiredIndices)
\r
3723 ERR_Error(ERR_TOO_MANY_DIM_USED, YES,
\r
3724 sym->name, sym->info.array.ndim);
\r
3728 ERR_Error(ERR_NOT_A_CHAR_ARRAY, YES, sym->name,
\r
3729 sym->info.array.ndim, requiredIndices);
\r
3734 if(i < sym->info.array.ndim - 1 && sym->info.array.dimensions[i] > 1)
\r
3736 PC_AppendPushVal(sym->info.array.dimensions[i]);
\r
3737 PC_AppendCmd(PCD_MULTIPLY);
\r
3741 PC_AppendCmd(PCD_ADD);
\r
3744 TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET);
\r
3747 // if there were unspecified indices, multiply the offset by their sizes [JB]
\r
3748 if(requiredIndices < sym->info.array.ndim - 1)
\r
3751 for(i = 0; i < sym->info.array.ndim - requiredIndices - 1; ++i)
\r
3753 mult *= sym->info.array.dimensions[sym->info.array.ndim - 2 - i];
\r
3757 PC_AppendPushVal(mult);
\r
3758 PC_AppendCmd(PCD_MULTIPLY);
\r
3763 static int *ProcessArrayLevel(int level, int *entry, int ndim,
\r
3764 int dims[MAX_ARRAY_DIMS], int muls[MAX_ARRAY_DIMS], char *name)
\r
3768 for(i = 0; i < dims[level-1]; ++i)
\r
3770 if(tk_Token == TK_COMMA)
\r
3772 entry += muls[level-1];
\r
3775 else if(tk_Token == TK_RBRACE)
\r
3780 return entry + muls[level-2] - i;
\r
3784 return entry + (muls[0]*dims[0]) - i;
\r
3791 if(tk_Token == TK_LBRACE)
\r
3793 ERR_Error(ERR_TOO_MANY_DIM_USED, YES, name, ndim);
\r
3794 SkipBraceBlock(0);
\r
3800 *entry++ = EvalConstExpression();
\r
3801 ArrayHasStrings |= pa_ConstExprIsString;
\r
3806 TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR);
\r
3808 entry = ProcessArrayLevel(level+1, entry, ndim, dims, muls, name);
\r
3810 if(i < dims[level-1]-1)
\r
3812 if(tk_Token != TK_RBRACE)
\r
3814 TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA);
\r
3820 if(tk_Token != TK_COMMA)
\r
3822 TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR);
\r
3831 TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR);
\r
3836 //==========================================================================
\r
3838 // InitializeArray
\r
3840 //==========================================================================
\r
3842 static void InitializeArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS], int size)
\r
3844 static int *entries = NULL;
\r
3845 static int lastsize = -1;
\r
3847 if(lastsize < size)
\r
3849 entries = MS_Realloc(entries, sizeof(int)*size, ERR_OUT_OF_MEMORY);
\r
3852 memset(entries, 0, sizeof(int)*size);
\r
3854 TK_NextTokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR);
\r
3856 ArrayHasStrings = NO;
\r
3857 ProcessArrayLevel(1, entries, sym->info.array.ndim, dims,
\r
3858 sym->info.array.dimensions, sym->name);
\r
3859 if(ImportMode != IMPORT_Importing)
\r
3861 PC_InitArray(sym->info.array.index, entries, ArrayHasStrings);
\r
3865 //==========================================================================
\r
3869 //==========================================================================
\r
3871 static symbolNode_t *DemandSymbol(char *name)
\r
3873 symbolNode_t *sym;
\r
3875 if((sym = SY_Find(name)) == NULL)
\r
3877 ERR_Exit(ERR_UNKNOWN_IDENTIFIER, YES, name);
\r
3882 //==========================================================================
\r
3884 // SpeculateSymbol
\r
3886 //==========================================================================
\r
3888 static symbolNode_t *SpeculateSymbol(char *name, boolean hasReturn)
\r
3890 symbolNode_t *sym;
\r
3892 sym = SY_Find(name);
\r
3895 char name[MAX_IDENTIFIER_LENGTH];
\r
3897 strcpy (name, tk_String);
\r
3899 if(tk_Token == TK_LPAREN)
\r
3900 { // Looks like a function call
\r
3901 sym = SpeculateFunction(name, hasReturn);
\r
3906 ERR_Exit(ERR_UNKNOWN_IDENTIFIER, YES, name);
\r
3912 //==========================================================================
\r
3914 // SpeculateFunction
\r
3916 // Add a temporary symbol for a function that is used before it is defined.
\r
3918 //==========================================================================
\r
3920 static symbolNode_t *SpeculateFunction(const char *name, boolean hasReturn)
\r
3922 symbolNode_t *sym;
\r
3924 MS_Message(MSG_DEBUG, "---- SpeculateFunction %s ----\n", name);
\r
3925 sym = SY_InsertGlobal(tk_String, SY_SCRIPTFUNC);
\r
3926 sym->info.scriptFunc.predefined = YES;
\r
3927 sym->info.scriptFunc.hasReturnValue = hasReturn;
\r
3928 sym->info.scriptFunc.sourceLine = tk_Line;
\r
3929 sym->info.scriptFunc.sourceName = tk_SourceName;
\r
3930 sym->info.scriptFunc.argCount = -1;
\r
3931 sym->info.scriptFunc.funcNumber = 0;
\r
3935 //==========================================================================
\r
3937 // UnspeculateFunction
\r
3939 // Fills in function calls that were made before this function was defined.
\r
3941 //==========================================================================
\r
3943 static void UnspeculateFunction(symbolNode_t *sym)
\r
3945 prefunc_t *fillin;
\r
3948 prev = &FillinFunctions;
\r
3949 fillin = FillinFunctions;
\r
3950 while(fillin != NULL)
\r
3952 prefunc_t *next = fillin->next;
\r
3953 if(fillin->sym == sym)
\r
3955 if(fillin->argcount != sym->info.scriptFunc.argCount)
\r
3957 ERR_ErrorAt(fillin->source, fillin->line);
\r
3958 ERR_Error(ERR_FUNC_ARGUMENT_COUNT, YES, sym->name,
\r
3959 sym->info.scriptFunc.argCount,
\r
3960 sym->info.scriptFunc.argCount == 1 ? "" : "s");
\r
3965 PC_WriteLong(sym->info.scriptFunc.funcNumber, fillin->address);
\r
3969 PC_WriteByte((U_BYTE)sym->info.scriptFunc.funcNumber, fillin->address);
\r
3971 if(FillinFunctionsLatest == &fillin->next)
\r
3973 FillinFunctionsLatest = prev;
\r
3980 prev = &fillin->next;
\r
3986 //==========================================================================
\r
3988 // AddScriptFuncRef
\r
3990 //==========================================================================
\r
3992 static void AddScriptFuncRef(symbolNode_t *sym, int address, int argcount)
\r
3994 prefunc_t *fillin = MS_Alloc(sizeof(*fillin), ERR_OUT_OF_MEMORY);
\r
3995 fillin->next = NULL;
\r
3996 fillin->sym = sym;
\r
3997 fillin->address = address;
\r
3998 fillin->argcount = argcount;
\r
3999 fillin->line = tk_Line;
\r
4000 fillin->source = tk_SourceName;
\r
4001 *FillinFunctionsLatest = fillin;
\r
4002 FillinFunctionsLatest = &fillin->next;
\r
4005 //==========================================================================
\r
4007 // Check for undefined functions
\r
4009 //==========================================================================
\r
4011 static void CheckForUndefinedFunctions(void)
\r
4013 prefunc_t *fillin = FillinFunctions;
\r
4015 while(fillin != NULL)
\r
4017 ERR_ErrorAt(fillin->source, fillin->line);
\r
4018 ERR_Error(ERR_UNDEFINED_FUNC, YES, fillin->sym->name);
\r
4019 fillin = fillin->next;
\r
4023 //==========================================================================
\r
4027 // If depth is 0, it scans for the first { and then starts going from there.
\r
4028 // At exit, the terminating } is left as the current token.
\r
4030 //==========================================================================
\r
4032 void SkipBraceBlock(int depth)
\r
4037 while(tk_Token != TK_LBRACE)
\r
4039 if(tk_Token == TK_EOF)
\r
4041 ERR_Exit(ERR_EOF, NO);
\r
4047 // Match it with a }
\r
4051 if(tk_Token == TK_EOF)
\r
4053 ERR_Exit(ERR_EOF, NO);
\r
4055 else if (tk_Token == TK_LBRACE)
\r
4059 else if (tk_Token == TK_RBRACE)
\r
4063 } while (depth > 0);
\r