Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1894 was 1894, checked in by rgrieder, 16 years ago
  • Converted ExprParser to 4 spaces/tab
  • Tiny little bug in String.cc
  • Property svn:eol-style set to native
File size: 10.8 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        this->failed_ = true;
376        return 0;
377    }
378}
379
380char* ExprParser::parse_word(char* str)
381{
382    char* word = str;
383    int counter = 0;
384    while (*reading_stream > 47 && *reading_stream < 58 || *reading_stream > 64 && *reading_stream < 91 || *reading_stream > 96 && *reading_stream < 123 || *reading_stream == 46)
385    {
386        *word++ = *reading_stream++;
387        counter++;
388        if (counter > 255)
389        {
390            this->failed_ = true;
391            return '\0';
392        }
393    };
394    *word = '\0';
395    return str;
396}
397
398ExprParser::binary_operator ExprParser::parse_binary_operator()
399{
400    binary_operator op;
401    switch (*reading_stream)
402    {
403    case '+': op = b_plus; break;
404    case '-': op = b_minus; break;
405    case '*': op = mal; break;
406    case '/': op = durch; break;
407    case '^': op = hoch; break;
408    case '%': op = modulo; break;
409    case '&': op = und; break;
410    case '|': op = oder; break;
411    case '=': op = gleich; break;
412    case '!': op = b_nicht; break;
413    case '<': op = kleiner; break;
414    case '>': op = groesser; break;
415    default: return undef;
416    }
417    if (*++reading_stream == '=')
418    {
419        if (op > 9)
420        {
421            ++reading_stream;
422            return (binary_operator)(op + 3);
423        }
424        else
425        {
426            --reading_stream;
427            return undef;
428        }
429    }
430    else
431        return op;
432}
433
434ExprParser::unary_operator ExprParser::parse_unary_operator()
435{
436    switch (*reading_stream)
437    {
438    case '!':
439        ++reading_stream;
440        return u_nicht;
441    case '+':
442        ++reading_stream;
443        return u_plus;
444    case '-':
445        ++reading_stream;
446        return u_minus;
447    default :
448        return u_plus;
449    }
450}
Note: See TracBrowser for help on using the repository browser.