2 //**************************************************************************
\r
6 //**************************************************************************
\r
8 // HEADER FILES ------------------------------------------------------------
\r
17 // MACROS ------------------------------------------------------------------
\r
19 // TYPES -------------------------------------------------------------------
\r
24 pcd_t directCommand;
\r
29 boolean hasReturnValue;
\r
33 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
\r
35 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
\r
37 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
\r
39 static symbolNode_t *Find(char *name, symbolNode_t *root);
\r
40 static symbolNode_t *Insert(char *name, symbolType_t type,
\r
41 symbolNode_t **root);
\r
42 static void FreeNodes(symbolNode_t *root);
\r
43 static void FreeNodesAtDepth(symbolNode_t **root, int depth);
\r
44 static void DeleteNode(symbolNode_t *node, symbolNode_t **parent_p);
\r
45 static void ClearShared(symbolNode_t *root);
\r
47 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
\r
49 // PUBLIC DATA DEFINITIONS -------------------------------------------------
\r
51 // PRIVATE DATA DEFINITIONS ------------------------------------------------
\r
53 static symbolNode_t *LocalRoot;
\r
54 static symbolNode_t *GlobalRoot;
\r
56 static internFuncDef_t InternalFunctions[] =
\r
58 { "tagwait", PCD_TAGWAITDIRECT, PCD_TAGWAIT, 1, 0, 0, NO, YES },
\r
59 { "polywait", PCD_POLYWAITDIRECT, PCD_POLYWAIT, 1, 0, 0, NO, YES },
\r
60 { "scriptwait", PCD_SCRIPTWAITDIRECT, PCD_SCRIPTWAIT, 1, 0, 0, NO, YES },
\r
61 { "namedscriptwait", PCD_NOP, PCD_SCRIPTWAITNAMED, 1, 0, 0, NO, YES },
\r
62 { "delay", PCD_DELAYDIRECT, PCD_DELAY, 1, 0, 0, NO, YES },
\r
63 { "random", PCD_RANDOMDIRECT, PCD_RANDOM, 2, 0, 0, YES, NO },
\r
64 { "thingcount", PCD_THINGCOUNTDIRECT, PCD_THINGCOUNT, 2, 0, 0, YES, NO },
\r
65 { "thingcountname", PCD_NOP, PCD_THINGCOUNTNAME, 2, 0, 0, YES, NO },
\r
66 { "changefloor", PCD_CHANGEFLOORDIRECT, PCD_CHANGEFLOOR, 2, 0, 0, NO, NO },
\r
67 { "changeceiling", PCD_CHANGECEILINGDIRECT, PCD_CHANGECEILING, 2, 0, 0, NO, NO },
\r
68 { "lineside", PCD_NOP, PCD_LINESIDE, 0, 0, 0, YES, NO },
\r
69 { "clearlinespecial", PCD_NOP, PCD_CLEARLINESPECIAL, 0, 0, 0, NO, NO },
\r
70 { "playercount", PCD_NOP, PCD_PLAYERCOUNT, 0, 0, 0, YES, NO },
\r
71 { "gametype", PCD_NOP, PCD_GAMETYPE, 0, 0, 0, YES, NO },
\r
72 { "gameskill", PCD_NOP, PCD_GAMESKILL, 0, 0, 0, YES, NO },
\r
73 { "timer", PCD_NOP, PCD_TIMER, 0, 0, 0, YES, NO },
\r
74 { "sectorsound", PCD_NOP, PCD_SECTORSOUND, 2, 0, 0, NO, NO },
\r
75 { "ambientsound", PCD_NOP, PCD_AMBIENTSOUND, 2, 0, 0, NO, NO },
\r
76 { "soundsequence", PCD_NOP, PCD_SOUNDSEQUENCE, 1, 0, 0, NO, NO },
\r
77 { "setlinetexture", PCD_NOP, PCD_SETLINETEXTURE, 4, 0, 0, NO, NO },
\r
78 { "setlineblocking", PCD_NOP, PCD_SETLINEBLOCKING, 2, 0, 0, NO, NO },
\r
79 { "setlinespecial", PCD_NOP, PCD_SETLINESPECIAL, 7, 4|8|16|32|64, 0, NO, NO },
\r
80 { "thingsound", PCD_NOP, PCD_THINGSOUND, 3, 0, 0, NO, NO },
\r
81 { "activatorsound", PCD_NOP, PCD_ACTIVATORSOUND, 2, 0, 0, NO, NO },
\r
82 { "localambientsound", PCD_NOP, PCD_LOCALAMBIENTSOUND, 2, 0, 0, NO, NO },
\r
83 { "setlinemonsterblocking", PCD_NOP, PCD_SETLINEMONSTERBLOCKING, 2, 0, 0, NO, NO },
\r
84 { "fixedmul", PCD_NOP, PCD_FIXEDMUL, 2, 0, 0, YES, NO },
\r
85 { "fixeddiv", PCD_NOP, PCD_FIXEDDIV, 2, 0, 0, YES, NO },
\r
86 // [BC] Start of new pcodes
\r
87 { "playerblueskull", PCD_NOP, PCD_PLAYERBLUESKULL, 0, 0, 0, YES, NO },
\r
88 { "playerredskull", PCD_NOP, PCD_PLAYERREDSKULL, 0, 0, 0, YES, NO },
\r
89 { "playeryellowskull", PCD_NOP, PCD_PLAYERYELLOWSKULL, 0, 0, 0, YES, NO },
\r
90 { "playerbluecard", PCD_NOP, PCD_PLAYERBLUECARD, 0, 0, 0, YES, NO },
\r
91 { "playerredcard", PCD_NOP, PCD_PLAYERREDCARD, 0, 0, 0, YES, NO },
\r
92 { "playeryellowcard", PCD_NOP, PCD_PLAYERYELLOWCARD, 0, 0, 0, YES, NO },
\r
93 { "playeronteam", PCD_NOP, PCD_PLAYERONTEAM, 0, 0, 0, YES, NO },
\r
94 { "playerteam", PCD_NOP, PCD_PLAYERTEAM, 0, 0, 0, YES, NO },
\r
95 { "playerfrags", PCD_NOP, PCD_PLAYERFRAGS, 0, 0, 0, YES, NO },
\r
96 { "playerhealth", PCD_NOP, PCD_PLAYERHEALTH, 0, 0, 0, YES, NO },
\r
97 { "playerarmorpoints", PCD_NOP, PCD_PLAYERARMORPOINTS, 0, 0, 0, YES, NO },
\r
98 { "playerexpert", PCD_NOP, PCD_PLAYEREXPERT, 0, 0, 0, YES, NO },
\r
99 { "bluecount", PCD_NOP, PCD_BLUETEAMCOUNT, 0, 0, 0, YES, NO },
\r
100 { "redcount", PCD_NOP, PCD_REDTEAMCOUNT, 0, 0, 0, YES, NO },
\r
101 { "bluescore", PCD_NOP, PCD_BLUETEAMSCORE, 0, 0, 0, YES, NO },
\r
102 { "redscore", PCD_NOP, PCD_REDTEAMSCORE, 0, 0, 0, YES, NO },
\r
103 { "isoneflagctf", PCD_NOP, PCD_ISONEFLAGCTF, 0, 0, 0, YES, NO },
\r
104 { "getinvasionwave", PCD_NOP, PCD_GETINVASIONWAVE, 0, 0, 0, YES, NO },
\r
105 { "getinvasionstate", PCD_NOP, PCD_GETINVASIONSTATE, 0, 0, 0, YES, NO },
\r
106 { "music_change", PCD_NOP, PCD_MUSICCHANGE, 2, 0, 0, NO, NO },
\r
107 { "consolecommand", PCD_CONSOLECOMMANDDIRECT, PCD_CONSOLECOMMAND, 3, 2|4, 0, NO, NO },
\r
108 { "singleplayer", PCD_NOP, PCD_SINGLEPLAYER, 0, 0, 0, YES, NO },
\r
109 // [RH] end of Skull Tag functions
\r
110 { "setgravity", PCD_SETGRAVITYDIRECT, PCD_SETGRAVITY, 1, 0, 0, NO, NO },
\r
111 { "setaircontrol", PCD_SETAIRCONTROLDIRECT, PCD_SETAIRCONTROL, 1, 0, 0, NO, NO },
\r
112 { "clearinventory", PCD_NOP, PCD_CLEARINVENTORY, 0, 0, 0, NO, NO },
\r
113 { "giveinventory", PCD_GIVEINVENTORYDIRECT, PCD_GIVEINVENTORY, 2, 0, 0, NO, NO },
\r
114 { "takeinventory", PCD_TAKEINVENTORYDIRECT, PCD_TAKEINVENTORY, 2, 0, 0, NO, NO },
\r
115 { "checkinventory", PCD_CHECKINVENTORYDIRECT, PCD_CHECKINVENTORY, 1, 0, 0, YES, NO },
\r
116 { "clearactorinventory", PCD_NOP, PCD_CLEARACTORINVENTORY, 1, 0, 0, NO, NO },
\r
117 { "giveactorinventory", PCD_NOP, PCD_GIVEACTORINVENTORY, 3, 0, 0, NO, NO },
\r
118 { "takeactorinventory", PCD_NOP, PCD_TAKEACTORINVENTORY, 3, 0, 0, NO, NO },
\r
119 { "checkactorinventory", PCD_NOP, PCD_CHECKACTORINVENTORY, 2, 0, 0, YES, NO },
\r
120 { "spawn", PCD_SPAWNDIRECT, PCD_SPAWN, 6, 16|32, 0, YES, NO },
\r
121 { "spawnspot", PCD_SPAWNSPOTDIRECT, PCD_SPAWNSPOT, 4, 4|8, 0, YES, NO },
\r
122 { "spawnspotfacing", PCD_NOP, PCD_SPAWNSPOTFACING, 3, 4, 0, YES, NO },
\r
123 { "setmusic", PCD_SETMUSICDIRECT, PCD_SETMUSIC, 3, 2|4, 0, NO, NO },
\r
124 { "localsetmusic", PCD_LOCALSETMUSICDIRECT, PCD_LOCALSETMUSIC, 3, 2|4, 0, NO, NO },
\r
125 { "setstyle", PCD_SETSTYLEDIRECT, PCD_SETSTYLE, 1, 0, 0, NO, NO },
\r
126 { "setfont", PCD_SETFONTDIRECT, PCD_SETFONT, 1, 0, 0, NO, NO },
\r
127 { "setthingspecial", PCD_NOP, PCD_SETTHINGSPECIAL, 7, 4|8|16|32|64, 0, NO, NO },
\r
128 { "fadeto", PCD_NOP, PCD_FADETO, 5, 0, 0, NO, NO },
\r
129 { "faderange", PCD_NOP, PCD_FADERANGE, 9, 0, 0, NO, NO },
\r
130 { "cancelfade", PCD_NOP, PCD_CANCELFADE, 0, 0, 0, NO, NO },
\r
131 { "playmovie", PCD_NOP, PCD_PLAYMOVIE, 1, 0, 0, YES, NO },
\r
132 { "setfloortrigger", PCD_NOP, PCD_SETFLOORTRIGGER, 8, 8|16|32|64|128, 0, NO, NO },
\r
133 { "setceilingtrigger", PCD_NOP, PCD_SETCEILINGTRIGGER, 8, 8|16|32|64|128, 0, NO, NO },
\r
134 { "setactorposition", PCD_NOP, PCD_SETACTORPOSITION, 5, 0, 0, YES, NO },
\r
135 { "getactorx", PCD_NOP, PCD_GETACTORX, 1, 0, 0, YES, NO },
\r
136 { "getactory", PCD_NOP, PCD_GETACTORY, 1, 0, 0, YES, NO },
\r
137 { "getactorz", PCD_NOP, PCD_GETACTORZ, 1, 0, 0, YES, NO },
\r
138 { "getactorfloorz", PCD_NOP, PCD_GETACTORFLOORZ, 1, 0, 0, YES, NO },
\r
139 { "getactorceilingz", PCD_NOP, PCD_GETACTORCEILINGZ, 1, 0, 0, YES, NO },
\r
140 { "getactorangle", PCD_NOP, PCD_GETACTORANGLE, 1, 0, 0, YES, NO },
\r
141 { "writetoini", PCD_NOP, PCD_WRITETOINI, 3, 0, 0, NO, NO },
\r
142 { "getfromini", PCD_NOP, PCD_GETFROMINI, 3, 0, 0, YES, NO },
\r
143 { "sin", PCD_NOP, PCD_SIN, 1, 0, 0, YES, NO },
\r
144 { "cos", PCD_NOP, PCD_COS, 1, 0, 0, YES, NO },
\r
145 { "vectorangle", PCD_NOP, PCD_VECTORANGLE, 2, 0, 0, YES, NO },
\r
146 { "checkweapon", PCD_NOP, PCD_CHECKWEAPON, 1, 0, 0, YES, NO },
\r
147 { "setweapon", PCD_NOP, PCD_SETWEAPON, 1, 0, 0, YES, NO },
\r
148 { "setmarineweapon", PCD_NOP, PCD_SETMARINEWEAPON, 2, 0, 0, NO, NO },
\r
149 { "setactorproperty", PCD_NOP, PCD_SETACTORPROPERTY, 3, 0, 0, NO, NO },
\r
150 { "getactorproperty", PCD_NOP, PCD_GETACTORPROPERTY, 2, 0, 0, YES, NO },
\r
151 { "playernumber", PCD_NOP, PCD_PLAYERNUMBER, 0, 0, 0, YES, NO },
\r
152 { "activatortid", PCD_NOP, PCD_ACTIVATORTID, 0, 0, 0, YES, NO },
\r
153 { "setmarinesprite", PCD_NOP, PCD_SETMARINESPRITE, 2, 0, 0, NO, NO },
\r
154 { "getscreenwidth", PCD_NOP, PCD_GETSCREENWIDTH, 0, 0, 0, YES, NO },
\r
155 { "getscreenheight", PCD_NOP, PCD_GETSCREENHEIGHT, 0, 0, 0, YES, NO },
\r
156 { "thing_projectile2", PCD_NOP, PCD_THING_PROJECTILE2, 7, 0, 0, NO, NO },
\r
157 { "strlen", PCD_NOP, PCD_STRLEN, 1, 0, 0, YES, NO },
\r
158 { "sethudsize", PCD_NOP, PCD_SETHUDSIZE, 3, 0, 0, NO, NO },
\r
159 { "getcvar", PCD_NOP, PCD_GETCVAR, 1, 0, 0, YES, NO },
\r
160 { "setresultvalue", PCD_NOP, PCD_SETRESULTVALUE, 1, 0, 0, NO, NO },
\r
161 { "getlinerowoffset", PCD_NOP, PCD_GETLINEROWOFFSET, 0, 0, 0, YES, NO },
\r
162 { "getsectorfloorz", PCD_NOP, PCD_GETSECTORFLOORZ, 3, 0, 0, YES, NO },
\r
163 { "getsectorceilingz", PCD_NOP, PCD_GETSECTORCEILINGZ, 3, 0, 0, YES, NO },
\r
164 { "getsigilpieces", PCD_NOP, PCD_GETSIGILPIECES, 0, 0, 0, YES, NO },
\r
165 { "getlevelinfo", PCD_NOP, PCD_GETLEVELINFO, 1, 0, 0, YES, NO },
\r
166 { "changesky", PCD_NOP, PCD_CHANGESKY, 2, 0, 0, NO, NO },
\r
167 { "playeringame", PCD_NOP, PCD_PLAYERINGAME, 1, 0, 0, YES, NO },
\r
168 { "playerisbot", PCD_NOP, PCD_PLAYERISBOT, 1, 0, 0, YES, NO },
\r
169 { "setcameratotexture", PCD_NOP, PCD_SETCAMERATOTEXTURE, 3, 0, 0, NO, NO },
\r
170 { "grabinput", PCD_NOP, PCD_GRABINPUT, 2, 0, 0, NO, NO },
\r
171 { "setmousepointer", PCD_NOP, PCD_SETMOUSEPOINTER, 3, 0, 0, NO, NO },
\r
172 { "movemousepointer", PCD_NOP, PCD_MOVEMOUSEPOINTER, 2, 0, 0, NO, NO },
\r
173 { "getammocapacity", PCD_NOP, PCD_GETAMMOCAPACITY, 1, 0, 0, YES, NO },
\r
174 { "setammocapacity", PCD_NOP, PCD_SETAMMOCAPACITY, 2, 0, 0, NO, NO },
\r
175 { "setactorangle", PCD_NOP, PCD_SETACTORANGLE, 2, 0, 0, NO, NO },
\r
176 { "spawnprojectile", PCD_NOP, PCD_SPAWNPROJECTILE, 7, 0, 0, NO, NO },
\r
177 { "getsectorlightlevel", PCD_NOP, PCD_GETSECTORLIGHTLEVEL, 1, 0, 0, YES, NO },
\r
178 { "playerclass", PCD_NOP, PCD_PLAYERCLASS, 1, 0, 0, YES, NO },
\r
179 { "getplayerinfo", PCD_NOP, PCD_GETPLAYERINFO, 2, 0, 0, YES, NO },
\r
180 { "changelevel", PCD_NOP, PCD_CHANGELEVEL, 4, 8, 0, NO, NO },
\r
181 { "sectordamage", PCD_NOP, PCD_SECTORDAMAGE, 5, 0, 0, NO, NO },
\r
182 { "replacetextures", PCD_NOP, PCD_REPLACETEXTURES, 3, 4, 0, NO, NO },
\r
183 { "getactorpitch", PCD_NOP, PCD_GETACTORPITCH, 1, 0, 0, YES, NO },
\r
184 { "setactorpitch", PCD_NOP, PCD_SETACTORPITCH, 2, 0, 0, NO, NO },
\r
185 { "setactorstate", PCD_NOP, PCD_SETACTORSTATE, 3, 4, 0, YES, NO },
\r
186 { "thing_damage2", PCD_NOP, PCD_THINGDAMAGE2, 3, 0, 0, YES, NO },
\r
187 { "useinventory", PCD_NOP, PCD_USEINVENTORY, 1, 0, 0, YES, NO },
\r
188 { "useactorinventory", PCD_NOP, PCD_USEACTORINVENTORY, 2, 0, 0, YES, NO },
\r
189 { "checkactorceilingtexture", PCD_NOP, PCD_CHECKACTORCEILINGTEXTURE, 2, 0, 0, YES, NO },
\r
190 { "checkactorfloortexture", PCD_NOP, PCD_CHECKACTORFLOORTEXTURE, 2, 0, 0, YES, NO },
\r
191 { "getactorlightlevel", PCD_NOP, PCD_GETACTORLIGHTLEVEL, 1, 0, 0, YES, NO },
\r
192 { "setmugshotstate", PCD_NOP, PCD_SETMUGSHOTSTATE, 1, 0, 0, NO, NO },
\r
193 { "thingcountsector", PCD_NOP, PCD_THINGCOUNTSECTOR, 3, 0, 0, YES, NO },
\r
194 { "thingcountnamesector", PCD_NOP, PCD_THINGCOUNTNAMESECTOR, 3, 0, 0, YES, NO },
\r
195 { "checkplayercamera", PCD_NOP, PCD_CHECKPLAYERCAMERA, 1, 0, 0, YES, NO },
\r
196 { "morphactor", PCD_NOP, PCD_MORPHACTOR, 7, 2|4|8|16|32|64, 0, YES, NO },
\r
197 { "unmorphactor", PCD_NOP, PCD_UNMORPHACTOR, 2, 2, 0, YES, NO },
\r
198 { "getplayerinput", PCD_NOP, PCD_GETPLAYERINPUT, 2, 0, 0, YES, NO },
\r
199 { "classifyactor", PCD_NOP, PCD_CLASSIFYACTOR, 1, 0, 0, YES, NO },
\r
201 { NULL, PCD_NOP, PCD_NOP, 0, 0, 0, NO, NO }
\r
204 static char *SymbolTypeNames[] =
\r
222 // CODE --------------------------------------------------------------------
\r
224 //==========================================================================
\r
228 //==========================================================================
\r
233 internFuncDef_t *def;
\r
237 for(def = InternalFunctions; def->name != NULL; def++)
\r
239 sym = SY_InsertGlobal(def->name, SY_INTERNFUNC);
\r
240 sym->info.internFunc.directCommand = def->directCommand;
\r
241 sym->info.internFunc.stackCommand = def->stackCommand;
\r
242 sym->info.internFunc.argCount = def->argCount;
\r
243 sym->info.internFunc.optMask = def->optMask;
\r
244 sym->info.internFunc.outMask = def->outMask;
\r
245 sym->info.internFunc.hasReturnValue = def->hasReturnValue;
\r
246 sym->info.internFunc.latent = def->latent;
\r
250 //==========================================================================
\r
254 //==========================================================================
\r
256 symbolNode_t *SY_Find(char *name)
\r
258 symbolNode_t *node;
\r
260 if((node = SY_FindGlobal(name)) == NULL)
\r
262 return SY_FindLocal(name);
\r
267 //==========================================================================
\r
271 //==========================================================================
\r
273 symbolNode_t *SY_FindGlobal(char *name)
\r
275 symbolNode_t *sym = Find(name, GlobalRoot);
\r
276 if(sym != NULL && sym->unused)
\r
278 MS_Message(MSG_DEBUG, "Symbol %s marked as used.\n", name);
\r
280 if(sym->type == SY_SCRIPTFUNC)
\r
282 PC_AddFunction(sym);
\r
284 else if(sym->type == SY_MAPVAR)
\r
286 if(pa_MapVarCount >= MAX_MAP_VARIABLES)
\r
288 ERR_Error(ERR_TOO_MANY_MAP_VARS, YES);
\r
292 sym->info.var.index = pa_MapVarCount++;
\r
293 PC_NameMapVariable(sym->info.var.index, sym);
\r
296 else if(sym->type == SY_MAPARRAY)
\r
298 if(pa_MapVarCount >= MAX_MAP_VARIABLES)
\r
300 ERR_Error(ERR_TOO_MANY_MAP_VARS, YES);
\r
304 sym->info.array.index = pa_MapVarCount++;
\r
305 PC_NameMapVariable(sym->info.array.index, sym);
\r
306 if(sym->type == SY_MAPARRAY)
\r
308 PC_AddArray(sym->info.array.index, sym->info.array.size);
\r
316 //==========================================================================
\r
320 //==========================================================================
\r
322 symbolNode_t *SY_FindLocal(char *name)
\r
324 return Find(name, LocalRoot);
\r
327 //==========================================================================
\r
331 //==========================================================================
\r
333 static symbolNode_t *Find(char *name, symbolNode_t *root)
\r
336 symbolNode_t *node;
\r
339 while(node != NULL)
\r
341 compare = strcmp(name, node->name);
\r
344 if(node->type != SY_DUMMY)
\r
353 node = compare < 0 ? node->left : node->right;
\r
358 //==========================================================================
\r
362 //==========================================================================
\r
364 symbolNode_t *SY_InsertLocal(char *name, symbolType_t type)
\r
366 if(Find(name, GlobalRoot))
\r
368 ERR_Error(ERR_LOCAL_VAR_SHADOWED, YES);
\r
370 MS_Message(MSG_DEBUG, "Inserting local identifier: %s (%s)\n",
\r
371 name, SymbolTypeNames[type]);
\r
372 return Insert(name, type, &LocalRoot);
\r
375 //==========================================================================
\r
379 //==========================================================================
\r
381 symbolNode_t *SY_InsertGlobal(char *name, symbolType_t type)
\r
383 MS_Message(MSG_DEBUG, "Inserting global identifier: %s (%s)\n",
\r
384 name, SymbolTypeNames[type]);
\r
385 return Insert(name, type, &GlobalRoot);
\r
388 //==========================================================================
\r
390 // SY_InsertGlobalUnique
\r
392 //==========================================================================
\r
394 symbolNode_t *SY_InsertGlobalUnique(char *name, symbolType_t type)
\r
396 if(SY_FindGlobal(name) != NULL)
\r
398 ERR_Exit(ERR_REDEFINED_IDENTIFIER, YES, name);
\r
400 return SY_InsertGlobal(name, type);
\r
403 //==========================================================================
\r
407 //==========================================================================
\r
409 static symbolNode_t *Insert(char *name, symbolType_t type,
\r
410 symbolNode_t **root)
\r
413 symbolNode_t *newNode;
\r
414 symbolNode_t *node;
\r
416 newNode = MS_Alloc(sizeof(symbolNode_t), ERR_NO_SYMBOL_MEM);
\r
417 newNode->name = MS_Alloc(strlen(name)+1, ERR_NO_SYMBOL_MEM);
\r
418 strcpy(newNode->name, name);
\r
419 newNode->left = newNode->right = NULL;
\r
420 newNode->type = type;
\r
421 newNode->unused = NO;
\r
422 newNode->imported = ImportMode == IMPORT_Importing;
\r
423 while((node = *root) != NULL)
\r
425 compare = strcmp(name, node->name);
\r
426 root = compare < 0 ? &(node->left) : &(node->right);
\r
432 //==========================================================================
\r
436 //==========================================================================
\r
438 void SY_FreeLocals(void)
\r
440 MS_Message(MSG_DEBUG, "Freeing local identifiers\n");
\r
441 FreeNodes(LocalRoot);
\r
445 //==========================================================================
\r
449 //==========================================================================
\r
451 void SY_FreeGlobals(void)
\r
453 MS_Message(MSG_DEBUG, "Freeing global identifiers\n");
\r
454 FreeNodes(GlobalRoot);
\r
458 //==========================================================================
\r
462 //==========================================================================
\r
464 static void FreeNodes(symbolNode_t *root)
\r
470 FreeNodes(root->left);
\r
471 FreeNodes(root->right);
\r
476 //==========================================================================
\r
478 // SY_FreeConstants
\r
480 //==========================================================================
\r
482 void SY_FreeConstants(int depth)
\r
484 MS_Message(MSG_DEBUG, "Freeing constants for depth %d\n", depth);
\r
485 FreeNodesAtDepth(&GlobalRoot, depth);
\r
488 //==========================================================================
\r
490 // FreeNodesAtDepth
\r
492 // Like FreeNodes, but it only frees the nodes of type SY_CONSTANT that are
\r
493 // marked at the specified depth. The other nodes are relinked to maintain a
\r
494 // proper binary tree.
\r
496 //==========================================================================
\r
498 static void FreeNodesAtDepth(symbolNode_t **root, int depth)
\r
500 symbolNode_t *node = *root;
\r
506 FreeNodesAtDepth(&node->left, depth);
\r
507 FreeNodesAtDepth(&node->right, depth);
\r
508 if(node->type == SY_CONSTANT && node->info.constant.fileDepth == depth)
\r
510 MS_Message(MSG_DEBUG, "Deleting constant %s\n", node->name);
\r
511 DeleteNode(node, root);
\r
515 //==========================================================================
\r
519 //==========================================================================
\r
521 static void DeleteNode(symbolNode_t *node, symbolNode_t **parent_p)
\r
523 symbolNode_t **temp;
\r
526 if(node->left == NULL)
\r
528 *parent_p = node->right;
\r
532 else if(node->right == NULL)
\r
534 *parent_p = node->left;
\r
540 // "Randomly" pick the in-order successor or predecessor to take
\r
541 // the place of the deleted node.
\r
545 temp = &node->left;
\r
546 while((*temp)->right != NULL)
\r
548 temp = &(*temp)->right;
\r
554 temp = &node->right;
\r
555 while((*temp)->left != NULL)
\r
557 temp = &(*temp)->left;
\r
560 nametemp = node->name;
\r
561 node->name = (*temp)->name;
\r
562 (*temp)->name = nametemp;
\r
563 node->type = (*temp)->type;
\r
564 node->unused = (*temp)->unused;
\r
565 node->imported = (*temp)->imported;
\r
566 node->info = (*temp)->info;
\r
567 DeleteNode(*temp, temp);
\r
571 //==========================================================================
\r
575 //==========================================================================
\r
577 void SY_ClearShared(void)
\r
579 MS_Message(MSG_DEBUG, "Marking library exports as unused\n");
\r
580 ClearShared(GlobalRoot);
\r
583 //==========================================================================
\r
587 //==========================================================================
\r
589 static void ClearShared(symbolNode_t *root)
\r
591 while(root != NULL)
\r
593 if( root->type == SY_SCRIPTFUNC ||
\r
594 root->type == SY_MAPVAR ||
\r
595 root->type == SY_MAPARRAY)
\r
597 root->unused = YES;
\r
599 ClearShared(root->left);
\r
600 root = root->right;
\r