Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mission_script.cpp
Go to the documentation of this file.
1 /*
2  * Vega Strike
3  * Copyright (C) 2001-2002 Daniel Horn
4  *
5  * http://vegastrike.sourceforge.net/
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 /*
23  * xml Mission Scripting written by Alexander Rawass <alexannika@users.sourceforge.net>
24  */
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <time.h>
30 #include <ctype.h>
31 #include <assert.h>
32 #ifndef WIN32
33 //this file isn't available on my system (all win32 machines?) i dun even know what it has or if we need it as I can compile without it
34 #include <unistd.h>
35 #endif
36 
37 #include <expat.h>
38 #include "xml_support.h"
39 
40 #include "vegastrike.h"
41 
42 #include "mission.h"
43 #include "easydom.h"
44 
45 #include "vs_globals.h"
46 #include "config_xml.h"
47 
48 #include "msgcenter.h"
49 #include "cmd/unit_generic.h"
50 
51 /* *********************************************************** */
52 
53 /* *********************************************************** */
54 
55 void Mission::doImport( missionNode *node, int mode )
56 {
57  if (mode == SCRIPT_PARSE && parsemode == PARSE_DECL) {
58  string name = node->attr_value( "name" );
59  if ( name.empty() ) {
60  fatalError( node, mode, "you have to give a name to import" );
61  assert( 0 );
62  }
63  node->script.name = name;
64  import_stack.push_back( name );
65  }
66 }
67 
68 /* *********************************************************** */
69 
70 void Mission::doModule( missionNode *node, int mode )
71 {
72  if (mode == SCRIPT_PARSE) {
73  string name = node->attr_value( "name" );
74  if (parsemode == PARSE_DECL) {
75  if ( name.empty() ) {
76  fatalError( node, mode, "you have to give a module name" );
77  assert( 0 );
78  }
79  if (runtime.modules[name] != NULL) {
80  fatalError( node, mode, "there can only be one module with name "+name );
81  assert( 0 );
82  }
83  if (name == "director")
84  director = node;
85  node->script.name = name;
86 
87  varInstMap *cvmap = new varInstMap;
88  node->script.classvars.push_back( cvmap );
89  node->script.classinst_counter = 0;
90  debug( 10, node, mode, "created classinst 0" );
91 
92  runtime.modules[name] = node; //add this module to the list of known modules
93  }
94  scope_stack.push_back( node );
95 
96  current_module = node;
97 
98  debug( 5, node, mode, "added module "+name+" to list of known modules" );
99  }
100  if (mode == SCRIPT_RUN) {
101  //SCRIPT_RUN
102  runtime.cur_thread->module_stack.push_back( node );
103  runtime.cur_thread->classid_stack.push_back( 0 );
104  }
105  vector< easyDomNode* >::const_iterator siter;
106  for (siter = node->subnodes.begin(); siter != node->subnodes.end(); siter++) {
107  missionNode *snode = (missionNode*) *siter;
108  if (snode->tag == DTAG_SCRIPT) {
109  varInst *vi = doScript( snode, mode );
110  deleteVarInst( vi );
111  } else if (snode->tag == DTAG_DEFVAR) {
112  doDefVar( snode, mode );
113  } else if (snode->tag == DTAG_GLOBALS) {
114  doGlobals( snode, mode );
115  } else if (snode->tag == DTAG_IMPORT) {
116  doImport( snode, mode );
117  } else {
118  fatalError( snode, mode, "unkown node type for module subnodes" );
119  assert( 0 );
120  }
121  }
122  if (mode == SCRIPT_PARSE) {
123  scope_stack.pop_back();
124  } else {
125  runtime.cur_thread->module_stack.pop_back();
126  runtime.cur_thread->classid_stack.pop_back();
127  }
128 }
129 
130 /* *********************************************************** */
131 
132 scriptContext* Mission::makeContext( missionNode *node )
133 {
134  scriptContext *context = new scriptContext;
135 
136  context->varinsts = new varInstMap;
137 
138  context->block_node = node;
139 
140  return context;
141 }
142 
143 /* *********************************************************** */
144 
145 void Mission::removeContextStack()
146 {
147  contextStack *cstack = runtime.cur_thread->exec_stack.back();
148  runtime.cur_thread->exec_stack.pop_back();
149  if (cstack->return_value != NULL)
150  deleteVarInst( cstack->return_value, true );
151  delete cstack;
152 }
153 
154 void Mission::addContextStack( missionNode *node )
155 {
156  contextStack *cstack = new contextStack;
157 
158  cstack->return_value = NULL;
159 
160  runtime.cur_thread->exec_stack.push_back( cstack );
161 }
162 
163 scriptContext* Mission::addContext( missionNode *node )
164 {
165  scriptContext *context = makeContext( node );
166  contextStack *stack = runtime.cur_thread->exec_stack.back();
167  stack->contexts.push_back( context );
168 
169  debug( 5, node, SCRIPT_RUN, "added context for this node" );
170  printRuntime();
171 
172  return context;
173 }
174 
175 /* *********************************************************** */
176 
177 void Mission::removeContext()
178 {
179  contextStack *stack = runtime.cur_thread->exec_stack.back();
180 
181  int lastelem = stack->contexts.size()-1;
182 
183  scriptContext *old = stack->contexts[lastelem];
184  stack->contexts.pop_back();
185 #if 0
186  vsUMap< string, varInst* >::const_iterator iter;
187  for (iter = old->varinsts->begin(); iter != old->varinsts->end(); iter++) {
188  varInst *vi = (*iter).second;
189  deleteVarInst( vi );
190  }
191 #endif
192  deleteVarMap( old->varinsts );
193  delete old->varinsts;
194  delete old;
195 }
196 
197 /* *********************************************************** */
198 
199 varInst* Mission::doScript( missionNode *node, int mode, varInstMap *varmap )
200 {
201  trace( node, mode );
202  if (mode == SCRIPT_PARSE) {
203  current_script = node;
204  if (parsemode == PARSE_DECL) {
205  node->script.name = node->attr_value( "name" );
206  if ( node->script.name.empty() )
207  fatalError( node, mode, "you have to give a script name" );
208  current_module->script.scripts[node->script.name] = node;
209  debug( 5, node, mode, "added to module "+current_module->script.name+" : script ="+node->script.name );
210 
211  node->script.nr_arguments = 0;
212 
213  string retvalue = node->attr_value( "type" );
214  if (retvalue.empty() || retvalue == "void")
215  node->script.vartype = VAR_VOID;
216  else
217  node->script.vartype = vartypeFromString( retvalue );
218  }
219  scope_stack.push_back( node );
220  }
221  debug( 5, node, mode, "executing script name="+node->script.name );
222  if (mode == SCRIPT_RUN) {
223  addContextStack( node );
224  addContext( node );
225  }
226  vector< easyDomNode* >::const_iterator siter;
227  if (mode == SCRIPT_PARSE && parsemode == PARSE_DECL) {
228  node->script.nr_arguments = 0;
229  node->script.argument_node = NULL;
230  }
231  for (siter = node->subnodes.begin(); siter != node->subnodes.end() && !have_return( mode ); siter++) {
232  missionNode *snode = (missionNode*) *siter;
233  if (snode->tag == DTAG_ARGUMENTS) {
234  doArguments( snode, mode, varmap );
235  if (mode == SCRIPT_PARSE && parsemode == PARSE_DECL)
236  node->script.argument_node = snode;
237  char buffer[200];
238  sprintf( buffer, "nr of arguments=%d", node->script.nr_arguments );
239  debug( 3, node, mode, buffer );
240  } else {
241  if (mode == SCRIPT_PARSE && parsemode == PARSE_DECL) {
242  //do nothing, break here
243  } else {
244  checkStatement( snode, mode );
245  }
246  }
247  }
248  if (mode == SCRIPT_RUN) {
249  removeContext();
250  contextStack *cstack = runtime.cur_thread->exec_stack.back();
251  varInst *vi = cstack->return_value;
252  if (vi != NULL) {
253  if (node->script.vartype != vi->type) {
254  fatalError( node, mode, "doScript: return type not set correctly" );
255  assert( 0 );
256  }
257  } else
258  if (node->script.vartype != VAR_VOID) {
259  fatalError( node, mode, "no return set from doScript" );
260  assert( 0 );
261  }
262  varInst *viret = NULL;
263  if (vi) {
264  viret = newVarInst( VI_TEMP );
265  viret->type = vi->type;
266  assignVariable( viret, vi );
267  }
268  removeContextStack();
269 
270  return viret;
271  } else {
272  scope_stack.pop_back();
273  return NULL;
274  }
275 }
276 
277 /* *********************************************************** */
278 
279 void Mission::doArguments( missionNode *node, int mode, varInstMap *varmap )
280 {
281  int nr_arguments = 0;
282  if (mode == SCRIPT_PARSE) {
283  if (parsemode == PARSE_DECL) {
284  vector< easyDomNode* >::const_iterator siter;
285  for (siter = node->subnodes.begin(); siter != node->subnodes.end(); siter++) {
286  missionNode *snode = (missionNode*) *siter;
287  if (snode->tag == DTAG_DEFVAR) {
288  doDefVar( snode, mode );
289  nr_arguments++;
290  } else {
291  fatalError( node, mode, "only defvars allowed below argument node" );
292  assert( 0 );
293  }
294  }
295  node->script.nr_arguments = nr_arguments;
296  }
297  }
298  nr_arguments = node->script.nr_arguments;
299  if (mode == SCRIPT_RUN) {
300  if (varmap) {
301  int nr_called = varmap->size();
302  if (nr_arguments != nr_called) {
303  fatalError( node, mode, "wrong number of args in doScript " );
304  assert( 0 );
305  }
306  for (int i = 0; i < nr_arguments; i++) {
307  missionNode *defnode = (missionNode*) node->subnodes[i];
308 
309  doDefVar( defnode, mode );
310  varInst *vi = doVariable( defnode, mode );
311 
312  varInst *call_vi = (*varmap)[defnode->script.name];
313  if (call_vi == NULL) {
314  fatalError( node, mode, "argument var "+node->script.name+" no found in varmap" );
315  assert( 0 );
316  }
317  assignVariable( vi, call_vi );
318  }
319  } else
320  //no varmap == 0 args
321  if (nr_arguments != 0) {
322  fatalError( node, mode, "doScript expected to be called with arguments" );
323  assert( 0 );
324  }
325  }
326  if (mode == SCRIPT_PARSE) {
327  if (parsemode == PARSE_DECL) {
328  missionNode *exec_scope = scope_stack.back();
329  exec_scope->script.nr_arguments = nr_arguments;
330  node->script.nr_arguments = nr_arguments;
331  }
332  }
333 }
334 
335 /* *********************************************************** */
336 
337 void Mission::doReturn( missionNode *node, int mode )
338 {
339  trace( node, mode );
340  if (mode == SCRIPT_PARSE) {
341  missionNode *script = current_script;
342 
343  node->script.exec_node = script;
344  }
345  int len = node->subnodes.size();
346  varInst *vi = newVarInst( VI_LOCAL );
347 
348  missionNode *script = node->script.exec_node;
349  if (script->script.vartype == VAR_VOID) {
350  if (len != 0) {
351  fatalError( node, mode, "script returning void, but return statement with node" );
352  assert( 0 );
353  }
354  } else {
355  //return something non-void
356  if (len != 1) {
357  fatalError( node, mode, "return statement needs only one subnode" );
358  assert( 0 );
359  }
360  missionNode *expr = (missionNode*) node->subnodes[0];
361  if (script->script.vartype == VAR_BOOL) {
362  bool res = checkBoolExpr( expr, mode );
363  vi->bool_val = res;
364  } else if (script->script.vartype == VAR_FLOAT) {
365  double res = checkFloatExpr( expr, mode );
366  vi->float_val = res;
367  } else if (script->script.vartype == VAR_INT) {
368  int res = checkIntExpr( expr, mode );
369  vi->int_val = res;
370  } else if (script->script.vartype == VAR_OBJECT) {
371  varInst *vi2 = checkObjectExpr( expr, mode );
372  vi->type = VAR_OBJECT;
373  assignVariable( vi, vi2 );
374  } else {
375  fatalError( node, mode, "unkown variable type" );
376  assert( 0 );
377  }
378  }
379  if (mode == SCRIPT_RUN) {
380  contextStack *cstack = runtime.cur_thread->exec_stack.back();
381 
382  vi->type = script->script.vartype;
383 
384  cstack->return_value = vi;
385  }
386 }
387 
388 /* *********************************************************** */
389 
390 void Mission::doBlock( missionNode *node, int mode )
391 {
392  trace( node, mode );
393  if (mode == SCRIPT_PARSE)
394  scope_stack.push_back( node );
395  if (mode == SCRIPT_RUN)
396  addContext( node );
397  vector< easyDomNode* >::const_iterator siter;
398  for (siter = node->subnodes.begin(); siter != node->subnodes.end() && !have_return( mode ); siter++) {
399  missionNode *snode = (missionNode*) *siter;
400  checkStatement( snode, mode );
401  }
402  if (mode == SCRIPT_RUN)
403  removeContext();
404  if (mode == SCRIPT_PARSE)
405  scope_stack.pop_back();
406 }
407 
408 /* *********************************************************** */
409 
410 varInst* Mission::doExec( missionNode *node, int mode )
411 {
412  trace( node, mode );
413  if (mode == SCRIPT_PARSE) {
414  string name = node->attr_value( "name" );
415  if ( name.empty() ) {
416  fatalError( node, mode, "you have to give name to exec" );
417  assert( 0 );
418  }
419  node->script.name = name;
420 
421  string use_modstr = node->attr_value( "module" );
422  missionNode *module = NULL;
423  missionNode *script = NULL;
424  if ( !use_modstr.empty() ) {
425  module = runtime.modules[use_modstr];
426  } else {
427  module = current_module;
428  }
429  if (module == NULL) {
430  fatalError( node, mode, "module "+use_modstr+" not found" );
431  assert( 0 );
432  }
433  script = module->script.scripts[name];
434  if (script == NULL) {
435  fatalError( node, mode, "script "+name+" not found in module "+use_modstr );
436  assert( 0 );
437  }
438  node->script.exec_node = script;
439  node->script.vartype = script->script.vartype;
440  node->script.module_node = module;
441  }
442  missionNode *arg_node = node->script.exec_node->script.argument_node;
443 
444  int nr_arguments;
445  if (arg_node == NULL)
446  nr_arguments = 0;
447  else
448  nr_arguments = arg_node->script.nr_arguments;
449  int nr_exec_args = node->subnodes.size();
450  if (nr_arguments != nr_exec_args) {
451  char buffer[200];
452  sprintf( buffer, "wrong nr of arguments in doExec=%d doScript=%d", nr_exec_args, nr_arguments );
453  fatalError( node, mode, buffer );
454  assert( 0 );
455  }
456  varInstMap *varmap = NULL;
457  if (nr_arguments > 0) {
458  varmap = new varInstMap;
459  for (int i = 0; i < nr_arguments; i++) {
460  missionNode *defnode = (missionNode*) arg_node->subnodes[i];
461  missionNode *callnode = (missionNode*) node->subnodes[i];
462 
463  varInst *vi = newVarInst( VI_LOCAL );
464  vi->type = defnode->script.vartype;
465  if (defnode->script.vartype == VAR_FLOAT) {
466  debug( 4, node, mode, "doExec checking floatExpr" );
467  double res = checkFloatExpr( callnode, mode );
468  vi->float_val = res;
469  } else if (defnode->script.vartype == VAR_INT) {
470  debug( 4, node, mode, "doExec checking intExpr" );
471  int res = checkIntExpr( callnode, mode );
472  vi->int_val = res;
473  } else if (defnode->script.vartype == VAR_BOOL) {
474  debug( 4, node, mode, "doExec checking boolExpr" );
475  bool ok = checkBoolExpr( callnode, mode );
476  vi->bool_val = ok;
477  } else if (defnode->script.vartype == VAR_OBJECT) {
478  debug( 3, node, mode, "doExec checking objectExpr" );
479  varInst *ovi = checkObjectExpr( callnode, mode );
480  vi->type = VAR_OBJECT;
481  if (mode == SCRIPT_RUN)
482  assignVariable( vi, ovi );
483  deleteVarInst( ovi );
484  } else {
485  fatalError( node, mode, "unsupported vartype in doExec" );
486  assert( 0 );
487  }
488  (*varmap)[defnode->script.name] = vi;
489  }
490  }
491  if (mode == SCRIPT_RUN) {
492  //SCRIPT_RUN
493 
494  debug( 4, node, mode, "executing "+node->script.name );
495 
496  missionNode *module = node->script.module_node;
497 
498  missionNode *old_module = runtime.cur_thread->module_stack.back();
499 
500  unsigned int classid = 0;
501  if (old_module == module)
502  classid = runtime.cur_thread->classid_stack.back();
503  runtime.cur_thread->module_stack.push_back( module );
504  runtime.cur_thread->classid_stack.push_back( classid );
505 
506  varInst *vi = doScript( node->script.exec_node, mode, varmap );
507 
508  runtime.cur_thread->module_stack.pop_back();
509  runtime.cur_thread->classid_stack.pop_back();
510  if (varmap) {
511  deleteVarMap( varmap );
512  delete varmap;
513  }
514  return vi;
515  }
516  //SCRIPT_PARSE
517 
518  varInst *vi = newVarInst( VI_TEMP );
519 
520  vi->type = node->script.exec_node->script.vartype;
521 
522  return vi;
523 }
524 
525 varInst* Mission::newVarInst( scope_type scopetype )
526 {
527  varInst *vi = new varInst( scopetype );
528  vi_counter++;
529 
530  return vi;
531 }
532 
533 void Mission::deleteVarInst( varInst *vi, bool del_local )
534 {
535  if (vi == NULL)
536  return;
537  if (vi->scopetype == VI_GLOBAL || vi->scopetype == VI_MODULE || vi->scopetype == VI_CLASSVAR) {
538  debug( 12, NULL, 0, "reqested to delete global/module vi\n" );
539  } else if (vi->scopetype == VI_ERROR) {
540  debug( 2, NULL, 0, "reqested to delete vi_error\n" );
541  } else if (del_local == false && vi->scopetype == VI_IN_OBJECT) {
542  //debug(2,NULL,0,"reqested to delete vi in object\n");
543  } else if (vi->scopetype == VI_CONST) {
544  debug( 12, NULL, 0, "reqested to delete const vi\n" );
545  } else if (del_local == false && vi->scopetype == VI_LOCAL) {
546  debug( 12, NULL, 0, "reqested to delete local vi\n" );
547  } else {
548  delete vi;
549  vi_counter--;
550  }
551 }
552 
553 void Mission::deleteVarMap( varInstMap *vmap )
554 {
555  vsUMap< string, varInst* >::const_iterator iter;
556  for (iter = vmap->begin(); iter != vmap->end(); iter++) {
557  varInst *vi = (*iter).second;
558  if (vi == NULL)
559  debug( 12, NULL, 0, "NULLVAR "+(*iter).first+"\n" );
560  else
561  deleteVarInst( vi, true );
562  }
563 }
564 
565 unsigned int Mission::createClassInstance( string modulename )
566 {
567  missionNode *module_node = runtime.modules[modulename];
568  if (module_node == NULL) {
569  fatalError( NULL, SCRIPT_RUN, "module "+modulename+" not found" );
570  assert( 0 );
571  }
572  module_node->script.classinst_counter++;
573 
574  char buf[200];
575  sprintf( buf, "class counter for module %s : %d\n", modulename.c_str(), module_node->script.classinst_counter );
576  debug( 1, NULL, 0, buf );
577 
578  varInstMap *cvmap = new varInstMap();
579 
580  module_node->script.classvars.push_back( cvmap );
581 
582  varInstMap *cvmap0 = module_node->script.classvars[0];
583 
584  vsUMap< string, varInst* >::const_iterator iter;
585  for (iter = cvmap0->begin(); iter != cvmap0->end(); iter++) {
586  varInst *vi0 = (*iter).second;
587  string vi0_name = (*iter).first;
588 
589  varInst *vi = newVarInst( VI_CLASSVAR );
590  vi->type = vi0->type;
591  assignVariable( vi, vi0 );
592 
593  (*cvmap)[vi0_name] = vi;
594  }
595  return module_node->script.classinst_counter;
596 }
597 
598 void Mission::destroyClassInstance( string modulename, unsigned int classid )
599 {
600  missionNode *module = runtime.modules[modulename];
601  if (module == NULL) {
602  fatalError( NULL, SCRIPT_RUN, "module "+modulename+" not found" );
603  assert( 0 );
604  }
605  if ( classid >= module->script.classvars.size() ) {
606  fatalError( module, SCRIPT_RUN, "illegal classvar nr." );
607  assert( 0 );
608  }
609  printf( "destroying class instance %s:%d\n", modulename.c_str(), classid );
610  varInstMap *cvmap = module->script.classvars[classid];
611 
612  deleteVarMap( cvmap );
613 
614  module->script.classvars[classid] = NULL;
615 }
616