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