Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2944 was 2171, checked in by landauf, 16 years ago

merged revisions 2111-2170 from objecthierarchy branch back to trunk.

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