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
script_expression.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 "cmd/unit_generic.h"
43 #include "mission.h"
44 #include "easydom.h"
45 
46 /* *********************************************************** */
47 
48 varInst* Mission::checkObjectExpr( missionNode *node, int mode )
49 {
50  varInst *res = NULL;
51  if (node->tag == DTAG_VAR_EXPR) {
52  res = doObjectVar( node, mode );
53  } else if (node->tag == DTAG_CALL) {
54  varInst *vi = doCall( node, mode );
55  if (vi->type == VAR_OBJECT) {
56  res = vi;
57  } else if (vi->type == VAR_ANY && mode == SCRIPT_PARSE) {
58  res = vi;
59  } else {
60  fatalError( node, mode, "expected a object call, got a different one" );
61  assert( 0 );
62  }
63  } else if (node->tag == DTAG_EXEC) {
64  varInst *vi = doExec( node, mode );
65  if (vi == NULL) {
66  fatalError( node, mode, "doExec returned NULL" );
67  assert( 0 );
68  } else if (node->script.vartype == VAR_OBJECT) {
69  res = vi;
70  } else {
71  fatalError( node, mode, "expected a object exec, got a different one" );
72  assert( 0 );
73  }
74  } else if (node->tag == DTAG_CONST) {
75  varInst *vi = doConst( node, mode );
76  if (vi->type == VAR_OBJECT && vi->objectname == "string") {
77  res = vi;
78  } else {
79  fatalError( node, mode, "expected a string const, got a different one: "+vi->objectname );
80  assert( 0 );
81  }
82  } else {
83  fatalError( node, mode, "no such object expression tag" );
84  assert( 0 );
85  }
86  return res;
87 }
88 
89 /* *********************************************************** */
90 
91 varInst* Mission::doMath( missionNode *node, int mode )
92 {
93  string mathname = node->attr_value( "math" );
94 
95  int len = node->subnodes.size();
96  if (len < 2) {
97  fatalError( node, mode, "math needs at least 2 arguments" );
98  assert( 0 );
99  }
100  varInst *res_vi = newVarInst( VI_TEMP );
101 
102  varInst *res1_vi = checkExpression( (missionNode*) node->subnodes[0], mode );
103  if (res1_vi->type != VAR_INT && res1_vi->type != VAR_FLOAT && res1_vi->type != VAR_ANY) {
104  printf( "res1_vi=%d\n", res1_vi->type );
105  fatalError( node, mode, "only int or float expr allowed for math" );
106  assert( 0 );
107  }
108  res_vi->type = res1_vi->type;
109  assignVariable( res_vi, res1_vi );
110  if (res_vi->type == VAR_ANY)
111  res_vi->type = VAR_FLOAT;
112  deleteVarInst( res1_vi );
113  for (int i = 1; i < len; i++) {
114  varInst *res2_vi = checkExpression( (missionNode*) node->subnodes[i], mode );
115  var_type res2_type = res2_vi->type;
116  if (res2_type == VAR_INT && res_vi->type == VAR_FLOAT) {
117  res2_type = VAR_FLOAT;
118  if (mode == SCRIPT_RUN) {
119  float res2 = (float) res2_vi->int_val;
120  float res = floatMath( mathname, res_vi->float_val, res2 );
121  res_vi->float_val = res;
122  }
123  } else if (res2_type == VAR_FLOAT && res_vi->type == VAR_INT) {
124  res_vi->type = VAR_FLOAT;
125  if (mode == SCRIPT_RUN) {
126  res_vi->float_val = (float) res_vi->int_val;
127  float res2 = res2_vi->float_val;
128  float res = floatMath( mathname, res_vi->float_val, res2 );
129  res_vi->float_val = res;
130  }
131  } else {
132  if (res_vi->type != res2_type) {
133  fatalError( node, mode, "can't do math on such types" );
134  assert( 0 );
135  }
136  if (mode == SCRIPT_RUN) {
137  if (res_vi->type == VAR_INT) {
138  int res = intMath( mathname, res_vi->int_val, res2_vi->int_val );
139  res_vi->int_val = res;
140  } else if (res_vi->type == VAR_FLOAT) {
141  float res = floatMath( mathname, res_vi->float_val, res2_vi->float_val );
142  res_vi->float_val = res;
143  } else if (res_vi->type != res2_type) {
144  fatalError( node, mode, "can't do math on such types" );
145  assert( 0 );
146  }
147  } //of SCRIPT_RUN
148  } //else
149  deleteVarInst( res2_vi );
150  } //for arguments
151 
152  return res_vi;
153 }
154 
155 int Mission::intMath( string mathname, int res1, int res2 )
156 {
157  int res = res1;
158  if (mathname == "+") {
159  res = res+res2;
160  } else if (mathname == "-") {
161  res = res-res2;
162  } else if (mathname == "*") {
163  res = res*res2;
164  } else if (mathname == "/") {
165  res = res/res2;
166  } else {
167  fatalError( NULL, SCRIPT_RUN, "no such intmath expression" );
168  assert( 0 );
169  }
170  return res;
171 }
172 
173 /* *********************************************************** */
174 double Mission::floatMath( string mathname, double res1, double res2 )
175 {
176  double res = res1;
177  if (mathname == "+") {
178  res = res+res2;
179  } else if (mathname == "-") {
180  res = res-res2;
181  } else if (mathname == "*") {
182  res = res*res2;
183  } else if (mathname == "/") {
184  res = res/res2;
185  } else {
186  fatalError( NULL, SCRIPT_RUN, "no such floatmath expression" );
187  assert( 0 );
188  }
189  return res;
190 }
191 
192 /* *********************************************************** */
193 
194 double Mission::doFMath( missionNode *node, int mode )
195 {
196  varInst *math_vi = doMath( node, mode );
197  if (math_vi->type != VAR_FLOAT) {
198  fatalError( node, mode, "fmath expected float" );
199  assert( 0 );
200  }
201  double ret = math_vi->float_val;
202  deleteVarInst( math_vi );
203 
204  return ret;
205 
206  string mathname = node->attr_value( "math" );
207 
208  int len = node->subnodes.size();
209  if (len < 2) {
210  fatalError( node, mode, "fmath needs at least 2 arguments" );
211  assert( 0 );
212  }
213  double res = checkFloatExpr( (missionNode*) node->subnodes[0], mode );
214 
215  char buffer[200];
216  sprintf( buffer, "fmath: 1st expr returns %f", res );
217  debug( 4, node, mode, buffer );
218  for (int i = 1; i < len; i++) {
219  double res2 = checkFloatExpr( (missionNode*) node->subnodes[i], mode );
220  if (mode == SCRIPT_RUN) {
221  if (mathname == "+") {
222  res = res+res2;
223  } else if (mathname == "-") {
224  res = res-res2;
225  } else if (mathname == "*") {
226  res = res*res2;
227  } else if (mathname == "/") {
228  res = res/res2;
229  } else {
230  fatalError( node, mode, "no such fmath expression" );
231  assert( 0 );
232  }
233  }
234  }
235  if (mode == SCRIPT_RUN)
236  return res;
237  return 0.0;
238 }
239 
240 /* *********************************************************** */
241 
242 int Mission::doIMath( missionNode *node, int mode )
243 {
244  varInst *math_vi = doMath( node, mode );
245  if (math_vi->type != VAR_INT) {
246  fatalError( node, mode, "fmath expected int" );
247  assert( 0 );
248  }
249  int res = math_vi->int_val;
250  deleteVarInst( math_vi );
251 
252  return res;
253 
254 #if 0
255  //if(mode==SCRIPT_PARSE){
256  string mathname = node->attr_value( "math" );
257 
258  int len = node->subnodes.size();
259  if (len < 2) {
260  fatalError( node, mode, "imath needs at least 2 arguments" );
261  assert( 0 );
262  }
263  int res = checkIntExpr( (missionNode*) node->subnodes[0], mode );
264 
265  char buffer[200];
266  sprintf( buffer, "imath: 1st expr returns %d", res );
267  debug( 4, node, mode, buffer );
268  for (int i = 1; i < len; i++) {
269  int res2 = checkIntExpr( (missionNode*) node->subnodes[i], mode );
270  if (mode == SCRIPT_RUN) {
271  if (mathname == "+") {
272  res = res+res2;
273  } else if (mathname == "-") {
274  res = res-res2;
275  } else if (mathname == "*") {
276  res = res*res2;
277  } else if (mathname == "/") {
278  res = res/res2;
279  } else {
280  fatalError( node, mode, "no such imath expression" );
281  assert( 0 );
282  }
283  }
284  }
285  if (mode == SCRIPT_RUN)
286  return res;
287  return 0;
288 #endif
289 }
290 
291 /* *********************************************************** */
292 
293 double Mission::checkFloatExpr( missionNode *node, int mode )
294 {
295  double res = 0.0;
296  if (node->tag == DTAG_VAR_EXPR) {
297  res = doFloatVar( node, mode );
298  } else if (node->tag == DTAG_FMATH) {
299  res = doFMath( node, mode );
300  } else if (node->tag == DTAG_CONST) {
301  varInst *vi = doConst( node, mode );
302  if (vi && vi->type == VAR_FLOAT) {
303  res = vi->float_val;
304  } else {
305  fatalError( node, mode, "expected a float const, got a different one" );
306  assert( 0 );
307  }
308  deleteVarInst( vi );
309  } else if (node->tag == DTAG_CALL) {
310  varInst *vi = doCall( node, mode );
311  if (vi->type == VAR_FLOAT) {
312  res = vi->float_val;
313  } else if (vi->type == VAR_ANY && mode == SCRIPT_PARSE) {
314  res = vi->float_val;
315  } else {
316  fatalError( node, mode, "expected a float call, got a different one" );
317  assert( 0 );
318  }
319  deleteVarInst( vi );
320  } else if (node->tag == DTAG_EXEC) {
321  varInst *vi = doExec( node, mode );
322  if (vi == NULL) {
323  fatalError( node, mode, "doExec returned NULL" );
324  assert( 0 );
325  } else if (node->script.vartype == VAR_FLOAT) {
326  res = vi->float_val;
327  } else {
328  fatalError( node, mode, "expected a float exec, got a different one" );
329  assert( 0 );
330  }
331  deleteVarInst( vi );
332  } else {
333  fatalError( node, mode, "no such float expression tag" );
334  assert( 0 );
335  }
336  return res;
337 }
338 /* *********************************************************** */
339 
340 int Mission::checkIntExpr( missionNode *node, int mode )
341 {
342  int res = 0;
343  if (node->tag == DTAG_VAR_EXPR) {
344  res = doIntVar( node, mode );
345  } else if (node->tag == DTAG_FMATH) {
346  res = doIMath( node, mode );
347  } else if (node->tag == DTAG_CONST) {
348  varInst *vi = doConst( node, mode );
349  if (vi && vi->type == VAR_INT) {
350  res = vi->int_val;
351  } else {
352  fatalError( node, mode, "expected a float const, got a different one" );
353  assert( 0 );
354  }
355  deleteVarInst( vi );
356  } else if (node->tag == DTAG_CALL) {
357  varInst *vi = doCall( node, mode );
358  if (vi->type == VAR_INT) {
359  res = vi->int_val;
360  } else if (vi->type == VAR_ANY && mode == SCRIPT_PARSE) {
361  res = vi->int_val;
362  } else {
363  fatalError( node, mode, "expected a int call, got a different one" );
364  assert( 0 );
365  }
366  deleteVarInst( vi );
367  } else if (node->tag == DTAG_EXEC) {
368  varInst *vi = doExec( node, mode );
369  if (vi == NULL) {
370  fatalError( node, mode, "doExec returned NULL" );
371  assert( 0 );
372  } else if (node->script.vartype == VAR_INT) {
373  res = vi->int_val;
374  } else {
375  fatalError( node, mode, "expected a int exec, got a different one" );
376  assert( 0 );
377  }
378  deleteVarInst( vi );
379  } else {
380  fatalError( node, mode, "no such int expression tag" );
381  assert( 0 );
382  }
383  return res;
384 }
385 
386 /* *********************************************************** */
387 
388 bool Mission::checkBoolExpr( missionNode *node, int mode )
389 {
390  bool ok = false;
391  //no difference between parse/run
392  if (node->tag == DTAG_AND_EXPR) {
393  ok = doAndOr( node, mode );
394  } else if (node->tag == DTAG_OR_EXPR) {
395  ok = doAndOr( node, mode );
396  } else if (node->tag == DTAG_NOT_EXPR) {
397  ok = doNot( node, mode );
398  } else if (node->tag == DTAG_TEST_EXPR) {
399  ok = doTest( node, mode );
400  } else if (node->tag == DTAG_VAR_EXPR) {
401  ok = doBooleanVar( node, mode );
402  } else if (node->tag == DTAG_CONST) {
403  varInst *vi = doConst( node, mode );
404  if (vi->type == VAR_BOOL) {
405  ok = vi->bool_val;
406  } else {
407  fatalError( node, mode, "expected a bool const, got a different one" );
408  assert( 0 );
409  }
410  deleteVarInst( vi );
411  } else if (node->tag == DTAG_CALL) {
412  varInst *vi = doCall( node, mode );
413  if (vi->type == VAR_BOOL) {
414  ok = vi->bool_val;
415  } else if (vi->type == VAR_ANY && mode == SCRIPT_PARSE) {
416  ok = vi->bool_val;
417  } else {
418  fatalError( node, mode, "expected a bool call, got a different one" );
419  assert( 0 );
420  }
421  deleteVarInst( vi );
422  } else if (node->tag == DTAG_EXEC) {
423  varInst *vi = doExec( node, mode );
424  if (vi == NULL) {
425  fatalError( node, mode, "doExec returned NULL" );
426  assert( 0 );
427  //parsing?
428  } else if (node->script.vartype == VAR_BOOL) {
429  ok = vi->bool_val;
430  } else {
431  fatalError( node, mode, "expected a bool exec, got a different one" );
432  assert( 0 );
433  }
434  deleteVarInst( vi );
435  } else {
436  fatalError( node, mode, "no such boolean expression tag" );
437  assert( 0 );
438  }
439  return ok;
440 }
441 
442 /* *********************************************************** */
443 
444 bool Mission::doAndOr( missionNode *node, int mode )
445 {
446  bool ok; //FIXME !! Not all branches result in ok being initialized
447  ok = true; //this line added temporarily by chuck_starchaser
448  //no difference between parse/run
449  if (node->tag == DTAG_AND_EXPR)
450  ok = true;
451  else if (node->tag == DTAG_OR_EXPR)
452  ok = false;
453  vector< easyDomNode* >::const_iterator siter;
454 
455  int i = 0;
456  for (siter = node->subnodes.begin(); siter != node->subnodes.end(); siter++, i++) {
457  missionNode *snode = (missionNode*) *siter;
458  bool res = checkBoolExpr( snode, mode );
459  if (node->tag == DTAG_AND_EXPR)
460  ok = ok && res;
461  else if (node->tag == DTAG_OR_EXPR)
462  ok = ok || res;
463  }
464  if (mode == SCRIPT_PARSE)
465  if (i < 2)
466  warning( "less than two arguments for and/or" );
467  return ok; //FIXME ok not initialized by all paths --chuck_starchaser
468 }
469 
470 /* *********************************************************** */
471 
472 bool Mission::doNot( missionNode *node, int mode )
473 {
474  bool ok;
475 
476  //no difference between parse/run
477 
478  missionNode *snode = (missionNode*) node->subnodes[0];
479  if (snode) {
480  ok = checkBoolExpr( snode, mode );
481 
482  return !ok;
483  } else {
484  fatalError( node, mode, "no subnode in not" );
485  assert( 0 );
486  return false; //we'll never get here
487  }
488 }
489 
490 /* *********************************************************** */
491 
492 bool Mission::doTest( missionNode *node, int mode )
493 {
494  if (mode == SCRIPT_PARSE) {
495  string teststr = node->attr_value( "test" );
496  if ( teststr.empty() ) {
497  fatalError( node, mode, "you have to give test an argument what to test" );
498  assert( 0 );
499  }
500  if (teststr == "gt") {
501  node->script.tester = TEST_GT;
502  } else if (teststr == "lt") {
503  node->script.tester = TEST_LT;
504  } else if (teststr == "eq") {
505  node->script.tester = TEST_EQ;
506  } else if (teststr == "ne") {
507  node->script.tester = TEST_NE;
508  } else if (teststr == "ge") {
509  node->script.tester = TEST_GE;
510  } else if (teststr == "le") {
511  node->script.tester = TEST_LE;
512  }
513 #if 0
514  else if (teststr == "between") {
515  node->script.tester = TEST_BETWEEN;
516  }
517 #endif
518 
519  else {
520  fatalError( node, mode, "unknown test argument for test" );
521  assert( 0 );
522  }
523 
524  vector< easyDomNode* >::const_iterator siter;
525 #if 0
526  int i = 0;
527  for (siter = node->subnodes.begin(); siter != node->subnodes.end() && i < 2; siter++) {
528  missionNode *snode = (missionNode*) *siter;
529  (node->script.test_arg)[i] = snode;
530  }
531  if (i < 2) {
532  fatalError( node, mode, "a test-expr needs exact two subnodes" );
533  assert( 0 );
534  }
535 #endif
536 
537  int len = node->subnodes.size();
538  if (len != 2) {
539  fatalError( node, mode, "a test-expr needs exact two subnodes" );
540  assert( 0 );
541  }
542  node->script.test_arg[0] = (missionNode*) node->subnodes[0];
543  node->script.test_arg[1] = (missionNode*) node->subnodes[1];
544  } //end of parse
545 
546  varInst *arg1_vi = checkExpression( node->script.test_arg[0], mode );
547  varInst *arg2_vi = checkExpression( node->script.test_arg[1], mode );
548  bool res = false;
549  if (arg1_vi->type != arg2_vi->type) {
550  fatalError( node, mode, "test is getting not the same types" );
551  assert( 0 );
552  }
553  if (mode == SCRIPT_RUN) {
554  if (arg1_vi->type == VAR_FLOAT) {
555  double arg1 = arg1_vi->float_val;
556  double arg2 = arg2_vi->float_val;
557  switch (node->script.tester)
558  {
559  case TEST_GT:
560  res = (arg1 > arg2);
561  break;
562  case TEST_LT:
563  res = (arg1 < arg2);
564  break;
565  case TEST_EQ:
566  res = (arg1 == arg2);
567  break;
568  case TEST_NE:
569  res = (arg1 != arg2);
570  break;
571  case TEST_GE:
572  res = (arg1 >= arg2);
573  break;
574  case TEST_LE:
575  res = (arg1 <= arg2);
576  break;
577  default:
578  fatalError( node, mode, "no valid tester" );
579  assert( 0 );
580  }
581  } else if (arg1_vi->type == VAR_INT) {
582  int arg1 = arg1_vi->int_val;
583  int arg2 = arg2_vi->int_val;
584  switch (node->script.tester)
585  {
586  case TEST_GT:
587  res = (arg1 > arg2);
588  break;
589  case TEST_LT:
590  res = (arg1 < arg2);
591  break;
592  case TEST_EQ:
593  res = (arg1 == arg2);
594  break;
595  case TEST_NE:
596  res = (arg1 != arg2);
597  break;
598  case TEST_GE:
599  res = (arg1 >= arg2);
600  break;
601  case TEST_LE:
602  res = (arg1 <= arg2);
603  break;
604  default:
605  fatalError( node, mode, "no valid tester" );
606  assert( 0 );
607  }
608  } else {
609  fatalError( node, mode, "no such type allowed for test" );
610  assert( 0 );
611  }
612  } //SCRIPT_RUN
613 
614  deleteVarInst( arg1_vi );
615  deleteVarInst( arg2_vi );
616 
617  return res;
618 }
619 
620 /* *********************************************************** */
621 
622 varInst* Mission::checkExpression( missionNode *node, int mode )
623 {
624  varInst *ret = NULL;
625  debug( 3, node, mode, "checking expression" );
626  switch (node->tag)
627  {
628  case DTAG_AND_EXPR:
629  case DTAG_OR_EXPR:
630  case DTAG_NOT_EXPR:
631  case DTAG_TEST_EXPR:
632  {
633  bool res = checkBoolExpr( node, mode );
634  ret = newVarInst( VI_TEMP );
635  ret->type = VAR_BOOL;
636  ret->bool_val = res;
637  break;
638  }
639  case DTAG_CONST:
640  ret = doConst( node, mode );
641  break;
642  case DTAG_VAR_EXPR:
643  ret = doVariable( node, mode );
644  break;
645  case DTAG_FMATH:
646  ret = doMath( node, mode );
647  break;
648  case DTAG_CALL:
649  ret = doCall( node, mode );
650  break;
651  case DTAG_EXEC:
652  ret = doExec( node, mode );
653  break;
654  default:
655  fatalError( node, mode, "no such expression" );
656  assert( 0 );
657  break;
658  }
659  return ret;
660 }
661