source: cpp/frams/genetics/fL/fL_matheval.cpp @ 1288

Last change on this file since 1288 was 896, checked in by Maciej Komosinski, 5 years ago

Replaced #defined macros for popular random-related operations with functions

File size: 21.2 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include <frams/util/extvalue.h>
6#include <frams/util/sstring.h>
7#include <stack>
8#include "fL_matheval.h"
9#include <frams/genetics/genooperators.h>
10
11// Used available operators in MathEvaluation
12
13double madd(double left, double right)
14{
15        return left + right;
16}
17
18double msub(double left, double right)
19{
20        return left - right;
21}
22
23double mmul(double left, double right)
24{
25        return left * right;
26}
27
28double mand(double left, double right)
29{
30        return left && right;
31}
32
33double mor(double left, double right)
34{
35        return left || right;
36}
37
38double mgreater(double left, double right)
39{
40        return left > right;
41}
42
43double mless(double left, double right)
44{
45        return left < right;
46}
47
48double mequal(double left, double right)
49{
50        return left == right;
51}
52
53double mnotequal(double left, double right)
54{
55        return left != right;
56}
57
58double meqless(double left, double right)
59{
60        return left <= right;
61}
62
63double meqgreater(double left, double right)
64{
65        return left >= right;
66}
67
68// Methods for converting evaluation tokens to string
69
70std::string MathEvaluation::Number::toString()
71{
72        return std::string(SString::valueOf(value).c_str());
73}
74
75std::string MathEvaluation::Variable::toString()
76{
77        if (id == -1) return std::string(1, VARIABLEPREFIX) + "t";
78        return std::string(1, VARIABLEPREFIX) + std::to_string(id);
79}
80
81std::string MathEvaluation::Parenthesis::toString()
82{
83        return ptype == ParenthesisType::OPEN ? "(" : ")";
84}
85
86std::string MathEvaluation::Operator::toString()
87{
88        return opname;
89}
90
91void MathEvaluation::Number::operator=(const Number& src)
92{
93        value = src.value;
94}
95
96double MathEvaluation::Operator::execute(double left, double right)
97{
98        return operation(left, right);
99}
100
101void MathEvaluation::registerOperator(double(*operation)(double left, double right), int precedence, MathEvaluation::Associativity assoc, std::string opsymbol)
102{
103        operators[opsymbol] = new Operator(operation, precedence, assoc, opsymbol);
104        operatorstrings.push_back(opsymbol);
105}
106
107void MathEvaluation::registerOperators()
108{
109        // list of available operators in MathEvaluation
110        registerOperator(madd, 2, Associativity::LEFT, "+");
111        registerOperator(msub, 2, Associativity::LEFT, "-");
112        registerOperator(mmul, 3, Associativity::LEFT, "*");
113        registerOperator(mgreater, 1, Associativity::LEFT, ">");
114        registerOperator(mless, 1, Associativity::LEFT, "<");
115        registerOperator(meqgreater, 1, Associativity::LEFT, ">=");
116        registerOperator(meqless, 1, Associativity::LEFT, "<=");
117        registerOperator(mequal, 1, Associativity::RIGHT, "=");
118        registerOperator(mnotequal, 1, Associativity::RIGHT, "<>");
119        registerOperator(mand, 0, Associativity::LEFT, "&");
120        registerOperator(mor, 0, Associativity::LEFT, "|");
121        arithmeticoperatorscount = 3;
122        comparisonoperatorscount = 6;
123}
124
125void MathEvaluation::clearPostfix()
126{
127        if (!postfixlist.empty())
128        {
129                for (Token *el : postfixlist)
130                {
131                        // only numbers or parenthesis should be removed - operators and
132                        // variables are removed later during destruction of the
133                        // MathEvaluation object
134                        if (el->type == TokenType::NUMBER ||
135                                el->type == TokenType::PARENTHESIS)
136                                delete el;
137                }
138                postfixlist.clear();
139        }
140}
141
142MathEvaluation::MathEvaluation(int varcount) : varcount(varcount), vars(varcount, NULL)
143{
144        registerOperators();
145        for (int i = 0; i < varcount; i++)
146        {
147                vars[i] = new Variable(i);
148        }
149        t = new Variable(-1);
150        t->value = 0;
151}
152
153MathEvaluation::~MathEvaluation()
154{
155        clearPostfix();
156
157        std::unordered_map<std::string, Operator *>::iterator it;
158        for (it = operators.begin(); it != operators.end(); it++)
159        {
160                delete it->second;
161        }
162        operators.clear();
163
164        for (Variable *var : vars)
165        {
166                delete var;
167        }
168        vars.clear();
169        delete t;
170}
171
172int MathEvaluation::convertString(std::string expression)
173{
174        originalexpression = expression;
175        clearPostfix(); //clear previous objects
176        ExtValue val;
177
178        unsigned int it = 0;
179
180        std::list<Token*> operatorstack; // stores operators for later
181
182        bool canbeunary = true; // used to determine if -/+ operators should be unary
183        while (it < expression.size())
184        {
185                bool parsenumber = false;
186                int oplen = 2; // first method checks if 2-character operators match, then 1-character
187
188                // if following letters describe variable
189                if (expression[it] == VARIABLEPREFIX ||
190                        (canbeunary && strchr("+-", expression[it]) &&
191                        it + 1 < expression.size() &&
192                        expression[it + 1] == VARIABLEPREFIX))
193                {
194                        // determine if before variable there is an unary operator '-'
195                        // if yes, the variable will be negated
196                        double mult = expression[it] == '-' ? -1 : 1;
197                        it += expression[it] == VARIABLEPREFIX ? 1 : 2;
198                        // if there is no space after '$' character, return error
199                        if (it >= expression.size())
200                        {
201                                std::string message = "Evaluation error: Invalid variable '";
202                                message += expression.substr(it) + "'";
203                                logMessage("MathEvaluation", "convertString", LOG_ERROR, message.c_str());
204                                while (!operatorstack.empty())
205                                {
206                                        if (operatorstack.back()->type != TokenType::OPERATOR)
207                                        {
208                                                delete operatorstack.back();
209                                        }
210                                        operatorstack.pop_back();
211                                }
212                                return -1;
213                        }
214
215                        //determine id of variable
216                        const char *ptr = expression[it] == 't' ? expression.c_str() + it + 1 : val.parseNumber(expression.c_str() + it, ExtPType::TInt);
217                        int index = expression[it] == 't' ? -1 : val.getInt();
218                        bool invalidid = false;
219                        // if id is parsed properly
220                        if (ptr) // if current element is number, then add it to RPN
221                        {
222                                // if id is exceeding available amount of variables, then variable
223                                // is invalid
224                                if (index >= varcount)
225                                {
226                                        invalidid = true;
227                                }
228                                else
229                                {
230                                        Variable *v = index == -1 ? t : vars[index];
231                                        // if variable had unary '-', then is multiplied by -1
232                                        // multiplying value stored in variable would change value
233                                        // in every occurrence of variable
234                                        if (mult == -1)
235                                        {
236                                                postfixlist.push_back(new Number(-1));
237                                                postfixlist.push_back(v);
238                                                postfixlist.push_back(operators["*"]);
239                                        }
240                                        // push pointer to a variable in order to make evaluation
241                                        // reusable for other values of variables
242                                        else
243                                        {
244                                                postfixlist.push_back(v);
245                                        }
246                                        int offset = ptr - (expression.c_str() + it);
247                                        it += offset;
248                                        // after variable there cannot be unary operator
249                                        canbeunary = false;
250                                }
251                        }
252                        // if parsing of variable went wrong, then return error message
253                        if (!ptr || invalidid)
254                        {
255                                std::string message = "Evaluation error: Invalid variable '";
256                                message += expression.substr(it) + "'";
257                                logMessage("MathEvaluation", "convertString", LOG_ERROR, message.c_str());
258                                while (!operatorstack.empty())
259                                {
260                                        if (operatorstack.back()->type != TokenType::OPERATOR)
261                                        {
262                                                delete operatorstack.back();
263                                        }
264                                        operatorstack.pop_back();
265                                }
266                                return -1;
267                        }
268                }
269                // if current characters describe operators
270                else if ((it + 1 < expression.size() && operators.find(expression.substr(it, oplen)) != operators.end())
271                        || operators.find(expression.substr(it, --oplen)) != operators.end())
272                {
273                        // if operator is + or - and from context it is known that it is
274                        // unary version of one of those operators, then move control to
275                        // number parsing
276                        if (canbeunary && strchr("+-", expression[it]) &&
277                                it + 1 < expression.size() && isdigit(expression[it + 1]))
278                        {
279                                parsenumber = true;
280                        }
281                        else
282                        {
283                                // otherwise prepare pointer to a given operator
284                                Operator *newop = operators[expression.substr(it, oplen)];
285
286                                bool finished = operatorstack.empty();
287
288                                // before operator will be put onto the operator stack, all operators
289                                // with higher precedence than the current operator should be popped
290                                // from the stack and added to postfix list
291                                while (!finished)
292                                {
293
294                                        Token *curr = operatorstack.back();
295                                        // when token in the operator stack is opened parenthesis,
296                                        // then the process of taking operators from stack stops.
297                                        if (curr->type == TokenType::PARENTHESIS)
298                                        {
299                                                Parenthesis *par = (Parenthesis *)curr;
300                                                if (par->ptype == ParenthesisType::OPEN)
301                                                {
302                                                        finished = true;
303                                                }
304                                        }
305                                        else
306                                        {
307                                                // if current operator in stack is left-associated and
308                                                // its precedence is equal or greater than precedence of
309                                                // new operator than current operator is taken from stack
310                                                // and added to postfixlist. If current operator is
311                                                // right-associated, then its precedence must be strictly
312                                                // higher than new operator precedence
313                                                Operator *op = (Operator *)curr;
314                                                if (newop->assoc == Associativity::LEFT && newop->precedence <= op->precedence)
315                                                {
316                                                        postfixlist.push_back(op);
317                                                        operatorstack.pop_back();
318                                                }
319                                                else if (newop->assoc == Associativity::RIGHT && newop->precedence < op->precedence)
320                                                {
321                                                        postfixlist.push_back(op);
322                                                        operatorstack.pop_back();
323                                                }
324                                                else
325                                                {
326                                                        finished = true;
327                                                }
328                                        }
329                                        finished = finished || operatorstack.empty();
330                                }
331                                // after operator there cannot be unary operator - wrap it in
332                                // parenthesis
333                                canbeunary = false;
334                                // add new operator to stack
335                                operatorstack.push_back(newop);
336                                it += oplen;
337                        }
338                }
339                else if (expression[it] == '(' || expression[it] == ')')
340                {
341                        // if current character is open parenthesis, then add it to
342                        // the operator stack
343                        if (expression[it] == '(')
344                        {
345                                Parenthesis *par = new Parenthesis(ParenthesisType::OPEN);
346                                // after open parenthesis there can be unary operator
347                                canbeunary = true;
348                                operatorstack.push_back(par);
349                        }
350                        else
351                        {
352                                // if current character is closed parenthesis, then all operators
353                                // are popped from stack into postfix list until first open
354                                // parenthesis is found
355                                bool finpop = false;
356                                while (!finpop)
357                                {
358                                        // if there is no more operators in the stack, then parenthesis
359                                        // is mismatched
360                                        if (operatorstack.empty())
361                                        {
362                                                logMessage("MathEvaluation", "convertString", LOG_ERROR, "Evaluation error: Parenthesis mismatch");
363                                                return -1;
364                                        }
365                                        Token *curr = operatorstack.back();
366                                        if (curr->type == TokenType::PARENTHESIS)
367                                        {
368                                                // if corresponding parenthesis is found, then opening
369                                                // parenthesis is deleted and removed from stack - postfix
370                                                // notation does not have parenthesis
371                                                Parenthesis *par = (Parenthesis *)curr;
372                                                if (par->ptype == ParenthesisType::OPEN)
373                                                {
374                                                        delete par;
375                                                        operatorstack.pop_back();
376                                                        finpop = true;
377                                                }
378                                        }
379                                        else
380                                        {
381                                                postfixlist.push_back(curr);
382                                                operatorstack.pop_back();
383                                        }
384                                }
385                                // after closed parenthesis unary operators does not exist
386                                canbeunary = false;
387                        }
388                        it++;
389                }
390                else if (isspace(expression[it])) // all whitespaces are skipped
391                {
392                        it++;
393                }
394                else // if above conditions are not satisfied, then method assumes that
395                {    // characters describe number
396                        parsenumber = true;
397                }
398                if (parsenumber)
399                {
400                        // if parsing went successfully, then push number to postfix list
401                        const char *ptr = val.parseNumber(expression.c_str() + it, ExtPType::TDouble);
402                        if (ptr) // if current element is number, then add it to RPN
403                        {
404                                Number *num = new Number(val.getDouble());
405                                postfixlist.push_back(num);
406                                int offset = ptr - (expression.c_str() + it);
407                                it += offset;
408                                // There are no unary operators after number
409                                canbeunary = false;
410                        }
411                        else
412                        {
413                                // otherwise return error
414                                std::string message = "Evaluation error: Invalid letter '";
415                                message += expression[it];
416                                message += "'";
417                                logMessage("MathEvaluation", "convertString", LOG_ERROR, message.c_str());
418                                while (!operatorstack.empty())
419                                {
420                                        if (operatorstack.back()->type != TokenType::OPERATOR)
421                                        {
422                                                delete operatorstack.back();
423                                        }
424                                        operatorstack.pop_back();
425                                }
426                                return -1;
427                        }
428                }
429        }
430
431        // Pop remaining operators from stack and add them to the postfix list
432        while (!operatorstack.empty())
433        {
434                Token *curr = operatorstack.back();
435                if (curr->type == TokenType::OPERATOR)
436                {
437                        postfixlist.push_back(curr);
438                        operatorstack.pop_back();
439                }
440                else
441                {
442                        // if current token in the stack is open parenthesis, then mismatch
443                        // occured
444                        logMessage("MathEvaluation", "convertString", LOG_ERROR, "Evaluation error: Parenthesis mismatch");
445                        while (!operatorstack.empty())
446                        {
447                                if (operatorstack.back()->type != TokenType::OPERATOR)
448                                {
449                                        delete operatorstack.back();
450                                }
451                                operatorstack.pop_back();
452                        }
453                        return -1;
454                }
455        }
456
457        return 0;
458}
459
460int MathEvaluation::evaluateRPN(double &res)
461{
462        // stack holds number used during operator execution
463        std::stack<Number *> numberstack;
464        for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++)
465        {
466                Token *tok = (*it);
467                // if token is number or variable - add it to number stack
468                if (tok->type == TokenType::NUMBER || tok->type == TokenType::VARIABLE)
469                {
470                        Number *num = new Number(((Number *)tok)->value);
471                        numberstack.push(num);
472                }
473                else
474                {
475                        // the token is an operator
476                        Operator *op = (Operator *)tok;
477                        // if there isn't at least 2 elements in number stack, then return error
478                        if (numberstack.size() < 2)
479                        {
480                                logMessage("MathEvaluation", "convertString", LOG_ERROR, "Evaluation error: The math expression is not complete");
481                                while (!numberstack.empty())
482                                {
483                                        if (numberstack.top()->type == TokenType::NUMBER) delete numberstack.top();
484                                        numberstack.pop();
485                                }
486                                return -1;
487                        }
488                        // otherwise, pop two top elements from number stack and use them
489                        // with current operator
490                        double right = numberstack.top()->value;
491                        if (numberstack.top()->type == TokenType::NUMBER) delete numberstack.top();
492                        numberstack.pop();
493                        double left = numberstack.top()->value;
494                        if (numberstack.top()->type == TokenType::NUMBER) delete numberstack.top();
495                        numberstack.pop();
496                        double result = op->execute(left, right);
497                        Number *newnum = new Number(result);
498                        // Push operation result to number stack
499                        numberstack.push(newnum);
500                }
501        }
502
503        // in the end of processing, only 1 element should be available in number stack.
504        // Otherwise expression was not complete and error will be returned
505        if (numberstack.size() != 1)
506        {
507                logMessage("MathEvaluation", "convertString", LOG_ERROR, "Evaluation error: The math expression is not complete");
508                while (!numberstack.empty())
509                {
510                        if (numberstack.top()->type == TokenType::NUMBER) delete numberstack.top();
511                        numberstack.pop();
512                }
513                return -1;
514        }
515
516        res = numberstack.top()->value;
517        if (numberstack.top()->type == TokenType::NUMBER) delete numberstack.top();
518        numberstack.pop();
519        return 0;
520}
521
522void MathEvaluation::modifyVariable(int i, double val)
523{
524        if (i == -1)
525        {
526                t->value = val;
527        }
528        else
529        {
530                if (!vars[i])
531                {
532                        vars[i] = new Variable(i);
533                }
534                vars[i]->value = val;
535        }
536}
537
538int MathEvaluation::evaluate(std::string expression, double &result)
539{
540        int res = convertString(expression);
541        if (res != 0) return res;
542        return evaluateRPN(result);
543}
544
545int MathEvaluation::RPNToInfix(std::string &result)
546{
547        if (postfixlist.size() == 0)
548        {
549                result = "";
550                return 0;
551        }
552        // stack holds stringified chunk and its precedence
553        std::stack<std::pair<std::string, int>> chunks;
554        // foreach token in postfix list
555        for (Token *tok : postfixlist)
556        {
557                // if token is not an operator, push stringified variable or number
558                // on top of stack
559                if (tok->type != TokenType::OPERATOR)
560                {
561                        // number or variable has no precedence
562                        chunks.push({ tok->toString(), -1 });
563                }
564                else // if token is an operator
565                {
566                        Operator *op = (Operator *)tok;
567                        int prec = op->precedence;
568                        // if there are not at least two stringified chunks in stack, return error
569                        if (chunks.size() < 2)
570                        {
571                                logMessage("MathEvaluation", "RPNToInfix", LOG_ERROR,
572                                        "Could not convert RPN notation to infix notation");
573                                return -1;
574                        }
575                        // pop first chunk
576                        std::pair<std::string, int> right = chunks.top();
577                        chunks.pop();
578                        if (right.second != -1 && right.second < op->precedence)
579                        {
580                                // if chunk on the right of operator has lower precedence than
581                                // this operator, then wrap it with parenthesis
582                                right.first = std::string(1, '(') + right.first + std::string(1, ')');
583                        }
584                        else if (right.second >= op->precedence)
585                        {
586                                prec = right.second;
587                        }
588                        std::pair<std::string, int> left = chunks.top();
589                        chunks.pop();
590                        if (left.second != -1 && left.second < op->precedence)
591                        {
592                                // if chunk on the left of operator has lower precedence than
593                                // this operator, then wrap it with parenthesis
594                                left.first = std::string(1, '(') + left.first + std::string(1, ')');
595                        }
596                        std::string res = left.first + op->toString() + right.first;
597                        // add summed chunk
598                        chunks.push({ res, prec });
599                }
600        }
601        // if there is more than one chunk then return error
602        if (chunks.size() != 1)
603        {
604                logMessage("MathEvaluation", "RPNToInfix", LOG_ERROR,
605                        "Could not convert RPN notation to infix notation - formula is not complete");
606                return -1;
607        }
608        result = chunks.top().first;
609        chunks.pop();
610        return 0;
611}
612
613void MathEvaluation::mutateValueOrVariable(MathEvaluation::Number *&currval, bool usetime)
614{
615        if (rndUint(2) == 0 && varcount > 0) // use variable
616        {
617                if (currval && currval->type == TokenType::NUMBER)
618                {
619                        delete currval;
620                }
621                int var = rndUint(varcount + (usetime ? 1 : 0));
622                if (varcount == var) // time is used
623                {
624                        currval = t;
625                }
626                else
627                {
628                        currval = vars[var];
629                }
630        }
631        else
632        {
633                if (!currval || currval->type == TokenType::VARIABLE)
634                {
635                        currval = new Number(rndDouble(1));
636                }
637                else
638                {
639                        currval->value = rndDouble(1);
640                }
641        }
642}
643
644MathEvaluation::Operator* MathEvaluation::getRandomOperator(int type)
645{ // 0 for all, 1 for arithmetic only, 2 for logical only
646        int randop = type == 2 ? arithmeticoperatorscount : 0;
647        int count = arithmeticoperatorscount;
648        if (type == 0)
649        {
650                count = operatorstrings.size();
651        }
652        else if (type == 2)
653        {
654                count = operatorstrings.size() - arithmeticoperatorscount;
655        }
656        randop += rndUint(count);
657        return operators[operatorstrings[randop]];
658}
659
660void MathEvaluation::mutateConditional()
661{
662        if (varcount > 0)
663        {
664                int currsize = postfixlist.size();
665                int varid = rndUint(varcount);
666                postfixlist.push_back(vars[varid]);
667                if (rndUint(2) == 0 && varcount > 1)
668                {
669                        int varid2 = rndUint(varcount - 1);
670                        if (varid2 >= varid) varid2++;
671                        postfixlist.push_back(vars[varid2]);
672                }
673                else
674                {
675                        Number *num = new Number(rndDouble(1));
676                        postfixlist.push_back(num);
677                }
678                int opid = arithmeticoperatorscount + rndUint(comparisonoperatorscount);
679                postfixlist.push_back(operators[operatorstrings[opid]]);
680                if (currsize > 0)
681                {
682                        postfixlist.push_back(operators["&"]);
683                }
684        }
685}
686
687int MathEvaluation::mutate(bool logical, bool usetime)
688{
689        if (postfixlist.size() == 0)
690        {
691                Number *val = new Number(rndDouble(1));
692                postfixlist.push_back(val);
693                return -1;
694        }
695        int method = rndUint(postfixlist.size() < MAX_MUT_FORMULA_SIZE ? MATH_MUT_COUNT : MATH_MUT_COUNT - 1);
696        switch (method)
697        {
698        case MATH_MUT_INSERTION:
699        {
700                std::list<Token *> insertpair;
701                Number *val = NULL;
702                mutateValueOrVariable(val, usetime);
703                insertpair.push_back(val);
704                std::list<Token *>::iterator it = postfixlist.begin();
705                // insertion can be applied from 1st occurrence
706                int insertlocation = 1 + rndUint(postfixlist.size() - 1);
707                std::advance(it, insertlocation);
708                Operator *rndop;
709                if (insertlocation == (int)postfixlist.size() - 1)
710                {
711                        rndop = getRandomOperator(logical ? 2 : 1);
712                }
713                else
714                {
715                        rndop = getRandomOperator(logical ? 0 : 1);
716
717                }
718                insertpair.push_back(rndop);
719                postfixlist.insert(it, insertpair.begin(), insertpair.end());
720                break;
721        }
722        case MATH_MUT_CHANGEVAL:
723        {
724                std::vector<std::list<Token *>::iterator> numbersineval;
725                int id = 0;
726                for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++)
727                {
728                        if ((*it)->type == TokenType::NUMBER || (*it)->type == TokenType::VARIABLE)
729                        {
730                                numbersineval.push_back(it);
731                        }
732                        id++;
733                }
734                int randid = rndUint(numbersineval.size());
735                Number *numptr = (Number *)(*numbersineval[randid]);
736                mutateValueOrVariable(numptr, usetime);
737                (*numbersineval[randid]) = numptr;
738                break;
739        }
740        case MATH_MUT_CHANGEOPER:
741        {
742                std::vector<std::list<Token *>::iterator> ops;
743                for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++)
744                {
745                        if ((*it)->type == TokenType::OPERATOR)
746                        {
747                                ops.push_back(it);
748                        }
749                }
750                if (ops.size() > 0)
751                {
752                        int randid = rndUint(ops.size());
753                        Operator *rndop;
754                        if (randid == (int)ops.size() - 1)
755                        {
756                                rndop = getRandomOperator(logical ? 2 : 1);
757                        }
758                        else
759                        {
760                                rndop = getRandomOperator(logical ? 0 : 1);
761                        }
762                        (*ops[randid]) = rndop;
763                }
764                break;
765        }
766        case MATH_MUT_DELETION:
767        {
768                std::list<Token *>::iterator it = postfixlist.begin();
769                std::vector<std::list<Token *>::iterator> firstofpairs;
770                while (it != postfixlist.end())
771                {
772                        if ((*it)->type == TokenType::NUMBER || (*it)->type == TokenType::VARIABLE)
773                        {
774                                std::list<Token *>::iterator next = it;
775                                next++;
776                                if (next != postfixlist.end() && (*next)->type == TokenType::OPERATOR)
777                                {
778                                        firstofpairs.push_back(it);
779                                }
780                        }
781                        it++;
782                }
783                if (firstofpairs.size() > 0)
784                {
785                        int rndid = rndUint(firstofpairs.size());
786                        if ((*firstofpairs[rndid])->type == TokenType::NUMBER)
787                        {
788                                delete (*firstofpairs[rndid]);
789                        }
790                        firstofpairs[rndid] = postfixlist.erase(firstofpairs[rndid]);
791                        postfixlist.erase(firstofpairs[rndid]);
792                }
793                break;
794        }
795        }
796        return method;
797}
798
799std::string MathEvaluation::getStringifiedRPN()
800{
801        std::string res = "";
802        for (Token *el: postfixlist)
803        {
804                res += el->toString();
805                res += " ";
806        }
807        return res;
808}
Note: See TracBrowser for help on using the repository browser.