2 //**************************************************************************
\r
6 //**************************************************************************
\r
8 // HEADER FILES ------------------------------------------------------------
\r
24 #include "strlist.h"
\r
26 // MACROS ------------------------------------------------------------------
\r
28 #define MAX_STATEMENT_DEPTH 128
\r
29 #define MAX_BREAK 128
\r
30 #define MAX_CONTINUE 128
\r
31 #define MAX_CASE 128
\r
32 #define EXPR_STACK_DEPTH 64
\r
34 // TYPES -------------------------------------------------------------------
\r
67 typedef struct prefunc_s
\r
69 struct prefunc_s *next;
\r
77 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
\r
79 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
\r
81 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
\r
83 static void CountScript(int type);
\r
84 static void Outside(void);
\r
85 static void OuterScript(void);
\r
86 static void OuterFunction(void);
\r
87 static void OuterMapVar(boolean local);
\r
88 static void OuterWorldVar(boolean isGlobal);
\r
89 static void OuterSpecialDef(void);
\r
90 static void OuterDefine(boolean force);
\r
91 static void OuterInclude(void);
\r
92 static void OuterImport(void);
\r
93 static boolean ProcessStatement(statement_t owner);
\r
94 static void LeadingCompoundStatement(statement_t owner);
\r
95 static void LeadingVarDeclare(void);
\r
96 static void LeadingLineSpecial(boolean executewait);
\r
97 static void LeadingFunction(boolean executewait);
\r
98 static void LeadingIdentifier(void);
\r
99 static void BuildPrintString(void);
\r
100 static void ActionOnCharRange(boolean write);
\r
101 static void LeadingStrcpy(void);
\r
102 static void LeadingPrint(void);
\r
103 static void LeadingHudMessage(void);
\r
104 static void LeadingVarAssign(symbolNode_t *sym);
\r
105 static pcd_t GetAssignPCD(tokenType_t token, symbolType_t symbol);
\r
106 static void LeadingInternFunc(symbolNode_t *sym);
\r
107 static void LeadingScriptFunc(symbolNode_t *sym);
\r
108 static void LeadingSuspend(void);
\r
109 static void LeadingTerminate(void);
\r
110 static void LeadingRestart(void);
\r
111 static void LeadingReturn(void);
\r
112 static void LeadingIf(void);
\r
113 static void LeadingFor(void);
\r
114 static void LeadingWhileUntil(void);
\r
115 static void LeadingDo(void);
\r
116 static void LeadingSwitch(void);
\r
117 static void LeadingCase(void);
\r
118 static void LeadingDefault(void);
\r
119 static void LeadingBreak(void);
\r
120 static void LeadingContinue(void);
\r
121 static void LeadingCreateTranslation(void);
\r
122 static void LeadingIncDec(int token);
\r
123 static void PushCase(int value, boolean isDefault);
\r
124 static caseInfo_t *GetCaseInfo(void);
\r
125 static int CaseInfoCmp(const void *a, const void *b);
\r
126 static boolean DefaultInCurrent(void);
\r
127 static void PushBreak(void);
\r
128 static void WriteBreaks(void);
\r
129 static boolean BreakAncestor(void);
\r
130 static void PushContinue(void);
\r
131 static void WriteContinues(int address);
\r
132 static boolean ContinueAncestor(void);
\r
133 static void ProcessInternFunc(symbolNode_t *sym);
\r
134 static void ProcessScriptFunc(symbolNode_t *sym, boolean discardReturn);
\r
135 static void EvalExpression(void);
\r
136 static void ExprLevX(int level);
\r
137 static void ExprLevA(void);
\r
138 static void ExprFactor(void);
\r
139 static void ConstExprFactor(void);
\r
140 static void SendExprCommand(pcd_t pcd);
\r
141 static void PushExStk(int value);
\r
142 static int PopExStk(void);
\r
143 static pcd_t TokenToPCD(tokenType_t token);
\r
144 static pcd_t GetPushVarPCD(symbolType_t symType);
\r
145 static pcd_t GetIncDecPCD(tokenType_t token, symbolType_t symbol);
\r
146 static int EvalConstExpression(void);
\r
147 static void ParseArrayIndices(symbolNode_t *sym, int requiredIndices);
\r
148 static void InitializeArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS], int size);
\r
149 static symbolNode_t *DemandSymbol(char *name);
\r
150 static symbolNode_t *SpeculateSymbol(char *name, boolean hasReturn);
\r
151 static symbolNode_t *SpeculateFunction(const char *name, boolean hasReturn);
\r
152 static void UnspeculateFunction(symbolNode_t *sym);
\r
153 static void AddScriptFuncRef(symbolNode_t *sym, int address, int argcount);
\r
154 static void CheckForUndefinedFunctions(void);
\r
155 static void SkipBraceBlock(int depth);
\r
157 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
\r
159 // PUBLIC DATA DEFINITIONS -------------------------------------------------
\r
161 int pa_ScriptCount;
\r
162 struct ScriptTypes *pa_TypedScriptCounts;
\r
163 int pa_MapVarCount;
\r
164 int pa_WorldVarCount;
\r
165 int pa_GlobalVarCount;
\r
166 int pa_WorldArrayCount;
\r
167 int pa_GlobalArrayCount;
\r
168 enum ImportModes ImportMode = IMPORT_None;
\r
169 boolean ExporterFlagged;
\r
170 boolean pa_ConstExprIsString;
\r
172 // PRIVATE DATA DEFINITIONS ------------------------------------------------
\r
174 static int ScriptVarCount;
\r
175 static statement_t StatementHistory[MAX_STATEMENT_DEPTH];
\r
176 static int StatementIndex;
\r
177 static breakInfo_t BreakInfo[MAX_BREAK];
\r
178 static int BreakIndex;
\r
179 static continueInfo_t ContinueInfo[MAX_CONTINUE];
\r
180 static int ContinueIndex;
\r
181 static caseInfo_t CaseInfo[MAX_CASE];
\r
182 static int CaseIndex;
\r
183 static int StatementLevel;
\r
184 static int ExprStack[EXPR_STACK_DEPTH];
\r
185 static int ExprStackIndex;
\r
186 static boolean ConstantExpression;
\r
187 static symbolNode_t *InsideFunction;
\r
188 static prefunc_t *FillinFunctions;
\r
189 static prefunc_t **FillinFunctionsLatest = &FillinFunctions;
\r
190 static boolean ArrayHasStrings;
\r
192 static int AdjustStmtLevel[] =
\r
198 1, // STMT_WHILEUNTIL
\r
203 static boolean IsBreakRoot[] =
\r
209 YES, // STMT_WHILEUNTIL
\r
210 YES, // STMT_SWITCH
\r
214 static boolean IsContinueRoot[] =
\r
220 YES, // STMT_WHILEUNTIL
\r
225 static tokenType_t LevAOps[] =
\r
231 static tokenType_t LevBOps[] =
\r
237 static tokenType_t LevCOps[] =
\r
243 static tokenType_t LevDOps[] =
\r
249 static tokenType_t LevEOps[] =
\r
255 static tokenType_t LevFOps[] =
\r
262 static tokenType_t LevGOps[] =
\r
271 static tokenType_t LevHOps[] =
\r
278 static tokenType_t LevIOps[] =
\r
285 static tokenType_t LevJOps[] =
\r
293 static tokenType_t *OpsList[] =
\r
308 static tokenType_t AssignOps[] =
\r
324 static struct ScriptTypes ScriptCounts[] =
\r
326 { "closed", 0, 0 },
\r
327 { "open", OPEN_SCRIPTS_BASE, 0 },
\r
328 { "respawn", RESPAWN_SCRIPTS_BASE, 0 },
\r
329 { "death", DEATH_SCRIPTS_BASE, 0 },
\r
330 { "enter", ENTER_SCRIPTS_BASE, 0 },
\r
331 { "pickup", PICKUP_SCRIPTS_BASE, 0 },
\r
332 { "bluereturn", BLUE_RETURN_SCRIPTS_BASE, 0 },
\r
333 { "redreturn", RED_RETURN_SCRIPTS_BASE, 0 },
\r
334 { "whitereturn", WHITE_RETURN_SCRIPTS_BASE, 0 },
\r
335 { "lightning", LIGHTNING_SCRIPTS_BASE, 0 },
\r
336 { "disconnect", DISCONNECT_SCRIPTS_BASE, 0 },
\r
337 { "unloading", UNLOADING_SCRIPTS_BASE, 0 },
\r
338 { "return", RETURN_SCRIPTS_BASE, 0 },
\r
339 { "event", EVENT_SCRIPTS_BASE, 0 },
\r
343 // CODE --------------------------------------------------------------------
\r
345 //==========================================================================
\r
349 //==========================================================================
\r
351 void PA_Parse(void)
\r
355 pa_ScriptCount = 0;
\r
356 pa_TypedScriptCounts = ScriptCounts;
\r
357 for (i = 0; ScriptCounts[i].TypeName != NULL; i++)
\r
359 ScriptCounts[i].TypeCount = 0;
\r
361 pa_MapVarCount = 0;
\r
362 pa_WorldVarCount = 0;
\r
363 pa_GlobalVarCount = 0;
\r
364 pa_WorldArrayCount = 0;
\r
365 pa_GlobalArrayCount = 0;
\r
368 CheckForUndefinedFunctions();
\r
372 //==========================================================================
\r
376 //==========================================================================
\r
378 static void CountScript(int type)
\r
382 for (i = 0; ScriptCounts[i].TypeName != NULL; i++)
\r
384 if (ScriptCounts[i].TypeBase == type)
\r
388 MS_Message(MSG_DEBUG, "Script type: %s\n",
\r
389 ScriptCounts[i].TypeName);
\r
391 ScriptCounts[i].TypeCount++;
\r
398 //==========================================================================
\r
402 //==========================================================================
\r
404 static void Outside(void)
\r
432 OuterWorldVar(YES);
\r
437 case TK_NUMBERSIGN:
\r
451 if(ImportMode != IMPORT_Importing)
\r
453 if(pc_Address != 8)
\r
455 ERR_Error(ERR_NOCOMPACT_NOT_HERE, YES);
\r
457 MS_Message(MSG_DEBUG, "Forcing NoShrink\n");
\r
458 pc_NoShrink = TRUE;
\r
463 if(ImportMode != IMPORT_Importing)
\r
465 MS_Message(MSG_DEBUG, "Will write WadAuthor-compatible object\n");
\r
466 MS_Message(MSG_NORMAL, "You don't need to use #wadauthor anymore.\n");
\r
467 pc_WadAuthor = TRUE;
\r
471 case TK_NOWADAUTHOR:
\r
472 if(ImportMode != IMPORT_Importing)
\r
474 MS_Message(MSG_DEBUG, "Will write WadAuthor-incompatible object\n");
\r
475 pc_WadAuthor = FALSE;
\r
479 case TK_ENCRYPTSTRINGS:
\r
480 if(ImportMode != IMPORT_Importing)
\r
482 MS_Message(MSG_DEBUG, "Strings will be encrypted\n");
\r
483 pc_EncryptStrings = TRUE;
\r
484 if(pc_EnforceHexen)
\r
486 ERR_Error(ERR_HEXEN_COMPAT, YES);
\r
495 TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND);
\r
496 if(ImportMode == IMPORT_None)
\r
498 MS_Message(MSG_DEBUG, "Allocations modified for exporting\n");
\r
499 ImportMode = IMPORT_Exporting;
\r
501 else if(ImportMode == IMPORT_Importing)
\r
503 PC_AddImport(tk_String);
\r
504 ExporterFlagged = YES;
\r
509 ERR_Error(ERR_INVALID_DIRECTIVE, YES);
\r
515 ERR_Exit(ERR_INVALID_DECLARATOR, YES, NULL);
\r
521 //==========================================================================
\r
525 //==========================================================================
\r
527 static void OuterScript(void)
\r
531 int scriptType, scriptFlags;
\r
533 MS_Message(MSG_DEBUG, "---- OuterScript ----\n");
\r
536 StatementLevel = 0;
\r
537 ScriptVarCount = 0;
\r
541 if(ImportMode == IMPORT_Importing)
\r
543 // When importing, the script number is not recorded, because
\r
544 // it might be a #define that is not included by the main .acs
\r
545 // file, so processing it would generate a syntax error.
\r
551 // [RH] If you want to use script 0, it must be written as <<0>>.
\r
552 // This is to avoid using it accidentally, since ZDoom uses script
\r
553 // 0 to implement many of the Strife-specific line specials.
\r
555 if(tk_Token == TK_LSHIFT)
\r
557 TK_NextTokenMustBe(TK_NUMBER, ERR_SCRIPT_OUT_OF_RANGE);
\r
560 ERR_Exit(ERR_SCRIPT_OUT_OF_RANGE, YES, NULL);
\r
562 TK_NextTokenMustBe(TK_RSHIFT, ERR_SCRIPT_OUT_OF_RANGE);
\r
566 else if(tk_Token == TK_STRING)
\r
567 { // Named scripts start counting at -1 and go down from there.
\r
568 if(strcasecmp("None", tk_String) == 0)
\r
570 ERR_Error(ERR_SCRIPT_NAMED_NONE, YES, NULL);
\r
572 scriptNumber = -1 - STR_FindInListInsensitive(STRLIST_NAMEDSCRIPTS, tk_String);
\r
577 scriptNumber = EvalConstExpression();
\r
578 if(scriptNumber < 1 || scriptNumber > 32767)
\r
581 ERR_Error(ERR_SCRIPT_OUT_OF_RANGE, YES, NULL);
\r
587 if (scriptNumber >= 0)
\r
589 MS_Message(MSG_DEBUG, "Script number: %d\n", scriptNumber);
\r
593 MS_Message(MSG_DEBUG, "Script name: %s (%d)\n",
\r
594 STR_GetString(STRLIST_NAMEDSCRIPTS, -scriptNumber - 1),
\r
599 if(tk_Token == TK_LPAREN)
\r
601 if(TK_NextToken() == TK_VOID)
\r
603 TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
610 TK_NextTokenMustBe(TK_INT, ERR_BAD_VAR_TYPE);
\r
611 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
612 if(ScriptVarCount == 4)
\r
614 ERR_Error(ERR_TOO_MANY_SCRIPT_ARGS, YES);
\r
616 if(SY_FindLocal(tk_String) != NULL)
\r
618 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);
\r
620 else if(ScriptVarCount < 4)
\r
622 sym = SY_InsertLocal(tk_String, SY_SCRIPTVAR);
\r
623 sym->info.var.index = ScriptVarCount;
\r
627 } while(tk_Token == TK_COMMA);
\r
628 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
633 case TK_DISCONNECT:
\r
634 scriptType = DISCONNECT_SCRIPTS_BASE;
\r
635 if(ScriptVarCount != 1)
\r
637 ERR_Error(ERR_DISCONNECT_NEEDS_1_ARG, YES);
\r
646 case TK_BLUERETURN:
\r
648 case TK_WHITERETURN:
\r
652 ERR_Error(ERR_UNCLOSED_WITH_ARGS, YES);
\r
656 scriptType = EVENT_SCRIPTS_BASE;
\r
657 if(ScriptVarCount != 3)
\r
659 ERR_Error(ERR_EVENT_NEEDS_3_ARG, YES);
\r
666 MS_Message(MSG_DEBUG, "Script type: %s (%d %s)\n",
\r
667 scriptType == 0 ? "closed" : "disconnect",
\r
668 ScriptVarCount, ScriptVarCount == 1 ? "arg" : "args");
\r
670 else switch (tk_Token)
\r
673 scriptType = OPEN_SCRIPTS_BASE;
\r
676 case TK_RESPAWN: // [BC]
\r
677 scriptType = RESPAWN_SCRIPTS_BASE;
\r
680 case TK_DEATH: // [BC]
\r
681 scriptType = DEATH_SCRIPTS_BASE;
\r
684 case TK_ENTER: // [BC]
\r
685 scriptType = ENTER_SCRIPTS_BASE;
\r
689 scriptType = RETURN_SCRIPTS_BASE;
\r
692 case TK_PICKUP: // [BC]
\r
693 scriptType = PICKUP_SCRIPTS_BASE;
\r
696 case TK_BLUERETURN: // [BC]
\r
697 scriptType = BLUE_RETURN_SCRIPTS_BASE;
\r
700 case TK_REDRETURN: // [BC]
\r
701 scriptType = RED_RETURN_SCRIPTS_BASE;
\r
704 case TK_WHITERETURN: // [BC]
\r
705 scriptType = WHITE_RETURN_SCRIPTS_BASE;
\r
709 scriptType = LIGHTNING_SCRIPTS_BASE;
\r
713 scriptType = UNLOADING_SCRIPTS_BASE;
\r
716 case TK_DISCONNECT:
\r
717 scriptType = DISCONNECT_SCRIPTS_BASE;
\r
718 ERR_Error (ERR_DISCONNECT_NEEDS_1_ARG, YES);
\r
721 case TK_EVENT: // [BB]
\r
722 scriptType = EVENT_SCRIPTS_BASE;
\r
723 ERR_Error (ERR_EVENT_NEEDS_3_ARG, YES);
\r
727 ERR_Error(ERR_BAD_SCRIPT_DECL, YES);
\r
733 if(tk_Token == TK_NET)
\r
735 scriptFlags |= NET_SCRIPT_FLAG;
\r
738 // [BB] If NET and CLIENTSIDE are specified, this construction can only parse
\r
739 // "NET CLIENTSIDE" but not "CLIENTSIDE NET".
\r
740 if(tk_Token == TK_CLIENTSIDE)
\r
742 scriptFlags |= CLIENTSIDE_SCRIPT_FLAG;
\r
745 CountScript(scriptType);
\r
746 PC_AddScript(scriptNumber, scriptType, scriptFlags, ScriptVarCount);
\r
747 pc_LastAppendedCommand = PCD_NOP;
\r
748 if(ProcessStatement(STMT_SCRIPT) == NO)
\r
750 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
752 if(pc_LastAppendedCommand != PCD_TERMINATE)
\r
754 PC_AppendCmd(PCD_TERMINATE);
\r
756 PC_SetScriptVarCount(scriptNumber, scriptType, ScriptVarCount);
\r
760 //==========================================================================
\r
764 //==========================================================================
\r
766 static void OuterFunction(void)
\r
768 enum ImportModes importing;
\r
773 MS_Message(MSG_DEBUG, "---- OuterFunction ----\n");
\r
774 importing = ImportMode;
\r
777 StatementLevel = 0;
\r
778 ScriptVarCount = 0;
\r
781 if(tk_Token != TK_STR && tk_Token != TK_INT &&
\r
782 tk_Token != TK_VOID && tk_Token != TK_BOOL)
\r
784 ERR_Error(ERR_BAD_RETURN_TYPE, YES);
\r
785 tk_Token = TK_VOID;
\r
787 hasReturn = tk_Token != TK_VOID;
\r
788 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
789 sym = SY_FindGlobal(tk_String);
\r
792 if(sym->type != SY_SCRIPTFUNC)
\r
794 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);
\r
799 if(!sym->info.scriptFunc.predefined)
\r
801 ERR_Error(ERR_FUNCTION_ALREADY_DEFINED, YES);
\r
802 ERR_ErrorAt(sym->info.scriptFunc.sourceName, sym->info.scriptFunc.sourceLine);
\r
803 ERR_Error(ERR_NONE, YES, "Previous definition was here.");
\r
808 if(sym->info.scriptFunc.hasReturnValue && !hasReturn)
\r
810 ERR_Error(ERR_PREVIOUS_NOT_VOID, YES);
\r
811 ERR_ErrorAt(sym->info.scriptFunc.sourceName, sym->info.scriptFunc.sourceLine);
\r
812 ERR_Error(ERR_NONE, YES, "Previous use was here.");
\r
817 sym = SY_InsertGlobal(tk_String, SY_SCRIPTFUNC);
\r
818 sym->info.scriptFunc.address = (importing == IMPORT_Importing ? 0 : pc_Address);
\r
819 sym->info.scriptFunc.predefined = NO;
\r
823 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
824 if(TK_NextToken() == TK_VOID)
\r
826 TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
834 symbolNode_t *local;
\r
837 /* if(tk_Token != TK_INT && tk_Token != TK_STR && tk_Token != TK_BOOL)
\r
839 ERR_Error(ERR_BAD_VAR_TYPE, YES);
\r
842 */ if(tk_Token == TK_INT || tk_Token == TK_BOOL)
\r
844 if(TK_NextToken() == TK_LBRACKET)
\r
846 TK_NextTokenMustBe(TK_RBRACKET, ERR_BAD_VAR_TYPE);
\r
847 type = SY_SCRIPTALIAS;
\r
852 type = SY_SCRIPTVAR;
\r
855 else if(tk_Token == TK_STR)
\r
857 type = SY_SCRIPTVAR;
\r
861 type = SY_SCRIPTVAR;
\r
862 ERR_Error(ERR_BAD_VAR_TYPE, YES);
\r
865 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
866 if(SY_FindLocal(tk_String) != NULL)
\r
868 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);
\r
872 local = SY_InsertLocal(tk_String, type);
\r
873 local->info.var.index = ScriptVarCount;
\r
877 } while(tk_Token == TK_COMMA);
\r
878 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
881 sym->info.scriptFunc.sourceLine = defLine;
\r
882 sym->info.scriptFunc.sourceName = tk_SourceName;
\r
883 sym->info.scriptFunc.argCount = ScriptVarCount;
\r
884 sym->info.scriptFunc.address = (importing == IMPORT_Importing) ? 0 : pc_Address;
\r
885 sym->info.scriptFunc.hasReturnValue = hasReturn;
\r
887 if(importing == IMPORT_Importing)
\r
891 sym->info.scriptFunc.predefined = NO;
\r
892 sym->info.scriptFunc.varCount = ScriptVarCount;
\r
897 InsideFunction = sym;
\r
898 pc_LastAppendedCommand = PCD_NOP;
\r
900 // If we just call ProcessStatement(STMT_SCRIPT), and this function
\r
901 // needs to return a value but the last pcode output was not a return,
\r
902 // then the line number given in the error can be confusing because it
\r
903 // is beyond the end of the function. To avoid this, we process the
\r
904 // compound statement ourself and check if it returned something
\r
905 // before checking for the '}'. If a return is required, then the error
\r
906 // line will be shown as the one that contains the '}' (if present).
\r
908 TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE);
\r
910 do {} while(ProcessStatement(STMT_SCRIPT) == YES);
\r
912 if(pc_LastAppendedCommand != PCD_RETURNVOID &&
\r
913 pc_LastAppendedCommand != PCD_RETURNVAL)
\r
918 ERR_Error(ERR_MUST_RETURN_A_VALUE, YES, NULL);
\r
920 PC_AppendCmd(PCD_RETURNVOID);
\r
923 TK_TokenMustBe(TK_RBRACE, ERR_INVALID_STATEMENT);
\r
926 sym->info.scriptFunc.predefined = NO;
\r
927 sym->info.scriptFunc.varCount = ScriptVarCount -
\r
928 sym->info.scriptFunc.argCount;
\r
929 PC_AddFunction(sym);
\r
930 UnspeculateFunction(sym);
\r
931 InsideFunction = NULL;
\r
934 //==========================================================================
\r
938 //==========================================================================
\r
940 static void OuterMapVar(boolean local)
\r
942 symbolNode_t *sym = NULL;
\r
945 MS_Message(MSG_DEBUG, "---- %s ----\n", local ? "LeadingStaticVarDeclare" : "OuterMapVar");
\r
948 if(pa_MapVarCount >= MAX_MAP_VARIABLES)
\r
950 ERR_Error(ERR_TOO_MANY_MAP_VARS, YES);
\r
951 index = MAX_MAP_VARIABLES;
\r
953 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
954 sym = local ? SY_FindLocal(tk_String)
\r
955 : SY_FindGlobal(tk_String);
\r
958 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);
\r
959 index = MAX_MAP_VARIABLES;
\r
963 sym = local ? SY_InsertLocal(tk_String, SY_MAPVAR)
\r
964 : SY_InsertGlobal(tk_String, SY_MAPVAR);
\r
965 if(ImportMode == IMPORT_Importing)
\r
967 sym->info.var.index = index = 0;
\r
971 sym->info.var.index = index = pa_MapVarCount;
\r
973 { // Local variables are not exported
\r
974 PC_NameMapVariable(index, sym);
\r
980 if(tk_Token == TK_ASSIGN)
\r
982 if(ImportMode != IMPORT_Importing)
\r
985 PC_PutMapVariable (index, EvalConstExpression());
\r
989 // When importing, skip the initializer, because we don't care.
\r
993 } while(tk_Token != TK_COMMA && tk_Token != TK_SEMICOLON);
\r
996 else if(tk_Token == TK_LBRACKET)
\r
1000 int dims[MAX_ARRAY_DIMS];
\r
1002 memset(dims, 0, sizeof(dims));
\r
1004 while(tk_Token == TK_LBRACKET)
\r
1006 if(ndim == MAX_ARRAY_DIMS)
\r
1008 ERR_Error(ERR_TOO_MANY_ARRAY_DIMS, YES);
\r
1012 } while(tk_Token != TK_COMMA && tk_Token != TK_SEMICOLON);
\r
1016 if (tk_Token == TK_RBRACKET)
\r
1018 ERR_Error(ERR_NEED_ARRAY_SIZE, YES);
\r
1022 dims[ndim] = EvalConstExpression();
\r
1023 if(dims[ndim] == 0)
\r
1025 ERR_Error(ERR_ZERO_DIMENSION, YES);
\r
1030 size = dims[ndim];
\r
1034 size *= dims[ndim];
\r
1038 TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET);
\r
1043 if(ImportMode != IMPORT_Importing)
\r
1045 PC_AddArray(index, size);
\r
1047 MS_Message(MSG_DEBUG, "%s changed to an array of size %d\n", sym->name, size);
\r
1048 sym->type = SY_MAPARRAY;
\r
1049 sym->info.array.index = index;
\r
1050 sym->info.array.ndim = ndim;
\r
1051 sym->info.array.size = size;
\r
1054 sym->info.array.dimensions[ndim-1] = 1;
\r
1055 for(i = ndim - 2; i >= 0; --i)
\r
1057 sym->info.array.dimensions[i] =
\r
1058 sym->info.array.dimensions[i+1] * dims[i+1];
\r
1061 MS_Message(MSG_DEBUG, " - with multipliers ");
\r
1062 for(i = 0; i < ndim; ++i)
\r
1064 MS_Message(MSG_DEBUG, "[%d]", sym->info.array.dimensions[i]);
\r
1066 MS_Message(MSG_DEBUG, "\n");
\r
1067 if(tk_Token == TK_ASSIGN)
\r
1069 InitializeArray(sym, dims, size);
\r
1073 } while(tk_Token == TK_COMMA);
\r
1074 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1078 //==========================================================================
\r
1082 //==========================================================================
\r
1084 static void OuterWorldVar(boolean isGlobal)
\r
1087 symbolNode_t *sym;
\r
1089 MS_Message(MSG_DEBUG, "---- Outer%sVar ----\n", isGlobal ? "Global" : "World");
\r
1090 if(TK_NextToken() != TK_INT)
\r
1092 if(tk_Token != TK_BOOL)
\r
1094 TK_TokenMustBe(TK_STR, ERR_BAD_VAR_TYPE);
\r
1099 TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_WVAR_INDEX);
\r
1100 if(tk_Number >= (isGlobal ? MAX_GLOBAL_VARIABLES : MAX_WORLD_VARIABLES))
\r
1102 ERR_Error(ERR_BAD_WVAR_INDEX+isGlobal, YES);
\r
1107 index = tk_Number;
\r
1109 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_WVAR_COLON+isGlobal);
\r
1110 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
1111 if(SY_FindGlobal(tk_String) != NULL)
\r
1113 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);
\r
1118 if(tk_Token == TK_LBRACKET)
\r
1121 if(tk_Token != TK_RBRACKET)
\r
1123 ERR_Error(ERR_NO_NEED_ARRAY_SIZE, YES);
\r
1124 TK_SkipPast(TK_RBRACKET);
\r
1130 if(tk_Token == TK_LBRACKET)
\r
1132 ERR_Error(ERR_NO_MULTIDIMENSIONS, YES);
\r
1135 TK_SkipPast(TK_RBRACKET);
\r
1137 while(tk_Token == TK_LBRACKET);
\r
1139 sym = SY_InsertGlobal(tk_String, isGlobal ? SY_GLOBALARRAY : SY_WORLDARRAY);
\r
1140 sym->info.array.index = index;
\r
1141 sym->info.array.ndim = 1;
\r
1142 sym->info.array.size = 0x7fffffff; // not used
\r
1143 memset(sym->info.array.dimensions, 0, sizeof(sym->info.array.dimensions));
\r
1146 pa_GlobalArrayCount++;
\r
1148 pa_WorldArrayCount++;
\r
1152 sym = SY_InsertGlobal(tk_String, isGlobal ? SY_GLOBALVAR : SY_WORLDVAR);
\r
1153 sym->info.var.index = index;
\r
1155 pa_GlobalVarCount++;
\r
1157 pa_WorldVarCount++;
\r
1160 } while(tk_Token == TK_COMMA);
\r
1161 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1165 //==========================================================================
\r
1167 // OuterSpecialDef
\r
1169 //==========================================================================
\r
1171 static void OuterSpecialDef(void)
\r
1174 symbolNode_t *sym;
\r
1176 MS_Message(MSG_DEBUG, "---- OuterSpecialDef ----\n");
\r
1177 if(ImportMode == IMPORT_Importing)
\r
1179 // No need to process special definitions when importing.
\r
1180 TK_SkipPast(TK_SEMICOLON);
\r
1186 if (TK_NextToken() == TK_MINUS)
\r
1188 TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_VAL);
\r
1189 special = -tk_Number;
\r
1193 TK_TokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_VAL);
\r
1194 special = tk_Number;
\r
1196 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_SPEC_COLON);
\r
1197 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
1198 sym = SY_InsertGlobalUnique(tk_String, SY_SPECIAL);
\r
1199 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
1200 TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_ARGC);
\r
1201 sym->info.special.value = special;
\r
1202 sym->info.special.argCount = tk_Number | (tk_Number << 16);
\r
1204 if(tk_Token == TK_COMMA)
\r
1205 { // Get maximum arg count
\r
1206 TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_ARGC);
\r
1207 sym->info.special.argCount =
\r
1208 (sym->info.special.argCount & 0xffff) | (tk_Number << 16);
\r
1214 TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
1216 } while(tk_Token == TK_COMMA);
\r
1217 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1222 //==========================================================================
\r
1226 //==========================================================================
\r
1228 static void OuterDefine(boolean force)
\r
1231 symbolNode_t *sym;
\r
1233 MS_Message(MSG_DEBUG, "---- OuterDefine %s----\n",
\r
1234 force ? "(forced) " : "");
\r
1235 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
1236 sym = SY_InsertGlobalUnique(tk_String, SY_CONSTANT);
\r
1238 value = EvalConstExpression();
\r
1239 MS_Message(MSG_DEBUG, "Constant value: %d\n", value);
\r
1240 sym->info.constant.value = value;
\r
1241 // Defines inside an import are deleted when the import is popped.
\r
1242 if(ImportMode != IMPORT_Importing || force)
\r
1244 sym->info.constant.fileDepth = 0;
\r
1248 sym->info.constant.fileDepth = TK_GetDepth();
\r
1252 //==========================================================================
\r
1256 //==========================================================================
\r
1258 static void OuterInclude(void)
\r
1260 // Don't include inside an import
\r
1261 if(ImportMode != IMPORT_Importing)
\r
1263 MS_Message(MSG_DEBUG, "---- OuterInclude ----\n");
\r
1264 TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND);
\r
1265 TK_Include(tk_String);
\r
1274 //==========================================================================
\r
1278 //==========================================================================
\r
1280 static void OuterImport(void)
\r
1283 MS_Message(MSG_DEBUG, "---- OuterImport ----\n");
\r
1284 if(ImportMode == IMPORT_Importing)
\r
1286 // Don't import inside an import
\r
1291 MS_Message(MSG_DEBUG, "Importing a file\n");
\r
1292 TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND);
\r
1293 TK_Import(tk_String, ImportMode);
\r
1298 //==========================================================================
\r
1300 // ProcessStatement
\r
1302 //==========================================================================
\r
1304 static boolean ProcessStatement(statement_t owner)
\r
1306 if(StatementIndex == MAX_STATEMENT_DEPTH)
\r
1308 ERR_Exit(ERR_STATEMENT_OVERFLOW, YES);
\r
1310 StatementHistory[StatementIndex++] = owner;
\r
1311 StatementLevel += AdjustStmtLevel[owner];
\r
1318 LeadingVarDeclare();
\r
1320 case TK_LINESPECIAL:
\r
1321 if (tk_SpecialValue >= 0)
\r
1323 LeadingLineSpecial(NO);
\r
1327 LeadingFunction(NO);
\r
1330 case TK_ACSEXECUTEWAIT:
\r
1331 tk_SpecialArgCount = 1 | (5<<16);
\r
1332 tk_SpecialValue = 80;
\r
1333 LeadingLineSpecial(YES);
\r
1335 case TK_ACSNAMEDEXECUTEWAIT:
\r
1336 tk_SpecialArgCount = 1 | (5<<16);
\r
1337 tk_SpecialValue = -39;
\r
1338 LeadingFunction(YES);
\r
1346 case TK_TERMINATE:
\r
1347 LeadingTerminate();
\r
1352 case TK_IDENTIFIER:
\r
1353 LeadingIdentifier();
\r
1356 case TK_PRINTBOLD:
\r
1361 case TK_STRPARAM_EVAL:
\r
1363 PC_AppendCmd(PCD_DROP);
\r
1364 /* Duplicate code: LeadingPrint() post-processing: */
\r
1365 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1371 PC_AppendCmd(PCD_DROP);
\r
1372 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1376 case TK_HUDMESSAGE:
\r
1377 case TK_HUDMESSAGEBOLD:
\r
1378 LeadingHudMessage();
\r
1388 LeadingWhileUntil();
\r
1397 if(owner != STMT_SWITCH)
\r
1399 ERR_Error(ERR_CASE_NOT_IN_SWITCH, YES);
\r
1400 TK_SkipPast(TK_COLON);
\r
1408 if(owner != STMT_SWITCH)
\r
1410 ERR_Error(ERR_DEFAULT_NOT_IN_SWITCH, YES);
\r
1411 TK_SkipPast(TK_COLON);
\r
1413 else if(DefaultInCurrent() == YES)
\r
1415 ERR_Error(ERR_MULTIPLE_DEFAULT, YES);
\r
1416 TK_SkipPast(TK_COLON);
\r
1424 if(BreakAncestor() == NO)
\r
1426 ERR_Error(ERR_MISPLACED_BREAK, YES);
\r
1427 TK_SkipPast(TK_SEMICOLON);
\r
1435 if(ContinueAncestor() == NO)
\r
1437 ERR_Error(ERR_MISPLACED_CONTINUE, YES);
\r
1438 TK_SkipPast(TK_SEMICOLON);
\r
1442 LeadingContinue();
\r
1445 case TK_CREATETRANSLATION:
\r
1446 LeadingCreateTranslation();
\r
1449 LeadingCompoundStatement(owner);
\r
1451 case TK_SEMICOLON:
\r
1456 LeadingIncDec(tk_Token);
\r
1461 StatementLevel -= AdjustStmtLevel[owner];
\r
1466 StatementLevel -= AdjustStmtLevel[owner];
\r
1470 //==========================================================================
\r
1472 // LeadingCompoundStatement
\r
1474 //==========================================================================
\r
1476 static void LeadingCompoundStatement(statement_t owner)
\r
1478 //StatementLevel += AdjustStmtLevel[owner];
\r
1479 TK_NextToken(); // Eat the TK_LBRACE
\r
1480 do {} while(ProcessStatement(owner) == YES);
\r
1481 TK_TokenMustBe(TK_RBRACE, ERR_INVALID_STATEMENT);
\r
1483 //StatementLevel -= AdjustStmtLevel[owner];
\r
1486 //==========================================================================
\r
1488 // LeadingVarDeclare
\r
1490 //==========================================================================
\r
1492 static void LeadingVarDeclare(void)
\r
1494 symbolNode_t *sym = NULL;
\r
1496 if(tk_Token == TK_STATIC)
\r
1499 if(tk_Token != TK_INT && tk_Token != TK_STR && tk_Token != TK_BOOL)
\r
1501 ERR_Error(ERR_BAD_VAR_TYPE, YES);
\r
1508 MS_Message(MSG_DEBUG, "---- LeadingVarDeclare ----\n");
\r
1511 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER);
\r
1513 if(ScriptVarCount == MAX_SCRIPT_VARIABLES)
\r
1515 ERR_Error(InsideFunction
\r
1516 ? ERR_TOO_MANY_FUNCTION_VARS
\r
1517 : ERR_TOO_MANY_SCRIPT_VARS,
\r
1523 if(SY_FindLocal(tk_String) != NULL)
\r
1525 ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String);
\r
1529 sym = SY_InsertLocal(tk_String, SY_SCRIPTVAR);
\r
1530 sym->info.var.index = ScriptVarCount;
\r
1534 if(tk_Token == TK_LBRACKET)
\r
1536 ERR_Error(ERR_ARRAY_MAPVAR_ONLY, YES);
\r
1537 do {} while(TK_NextToken() != TK_COMMA && tk_Token != TK_SEMICOLON);
\r
1539 else if(tk_Token == TK_ASSIGN)
\r
1545 PC_AppendCmd(PCD_ASSIGNSCRIPTVAR);
\r
1546 PC_AppendShrink(sym->info.var.index);
\r
1549 } while(tk_Token == TK_COMMA);
\r
1550 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1554 //==========================================================================
\r
1556 // LeadingLineSpecial
\r
1558 //==========================================================================
\r
1560 static void LeadingLineSpecial(boolean executewait)
\r
1567 U_INT specialValue;
\r
1570 MS_Message(MSG_DEBUG, "---- LeadingLineSpecial ----\n");
\r
1571 argCountMin = tk_SpecialArgCount & 0xffff;
\r
1572 argCountMax = tk_SpecialArgCount >> 16;
\r
1573 specialValue = tk_SpecialValue;
\r
1574 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
1576 if(argCountMax > 0)
\r
1578 if(TK_NextToken() == TK_CONST)
\r
1580 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
1590 if(i == argCountMax)
\r
1592 ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES);
\r
1593 i = argCountMax+1;
\r
1598 argSave[i] = EvalConstExpression();
\r
1603 if (i == 0 && executewait)
\r
1605 PC_AppendCmd(PCD_DUP);
\r
1608 if(i < argCountMax)
\r
1612 } while(tk_Token == TK_COMMA);
\r
1613 if(i < argCountMin)
\r
1615 ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES);
\r
1616 TK_SkipPast(TK_SEMICOLON);
\r
1623 // [RH] I added some zero-argument specials without realizing that
\r
1624 // ACS won't allow for less than one, so fake them as one-argument
\r
1625 // specials with a parameter of 0.
\r
1631 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
1632 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1635 PC_AppendCmd(PCD_LSPEC1+(argCount-1));
\r
1638 PC_AppendInt(specialValue);
\r
1642 if (specialValue > 255)
\r
1644 ERR_Error(ERR_SPECIAL_RANGE, YES);
\r
1646 PC_AppendByte((U_BYTE)specialValue);
\r
1650 PC_AppendCmd(PCD_SCRIPTWAIT);
\r
1655 boolean useintform;
\r
1659 PC_AppendCmd(PCD_LSPEC1DIRECT+(argCount-1));
\r
1660 PC_AppendInt(specialValue);
\r
1666 for (i = 0; i < argCount; i++)
\r
1668 if ((U_INT)argSave[i] > 255)
\r
1674 PC_AppendCmd((argCount-1)+(useintform?PCD_LSPEC1DIRECT:PCD_LSPEC1DIRECTB));
\r
1675 PC_AppendByte((U_BYTE)specialValue);
\r
1679 for (i = 0; i < argCount; i++)
\r
1681 PC_AppendInt(argSave[i]);
\r
1686 for (i = 0; i < argCount; i++)
\r
1688 PC_AppendByte((U_BYTE)argSave[i]);
\r
1693 PC_AppendCmd(PCD_SCRIPTWAITDIRECT);
\r
1694 PC_AppendInt(argSave[0]);
\r
1700 //==========================================================================
\r
1702 // LeadingLineSpecial
\r
1704 //==========================================================================
\r
1706 static void LeadingFunction(boolean executewait)
\r
1714 MS_Message(MSG_DEBUG, "---- LeadingFunction ----\n");
\r
1715 argCountMin = tk_SpecialArgCount & 0xffff;
\r
1716 argCountMax = tk_SpecialArgCount >> 16;
\r
1717 specialValue = -tk_SpecialValue;
\r
1718 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
1720 if(argCountMax > 0)
\r
1722 if(TK_NextToken() == TK_CONST)
\r
1724 // Just skip const declarators
\r
1725 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
1733 if(i == argCountMax)
\r
1735 ERR_Error(ERR_BAD_ARG_COUNT, YES);
\r
1736 i = argCountMax+1;
\r
1740 if (i == 0 && executewait)
\r
1742 PC_AppendCmd(PCD_DUP);
\r
1744 if(i < argCountMax)
\r
1748 } while(tk_Token == TK_COMMA);
\r
1749 if(i < argCountMin)
\r
1751 ERR_Error(ERR_BAD_ARG_COUNT, YES);
\r
1752 TK_SkipPast(TK_SEMICOLON);
\r
1762 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
1763 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1764 PC_AppendCmd(PCD_CALLFUNC);
\r
1767 PC_AppendInt(argCount);
\r
1768 PC_AppendInt(specialValue);
\r
1772 PC_AppendByte((U_BYTE)argCount);
\r
1773 PC_AppendWord((U_WORD)specialValue);
\r
1775 PC_AppendCmd(PCD_DROP);
\r
1778 PC_AppendCmd(PCD_SCRIPTWAITNAMED);
\r
1783 //==========================================================================
\r
1785 // LeadingIdentifier
\r
1787 //==========================================================================
\r
1789 static void LeadingIdentifier(void)
\r
1791 symbolNode_t *sym;
\r
1793 sym = SpeculateSymbol(tk_String, NO);
\r
1797 case SY_SCRIPTVAR:
\r
1798 case SY_SCRIPTALIAS:
\r
1801 case SY_GLOBALVAR:
\r
1802 case SY_WORLDARRAY:
\r
1803 case SY_GLOBALARRAY:
\r
1804 LeadingVarAssign(sym);
\r
1806 case SY_INTERNFUNC:
\r
1807 LeadingInternFunc(sym);
\r
1809 case SY_SCRIPTFUNC:
\r
1810 LeadingScriptFunc(sym);
\r
1817 //==========================================================================
\r
1819 // LeadingInternFunc
\r
1821 //==========================================================================
\r
1823 static void LeadingInternFunc(symbolNode_t *sym)
\r
1825 if(InsideFunction && sym->info.internFunc.latent)
\r
1827 ERR_Error(ERR_LATENT_IN_FUNC, YES);
\r
1829 ProcessInternFunc(sym);
\r
1830 if(sym->info.internFunc.hasReturnValue == YES)
\r
1832 PC_AppendCmd(PCD_DROP);
\r
1834 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
1838 //==========================================================================
\r
1840 // ProcessInternFunc
\r
1842 //==========================================================================
\r
1844 static void ProcessInternFunc(symbolNode_t *sym)
\r
1851 boolean specialDirect;
\r
1854 MS_Message(MSG_DEBUG, "---- ProcessInternFunc ----\n");
\r
1855 argCount = sym->info.internFunc.argCount;
\r
1856 optMask = sym->info.internFunc.optMask;
\r
1857 outMask = sym->info.internFunc.outMask;
\r
1858 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
1859 if(TK_NextToken() == TK_CONST)
\r
1861 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
1862 if(sym->info.internFunc.directCommand == PCD_NOP)
\r
1864 ERR_Error(ERR_NO_DIRECT_VER, YES, NULL);
\r
1866 specialDirect = NO;
\r
1871 if (pc_NoShrink || argCount > 2 ||
\r
1872 (sym->info.internFunc.directCommand != PCD_DELAYDIRECT &&
\r
1873 sym->info.internFunc.directCommand != PCD_RANDOMDIRECT))
\r
1875 specialDirect = NO;
\r
1876 PC_AppendCmd(sym->info.internFunc.directCommand);
\r
1880 specialDirect = YES;
\r
1888 specialDirect = NO; // keep GCC quiet
\r
1893 if(tk_Token == TK_RPAREN)
\r
1895 ERR_Error(ERR_MISSING_PARAM, YES);
\r
1899 TK_Undo(); // Adjust for first expression
\r
1904 ERR_Error(ERR_BAD_ARG_COUNT, YES);
\r
1905 TK_SkipTo(TK_SEMICOLON);
\r
1912 if (tk_Token != TK_COMMA)
\r
1914 if (specialDirect)
\r
1916 argSave[i] = EvalConstExpression();
\r
1920 PC_AppendInt(EvalConstExpression());
\r
1927 if (specialDirect)
\r
1938 ERR_Error(ERR_MISSING_PARAM, YES);
\r
1944 if (tk_Token != TK_COMMA)
\r
1946 if (!(outMask & 1))
\r
1950 else if (tk_Token != TK_IDENTIFIER)
\r
1952 ERR_Error (ERR_PARM_MUST_BE_VAR, YES);
\r
1956 } while (tk_Token != TK_COMMA && tk_Token != TK_RPAREN);
\r
1960 symbolNode_t *sym = DemandSymbol (tk_String);
\r
1961 PC_AppendCmd (PCD_PUSHNUMBER);
\r
1962 switch (sym->type)
\r
1964 case SY_SCRIPTVAR:
\r
1965 PC_AppendInt(sym->info.var.index | OUTVAR_SCRIPT_SPEC);
\r
1968 PC_AppendInt(sym->info.var.index | OUTVAR_MAP_SPEC);
\r
1971 PC_AppendInt(sym->info.var.index | OUTVAR_WORLD_SPEC);
\r
1973 case SY_GLOBALVAR:
\r
1974 PC_AppendInt(sym->info.var.index | OUTVAR_GLOBAL_SPEC);
\r
1977 ERR_Error (ERR_PARM_MUST_BE_VAR, YES);
\r
1981 } while (tk_Token != TK_COMMA && tk_Token != TK_RPAREN);
\r
1991 PC_AppendPushVal(0);
\r
1995 ERR_Error(ERR_MISSING_PARAM, YES);
\r
2002 } while(tk_Token == TK_COMMA);
\r
2005 while (i < argCount && (optMask & 1))
\r
2007 if (direct == YES)
\r
2009 if (specialDirect)
\r
2020 PC_AppendPushVal(0);
\r
2025 if(i != argCount && i > 0)
\r
2027 ERR_Error(ERR_BAD_ARG_COUNT, YES);
\r
2029 TK_TokenMustBe(TK_RPAREN, argCount > 0 ? ERR_MISSING_RPAREN : ERR_BAD_ARG_COUNT);
\r
2032 PC_AppendCmd(sym->info.internFunc.stackCommand);
\r
2034 else if (specialDirect)
\r
2036 boolean useintform = NO;
\r
2039 switch (sym->info.internFunc.directCommand)
\r
2041 case PCD_DELAYDIRECT:
\r
2042 shortpcd = PCD_DELAYDIRECTB;
\r
2044 case PCD_RANDOMDIRECT:
\r
2045 shortpcd = PCD_RANDOMDIRECTB;
\r
2049 shortpcd = PCD_NOP;
\r
2055 for (i = 0; i < argCount; i++)
\r
2057 if ((U_INT)argSave[i] > 255)
\r
2067 PC_AppendCmd(sym->info.internFunc.directCommand);
\r
2068 for (i = 0; i < argCount; i++)
\r
2070 PC_AppendInt (argSave[i]);
\r
2075 PC_AppendCmd (shortpcd);
\r
2076 for (i = 0; i < argCount; i++)
\r
2078 PC_AppendByte ((U_BYTE)argSave[i]);
\r
2085 //==========================================================================
\r
2087 // LeadingScriptFunc
\r
2089 //==========================================================================
\r
2091 static void LeadingScriptFunc(symbolNode_t *sym)
\r
2093 ProcessScriptFunc(sym, YES);
\r
2094 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2099 //==========================================================================
\r
2101 // ProcessScriptFunc
\r
2103 //==========================================================================
\r
2105 static void ProcessScriptFunc(symbolNode_t *sym, boolean discardReturn)
\r
2110 MS_Message(MSG_DEBUG, "---- ProcessScriptFunc ----\n");
\r
2111 argCount = sym->info.scriptFunc.argCount;
\r
2112 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2116 TK_NextTokenMustBe(TK_RPAREN, ERR_BAD_ARG_COUNT);
\r
2118 else if(argCount > 0)
\r
2121 if(tk_Token == TK_RPAREN)
\r
2123 ERR_Error(ERR_BAD_ARG_COUNT, YES);
\r
2124 TK_SkipTo(TK_SEMICOLON);
\r
2132 ERR_Error(ERR_BAD_ARG_COUNT, YES);
\r
2133 TK_SkipTo(TK_SEMICOLON);
\r
2137 if (tk_Token != TK_COMMA)
\r
2143 ERR_Error(ERR_MISSING_PARAM, YES);
\r
2144 TK_SkipTo(TK_SEMICOLON);
\r
2148 } while(tk_Token == TK_COMMA);
\r
2151 { // Function has not been defined yet, so assume arg count is correct
\r
2153 while (tk_Token != TK_RPAREN)
\r
2157 if (tk_Token == TK_COMMA)
\r
2161 else if (tk_Token != TK_RPAREN)
\r
2163 ERR_Error(ERR_MISSING_PARAM, YES);
\r
2164 TK_SkipTo(TK_SEMICOLON);
\r
2169 else if(i != argCount)
\r
2171 ERR_Error(ERR_BAD_ARG_COUNT, YES);
\r
2172 TK_SkipTo(TK_SEMICOLON);
\r
2175 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2176 PC_AppendCmd(discardReturn ? PCD_CALLDISCARD : PCD_CALL);
\r
2177 if(sym->info.scriptFunc.predefined && ImportMode != IMPORT_Importing)
\r
2179 AddScriptFuncRef(sym, pc_Address, i);
\r
2183 PC_AppendInt(sym->info.scriptFunc.funcNumber);
\r
2187 PC_AppendByte((U_BYTE)sym->info.scriptFunc.funcNumber);
\r
2192 //==========================================================================
\r
2194 // BuildPrintString
\r
2196 //==========================================================================
\r
2198 static void BuildPrintString(void)
\r
2204 switch(TK_NextCharacter())
\r
2206 case 'a': // character array support [JB]
\r
2207 ActionOnCharRange(NO);
\r
2209 case 's': // string
\r
2210 printCmd = PCD_PRINTSTRING;
\r
2212 case 'l': // [RH] localized string
\r
2213 printCmd = PCD_PRINTLOCALIZED;
\r
2215 case 'i': // integer
\r
2216 case 'd': // decimal
\r
2217 printCmd = PCD_PRINTNUMBER;
\r
2219 case 'c': // character
\r
2220 printCmd = PCD_PRINTCHARACTER;
\r
2222 case 'n': // [BC] name
\r
2223 printCmd = PCD_PRINTNAME;
\r
2225 case 'f': // [RH] fixed point
\r
2226 printCmd = PCD_PRINTFIXED;
\r
2228 case 'k': // [GRB] key binding
\r
2229 printCmd = PCD_PRINTBIND;
\r
2231 case 'b': // [RH] binary integer
\r
2232 printCmd = PCD_PRINTBINARY;
\r
2234 case 'x': // [RH] hexadecimal integer
\r
2235 printCmd = PCD_PRINTHEX;
\r
2238 printCmd = PCD_PRINTSTRING;
\r
2239 ERR_Error(ERR_UNKNOWN_PRTYPE, YES);
\r
2242 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2245 PC_AppendCmd(printCmd);
\r
2246 } while(tk_Token == TK_COMMA);
\r
2249 //==========================================================================
\r
2251 // ActionOnCharRange // FDARI (mutation of PrintCharArray // JB)
\r
2253 //==========================================================================
\r
2255 static void ActionOnCharRange(boolean write)
\r
2257 boolean rangeConstraints;
\r
2258 symbolNode_t *sym;
\r
2259 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2262 if (tk_Token == TK_LPAREN)
\r
2264 rangeConstraints = YES;
\r
2269 rangeConstraints = NO;
\r
2272 sym = SpeculateSymbol(tk_String, NO);
\r
2273 if((sym->type != SY_MAPARRAY) && (sym->type != SY_WORLDARRAY)
\r
2274 && (sym->type != SY_GLOBALARRAY))
\r
2276 ERR_Error(ERR_NOT_AN_ARRAY, YES);
\r
2279 if(sym->info.array.ndim > 1)
\r
2281 ParseArrayIndices(sym, sym->info.array.ndim-1);
\r
2285 PC_AppendPushVal(0);
\r
2288 PC_AppendPushVal(sym->info.array.index);
\r
2291 if (rangeConstraints)
\r
2296 rangeConstraints = NO;
\r
2307 PC_AppendPushVal(0x7FFFFFFF);
\r
2311 EvalExpression(); // limit on capacity
\r
2312 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2316 ERR_Error(ERR_MISSING_RPAREN, YES);
\r
2322 ERR_Error(ERR_MISSING_RPAREN, YES);
\r
2329 if (!rangeConstraints)
\r
2331 PC_AppendPushVal(0);
\r
2332 PC_AppendPushVal(0x7FFFFFFF);
\r
2335 TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA);
\r
2339 if (tk_Token == TK_COMMA)
\r
2346 PC_AppendPushVal(0);
\r
2350 if(sym->type == SY_MAPARRAY)
\r
2352 if (write) PC_AppendCmd(PCD_STRCPYTOMAPCHRANGE);
\r
2353 else PC_AppendCmd( rangeConstraints ? PCD_PRINTMAPCHRANGE : PCD_PRINTMAPCHARARRAY );
\r
2355 else if(sym->type == SY_WORLDARRAY)
\r
2357 if (write) PC_AppendCmd(PCD_STRCPYTOWORLDCHRANGE);
\r
2358 else PC_AppendCmd( rangeConstraints ? PCD_PRINTWORLDCHRANGE : PCD_PRINTWORLDCHARARRAY );
\r
2360 else // if(sym->type == SY_GLOBALARRAY)
\r
2362 if (write) PC_AppendCmd(PCD_STRCPYTOGLOBALCHRANGE);
\r
2363 else PC_AppendCmd( rangeConstraints ? PCD_PRINTGLOBALCHRANGE : PCD_PRINTGLOBALCHARARRAY );
\r
2367 //==========================================================================
\r
2371 //==========================================================================
\r
2373 static void LeadingStrcpy(void)
\r
2375 MS_Message(MSG_DEBUG, "---- LeadingStrcpy ----\n");
\r
2376 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2378 switch(TK_NextCharacter()) // structure borrowed from printbuilder
\r
2381 ActionOnCharRange(YES);
\r
2385 ERR_Error(ERR_UNKNOWN_PRTYPE, YES);
\r
2389 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2392 //==========================================================================
\r
2396 //==========================================================================
\r
2398 static void LeadingPrint(void)
\r
2400 tokenType_t stmtToken;
\r
2402 MS_Message(MSG_DEBUG, "---- LeadingPrint ----\n");
\r
2403 stmtToken = tk_Token; // Will be TK_PRINT or TK_PRINTBOLD, TK_LOG or TK_STRPARAM_EVAL [FDARI]
\r
2404 PC_AppendCmd(PCD_BEGINPRINT);
\r
2405 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2406 BuildPrintString();
\r
2407 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2409 switch (stmtToken)
\r
2412 PC_AppendCmd(PCD_ENDPRINT);
\r
2415 case TK_PRINTBOLD:
\r
2416 PC_AppendCmd(PCD_ENDPRINTBOLD);
\r
2419 case TK_STRPARAM_EVAL:
\r
2420 PC_AppendCmd(PCD_SAVESTRING);
\r
2421 return; // THE CALLER MUST DO THE POST-PROCESSING
\r
2425 PC_AppendCmd(PCD_ENDLOG);
\r
2429 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2433 //==========================================================================
\r
2435 // LeadingHudMessage
\r
2437 // hudmessage(str text; int type, int id, int color, fixed x, fixed y, fixed holdtime, ...)
\r
2439 //==========================================================================
\r
2441 static void LeadingHudMessage(void)
\r
2443 tokenType_t stmtToken;
\r
2446 MS_Message(MSG_DEBUG, "---- LeadingHudMessage ----\n");
\r
2447 stmtToken = tk_Token; // Will be TK_HUDMESSAGE or TK_HUDMESSAGEBOLD
\r
2448 PC_AppendCmd(PCD_BEGINPRINT);
\r
2449 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2450 BuildPrintString();
\r
2451 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_PARAM);
\r
2452 PC_AppendCmd(PCD_MOREHUDMESSAGE);
\r
2453 for (i = 6; i > 0; i--)
\r
2458 TK_TokenMustBe(TK_COMMA, ERR_MISSING_PARAM);
\r
2460 if (tk_Token == TK_COMMA)
\r
2461 { // HUD message has optional parameters
\r
2462 PC_AppendCmd(PCD_OPTHUDMESSAGE);
\r
2467 } while (tk_Token == TK_COMMA);
\r
2469 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2470 PC_AppendCmd(stmtToken == TK_HUDMESSAGE ?
\r
2471 PCD_ENDHUDMESSAGE : PCD_ENDHUDMESSAGEBOLD);
\r
2472 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2476 //==========================================================================
\r
2478 // LeadingCreateTranslation
\r
2480 // Simple grammar:
\r
2482 // tranlationstmt: CreateTranslation ( exp opt_args ) ;
\r
2483 // opt_args: /* empty: just reset the translation */ | , arglist
\r
2484 // arglist: arg | arglist arg
\r
2485 // arg: range = replacement
\r
2486 // range: exp : exp
\r
2487 // replacement: palrep | colorrep
\r
2488 // palrep: exp : exp
\r
2489 // colorrep: [exp,exp,exp]:[exp,exp,exp]
\r
2490 // desatrep: %colorrep
\r
2491 //==========================================================================
\r
2493 static void LeadingCreateTranslation(void)
\r
2495 MS_Message(MSG_DEBUG, "---- LeadingCreateTranslation ----\n");
\r
2496 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2499 PC_AppendCmd(PCD_STARTTRANSLATION);
\r
2500 while (tk_Token == TK_COMMA)
\r
2502 pcd_t translationcode;
\r
2505 EvalExpression(); // Get first palette entry in range
\r
2506 TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2508 EvalExpression(); // Get second palette entry in range
\r
2509 TK_TokenMustBe(TK_ASSIGN, ERR_MISSING_ASSIGN);
\r
2512 if(tk_Token == TK_PERCENT)
\r
2514 translationcode = PCD_TRANSLATIONRANGE3;
\r
2515 TK_NextTokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET);
\r
2519 translationcode = PCD_TRANSLATIONRANGE2;
\r
2521 if(tk_Token == TK_LBRACKET)
\r
2522 { // Replacement is color range
\r
2527 for(j = 2; j != 0; --j)
\r
2529 for(i = 3; i != 0; --i)
\r
2534 TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA);
\r
2538 TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET);
\r
2544 TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2545 TK_NextTokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET);
\r
2551 { // Replacement is palette range
\r
2553 TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2556 translationcode = PCD_TRANSLATIONRANGE1;
\r
2558 PC_AppendCmd(translationcode);
\r
2560 PC_AppendCmd(PCD_ENDTRANSLATION);
\r
2561 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2562 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2566 //==========================================================================
\r
2570 //==========================================================================
\r
2572 static void LeadingIf(void)
\r
2577 MS_Message(MSG_DEBUG, "---- LeadingIf ----\n");
\r
2578 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2581 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2582 PC_AppendCmd(PCD_IFNOTGOTO);
\r
2583 jumpAddrPtr1 = pc_Address;
\r
2586 if(ProcessStatement(STMT_IF) == NO)
\r
2588 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
2590 if(tk_Token == TK_ELSE)
\r
2592 PC_AppendCmd(PCD_GOTO);
\r
2593 jumpAddrPtr2 = pc_Address;
\r
2595 PC_WriteInt(pc_Address, jumpAddrPtr1);
\r
2597 if(ProcessStatement(STMT_ELSE) == NO)
\r
2599 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
2601 PC_WriteInt(pc_Address, jumpAddrPtr2);
\r
2605 PC_WriteInt(pc_Address, jumpAddrPtr1);
\r
2609 //==========================================================================
\r
2613 //==========================================================================
\r
2615 static void LeadingFor(void)
\r
2622 MS_Message(MSG_DEBUG, "---- LeadingFor ----\n");
\r
2623 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2625 if(ProcessStatement(STMT_IF) == NO)
\r
2627 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
2629 exprAddr = pc_Address;
\r
2631 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2633 PC_AppendCmd(PCD_IFGOTO);
\r
2634 ifgotoAddr = pc_Address;
\r
2636 PC_AppendCmd(PCD_GOTO);
\r
2637 gotoAddr = pc_Address;
\r
2639 incAddr = pc_Address;
\r
2640 forSemicolonHack = TRUE;
\r
2641 if(ProcessStatement(STMT_IF) == NO)
\r
2643 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
2645 forSemicolonHack = FALSE;
\r
2646 PC_AppendCmd(PCD_GOTO);
\r
2647 PC_AppendInt(exprAddr);
\r
2648 PC_WriteInt(pc_Address,ifgotoAddr);
\r
2649 if(ProcessStatement(STMT_FOR) == NO)
\r
2651 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
2653 PC_AppendCmd(PCD_GOTO);
\r
2654 PC_AppendInt(incAddr);
\r
2655 WriteContinues(incAddr);
\r
2657 PC_WriteInt(pc_Address,gotoAddr);
\r
2660 //==========================================================================
\r
2662 // LeadingWhileUntil
\r
2664 //==========================================================================
\r
2666 static void LeadingWhileUntil(void)
\r
2668 tokenType_t stmtToken;
\r
2672 MS_Message(MSG_DEBUG, "---- LeadingWhileUntil ----\n");
\r
2673 stmtToken = tk_Token;
\r
2674 topAddr = pc_Address;
\r
2675 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2678 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2679 PC_AppendCmd(stmtToken == TK_WHILE ? PCD_IFNOTGOTO : PCD_IFGOTO);
\r
2680 outAddrPtr = pc_Address;
\r
2683 if(ProcessStatement(STMT_WHILEUNTIL) == NO)
\r
2685 ERR_Error(ERR_INVALID_STATEMENT, YES);
\r
2687 PC_AppendCmd(PCD_GOTO);
\r
2688 PC_AppendInt(topAddr);
\r
2690 PC_WriteInt(pc_Address, outAddrPtr);
\r
2692 WriteContinues(topAddr);
\r
2696 //==========================================================================
\r
2700 //==========================================================================
\r
2702 static void LeadingDo(void)
\r
2706 tokenType_t stmtToken;
\r
2708 MS_Message(MSG_DEBUG, "---- LeadingDo ----\n");
\r
2709 topAddr = pc_Address;
\r
2711 if(ProcessStatement(STMT_DO) == NO)
\r
2713 ERR_Error(ERR_INVALID_STATEMENT, YES, NULL);
\r
2715 if(tk_Token != TK_WHILE && tk_Token != TK_UNTIL)
\r
2717 ERR_Error(ERR_BAD_DO_STATEMENT, YES, NULL);
\r
2718 TK_SkipPast(TK_SEMICOLON);
\r
2721 stmtToken = tk_Token;
\r
2722 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2723 exprAddr = pc_Address;
\r
2726 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2727 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2728 PC_AppendCmd(stmtToken == TK_WHILE ? PCD_IFGOTO : PCD_IFNOTGOTO);
\r
2729 PC_AppendInt(topAddr);
\r
2730 WriteContinues(exprAddr);
\r
2735 //==========================================================================
\r
2739 //==========================================================================
\r
2741 static void LeadingSwitch(void)
\r
2743 int switcherAddrPtr;
\r
2745 caseInfo_t *cInfo;
\r
2746 int defaultAddress;
\r
2748 MS_Message(MSG_DEBUG, "---- LeadingSwitch ----\n");
\r
2750 TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN);
\r
2753 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
2755 PC_AppendCmd(PCD_GOTO);
\r
2756 switcherAddrPtr = pc_Address;
\r
2760 if(ProcessStatement(STMT_SWITCH) == NO)
\r
2762 ERR_Error(ERR_INVALID_STATEMENT, YES, NULL);
\r
2765 PC_AppendCmd(PCD_GOTO);
\r
2766 outAddrPtr = pc_Address;
\r
2769 PC_WriteInt(pc_Address, switcherAddrPtr);
\r
2770 defaultAddress = 0;
\r
2774 while((cInfo = GetCaseInfo()) != NULL)
\r
2776 if(cInfo->isDefault == YES)
\r
2778 defaultAddress = cInfo->address;
\r
2781 PC_AppendCmd(PCD_CASEGOTO);
\r
2782 PC_AppendInt(cInfo->value);
\r
2783 PC_AppendInt(cInfo->address);
\r
2786 else if(CaseIndex != 0)
\r
2788 caseInfo_t *maxCase = &CaseInfo[CaseIndex];
\r
2789 caseInfo_t *minCase = maxCase;
\r
2791 // [RH] Sort cases so that the VM can handle them with
\r
2792 // a quick binary search.
\r
2793 while((cInfo = GetCaseInfo()) != NULL)
\r
2797 qsort(minCase, maxCase - minCase, sizeof(caseInfo_t), CaseInfoCmp);
\r
2798 if(minCase->isDefault == YES)
\r
2800 defaultAddress = minCase->address;
\r
2803 if (minCase < maxCase)
\r
2805 PC_AppendCmd(PCD_CASEGOTOSORTED);
\r
2806 if(pc_Address%4 != 0)
\r
2807 { // Align to a 4-byte boundary
\r
2809 PC_Append((void *)&pad, 4-(pc_Address%4));
\r
2811 PC_AppendInt(maxCase - minCase);
\r
2812 for(; minCase < maxCase; ++minCase)
\r
2814 PC_AppendInt(minCase->value);
\r
2815 PC_AppendInt(minCase->address);
\r
2819 PC_AppendCmd(PCD_DROP);
\r
2821 if(defaultAddress != 0)
\r
2823 PC_AppendCmd(PCD_GOTO);
\r
2824 PC_AppendInt(defaultAddress);
\r
2827 PC_WriteInt(pc_Address, outAddrPtr);
\r
2832 //==========================================================================
\r
2836 //==========================================================================
\r
2838 static void LeadingCase(void)
\r
2840 MS_Message(MSG_DEBUG, "---- LeadingCase ----\n");
\r
2842 PushCase(EvalConstExpression(), NO);
\r
2843 TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2847 //==========================================================================
\r
2851 //==========================================================================
\r
2853 static void LeadingDefault(void)
\r
2855 MS_Message(MSG_DEBUG, "---- LeadingDefault ----\n");
\r
2856 TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON);
\r
2861 //==========================================================================
\r
2865 //==========================================================================
\r
2867 static void PushCase(int value, boolean isDefault)
\r
2869 if(CaseIndex == MAX_CASE)
\r
2871 ERR_Exit(ERR_CASE_OVERFLOW, YES);
\r
2873 CaseInfo[CaseIndex].level = StatementLevel;
\r
2874 CaseInfo[CaseIndex].value = value;
\r
2875 CaseInfo[CaseIndex].isDefault = isDefault;
\r
2876 CaseInfo[CaseIndex].address = pc_Address;
\r
2880 //==========================================================================
\r
2884 //==========================================================================
\r
2886 static caseInfo_t *GetCaseInfo(void)
\r
2888 if(CaseIndex == 0)
\r
2892 if(CaseInfo[CaseIndex-1].level > StatementLevel)
\r
2894 return &CaseInfo[--CaseIndex];
\r
2899 //==========================================================================
\r
2903 //==========================================================================
\r
2905 static int CaseInfoCmp (const void *a, const void *b)
\r
2907 const caseInfo_t *ca = (const caseInfo_t *)a;
\r
2908 const caseInfo_t *cb = (const caseInfo_t *)b;
\r
2910 // The default case always gets moved to the front.
\r
2919 return ca->value - cb->value;
\r
2922 //==========================================================================
\r
2924 // DefaultInCurrent
\r
2926 //==========================================================================
\r
2928 static boolean DefaultInCurrent(void)
\r
2932 for(i = 0; i < CaseIndex; i++)
\r
2934 if(CaseInfo[i].isDefault == YES
\r
2935 && CaseInfo[i].level == StatementLevel)
\r
2943 //==========================================================================
\r
2947 //==========================================================================
\r
2949 static void LeadingBreak(void)
\r
2951 MS_Message(MSG_DEBUG, "---- LeadingBreak ----\n");
\r
2952 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
2953 PC_AppendCmd(PCD_GOTO);
\r
2959 //==========================================================================
\r
2963 //==========================================================================
\r
2965 static void PushBreak(void)
\r
2967 if(BreakIndex == MAX_CASE)
\r
2969 ERR_Exit(ERR_BREAK_OVERFLOW, YES);
\r
2971 BreakInfo[BreakIndex].level = StatementLevel;
\r
2972 BreakInfo[BreakIndex].addressPtr = pc_Address;
\r
2976 //==========================================================================
\r
2980 //==========================================================================
\r
2982 static void WriteBreaks(void)
\r
2984 while(BreakIndex && BreakInfo[BreakIndex-1].level > StatementLevel)
\r
2986 PC_WriteInt(pc_Address, BreakInfo[--BreakIndex].addressPtr);
\r
2990 //==========================================================================
\r
2994 // Returns YES if the current statement history contains a break root
\r
2997 //==========================================================================
\r
2999 static boolean BreakAncestor(void)
\r
3003 for(i = 0; i < StatementIndex; i++)
\r
3005 if(IsBreakRoot[StatementHistory[i]])
\r
3013 //==========================================================================
\r
3015 // LeadingContinue
\r
3017 //==========================================================================
\r
3019 static void LeadingContinue(void)
\r
3021 MS_Message(MSG_DEBUG, "---- LeadingContinue ----\n");
\r
3022 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
3023 PC_AppendCmd(PCD_GOTO);
\r
3029 //==========================================================================
\r
3033 //==========================================================================
\r
3035 static void PushContinue(void)
\r
3037 if(ContinueIndex == MAX_CONTINUE)
\r
3039 ERR_Exit(ERR_CONTINUE_OVERFLOW, YES);
\r
3041 ContinueInfo[ContinueIndex].level = StatementLevel;
\r
3042 ContinueInfo[ContinueIndex].addressPtr = pc_Address;
\r
3046 //==========================================================================
\r
3050 //==========================================================================
\r
3052 static void WriteContinues(int address)
\r
3054 if(ContinueIndex == 0)
\r
3058 while(ContinueInfo[ContinueIndex-1].level > StatementLevel)
\r
3060 PC_WriteInt(address, ContinueInfo[--ContinueIndex].addressPtr);
\r
3064 //==========================================================================
\r
3066 // ContinueAncestor
\r
3068 //==========================================================================
\r
3070 static boolean ContinueAncestor(void)
\r
3074 for(i = 0; i < StatementIndex; i++)
\r
3076 if(IsContinueRoot[StatementHistory[i]])
\r
3084 //==========================================================================
\r
3088 //==========================================================================
\r
3090 static void LeadingIncDec(int token)
\r
3092 symbolNode_t *sym;
\r
3094 MS_Message(MSG_DEBUG, "---- LeadingIncDec ----\n");
\r
3095 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INCDEC_OP_ON_NON_VAR);
\r
3096 sym = DemandSymbol(tk_String);
\r
3097 if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR
\r
3098 && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR
\r
3099 && sym->type != SY_MAPARRAY && sym->type != SY_GLOBALARRAY
\r
3100 && sym->type != SY_WORLDARRAY && sym->type != SY_SCRIPTALIAS)
\r
3102 ERR_Error(ERR_INCDEC_OP_ON_NON_VAR, YES);
\r
3103 TK_SkipPast(TK_SEMICOLON);
\r
3107 if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY
\r
3108 || sym->type == SY_GLOBALARRAY)
\r
3110 ParseArrayIndices(sym, sym->info.array.ndim);
\r
3112 else if(tk_Token == TK_LBRACKET)
\r
3114 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);
\r
3115 while(tk_Token == TK_LBRACKET)
\r
3117 TK_SkipPast(TK_RBRACKET);
\r
3120 PC_AppendCmd(GetIncDecPCD(token, sym->type));
\r
3121 PC_AppendShrink(sym->info.var.index);
\r
3122 if(forSemicolonHack)
\r
3124 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
3128 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
3133 //==========================================================================
\r
3135 // LeadingVarAssign
\r
3137 //==========================================================================
\r
3139 static void LeadingVarAssign(symbolNode_t *sym)
\r
3142 tokenType_t assignToken;
\r
3144 MS_Message(MSG_DEBUG, "---- LeadingVarAssign ----\n");
\r
3148 TK_NextToken(); // Fetch assignment operator
\r
3149 if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY
\r
3150 || sym->type == SY_GLOBALARRAY)
\r
3152 ParseArrayIndices(sym, sym->info.array.ndim);
\r
3154 else if(tk_Token == TK_LBRACKET)
\r
3156 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);
\r
3157 while(tk_Token == TK_LBRACKET)
\r
3159 TK_SkipPast(TK_RBRACKET);
\r
3162 if(tk_Token == TK_INC || tk_Token == TK_DEC)
\r
3163 { // Postfix increment or decrement
\r
3164 PC_AppendCmd(GetIncDecPCD(tk_Token, sym->type));
\r
3167 PC_AppendInt(sym->info.var.index);
\r
3171 PC_AppendByte(sym->info.var.index);
\r
3176 { // Normal operator
\r
3177 if(TK_Member(AssignOps) == NO)
\r
3179 ERR_Error(ERR_MISSING_ASSIGN_OP, YES);
\r
3180 TK_SkipPast(TK_SEMICOLON);
\r
3183 assignToken = tk_Token;
\r
3186 PC_AppendCmd(GetAssignPCD(assignToken, sym->type));
\r
3187 PC_AppendShrink(sym->info.var.index);
\r
3189 if(tk_Token == TK_COMMA)
\r
3191 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_BAD_ASSIGNMENT);
\r
3192 sym = DemandSymbol(tk_String);
\r
3193 if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR
\r
3194 && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR
\r
3195 && sym->type != SY_WORLDARRAY && sym->type != SY_GLOBALARRAY
\r
3196 && sym->type != SY_SCRIPTALIAS)
\r
3198 ERR_Error(ERR_BAD_ASSIGNMENT, YES);
\r
3199 TK_SkipPast(TK_SEMICOLON);
\r
3205 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
3209 } while(done == NO);
\r
3212 //==========================================================================
\r
3216 //==========================================================================
\r
3218 static pcd_t GetAssignPCD(tokenType_t token, symbolType_t symbol)
\r
3221 static tokenType_t tokenLookup[] =
\r
3223 TK_ASSIGN, TK_ADDASSIGN, TK_SUBASSIGN,
\r
3224 TK_MULASSIGN, TK_DIVASSIGN, TK_MODASSIGN,
\r
3225 TK_ANDASSIGN, TK_EORASSIGN, TK_ORASSIGN,
\r
3226 TK_LSASSIGN, TK_RSASSIGN
\r
3228 static symbolType_t symbolLookup[] =
\r
3230 SY_SCRIPTVAR, SY_MAPVAR, SY_WORLDVAR, SY_GLOBALVAR, SY_MAPARRAY,
\r
3231 SY_WORLDARRAY, SY_GLOBALARRAY
\r
3233 static pcd_t assignmentLookup[11][7] =
\r
3235 { PCD_ASSIGNSCRIPTVAR, PCD_ASSIGNMAPVAR, PCD_ASSIGNWORLDVAR, PCD_ASSIGNGLOBALVAR, PCD_ASSIGNMAPARRAY, PCD_ASSIGNWORLDARRAY, PCD_ASSIGNGLOBALARRAY },
\r
3236 { PCD_ADDSCRIPTVAR, PCD_ADDMAPVAR, PCD_ADDWORLDVAR, PCD_ADDGLOBALVAR, PCD_ADDMAPARRAY, PCD_ADDWORLDARRAY, PCD_ADDGLOBALARRAY },
\r
3237 { PCD_SUBSCRIPTVAR, PCD_SUBMAPVAR, PCD_SUBWORLDVAR, PCD_SUBGLOBALVAR, PCD_SUBMAPARRAY, PCD_SUBWORLDARRAY, PCD_SUBGLOBALARRAY },
\r
3238 { PCD_MULSCRIPTVAR, PCD_MULMAPVAR, PCD_MULWORLDVAR, PCD_MULGLOBALVAR, PCD_MULMAPARRAY, PCD_MULWORLDARRAY, PCD_MULGLOBALARRAY },
\r
3239 { PCD_DIVSCRIPTVAR, PCD_DIVMAPVAR, PCD_DIVWORLDVAR, PCD_DIVGLOBALVAR, PCD_DIVMAPARRAY, PCD_DIVWORLDARRAY, PCD_DIVGLOBALARRAY },
\r
3240 { PCD_MODSCRIPTVAR, PCD_MODMAPVAR, PCD_MODWORLDVAR, PCD_MODGLOBALVAR, PCD_MODMAPARRAY, PCD_MODWORLDARRAY, PCD_MODGLOBALARRAY },
\r
3241 { PCD_ANDSCRIPTVAR, PCD_ANDMAPVAR, PCD_ANDWORLDVAR, PCD_ANDGLOBALVAR, PCD_ANDMAPARRAY, PCD_ANDWORLDARRAY, PCD_ANDGLOBALARRAY },
\r
3242 { PCD_EORSCRIPTVAR, PCD_EORMAPVAR, PCD_EORWORLDVAR, PCD_EORGLOBALVAR, PCD_EORMAPARRAY, PCD_EORWORLDARRAY, PCD_EORGLOBALARRAY },
\r
3243 { PCD_ORSCRIPTVAR, PCD_ORMAPVAR, PCD_ORWORLDVAR, PCD_ORGLOBALVAR, PCD_ORMAPARRAY, PCD_ORWORLDARRAY, PCD_ORGLOBALARRAY },
\r
3244 { PCD_LSSCRIPTVAR, PCD_LSMAPVAR, PCD_LSWORLDVAR, PCD_LSGLOBALVAR, PCD_LSMAPARRAY, PCD_LSWORLDARRAY, PCD_LSGLOBALARRAY },
\r
3245 { PCD_RSSCRIPTVAR, PCD_RSMAPVAR, PCD_RSWORLDVAR, PCD_RSGLOBALVAR, PCD_RSMAPARRAY, PCD_RSWORLDARRAY, PCD_RSGLOBALARRAY }
\r
3248 for(i = 0; i < ARRAY_SIZE(tokenLookup); ++i)
\r
3250 if(tokenLookup[i] == token)
\r
3252 for(j = 0; j < ARRAY_SIZE(symbolLookup); ++j)
\r
3254 if (symbolLookup[j] == symbol)
\r
3256 return assignmentLookup[i][j];
\r
3265 //==========================================================================
\r
3269 //==========================================================================
\r
3271 static void LeadingSuspend(void)
\r
3273 MS_Message(MSG_DEBUG, "---- LeadingSuspend ----\n");
\r
3274 if(InsideFunction)
\r
3276 ERR_Error(ERR_SUSPEND_IN_FUNCTION, YES);
\r
3278 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
3279 PC_AppendCmd(PCD_SUSPEND);
\r
3283 //==========================================================================
\r
3285 // LeadingTerminate
\r
3287 //==========================================================================
\r
3289 static void LeadingTerminate(void)
\r
3291 MS_Message(MSG_DEBUG, "---- LeadingTerminate ----\n");
\r
3292 if(InsideFunction)
\r
3294 ERR_Error(ERR_TERMINATE_IN_FUNCTION, YES);
\r
3296 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
3297 PC_AppendCmd(PCD_TERMINATE);
\r
3301 //==========================================================================
\r
3305 //==========================================================================
\r
3307 static void LeadingRestart(void)
\r
3309 MS_Message(MSG_DEBUG, "---- LeadingRestart ----\n");
\r
3310 if(InsideFunction)
\r
3312 ERR_Error(ERR_RESTART_IN_FUNCTION, YES);
\r
3314 TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
3315 PC_AppendCmd(PCD_RESTART);
\r
3319 //==========================================================================
\r
3323 //==========================================================================
\r
3325 static void LeadingReturn(void)
\r
3327 MS_Message(MSG_DEBUG, "---- LeadingReturn ----\n");
\r
3328 if(!InsideFunction)
\r
3330 ERR_Error(ERR_RETURN_OUTSIDE_FUNCTION, YES);
\r
3331 while (TK_NextToken () != TK_SEMICOLON)
\r
3333 if (tk_Token == TK_EOF)
\r
3340 if(tk_Token == TK_SEMICOLON)
\r
3342 if(InsideFunction->info.scriptFunc.hasReturnValue)
\r
3344 ERR_Error(ERR_MUST_RETURN_A_VALUE, YES);
\r
3346 PC_AppendCmd(PCD_RETURNVOID);
\r
3350 if(!InsideFunction->info.scriptFunc.hasReturnValue)
\r
3352 ERR_Error(ERR_MUST_NOT_RETURN_A_VALUE, YES);
\r
3355 TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON);
\r
3356 PC_AppendCmd(PCD_RETURNVAL);
\r
3362 //==========================================================================
\r
3364 // EvalConstExpression
\r
3366 //==========================================================================
\r
3368 static int EvalConstExpression(void)
\r
3370 pa_ConstExprIsString = NO; // Used by PC_PutMapVariable
\r
3371 ExprStackIndex = 0;
\r
3372 ConstantExpression = YES;
\r
3374 if(ExprStackIndex != 1)
\r
3376 ERR_Error(ERR_BAD_CONST_EXPR, YES, NULL);
\r
3378 ExprStackIndex = 1;
\r
3380 return PopExStk();
\r
3383 //==========================================================================
\r
3387 // [RH] Rewrote all the ExprLevA - ExprLevJ functions in favor of a single
\r
3388 // table-driven parser function.
\r
3390 //==========================================================================
\r
3392 static void EvalExpression(void)
\r
3394 ConstantExpression = NO;
\r
3398 static void ExprLevA(void)
\r
3403 // Operator precedence levels:
\r
3409 // Operators: == !=
\r
3410 // Operators: < <= > >=
\r
3411 // Operators: << >>
\r
3413 // Operators: * / %
\r
3415 static void ExprLevX(int level)
\r
3417 if(OpsList[level] == NULL)
\r
3419 boolean unaryMinus;
\r
3421 unaryMinus = FALSE;
\r
3422 if(tk_Token == TK_MINUS)
\r
3424 unaryMinus = TRUE;
\r
3427 if(tk_Token == TK_PLUS)
\r
3429 // Completely ignore unary plus
\r
3432 if(ConstantExpression == YES)
\r
3434 ConstExprFactor();
\r
3440 if(unaryMinus == TRUE)
\r
3442 SendExprCommand(PCD_UNARYMINUS);
\r
3447 ExprLevX(level + 1);
\r
3448 while(TK_Member(OpsList[level]))
\r
3450 tokenType_t token = tk_Token;
\r
3452 ExprLevX(level + 1);
\r
3453 SendExprCommand(TokenToPCD(token));
\r
3458 static void ExprLineSpecial(void)
\r
3460 int argCountMin = tk_SpecialArgCount & 0xffff;
\r
3461 int argCountMax = tk_SpecialArgCount >> 16;
\r
3462 int specialValue = tk_SpecialValue;
\r
3464 // There are two ways to use a special in an expression:
\r
3465 // 1. The special name by itself returns the special's number.
\r
3466 // 2. The special followed by parameters actually executes the special.
\r
3468 if(tk_Token != TK_LPAREN)
\r
3470 PC_AppendPushVal(specialValue);
\r
3477 if(tk_Token != TK_RPAREN)
\r
3485 } while(tk_Token == TK_COMMA);
\r
3487 if(argCount < argCountMin || argCount > argCountMax)
\r
3489 ERR_Error(specialValue >=0? ERR_BAD_LSPEC_ARG_COUNT : ERR_BAD_ARG_COUNT, YES);
\r
3492 if (specialValue >= 0)
\r
3494 for(; argCount < 5; ++argCount)
\r
3496 PC_AppendPushVal(0);
\r
3498 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
3500 PC_AppendCmd(PCD_LSPEC5RESULT);
\r
3503 PC_AppendInt(specialValue);
\r
3507 PC_AppendByte((U_BYTE)specialValue);
\r
3512 TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN);
\r
3514 PC_AppendCmd(PCD_CALLFUNC);
\r
3517 PC_AppendInt(argCount);
\r
3518 PC_AppendInt(-specialValue);
\r
3522 PC_AppendByte((U_BYTE)argCount);
\r
3523 PC_AppendWord((U_WORD)-specialValue);
\r
3529 static void ExprFactor(void)
\r
3531 symbolNode_t *sym;
\r
3532 tokenType_t opToken;
\r
3537 if (ImportMode != IMPORT_Importing)
\r
3539 tk_Number = STR_Find(tk_String);
\r
3540 PC_AppendPushVal(tk_Number);
\r
3541 if (ImportMode == IMPORT_Exporting)
\r
3543 // The VM identifies strings by storing a library ID in the
\r
3544 // high word of the string index. The library ID is not
\r
3545 // known until the script actually gets loaded into the game,
\r
3546 // so we need to use this p-code to tack the ID of the
\r
3547 // currently running library to the index of the string that
\r
3548 // just got pushed onto the stack.
\r
3550 // Simply assuming that a string is from the current library
\r
3551 // is not good enough, because they can be passed around
\r
3552 // between libraries and the map's behavior. Thus, we need
\r
3553 // to know which object file a particular string belongs to.
\r
3555 // A specific example:
\r
3556 // A map's behavior calls a function in a library and passes
\r
3559 // LibFunc ("The library will do something with this string.");
\r
3561 // The library function needs to know that the string originated
\r
3562 // outside the library. Similarly, if a library function returns
\r
3563 // a string, the caller needs to know that the string did not
\r
3564 // originate from the same object file.
\r
3566 // And that's why strings have library IDs tacked onto them.
\r
3567 // The map's main behavior (i.e. an object that is not a library)
\r
3568 // always uses library ID 0 to identify its strings, so its
\r
3569 // strings don't need to be tagged.
\r
3570 PC_AppendCmd(PCD_TAGSTRING);
\r
3576 PC_AppendPushVal(tk_Number);
\r
3582 if(tk_Token != TK_RPAREN)
\r
3584 ERR_Error(ERR_BAD_EXPR, YES, NULL);
\r
3585 TK_SkipPast(TK_RPAREN);
\r
3595 PC_AppendCmd(PCD_NEGATELOGICAL);
\r
3600 PC_AppendCmd(PCD_NEGATEBINARY);
\r
3604 opToken = tk_Token;
\r
3605 TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INCDEC_OP_ON_NON_VAR);
\r
3606 sym = DemandSymbol(tk_String);
\r
3607 if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR
\r
3608 && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR
\r
3609 && sym->type != SY_MAPARRAY && sym->type != SY_WORLDARRAY
\r
3610 && sym->type != SY_GLOBALARRAY)
\r
3612 ERR_Error(ERR_INCDEC_OP_ON_NON_VAR, YES);
\r
3617 if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY
\r
3618 || sym->type == SY_GLOBALARRAY)
\r
3620 ParseArrayIndices(sym, sym->info.array.ndim);
\r
3621 PC_AppendCmd(PCD_DUP);
\r
3623 else if(tk_Token == TK_LBRACKET)
\r
3625 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);
\r
3626 while(tk_Token == TK_LBRACKET)
\r
3628 TK_SkipPast(TK_RBRACKET);
\r
3631 PC_AppendCmd(GetIncDecPCD(opToken, sym->type));
\r
3632 PC_AppendShrink(sym->info.var.index);
\r
3633 PC_AppendCmd(GetPushVarPCD(sym->type));
\r
3634 PC_AppendShrink(sym->info.var.index);
\r
3637 case TK_IDENTIFIER:
\r
3638 sym = SpeculateSymbol(tk_String, YES);
\r
3641 case SY_SCRIPTALIAS:
\r
3645 case SY_WORLDARRAY:
\r
3646 case SY_GLOBALARRAY:
\r
3648 ParseArrayIndices(sym, sym->info.array.ndim);
\r
3650 case SY_SCRIPTVAR:
\r
3653 case SY_GLOBALVAR:
\r
3654 if(sym->type != SY_MAPARRAY && sym->type != SY_WORLDARRAY
\r
3655 && sym->type != SY_GLOBALARRAY)
\r
3658 if(tk_Token == TK_LBRACKET)
\r
3660 ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name);
\r
3661 while(tk_Token == TK_LBRACKET)
\r
3663 TK_SkipPast(TK_RBRACKET);
\r
3667 if((tk_Token == TK_INC || tk_Token == TK_DEC)
\r
3668 && (sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY
\r
3669 || sym->type == SY_GLOBALARRAY))
\r
3671 PC_AppendCmd(PCD_DUP);
\r
3673 PC_AppendCmd(GetPushVarPCD(sym->type));
\r
3674 PC_AppendShrink(sym->info.var.index);
\r
3675 if(tk_Token == TK_INC || tk_Token == TK_DEC)
\r
3677 if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY
\r
3678 || sym->type == SY_GLOBALARRAY)
\r
3680 PC_AppendCmd(PCD_SWAP);
\r
3682 PC_AppendCmd(GetIncDecPCD(tk_Token, sym->type));
\r
3683 PC_AppendShrink(sym->info.var.index);
\r
3687 case SY_INTERNFUNC:
\r
3688 if(sym->info.internFunc.hasReturnValue == NO)
\r
3690 ERR_Error(ERR_EXPR_FUNC_NO_RET_VAL, YES);
\r
3692 ProcessInternFunc(sym);
\r
3694 case SY_SCRIPTFUNC:
\r
3695 if(sym->info.scriptFunc.hasReturnValue == NO)
\r
3697 ERR_Error(ERR_EXPR_FUNC_NO_RET_VAL, YES);
\r
3699 ProcessScriptFunc(sym, NO);
\r
3702 ERR_Error(ERR_ILLEGAL_EXPR_IDENT, YES, tk_String);
\r
3707 case TK_LINESPECIAL:
\r
3708 ExprLineSpecial();
\r
3710 case TK_STRPARAM_EVAL:
\r
3719 ERR_Error(ERR_BAD_EXPR, YES);
\r
3725 static void ConstExprFactor(void)
\r
3730 if (ImportMode != IMPORT_Importing)
\r
3732 int strnum = STR_Find(tk_String);
\r
3733 if (ImportMode == IMPORT_Exporting)
\r
3735 pa_ConstExprIsString = YES;
\r
3737 PushExStk(strnum);
\r
3741 // Importing, so it doesn't matter
\r
3747 PushExStk(tk_Number);
\r
3753 if(tk_Token != TK_RPAREN)
\r
3755 ERR_Error(ERR_BAD_CONST_EXPR, YES);
\r
3756 TK_SkipPast(TK_RPAREN);
\r
3765 ConstExprFactor();
\r
3766 SendExprCommand(PCD_NEGATELOGICAL);
\r
3770 ConstExprFactor();
\r
3771 SendExprCommand(PCD_NEGATEBINARY);
\r
3774 ERR_Error(ERR_BAD_CONST_EXPR, YES);
\r
3776 while(tk_Token != TK_COMMA &&
\r
3777 tk_Token != TK_SEMICOLON &&
\r
3778 tk_Token != TK_RPAREN)
\r
3780 if(tk_Token == TK_EOF)
\r
3782 ERR_Exit(ERR_EOF, YES);
\r
3790 //==========================================================================
\r
3792 // SendExprCommand
\r
3794 //==========================================================================
\r
3796 static void SendExprCommand(pcd_t pcd)
\r
3798 int operand1, operand2;
\r
3800 if(ConstantExpression == NO)
\r
3802 PC_AppendCmd(pcd);
\r
3808 PushExStk(PopExStk()+PopExStk());
\r
3810 case PCD_SUBTRACT:
\r
3811 operand2 = PopExStk();
\r
3812 PushExStk(PopExStk()-operand2);
\r
3814 case PCD_MULTIPLY:
\r
3815 PushExStk(PopExStk()*PopExStk());
\r
3818 operand2 = PopExStk();
\r
3819 PushExStk(PopExStk()/operand2);
\r
3822 operand2 = PopExStk();
\r
3823 PushExStk(PopExStk()%operand2);
\r
3826 PushExStk(PopExStk() == PopExStk());
\r
3829 PushExStk(PopExStk() != PopExStk());
\r
3832 operand2 = PopExStk();
\r
3833 PushExStk(PopExStk() < operand2);
\r
3836 operand2 = PopExStk();
\r
3837 PushExStk(PopExStk() > operand2);
\r
3840 operand2 = PopExStk();
\r
3841 PushExStk(PopExStk() <= operand2);
\r
3844 operand2 = PopExStk();
\r
3845 PushExStk(PopExStk() >= operand2);
\r
3847 case PCD_ANDLOGICAL:
\r
3848 operand2 = PopExStk();
\r
3849 operand1 = PopExStk();
\r
3850 PushExStk(operand1 && operand2);
\r
3852 case PCD_ORLOGICAL:
\r
3853 operand2 = PopExStk();
\r
3854 operand1 = PopExStk();
\r
3855 PushExStk(operand1 || operand2);
\r
3857 case PCD_ANDBITWISE:
\r
3858 PushExStk(PopExStk()&PopExStk());
\r
3860 case PCD_ORBITWISE:
\r
3861 PushExStk(PopExStk()|PopExStk());
\r
3863 case PCD_EORBITWISE:
\r
3864 PushExStk(PopExStk()^PopExStk());
\r
3866 case PCD_NEGATELOGICAL:
\r
3867 PushExStk(!PopExStk());
\r
3869 case PCD_NEGATEBINARY:
\r
3870 PushExStk(~PopExStk());
\r
3873 operand2 = PopExStk();
\r
3874 PushExStk(PopExStk()<<operand2);
\r
3877 operand2 = PopExStk();
\r
3878 PushExStk(PopExStk()>>operand2);
\r
3880 case PCD_UNARYMINUS:
\r
3881 PushExStk(-PopExStk());
\r
3884 ERR_Exit(ERR_UNKNOWN_CONST_EXPR_PCD, YES);
\r
3889 //==========================================================================
\r
3893 //==========================================================================
\r
3895 static void PushExStk(int value)
\r
3897 if(ExprStackIndex == EXPR_STACK_DEPTH)
\r
3899 ERR_Exit(ERR_EXPR_STACK_OVERFLOW, YES);
\r
3901 ExprStack[ExprStackIndex++] = value;
\r
3904 //==========================================================================
\r
3908 //==========================================================================
\r
3910 static int PopExStk(void)
\r
3912 if(ExprStackIndex < 1)
\r
3914 ERR_Error(ERR_EXPR_STACK_EMPTY, YES);
\r
3917 return ExprStack[--ExprStackIndex];
\r
3920 //==========================================================================
\r
3924 //==========================================================================
\r
3926 static pcd_t TokenToPCD(tokenType_t token)
\r
3931 tokenType_t token;
\r
3933 } operatorLookup[] =
\r
3935 { TK_ORLOGICAL, PCD_ORLOGICAL },
\r
3936 { TK_ANDLOGICAL, PCD_ANDLOGICAL },
\r
3937 { TK_ORBITWISE, PCD_ORBITWISE },
\r
3938 { TK_EORBITWISE, PCD_EORBITWISE },
\r
3939 { TK_ANDBITWISE, PCD_ANDBITWISE },
\r
3940 { TK_EQ, PCD_EQ },
\r
3941 { TK_NE, PCD_NE },
\r
3942 { TK_LT, PCD_LT },
\r
3943 { TK_LE, PCD_LE },
\r
3944 { TK_GT, PCD_GT },
\r
3945 { TK_GE, PCD_GE },
\r
3946 { TK_LSHIFT, PCD_LSHIFT },
\r
3947 { TK_RSHIFT, PCD_RSHIFT },
\r
3948 { TK_PLUS, PCD_ADD },
\r
3949 { TK_MINUS, PCD_SUBTRACT },
\r
3950 { TK_ASTERISK, PCD_MULTIPLY },
\r
3951 { TK_SLASH, PCD_DIVIDE },
\r
3952 { TK_PERCENT, PCD_MODULUS },
\r
3953 { TK_NONE, PCD_NOP }
\r
3956 for(i = 0; operatorLookup[i].token != TK_NONE; i++)
\r
3958 if(operatorLookup[i].token == token)
\r
3960 return operatorLookup[i].pcd;
\r
3966 //==========================================================================
\r
3970 //==========================================================================
\r
3972 static pcd_t GetPushVarPCD(symbolType_t symType)
\r
3976 case SY_SCRIPTVAR:
\r
3977 return PCD_PUSHSCRIPTVAR;
\r
3979 return PCD_PUSHMAPVAR;
\r
3981 return PCD_PUSHWORLDVAR;
\r
3982 case SY_GLOBALVAR:
\r
3983 return PCD_PUSHGLOBALVAR;
\r
3985 return PCD_PUSHMAPARRAY;
\r
3986 case SY_WORLDARRAY:
\r
3987 return PCD_PUSHWORLDARRAY;
\r
3988 case SY_GLOBALARRAY:
\r
3989 return PCD_PUSHGLOBALARRAY;
\r
3996 //==========================================================================
\r
4000 //==========================================================================
\r
4002 static pcd_t GetIncDecPCD(tokenType_t token, symbolType_t symbol)
\r
4007 tokenType_t token;
\r
4008 symbolType_t symbol;
\r
4010 } incDecLookup[] =
\r
4012 { TK_INC, SY_SCRIPTVAR, PCD_INCSCRIPTVAR },
\r
4013 { TK_INC, SY_MAPVAR, PCD_INCMAPVAR },
\r
4014 { TK_INC, SY_WORLDVAR, PCD_INCWORLDVAR },
\r
4015 { TK_INC, SY_GLOBALVAR, PCD_INCGLOBALVAR },
\r
4016 { TK_INC, SY_MAPARRAY, PCD_INCMAPARRAY },
\r
4017 { TK_INC, SY_WORLDARRAY, PCD_INCWORLDARRAY },
\r
4018 { TK_INC, SY_GLOBALARRAY, PCD_INCGLOBALARRAY },
\r
4020 { TK_DEC, SY_SCRIPTVAR, PCD_DECSCRIPTVAR },
\r
4021 { TK_DEC, SY_MAPVAR, PCD_DECMAPVAR },
\r
4022 { TK_DEC, SY_WORLDVAR, PCD_DECWORLDVAR },
\r
4023 { TK_DEC, SY_GLOBALVAR, PCD_DECGLOBALVAR },
\r
4024 { TK_DEC, SY_MAPARRAY, PCD_DECMAPARRAY },
\r
4025 { TK_DEC, SY_WORLDARRAY, PCD_DECWORLDARRAY },
\r
4026 { TK_DEC, SY_GLOBALARRAY, PCD_DECGLOBALARRAY },
\r
4028 { TK_NONE, SY_DUMMY, PCD_NOP }
\r
4031 for(i = 0; incDecLookup[i].token != TK_NONE; i++)
\r
4033 if(incDecLookup[i].token == token
\r
4034 && incDecLookup[i].symbol == symbol)
\r
4036 return incDecLookup[i].pcd;
\r
4042 //==========================================================================
\r
4044 // ParseArrayIndices
\r
4046 //==========================================================================
\r
4048 static void ParseArrayIndices(symbolNode_t *sym, int requiredIndices)
\r
4050 boolean warned = NO;
\r
4053 if(requiredIndices > 0)
\r
4055 TK_TokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET);
\r
4058 while(tk_Token == TK_LBRACKET)
\r
4061 if((sym->type == SY_MAPARRAY && i == requiredIndices) ||
\r
4062 (sym->type != SY_MAPARRAY && i > 0))
\r
4067 if(sym->info.array.ndim == requiredIndices)
\r
4069 ERR_Error(ERR_TOO_MANY_DIM_USED, YES,
\r
4070 sym->name, sym->info.array.ndim);
\r
4074 ERR_Error(ERR_NOT_A_CHAR_ARRAY, YES, sym->name,
\r
4075 sym->info.array.ndim, requiredIndices);
\r
4080 if(i < sym->info.array.ndim - 1 && sym->info.array.dimensions[i] > 1)
\r
4082 PC_AppendPushVal(sym->info.array.dimensions[i]);
\r
4083 PC_AppendCmd(PCD_MULTIPLY);
\r
4087 PC_AppendCmd(PCD_ADD);
\r
4090 TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET);
\r
4093 if(i < requiredIndices)
\r
4095 ERR_Error(ERR_TOO_FEW_DIM_USED, YES,
\r
4096 sym->name, requiredIndices - i);
\r
4098 // if there were unspecified indices, multiply the offset by their sizes [JB]
\r
4099 if(requiredIndices < sym->info.array.ndim - 1)
\r
4102 for(i = 0; i < sym->info.array.ndim - requiredIndices - 1; ++i)
\r
4104 mult *= sym->info.array.dimensions[sym->info.array.ndim - 2 - i];
\r
4108 PC_AppendPushVal(mult);
\r
4109 PC_AppendCmd(PCD_MULTIPLY);
\r
4114 static void ProcessArrayLevel(int level, int *entry, int ndim,
\r
4115 int dims[MAX_ARRAY_DIMS], int muls[MAX_ARRAY_DIMS], char *name)
\r
4117 int warned_too_many = NO;
\r
4122 if(tk_Token == TK_COMMA)
\r
4124 entry += muls[level-1];
\r
4127 else if(tk_Token == TK_RBRACE)
\r
4136 if(tk_Token == TK_LBRACE)
\r
4138 ERR_Error(ERR_TOO_MANY_DIM_USED, YES, name, ndim);
\r
4139 SkipBraceBlock(0);
\r
4147 if (i >= dims[level - 1] && !warned_too_many)
\r
4149 warned_too_many = YES;
\r
4150 ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES);
\r
4152 val = EvalConstExpression();
\r
4153 ArrayHasStrings |= pa_ConstExprIsString;
\r
4154 if (i < dims[level - 1])
\r
4162 //Bugfix for r3226 by Zom-B
\r
4163 if (i >= dims[level - 1])
\r
4165 if (!warned_too_many)
\r
4167 warned_too_many = YES;
\r
4168 ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES);
\r
4170 // Allow execution to continue without stray memory access
\r
4171 entry -= muls[level-1];
\r
4173 TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR);
\r
4175 ProcessArrayLevel(level+1, entry, ndim, dims, muls, name);
\r
4176 assert(level > 0);
\r
4177 entry += muls[level-1];
\r
4179 if(i < dims[level-1]-1)
\r
4181 if(tk_Token != TK_RBRACE)
\r
4183 TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA);
\r
4189 if(tk_Token != TK_COMMA)
\r
4191 TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR);
\r
4200 TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR);
\r
4204 //==========================================================================
\r
4206 // InitializeArray
\r
4208 //==========================================================================
\r
4210 static void InitializeArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS], int size)
\r
4212 static int *entries = NULL;
\r
4213 static int lastsize = -1;
\r
4215 if(lastsize < size)
\r
4217 entries = MS_Realloc(entries, sizeof(int)*size, ERR_OUT_OF_MEMORY);
\r
4220 memset(entries, 0, sizeof(int)*size);
\r
4222 TK_NextTokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR);
\r
4224 ArrayHasStrings = NO;
\r
4225 ProcessArrayLevel(1, entries, sym->info.array.ndim, dims,
\r
4226 sym->info.array.dimensions, sym->name);
\r
4227 if(ImportMode != IMPORT_Importing)
\r
4229 PC_InitArray(sym->info.array.index, entries, ArrayHasStrings);
\r
4233 //==========================================================================
\r
4237 //==========================================================================
\r
4239 static symbolNode_t *DemandSymbol(char *name)
\r
4241 symbolNode_t *sym;
\r
4243 if((sym = SY_Find(name)) == NULL)
\r
4245 ERR_Exit(ERR_UNKNOWN_IDENTIFIER, YES, name);
\r
4250 //==========================================================================
\r
4252 // SpeculateSymbol
\r
4254 //==========================================================================
\r
4256 static symbolNode_t *SpeculateSymbol(char *name, boolean hasReturn)
\r
4258 symbolNode_t *sym;
\r
4260 sym = SY_Find(name);
\r
4263 char name[MAX_IDENTIFIER_LENGTH];
\r
4265 strcpy (name, tk_String);
\r
4267 if(tk_Token == TK_LPAREN)
\r
4268 { // Looks like a function call
\r
4269 sym = SpeculateFunction(name, hasReturn);
\r
4274 ERR_Exit(ERR_UNKNOWN_IDENTIFIER, YES, name);
\r
4280 //==========================================================================
\r
4282 // SpeculateFunction
\r
4284 // Add a temporary symbol for a function that is used before it is defined.
\r
4286 //==========================================================================
\r
4288 static symbolNode_t *SpeculateFunction(const char *name, boolean hasReturn)
\r
4290 symbolNode_t *sym;
\r
4292 MS_Message(MSG_DEBUG, "---- SpeculateFunction %s ----\n", name);
\r
4293 sym = SY_InsertGlobal(tk_String, SY_SCRIPTFUNC);
\r
4294 sym->info.scriptFunc.predefined = YES;
\r
4295 sym->info.scriptFunc.hasReturnValue = hasReturn;
\r
4296 sym->info.scriptFunc.sourceLine = tk_Line;
\r
4297 sym->info.scriptFunc.sourceName = tk_SourceName;
\r
4298 sym->info.scriptFunc.argCount = -1;
\r
4299 sym->info.scriptFunc.funcNumber = 0;
\r
4303 //==========================================================================
\r
4305 // UnspeculateFunction
\r
4307 // Fills in function calls that were made before this function was defined.
\r
4309 //==========================================================================
\r
4311 static void UnspeculateFunction(symbolNode_t *sym)
\r
4313 prefunc_t *fillin;
\r
4316 prev = &FillinFunctions;
\r
4317 fillin = FillinFunctions;
\r
4318 while(fillin != NULL)
\r
4320 prefunc_t *next = fillin->next;
\r
4321 if(fillin->sym == sym)
\r
4323 if(fillin->argcount != sym->info.scriptFunc.argCount)
\r
4325 ERR_ErrorAt(fillin->source, fillin->line);
\r
4326 ERR_Error(ERR_FUNC_ARGUMENT_COUNT, YES, sym->name,
\r
4327 sym->info.scriptFunc.argCount,
\r
4328 sym->info.scriptFunc.argCount == 1 ? "" : "s");
\r
4333 PC_WriteInt(sym->info.scriptFunc.funcNumber, fillin->address);
\r
4337 PC_WriteByte((U_BYTE)sym->info.scriptFunc.funcNumber, fillin->address);
\r
4339 if(FillinFunctionsLatest == &fillin->next)
\r
4341 FillinFunctionsLatest = prev;
\r
4348 prev = &fillin->next;
\r
4354 //==========================================================================
\r
4356 // AddScriptFuncRef
\r
4358 //==========================================================================
\r
4360 static void AddScriptFuncRef(symbolNode_t *sym, int address, int argcount)
\r
4362 prefunc_t *fillin = MS_Alloc(sizeof(*fillin), ERR_OUT_OF_MEMORY);
\r
4363 fillin->next = NULL;
\r
4364 fillin->sym = sym;
\r
4365 fillin->address = address;
\r
4366 fillin->argcount = argcount;
\r
4367 fillin->line = tk_Line;
\r
4368 fillin->source = tk_SourceName;
\r
4369 *FillinFunctionsLatest = fillin;
\r
4370 FillinFunctionsLatest = &fillin->next;
\r
4373 //==========================================================================
\r
4375 // Check for undefined functions
\r
4377 //==========================================================================
\r
4379 static void CheckForUndefinedFunctions(void)
\r
4381 prefunc_t *fillin = FillinFunctions;
\r
4383 while(fillin != NULL)
\r
4385 ERR_ErrorAt(fillin->source, fillin->line);
\r
4386 ERR_Error(ERR_UNDEFINED_FUNC, YES, fillin->sym->name);
\r
4387 fillin = fillin->next;
\r
4391 //==========================================================================
\r
4395 // If depth is 0, it scans for the first { and then starts going from there.
\r
4396 // At exit, the terminating } is left as the current token.
\r
4398 //==========================================================================
\r
4400 void SkipBraceBlock(int depth)
\r
4405 while(tk_Token != TK_LBRACE)
\r
4407 if(tk_Token == TK_EOF)
\r
4409 ERR_Exit(ERR_EOF, NO);
\r
4415 // Match it with a }
\r
4419 if(tk_Token == TK_EOF)
\r
4421 ERR_Exit(ERR_EOF, NO);
\r
4423 else if (tk_Token == TK_LBRACE)
\r
4427 else if (tk_Token == TK_RBRACE)
\r
4431 } while (depth > 0);
\r