1 /*
2 ** c_expr.cpp
3 ** Console commands dealing with mathematical expressions
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2006 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 **    notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 **    notice, this list of conditions and the following disclaimer in the
17 **    documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 **    derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34 
35 // HEADER FILES ------------------------------------------------------------
36 
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <math.h>
40 #include <string.h>
41 
42 #include "c_dispatch.h"
43 #include "c_cvars.h"
44 
45 // MACROS ------------------------------------------------------------------
46 
47 // TYPES -------------------------------------------------------------------
48 
49 enum EProductionType
50 {
51 	PROD_String, PROD_Double
52 };
53 
54 struct FProduction
55 {
56 	EProductionType Type;
57 };
58 
59 struct FStringProd : public FProduction
60 {
61 	char Value[1];
62 };
63 
64 struct FDoubleProd : public FProduction
65 {
66 	double Value;
67 };
68 
69 struct FProducer
70 {
71 	char Token[4];
72 	FProduction *(*DoubleProducer) (FDoubleProd *prod1, FDoubleProd *prod2);
73 	FProduction *(*StringProducer) (FStringProd *prod1, FStringProd *prod2);
74 };
75 
76 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
77 
78 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
79 
80 bool IsFloat (const char *str);
81 
82 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
83 
84 static FProduction *ParseExpression (FCommandLine &argv, int &parsept);
85 static const char *IsNum (const char *str);
86 static FStringProd *NewStringProd (const char *str);
87 static FStringProd *NewStringProd (size_t len);
88 static FDoubleProd *NewDoubleProd (double val);
89 static FStringProd *DoubleToString (FProduction *prod);
90 static FDoubleProd *StringToDouble (FProduction *prod);
91 void MaybeStringCoerce (FProduction *&prod1, FProduction *&prod2);
92 void MustStringCoerce (FProduction *&prod1, FProduction *&prod2);
93 void DoubleCoerce (FProduction *&prod1, FProduction *&prod2);
94 
95 FProduction *ProdAddDbl  (FDoubleProd *prod1, FDoubleProd *prod2);
96 FProduction *ProdAddStr  (FStringProd *prod1, FStringProd *prod2);
97 FProduction *ProdSubDbl  (FDoubleProd *prod1, FDoubleProd *prod2);
98 FProduction *ProdMulDbl  (FDoubleProd *prod1, FDoubleProd *prod2);
99 FProduction *ProdDivDbl  (FDoubleProd *prod1, FDoubleProd *prod2);
100 FProduction *ProdModDbl  (FDoubleProd *prod1, FDoubleProd *prod2);
101 FProduction *ProdPowDbl  (FDoubleProd *prod1, FDoubleProd *prod2);
102 FProduction *ProdLTDbl   (FDoubleProd *prod1, FDoubleProd *prod2);
103 FProduction *ProdLTEDbl  (FDoubleProd *prod1, FDoubleProd *prod2);
104 FProduction *ProdGTDbl   (FDoubleProd *prod1, FDoubleProd *prod2);
105 FProduction *ProdGTEDbl  (FDoubleProd *prod1, FDoubleProd *prod2);
106 FProduction *ProdEqDbl   (FDoubleProd *prod1, FDoubleProd *prod2);
107 FProduction *ProdNeqDbl  (FDoubleProd *prod1, FDoubleProd *prod2);
108 FProduction *ProdXorDbl  (FDoubleProd *prod1, FDoubleProd *prod2);
109 FProduction *ProdAndDbl  (FDoubleProd *prod1, FDoubleProd *prod2);
110 FProduction *ProdOrDbl   (FDoubleProd *prod1, FDoubleProd *prod2);
111 FProduction *ProdLAndDbl (FDoubleProd *prod1, FDoubleProd *prod2);
112 FProduction *ProdLOrDbl  (FDoubleProd *prod1, FDoubleProd *prod2);
113 FProduction *ProdLTStr   (FStringProd *prod1, FStringProd *prod2);
114 FProduction *ProdLTEStr  (FStringProd *prod1, FStringProd *prod2);
115 FProduction *ProdGTStr   (FStringProd *prod1, FStringProd *prod2);
116 FProduction *ProdGTEStr  (FStringProd *prod1, FStringProd *prod2);
117 FProduction *ProdEqStr   (FStringProd *prod1, FStringProd *prod2);
118 FProduction *ProdNeqStr  (FStringProd *prod1, FStringProd *prod2);
119 
120 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
121 
122 // PUBLIC DATA DEFINITIONS -------------------------------------------------
123 
124 // PRIVATE DATA DEFINITIONS ------------------------------------------------
125 
126 static FProducer Producers[] =
127 {
128 	{ "+",   ProdAddDbl, ProdAddStr },
129 	{ "-",   ProdSubDbl, NULL },
130 	{ "*",   ProdMulDbl, NULL },
131 	{ "/",   ProdDivDbl, NULL },
132 	{ "%",   ProdModDbl, NULL },
133 	{ "^",   ProdPowDbl, NULL },
134 	{ "<",   ProdLTDbl,  ProdLTStr },
135 	{ "<=",  ProdLTEDbl, ProdLTEStr },
136 	{ ">",   ProdGTDbl,  ProdGTStr },
137 	{ ">=",  ProdGTEDbl, ProdGTEStr },
138 	{ "=",   ProdEqDbl,  ProdEqStr },
139 	{ "==",  ProdEqDbl,  ProdEqStr },
140 	{ "!=",  ProdNeqDbl, ProdNeqStr },
141 	{ "<>",  ProdNeqDbl, ProdNeqStr },
142 	{ "xor", ProdXorDbl, NULL },
143 	{ "&",   ProdAndDbl, NULL },
144 	{ "|",   ProdOrDbl,  NULL },
145 	{ "&&",  ProdLAndDbl, NULL },
146 	{ "||",  ProdLOrDbl, NULL }
147 };
148 
149 // CODE --------------------------------------------------------------------
150 
151 //==========================================================================
152 //
153 // ParseExpression
154 //
155 // Builds a production from an expression. The supported syntax is LISP-like
156 // but without parentheses.
157 //
158 //==========================================================================
159 
ParseExpression(FCommandLine & argv,int & parsept)160 static FProduction *ParseExpression (FCommandLine &argv, int &parsept)
161 {
162 	if (parsept >= argv.argc())
163 		return NULL;
164 
165 	const char *token = argv[parsept++];
166 	FProduction *prod1 = NULL, *prod2 = NULL, *prod3 = NULL;
167 
168 	if (IsFloat (token))
169 	{
170 		return NewDoubleProd (atof(token));
171 	}
172 	else if (stricmp (token, "true") == 0)
173 	{
174 		return NewDoubleProd (1.0);
175 	}
176 	else if (stricmp (token, "false") == 0)
177 	{
178 		return NewDoubleProd (0.0);
179 	}
180 	else
181 	{
182 		for (size_t i = 0; i < countof(Producers); ++i)
183 		{
184 			if (strcmp (Producers[i].Token, token) == 0)
185 			{
186 				prod1 = ParseExpression (argv, parsept);
187 				prod2 = ParseExpression (argv, parsept);
188 				if (prod1 == NULL || prod2 == NULL)
189 				{
190 					goto missing;
191 				}
192 				if (Producers[i].StringProducer == NULL)
193 				{
194 					DoubleCoerce (prod1, prod2);
195 				}
196 				else if (Producers[i].DoubleProducer == NULL)
197 				{
198 					MustStringCoerce (prod1, prod2);
199 				}
200 				else
201 				{
202 					MaybeStringCoerce (prod1, prod2);
203 				}
204 				if (prod1->Type == PROD_String)
205 				{
206 					prod3 = Producers[i].StringProducer ((FStringProd *)prod1, (FStringProd *)prod2);
207 				}
208 				else
209 				{
210 					prod3 = Producers[i].DoubleProducer ((FDoubleProd *)prod1, (FDoubleProd *)prod2);
211 				}
212 				goto done;
213 			}
214 		}
215 		if (strcmp ("!", token) == 0)
216 		{
217 			prod1 = ParseExpression (argv, parsept);
218 			if (prod1 == NULL)
219 			{
220 				goto missing;
221 			}
222 			if (prod1->Type == PROD_String)
223 			{
224 				prod1 = StringToDouble (prod1);
225 			}
226 			prod3 = NewDoubleProd (!static_cast<FDoubleProd *>(prod1)->Value);
227 			goto done;
228 		}
229 		return NewStringProd (token);
230 	}
231 
232 missing:
233 	Printf ("Missing argument to %s\n", token);
234 
235 done:
236 	if (prod2 != NULL) M_Free (prod2);
237 	if (prod1 != NULL) M_Free (prod1);
238 	return prod3;
239 }
240 
241 //==========================================================================
242 //
243 // IsFloat
244 //
245 //==========================================================================
246 
IsFloat(const char * str)247 bool IsFloat (const char *str)
248 {
249 	const char *pt;
250 
251 	if (*str == '+' || *str == '-')
252 		str++;
253 
254 	if (*str == '.')
255 	{
256 		pt = str;
257 	}
258 	else
259 	{
260 		pt = IsNum (str);
261 		if (pt == NULL)
262 			return false;
263 	}
264 	if (*pt == '.')
265 	{
266 		pt = IsNum (pt+1);
267 		if (pt == NULL)
268 			return false;
269 	}
270 	if (*pt == 'e' || *pt == 'E')
271 	{
272 		pt++;
273 		if (*pt == '+' || *pt == '-')
274 			pt++;
275 		pt = IsNum (pt);
276 	}
277 	return pt != NULL && *pt == 0;
278 }
279 
280 //==========================================================================
281 //
282 // IsNum
283 //
284 //==========================================================================
285 
IsNum(const char * str)286 static const char *IsNum (const char *str)
287 {
288 	const char *start = str;
289 
290 	while (*str)
291 	{
292 		if (*str >= '0' && *str <= '9')
293 			str++;
294 		else
295 			break;
296 	}
297 
298 	return (str > start) ? str : NULL;
299 }
300 
301 //==========================================================================
302 //
303 // NewStringProd (from a string)
304 //
305 //==========================================================================
306 
NewStringProd(const char * str)307 static FStringProd *NewStringProd (const char *str)
308 {
309 	FStringProd *prod = (FStringProd *)M_Malloc (sizeof(FStringProd)+strlen(str));
310 	prod->Type = PROD_String;
311 	strcpy (prod->Value, str);
312 	return prod;
313 }
314 
315 //==========================================================================
316 //
317 // NewStringProd (from a length)
318 //
319 //==========================================================================
320 
NewStringProd(size_t len)321 static FStringProd *NewStringProd (size_t len)
322 {
323 	FStringProd *prod = (FStringProd *)M_Malloc (sizeof(FStringProd)+len);
324 	prod->Type = PROD_String;
325 	prod->Value[0] = 0;
326 	return prod;
327 }
328 
329 //==========================================================================
330 //
331 // NewDoubleProd
332 //
333 //==========================================================================
334 
NewDoubleProd(double val)335 static FDoubleProd *NewDoubleProd (double val)
336 {
337 	FDoubleProd *prod = (FDoubleProd *)M_Malloc (sizeof(FDoubleProd));
338 	prod->Type = PROD_Double;
339 	prod->Value = val;
340 	return prod;
341 }
342 
343 //==========================================================================
344 //
345 // DoubleToString
346 //
347 //==========================================================================
348 
DoubleToString(FProduction * prod)349 static FStringProd *DoubleToString (FProduction *prod)
350 {
351 	char buf[128];
352 	FStringProd *newprod;
353 
354 	mysnprintf (buf, countof(buf), "%g", static_cast<FDoubleProd *>(prod)->Value);
355 	newprod = NewStringProd (buf);
356 	M_Free (prod);
357 	return newprod;
358 }
359 
360 //==========================================================================
361 //
362 // StringToDouble
363 //
364 //==========================================================================
365 
StringToDouble(FProduction * prod)366 static FDoubleProd *StringToDouble (FProduction *prod)
367 {
368 	FDoubleProd *newprod;
369 
370 	newprod = NewDoubleProd (atof (static_cast<FStringProd *>(prod)->Value));
371 	M_Free (prod);
372 	return newprod;
373 }
374 
375 //==========================================================================
376 //
377 // MaybeStringCoerce
378 //
379 // If one of the parameters is a string, convert the other to a string.
380 //
381 //==========================================================================
382 
MaybeStringCoerce(FProduction * & prod1,FProduction * & prod2)383 void MaybeStringCoerce (FProduction *&prod1, FProduction *&prod2)
384 {
385 	if (prod1->Type == PROD_String)
386 	{
387 		if (prod2->Type == PROD_Double)
388 		{
389 			prod2 = DoubleToString (prod2);
390 		}
391 	}
392 	else if (prod2->Type == PROD_String)
393 	{
394 		prod1 = DoubleToString (prod1);
395 	}
396 }
397 
398 //==========================================================================
399 //
400 // MustStringCoerce
401 //
402 // Ensures that both parameters are strings
403 //
404 //==========================================================================
405 
MustStringCoerce(FProduction * & prod1,FProduction * & prod2)406 void MustStringCoerce (FProduction *&prod1, FProduction *&prod2)
407 {
408 	if (prod1->Type == PROD_Double)
409 	{
410 		prod1 = DoubleToString (prod1);
411 	}
412 	if (prod2->Type == PROD_Double)
413 	{
414 		prod2 = DoubleToString (prod2);
415 	}
416 }
417 
418 //==========================================================================
419 //
420 // DoubleCoerce
421 //
422 // Ensures that both parameters are doubles
423 //
424 //==========================================================================
425 
DoubleCoerce(FProduction * & prod1,FProduction * & prod2)426 void DoubleCoerce (FProduction *&prod1, FProduction *&prod2)
427 {
428 	if (prod1->Type == PROD_String)
429 	{
430 		prod1 = StringToDouble (prod1);
431 	}
432 	if (prod2->Type == PROD_String)
433 	{
434 		prod2 = StringToDouble (prod2);
435 	}
436 }
437 
438 //==========================================================================
439 //
440 // ProdAddDbl
441 //
442 //==========================================================================
443 
ProdAddDbl(FDoubleProd * prod1,FDoubleProd * prod2)444 FProduction *ProdAddDbl (FDoubleProd *prod1, FDoubleProd *prod2)
445 {
446 	return NewDoubleProd (prod1->Value + prod2->Value);
447 }
448 
449 //==========================================================================
450 //
451 // ProdAddStr
452 //
453 //==========================================================================
454 
ProdAddStr(FStringProd * prod1,FStringProd * prod2)455 FProduction *ProdAddStr (FStringProd *prod1, FStringProd *prod2)
456 {
457 	size_t len = strlen (prod1->Value) + strlen (prod2->Value) + 1;
458 	FStringProd *prod = NewStringProd (len);
459 	strcpy (prod->Value, prod1->Value);
460 	strcat (prod->Value, prod2->Value);
461 	return prod;
462 }
463 
464 //==========================================================================
465 //
466 // ProdSubDbl
467 //
468 //==========================================================================
469 
ProdSubDbl(FDoubleProd * prod1,FDoubleProd * prod2)470 FProduction *ProdSubDbl (FDoubleProd *prod1, FDoubleProd *prod2)
471 {
472 	return NewDoubleProd (prod1->Value - prod2->Value);
473 }
474 
475 //==========================================================================
476 //
477 // ProdMulDbl
478 //
479 //==========================================================================
480 
ProdMulDbl(FDoubleProd * prod1,FDoubleProd * prod2)481 FProduction *ProdMulDbl (FDoubleProd *prod1, FDoubleProd *prod2)
482 {
483 	return NewDoubleProd (prod1->Value * prod2->Value);
484 }
485 
486 //==========================================================================
487 //
488 // ProdDivDbl
489 //
490 //==========================================================================
491 
ProdDivDbl(FDoubleProd * prod1,FDoubleProd * prod2)492 FProduction *ProdDivDbl (FDoubleProd *prod1, FDoubleProd *prod2)
493 {
494 	return NewDoubleProd (prod1->Value / prod2->Value);
495 }
496 
497 //==========================================================================
498 //
499 // ProdModDbl
500 //
501 //==========================================================================
502 
ProdModDbl(FDoubleProd * prod1,FDoubleProd * prod2)503 FProduction *ProdModDbl (FDoubleProd *prod1, FDoubleProd *prod2)
504 {
505 	return NewDoubleProd (fmod (prod1->Value, prod2->Value));
506 }
507 
508 //==========================================================================
509 //
510 // ProdPowDbl
511 //
512 //==========================================================================
513 
ProdPowDbl(FDoubleProd * prod1,FDoubleProd * prod2)514 FProduction *ProdPowDbl (FDoubleProd *prod1, FDoubleProd *prod2)
515 {
516 	return NewDoubleProd (pow (prod1->Value, prod2->Value));
517 }
518 
519 //==========================================================================
520 //
521 // ProdLTDbl
522 //
523 //==========================================================================
524 
ProdLTDbl(FDoubleProd * prod1,FDoubleProd * prod2)525 FProduction *ProdLTDbl (FDoubleProd *prod1, FDoubleProd *prod2)
526 {
527 	return NewDoubleProd (prod1->Value < prod2->Value);
528 }
529 
530 //==========================================================================
531 //
532 // ProdLTEDbl
533 //
534 //==========================================================================
535 
ProdLTEDbl(FDoubleProd * prod1,FDoubleProd * prod2)536 FProduction *ProdLTEDbl (FDoubleProd *prod1, FDoubleProd *prod2)
537 {
538 	return NewDoubleProd (prod1->Value <= prod2->Value);
539 }
540 
541 //==========================================================================
542 //
543 // ProdGTDbl
544 //
545 //==========================================================================
546 
ProdGTDbl(FDoubleProd * prod1,FDoubleProd * prod2)547 FProduction *ProdGTDbl (FDoubleProd *prod1, FDoubleProd *prod2)
548 {
549 	return NewDoubleProd (prod1->Value > prod2->Value);
550 }
551 
552 //==========================================================================
553 //
554 // ProdGTEDbl
555 //
556 //==========================================================================
557 
ProdGTEDbl(FDoubleProd * prod1,FDoubleProd * prod2)558 FProduction *ProdGTEDbl (FDoubleProd *prod1, FDoubleProd *prod2)
559 {
560 	return NewDoubleProd (prod1->Value >= prod2->Value);
561 }
562 
563 //==========================================================================
564 //
565 // ProdEqDbl
566 //
567 //==========================================================================
568 
ProdEqDbl(FDoubleProd * prod1,FDoubleProd * prod2)569 FProduction *ProdEqDbl (FDoubleProd *prod1, FDoubleProd *prod2)
570 {
571 	return NewDoubleProd (prod1->Value == prod2->Value);
572 }
573 
574 //==========================================================================
575 //
576 // ProdNeqDbl
577 //
578 //==========================================================================
579 
ProdNeqDbl(FDoubleProd * prod1,FDoubleProd * prod2)580 FProduction *ProdNeqDbl (FDoubleProd *prod1, FDoubleProd *prod2)
581 {
582 	return NewDoubleProd (prod1->Value != prod2->Value);
583 }
584 
585 //==========================================================================
586 //
587 // ProdLTStr
588 //
589 //==========================================================================
590 
ProdLTStr(FStringProd * prod1,FStringProd * prod2)591 FProduction *ProdLTStr (FStringProd *prod1, FStringProd *prod2)
592 {
593 	return NewDoubleProd (stricmp (prod1->Value, prod2->Value) < 0);
594 }
595 
596 //==========================================================================
597 //
598 // ProdLTEStr
599 //
600 //==========================================================================
601 
ProdLTEStr(FStringProd * prod1,FStringProd * prod2)602 FProduction *ProdLTEStr (FStringProd *prod1, FStringProd *prod2)
603 {
604 	return NewDoubleProd (stricmp (prod1->Value, prod2->Value) <= 0);
605 }
606 
607 //==========================================================================
608 //
609 // ProdGTStr
610 //
611 //==========================================================================
612 
ProdGTStr(FStringProd * prod1,FStringProd * prod2)613 FProduction *ProdGTStr (FStringProd *prod1, FStringProd *prod2)
614 {
615 	return NewDoubleProd (stricmp (prod1->Value, prod2->Value) > 0);
616 }
617 
618 //==========================================================================
619 //
620 // ProdGTEStr
621 //
622 //==========================================================================
623 
ProdGTEStr(FStringProd * prod1,FStringProd * prod2)624 FProduction *ProdGTEStr (FStringProd *prod1, FStringProd *prod2)
625 {
626 	return NewDoubleProd (stricmp (prod1->Value, prod2->Value) >= 0);
627 }
628 
629 //==========================================================================
630 //
631 // ProdEqStr
632 //
633 //==========================================================================
634 
ProdEqStr(FStringProd * prod1,FStringProd * prod2)635 FProduction *ProdEqStr (FStringProd *prod1, FStringProd *prod2)
636 {
637 	return NewDoubleProd (stricmp (prod1->Value, prod2->Value) == 0);
638 }
639 
640 //==========================================================================
641 //
642 // ProdNeqStr
643 //
644 //==========================================================================
645 
ProdNeqStr(FStringProd * prod1,FStringProd * prod2)646 FProduction *ProdNeqStr (FStringProd *prod1, FStringProd *prod2)
647 {
648 	return NewDoubleProd (stricmp (prod1->Value, prod2->Value) != 0);
649 }
650 
651 //==========================================================================
652 //
653 // ProdXorDbl
654 //
655 //==========================================================================
656 
ProdXorDbl(FDoubleProd * prod1,FDoubleProd * prod2)657 FProduction *ProdXorDbl (FDoubleProd *prod1, FDoubleProd *prod2)
658 {
659 	return NewDoubleProd ((double)((SQWORD)prod1->Value ^ (SQWORD)prod2->Value));
660 }
661 
662 //==========================================================================
663 //
664 // ProdAndDbl
665 //
666 //==========================================================================
667 
ProdAndDbl(FDoubleProd * prod1,FDoubleProd * prod2)668 FProduction *ProdAndDbl (FDoubleProd *prod1, FDoubleProd *prod2)
669 {
670 	return NewDoubleProd ((double)((SQWORD)prod1->Value & (SQWORD)prod2->Value));
671 }
672 
673 //==========================================================================
674 //
675 // ProdOrDbl
676 //
677 //==========================================================================
678 
ProdOrDbl(FDoubleProd * prod1,FDoubleProd * prod2)679 FProduction *ProdOrDbl (FDoubleProd *prod1, FDoubleProd *prod2)
680 {
681 	return NewDoubleProd ((double)((SQWORD)prod1->Value | (SQWORD)prod2->Value));
682 }
683 
684 //==========================================================================
685 //
686 // ProdLAndDbl
687 //
688 //==========================================================================
689 
ProdLAndDbl(FDoubleProd * prod1,FDoubleProd * prod2)690 FProduction *ProdLAndDbl (FDoubleProd *prod1, FDoubleProd *prod2)
691 {
692 	return NewDoubleProd ((double)((SQWORD)prod1->Value && (SQWORD)prod2->Value));
693 }
694 
695 //==========================================================================
696 //
697 // ProdLOrDbl
698 //
699 //==========================================================================
700 
ProdLOrDbl(FDoubleProd * prod1,FDoubleProd * prod2)701 FProduction *ProdLOrDbl (FDoubleProd *prod1, FDoubleProd *prod2)
702 {
703 	return NewDoubleProd ((double)((SQWORD)prod1->Value || (SQWORD)prod2->Value));
704 }
705 
706 
707 //==========================================================================
708 //
709 //
710 //
711 //==========================================================================
712 
713 //==========================================================================
714 //
715 // CCMD test
716 //
717 // If <expr> is non-zero, execute <true cmd>.
718 // If <expr> is zero, execute [false cmd] if specified.
719 //
720 //==========================================================================
721 
CCMD(test)722 CCMD (test)
723 {
724 	int parsept = 1;
725 	FProduction *prod = ParseExpression (argv, parsept);
726 
727 	if (prod == NULL || parsept >= argv.argc())
728 	{
729 		Printf ("Usage: test <expr> <true cmd> [false cmd]\n");
730 	}
731 	else
732 	{
733 		if (prod->Type == PROD_String)
734 		{
735 			prod = StringToDouble (prod);
736 		}
737 
738 		if (static_cast<FDoubleProd *>(prod)->Value != 0.0)
739 		{
740 			AddCommandString (argv[parsept]);
741 		}
742 		else if (++parsept < argv.argc())
743 		{
744 			AddCommandString (argv[parsept]);
745 		}
746 	}
747 	if (prod != NULL)
748 	{
749 		M_Free (prod);
750 	}
751 }
752 
753 //==========================================================================
754 //
755 // CCMD eval
756 //
757 // Evaluates an expression and either prints it to the console or stores
758 // it in an existing cvar.
759 //
760 //==========================================================================
761 
CCMD(eval)762 CCMD (eval)
763 {
764 	if (argv.argc() >= 2)
765 	{
766 		int parsept = 1;
767 		FProduction *prod = ParseExpression (argv, parsept);
768 
769 		if (prod != NULL)
770 		{
771 			if (parsept < argv.argc())
772 			{
773 				FBaseCVar *var = FindCVar (argv[parsept], NULL);
774 				if (var == NULL)
775 				{
776 					Printf ("Unknown variable %s\n", argv[parsept]);
777 				}
778 				else
779 				{
780 					UCVarValue val;
781 
782 					if (prod->Type == PROD_Double)
783 					{
784 						val.Float = (float)static_cast<FDoubleProd *>(prod)->Value;
785 						var->SetGenericRep (val, CVAR_Float);
786 					}
787 					else
788 					{
789 						val.String = static_cast<FStringProd *>(prod)->Value;
790 						var->SetGenericRep (val, CVAR_String);
791 					}
792 				}
793 			}
794 			else
795 			{
796 				if (prod->Type == PROD_Double)
797 				{
798 					Printf ("%g\n", static_cast<FDoubleProd *>(prod)->Value);
799 				}
800 				else
801 				{
802 					Printf ("%s\n", static_cast<FStringProd *>(prod)->Value);
803 				}
804 			}
805 			M_Free (prod);
806 			return;
807 		}
808 	}
809 
810 	Printf ("Usage: eval <expression> [variable]\n");
811 }
812