wxArt2D
eval.cpp
1 /*! \file canextobj/src/eval.cpp
2  \author Probably Klaas Holwerda
3 
4  Copyright: 2001-2004 (C) Probably Klaas Holwerda
5 
6  Licence: wxWidgets Licence
7 
8  RCS-ID: $Id: eval.cpp,v 1.16 2009/06/07 13:28:08 titato Exp $
9 */
10 
11 /*************************************************************************
12 ** **
13 ** EE.C Expression Evaluator **
14 ** **
15 ** AUTHOR: Mark Morley **
16 ** COPYRIGHT: (c) 1992 by Mark Morley **
17 ** DATE: December 1991 **
18 ** HISTORY: Jan 1992 - Made it squash all command line arguments **
19 ** into one big long string. **
20 ** - It now can set/get VMS symbols as if they **
21 ** were variables. **
22 ** - Changed max variable name length from 5 to 15 **
23 ** Jun 1992 - Updated comments and docs **
24 ** **
25 ** You are free to incorporate this code into your own works, even if it **
26 ** is a commercial application. However, you may not charge anyone else **
27 ** for the use of this code! If you intend to distribute your code, **
28 ** I'd appreciate it if you left this message intact. I'd like to **
29 ** receive credit wherever it is appropriate. Thanks! **
30 ** **
31 ** I don't promise that this code does what you think it does... **
32 ** **
33 ** Please mail any bug reports/fixes/enhancments to me at: **
34 ** morley@camosun.bc.ca **
35 ** or **
36 ** Mark Morley **
37 ** 3889 Mildred Street **
38 ** Victoria, BC Canada **
39 ** V8Z 7G1 **
40 ** (604) 479-7861 **
41 ** **
42  *************************************************************************/
43 
44 #include "a2dprec.h"
45 
46 #ifdef __BORLANDC__
47 #pragma hdrstop
48 #endif
49 
50 #ifndef WX_PRECOMP
51 #include "wx/defs.h"
52 #endif
53 
54 
55 #include <stdlib.h>
56 #include <string.h>
57 #include <math.h>
58 #include <wx/utils.h>
59 
60 
61 
62 #include "wx/canvas/eval.h"
63 
64 
65 #define SAVE_ERR(n) {ERROR2=n; ERPOS=m_expression-ERANC-1; ERTOK = m_token;}
66 
67 #if wxUSE_EXCEPTIONS
68 class EvalErr
69 {
70  // Simple type to throw as exception.
71 };
72 #define ERR(n) { SAVE_ERR(n); throw EvalErr();}
73 #else
74 #define ERR(n) { SAVE_ERR(n); longjmp(m_jb,1);}
75 #endif
76 
77 /* These defines only happen if the values are not already defined! You may
78  want to add more precision here, if your machine supports it. */
79 
80 
81 
82 #ifndef M_PI
83 #define M_PI 3.14159265358979323846
84 #endif
85 #ifndef M_E
86 #define M_E 2.71828182845904523536
87 #endif
88 
89 
90 /*************************************************************************
91 ** **
92 ** PROTOTYPES FOR CUSTOM MATH FUNCTIONS **
93 ** **
94  *************************************************************************/
95 
96 double deg( double x );
97 double rad( double x );
98 
99 
100 /*************************************************************************
101 ** **
102 ** VARIABLE DECLARATIONS **
103 ** **
104 *************************************************************************/
105 
106 int ERROR2; /* The error number */
107 wxString ERTOK; /* The token that generated the error */
108 int ERPOS; /* The offset from the start of the expression */
109 #if wxUSE_UNICODE
110  wxStringCharType* ERANC; /* Used to calculate ERPOS */
111 #else
112  wxChar* ERANC; /* Used to calculate ERPOS */
113 #endif // wxUSE_UNICODE
114 
115 
116 
117 WX_DEFINE_LIST( a2dFunctionList );
118 WX_DEFINE_LIST( a2dVariableList );
119 
120 /*************************************************************************
121 ** **
122 ** Some custom math functions... Note that they must be prototyped **
123 ** above (if your compiler requires it) **
124 ** **
125 ** deg( x ) Converts x radians to degrees. **
126 ** rad( x ) Converts x degrees to radians. **
127 ** **
128  *************************************************************************/
129 
130 double
131 deg( double x )
132 {
133  return( x * 180.0 / M_PI );
134 }
135 
136 double
137 rad( double x )
138 {
139  return( x * M_PI / 180.0 );
140 }
141 
142 a2dEval::a2dEval()
143 {
144  m_tokenstr.Alloc( VARLEN );
145 #if wxUSE_UNICODE
146  m_token = m_tokenstr.wx_str();
147 #else
148  m_token = ( wxChar* ) m_tokenstr.c_str();
149 #endif
150 
151  ClearAllVars();
152 
153  /*
154  Add any "constants" here... These are "read-only" values that are
155  provided as a convienence to the user. Their values can not be
156  permanently changed. The first field is the variable name, the second
157  is its value.
158  */
159  m_const.Append( new a2dEvalVar( wxT( "pi" ), M_PI ) );
160  m_const.Append( new a2dEvalVar( wxT( "e" ), M_E ) );
161 
162  /*
163  Add any math functions that you wish to recognise here. Use the
164  MATH_FUNC helper macro below to define the functions. Note that
165  only those math functions for which there are matching
166  a2dEvalFunction can be used. If you need to add other kinds of
167  functions (eg, with more than two arguments), you also need to
168  add the correponding a2dEvalFunction constructor.
169  */
170 #define MATH_FUNC(f) m_functions.Append(new a2dEvalFunction(wxT(#f), f))
171  MATH_FUNC( sin );
172  MATH_FUNC( cos );
173  MATH_FUNC( tan );
174  MATH_FUNC( asin );
175  MATH_FUNC( acos );
176  MATH_FUNC( atan );
177  MATH_FUNC( sinh );
178  MATH_FUNC( cosh );
179  MATH_FUNC( tanh );
180  MATH_FUNC( exp );
181  MATH_FUNC( log );
182  MATH_FUNC( log10 );
183  MATH_FUNC( sqrt );
184  MATH_FUNC( floor );
185  MATH_FUNC( ceil );
186  MATH_FUNC( fabs );
187  MATH_FUNC( deg );
188  MATH_FUNC( rad );
189  MATH_FUNC( hypot );
190 }
191 
192 /*************************************************************************
193 ** **
194 ** GetSymbol( char* s ) **
195 ** **
196 ** This routine obtains a value from the program's environment. **
197 ** This works for DOS and VMS (and other OS's???)
198 ** **
199  ************************************************************************/
200 
201 bool a2dEval::GetSymbol( const wxString& envname, TYPENUMBER* envValue )
202 {
203  wxString senvValue;
204  if( !wxGetEnv( envname, &senvValue ) )
205  return false; // Environment name not found
206 
207  if ( senvValue.ToDouble( envValue ) )
208  return true;
209  return false;
210 }
211 
212 a2dEval::~a2dEval()
213 {
214  a2dVariableList::compatibility_iterator node = m_vars.GetFirst();
215  while ( node )
216  {
217  delete node->GetData();
218  m_vars.DeleteNode( node );
219  node = m_vars.GetFirst();
220  }
221 
222  node = m_const.GetFirst();
223  while ( node )
224  {
225  delete node->GetData();
226  m_const.DeleteNode( node );
227  node = m_const.GetFirst();
228  }
229 
230  a2dFunctionList::compatibility_iterator node2 = m_functions.GetFirst();
231  while ( node2 )
232  {
233  delete node2->GetData();
234  m_functions.DeleteNode( node2 );
235  node2 = m_functions.GetFirst();
236  }
237 }
238 /*************************************************************************
239 ** **
240 ** ClearAllVars() **
241 ** **
242 ** Erases all user-defined variables from memory. Note that constants **
243 ** can not be erased or modified in any way by the user. **
244 ** **
245 ** Returns nothing. **
246 ** **
247  *************************************************************************/
248 
249 void a2dEval::ClearAllVars()
250 {
251  a2dVariableList::compatibility_iterator node = m_vars.GetFirst();
252  while ( node )
253  {
254  delete node->GetData();
255  m_vars.DeleteNode( node );
256  node = m_vars.GetFirst();
257  }
258 }
259 
260 
261 /*************************************************************************
262 ** **
263 ** ClearVar( char* name ) **
264 ** **
265 ** Erases the user-defined variable that is called NAME from memory. **
266 ** Note that constants are not affected. **
267 ** **
268 ** Returns 1 if the variable was found and erased, or 0 if it didn't **
269 ** exist. **
270 ** **
271  *************************************************************************/
272 
273 bool a2dEval::ClearVar( const wxString& name )
274 {
275  a2dVariableList::compatibility_iterator node = m_vars.GetFirst();
276  while ( node )
277  {
278  a2dEvalVar* obj = node->GetData();
279  if( ( !obj->m_name.IsEmpty () ) && obj->m_name == name )
280  {
281  a2dVariableList::compatibility_iterator h = node;
282  //remove this node
283  node = node->GetNext();
284  delete h->GetData();
285  m_vars.DeleteNode( h );
286  return true;
287  }
288  else
289  node = node->GetNext();
290  }
291 
292  return false;
293 }
294 
295 
296 /*************************************************************************
297 ** **
298 ** GetValue( char* name, TYPENUMBER* value ) **
299 ** **
300 ** Looks up the specified variable (or constant) known as NAME and **
301 ** returns its contents in VALUE. **
302 ** **
303 ** First the user-defined variables are searched, then the constants are **
304 ** searched. **
305 ** **
306 ** Returns true if the value was found, or false if it wasn't. **
307 ** **
308  *************************************************************************/
309 
310 bool a2dEval::GetValue( const wxString& name, TYPENUMBER* value )
311 {
312  /* First check for an environment variable reference... */
313  if( name[0] == wxT( '_' ) )
314  return( GetSymbol( name.Mid( 1 ), value ) );
315 
316 
317  /* Now check the user-defined variables. */
318  a2dVariableList::compatibility_iterator node = m_vars.GetFirst();
319  while ( node )
320  {
321  a2dEvalVar* obj = node->GetData();
322  if ( obj->m_name == name )
323  {
324  *value = obj->m_value;
325  return true;
326  }
327  node = node->GetNext();
328  }
329 
330 
331  /* Now check the programmer-defined constants. */
332  node = m_const.GetFirst();
333  while ( node )
334  {
335  a2dEvalVar* obj = node->GetData();
336  if( obj->m_name == name )
337  {
338  *value = obj->m_value;
339  return true;
340  }
341  node = node->GetNext();
342  }
343 
344  return false;
345 }
346 
347 
348 /*************************************************************************
349 ** **
350 ** SetValue( char* name, TYPENUMBER* value ) **
351 ** **
352 ** First, it erases any user-defined variable that is called NAME. Then **
353 ** it creates a new variable called NAME and gives it the value VALUE. **
354 ** **
355 ** Returns 1 if the value was added, or 0 if there was no more room. **
356 ** **
357  *************************************************************************/
358 
359 bool a2dEval::SetValue( const wxString& name, TYPENUMBER value )
360 {
361  ClearVar( name );
362  m_vars.Append( new a2dEvalVar( name, value ) );
363  return true;
364 }
365 
366 
367 /*************************************************************************
368 ** **
369 ** Parse() Internal use only **
370 ** **
371 ** This function is used to grab the next token from the expression that **
372 ** is being evaluated. **
373 ** **
374  *************************************************************************/
375 
376 void a2dEval::Parse()
377 {
378 #if wxUSE_UNICODE
379  wxStringCharType* t;
380 #else
381  wxChar* t;
382 #endif // wxUSE_UNICODE
383 
384  m_type = 0;
385 #if wxUSE_UNICODE
386  t = (wxStringCharType*) m_token;
387 #else
388  t = m_token;
389 #endif // wxUSE_UNICODE
390  while( iswhite( *m_expression ) )
391  m_expression++;
392  if( isdelim( *m_expression ) )
393  {
394  m_type = DEL;
395  *t++ = *m_expression++;
396  }
397  else if( isnumer( *m_expression ) )
398  {
399  m_type = NUM;
400  while( isnumer( *m_expression ) )
401  *t++ = *m_expression++;
402  }
403  else if( isalphaeval( *m_expression ) )
404  {
405  m_type = VAR;
406  while( isalphaeval( *m_expression ) )
407  *t++ = *m_expression++;
408  //m_token[VARLEN] = 0;
409  }
410  else if( *m_expression )
411  {
412  *t++ = *m_expression++;
413  *t = 0;
414  ERR( E_SYNTAX );
415  }
416  *t = 0;
417  while( iswhite( *m_expression ) )
418  m_expression++;
419 }
420 
421 
422 /*************************************************************************
423 ** **
424 ** Level1( TYPENUMBER* r ) Internal use only **
425 ** **
426 ** This function handles any variable assignment operations. **
427 ** It returns a value of 1 if it is a top-level assignment operation, **
428 ** otherwise it returns 0 **
429 ** **
430  *************************************************************************/
431 
432 int a2dEval::Level1( TYPENUMBER* r )
433 {
434  wxString t;
435 
436  if( m_type == VAR )
437  if( *m_expression == wxT( '=' ) )
438  {
439  t = m_token;
440  Parse();
441  Parse();
442  if( !*m_token )
443  {
444  ClearVar( t );
445  return( 1 );
446  }
447  Level2( r );
448  if( ! SetValue( t, *r ) )
449  ERR( E_MAXVARS );
450  return( 1 );
451  }
452  Level2( r );
453  return( 0 );
454 }
455 
456 
457 /*************************************************************************
458 ** **
459 ** Level2( TYPENUMBER* r ) Internal use only **
460 ** **
461 ** This function handles any addition and subtraction operations. **
462 ** **
463  *************************************************************************/
464 
465 void a2dEval::Level2( TYPENUMBER* r )
466 {
467  TYPENUMBER t = 0;
468  wxChar o;
469 
470  Level3( r );
471  while( ( o = *m_token ) == wxT( '+' ) || o == wxT( '-' ) )
472  {
473  Parse();
474  Level3( &t );
475  if( o == wxT( '+' ) )
476  *r = *r + t;
477  else if( o == wxT( '-' ) )
478  *r = *r - t;
479  }
480 }
481 
482 
483 /*************************************************************************
484 ** **
485 ** Level3( TYPENUMBER* r ) Internal use only **
486 ** **
487 ** This function handles any multiplication, division, or modulo. **
488 ** **
489  *************************************************************************/
490 
491 void a2dEval::Level3( TYPENUMBER* r )
492 {
493  TYPENUMBER t;
494  wxChar o;
495 
496  Level4( r );
497  while( ( o = *m_token ) == wxT( '*' ) || o == wxT( '/' ) || o == wxT( '%' ) )
498  {
499  Parse();
500  Level4( &t );
501  if( o == wxT( '*' ) )
502  *r = *r * t;
503  else if( o == wxT( '/' ) )
504  {
505  if( t == 0 )
506  ERR( E_DIVZERO );
507  *r = *r / t;
508  }
509  else if( o == wxT( '%' ) )
510  {
511  if( t == 0 )
512  ERR( E_DIVZERO );
513  *r = fmod( *r, t );
514  }
515  }
516 }
517 
518 
519 /*************************************************************************
520 ** **
521 ** Level4( TYPENUMBER* r ) Internal use only **
522 ** **
523 ** This function handles any "to the power of" operations. **
524 ** **
525  *************************************************************************/
526 
527 void a2dEval::Level4( TYPENUMBER* r )
528 {
529  TYPENUMBER t;
530 
531  Level5( r );
532  if( *m_token == wxT( '^' ) )
533  {
534  Parse();
535  Level5( &t );
536  *r = pow( *r, t );
537  }
538 }
539 
540 
541 /*************************************************************************
542 ** **
543 ** Level5( TYPENUMBER* r ) Internal use only **
544 ** **
545 ** This function handles any unary + or - signs. **
546 ** **
547  *************************************************************************/
548 
549 void a2dEval::Level5( TYPENUMBER* r )
550 {
551  wxChar o = 0;
552 
553  if( *m_token == wxT( '+' ) || *m_token == wxT( '-' ) )
554  {
555  o = *m_token;
556  Parse();
557  }
558  Level6( r );
559  if( o == wxT( '-' ) )
560  *r = -*r;
561 }
562 
563 
564 /*************************************************************************
565 ** **
566 ** Level6( TYPENUMBER* r ) Internal use only **
567 ** **
568 ** This function handles any literal numbers, variables, or functions. **
569 ** **
570  *************************************************************************/
571 
572 void a2dEval::Level6( TYPENUMBER* r )
573 {
574  int n;
575  TYPENUMBER a[3];
576 
577  if( *m_token == wxT( '(' ) )
578  {
579  Parse();
580  if( *m_token == wxT( ')' ) )
581  ERR( E_NOARG );
582  Level1( r );
583  if( *m_token != wxT( ')' ) )
584  ERR( E_UNBALAN );
585  Parse();
586  }
587  else
588  {
589  if( m_type == NUM )
590  {
591  wxString numstr = m_token;
592  numstr.ToDouble( r );
593  Parse();
594  }
595  else if( m_type == VAR )
596  {
597  if( *m_expression == wxT( '(' ) )
598  {
599  a2dFunctionList::compatibility_iterator node = m_functions.GetFirst();
600  while ( node )
601  {
602  a2dEvalFunction* obj = node->GetData();
603 
604  if( m_token == obj->m_name )
605  {
606  Parse();
607  n = 0;
608  do
609  {
610  Parse();
611  if( *m_token == wxT( ')' ) || *m_token == wxT( ',' ) )
612  ERR( E_NOARG );
613  a[n] = 0;
614  Level1( &a[n] );
615  n++;
616  }
617  while( n < 4 && *m_token == wxT( ',' ) );
618  Parse();
619  if( n != obj->m_args )
620  {
621  m_tokenstr = obj->m_name;
622  ERR( E_NUMARGS );
623  }
624  *r = obj->m_func( a[0], a[1], a[2] );
625  return;
626  }
627  if( obj->m_name.IsEmpty () )
628  ERR( E_BADFUNC );
629 
630  node = node->GetNext();
631  }
632  }
633  else if( ! GetValue( m_token, r ) )
634  ERR( E_UNKNOWN );
635 
636  Parse();
637  }
638  else
639  ERR( E_SYNTAX );
640  }
641 }
642 
643 
644 /*************************************************************************
645 ** **
646 ** Evaluate( TYPENUMBER* result, int* a ) **
647 ** **
648 ** This function is called to evaluate the expression E and return the **
649 ** answer in RESULT. If the expression was a top-level assignment, a **
650 ** value of 1 will be returned in A, otherwise it will contain 0. **
651 ** **
652 ** Returns E_OK if the expression is valid, or an error code. **
653 ** **
654  *************************************************************************/
655 
656 int a2dEval::Evaluate( TYPENUMBER* result, int* a )
657 {
658 #if wxUSE_EXCEPTIONS
659  try
660  {
661 #else
662  if( setjmp( m_jb ) )
663  return( ERROR2 );
664 #endif
665 
666 
667 #if wxUSE_UNICODE
668  m_expression = m_eval.wx_str();
669  ERANC = (wxStringCharType*) m_expression;
670 #else
671  m_expression = ( wxChar* ) m_eval.c_str();
672  ERANC = ( wxChar* ) m_eval.c_str();
673 #endif // wxUSE_UNICODE
674 
675  //strlwr( m_expression );
676  *result = 0;
677  Parse();
678  if( ! *m_token )
679  ERR( E_EMPTY );
680  *a = Level1( result );
681  return( E_OK );
682 #if wxUSE_EXCEPTIONS
683  }
684  catch( const EvalErr& )
685  {
686  return( ERROR2 );
687  }
688 #endif
689 }
690 
691 
692 /*************************************************************************
693 ** **
694 ** What follows is a main() routine that evaluates the command line **
695 ** arguments one at a time, and displays the results of each expression. **
696 ** Without arguments, it becomes an interactive calculator. **
697 ** **
698  *************************************************************************/
699 
700 #include <stdio.h>
701 
702 const wxChar* ErrMsgs[] =
703 {
704  wxT( "Syntax error" ),
705  wxT( "Unbalanced parenthesis" ),
706  wxT( "Division by zero" ),
707  wxT( "Unknown variable" ),
708  wxT( "Maximum variables exceeded" ),
709  wxT( "Unrecognised funtion" ),
710  wxT( "Wrong number of arguments to funtion" ),
711  wxT( "Missing an argument" ),
712  wxT( "Empty expression" )
713 };
714 
715 
716 /*
717 int main( int argc, char* argv[] )
718 {
719  TYPENUMBER result;
720  int i;
721  int ec;
722  int a;
723  char line[1024];
724  char* v;
725  a2dEval toeval;
726 
727  // If we have command line arguments then we evaluate them and exit.
728  if( argc > 1 )
729  {
730  // Concatenate all arguments into one string.
731  strcpy( line, argv[1] );
732  for( i = 2; i < argc; i++ )
733  strcat( line, argv[i] );
734 
735  toeval.ClearAllVars();
736  toeval.SetEvalString(line);
737  // Call the evaluator.
738  if( (ec = toeval.Evaluate( &result, &a )) == E_OK )
739  {
740  // If we didn't assign a variable, then print the result.
741  if( ! a )
742  printf( "%g\n", result );
743  }
744  else if( ec != E_EMPTY )
745  {
746  // Display error info. In this example, an E_EMPTY error is ignored.
747  printf( "ERROR: %s - %s", ErrMsgs[ERROR2 - 1], ERTOK );
748  printf( "\n%s", ERANC );
749  printf( "\n%*s^\n", ERPOS, "" );
750  }
751  return 1;
752  }
753 
754  toeval.ClearAllVars();
755  double x;
756  for ( x=-10;x<10;x++)
757  {
758  toeval.SetValue("x",x);
759  sprintf(line,"y=x*2");
760  toeval.SetEvalString(line);
761  toeval.Evaluate( &result, &a );
762 
763  double y;
764  toeval.GetValue("y",&y);
765  printf( "=>%f\n", y );
766  }
767 
768 
769  // There were no command line arguments, so lets go interactive.
770  printf( "\nEE - Equation Evaluator" );
771  printf( "\nBy Mark Morley December 1991" );
772  printf( "\nEnter EXIT to quit.\n" );
773  printf( "\nEE> " );
774 
775  // Input one line at a time from the user. Note that it uses stdin, so on
776  // DOS or UNIX you could pipe a list of expressions into it...
777  for( gets( line ); !feof( stdin ); gets( line ) )
778  {
779  strlwr( line );
780  toeval.SetEvalString(line);
781 
782  // Did the user ask to exit?
783  if( ! strcmp( line, "exit" ) )
784  return 1;
785 
786  // Did the user ask to see the variables in memory?
787  else if( ! strcmp( line, "vars" ) )
788  {
789  a2dVariableList::compatibility_iterator node = toeval.m_vars.GetFirst();
790  while (node)
791  {
792  a2dEvalVar *obj = node->GetData();
793  printf( "%s = %g\n", obj->m_name, obj->m_value );
794  node = node->GetNext();
795  }
796  }
797 
798  // Did the user ask to see the constants in memory?
799  else if( ! strcmp( line, "cons" ) )
800  {
801  a2dVariableList::compatibility_iterator node = toeval.m_const.GetFirst();
802  while (node)
803  {
804  a2dEvalVar *obj = node->GetData();
805  printf( "%s = %g\n", obj->m_name, obj->m_value );
806  node = node->GetNext();
807  }
808  }
809 
810  // Did the user ask to clear all variables?
811  else if( ! strcmp( line, "clr" ) )
812  toeval.ClearAllVars();
813 
814  // If none of the above, then we attempt to evaluate the user's input.
815  else
816  {
817  // Call the evaluator.
818  if( (ec = toeval.Evaluate( &result, &a )) == E_OK )
819  {
820  // Only display the result if it was not an assignment.
821  if( ! a )
822  printf( "%g\n", result );
823  }
824  else if( ec != E_EMPTY )
825  {
826  // Display error information. E_EMPTY is ignored.
827  printf( "ERROR: %s - %s", ErrMsgs[ERROR - 1], ERTOK );
828  printf( "\n%s", ERANC );
829  printf( "\n%*s^\n", ERPOS, "" );
830  }
831  }
832  printf( "EE> " );
833  }
834 }
835 */
holds a function in an evaluation string for a2dEval
Definition: eval.h:70
holds a variable in an evaluation string for a2dEval
Definition: eval.h:49
eval.cpp Source File -- Sun Oct 12 2014 17:04:19 -- Sun Oct 12 2014 -- 1.8.5 -- wxArt2D -- . -- Main Page Reference Documentation