Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/consolecommands/src/libraries/util/ExprParser.cc @ 6858

Last change on this file since 6858 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
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 <cstdlib>
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()
50    {
51        this->failed_ = false;
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    {
63        this->reading_stream = str.c_str();
64        if (str.size() == 0 || *reading_stream == '\0')
65        {
66            this->failed_ = true;
67            this->result_ = 0.0;
68        }
69        else
70        {
71            this->result_ = parse_expr_8();
72            this->remains_ = reading_stream;
73        }
74    }
75
76    //Private functions:
77    /******************/
78    double ExprParser::parse_argument()
79    {
80        double value = parse_expr_8();
81        if (*reading_stream == ',')
82        {
83            ++reading_stream;
84            return value;
85        }
86        else
87        {
88            this->failed_ = true;
89            return 0;
90        }
91    }
92
93    double ExprParser::parse_last_argument()
94    {
95        double value = parse_expr_8();
96        if (*reading_stream == ')')
97        {
98            ++reading_stream;
99            return value;
100        }
101        else
102        {
103            this->failed_ = true;
104            return 0;
105        }
106    }
107
108    double ExprParser::parse_expr_8()
109    {
110        double value = parse_expr_7();
111        for(;;)
112        {
113            switch (op)
114            {
115            case oder:
116                value = parse_expr_7() || value;
117                break;
118            default: return value;
119            }
120        };
121    }
122
123
124    double ExprParser::parse_expr_7()
125    {
126        double value = parse_expr_6();
127        for(;;)
128        {
129            switch (op)
130            {
131            case und:
132                value = value && parse_expr_6();
133                break;
134            default: return value;
135            }
136        };
137    }
138
139    double ExprParser::parse_expr_6()
140    {
141        double value = parse_expr_5();
142        for(;;)
143        {
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    }
157
158    double ExprParser::parse_expr_5()
159    {
160        double value = parse_expr_4();
161        for(;;)
162        {
163            switch (op)
164            {
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;
179            }
180        };
181    }
182
183    double ExprParser::parse_expr_4()
184    {
185        double value = parse_expr_3();
186        for(;;)
187        {
188            switch (op)
189            {
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;
198            }
199        };
200    }
201
202    double ExprParser::parse_expr_3()
203    {
204        double value = parse_expr_2();
205        for(;;)
206        {
207            switch (op)
208            {
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;
223            }
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)
234            {
235            case hoch:
236                value = pow(value,parse_expr_1());
237                break;
238            default:
239                return value;
240            }
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        }
260        else if ((*reading_stream > 47 && *reading_stream < 59) || *reading_stream == 46)
261        {  // number
262            value = strtod(reading_stream, const_cast<char**>(&reading_stream));
263        }
264        else if ((*reading_stream > 64 && *reading_stream < 91) || (*reading_stream > 96 && *reading_stream < 123) || *reading_stream == 46)
265        {  // variable or function
266            char* word = new char[256];
267            parse_word(word);
268            PARSE_BLANKS;
269            if (*reading_stream == '(')
270            {
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                }
353            }
354            else
355            {
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
360                {
361                    this->failed_ = true;
362                    delete[] word;
363                    return 0;
364                }
365            }
366            delete[] word;
367        }
368        else if (*reading_stream == 40)
369        {  // expression in parenthesis
370            ++reading_stream;
371            value = parse_last_argument();
372        }
373        else
374        {
375            this->failed_ = true;
376            return 0;
377        }
378
379        PARSE_BLANKS;
380        switch (op)
381        {
382        case u_nicht: return !value;
383        case u_plus:  return  value;
384        case u_minus: return -value;
385        default:
386            this->failed_ = true;
387            return 0;
388        }
389    }
390
391    char* ExprParser::parse_word(char* str)
392    {
393        char* word = str;
394        int counter = 0;
395        while ((*reading_stream > 47 && *reading_stream < 58) || (*reading_stream > 64 && *reading_stream < 91) || (*reading_stream > 96 && *reading_stream < 123) || *reading_stream == 46)
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;
407    }
408
409    ExprParser::binary_operator ExprParser::parse_binary_operator()
410    {
411        binary_operator op;
412        switch (*reading_stream)
413        {
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;
427        }
428        if (*++reading_stream == '=')
429        {
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            }
440        }
441        else
442            return op;
443    }
444
445    ExprParser::unary_operator ExprParser::parse_unary_operator()
446    {
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        }
461    }
462}
Note: See TracBrowser for help on using the repository browser.