Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ceguilua/src/util/ExprParser.cc @ 2070

Last change on this file since 2070 was 1639, checked in by rgrieder, 16 years ago

merged nico's fixes for gcc 4.3 back to trunk.
I'm not going to delete branch yet.

  • Property svn:eol-style set to native
File size: 10.3 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#include <stdlib.h>
38
39// macros for easier if, else statements
40#define CASE_1(var) if (!strcmp(SWITCH,var))
41#define CASE(var) else if (!strcmp(SWITCH,var))
42#define CASE_ELSE else
43
44//! skip white spaces
45#define PARSE_BLANKS while (*reading_stream == ' ') ++reading_stream;
46
47ExprParser::ExprParser(const std::string& str)
48{
49  this->failed_ = false;
50  this->reading_stream = str.c_str();
51  if (str.size() == 0 || *reading_stream == '\0')
52  {
53    this->failed_ = true;
54    this->result_ = 0.0;
55  }
56  else
57  {
58    this->result_ = parse_expr_8();
59    this->remains_ = reading_stream;
60  }
61}
62
63//Private functions:
64/******************/
65double ExprParser::parse_argument()
66{
67   double value = parse_expr_8();
68   if (*reading_stream == ',')
69   {
70      ++reading_stream;
71      return value;
72   }
73   else
74   {
75     this->failed_ = true;
76     return 0;
77   }
78}
79
80double ExprParser::parse_last_argument()
81{
82   double value = parse_expr_8();
83   if (*reading_stream == ')')
84   {
85      ++reading_stream;
86      return value;
87   }
88   else
89   {
90     this->failed_ = true;
91     return 0;
92   }
93}
94
95double ExprParser::parse_expr_8()
96{
97   double value = parse_expr_7();
98   for(;;)
99   {
100      switch (op)
101      {
102         case oder:
103            value = parse_expr_7() || value;
104            break;
105         default: return value;
106      }
107   };
108}
109
110
111double ExprParser::parse_expr_7()
112{
113   double value = parse_expr_6();
114   for(;;)
115   {
116      switch (op)
117      {
118         case und:
119            value = value && parse_expr_6();
120            break;
121         default: return value;
122      }
123   };
124}
125
126double ExprParser::parse_expr_6()
127{
128   double value = parse_expr_5();
129   for(;;)
130   {
131      switch (op)
132      {
133         case gleich:
134            value = (value == parse_expr_5());
135            break;
136         case ungleich:
137            value = (value != parse_expr_5());
138            break;
139         default:
140            return value;
141      }
142   };
143}
144
145double ExprParser::parse_expr_5()
146{
147   double value = parse_expr_4();
148   for(;;)
149   {
150      switch (op)
151      {
152         case kleiner:
153            value = (value < parse_expr_4());
154            break;
155         case kleinergleich:
156            value = (value <= parse_expr_4());
157            break;
158         case groesser:
159            value = (value > parse_expr_4());
160            break;
161         case groessergleich:
162            value = (value >= parse_expr_4());
163            break;
164         default:
165            return value;
166      }
167   };
168}
169
170double ExprParser::parse_expr_4()
171{
172   double value = parse_expr_3();
173   for(;;)
174   {
175      switch (op)
176      {
177         case b_plus:
178            value += parse_expr_3();
179            break;
180         case b_minus:
181            value -= parse_expr_3();
182            break;
183         default:
184            return value;
185      }
186   };
187}
188
189double ExprParser::parse_expr_3()
190{
191   double value = parse_expr_2();
192   for(;;)
193   {
194      switch (op)
195      {
196         case mal:
197            value *= parse_expr_2();
198            break;
199         case durch:
200            value /= parse_expr_2();
201            break;
202         case modulo:
203         {
204            double temp = parse_expr_2();
205            value = value - floor(value/temp)*temp;
206            break;
207         }
208         default:
209            return value;
210      }
211   };
212}
213
214double ExprParser::parse_expr_2()
215{
216   double value = parse_expr_1();
217   while (*reading_stream != '\0')
218   {
219      op = parse_binary_operator();
220      switch (op)
221      {
222         case hoch:
223            value = pow(value,parse_expr_1());
224            break;
225         default:
226            return value;
227      }
228   };
229   op = undef;
230   return value;
231}
232
233double ExprParser::parse_expr_1()
234{
235   PARSE_BLANKS
236   double value;
237
238   unary_operator op = parse_unary_operator();
239   PARSE_BLANKS
240
241   if (*reading_stream == '\0')
242   {
243     // end of string
244     this->failed_ = true;
245     return 0;
246   }
247   else if (*reading_stream > 47 && *reading_stream < 59 || *reading_stream == 46)
248   {  // number
249      value = strtod(reading_stream, const_cast<char**>(&reading_stream));
250   }
251   else if (*reading_stream > 64 && *reading_stream < 91 || *reading_stream > 96 && *reading_stream < 123 || *reading_stream == 46)
252   {  // variable or function
253      char* word = new char[256];
254      parse_word(word);
255      PARSE_BLANKS
256      if (*reading_stream == '(')
257      {
258         ++reading_stream;
259#define SWITCH word
260         CASE_1("sin")
261            value = sin(parse_last_argument());
262         CASE("asin")
263            value = asin(parse_last_argument());
264         CASE("sinh")
265            value = sinh(parse_last_argument());
266         CASE("asinh")
267         {
268            value = parse_last_argument();
269            value = log(sqrt(pow(value, 2) + 1) + value);
270         }
271         CASE("cos")
272            value = cos(parse_last_argument());
273         CASE("acos")
274            value = acos(parse_last_argument());
275         CASE("cosh")
276            value = cosh(parse_last_argument());
277         CASE("acosh")
278         {
279            value = parse_last_argument();
280            value = log(sqrt(pow(value, 2) - 1) + value);
281         }
282         CASE("tan")
283            value = tan(parse_last_argument());
284         CASE("atan")
285            value = atan(parse_last_argument());
286         CASE("atan2")
287            value = atan2(parse_argument(),parse_last_argument());
288         CASE("tanh")
289            value = tanh(parse_last_argument());
290         CASE("atanh")
291         {
292            value = parse_last_argument();
293            value = 0.5*log((value + 1)/(value - 1));
294         }
295         CASE("int")
296            value = floor(parse_last_argument());
297         CASE("floor")
298            value = floor(parse_last_argument());
299         CASE("ceil")
300            value = ceil(parse_last_argument());
301         CASE("abs")
302            value = fabs(parse_last_argument());
303         CASE("exp")
304            value = exp(parse_last_argument());
305         CASE("log")
306            value = log10(parse_last_argument());
307         CASE("ln")
308            value = log(parse_last_argument());
309         CASE("sign")
310         {
311            value = parse_last_argument();
312            value = (value>0 ? 1 : (value<0 ? -1 : 0));
313         }
314         CASE("sqrt")
315            value = sqrt(parse_last_argument());
316         CASE("degrees")
317            value = parse_last_argument()*180/3.1415926535897932;
318         CASE("radians")
319            value = parse_last_argument()*3.1415926535897932/180;
320         CASE("mod")
321         {
322            value = parse_argument();
323            double value2 = parse_last_argument();
324            value = value - floor(value/value2)*value2;
325         }
326         CASE("pow")
327            value = pow(parse_argument(),parse_last_argument());
328         CASE("div")
329            value = floor(parse_argument()/parse_last_argument());
330         CASE("max")
331           value = std::max(parse_argument(),parse_last_argument());
332         CASE("min")
333           value = std::min(parse_argument(),parse_last_argument());
334         CASE_ELSE
335         {
336           this->failed_ = true;
337           delete[] word;
338           return 0;
339         }
340      }
341      else
342      {
343#define SWITCH word
344         CASE_1("pi")
345           value = 3.1415926535897932;
346         CASE("e")
347           value = 2.7182818284590452;
348         CASE_ELSE
349         {
350           this->failed_ = true;
351           delete[] word;
352           return 0;
353         }
354      }
355      delete[] word;
356   }
357   else if (*reading_stream == 40)
358   {  // expresion in paranthesis
359      ++reading_stream;
360      value = parse_last_argument();
361   }
362   else
363   {
364     this->failed_ = true;
365     return 0;
366   }
367
368   PARSE_BLANKS
369   switch (op)
370   {
371      case u_nicht: return !value;
372      case u_plus:  return  value;
373      case u_minus: return -value;
374      default:
375        {
376          this->failed_ = true;
377          return 0;
378        }
379   }
380}
381
382char* ExprParser::parse_word(char* str)
383{
384   char* word = str;
385   int counter = 0;
386   while (*reading_stream > 47 && *reading_stream < 58 || *reading_stream > 64 && *reading_stream < 91 || *reading_stream > 96 && *reading_stream < 123 || *reading_stream == 46)
387   {
388      *word++ = *reading_stream++;
389      counter++;
390      if (counter > 255)
391      {
392        this->failed_ = true;
393        return '\0';
394      }
395   };
396   *word = '\0';
397   return str;
398}
399
400ExprParser::binary_operator ExprParser::parse_binary_operator()
401{
402   binary_operator op;
403   switch (*reading_stream)
404   {
405      case '+': op = b_plus; break;
406      case '-': op = b_minus; break;
407      case '*': op = mal; break;
408      case '/': op = durch; break;
409      case '^': op = hoch; break;
410      case '%': op = modulo; break;
411      case '&': op = und; break;
412      case '|': op = oder; break;
413      case '=': op = gleich; break;
414      case '!': op = b_nicht; break;
415      case '<': op = kleiner; break;
416      case '>': op = groesser; break;
417      default: return undef;
418   }
419   if (*++reading_stream == '=')
420   {
421      if (op > 9)
422      {
423         ++reading_stream;
424         return (binary_operator)(op + 3);
425      }
426      else
427      {
428         --reading_stream;
429         return undef;
430      }
431   }
432   else
433      return op;
434}
435
436ExprParser::unary_operator ExprParser::parse_unary_operator()
437{
438   switch (*reading_stream)
439   {
440      case '!':
441         ++reading_stream;
442         return u_nicht;
443      case '+':
444         ++reading_stream;
445         return u_plus;
446      case '-':
447         ++reading_stream;
448         return u_minus;
449      default :
450         return u_plus;
451   }
452}
Note: See TracBrowser for help on using the repository browser.