doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Script_Compiler.cpp
Go to the documentation of this file.
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 
41 const char *idCompiler::punctuation[] = {
42  "+=", "-=", "*=", "/=", "%=", "&=", "|=", "++", "--",
43  "&&", "||", "<=", ">=", "==", "!=", "::", ";", ",",
44  "~", "!", "*", "/", "%", "(", ")", "-", "+",
45  "=", "[", "]", ".", "<", ">" , "&", "|", ":", NULL
46 };
47 
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 */
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;
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 */
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 */
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 */
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 */
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 */
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
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
675 
676  if ( !parserPtr->ReadToken( &token ) ) {
677  eof = true;
678  return;
679  }
680 
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
700  return;
701 
702  case TT_LITERAL: {
703  // handle quoted vectors as a unit
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:
728  return;
729 
730  case TT_PUNCTUATION:
731  // entity names
732  if ( 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 */
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 */
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 */
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 */
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 */
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 */
919  idVarDef *def;
920 
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 
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
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
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 */
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 */
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 */
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 */
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 */
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.
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 */
1305  idVarDef *e;
1306  int op;
1307 
1308  if ( !immediateType && CheckToken( "~" ) ) {
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 ) {
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;
1419 
1420  if ( callthread ) {
1421  Error( "Invalid thread call" );
1422  }
1423 
1424  // threads return the thread number
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 */
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 ) {
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
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 */
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 ) {
1720  } else {
1721  gameLocal.program.returnDef->SetTypeDef( returnType );
1723  }
1724  EmitOpcode( OP_RETURN, 0, 0 );
1725 }
1726 
1727 /*
1728 ================
1729 idCompiler::ParseWhileStatement
1730 ================
1731 */
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 */
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 {
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 {
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 */
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 */
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 */
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" ) ) {
1948  return;
1949  }
1950 
1951  if ( CheckToken( "while" ) ) {
1953  return;
1954  }
1955 
1956  if ( CheckToken( "for" ) ) {
1958  return;
1959  }
1960 
1961  if ( CheckToken( "do" ) ) {
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 
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 
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.
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
2254 
2255  scope = oldscope;
2256 }
2257 
2258 /*
2259 ================
2260 idCompiler::ParseVariableDef
2261 ================
2262 */
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 ) {
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 */
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 */
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 */
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 
2593  parser.LoadMemory( text, strlen( text ), filename );
2594  parserPtr = &parser;
2595 
2596  // unread tokens to include script defines
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 = "#";
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
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 }
idList< int > parmSize
void SetName(const char *newname)
idTypeDef * CheckType(void)
#define strcmp
Definition: Str.h:41
bool TypeMatches(etype_t type1, etype_t type2) const
int type
Definition: Token.h:77
GLsizei const GLfloat * value
Definition: glext.h:3614
bool Compare(const idVec3 &a) const
Definition: Vector.h:496
idVarDef * GetDefList(const char *name) const
void ParseWhileStatement(void)
idVarDef def_entity
idVarDef def_object
assert(prefInfo.fullscreenBtn)
idVarDef def_string & type_string
char * stringPtr
idVarDef def_vector
void UnreadToken(idToken *token)
Definition: Parser.cpp:2745
int Cmp(const char *text) const
Definition: Str.h:652
etype_t Type(void) const
void SkipOutOfFunction(void)
static opcode_t opcodes[]
idVarDef * JumpDef(int jumpfrom, int jumpto)
void ParseDefs(void)
etype_t Type(void) const
void Printf(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:699
Definition: Timer.h:40
void NextToken(void)
float * floatPtr
statement_t * AllocStatement(void)
etype_t
GLenum GLsizei GLenum format
Definition: glext.h:2846
statement_t & GetStatement(int index)
idVarDef * GetDef(const idTypeDef *type, const char *name, const idVarDef *scope) const
void SetNum(int newnum, bool resize=true)
Definition: List.h:289
void ParseReturnStatement(void)
#define D_EVENT_ENTITY_NULL
Definition: Event.h:45
#define TT_NAME
Definition: Token.h:44
#define D_EVENT_VOID
Definition: Event.h:39
int Length(void) const
Definition: Str.h:702
function_t * functionPtr
idVarDef * EmitOpcode(const opcode_t *op, idVarDef *var_a, idVarDef *var_b)
void ParseName(idStr &name)
idVarDef * ParseImmediate(void)
#define D_EVENT_STRING
Definition: Event.h:43
varEval_t value
const idEventDef * eventdef
idVarDef def_object & type_object
float z
Definition: Vector.h:320
case const int
Definition: Callbacks.cpp:52
int subtype
Definition: Token.h:78
idParser parser
int linesCrossed
Definition: Token.h:80
float GetFloatValue(void)
Definition: Token.h:138
int GetFilenum(const char *name)
Definition: Vector.h:316
idVarDef * ParseFunctionCall(idVarDef *func)
case const float
Definition: Callbacks.cpp:62
void ParseIfStatement(void)
idVarDef * GetTerm(void)
void SkipToSemicolon(void)
idVarDef * type_c
idVarDef def_namespace & type_namespace
int LoadMemory(const char *ptr, int length, const char *name)
Definition: Parser.cpp:3049
void FreeSource(bool keepDefines=false)
Definition: Parser.cpp:3084
void Start(void)
Definition: Timer.h:144
void SetTypeDef(idTypeDef *_type)
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
void ParseNamespace(idVarDef *newScope)
Definition: Token.h:71
#define TT_STRING
Definition: Token.h:41
#define D_EVENT_ENTITY
Definition: Event.h:44
idVarDef * JumpFrom(int jumpfrom)
idVarDef def_scriptevent & type_scriptevent
const char * name
int NumParameters(void) const
double Milliseconds(void) const
Definition: Timer.h:191
idVarDef * a
idVec3 * vectorPtr
float x
Definition: Vector.h:318
#define P_PRECOMP
Definition: Lexer.h:126
int i
Definition: process.py:33
GLuint GLuint num
Definition: glext.h:5390
const char * Name(void) const
idVarDef * GetExpression(int priority)
#define NOT_PRIORITY
int Icmp(const char *text) const
Definition: Str.h:667
#define D_EVENT_FLOAT
Definition: Event.h:41
const idVarDef * basetype
#define TT_NUMBER
Definition: Token.h:43
idVarDef def_void & type_void
idProgram program
Definition: Game_local.h:293
unsigned short op
const char * GlobalName(void) const
void FreeDef(idVarDef *d, const idVarDef *scope)
void ParseForStatement(void)
const function_t * GetFunction(int funcNumber) const
idVarDef * ParseObjectCall(idVarDef *object, idVarDef *func)
void void idVarDef * OptimizeOpcode(const opcode_t *op, idVarDef *var_a, idVarDef *var_b)
bool CheckToken(const char *string)
idVarDef def_field
idVarDef def_vector & type_vector
idTypeDef * immediateType
float vector[3]
int ReadToken(idToken *token)
Definition: Parser.cpp:2338
void Error(const char *error,...) const id_attribute((format(printf
void SetString(const char *string, bool constant)
static const char * punctuation[]
const char * GetFilename(int num)
Definition: Lexer.h:137
int line
Definition: Token.h:79
int Size(void) const
static const idEventDef * FindEvent(const char *name)
Definition: Event.cpp:192
const char * GetParmName(int parmNumber) const
idTypeDef * TypeDef(void) const
const GLubyte * c
Definition: glext.h:4677
INT32 * numerator
Definition: wglext.h:503
idVarDef * type_b
int GetFunctionNumber(const function_t *func) const
idVarDef def_float & type_float
const char * Name(void) const
idVarDef def_boolean & type_boolean
#define SCRIPT_DEFAULTDEFS
Definition: Game.h:41
idVarDef * AllocDef(idTypeDef *type, const char *name, idVarDef *scope, bool constant)
idTypeDef * ReturnType(void) const
#define NULL
Definition: Lib.h:88
void AddFunction(const function_t *func)
idVarDef * LookupDef(const char *name, const idVarDef *baseobj)
float y
Definition: Vector.h:319
#define D_EVENT_VECTOR
Definition: Event.h:42
void ParseDoWhileStatement(void)
idVarDef * def
idVarDef * SizeConstant(int size)
void ParseObjectDef(const char *objname)
idTypeDef * ParseFunction(idTypeDef *returnType, const char *name)
idParser * parserPtr
initialized_t initialized
idVarDef * GetImmediate(idTypeDef *type, const eval_t *eval, const char *string)
idVarDef def_entity & type_entity
#define FUNCTION_PRIORITY
#define D_EVENT_TRACE
Definition: Event.h:46
int GetPunctuationId(const char *p)
Definition: Parser.cpp:3154
void ParseVariableDef(idTypeDef *type, const char *name)
int NumFunctions(void) const
void void Warning(const char *str,...) const id_attribute((format(printf
Definition: Parser.cpp:335
void SetFlags(int flags)
Definition: Parser.cpp:2990
void AddField(idTypeDef *fieldtype, const char *name)
idVarDef def_virtualfunction & type_virtualfunction
idVarDef * FindImmediate(const idTypeDef *type, const eval_t *eval, const char *string) const
idTypeDef * GetParmType(int parmNumber) const
void ParseEventDef(idTypeDef *type, const char *name)
bool rightAssociative
idGameLocal gameLocal
Definition: Game_local.cpp:64
idVarDef def_string
int firstStatement
idVarDef * c
idTypeDef * SuperClass(void) const
idVarDef def_pointer & type_pointer
void ExpectToken(const char *string)
idTypeDef * ParseType(void)
idVarDef * JumpTo(int jumpto)
void SetFieldType(idTypeDef *type)
idVarDef def_boolean
bool Inherits(const idTypeDef *basetype) const
#define TT_LITERAL
Definition: Token.h:42
int NumStatements(void)
INT32 INT32 * denominator
Definition: wglext.h:503
idTypeDef * AllocType(idTypeDef &type)
idTypeDef * GetType(idTypeDef &type, bool allocate)
void CompileFile(const char *text, const char *filename, bool console)
void Stop(void)
Definition: Timer.h:155
idVarDef * FindFreeResultDef(idTypeDef *type, const char *name, idVarDef *scope, const idVarDef *a, const idVarDef *b)
idVarDef def_pointer
void PatchLoop(int start, int continuePos)
idVarDef def_jumpoffset
idVarDef * EmitFunctionParms(int op, idVarDef *func, int startarg, int startsize, idVarDef *object)
idVarDef * def
static WindowRef ValidModeCallbackProc inCallback OSStatus err
idVarDef def_function & type_function
unsigned short linenumber
idTypeDef * FindType(const char *name)
void SetValue(const eval_t &value, bool constant)
GLuint id
Definition: glext.h:3103
#define TT_PUNCTUATION
Definition: Token.h:45
float _float
float Divide(float numerator, float denominator)
char error[MAX_STRING_CHARS]
Definition: Lib.h:152
#define TILDE_PRIORITY
idVarDef * JumpConstant(int value)
idVarDef * b
idVarDef * returnDef
eval_t immediate
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
idVarDef def_argsize
const char * GetArgFormat(void) const
Definition: Event.h:153
idVarDef * ParseValue(void)
Definition: Str.h:116
unsigned short file
idVarDef * Next(void) const
int SkipBracedSection(bool parseFirstBrace=true)
Definition: Parser.cpp:2611
idVarDef * ParseEventCall(idVarDef *object, idVarDef *func)
idVarDef * scope
int vsprintf(idStr &string, const char *fmt, va_list argptr)
Definition: Str.cpp:1549
idVarDef def_argsize & type_argsize
const char * c_str(void) const
Definition: Str.h:487
idVarDef def_function
idVarDef * VirtualFunctionConstant(idVarDef *func)
idTypeDef * GetTypeForEventArg(char argType)
idVarDef * type_a
idVarDef * returnStringDef
void void Warning(const char *message,...) const id_attribute((format(printf
bool EmitPush(idVarDef *expression, const idTypeDef *funcArg)
idVarDef def_jumpoffset & type_jumpoffset
#define INT_PRIORITY
function_t * FindFunction(const char *name) const
idTypeDef * PointerType(void) const
char GetReturnType(void) const
Definition: Event.h:171
static bool punctuationValid[256]
#define TOP_PRIORITY
char * va(const char *fmt,...)
Definition: Str.cpp:1568
function_t & AllocFunction(idVarDef *def)
const char *const RESULT_STRING
idVarDef * scope
void ParseStatement(void)
idVarDef def_void
#define D_EVENT_INTEGER
Definition: Event.h:40
idVarDef def_namespace
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
idVarDef def_float
void ParseFunctionDef(idTypeDef *returnType, const char *name)
int entity
GLuint start
Definition: glext.h:2845
int virtualFunction
const char * GetFileName(void) const
Definition: Parser.h:247
void SetObject(idScriptObject *object)
idVarDef * ParseSysObjectCall(idVarDef *func)
idTypeDef * FieldType(void) const