Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/util/ExprParser.cc @ 1162

Last change on this file since 1162 was 1120, checked in by rgrieder, 17 years ago
  • merged calculator into trunk
File size: 10.7 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Reto Grieder
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30  @file
31  @brief Declaration of FloatParser
32*/
33
34#include "ExprParser.h"
35#include <cmath>
36#include <cstring>
37
38// macros for easier if, else statements
39#define CASE_1(var) if (!strcmp(SWITCH,var))
40#define CASE(var) else if (!strcmp(SWITCH,var))
41#define CASE_ELSE else
42
43//! skip white spaces
44#define PARSE_BLANKS while (*reading_stream == ' ') ++reading_stream;
45
46ExprParser::ExprParser(const std::string& str)
47{
48  this->failed_ = false;
49  this->reading_stream = str.c_str();
50  if (str.size() == 0 || *reading_stream == '\0')
51  {
52    this->failed_ = true;
53    this->result_ = 0.0;
54  }
55  else
56  {
57    this->result_ = parse_expr_8();
58    this->remains_ = reading_stream;
59  }
60}
61
62//Private functions:
63/******************/
64double ExprParser::parse_argument()
65{
66   double value = parse_expr_8();
67   if (*reading_stream == ',')
68   {
69      ++reading_stream;
70      return value;
71   }
72   else
73   {
74     this->failed_ = true;
75     return 0;
76   }
77}
78
79double ExprParser::parse_last_argument()
80{
81   double value = parse_expr_8();
82   if (*reading_stream == ')')
83   {
84      ++reading_stream;
85      return value;
86   }
87   else
88   {
89     this->failed_ = true;
90     return 0;
91   }
92}
93
94double ExprParser::parse_expr_8()
95{
96   double value = parse_expr_7();
97   for(;;)
98   {
99      switch (op)
100      {
101         case oder:
102            value = parse_expr_7() || value;
103            break;
104         default: return value;
105      }
106   };
107}
108
109
110double ExprParser::parse_expr_7()
111{
112   double value = parse_expr_6();
113   for(;;)
114   {
115      switch (op)
116      {
117         case und:
118            value = value && parse_expr_6();
119            break;
120         default: return value;
121      }
122   };
123}
124
125double ExprParser::parse_expr_6()
126{
127   double value = parse_expr_5();
128   for(;;)
129   {
130      switch (op)
131      {
132         case gleich:
133            value = (value == parse_expr_5());
134            break;
135         case ungleich:
136            value = (value != parse_expr_5());
137            break;
138         default:
139            return value;
140      }
141   };
142}
143
144double ExprParser::parse_expr_5()
145{
146   double value = parse_expr_4();
147   for(;;)
148   {
149      switch (op)
150      {
151         case kleiner:
152            value = (value < parse_expr_4());
153            break;
154         case kleinergleich:
155            value = (value <= parse_expr_4());
156            break;
157         case groesser:
158            value = (value > parse_expr_4());
159            break;
160         case groessergleich:
161            value = (value >= parse_expr_4());
162            break;
163         default:
164            return value;
165      }
166   };
167}
168
169double ExprParser::parse_expr_4()
170{
171   double value = parse_expr_3();
172   for(;;)
173   {
174      switch (op)
175      {
176         case b_plus:
177            value += parse_expr_3();
178            break;
179         case b_minus:
180            value -= parse_expr_3();
181            break;
182         default:
183            return value;
184      }
185   };
186}
187
188double ExprParser::parse_expr_3()
189{
190   double value = parse_expr_2();
191   for(;;)
192   {
193      switch (op)
194      {
195         case mal:
196            value *= parse_expr_2();
197            break;
198         case durch:
199            value /= parse_expr_2();
200            break;
201         case modulo:
202         {
203            double temp = parse_expr_2();
204            value = value - floor(value/temp)*temp;
205            break;
206         }
207         default:
208            return value;
209      }
210   };
211}
212
213double ExprParser::parse_expr_2()
214{
215   double value = parse_expr_1();
216   while (*reading_stream != '\0')
217   {
218      op = parse_binary_operator();
219      switch (op)
220      {
221         case hoch:
222            value = pow(value,parse_expr_1());
223            break;
224         default:
225            return value;
226      }
227   };
228   op = undef;
229   return value;
230}
231
232double ExprParser::parse_expr_1()
233{
234   PARSE_BLANKS
235   double value;
236
237   unary_operator op = parse_unary_operator();
238   PARSE_BLANKS
239
240   if (*reading_stream == '\0')
241   {
242     // end of string
243     this->failed_ = true;
244     return 0;
245   }
246   else if (*reading_stream > 47 && *reading_stream < 59 || *reading_stream == 46)
247   {  // number
248      value = strtod(reading_stream, const_cast<char**>(&reading_stream));
249   }
250   else if (*reading_stream > 64 && *reading_stream < 91 || *reading_stream > 96 && *reading_stream < 123 || *reading_stream == 46)
251   {  // variable or function
252      char* word = new char[256];
253      parse_word(word);
254      PARSE_BLANKS
255      if (*reading_stream == '(')
256      {
257         ++reading_stream;
258#define SWITCH word
259         CASE_1("sin")
260            value = sin(parse_last_argument());
261         CASE("asin")
262            value = asin(parse_last_argument());
263         CASE("sinh")
264            value = sinh(parse_last_argument());
265         CASE("asinh")
266         {
267            value = parse_last_argument();
268            value = log(sqrt(pow(value, 2) + 1) + value);
269         }
270         CASE("cos")
271            value = cos(parse_last_argument());
272         CASE("acos")
273            value = acos(parse_last_argument());
274         CASE("cosh")
275            value = cosh(parse_last_argument());
276         CASE("acosh")
277         {
278            value = parse_last_argument();
279            value = log(sqrt(pow(value, 2) - 1) + value);
280         }
281         CASE("tan")
282            value = tan(parse_last_argument());
283         CASE("atan")
284            value = atan(parse_last_argument());
285         CASE("atan2")
286            value = atan2(parse_argument(),parse_last_argument());
287         CASE("tanh")
288            value = tanh(parse_last_argument());
289         CASE("atanh")
290         {
291            value = parse_last_argument();
292            value = 0.5*log((value + 1)/(value - 1));
293         }
294         CASE("int")
295            value = floor(parse_last_argument());
296         CASE("floor")
297            value = floor(parse_last_argument());
298         CASE("ceil")
299            value = ceil(parse_last_argument());
300         CASE("abs")
301            value = fabs(parse_last_argument());
302         CASE("exp")
303            value = exp(parse_last_argument());
304         CASE("log")
305            value = log10(parse_last_argument());
306         CASE("ln")
307            value = log(parse_last_argument());
308         CASE("sign")
309         {
310            value = parse_last_argument();
311            value = (value>0 ? 1 : (value<0 ? -1 : 0));
312         }
313         CASE("sqrt")
314            value = sqrt(parse_last_argument());
315         CASE("degrees")
316            value = parse_last_argument()*180/3.1415926535897932;
317         CASE("radians")
318            value = parse_last_argument()*3.1415926535897932/180;
319         CASE("mod")
320         {
321            value = parse_argument();
322            double value2 = parse_last_argument();
323            value = value - floor(value/value2)*value2;
324         }
325         CASE("pow")
326            value = pow(parse_argument(),parse_last_argument());
327         CASE("div")
328            value = floor(parse_argument()/parse_last_argument());
329         CASE("max")
330           value = std::max(parse_argument(),parse_last_argument());
331         CASE("min")
332           value = std::min(parse_argument(),parse_last_argument());
333         CASE_ELSE
334         {
335           this->failed_ = true;
336           delete[] word;
337           return 0;
338         }
339      }
340      else
341      {
342#define SWITCH word
343         CASE_1("pi")
344           value = 3.1415926535897932;
345         CASE("e")
346           value = 2.7182818284590452;
347         CASE_ELSE
348         {
349           this->failed_ = true;
350           delete[] word;
351           return 0;
352         }
353      }
354      delete[] word;
355   }
356   else if (*reading_stream == 40)
357   {  // expresion in paranthesis
358      ++reading_stream;
359      value = parse_last_argument();
360   }
361   else
362   {
363     this->failed_ = true;
364     return 0;
365   }
366
367   PARSE_BLANKS
368   switch (op)
369   {
370      case u_nicht: return !value;
371      case u_plus:  return  value;
372      case u_minus: return -value;
373      default:
374        {
375          this->failed_ = true;
376          return 0;
377        }
378   }
379}
380
381char* ExprParser::parse_word(char* str)
382{
383   char* word = str;
384   int counter = 0;
385   while (*reading_stream > 47 && *reading_stream < 58 || *reading_stream > 64 && *reading_stream < 91 || *reading_stream > 96 && *reading_stream < 123 || *reading_stream == 46)
386   {
387      *word++ = *reading_stream++;
388      counter++;
389      if (counter > 255)
390      {
391        this->failed_ = true;
392        return '\0';
393      }
394   };
395   *word = '\0';
396   return str;
397}
398
399ExprParser::binary_operator ExprParser::parse_binary_operator()
400{
401   binary_operator op;
402   switch (*reading_stream)
403   {
404      case '+': op = b_plus; break;
405      case '-': op = b_minus; break;
406      case '*': op = mal; break;
407      case '/': op = durch; break;
408      case '^': op = hoch; break;
409      case '%': op = modulo; break;
410      case '&': op = und; break;
411      case '|': op = oder; break;
412      case '=': op = gleich; break;
413      case '!': op = b_nicht; break;
414      case '<': op = kleiner; break;
415      case '>': op = groesser; break;
416      default: return undef;
417   }
418   if (*++reading_stream == '=')
419   {
420      if (op > 9)
421      {
422         ++reading_stream;
423         return (binary_operator)(op + 3);
424      }
425      else
426      {
427         --reading_stream;
428         return undef;
429      }
430   }
431   else
432      return op;
433}
434
435ExprParser::unary_operator ExprParser::parse_unary_operator()
436{
437   switch (*reading_stream)
438   {
439      case '!':
440         ++reading_stream;
441         return u_nicht;
442      case '+':
443         ++reading_stream;
444         return u_plus;
445      case '-':
446         ++reading_stream;
447         return u_minus;
448      default :
449         return u_plus;
450   }
451}
Note: See TracBrowser for help on using the repository browser.