Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation2/src/libraries/util/ExprParser.cc @ 6791

Last change on this file since 6791 was 6185, checked in by rgrieder, 15 years ago

Extended ExprParser to support arbitrary variables. You can set them with ExprParser::setVariable.

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