]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/game/script/Script_Compiler.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / game / script / Script_Compiler.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "../Game_local.h"
33
34 #define FUNCTION_PRIORITY       2
35 #define INT_PRIORITY            2
36 #define NOT_PRIORITY            5
37 #define TILDE_PRIORITY          5
38 #define TOP_PRIORITY            7
39
40 bool idCompiler::punctuationValid[ 256 ];
41 char *idCompiler::punctuation[] = {
42         "+=", "-=", "*=", "/=", "%=", "&=", "|=", "++", "--",
43         "&&", "||", "<=", ">=", "==", "!=", "::", ";",  ",",
44         "~",  "!",  "*",  "/",  "%",  "(",   ")",  "-", "+",
45         "=",  "[",  "]",  ".",  "<",  ">" ,  "&",  "|", ":",  NULL
46 };
47
48 opcode_t idCompiler::opcodes[] = {
49         { "<RETURN>", "RETURN", -1, false, &def_void, &def_void, &def_void },
50                 
51         { "++", "UINC_F", 1, true, &def_float, &def_void, &def_void },
52         { "++", "UINCP_F", 1, true, &def_object, &def_field, &def_float },
53         { "--", "UDEC_F", 1, true, &def_float, &def_void, &def_void },
54         { "--", "UDECP_F", 1, true, &def_object, &def_field, &def_float },
55
56         { "~", "COMP_F", -1, false, &def_float, &def_void, &def_float },
57         
58         { "*", "MUL_F", 3, false, &def_float, &def_float, &def_float },
59         { "*", "MUL_V", 3, false, &def_vector, &def_vector, &def_float },
60         { "*", "MUL_FV", 3, false, &def_float, &def_vector, &def_vector },
61         { "*", "MUL_VF", 3, false, &def_vector, &def_float, &def_vector },
62         
63         { "/", "DIV", 3, false, &def_float, &def_float, &def_float },
64         { "%", "MOD_F", 3, false, &def_float, &def_float, &def_float },
65         
66         { "+", "ADD_F", 4, false, &def_float, &def_float, &def_float },
67         { "+", "ADD_V", 4, false, &def_vector, &def_vector, &def_vector },
68         { "+", "ADD_S", 4, false, &def_string, &def_string, &def_string },
69         { "+", "ADD_FS", 4, false, &def_float, &def_string, &def_string },
70         { "+", "ADD_SF", 4, false, &def_string, &def_float, &def_string },
71         { "+", "ADD_VS", 4, false, &def_vector, &def_string, &def_string },
72         { "+", "ADD_SV", 4, false, &def_string, &def_vector, &def_string },
73         
74         { "-", "SUB_F", 4, false, &def_float, &def_float, &def_float },
75         { "-", "SUB_V", 4, false, &def_vector, &def_vector, &def_vector },
76         
77         { "==", "EQ_F", 5, false, &def_float, &def_float, &def_float },
78         { "==", "EQ_V", 5, false, &def_vector, &def_vector, &def_float },
79         { "==", "EQ_S", 5, false, &def_string, &def_string, &def_float },
80         { "==", "EQ_E", 5, false, &def_entity, &def_entity, &def_float },
81         { "==", "EQ_EO", 5, false, &def_entity, &def_object, &def_float },
82         { "==", "EQ_OE", 5, false, &def_object, &def_entity, &def_float },
83         { "==", "EQ_OO", 5, false, &def_object, &def_object, &def_float },
84         
85         { "!=", "NE_F", 5, false, &def_float, &def_float, &def_float },
86         { "!=", "NE_V", 5, false, &def_vector, &def_vector, &def_float },
87         { "!=", "NE_S", 5, false, &def_string, &def_string, &def_float },
88     { "!=", "NE_E", 5, false, &def_entity, &def_entity, &def_float },
89         { "!=", "NE_EO", 5, false, &def_entity, &def_object, &def_float },
90         { "!=", "NE_OE", 5, false, &def_object, &def_entity, &def_float },
91         { "!=", "NE_OO", 5, false, &def_object, &def_object, &def_float },
92         
93         { "<=", "LE", 5, false, &def_float, &def_float, &def_float },
94         { ">=", "GE", 5, false, &def_float, &def_float, &def_float },
95         { "<", "LT", 5, false, &def_float, &def_float, &def_float },
96         { ">", "GT", 5, false, &def_float, &def_float, &def_float },
97         
98         { ".", "INDIRECT_F", 1, false, &def_object, &def_field, &def_float },
99         { ".", "INDIRECT_V", 1, false, &def_object, &def_field, &def_vector },
100         { ".", "INDIRECT_S", 1, false, &def_object, &def_field, &def_string },
101         { ".", "INDIRECT_E", 1, false, &def_object, &def_field, &def_entity },
102         { ".", "INDIRECT_BOOL", 1, false, &def_object, &def_field, &def_boolean },
103         { ".", "INDIRECT_OBJ", 1, false, &def_object, &def_field, &def_object },
104
105         { ".", "ADDRESS", 1, false, &def_entity, &def_field, &def_pointer },
106
107         { ".", "EVENTCALL", 2, false, &def_entity, &def_function, &def_void },
108         { ".", "OBJECTCALL", 2, false, &def_object, &def_function, &def_void },
109         { ".", "SYSCALL", 2, false, &def_void, &def_function, &def_void },
110
111         { "=", "STORE_F", 6, true, &def_float, &def_float, &def_float },
112         { "=", "STORE_V", 6, true, &def_vector, &def_vector, &def_vector },
113         { "=", "STORE_S", 6, true, &def_string, &def_string, &def_string },
114         { "=", "STORE_ENT", 6, true, &def_entity, &def_entity, &def_entity },
115         { "=", "STORE_BOOL", 6, true, &def_boolean, &def_boolean, &def_boolean },
116         { "=", "STORE_OBJENT", 6, true, &def_object, &def_entity, &def_object },
117         { "=", "STORE_OBJ", 6, true, &def_object, &def_object, &def_object },
118         { "=", "STORE_OBJENT", 6, true, &def_entity, &def_object, &def_object },
119         
120         { "=", "STORE_FTOS", 6, true, &def_string, &def_float, &def_string },
121         { "=", "STORE_BTOS", 6, true, &def_string, &def_boolean, &def_string },
122         { "=", "STORE_VTOS", 6, true, &def_string, &def_vector, &def_string },
123         { "=", "STORE_FTOBOOL", 6, true, &def_boolean, &def_float, &def_boolean },
124         { "=", "STORE_BOOLTOF", 6, true, &def_float, &def_boolean, &def_float },
125
126         { "=", "STOREP_F", 6, true, &def_pointer, &def_float, &def_float },
127         { "=", "STOREP_V", 6, true, &def_pointer, &def_vector, &def_vector },
128         { "=", "STOREP_S", 6, true, &def_pointer, &def_string, &def_string },
129         { "=", "STOREP_ENT", 6, true, &def_pointer, &def_entity, &def_entity },
130         { "=", "STOREP_FLD", 6, true, &def_pointer, &def_field, &def_field },
131         { "=", "STOREP_BOOL", 6, true, &def_pointer, &def_boolean, &def_boolean },
132         { "=", "STOREP_OBJ", 6, true, &def_pointer, &def_object, &def_object },
133         { "=", "STOREP_OBJENT", 6, true, &def_pointer, &def_object, &def_object },
134
135         { "<=>", "STOREP_FTOS", 6, true, &def_pointer, &def_float, &def_string },
136         { "<=>", "STOREP_BTOS", 6, true, &def_pointer, &def_boolean, &def_string },
137         { "<=>", "STOREP_VTOS", 6, true, &def_pointer, &def_vector, &def_string },
138         { "<=>", "STOREP_FTOBOOL", 6, true, &def_pointer, &def_float, &def_boolean },
139         { "<=>", "STOREP_BOOLTOF", 6, true, &def_pointer, &def_boolean, &def_float },
140         
141         { "*=", "UMUL_F", 6, true, &def_float, &def_float, &def_void },
142         { "*=", "UMUL_V", 6, true, &def_vector, &def_float, &def_void },
143         { "/=", "UDIV_F", 6, true, &def_float, &def_float, &def_void },
144         { "/=", "UDIV_V", 6, true, &def_vector, &def_float, &def_void },
145         { "%=", "UMOD_F", 6, true, &def_float, &def_float, &def_void },
146         { "+=", "UADD_F", 6, true, &def_float, &def_float, &def_void },
147         { "+=", "UADD_V", 6, true, &def_vector, &def_vector, &def_void },
148         { "-=", "USUB_F", 6, true, &def_float, &def_float, &def_void },
149         { "-=", "USUB_V", 6, true, &def_vector, &def_vector, &def_void },
150         { "&=", "UAND_F", 6, true, &def_float, &def_float, &def_void },
151         { "|=", "UOR_F", 6, true, &def_float, &def_float, &def_void },
152         
153         { "!", "NOT_BOOL", -1, false, &def_boolean, &def_void, &def_float },
154         { "!", "NOT_F", -1, false, &def_float, &def_void, &def_float },
155         { "!", "NOT_V", -1, false, &def_vector, &def_void, &def_float },
156         { "!", "NOT_S", -1, false, &def_vector, &def_void, &def_float },
157         { "!", "NOT_ENT", -1, false, &def_entity, &def_void, &def_float },
158
159         { "<NEG_F>", "NEG_F", -1, false, &def_float, &def_void, &def_float },
160         { "<NEG_V>", "NEG_V", -1, false, &def_vector, &def_void, &def_vector },
161
162         { "int", "INT_F", -1, false, &def_float, &def_void, &def_float },
163         
164         { "<IF>", "IF", -1, false, &def_float, &def_jumpoffset, &def_void },
165         { "<IFNOT>", "IFNOT", -1, false, &def_float, &def_jumpoffset, &def_void },
166         
167         // calls returns REG_RETURN
168         { "<CALL>", "CALL", -1, false, &def_function, &def_argsize, &def_void },
169         { "<THREAD>", "THREAD", -1, false, &def_function, &def_argsize, &def_void },
170         { "<THREAD>", "OBJTHREAD", -1, false, &def_function, &def_argsize, &def_void },
171         
172         { "<PUSH>", "PUSH_F", -1, false, &def_float, &def_float, &def_void },
173         { "<PUSH>", "PUSH_V", -1, false, &def_vector, &def_vector, &def_void },
174         { "<PUSH>", "PUSH_S", -1, false, &def_string, &def_string, &def_void },
175         { "<PUSH>", "PUSH_ENT", -1, false, &def_entity, &def_entity, &def_void },
176         { "<PUSH>", "PUSH_OBJ", -1, false, &def_object, &def_object, &def_void },
177         { "<PUSH>", "PUSH_OBJENT", -1, false, &def_entity, &def_object, &def_void },
178         { "<PUSH>", "PUSH_FTOS", -1, false, &def_string, &def_float, &def_void },
179         { "<PUSH>", "PUSH_BTOF", -1, false, &def_float, &def_boolean, &def_void },
180         { "<PUSH>", "PUSH_FTOB", -1, false, &def_boolean, &def_float, &def_void },
181         { "<PUSH>", "PUSH_VTOS", -1, false, &def_string, &def_vector, &def_void },
182         { "<PUSH>", "PUSH_BTOS", -1, false, &def_string, &def_boolean, &def_void },
183         
184         { "<GOTO>", "GOTO", -1, false, &def_jumpoffset, &def_void, &def_void },
185         
186         { "&&", "AND", 7, false, &def_float, &def_float, &def_float },
187         { "&&", "AND_BOOLF", 7, false, &def_boolean, &def_float, &def_float },
188         { "&&", "AND_FBOOL", 7, false, &def_float, &def_boolean, &def_float },
189         { "&&", "AND_BOOLBOOL", 7, false, &def_boolean, &def_boolean, &def_float },
190         { "||", "OR", 7, false, &def_float, &def_float, &def_float },
191         { "||", "OR_BOOLF", 7, false, &def_boolean, &def_float, &def_float },
192         { "||", "OR_FBOOL", 7, false, &def_float, &def_boolean, &def_float },
193         { "||", "OR_BOOLBOOL", 7, false, &def_boolean, &def_boolean, &def_float },
194         
195         { "&", "BITAND", 3, false, &def_float, &def_float, &def_float },
196         { "|", "BITOR", 3, false, &def_float, &def_float, &def_float },
197
198         { "<BREAK>", "BREAK", -1, false, &def_float, &def_void, &def_void },
199         { "<CONTINUE>", "CONTINUE", -1, false, &def_float, &def_void, &def_void },
200
201         { NULL }
202 };
203
204 /*
205 ================
206 idCompiler::idCompiler()
207 ================
208 */
209 idCompiler::idCompiler() {
210         char    **ptr;
211         int             id;
212
213         // make sure we have the right # of opcodes in the table
214         assert( ( sizeof( opcodes ) / sizeof( opcodes[ 0 ] ) ) == ( NUM_OPCODES + 1 ) );
215
216         eof     = true;
217         parserPtr = &parser;
218
219         callthread                      = false;
220         loopDepth                       = 0;
221         eof                                     = false;
222         braceDepth                      = 0;
223         immediateType           = NULL;
224         basetype                        = NULL;
225         currentLineNumber       = 0;
226         currentFileNumber       = 0;
227         errorCount                      = 0;
228         console                         = false;
229         scope                           = &def_namespace;
230
231         memset( &immediate, 0, sizeof( immediate ) );
232         memset( punctuationValid, 0, sizeof( punctuationValid ) );
233         for( ptr = punctuation; *ptr != NULL; ptr++ ) {
234                 id = parserPtr->GetPunctuationId( *ptr );
235                 if ( ( id >= 0 ) && ( id < 256 ) ) {
236                         punctuationValid[ id ] = true;
237                 }
238         }
239 }
240
241 /*
242 ============
243 idCompiler::Error
244
245 Aborts the current file load
246 ============
247 */
248 void idCompiler::Error( const char *message, ... ) const {
249         va_list argptr;
250         char    string[ 1024 ];
251
252         va_start( argptr, message );
253         vsprintf( string, message, argptr );
254         va_end( argptr );
255
256         throw idCompileError( string );
257 }
258
259 /*
260 ============
261 idCompiler::Warning
262
263 Prints a warning about the current line
264 ============
265 */
266 void idCompiler::Warning( const char *message, ... ) const {
267         va_list argptr;
268         char    string[ 1024 ];
269
270         va_start( argptr, message );
271         vsprintf( string, message, argptr );
272         va_end( argptr );
273
274         parserPtr->Warning( "%s", string );
275 }
276
277 /*
278 ============
279 idCompiler::VirtualFunctionConstant
280
281 Creates a def for an index into a virtual function table
282 ============
283 */
284 ID_INLINE idVarDef *idCompiler::VirtualFunctionConstant( idVarDef *func ) {
285         eval_t eval;
286
287         memset( &eval, 0, sizeof( eval ) );
288         eval._int = func->scope->TypeDef()->GetFunctionNumber( func->value.functionPtr );
289         if ( eval._int < 0 ) {
290                 Error( "Function '%s' not found in scope '%s'", func->Name(), func->scope->Name() );
291         }
292     
293         return GetImmediate( &type_virtualfunction, &eval, "" );
294 }
295
296 /*
297 ============
298 idCompiler::SizeConstant
299
300 Creates a def for a size constant
301 ============
302 */
303 ID_INLINE idVarDef *idCompiler::SizeConstant( int size ) {
304         eval_t eval;
305
306         memset( &eval, 0, sizeof( eval ) );
307         eval._int = size;
308         return GetImmediate( &type_argsize, &eval, "" );
309 }
310
311 /*
312 ============
313 idCompiler::JumpConstant
314
315 Creates a def for a jump constant
316 ============
317 */
318 ID_INLINE idVarDef *idCompiler::JumpConstant( int value ) {
319         eval_t eval;
320
321         memset( &eval, 0, sizeof( eval ) );
322         eval._int = value;
323         return GetImmediate( &type_jumpoffset, &eval, "" );
324 }
325
326 /*
327 ============
328 idCompiler::JumpDef
329
330 Creates a def for a relative jump from one code location to another
331 ============
332 */
333 ID_INLINE idVarDef *idCompiler::JumpDef( int jumpfrom, int jumpto ) {
334         return JumpConstant( jumpto - jumpfrom );
335 }
336
337 /*
338 ============
339 idCompiler::JumpTo
340
341 Creates a def for a relative jump from current code location
342 ============
343 */
344 ID_INLINE idVarDef *idCompiler::JumpTo( int jumpto ) {
345         return JumpDef( gameLocal.program.NumStatements(), jumpto );
346 }
347
348 /*
349 ============
350 idCompiler::JumpFrom
351
352 Creates a def for a relative jump from code location to current code location
353 ============
354 */
355 ID_INLINE idVarDef *idCompiler::JumpFrom( int jumpfrom ) {
356         return JumpDef( jumpfrom, gameLocal.program.NumStatements() );
357 }
358
359 /*
360 ============
361 idCompiler::Divide
362 ============
363 */
364 ID_INLINE float idCompiler::Divide( float numerator, float denominator ) {
365         if ( denominator == 0 ) {
366                 Error( "Divide by zero" );
367                 return 0;
368         }
369
370         return numerator / denominator;
371 }
372
373 /*
374 ============
375 idCompiler::FindImmediate
376
377 tries to find an existing immediate with the same value
378 ============
379 */
380 idVarDef *idCompiler::FindImmediate( const idTypeDef *type, const eval_t *eval, const char *string ) const {
381         idVarDef        *def;
382         etype_t         etype;
383
384         etype = type->Type();
385
386         // check for a constant with the same value
387         for( def = gameLocal.program.GetDefList( "<IMMEDIATE>" ); def != NULL; def = def->Next() ) {
388                 if ( def->TypeDef() != type ) {
389                         continue;
390                 }
391
392                 switch( etype ) {
393                 case ev_field :
394                         if ( *def->value.intPtr == eval->_int ) {
395                                 return def;
396                         }
397                         break;
398
399                 case ev_argsize :
400                         if ( def->value.argSize == eval->_int ) {
401                                 return def;
402                         }
403                         break;
404
405                 case ev_jumpoffset :
406                         if ( def->value.jumpOffset == eval->_int ) {
407                                 return def;
408                         }
409                         break;
410
411                 case ev_entity :
412                         if ( *def->value.intPtr == eval->entity ) {
413                                 return def;
414                         }
415                         break;
416
417                 case ev_string :
418                         if ( idStr::Cmp( def->value.stringPtr, string ) == 0 ) {
419                                 return def;
420                         }
421                         break;
422
423                 case ev_float :
424                         if ( *def->value.floatPtr == eval->_float ) {
425                                 return def;
426                         }
427                         break;
428
429                 case ev_virtualfunction :
430                         if ( def->value.virtualFunction == eval->_int ) {
431                                 return def;
432                         }
433                         break;
434
435
436                 case ev_vector :
437                         if ( ( def->value.vectorPtr->x == eval->vector[ 0 ] ) && 
438                                 ( def->value.vectorPtr->y == eval->vector[ 1 ] ) && 
439                                 ( def->value.vectorPtr->z == eval->vector[ 2 ] ) ) {
440                                 return def;
441                         }
442                         break;
443
444                 default :
445                         Error( "weird immediate type" );
446                         break;
447                 }
448         }
449
450         return NULL;
451 }
452
453 /*
454 ============
455 idCompiler::GetImmediate
456
457 returns an existing immediate with the same value, or allocates a new one
458 ============
459 */
460 idVarDef *idCompiler::GetImmediate( idTypeDef *type, const eval_t *eval, const char *string ) {
461         idVarDef *def;
462
463         def = FindImmediate( type, eval, string );
464         if ( def ) {
465                 def->numUsers++;
466         } else {
467                 // allocate a new def
468                 def = gameLocal.program.AllocDef( type, "<IMMEDIATE>", &def_namespace, true );
469                 if ( type->Type() == ev_string ) {
470                         def->SetString( string, true );
471                 } else {
472                         def->SetValue( *eval, true );
473                 }
474         }
475
476         return def;
477 }
478
479 /*
480 ============
481 idCompiler::OptimizeOpcode
482
483 try to optimize when the operator works on constants only
484 ============
485 */
486 idVarDef *idCompiler::OptimizeOpcode( const opcode_t *op, idVarDef *var_a, idVarDef *var_b ) {
487         eval_t          c;
488         idTypeDef       *type;
489
490         if ( var_a && var_a->initialized != idVarDef::initializedConstant ) {
491                 return NULL;
492         }
493         if ( var_b && var_b->initialized != idVarDef::initializedConstant ) {
494                 return NULL;
495         }
496
497         idVec3 &vec_c = *reinterpret_cast<idVec3 *>( &c.vector[ 0 ] );
498
499         memset( &c, 0, sizeof( c ) );
500         switch( op - opcodes ) {
501                 case OP_ADD_F:          c._float = *var_a->value.floatPtr + *var_b->value.floatPtr; type = &type_float; break;
502                 case OP_ADD_V:          vec_c = *var_a->value.vectorPtr + *var_b->value.vectorPtr; type = &type_vector; break;
503                 case OP_SUB_F:          c._float = *var_a->value.floatPtr - *var_b->value.floatPtr; type = &type_float; break;
504                 case OP_SUB_V:          vec_c = *var_a->value.vectorPtr - *var_b->value.vectorPtr; type = &type_vector; break;
505                 case OP_MUL_F:          c._float = *var_a->value.floatPtr * *var_b->value.floatPtr; type = &type_float; break;
506                 case OP_MUL_V:          c._float = *var_a->value.vectorPtr * *var_b->value.vectorPtr; type = &type_float; break;
507                 case OP_MUL_FV:         vec_c = *var_b->value.vectorPtr * *var_a->value.floatPtr; type = &type_vector; break;
508                 case OP_MUL_VF:         vec_c = *var_a->value.vectorPtr * *var_b->value.floatPtr; type = &type_vector; break;
509                 case OP_DIV_F:          c._float = Divide( *var_a->value.floatPtr, *var_b->value.floatPtr ); type = &type_float; break;
510                 case OP_MOD_F:          c._float = (int)*var_a->value.floatPtr % (int)*var_b->value.floatPtr; type = &type_float; break;
511                 case OP_BITAND:         c._float = ( int )*var_a->value.floatPtr & ( int )*var_b->value.floatPtr; type = &type_float; break;
512                 case OP_BITOR:          c._float = ( int )*var_a->value.floatPtr | ( int )*var_b->value.floatPtr; type = &type_float; break;
513                 case OP_GE:                     c._float = *var_a->value.floatPtr >= *var_b->value.floatPtr; type = &type_float; break;
514                 case OP_LE:                     c._float = *var_a->value.floatPtr <= *var_b->value.floatPtr; type = &type_float; break;
515                 case OP_GT:                     c._float = *var_a->value.floatPtr > *var_b->value.floatPtr; type = &type_float; break;
516                 case OP_LT:                     c._float = *var_a->value.floatPtr < *var_b->value.floatPtr; type = &type_float; break;
517                 case OP_AND:            c._float = *var_a->value.floatPtr && *var_b->value.floatPtr; type = &type_float; break;
518                 case OP_OR:                     c._float = *var_a->value.floatPtr || *var_b->value.floatPtr; type = &type_float; break;
519                 case OP_NOT_BOOL:       c._int = !*var_a->value.intPtr; type = &type_boolean; break;
520                 case OP_NOT_F:          c._float = !*var_a->value.floatPtr; type = &type_float; break;
521                 case OP_NOT_V:          c._float = !var_a->value.vectorPtr->x && !var_a->value.vectorPtr->y && !var_a->value.vectorPtr->z; type = &type_float; break;
522                 case OP_NEG_F:          c._float = -*var_a->value.floatPtr; type = &type_float; break;
523                 case OP_NEG_V:          vec_c = -*var_a->value.vectorPtr; type = &type_vector; break;
524                 case OP_INT_F:          c._float = ( int )*var_a->value.floatPtr; type = &type_float; break;
525                 case OP_EQ_F:           c._float = ( *var_a->value.floatPtr == *var_b->value.floatPtr ); type = &type_float; break;
526                 case OP_EQ_V:           c._float = var_a->value.vectorPtr->Compare( *var_b->value.vectorPtr ); type = &type_float; break;
527                 case OP_EQ_E:           c._float = ( *var_a->value.intPtr == *var_b->value.intPtr ); type = &type_float; break;
528                 case OP_NE_F:           c._float = ( *var_a->value.floatPtr != *var_b->value.floatPtr ); type = &type_float; break;
529                 case OP_NE_V:           c._float = !var_a->value.vectorPtr->Compare( *var_b->value.vectorPtr ); type = &type_float; break;
530                 case OP_NE_E:           c._float = ( *var_a->value.intPtr != *var_b->value.intPtr ); type = &type_float; break;
531                 case OP_UADD_F:         c._float = *var_b->value.floatPtr + *var_a->value.floatPtr; type = &type_float; break;
532                 case OP_USUB_F:         c._float = *var_b->value.floatPtr - *var_a->value.floatPtr; type = &type_float; break;
533                 case OP_UMUL_F:         c._float = *var_b->value.floatPtr * *var_a->value.floatPtr; type = &type_float; break;
534                 case OP_UDIV_F:         c._float = Divide( *var_b->value.floatPtr, *var_a->value.floatPtr ); type = &type_float; break;
535                 case OP_UMOD_F:         c._float = ( int ) *var_b->value.floatPtr % ( int )*var_a->value.floatPtr; type = &type_float; break;
536                 case OP_UOR_F:          c._float = ( int )*var_b->value.floatPtr | ( int )*var_a->value.floatPtr; type = &type_float; break;
537                 case OP_UAND_F:         c._float = ( int )*var_b->value.floatPtr & ( int )*var_a->value.floatPtr; type = &type_float; break;
538                 case OP_UINC_F:         c._float = *var_a->value.floatPtr + 1; type = &type_float; break;
539                 case OP_UDEC_F:         c._float = *var_a->value.floatPtr - 1; type = &type_float; break;
540                 case OP_COMP_F:         c._float = ( float )~( int )*var_a->value.floatPtr; type = &type_float; break;
541                 default:                        type = NULL; break;
542         }
543
544         if ( !type ) {
545                 return NULL;
546         }
547
548         if ( var_a ) {
549                 var_a->numUsers--;
550                 if ( var_a->numUsers <= 0 ) {
551                         gameLocal.program.FreeDef( var_a, NULL );
552                 }
553         }
554         if ( var_b ) {
555                 var_b->numUsers--;
556                 if ( var_b->numUsers <= 0 ) {
557                         gameLocal.program.FreeDef( var_b, NULL );
558                 }
559         }
560
561         return GetImmediate( type, &c, "" );
562 }
563
564 /*
565 ============
566 idCompiler::EmitOpcode
567
568 Emits a primitive statement, returning the var it places it's value in
569 ============
570 */
571 idVarDef *idCompiler::EmitOpcode( const opcode_t *op, idVarDef *var_a, idVarDef *var_b ) {
572         statement_t     *statement;
573         idVarDef        *var_c;
574
575         var_c = OptimizeOpcode( op, var_a, var_b );
576         if ( var_c ) {
577                 return var_c;
578         }
579
580         if ( var_a && !strcmp( var_a->Name(), RESULT_STRING ) ) {
581                 var_a->numUsers++;
582         }
583         if ( var_b && !strcmp( var_b->Name(), RESULT_STRING ) ) {
584                 var_b->numUsers++;
585         }
586         
587         statement = gameLocal.program.AllocStatement();
588         statement->linenumber   = currentLineNumber;
589         statement->file                 = currentFileNumber;
590         
591         if ( ( op->type_c == &def_void ) || op->rightAssociative ) {
592                 // ifs, gotos, and assignments don't need vars allocated
593                 var_c = NULL;
594         } else {
595                 // allocate result space
596                 // try to reuse result defs as much as possible
597                 var_c = gameLocal.program.FindFreeResultDef( op->type_c->TypeDef(), RESULT_STRING, scope, var_a, var_b );
598                 // set user count back to 1, a result def needs to be used twice before it can be reused
599                 var_c->numUsers = 1;
600         }
601
602         statement->op   = op - opcodes;
603         statement->a    = var_a;
604         statement->b    = var_b;
605         statement->c    = var_c;
606
607         if ( op->rightAssociative ) {
608                 return var_a;
609         }
610
611         return var_c;
612 }
613
614 /*
615 ============
616 idCompiler::EmitOpcode
617
618 Emits a primitive statement, returning the var it places it's value in
619 ============
620 */
621 ID_INLINE idVarDef *idCompiler::EmitOpcode( int op, idVarDef *var_a, idVarDef *var_b ) {
622         return EmitOpcode( &opcodes[ op ], var_a, var_b );
623 }
624
625 /*
626 ============
627 idCompiler::EmitPush
628
629 Emits an opcode to push the variable onto the stack.
630 ============
631 */
632 bool idCompiler::EmitPush( idVarDef *expression, const idTypeDef *funcArg ) {
633         opcode_t *op;
634         opcode_t *out;
635
636         out = NULL;
637         for( op = &opcodes[ OP_PUSH_F ]; op->name && !strcmp( op->name, "<PUSH>" ); op++ ) {
638                 if ( ( funcArg->Type() == op->type_a->Type() ) && ( expression->Type() == op->type_b->Type() ) ) {
639                         out = op;
640                         break;
641                 }
642         }
643
644         if ( !out ) {
645                 if ( ( expression->TypeDef() != funcArg ) && !expression->TypeDef()->Inherits( funcArg ) ) {
646                         return false;
647                 }
648
649                 out = &opcodes[ OP_PUSH_ENT ];
650         }
651
652         EmitOpcode( out, expression, 0 );
653
654         return true;
655 }
656
657 /*
658 ==============
659 idCompiler::NextToken
660
661 Sets token, immediateType, and possibly immediate
662 ==============
663 */
664 void idCompiler::NextToken( void ) {
665         int i;
666
667         // reset our type
668         immediateType = NULL;
669         memset( &immediate, 0, sizeof( immediate ) );
670
671         // Save the token's line number and filename since when we emit opcodes the current 
672         // token is always the next one to be read 
673         currentLineNumber = token.line;
674         currentFileNumber = gameLocal.program.GetFilenum( parserPtr->GetFileName() );
675
676         if ( !parserPtr->ReadToken( &token ) ) {
677                 eof = true;
678                 return;
679         }
680
681         if ( currentFileNumber != gameLocal.program.GetFilenum( parserPtr->GetFileName() ) ) {
682                 if ( ( braceDepth > 0 ) && ( token != "}" ) ) {
683                         // missing a closing brace.  try to give as much info as possible.
684                         if ( scope->Type() == ev_function ) {
685                                 Error( "Unexpected end of file inside function '%s'.  Missing closing braces.", scope->Name() );
686                         } else if ( scope->Type() == ev_object ) {
687                                 Error( "Unexpected end of file inside object '%s'.  Missing closing braces.", scope->Name() );
688                         } else if ( scope->Type() == ev_namespace ) {
689                                 Error( "Unexpected end of file inside namespace '%s'.  Missing closing braces.", scope->Name() );
690                         } else {
691                                 Error( "Unexpected end of file inside braced section" );
692                         }
693                 }
694         }
695
696         switch( token.type ) {
697         case TT_STRING:
698                 // handle quoted strings as a unit
699                 immediateType = &type_string;
700                 return;
701
702         case TT_LITERAL: {
703                 // handle quoted vectors as a unit
704                 immediateType = &type_vector;
705                 idLexer lex( token, token.Length(), parserPtr->GetFileName(), LEXFL_NOERRORS );
706                 idToken token2;
707                 for( i = 0; i < 3; i++ ) {
708                         if ( !lex.ReadToken( &token2 ) ) {
709                                 Error( "Couldn't read vector. '%s' is not in the form of 'x y z'", token.c_str() );
710                         }
711                         if ( token2.type == TT_PUNCTUATION && token2 == "-" ) {
712                                 if ( !lex.CheckTokenType( TT_NUMBER, 0, &token2 ) ) {
713                                         Error( "expected a number following '-' but found '%s' in vector '%s'", token2.c_str(), token.c_str() );
714                                 }
715                                 immediate.vector[ i ] = -token2.GetFloatValue();
716                         } else if ( token2.type == TT_NUMBER ) {
717                                 immediate.vector[ i ] = token2.GetFloatValue();
718                         } else {
719                                 Error( "vector '%s' is not in the form of 'x y z'.  expected float value, found '%s'", token.c_str(), token2.c_str() );
720                         }
721                 }
722                 return;
723         }
724
725         case TT_NUMBER:
726                 immediateType = &type_float;
727                 immediate._float = token.GetFloatValue();
728                 return;
729
730         case TT_PUNCTUATION:
731                 // entity names
732                 if ( token == "$" ) {
733                         immediateType = &type_entity;
734                         parserPtr->ReadToken( &token );
735                         return;
736                 }
737
738                 if ( token == "{" ) {
739                         braceDepth++;
740                         return;
741                 }
742
743                 if ( token == "}" ) {
744                         braceDepth--;
745                         return;
746                 }
747
748                 if ( punctuationValid[ token.subtype ] ) {
749                         return;
750                 }
751
752                 Error( "Unknown punctuation '%s'", token.c_str() );
753                 break;
754
755         case TT_NAME:
756                 return;
757
758         default:
759                 Error( "Unknown token '%s'", token.c_str() );
760         }
761 }
762
763 /*
764 =============
765 idCompiler::ExpectToken
766
767 Issues an Error if the current token isn't equal to string
768 Gets the next token
769 =============
770 */
771 void idCompiler::ExpectToken( const char *string ) {
772         if ( token != string ) {
773                 Error( "expected '%s', found '%s'", string, token.c_str() );
774         }
775
776         NextToken();
777 }
778
779 /*
780 =============
781 idCompiler::CheckToken
782
783 Returns true and gets the next token if the current token equals string
784 Returns false and does nothing otherwise
785 =============
786 */
787 bool idCompiler::CheckToken( const char *string ) {
788         if ( token != string ) {
789                 return false;
790         }
791                 
792         NextToken();
793         
794         return true;
795 }
796
797 /*
798 ============
799 idCompiler::ParseName
800
801 Checks to see if the current token is a valid name
802 ============
803 */
804 void idCompiler::ParseName( idStr &name ) {
805         if ( token.type != TT_NAME ) {
806                 Error( "'%s' is not a name", token.c_str() );
807         }
808
809         name = token;
810         NextToken();
811 }
812
813 /*
814 ============
815 idCompiler::SkipOutOfFunction
816
817 For error recovery, pops out of nested braces
818 ============
819 */
820 void idCompiler::SkipOutOfFunction( void ) {
821         while( braceDepth ) {
822                 parserPtr->SkipBracedSection( false );
823                 braceDepth--;
824         }
825         NextToken();
826 }
827
828 /*
829 ============
830 idCompiler::SkipToSemicolon
831
832 For error recovery
833 ============
834 */
835 void idCompiler::SkipToSemicolon( void ) {
836         do {
837                 if ( CheckToken( ";" ) ) {
838                         return;
839                 }
840
841                 NextToken();
842         } while( !eof );
843 }
844
845 /*
846 ============
847 idCompiler::CheckType
848
849 Parses a variable type, including functions types
850 ============
851 */
852 idTypeDef *idCompiler::CheckType( void ) {
853         idTypeDef *type;
854         
855         if ( token == "float" ) {
856                 type = &type_float;
857         } else if ( token == "vector" ) {
858                 type = &type_vector;
859         } else if ( token == "entity" ) {
860                 type = &type_entity;
861         } else if ( token == "string" ) {
862                 type = &type_string;
863         } else if ( token == "void" ) {
864                 type = &type_void;
865         } else if ( token == "object" ) {
866                 type = &type_object;
867         } else if ( token == "boolean" ) {
868                 type = &type_boolean;
869         } else if ( token == "namespace" ) {
870                 type = &type_namespace;
871         } else if ( token == "scriptEvent" ) {
872                 type = &type_scriptevent;
873         } else {
874                 type = gameLocal.program.FindType( token.c_str() );
875                 if ( type && !type->Inherits( &type_object ) ) {
876                         type = NULL;
877                 }
878         }
879         
880         return type;
881 }
882
883 /*
884 ============
885 idCompiler::ParseType
886
887 Parses a variable type, including functions types
888 ============
889 */
890 idTypeDef *idCompiler::ParseType( void ) {
891         idTypeDef *type;
892         
893         type = CheckType();
894         if ( !type ) {
895                 Error( "\"%s\" is not a type", token.c_str() );
896         }
897
898         if ( ( type == &type_scriptevent ) && ( scope != &def_namespace ) ) {
899                 Error( "scriptEvents can only defined in the global namespace" );
900         }
901
902         if ( ( type == &type_namespace ) && ( scope->Type() != ev_namespace ) ) {
903                 Error( "A namespace may only be defined globally, or within another namespace" );
904         }
905
906         NextToken();
907         
908         return type;
909 }
910
911 /*
912 ============
913 idCompiler::ParseImmediate
914
915 Looks for a preexisting constant
916 ============
917 */
918 idVarDef *idCompiler::ParseImmediate( void ) {
919         idVarDef *def;
920
921         def = GetImmediate( immediateType, &immediate, token.c_str() );
922         NextToken();
923
924         return def;
925 }
926
927 /*
928 ============
929 idCompiler::EmitFunctionParms
930 ============
931 */
932 idVarDef *idCompiler::EmitFunctionParms( int op, idVarDef *func, int startarg, int startsize, idVarDef *object ) {
933         idVarDef                *e;
934         const idTypeDef *type;
935         const idTypeDef *funcArg;
936         idVarDef                *returnDef;
937         idTypeDef               *returnType;
938         int                     arg;
939         int                     size;
940         int                             resultOp;
941
942         type = func->TypeDef();
943         if ( func->Type() != ev_function ) {
944                 Error( "'%s' is not a function", func->Name() );
945         }
946
947         // copy the parameters to the global parameter variables
948         arg = startarg;
949         size = startsize;
950         if ( !CheckToken( ")" ) ) {
951                 do {
952                         if ( arg >= type->NumParameters() ) {
953                                 Error( "too many parameters" );
954                         }
955
956                         e = GetExpression( TOP_PRIORITY );
957
958                         funcArg = type->GetParmType( arg );
959                         if ( !EmitPush( e, funcArg ) ) {
960                                 Error( "type mismatch on parm %i of call to '%s'", arg + 1, func->Name() );
961                         }
962
963                         if ( funcArg->Type() == ev_object ) {
964                                 size += type_object.Size();
965                         } else {
966                                 size += funcArg->Size();
967                         }
968
969                         arg++;
970                 } while( CheckToken( "," ) );
971         
972                 ExpectToken( ")" );
973         }
974
975         if ( arg < type->NumParameters() ) {
976                 Error( "too few parameters for function '%s'", func->Name() );
977         }
978
979         if ( op == OP_CALL ) {
980                 EmitOpcode( op, func, 0 );
981         } else if ( ( op == OP_OBJECTCALL ) || ( op == OP_OBJTHREAD ) ) {
982                 EmitOpcode( op, object, VirtualFunctionConstant( func ) );
983
984                 // need arg size seperate since script object may be NULL
985                 statement_t &statement = gameLocal.program.GetStatement( gameLocal.program.NumStatements() - 1 );
986                 statement.c = SizeConstant( func->value.functionPtr->parmTotal );
987         } else {
988                 EmitOpcode( op, func, SizeConstant( size ) );
989         }
990
991         // we need to copy off the result into a temporary result location, so figure out the opcode
992         returnType = type->ReturnType();
993         if ( returnType->Type() == ev_string ) {
994                 resultOp = OP_STORE_S;
995                 returnDef = gameLocal.program.returnStringDef;
996         } else {
997                 gameLocal.program.returnDef->SetTypeDef( returnType );
998                 returnDef = gameLocal.program.returnDef;
999
1000                 switch( returnType->Type() ) {
1001                 case ev_void :
1002                         resultOp = OP_STORE_F;
1003                         break;
1004
1005                 case ev_boolean :
1006                         resultOp = OP_STORE_BOOL;
1007                         break;
1008
1009                 case ev_float :
1010                         resultOp = OP_STORE_F;
1011                         break;
1012
1013                 case ev_vector :
1014                         resultOp = OP_STORE_V;
1015                         break;
1016
1017                 case ev_entity :
1018                         resultOp = OP_STORE_ENT;
1019                         break;
1020
1021                 case ev_object :
1022                         resultOp = OP_STORE_OBJ;
1023                         break;
1024
1025                 default :
1026                         Error( "Invalid return type for function '%s'", func->Name() );
1027                         // shut up compiler
1028                         resultOp = OP_STORE_OBJ;
1029                         break;
1030                 }
1031         }
1032
1033         if ( returnType->Type() == ev_void ) {
1034                 // don't need result space since there's no result, so just return the normal result def.
1035                 return returnDef;
1036         }
1037
1038         // allocate result space
1039         // try to reuse result defs as much as possible
1040         statement_t &statement = gameLocal.program.GetStatement( gameLocal.program.NumStatements() - 1 );
1041         idVarDef *resultDef = gameLocal.program.FindFreeResultDef( returnType, RESULT_STRING, scope, statement.a, statement.b );
1042         // set user count back to 0, a result def needs to be used twice before it can be reused
1043         resultDef->numUsers = 0;
1044
1045         EmitOpcode( resultOp, returnDef, resultDef );
1046
1047         return resultDef;
1048 }
1049
1050 /*
1051 ============
1052 idCompiler::ParseFunctionCall
1053 ============
1054 */
1055 idVarDef *idCompiler::ParseFunctionCall( idVarDef *funcDef ) {
1056         assert( funcDef );
1057
1058         if ( funcDef->Type() != ev_function ) {
1059                 Error( "'%s' is not a function", funcDef->Name() );
1060         }
1061
1062         if ( funcDef->initialized == idVarDef::uninitialized ) {
1063                 Error( "Function '%s' has not been defined yet", funcDef->GlobalName() );
1064         }
1065
1066         assert( funcDef->value.functionPtr );
1067         if ( callthread ) {
1068                 if ( ( funcDef->initialized != idVarDef::uninitialized ) && funcDef->value.functionPtr->eventdef ) {
1069                         Error( "Built-in functions cannot be called as threads" );
1070                 }
1071                 callthread = false;
1072                 return EmitFunctionParms( OP_THREAD, funcDef, 0, 0, NULL );
1073         } else {
1074                 if ( ( funcDef->initialized != idVarDef::uninitialized ) && funcDef->value.functionPtr->eventdef ) {
1075                         if ( ( scope->Type() != ev_namespace ) && ( scope->scope->Type() == ev_object ) ) {
1076                                 // get the local object pointer
1077                                 idVarDef *thisdef = gameLocal.program.GetDef( scope->scope->TypeDef(), "self", scope );
1078                                 if ( !thisdef ) {
1079                                         Error( "No 'self' within scope" );
1080                                 }
1081
1082                                 return ParseEventCall( thisdef, funcDef );
1083                         } else {
1084                                 Error( "Built-in functions cannot be called without an object" );
1085                         }
1086                 }
1087
1088                 return EmitFunctionParms( OP_CALL, funcDef, 0, 0, NULL );
1089         }
1090 }
1091
1092 /*
1093 ============
1094 idCompiler::ParseObjectCall
1095 ============
1096 */
1097 idVarDef *idCompiler::ParseObjectCall( idVarDef *object, idVarDef *func ) {
1098         EmitPush( object, object->TypeDef() );
1099         if ( callthread ) {
1100                 callthread = false;
1101                 return EmitFunctionParms( OP_OBJTHREAD, func, 1, type_object.Size(), object );
1102         } else {
1103                 return EmitFunctionParms( OP_OBJECTCALL, func, 1, 0, object );
1104         }
1105 }
1106
1107 /*
1108 ============
1109 idCompiler::ParseEventCall
1110 ============
1111 */
1112 idVarDef *idCompiler::ParseEventCall( idVarDef *object, idVarDef *funcDef ) {
1113         if ( callthread ) {
1114                 Error( "Cannot call built-in functions as a thread" );
1115         }
1116
1117         if ( funcDef->Type() != ev_function ) {
1118                 Error( "'%s' is not a function", funcDef->Name() );
1119         }
1120
1121         if ( !funcDef->value.functionPtr->eventdef ) {
1122                 Error( "\"%s\" cannot be called with object notation", funcDef->Name() );
1123         }
1124
1125         if ( object->Type() == ev_object ) {
1126                 EmitPush( object, &type_entity );
1127         } else {
1128                 EmitPush( object, object->TypeDef() );
1129         }
1130
1131         return EmitFunctionParms( OP_EVENTCALL, funcDef, 0, type_object.Size(), NULL );
1132 }
1133
1134 /*
1135 ============
1136 idCompiler::ParseSysObjectCall
1137 ============
1138 */
1139 idVarDef *idCompiler::ParseSysObjectCall( idVarDef *funcDef ) {
1140         if ( callthread ) {
1141                 Error( "Cannot call built-in functions as a thread" );
1142         }
1143
1144         if ( funcDef->Type() != ev_function ) {
1145                 Error( "'%s' is not a function", funcDef->Name() );
1146         }
1147
1148         if ( !funcDef->value.functionPtr->eventdef ) {
1149                 Error( "\"%s\" cannot be called with object notation", funcDef->Name() );
1150         }
1151
1152         if ( !idThread::Type.RespondsTo( *funcDef->value.functionPtr->eventdef ) ) {
1153                 Error( "\"%s\" is not callable as a 'sys' function", funcDef->Name() );
1154         }
1155
1156         return EmitFunctionParms( OP_SYSCALL, funcDef, 0, 0, NULL );
1157 }
1158
1159 /*
1160 ============
1161 idCompiler::LookupDef
1162 ============
1163 */
1164 idVarDef *idCompiler::LookupDef( const char *name, const idVarDef *baseobj ) {
1165         idVarDef        *def;
1166         idVarDef        *field;
1167         etype_t         type_b;
1168         etype_t         type_c;
1169         opcode_t        *op;
1170
1171         // check if we're accessing a field
1172         if ( baseobj && ( baseobj->Type() == ev_object ) ) {
1173                 const idVarDef *tdef;
1174
1175                 def = NULL;
1176                 for( tdef = baseobj; tdef != &def_object; tdef = tdef->TypeDef()->SuperClass()->def ) {
1177                         def = gameLocal.program.GetDef( NULL, name, tdef );
1178                         if ( def ) {
1179                                 break;
1180                         }
1181                 }
1182         } else {
1183                 // first look through the defs in our scope
1184                 def = gameLocal.program.GetDef( NULL, name, scope );
1185                 if ( !def ) {
1186                         // if we're in a member function, check types local to the object
1187                         if ( ( scope->Type() != ev_namespace ) && ( scope->scope->Type() == ev_object ) ) {
1188                                 // get the local object pointer
1189                                 idVarDef *thisdef = gameLocal.program.GetDef( scope->scope->TypeDef(), "self", scope );
1190
1191                                 field = LookupDef( name, scope->scope->TypeDef()->def );
1192                                 if ( !field ) {
1193                                         Error( "Unknown value \"%s\"", name );
1194                                 }
1195
1196                                 // type check
1197                                 type_b = field->Type();
1198                                 if ( field->Type() == ev_function ) {
1199                                         type_c = field->TypeDef()->ReturnType()->Type();
1200                                 } else {
1201                                         type_c = field->TypeDef()->FieldType()->Type(); // field access gets type from field
1202                         if ( CheckToken( "++" ) ) {
1203                                                 if ( type_c != ev_float ) {
1204                                                         Error( "Invalid type for ++" );
1205                                                 }
1206                                                 def = EmitOpcode( OP_UINCP_F, thisdef, field );
1207                                                 return def;
1208                                         } else if ( CheckToken( "--" ) ) {
1209                                                 if ( type_c != ev_float ) {
1210                                                         Error( "Invalid type for --" );
1211                                                 }
1212                                                 def = EmitOpcode( OP_UDECP_F, thisdef, field );
1213                                                 return def;
1214                                         }
1215                                 }
1216
1217                                 op = &opcodes[ OP_INDIRECT_F ];
1218                                 while( ( op->type_a->Type() != ev_object ) 
1219                                         || ( type_b != op->type_b->Type() ) || ( type_c != op->type_c->Type() ) ) {
1220                                         if ( ( op->priority == FUNCTION_PRIORITY ) && ( op->type_a->Type() == ev_object ) && ( op->type_c->Type() == ev_void ) && 
1221                                                 ( type_c != op->type_c->Type() ) ) {
1222                                                 // catches object calls that return a value
1223                                                 break;
1224                                         }
1225                                         op++;
1226                                         if ( !op->name || strcmp( op->name, "." ) ) {
1227                                                 Error( "no valid opcode to access type '%s'", field->TypeDef()->SuperClass()->Name() );
1228                                         }
1229                                 }
1230
1231                                 if ( ( op - opcodes ) == OP_OBJECTCALL ) {
1232                                         ExpectToken( "(" );
1233                                         def = ParseObjectCall( thisdef, field );
1234                                 } else {
1235                                         // emit the conversion opcode
1236                                         def = EmitOpcode( op, thisdef, field );
1237
1238                                         // field access gets type from field
1239                                         def->SetTypeDef( field->TypeDef()->FieldType() );
1240                                 }
1241                         }
1242                 }
1243         }
1244
1245         return def;
1246 }
1247
1248 /*
1249 ============
1250 idCompiler::ParseValue
1251
1252 Returns the def for the current token
1253 ============
1254 */
1255 idVarDef *idCompiler::ParseValue( void ) {
1256         idVarDef        *def;
1257         idVarDef        *namespaceDef;
1258         idStr           name;
1259         
1260         if ( immediateType == &type_entity ) {
1261                 // if an immediate entity ($-prefaced name) then create or lookup a def for it.
1262                 // when entities are spawned, they'll lookup the def and point it to them.
1263                 def = gameLocal.program.GetDef( &type_entity, "$" + token, &def_namespace );
1264                 if ( !def ) {
1265                         def = gameLocal.program.AllocDef( &type_entity, "$" + token, &def_namespace, true );
1266                 }
1267                 NextToken();
1268                 return def;
1269         } else if ( immediateType ) {
1270                 // if the token is an immediate, allocate a constant for it
1271                 return ParseImmediate();
1272         }
1273
1274         ParseName( name );
1275         def = LookupDef( name, basetype );
1276         if ( !def ) {
1277                 if ( basetype ) {
1278                         Error( "%s is not a member of %s", name.c_str(), basetype->TypeDef()->Name() );
1279                 } else {
1280                         Error( "Unknown value \"%s\"", name.c_str() );
1281                 }
1282         // if namespace, then look up the variable in that namespace
1283         } else if ( def->Type() == ev_namespace ) {
1284                 while( def->Type() == ev_namespace ) {
1285                         ExpectToken( "::" );
1286                         ParseName( name );
1287                         namespaceDef = def;
1288                         def = gameLocal.program.GetDef( NULL, name, namespaceDef );
1289                         if ( !def ) {
1290                                 Error( "Unknown value \"%s::%s\"", namespaceDef->GlobalName(), name.c_str() );
1291                         }
1292                 }
1293                 //def = LookupDef( name, basetype );
1294         }
1295
1296         return def;
1297 }
1298
1299 /*
1300 ============
1301 idCompiler::GetTerm
1302 ============
1303 */
1304 idVarDef *idCompiler::GetTerm( void ) {
1305         idVarDef        *e;
1306         int             op;
1307         
1308         if ( !immediateType && CheckToken( "~" ) ) {
1309                 e = GetExpression( TILDE_PRIORITY );
1310                 switch( e->Type() ) {
1311                 case ev_float :
1312                         op = OP_COMP_F;
1313                         break;
1314
1315                 default :
1316                         Error( "type mismatch for ~" );
1317
1318                         // shut up compiler
1319                         op = OP_COMP_F;
1320                         break;
1321                 }
1322
1323                 return EmitOpcode( op, e, 0 );
1324         }
1325
1326         if ( !immediateType && CheckToken( "!" ) ) {
1327                 e = GetExpression( NOT_PRIORITY );
1328                 switch( e->Type() ) {
1329                 case ev_boolean :
1330                         op = OP_NOT_BOOL;
1331                         break;
1332
1333                 case ev_float :
1334                         op = OP_NOT_F;
1335                         break;
1336
1337                 case ev_string :
1338                         op = OP_NOT_S;
1339                         break;
1340
1341                 case ev_vector :
1342                         op = OP_NOT_V;
1343                         break;
1344
1345                 case ev_entity :
1346                         op = OP_NOT_ENT;
1347                         break;
1348
1349                 case ev_function :
1350                         Error( "Invalid type for !" );
1351
1352                         // shut up compiler
1353                         op = OP_NOT_F;
1354                         break;
1355
1356                 case ev_object :
1357                         op = OP_NOT_ENT;
1358                         break;
1359
1360                 default :
1361                         Error( "type mismatch for !" );
1362
1363                         // shut up compiler
1364                         op = OP_NOT_F;
1365                         break;
1366                 }
1367
1368                 return EmitOpcode( op, e, 0 );
1369         }
1370
1371         // check for negation operator
1372         if ( !immediateType && CheckToken( "-" ) ) {
1373                 // constants are directly negated without an instruction
1374                 if ( immediateType == &type_float ) {
1375                         immediate._float = -immediate._float;
1376                         return ParseImmediate();
1377                 } else if ( immediateType == &type_vector ) {
1378                         immediate.vector[0] = -immediate.vector[0];
1379                         immediate.vector[1] = -immediate.vector[1];
1380                         immediate.vector[2] = -immediate.vector[2];
1381                         return ParseImmediate();
1382                 } else {
1383                         e = GetExpression( NOT_PRIORITY );
1384                         switch( e->Type() ) {
1385                         case ev_float :
1386                                 op = OP_NEG_F;
1387                                 break;
1388
1389                         case ev_vector :
1390                                 op = OP_NEG_V;
1391                                 break;
1392                         default :
1393                                 Error( "type mismatch for -" );
1394
1395                                 // shut up compiler
1396                                 op = OP_NEG_F;
1397                                 break;
1398                         }
1399                         return EmitOpcode( &opcodes[ op ], e, 0 );
1400                 }
1401         }
1402         
1403         if ( CheckToken( "int" ) ) {
1404                 ExpectToken( "(" );
1405
1406                 e = GetExpression( INT_PRIORITY );
1407                 if ( e->Type() != ev_float ) {
1408                         Error( "type mismatch for int()" );
1409                 }
1410
1411                 ExpectToken( ")" );
1412
1413                 return EmitOpcode( OP_INT_F, e, 0 );
1414         }
1415         
1416         if ( CheckToken( "thread" ) ) {
1417                 callthread = true;
1418                 e = GetExpression( FUNCTION_PRIORITY );
1419
1420                 if ( callthread ) {
1421                         Error( "Invalid thread call" );
1422                 }
1423
1424                 // threads return the thread number
1425                 gameLocal.program.returnDef->SetTypeDef( &type_float );
1426                 return gameLocal.program.returnDef;
1427         }
1428         
1429         if ( !immediateType && CheckToken( "(" ) ) {
1430                 e = GetExpression( TOP_PRIORITY );
1431                 ExpectToken( ")" );
1432
1433                 return e;
1434         }
1435         
1436         return ParseValue();
1437 }
1438
1439 /*
1440 ==============
1441 idCompiler::TypeMatches
1442 ==============
1443 */
1444 bool idCompiler::TypeMatches( etype_t type1, etype_t type2 ) const {
1445         if ( type1 == type2 ) {
1446                 return true;
1447         }
1448
1449         //if ( ( type1 == ev_entity ) && ( type2 == ev_object ) ) {
1450         //      return true;
1451         //}
1452                 
1453         //if ( ( type2 == ev_entity ) && ( type1 == ev_object ) ) {
1454         //      return true;
1455         //}
1456
1457         return false;
1458 }
1459
1460 /*
1461 ==============
1462 idCompiler::GetExpression
1463 ==============
1464 */
1465 idVarDef *idCompiler::GetExpression( int priority ) {
1466         opcode_t                *op;
1467         opcode_t                *oldop;
1468         idVarDef                *e;
1469         idVarDef                *e2;
1470         const idVarDef  *oldtype;
1471         etype_t                 type_a;
1472         etype_t                 type_b;
1473         etype_t                 type_c;
1474         
1475         if ( priority == 0 ) {
1476                 return GetTerm();
1477         }
1478                 
1479         e = GetExpression( priority - 1 );
1480         if ( token == ";" ) {
1481                 // save us from searching through the opcodes unneccesarily
1482                 return e;
1483         }
1484
1485         while( 1 ) {
1486                 if ( ( priority == FUNCTION_PRIORITY ) && CheckToken( "(" ) ) {
1487                         return ParseFunctionCall( e );
1488                 }
1489
1490                 // has to be a punctuation
1491                 if ( immediateType ) {
1492                         break;
1493                 }
1494
1495                 for( op = opcodes; op->name; op++ ) {
1496                         if ( ( op->priority == priority ) && CheckToken( op->name ) ) {
1497                                 break;
1498                         }
1499                 }
1500
1501                 if ( !op->name ) {
1502                         // next token isn't at this priority level
1503                         break;
1504                 }
1505
1506                 // unary operators act only on the left operand
1507                 if ( op->type_b == &def_void ) {
1508                         e = EmitOpcode( op, e, 0 );
1509                         return e;
1510                 }
1511
1512                 // preserve our base type
1513                 oldtype = basetype;
1514
1515                 // field access needs scope from object
1516                 if ( ( op->name[ 0 ] == '.' ) && e->TypeDef()->Inherits( &type_object ) ) {
1517                         // save off what type this field is part of
1518                         basetype = e->TypeDef()->def;
1519                 }
1520
1521                 if ( op->rightAssociative ) {
1522                         // if last statement is an indirect, change it to an address of
1523                         if ( gameLocal.program.NumStatements() > 0 ) {
1524                                 statement_t &statement = gameLocal.program.GetStatement( gameLocal.program.NumStatements() - 1 );
1525                                 if ( ( statement.op >= OP_INDIRECT_F ) && ( statement.op < OP_ADDRESS ) ) {
1526                                         statement.op = OP_ADDRESS;
1527                                         type_pointer.SetPointerType( e->TypeDef() );
1528                                         e->SetTypeDef( &type_pointer );
1529                                 }
1530                         }
1531
1532                         e2 = GetExpression( priority );
1533                 } else {
1534                         e2 = GetExpression( priority - 1 );
1535                 }
1536
1537                 // restore type
1538                 basetype = oldtype;
1539                         
1540                 // type check
1541                 type_a = e->Type();
1542                 type_b = e2->Type();
1543
1544                 // field access gets type from field
1545                 if ( op->name[ 0 ] == '.' ) {
1546                         if ( ( e2->Type() == ev_function ) && e2->TypeDef()->ReturnType() ) {
1547                                 type_c = e2->TypeDef()->ReturnType()->Type();
1548                         } else if ( e2->TypeDef()->FieldType() ) {
1549                                 type_c = e2->TypeDef()->FieldType()->Type();
1550                         } else {
1551                                 // not a field
1552                                 type_c = ev_error;
1553                         }
1554                 } else {
1555                         type_c = ev_void;
1556                 }
1557
1558                 oldop = op;
1559                 while( !TypeMatches( type_a, op->type_a->Type() ) || !TypeMatches( type_b, op->type_b->Type() ) ||
1560                         ( ( type_c != ev_void ) && !TypeMatches( type_c, op->type_c->Type() ) ) ) {
1561                         if ( ( op->priority == FUNCTION_PRIORITY ) && TypeMatches( type_a, op->type_a->Type() ) && TypeMatches( type_b, op->type_b->Type() ) ) {
1562                                 break;
1563                         }
1564
1565                         op++;
1566                         if ( !op->name || strcmp( op->name, oldop->name ) ) {
1567                                 Error( "type mismatch for '%s'", oldop->name );
1568                         }
1569                 }
1570
1571                 switch( op - opcodes ) {
1572                 case OP_SYSCALL :
1573                         ExpectToken( "(" );
1574                         e = ParseSysObjectCall( e2 );
1575                         break;
1576
1577                 case OP_OBJECTCALL :
1578                         ExpectToken( "(" );
1579                         if ( ( e2->initialized != idVarDef::uninitialized ) && e2->value.functionPtr->eventdef ) {
1580                                 e = ParseEventCall( e, e2 );
1581                         } else {
1582                                 e = ParseObjectCall( e, e2 );
1583                         }
1584                         break;
1585                 
1586                 case OP_EVENTCALL :
1587                         ExpectToken( "(" );
1588                         if ( ( e2->initialized != idVarDef::uninitialized ) && e2->value.functionPtr->eventdef ) {
1589                                 e = ParseEventCall( e, e2 );
1590                         } else {
1591                                 e = ParseObjectCall( e, e2 );
1592                         }
1593                         break;
1594
1595                 default:
1596                         if ( callthread ) {
1597                                 Error( "Expecting function call after 'thread'" );
1598                         }
1599
1600                         if ( ( type_a == ev_pointer ) && ( type_b != e->TypeDef()->PointerType()->Type() ) ) {
1601                                 // FIXME: need to make a general case for this
1602                                 if ( ( op - opcodes == OP_STOREP_F ) && ( e->TypeDef()->PointerType()->Type() == ev_boolean ) ) {
1603                                         // copy from float to boolean pointer
1604                                         op = &opcodes[ OP_STOREP_FTOBOOL ];
1605                                 } else if ( ( op - opcodes == OP_STOREP_BOOL ) && ( e->TypeDef()->PointerType()->Type() == ev_float ) ) {
1606                                         // copy from boolean to float pointer
1607                                         op = &opcodes[ OP_STOREP_BOOLTOF ];
1608                                 } else if ( ( op - opcodes == OP_STOREP_F ) && ( e->TypeDef()->PointerType()->Type() == ev_string ) ) {
1609                                         // copy from float to string pointer
1610                                         op = &opcodes[ OP_STOREP_FTOS ];
1611                                 } else if ( ( op - opcodes == OP_STOREP_BOOL ) && ( e->TypeDef()->PointerType()->Type() == ev_string ) ) {
1612                                         // copy from boolean to string pointer
1613                                         op = &opcodes[ OP_STOREP_BTOS ];
1614                                 } else if ( ( op - opcodes == OP_STOREP_V ) && ( e->TypeDef()->PointerType()->Type() == ev_string ) ) {
1615                                         // copy from vector to string pointer
1616                                         op = &opcodes[ OP_STOREP_VTOS ];
1617                                 } else if ( ( op - opcodes == OP_STOREP_ENT ) && ( e->TypeDef()->PointerType()->Type() == ev_object ) ) {
1618                                         // store an entity into an object pointer
1619                                         op = &opcodes[ OP_STOREP_OBJENT ];
1620                                 } else {
1621                                         Error( "type mismatch for '%s'", op->name );
1622                                 }
1623                         }
1624                         
1625                         if ( op->rightAssociative ) {
1626                                 e = EmitOpcode( op, e2, e );
1627                         } else {
1628                                 e = EmitOpcode( op, e, e2 );
1629                         }
1630
1631                         if ( op - opcodes == OP_STOREP_OBJENT ) {
1632                                 // statement.b points to type_pointer, which is just a temporary that gets its type reassigned, so we store the real type in statement.c
1633                                 // so that we can do a type check during run time since we don't know what type the script object is at compile time because it
1634                                 // comes from an entity
1635                                 statement_t &statement = gameLocal.program.GetStatement( gameLocal.program.NumStatements() - 1 );
1636                                 statement.c = type_pointer.PointerType()->def;
1637                         }
1638
1639                         // field access gets type from field
1640                         if ( type_c != ev_void ) {
1641                                 e->SetTypeDef( e2->TypeDef()->FieldType() );
1642                         }
1643                         break;
1644                 }
1645         }
1646
1647         return e;
1648 }
1649
1650 /*
1651 ================
1652 idCompiler::PatchLoop
1653 ================
1654 */
1655 void idCompiler::PatchLoop( int start, int continuePos ) {
1656         int                     i;
1657         statement_t     *pos;
1658
1659         pos = &gameLocal.program.GetStatement( start );
1660         for( i = start; i < gameLocal.program.NumStatements(); i++, pos++ ) {
1661                 if ( pos->op == OP_BREAK ) {
1662                         pos->op = OP_GOTO;
1663                         pos->a = JumpFrom( i );
1664                 } else if ( pos->op == OP_CONTINUE ) {
1665                         pos->op = OP_GOTO;
1666                         pos->a = JumpDef( i, continuePos );
1667                 }
1668         }
1669 }
1670
1671 /*
1672 ================
1673 idCompiler::ParseReturnStatement
1674 ================
1675 */
1676 void idCompiler::ParseReturnStatement( void ) {
1677         idVarDef        *e;
1678         etype_t         type_a;
1679         etype_t         type_b;
1680         opcode_t        *op;
1681
1682         if ( CheckToken( ";" ) ) {
1683                 if ( scope->TypeDef()->ReturnType()->Type() != ev_void ) {
1684                         Error( "expecting return value" );
1685                 }
1686
1687                 EmitOpcode( OP_RETURN, 0, 0 );
1688                 return;
1689         }
1690
1691         e = GetExpression( TOP_PRIORITY );
1692         ExpectToken( ";" );
1693
1694         type_a = e->Type();
1695         type_b = scope->TypeDef()->ReturnType()->Type();
1696
1697         if ( TypeMatches( type_a, type_b ) ) {
1698                 EmitOpcode( OP_RETURN, e, 0 );
1699                 return;
1700         }
1701
1702         for( op = opcodes; op->name; op++ ) {
1703                 if ( !strcmp( op->name, "=" ) ) {
1704                         break;
1705                 }
1706         }
1707
1708         assert( op->name );
1709
1710         while( !TypeMatches( type_a, op->type_a->Type() ) || !TypeMatches( type_b, op->type_b->Type() ) ) {
1711                 op++;
1712                 if ( !op->name || strcmp( op->name, "=" ) ) {
1713                         Error( "type mismatch for return value" );
1714                 }
1715         }
1716
1717         idTypeDef *returnType = scope->TypeDef()->ReturnType();
1718         if ( returnType->Type() == ev_string ) {
1719                 EmitOpcode( op, e, gameLocal.program.returnStringDef );
1720         } else {
1721                 gameLocal.program.returnDef->SetTypeDef( returnType );
1722                 EmitOpcode( op, e, gameLocal.program.returnDef );
1723         }
1724         EmitOpcode( OP_RETURN, 0, 0 );
1725 }
1726         
1727 /*
1728 ================
1729 idCompiler::ParseWhileStatement
1730 ================
1731 */
1732 void idCompiler::ParseWhileStatement( void ) {
1733         idVarDef        *e;
1734         int                     patch1;
1735         int                     patch2;
1736
1737         loopDepth++;
1738
1739         ExpectToken( "(" );
1740         
1741         patch2 = gameLocal.program.NumStatements();
1742         e = GetExpression( TOP_PRIORITY );
1743         ExpectToken( ")" );
1744
1745         if ( ( e->initialized == idVarDef::initializedConstant ) && ( *e->value.intPtr != 0 ) ) {
1746                 //FIXME: we can completely skip generation of this code in the opposite case
1747                 ParseStatement();
1748                 EmitOpcode( OP_GOTO, JumpTo( patch2 ), 0 );
1749         } else {
1750                 patch1 = gameLocal.program.NumStatements();
1751         EmitOpcode( OP_IFNOT, e, 0 );
1752                 ParseStatement();
1753                 EmitOpcode( OP_GOTO, JumpTo( patch2 ), 0 );
1754                 gameLocal.program.GetStatement( patch1 ).b = JumpFrom( patch1 );
1755         }
1756
1757         // fixup breaks and continues
1758         PatchLoop( patch2, patch2 );
1759
1760         loopDepth--;
1761 }
1762
1763 /*
1764 ================
1765 idCompiler::ParseForStatement
1766
1767 Form of for statement with a counter:
1768
1769         a = 0;
1770 start:                                  << patch4
1771         if ( !( a < 10 ) ) {
1772                 goto end;               << patch1
1773         } else {
1774                 goto process;   << patch3
1775         }
1776
1777 increment:                              << patch2
1778         a = a + 1;
1779         goto start;                     << goto patch4
1780
1781 process:
1782         statements;
1783         goto increment;         << goto patch2
1784
1785 end:
1786
1787 Form of for statement without a counter:
1788
1789         a = 0;
1790 start:                                  << patch2
1791         if ( !( a < 10 ) ) {
1792                 goto end;               << patch1
1793         }
1794
1795 process:
1796         statements;
1797         goto start;                     << goto patch2
1798
1799 end:
1800 ================
1801 */
1802 void idCompiler::ParseForStatement( void ) {
1803         idVarDef        *e;
1804         int                     start;
1805         int                     patch1;
1806         int                     patch2;
1807         int                     patch3;
1808         int                     patch4;
1809
1810         loopDepth++;
1811
1812         start = gameLocal.program.NumStatements();
1813
1814         ExpectToken( "(" );
1815         
1816         // init
1817         if ( !CheckToken( ";" ) ) {
1818                 do {
1819                         GetExpression( TOP_PRIORITY );
1820                 } while( CheckToken( "," ) );
1821
1822                 ExpectToken( ";" );
1823         }
1824
1825         // condition
1826         patch2 = gameLocal.program.NumStatements();
1827
1828         e = GetExpression( TOP_PRIORITY );
1829         ExpectToken( ";" );
1830
1831         //FIXME: add check for constant expression
1832         patch1 = gameLocal.program.NumStatements();
1833         EmitOpcode( OP_IFNOT, e, 0 );
1834
1835         // counter
1836         if ( !CheckToken( ")" ) ) {
1837                 patch3 = gameLocal.program.NumStatements();
1838                 EmitOpcode( OP_IF, e, 0 );
1839
1840                 patch4 = patch2;
1841                 patch2 = gameLocal.program.NumStatements();
1842                 do {
1843                         GetExpression( TOP_PRIORITY );
1844                 } while( CheckToken( "," ) );
1845                 
1846                 ExpectToken( ")" );
1847
1848                 // goto patch4
1849                 EmitOpcode( OP_GOTO, JumpTo( patch4 ), 0 );
1850
1851                 // fixup patch3
1852                 gameLocal.program.GetStatement( patch3 ).b = JumpFrom( patch3 );
1853         }
1854
1855         ParseStatement();
1856
1857         // goto patch2
1858         EmitOpcode( OP_GOTO, JumpTo( patch2 ), 0 );
1859
1860         // fixup patch1
1861         gameLocal.program.GetStatement( patch1 ).b = JumpFrom( patch1 );
1862
1863         // fixup breaks and continues
1864         PatchLoop( start, patch2 );
1865
1866         loopDepth--;
1867 }
1868
1869 /*
1870 ================
1871 idCompiler::ParseDoWhileStatement
1872 ================
1873 */
1874 void idCompiler::ParseDoWhileStatement( void ) {
1875         idVarDef        *e;
1876         int                     patch1;
1877
1878         loopDepth++;
1879
1880         patch1 = gameLocal.program.NumStatements();
1881         ParseStatement();
1882         ExpectToken( "while" );
1883         ExpectToken( "(" );
1884         e = GetExpression( TOP_PRIORITY );
1885         ExpectToken( ")" );
1886         ExpectToken( ";" );
1887
1888         EmitOpcode( OP_IF, e, JumpTo( patch1 ) );
1889
1890         // fixup breaks and continues
1891         PatchLoop( patch1, patch1 );
1892
1893         loopDepth--;
1894 }
1895
1896 /*
1897 ================
1898 idCompiler::ParseIfStatement
1899 ================
1900 */
1901 void idCompiler::ParseIfStatement( void ) {
1902         idVarDef        *e;
1903         int                     patch1;
1904         int                     patch2;
1905
1906         ExpectToken( "(" );
1907         e = GetExpression( TOP_PRIORITY );
1908         ExpectToken( ")" );
1909
1910         //FIXME: add check for constant expression
1911         patch1 = gameLocal.program.NumStatements();
1912         EmitOpcode( OP_IFNOT, e, 0 );
1913
1914         ParseStatement();
1915         
1916         if ( CheckToken( "else" ) ) {
1917                 patch2 = gameLocal.program.NumStatements();
1918                 EmitOpcode( OP_GOTO, 0, 0 );
1919                 gameLocal.program.GetStatement( patch1 ).b = JumpFrom( patch1 );
1920                 ParseStatement();
1921                 gameLocal.program.GetStatement( patch2 ).a = JumpFrom( patch2 );
1922         } else {
1923                 gameLocal.program.GetStatement( patch1 ).b = JumpFrom( patch1 );
1924         }
1925 }
1926
1927 /*
1928 ============
1929 idCompiler::ParseStatement
1930 ============
1931 */
1932 void idCompiler::ParseStatement( void ) {
1933         if ( CheckToken( ";" ) ) {
1934                 // skip semicolons, which are harmless and ok syntax
1935                 return;
1936         }
1937
1938         if ( CheckToken( "{" ) ) {
1939                 do {
1940                         ParseStatement();
1941                 } while( !CheckToken( "}" ) );
1942
1943                 return;
1944         } 
1945
1946         if ( CheckToken( "return" ) ) {
1947                 ParseReturnStatement();
1948                 return;
1949         }
1950         
1951         if ( CheckToken( "while" ) ) {
1952                 ParseWhileStatement();
1953                 return;
1954         }
1955
1956         if ( CheckToken( "for" ) ) {
1957                 ParseForStatement();
1958                 return;
1959         }
1960
1961         if ( CheckToken( "do" ) ) {
1962                 ParseDoWhileStatement();
1963                 return;
1964         }
1965
1966         if ( CheckToken( "break" ) ) {
1967                 ExpectToken( ";" );
1968                 if ( !loopDepth ) {
1969                         Error( "cannot break outside of a loop" );
1970                 }
1971                 EmitOpcode( OP_BREAK, 0, 0 );
1972                 return;
1973         }
1974
1975         if ( CheckToken( "continue" ) ) {
1976                 ExpectToken( ";" );
1977                 if ( !loopDepth ) {
1978                         Error( "cannot contine outside of a loop" );
1979                 }
1980                 EmitOpcode( OP_CONTINUE, 0, 0 );
1981                 return;
1982         }
1983
1984         if ( CheckType() != NULL ) {
1985                 ParseDefs();
1986                 return;
1987         }
1988
1989         if ( CheckToken( "if" ) ) {
1990                 ParseIfStatement();
1991                 return;
1992         }
1993
1994         GetExpression( TOP_PRIORITY );
1995         ExpectToken(";");
1996 }
1997
1998 /*
1999 ================
2000 idCompiler::ParseObjectDef
2001 ================
2002 */
2003 void idCompiler::ParseObjectDef( const char *objname ) {
2004         idTypeDef       *objtype;
2005         idTypeDef       *type;
2006         idTypeDef       *parentType;
2007         idTypeDef       *fieldtype;
2008         idStr           name;
2009         const char  *fieldname;
2010         idTypeDef       newtype( ev_field, NULL, "", 0, NULL );
2011         idVarDef        *oldscope;
2012         int                     num;
2013         int                     i;
2014
2015         oldscope = scope;
2016         if ( scope->Type() != ev_namespace ) {
2017                 Error( "Objects cannot be defined within functions or other objects" );
2018         }
2019
2020         // make sure it doesn't exist before we create it
2021         if ( gameLocal.program.FindType( objname ) != NULL ) {
2022                 Error( "'%s' : redefinition; different basic types", objname );
2023         }
2024
2025         // base type
2026         if ( !CheckToken( ":" ) ) {
2027                 parentType = &type_object;
2028         } else {
2029                 parentType = ParseType();
2030                 if ( !parentType->Inherits( &type_object ) ) {
2031                         Error( "Objects may only inherit from objects." );
2032                 }
2033         }
2034         
2035         objtype = gameLocal.program.AllocType( ev_object, NULL, objname, parentType == &type_object ? 0 : parentType->Size(), parentType );
2036         objtype->def = gameLocal.program.AllocDef( objtype, objname, scope, true );
2037         scope = objtype->def;
2038
2039         // inherit all the functions
2040         num = parentType->NumFunctions();
2041         for( i = 0; i < parentType->NumFunctions(); i++ ) {
2042                 const function_t *func = parentType->GetFunction( i );
2043                 objtype->AddFunction( func );
2044         }
2045
2046         ExpectToken( "{" );
2047
2048         do {
2049                 if ( CheckToken( ";" ) ) {
2050                         // skip semicolons, which are harmless and ok syntax
2051                         continue;
2052                 }
2053
2054                 fieldtype = ParseType();
2055                 newtype.SetFieldType( fieldtype );
2056
2057                 fieldname = va( "%s field", fieldtype->Name() );
2058                 newtype.SetName( fieldname );
2059
2060                 ParseName( name );
2061
2062                 // check for a function prototype or declaraction
2063                 if ( CheckToken( "(" ) ) {
2064                         ParseFunctionDef( newtype.FieldType(), name );
2065                 } else {
2066                         type = gameLocal.program.GetType( newtype, true );
2067                         assert( !type->def );
2068                         gameLocal.program.AllocDef( type, name, scope, true );
2069                         objtype->AddField( type, name );
2070                         ExpectToken( ";" );
2071                 }
2072         } while( !CheckToken( "}" ) );
2073
2074         scope = oldscope;
2075
2076         ExpectToken( ";" );
2077 }
2078
2079 /*
2080 ============
2081 idCompiler::ParseFunction
2082
2083 parse a function type
2084 ============
2085 */
2086 idTypeDef *idCompiler::ParseFunction( idTypeDef *returnType, const char *name ) {
2087         idTypeDef       newtype( ev_function, NULL, name, type_function.Size(), returnType );
2088         idTypeDef       *type;
2089         
2090         if ( scope->Type() != ev_namespace ) {
2091                 // create self pointer
2092                 newtype.AddFunctionParm( scope->TypeDef(), "self" );
2093         }
2094
2095         if ( !CheckToken( ")" ) ) {
2096                 idStr parmName;
2097                 do {
2098                         type = ParseType();
2099                         ParseName( parmName );
2100                         newtype.AddFunctionParm( type, parmName );
2101                 } while( CheckToken( "," ) );
2102
2103                 ExpectToken( ")" );
2104         }
2105
2106         return gameLocal.program.GetType( newtype, true );
2107 }
2108
2109 /*
2110 ================
2111 idCompiler::ParseFunctionDef
2112 ================
2113 */
2114 void idCompiler::ParseFunctionDef( idTypeDef *returnType, const char *name ) {
2115         idTypeDef               *type;
2116         idVarDef                *def;
2117         const idVarDef  *parm;
2118         idVarDef                *oldscope;
2119         int                     i;
2120         int                     numParms;
2121         const idTypeDef *parmType;
2122         function_t              *func;
2123         statement_t             *pos;
2124
2125         if ( ( scope->Type() != ev_namespace ) && !scope->TypeDef()->Inherits( &type_object ) ) {
2126                 Error( "Functions may not be defined within other functions" );
2127         }
2128
2129         type = ParseFunction( returnType, name );
2130         def = gameLocal.program.GetDef( type, name, scope );
2131         if ( !def ) {
2132                 def = gameLocal.program.AllocDef( type, name, scope, true );
2133                 type->def = def;
2134
2135                 func = &gameLocal.program.AllocFunction( def );
2136                 if ( scope->TypeDef()->Inherits( &type_object ) ) {
2137                         scope->TypeDef()->AddFunction( func );
2138                 }
2139         } else {
2140                 func = def->value.functionPtr;
2141                 assert( func );
2142                 if ( func->firstStatement ) {
2143                         Error( "%s redeclared", def->GlobalName() );
2144                 }
2145         }
2146
2147         // check if this is a prototype or declaration
2148         if ( !CheckToken( "{" ) ) {
2149                 // it's just a prototype, so get the ; and move on
2150                 ExpectToken( ";" );
2151                 return;
2152         }
2153
2154         // calculate stack space used by parms
2155         numParms = type->NumParameters();
2156         func->parmSize.SetNum( numParms );
2157         for( i = 0; i < numParms; i++ ) {
2158                 parmType = type->GetParmType( i );
2159                 if ( parmType->Inherits( &type_object ) ) {
2160                         func->parmSize[ i ] = type_object.Size();
2161                 } else {
2162                         func->parmSize[ i ] = parmType->Size();
2163                 }
2164                 func->parmTotal += func->parmSize[ i ];
2165         }
2166
2167         // define the parms
2168         for( i = 0; i < numParms; i++ ) {
2169                 if ( gameLocal.program.GetDef( type->GetParmType( i ), type->GetParmName( i ), def ) ) {
2170                         Error( "'%s' defined more than once in function parameters", type->GetParmName( i ) );
2171                 }
2172                 parm = gameLocal.program.AllocDef( type->GetParmType( i ), type->GetParmName( i ), def, false );
2173         }
2174
2175         oldscope = scope;
2176         scope = def;
2177
2178         func->firstStatement = gameLocal.program.NumStatements();
2179
2180         // check if we should call the super class constructor
2181         if ( oldscope->TypeDef()->Inherits( &type_object ) && !idStr::Icmp( name, "init" ) ) {
2182                 idTypeDef *superClass;
2183                 function_t *constructorFunc = NULL;
2184
2185                 // find the superclass constructor
2186                 for( superClass = oldscope->TypeDef()->SuperClass(); superClass != &type_object; superClass = superClass->SuperClass() ) {
2187                         constructorFunc = gameLocal.program.FindFunction( va( "%s::init", superClass->Name() ) );
2188                         if ( constructorFunc ) {
2189                                 break;
2190                         }
2191                 }
2192
2193                 // emit the call to the constructor
2194                 if ( constructorFunc ) {
2195                         idVarDef *selfDef = gameLocal.program.GetDef( type->GetParmType( 0 ), type->GetParmName( 0 ), def );
2196                         assert( selfDef );
2197                         EmitPush( selfDef, selfDef->TypeDef() );
2198                         EmitOpcode( &opcodes[ OP_CALL ], constructorFunc->def, 0 );
2199                 }
2200         }
2201
2202         // parse regular statements
2203         while( !CheckToken( "}" ) ) {
2204                 ParseStatement();
2205         }
2206
2207         // check if we should call the super class destructor
2208         if ( oldscope->TypeDef()->Inherits( &type_object ) && !idStr::Icmp( name, "destroy" ) ) {
2209                 idTypeDef *superClass;
2210                 function_t *destructorFunc = NULL;
2211
2212                 // find the superclass destructor
2213                 for( superClass = oldscope->TypeDef()->SuperClass(); superClass != &type_object; superClass = superClass->SuperClass() ) {
2214                         destructorFunc = gameLocal.program.FindFunction( va( "%s::destroy", superClass->Name() ) );
2215                         if ( destructorFunc ) {
2216                                 break;
2217                         }
2218                 }
2219
2220                 if ( destructorFunc ) {
2221                         if ( func->firstStatement < gameLocal.program.NumStatements() ) {
2222                                 // change all returns to point to the call to the destructor
2223                                 pos = &gameLocal.program.GetStatement( func->firstStatement );
2224                                 for( i = func->firstStatement; i < gameLocal.program.NumStatements(); i++, pos++ ) {
2225                                         if ( pos->op == OP_RETURN ) {
2226                                                 pos->op = OP_GOTO;
2227                                                 pos->a = JumpDef( i, gameLocal.program.NumStatements() );
2228                                         }
2229                                 }
2230                         }
2231
2232                         // emit the call to the destructor
2233                         idVarDef *selfDef = gameLocal.program.GetDef( type->GetParmType( 0 ), type->GetParmName( 0 ), def );
2234                         assert( selfDef );
2235                         EmitPush( selfDef, selfDef->TypeDef() );
2236                         EmitOpcode( &opcodes[ OP_CALL ], destructorFunc->def, 0 );
2237                 }
2238         }
2239
2240 // Disabled code since it caused a function to fall through to the next function when last statement is in the form "if ( x ) { return; }"
2241 #if 0
2242         // don't bother adding a return opcode if the "return" statement was used.
2243         if ( ( func->firstStatement == gameLocal.program.NumStatements() ) || ( gameLocal.program.GetStatement( gameLocal.program.NumStatements() - 1 ).op != OP_RETURN ) ) {
2244                 // emit an end of statements opcode
2245                 EmitOpcode( OP_RETURN, 0, 0 );
2246         }
2247 #else
2248         // always emit the return opcode
2249         EmitOpcode( OP_RETURN, 0, 0 );
2250 #endif
2251
2252         // record the number of statements in the function
2253         func->numStatements = gameLocal.program.NumStatements() - func->firstStatement;
2254
2255         scope = oldscope;
2256 }
2257
2258 /*
2259 ================
2260 idCompiler::ParseVariableDef
2261 ================
2262 */
2263 void idCompiler::ParseVariableDef( idTypeDef *type, const char *name ) {
2264         idVarDef        *def, *def2;
2265         bool            negate;
2266
2267         def = gameLocal.program.GetDef( type, name, scope );
2268         if ( def ) {
2269                 Error( "%s redeclared", name );
2270         }
2271         
2272         def = gameLocal.program.AllocDef( type, name, scope, false );
2273
2274         // check for an initialization
2275         if ( CheckToken( "=" ) ) {
2276                 // if a local variable in a function then write out interpreter code to initialize variable
2277                 if ( scope->Type() == ev_function ) {
2278                         def2 = GetExpression( TOP_PRIORITY );
2279                         if ( ( type == &type_float ) && ( def2->TypeDef() == &type_float ) ) {
2280                                 EmitOpcode( OP_STORE_F, def2, def );
2281                         } else if ( ( type == &type_vector ) && ( def2->TypeDef() == &type_vector ) ) {
2282                                 EmitOpcode( OP_STORE_V, def2, def );
2283                         } else if ( ( type == &type_string ) && ( def2->TypeDef() == &type_string ) ) {
2284                                 EmitOpcode( OP_STORE_S, def2, def );
2285                         } else if ( ( type == &type_entity ) && ( ( def2->TypeDef() == &type_entity ) || ( def2->TypeDef()->Inherits( &type_object ) ) ) ) {
2286                                 EmitOpcode( OP_STORE_ENT, def2, def );
2287                         } else if ( ( type->Inherits( &type_object ) ) && ( def2->TypeDef() == &type_entity ) ) {
2288                                 EmitOpcode( OP_STORE_OBJENT, def2, def );
2289                         } else if ( ( type->Inherits( &type_object ) ) && ( def2->TypeDef()->Inherits( type ) ) ) {
2290                                 EmitOpcode( OP_STORE_OBJ, def2, def );
2291                         } else if ( ( type == &type_boolean ) && ( def2->TypeDef() == &type_boolean ) ) {
2292                                 EmitOpcode( OP_STORE_BOOL, def2, def );
2293                         } else if ( ( type == &type_string ) && ( def2->TypeDef() == &type_float ) ) {
2294                                 EmitOpcode( OP_STORE_FTOS, def2, def );
2295                         } else if ( ( type == &type_string ) && ( def2->TypeDef() == &type_boolean ) ) {
2296                                 EmitOpcode( OP_STORE_BTOS, def2, def );
2297                         } else if ( ( type == &type_string ) && ( def2->TypeDef() == &type_vector ) ) {
2298                                 EmitOpcode( OP_STORE_VTOS, def2, def );
2299                         } else if ( ( type == &type_boolean ) && ( def2->TypeDef() == &type_float ) ) {
2300                                 EmitOpcode( OP_STORE_FTOBOOL, def2, def );
2301                         } else if ( ( type == &type_float ) && ( def2->TypeDef() == &type_boolean ) ) {
2302                                 EmitOpcode( OP_STORE_BOOLTOF, def2, def );
2303                         } else {
2304                                 Error( "bad initialization for '%s'", name );
2305                         }
2306                 } else {
2307                         // global variables can only be initialized with immediate values
2308                         negate = false;
2309                         if ( token.type == TT_PUNCTUATION && token == "-" ) {
2310                                 negate = true;
2311                                 NextToken();
2312                                 if ( immediateType != &type_float ) {
2313                                         Error( "wrong immediate type for '-' on variable '%s'", name );
2314                                 }
2315                         }
2316
2317                         if ( immediateType != type ) {
2318                                 Error( "wrong immediate type for '%s'", name );
2319                         }
2320
2321                         // global variables are initialized at start up
2322                         if ( type == &type_string ) {
2323                                 def->SetString( token, false );
2324                         } else {
2325                                 if ( negate ) {
2326                                         immediate._float = -immediate._float;
2327                                 }
2328                                 def->SetValue( immediate, false );
2329                         }
2330                         NextToken();
2331                 }
2332         } else if ( type == &type_string ) {
2333                 // local strings on the stack are initialized in the interpreter
2334                 if ( scope->Type() != ev_function ) {
2335                         def->SetString( "", false );
2336                 }
2337         } else if ( type->Inherits( &type_object ) ) {
2338                 if ( scope->Type() != ev_function ) {
2339                         def->SetObject( NULL );
2340                 }
2341         }
2342 }
2343
2344 /*
2345 ================
2346 idCompiler::GetTypeForEventArg
2347 ================
2348 */
2349 idTypeDef *idCompiler::GetTypeForEventArg( char argType ) {
2350         idTypeDef *type;
2351
2352         switch( argType ) {
2353         case D_EVENT_INTEGER :
2354                 // this will get converted to int by the interpreter
2355                 type = &type_float;
2356                 break;
2357
2358         case D_EVENT_FLOAT :
2359                 type = &type_float;
2360                 break;
2361
2362         case D_EVENT_VECTOR :
2363                 type = &type_vector;
2364                 break;
2365
2366         case D_EVENT_STRING :
2367                 type = &type_string;
2368                 break;
2369
2370         case D_EVENT_ENTITY :
2371         case D_EVENT_ENTITY_NULL :
2372                 type = &type_entity;
2373                 break;
2374
2375         case D_EVENT_VOID :
2376                 type = &type_void;
2377                 break;
2378
2379         case D_EVENT_TRACE :
2380                 // This data type isn't available from script
2381                 type = NULL;
2382                 break;
2383
2384         default:
2385                 // probably a typo
2386                 type = NULL;
2387                 break;
2388         }
2389         
2390         return type;
2391 }
2392
2393 /*
2394 ================
2395 idCompiler::ParseEventDef
2396 ================
2397 */
2398 void idCompiler::ParseEventDef( idTypeDef *returnType, const char *name ) {
2399         const idTypeDef *expectedType;
2400         idTypeDef               *argType;
2401         idTypeDef               *type;
2402         int                     i;
2403         int                             num;
2404         const char              *format;
2405         const idEventDef *ev;
2406         idStr                   parmName;
2407
2408         ev = idEventDef::FindEvent( name );
2409         if ( !ev ) {
2410                 Error( "Unknown event '%s'", name );
2411         }
2412
2413         // set the return type
2414         expectedType = GetTypeForEventArg( ev->GetReturnType() );
2415         if ( !expectedType ) {
2416                 Error( "Invalid return type '%c' in definition of '%s' event.", ev->GetReturnType(), name );
2417         }
2418         if ( returnType != expectedType ) {
2419                 Error( "Return type doesn't match internal return type '%s'", expectedType->Name() );
2420         }
2421
2422         idTypeDef newtype( ev_function, NULL, name, type_function.Size(), returnType );
2423
2424         ExpectToken( "(" );
2425
2426         format = ev->GetArgFormat();
2427         num = strlen( format );
2428         for( i = 0; i < num; i++ ) {
2429                 expectedType = GetTypeForEventArg( format[ i ] );
2430                 if ( !expectedType || ( expectedType == &type_void ) ) {
2431                         Error( "Invalid parameter '%c' in definition of '%s' event.", format[ i ], name );
2432                 }
2433
2434                 argType = ParseType();
2435                 ParseName( parmName );
2436                 if ( argType != expectedType ) {
2437                         Error( "The type of parm %d ('%s') does not match the internal type '%s' in definition of '%s' event.", 
2438                                 i + 1, parmName.c_str(), expectedType->Name(), name );
2439                 }
2440
2441                 newtype.AddFunctionParm( argType, "" );
2442
2443                 if ( i < num - 1 ) {
2444                         if ( CheckToken( ")" ) ) {
2445                                 Error( "Too few parameters for event definition.  Internal definition has %d parameters.", num );
2446                         }
2447                         ExpectToken( "," );
2448                 }
2449         }
2450         if ( !CheckToken( ")" ) ) {
2451                 Error( "Too many parameters for event definition.  Internal definition has %d parameters.", num );
2452         }
2453         ExpectToken( ";" );
2454
2455         type = gameLocal.program.FindType( name );
2456         if ( type ) {
2457                 if ( !newtype.MatchesType( *type ) || ( type->def->value.functionPtr->eventdef != ev ) ) {
2458                         Error( "Type mismatch on redefinition of '%s'", name );
2459                 }
2460         } else {
2461                 type = gameLocal.program.AllocType( newtype );
2462                 type->def = gameLocal.program.AllocDef( type, name, &def_namespace, true );
2463
2464                 function_t &func        = gameLocal.program.AllocFunction( type->def );
2465                 func.eventdef           = ev;
2466                 func.parmSize.SetNum( num );
2467                 for( i = 0; i < num; i++ ) {
2468                         argType = newtype.GetParmType( i );
2469                         func.parmTotal          += argType->Size();
2470                         func.parmSize[ i ]      = argType->Size();
2471                 }
2472
2473                 // mark the parms as local
2474                 func.locals     = func.parmTotal;
2475         }
2476 }
2477
2478 /*
2479 ================
2480 idCompiler::ParseDefs
2481
2482 Called at the outer layer and when a local statement is hit
2483 ================
2484 */
2485 void idCompiler::ParseDefs( void ) {
2486         idStr           name;
2487         idTypeDef       *type;
2488         idVarDef        *def;
2489         idVarDef        *oldscope;
2490
2491         if ( CheckToken( ";" ) ) {
2492                 // skip semicolons, which are harmless and ok syntax
2493                 return;
2494         }
2495
2496         type = ParseType();
2497         if ( type == &type_scriptevent ) {
2498                 type = ParseType();
2499                 ParseName( name );
2500                 ParseEventDef( type, name );
2501                 return;
2502         }
2503     
2504         ParseName( name );
2505
2506         if ( type == &type_namespace ) {
2507                 def = gameLocal.program.GetDef( type, name, scope );
2508                 if ( !def ) {
2509                         def = gameLocal.program.AllocDef( type, name, scope, true );
2510                 }
2511                 ParseNamespace( def );
2512         } else if ( CheckToken( "::" ) ) {
2513                 def = gameLocal.program.GetDef( NULL, name, scope );
2514                 if ( !def ) {
2515                         Error( "Unknown object name '%s'", name.c_str() );
2516                 }
2517                 ParseName( name );
2518                 oldscope = scope;
2519                 scope = def;
2520
2521                 ExpectToken( "(" );
2522                 ParseFunctionDef( type, name.c_str() );
2523                 scope = oldscope;
2524         } else if ( type == &type_object ) {
2525                 ParseObjectDef( name.c_str() );
2526         } else if ( CheckToken( "(" ) ) {               // check for a function prototype or declaraction
2527                 ParseFunctionDef( type, name.c_str() );
2528         } else {
2529                 ParseVariableDef( type, name.c_str() );
2530                 while( CheckToken( "," ) ) {
2531                         ParseName( name );
2532                         ParseVariableDef( type, name.c_str() );
2533                 }
2534                 ExpectToken( ";" );
2535         }
2536 }
2537
2538 /*
2539 ================
2540 idCompiler::ParseNamespace
2541
2542 Parses anything within a namespace definition
2543 ================
2544 */
2545 void idCompiler::ParseNamespace( idVarDef *newScope ) {
2546         idVarDef *oldscope;
2547
2548         oldscope = scope;
2549         if ( newScope != &def_namespace ) {
2550                 ExpectToken( "{" );
2551         }
2552
2553         while( !eof ) {
2554                 scope           = newScope;
2555                 callthread      = false;
2556
2557                 if ( ( newScope != &def_namespace ) && CheckToken( "}" ) ) {
2558                         break;
2559                 }
2560
2561                 ParseDefs();
2562         }
2563
2564         scope = oldscope;
2565 }
2566
2567 /*
2568 ============
2569 idCompiler::CompileFile
2570
2571 compiles the 0 terminated text, adding definitions to the program structure
2572 ============
2573 */
2574 void idCompiler::CompileFile( const char *text, const char *filename, bool toConsole ) {
2575         idTimer compile_time;
2576         bool error;
2577
2578         compile_time.Start();
2579
2580         scope                           = &def_namespace;
2581         basetype                        = NULL;
2582         callthread                      = false;
2583         loopDepth                       = 0;
2584         eof                                     = false;
2585         braceDepth                      = 0;
2586         immediateType           = NULL;
2587         currentLineNumber       = 0;
2588         console                         = toConsole;
2589         
2590         memset( &immediate, 0, sizeof( immediate ) );
2591
2592         parser.SetFlags( LEXFL_ALLOWMULTICHARLITERALS );
2593         parser.LoadMemory( text, strlen( text ), filename );
2594         parserPtr = &parser;
2595
2596         // unread tokens to include script defines
2597         token = SCRIPT_DEFAULTDEFS;
2598         token.type = TT_STRING;
2599         token.subtype = token.Length();
2600         token.line = token.linesCrossed = 0;
2601         parser.UnreadToken( &token );
2602
2603         token = "include";
2604         token.type = TT_NAME;
2605         token.subtype = token.Length();
2606         token.line = token.linesCrossed = 0;
2607         parser.UnreadToken( &token );
2608
2609         token = "#";
2610         token.type = TT_PUNCTUATION;
2611         token.subtype = P_PRECOMP;
2612         token.line = token.linesCrossed = 0;
2613         parser.UnreadToken( &token );
2614
2615         // init the current token line to be the first line so that currentLineNumber is set correctly in NextToken
2616         token.line = 1;
2617
2618         error = false;
2619         try {
2620                 // read first token
2621                 NextToken();
2622                 while( !eof && !error ) {
2623                         // parse from global namespace
2624                         ParseNamespace( &def_namespace );
2625                 }
2626         }
2627                 
2628         catch( idCompileError &err ) {
2629                 idStr error;
2630
2631                 if ( console ) {
2632                         // don't print line number of an error if were calling script from the console using the "script" command
2633                         sprintf( error, "Error: %s\n", err.error );
2634                 } else {
2635                         sprintf( error, "Error: file %s, line %d: %s\n", gameLocal.program.GetFilename( currentFileNumber ), currentLineNumber, err.error );
2636                 }
2637
2638                 parser.FreeSource();
2639
2640                 throw idCompileError( error );
2641         }
2642
2643         parser.FreeSource();
2644
2645         compile_time.Stop();
2646         if ( !toConsole ) {
2647                 gameLocal.Printf( "Compiled '%s': %.1f ms\n", filename, compile_time.Milliseconds() );
2648         }
2649 }