Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/util/ExprParser.cc @ 7944

Last change on this file since 7944 was 7184, checked in by rgrieder, 14 years ago

Replaced mathematical constants with a common definition in Math.h.
Use math::pi, math::pi_d (double), math::e, etc. from now on.

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