1 #include "calcparser.h"
2 
3 
4 static String _Errors[] = {QObject::tr("Unknown error!"), QObject::tr("Syntax error"), QObject::tr("Unclosed parenthesis"),
5      QObject::tr("Unknown function"), QObject::tr("Division by zero!"),
6      QObject::tr("Invalid argument"), QObject::tr("Value is too large"), QObject::tr("Undefined variable"),
7      QObject::tr("Empty parentheses"), QObject::tr("Type mismatch"), QObject::tr("Readonly variable")};
8 
9 
10 static String VarTypes[] = {"float", "string"};
11 
12 
13 
14 //----------------------------------------------------------------------------------------------------------------------
CalcParser(String * pexpr)15 CalcParser::CalcParser(String *pexpr)
16 {
17     token_end.SetType(t_type::END);
18     token_end.SetValue("END");
19     SetParams(pexpr);
20     InitMapToksHtml();
21     InitFuncs();
22 
23     SetVariable("pi", DoubleToString(PI), e_type_var::FLOAT, true);
24     SetVariable("e", DoubleToString(static_cast<double>(exp(1))), e_type_var::FLOAT, true);
25 }
26 
27 //----------------------------------------------------------------------------------------------------------------------
~CalcParser()28 CalcParser::~CalcParser()
29 {
30     Tokens.clear();
31     Vars.clear();
32     ToksHtml.clear();
33 
34     for (auto mf: map_funcs) { delete mf.second;}
35     map_funcs.clear();
36     delete result;
37 }
38 
39 
40 //----------------------------------------------------------------------------------------------------------------------
SetVariable(String name,String value,e_type_var type,bool readonly)41 void CalcParser::SetVariable(String name, String value, e_type_var type, bool readonly)
42 {
43     if(name.isEmpty() || name == "") return;
44 
45     Variable var(name, value, type);
46     var.read_only = readonly;
47     Vars[var.name] = var;
48 }
49 
50 
51 //----------------------------------------------------------------------------------------------------------------------
Run(void)52 bool CalcParser::Run(void)
53 {
54     bool res = true;
55     result->SetValue(0);
56     i_toks = Tokens.begin();
57     do
58     {
59         res &= Calculate(result);
60     }while(token->Type() == t_type::ENDLINE);
61     return res;
62 }
63 
64 //----------------------------------------------------------------------------------------------------------------------
Calculate(CValue * loc_result)65 bool CalcParser::Calculate(CValue *loc_result)
66 {
67     GetToken();
68     while(token->Type() != t_type::ENDLINE && token->Type() != t_type::END)
69     {
70         result->SetType(e_type_var::FLOAT);
71         Add_exp(loc_result);
72         if(token->Type() != t_type::ENDLINE && token->Type() != t_type::END)
73             Error(errors::SYNTAX);
74 
75     }
76     return !HasErr();
77 }
78 
79 //----------------------------------------------------------------------------------------------------------------------
InitVariableFromExpression()80 bool CalcParser::InitVariableFromExpression()
81 {
82     Token t0, t1;
83     Token *t = token;
84     String var;
85     TokenList::iterator it = i_toks;
86     CValue res;
87     Variable v;
88 
89     t0 = *token;
90     if(t0.Type() == t_type::VARIABLE)
91     {
92         GetToken();
93         t1 = *token;
94         if(t1.Value() == "=")
95         {
96             var = t0.Value();
97 
98             binit_var = true;
99 
100             GetToken();
101             Add_exp(&res);
102             if(!this->HasErr())
103             {
104                 VarList::const_iterator var_it = Vars.find(var);
105                 if(var_it != Vars.end())
106                 {
107                     v = VariableByIterator(var_it);
108                     if(v.read_only)
109                     {
110                         Error(errors::RO);
111                         return false;
112                     }
113 
114                 }
115 
116                 v.type = t0.type_var;
117                 if(v.type != res.Type())
118                 {
119                     Error(errors::TMS);
120                     return false;
121                 }
122                 v.name = var;
123                 if(v.type == e_type_var::FLOAT)
124                     v.value = DoubleToString(res.ValueFloat());
125                 else
126                     v.value = res.ValueString();
127 
128                 Vars[var] = v;
129                 return true;
130             }
131             else
132                 return false;
133 
134         }
135     }
136     i_toks = it;
137     token = t;
138     return false;
139 }
140 
141 //----------------------------------------------------------------------------------------------------------------------
InitExpr(String * pexpr)142 void CalcParser::InitExpr(String *pexpr)
143 {
144     binit_var = false;
145     if(pexpr == nullptr)
146         expr = "";
147     else
148         expr = *pexpr;
149 
150     lc = localeconv();// надо перенести в расчет
151     if(lc)
152         dec_point.insert(0, lc->decimal_point);
153 
154     token = &token_end;
155 }
156 
157 
158 //----------------------------------------------------------------------------------------------------------------------
SetParams(String * pexpr,int scale,Drg DRG_mode)159 void CalcParser::SetParams(String *pexpr, int scale, Drg DRG_mode)
160 {
161     err = errors::SUCCESS;
162     result->SetType(e_type_var::FLOAT);
163 
164     InitExpr(pexpr);
165 
166     SetScale(scale);
167     SetDRG(DRG_mode);
168     LoadTokens();
169 }
170 
171 
172 //----------------------------------------------------------------------------------------------------------------------
SetScale(int scale)173 void CalcParser::SetScale(int scale)
174 {
175     Token *t;
176     double number;
177     String s;
178     int prev_scale = this->scale;
179 
180     this->scale = scale;
181 
182     for(auto i = Tokens.begin(); i != Tokens.end(); ++i)
183     {
184         t = &(*i);
185         if(t->Type() == t_type::NUMBER)
186         {
187             number = ScaleToVal(t->Value(), prev_scale);
188             t->SetValue(DoubleToString(number));
189         }
190     }
191 }
192 
193 
194 //----------------------------------------------------------------------------------------------------------------------
Scale()195 int CalcParser::Scale()
196 {
197     return scale;
198 }
199 
200 
201 //----------------------------------------------------------------------------------------------------------------------
SetDRG(Drg drg_mode)202 void CalcParser::SetDRG(Drg drg_mode)
203 {
204     this->DRG_mode = drg_mode;
205 }
206 
207 
208 //----------------------------------------------------------------------------------------------------------------------
DRG()209 Drg CalcParser::DRG()
210 {
211     return DRG_mode;
212 }
213 
214 
215 //----------------------------------------------------------------------------------------------------------------------
LoadTokens()216 void CalcParser::LoadTokens()
217 {
218     Token *nTok;
219 
220     exp_p = expr.begin();
221     Tokens.clear();
222 
223     while((nTok = LoadToken()) != nullptr)
224     {
225         if(nTok->Type() == t_type::VARIABLE)
226         {
227             auto var_it = Vars.find(nTok->Value());
228             if(var_it != Vars.end())
229             {
230                 Variable v = VariableByIterator(var_it);
231                 nTok->type_var = v.type;
232             }
233         }
234         if(nTok->Value() == ",")
235             nTok->SetType(t_type::COMMA);
236         Tokens.push_back(*nTok);
237         delete nTok;
238     }
239 }
240 
241 
242 //----------------------------------------------------------------------------------------------------------------------
CheckParentheses()243 int CalcParser::CheckParentheses()
244 {
245    int res = 0;
246    auto i = Tokens.begin();
247    Token t;
248 
249    while(i != Tokens.end())
250    {
251        t = *i++;
252        if(t.Value() == "(" || t.Type() == t_type::FUNCTION)
253            res++;
254        if(t.Value() == ")")
255            res--;
256    }
257    return res;
258 }
259 
260 
261 //----------------------------------------------------------------------------------------------------------------------
FindParentheses()262 TokenList::iterator CalcParser::FindParentheses()
263 {
264     int res = 0;
265     auto i = Tokens.end();
266     Token t;
267 
268     if(Tokens.empty())
269         return Tokens.end();
270 
271     while(i-- != Tokens.begin())
272     {
273         t = *i;
274 
275         if(t.Value() == "(" || t.Type() == t_type::FUNCTION)
276             res++;
277         if(t.Value() == ")")
278             res--;
279         if(0 == res)
280             break;
281     }
282     if((t.Value() == "(" || t.Type() == t_type::FUNCTION) && res == 0)
283         return i;
284     return Tokens.end();
285 }
286 
287 
288 //----------------------------------------------------------------------------------------------------------------------
InvExpInNumber(Token * tok)289 bool CalcParser::InvExpInNumber(Token* tok)
290 {
291     int index;
292     String value;
293 
294     if(!tok)
295         return false;
296     value = tok->Value();
297     if(value.indexOf('e') == -1)
298         return false;
299 
300     index = value.indexOf('+');
301     if(index != -1)
302     {
303         value[index] = '-';
304         tok->SetValue(value);
305         return true;
306     }
307     index = value.indexOf('-');
308     if(index != -1)
309     {
310         value[index] = '+';
311         tok->SetValue(value);
312         return true;
313     }
314     return false;
315 }
316 
317 
318 //----------------------------------------------------------------------------------------------------------------------
AddPrefixInverse()319 bool CalcParser::AddPrefixInverse()
320 {
321     EraseErrors();
322 
323     Token *ltok = LastToken();
324     Token before_tok;
325     Token before_before_tok;
326     auto i = Tokens.end();
327     decltype(i) before_i;
328 
329         if(ltok->Type() == t_type::NUMBER || ltok->Value() == ")")
330         {
331             if(ltok->Type() == t_type::NUMBER)
332                 before_i = --i;
333             else
334                 before_i = i = FindParentheses();
335 
336             if(i == Tokens.begin())
337             {
338                 before_tok = *i;
339                 before_before_tok = token_end;
340             }
341             else
342             {
343                 before_tok = *--i;
344                 if(i == Tokens.begin())
345                     before_before_tok = *i;
346                 else
347                     before_before_tok = *--i;
348             }
349 
350             if(before_tok.Value() == "/" && before_before_tok.Value() == "1")
351             {
352                 i = Tokens.erase(i);
353                 Tokens.erase(i);
354             }
355             else
356             {
357                 before_i = Tokens.insert(before_i, *(new Token("/", t_type::DELIMITER)));
358                 Tokens.insert(before_i, *(new Token("1", t_type::NUMBER)));
359             }
360             return true;
361         }
362         return false;
363 }
364 
365 
366 //----------------------------------------------------------------------------------------------------------------------
AddPrefixOp(String op)367 bool CalcParser::AddPrefixOp(String op)
368 {
369     EraseErrors();
370 
371     Token *ltok = LastToken();
372     Token before_tok;
373     auto i = Tokens.end();
374     decltype(i) before_i;
375 
376     if(op == "1/")
377         return AddPrefixInverse();
378 
379     if(op == "-" || op == "~")
380     {
381         if(ltok->Type() == t_type::NUMBER || ltok->Value() == ")")
382         {
383             if(ltok->Type() == t_type::NUMBER)
384             {
385                 if(InvExpInNumber(ltok))
386                     return true;
387                 else
388                     before_i = --i;
389             }
390             else
391                 before_i = i = FindParentheses();
392 
393             if(i == Tokens.begin())
394                 before_tok = *i;
395             else
396                 before_tok = *(--i);
397 
398             if((before_tok.Value() == op || before_tok.Value() == "+") && before_tok.prefix)
399             {
400                 Tokens.erase(i);
401                 return true;
402             }
403             else
404             {
405                 if(before_tok.Value() == "-" && before_tok.prefix && op == "~")
406                     return false;
407                 if(before_tok.Value() == "~" && before_tok.prefix && op == "-")
408                     return false;
409 
410                 Tokens.insert(before_i, *(new Token(op, t_type::DELIMITER, true)));
411                 return true;
412             }
413         }
414     }
415     return false;
416 }
417 
418 
419 //----------------------------------------------------------------------------------------------------------------------
AddToken(String * pexpr)420 bool CalcParser::AddToken(String *pexpr)
421 {
422     if(*pexpr == "+/-")
423         return AddPrefixOp("-");
424     if(*pexpr == "1/x")
425         return AddPrefixOp("1/");
426     if(*pexpr == "exp")
427         *pexpr = ".e+";
428 
429     InitExpr(pexpr);
430     Token *nTok;
431     Token *ltok;
432     bool res = true;
433 
434     EraseErrors();
435     exp_p = expr.begin();
436 
437     while((nTok = LoadToken()) != nullptr)
438     {
439         if(nTok->Value() == "del") //для отладки
440         {
441             ToBack();
442         }
443         else
444         {
445             ltok = LastToken();
446 
447             if(nTok->Type() == t_type::NUMBER)
448             {
449                 if(nTok->Value() == "." && (ltok->Type() == t_type::END || ltok->Type() != t_type::NUMBER))
450                     nTok->SetValue("0" + nTok->Value());
451 
452                 if(ltok->Type() == t_type::NUMBER)
453                 {
454                     if(ltok->Value().indexOf('.') != -1 && nTok->Value() == ".e+")
455                         nTok->SetValue("e+");
456 
457                     if(ltok->Value().indexOf('.') != -1 && nTok->Value().indexOf('.') != -1)
458                         return false;
459                     if(ltok->Value().indexOf('e') != -1 && nTok->Value().indexOf('e') != -1)
460                         return false;
461                     if(ltok->Value().indexOf('i') != -1 && nTok->Value().indexOf('i') != -1)
462                         return false;
463 
464                     ltok->Add(nTok->Value());
465                 }
466                 else
467                 {
468                     if(!(ltok->Value() == ")" || ltok->Type() == t_type::VARIABLE))
469                         Tokens.push_back(*nTok);
470                     else
471                         res = false;
472                 }
473             }
474             else
475                 if(nTok->Value() == "(")
476                 {
477                     if(ltok->Type() != t_type::NUMBER && ltok->Type() != t_type::VARIABLE && ltok->Value() != ")")
478                         Tokens.push_back(*nTok);
479                     else
480                         res = false;
481                 }
482             else
483                 if(nTok->Value() == ")")
484                 {
485                     if(ltok->Type() == t_type::NUMBER || ltok->Type() == t_type::VARIABLE || ltok->Value() == ")")
486                     {
487                         Tokens.push_back(*nTok);
488                         if(CheckParentheses() < 0)
489                         {
490                             nTok->SetValue("(");
491                             Tokens.push_front(*nTok);
492                         }
493                     }
494                     else
495                         res = false;
496                 }
497             else
498                 if(nTok->Type() == t_type::FUNCTION || nTok->Type() == t_type::VARIABLE)
499                 {
500                     if(ltok->Type() != t_type::NUMBER && ltok->Value() != ")" && ltok->Type() != t_type::VARIABLE)
501                         Tokens.push_back(*nTok);
502                     else
503                         res = false;
504                 }
505             else
506                 if(nTok->Type() == t_type::DELIMITER)
507                 {
508                     if((ltok->Type() != t_type::DELIMITER && ltok->Type() != t_type::END && ltok->Type() != t_type::FUNCTION)
509                             || ltok->Value() == ")")
510                     {
511                         if(nTok->Value() == "~")
512                             res = AddPrefixOp(nTok->Value());
513                         else
514                             Tokens.push_back(*nTok);
515                     }
516                     else
517                     {
518                         if((nTok->Value() == "+" || nTok->Value() == "-" || nTok->Value() == "~")
519 
520                                 && (!ltok->prefix))
521                         {
522                             nTok->prefix = true;
523                             Tokens.push_back(*nTok);
524                         }
525                         else
526                             res = false;
527                     }
528                 }
529             else
530                     res = false;
531         }
532         delete nTok;
533         if(!res)
534             break;
535 
536     }
537     return res;
538 }
539 
540 //----------------------------------------------------------------------------------------------------------------------
LastToken()541 Token* CalcParser::LastToken()
542 {
543     if(Tokens.empty())
544         return &token_end;
545     auto i = Tokens.end();
546     Token *t = &(*--i);
547     return t;
548 }
549 
550 
551 //----------------------------------------------------------------------------------------------------------------------
LastTokenValue()552 String CalcParser::LastTokenValue()
553 {
554     return LastToken()->Value();
555 }
556 
557 
558 //----------------------------------------------------------------------------------------------------------------------
ToBack(bool lastdigit)559 void CalcParser::ToBack(bool lastdigit)
560 {
561     bool cutnumber = false;
562 
563     EraseErrors();
564     Token *lastT = LastToken();
565 
566     if(lastT->Type() != t_type::END)
567     {
568         if(lastdigit)
569             cutnumber = lastT->CutNumber();
570         if(!cutnumber)
571         {
572             if(lastT->Value() == ")")
573             {
574                 auto itP = FindParentheses();
575                 if(itP == Tokens.begin() && (static_cast<Token*>(&(*itP))->Type()) != t_type::FUNCTION)
576                     Tokens.pop_front();
577             }
578 
579             Tokens.pop_back();
580             //i_toks = Tokens.end() - 1;
581         }
582     }
583 }
584 
585 
586 //----------------------------------------------------------------------------------------------------------------------
TypeRes()587 e_type_var CalcParser::TypeRes()
588 {
589     return result->Type();
590 }
591 
592 
593 //----------------------------------------------------------------------------------------------------------------------
HasErr()594 bool CalcParser::HasErr()
595 {
596     for (Token t: Tokens) { err = t.Err(); if (err != errors::SUCCESS) break;}
597     return err != errors::SUCCESS;
598 }
599 
600 
601 //----------------------------------------------------------------------------------------------------------------------
GetResult()602 double CalcParser::GetResult()
603 {
604     return RoundS(result->ValueFloat(), PRECISION_FOR_DOUBLE);
605 }
606 
607 
608 //----------------------------------------------------------------------------------------------------------------------
GetResultStr()609 String CalcParser::GetResultStr()
610 {
611     return result->ValueString();
612 }
613 
614 
615 //----------------------------------------------------------------------------------------------------------------------
ReadVariableToken(Token * loc_token)616 void CalcParser::ReadVariableToken(Token *loc_token)
617 {
618     while(isalpha(*exp_p) || strchr("1234567890", *exp_p))
619         loc_token->Add(*exp_p++);
620     if(*exp_p == '(')
621     {
622         loc_token->SetType(t_type::FUNCTION);
623         loc_token->Add(*exp_p++);
624     }
625     else
626         loc_token->SetType(t_type::VARIABLE);
627 
628 }
629 
630 
631 //----------------------------------------------------------------------------------------------------------------------
LoadToken()632 Token* CalcParser::LoadToken()
633 {
634     Token *loc_token;
635 
636     while(Space(*exp_p))
637         ++exp_p;
638 
639     if (exp_p >= expr.end())
640         return nullptr;
641 
642     loc_token = new Token();
643 
644     if(strchr("*/+-()%^!&|~=", *exp_p))
645     {
646         loc_token->SetType(t_type::DELIMITER);
647         loc_token->Add(*exp_p++);
648         //if(loc_token->Value() == "=")
649         //    exp_p = expr.end();
650     }
651 
652     else
653     if(strchr("<>", *exp_p))
654     {
655         loc_token->SetType(t_type::DELIMITER);
656         if(*exp_p == '<' && *(exp_p + 1) == '<')
657             loc_token->Add("<<");
658         else
659         if(*exp_p == '>' && *(exp_p + 1) == '>')
660             loc_token->Add(">>");
661         else
662             Error(errors::SYNTAX, loc_token);
663 
664         exp_p += 2;
665     }
666     else
667         if(isalpha(*exp_p))
668         {
669             ReadVariableToken(loc_token);
670             if(loc_token->Type() == t_type::VARIABLE)
671             {
672                 if(loc_token->Value() == VarTypes[1]) //строковая переменная
673                 {
674                     loc_token->SetValue("");
675                     while(Space(*exp_p) && exp_p != expr.end())
676                         ++exp_p;
677 
678                     if(isalpha(*exp_p))
679                     {
680                         ReadVariableToken(loc_token);
681                         if(loc_token->Type() == t_type::VARIABLE)
682                             loc_token->type_var = e_type_var::STRING;
683                         else
684                             Error(errors::SYNTAX, loc_token);
685                     }
686                     else
687                         Error(errors::SYNTAX, loc_token);
688                 }
689             }
690         }
691     else
692     if(isdigit(*exp_p) && !strchr("ie+-", *exp_p))
693     {
694         while(isdigit(*exp_p))
695         {
696             if(*exp_p == 'e')
697             {
698                 if(strchr("-+",*(exp_p + 1)))
699                     loc_token->Add(*exp_p++);
700                 else
701                     Error(errors::SYNTAX, loc_token);
702             }
703             loc_token->Add(*exp_p++);
704         }
705         loc_token->SetType(t_type::NUMBER);
706     }
707     else
708     if(*exp_p == ';')
709     {
710         loc_token->Add(*exp_p++);
711         loc_token->SetType(t_type::ENDLINE);
712     }
713     else
714     if(*exp_p == '"')
715     {
716         ++exp_p;
717         while(exp_p != expr.end() && *exp_p != '"')
718             loc_token->Add(*exp_p++);
719 
720         if(*exp_p++ != '"')
721             Error(errors::SYNTAX, loc_token);
722 
723         loc_token->SetType(t_type::TEXT);
724         loc_token->type_var = e_type_var::STRING;
725     }
726     else
727     {
728         loc_token->Add(*exp_p++);
729         loc_token->SetType(t_type::UNK);
730     }
731     return loc_token;
732 }
733 
734 
735 //----------------------------------------------------------------------------------------------------------------------
GetToken()736 void CalcParser::GetToken()
737 {
738     token = &token_end;
739     if(i_toks == Tokens.end())
740         return;
741     token = &(*i_toks++);
742 }
743 
744 
745 //----------------------------------------------------------------------------------------------------------------------
GetExpression(String eq,bool html)746 String CalcParser::GetExpression(String eq, bool html)
747 {
748     if(binit_var)
749         return "";
750 
751     String es = "";
752     String number_color, function_color, delimiter_color, default_color;
753     String b_tag, e_tag;
754     String def_expr = "0";
755     Token t, next_t;
756     bool empty = Tokens.empty();
757     String space;
758     String tokVal;
759     MapStrings::const_iterator mit;
760 
761     if(empty)
762         AddToken(&def_expr);
763 
764     auto tit = Tokens.begin();
765 
766     default_color = GetStrValueVariable("default_color");
767     number_color = GetStrValueVariable("number_color");
768     function_color = GetStrValueVariable("function_color");
769     delimiter_color = GetStrValueVariable("delimiter_color");
770 
771     this->eq = eq;
772     while(tit != Tokens.end())
773     {
774         t = *tit++;
775         if(t.Type() != t_type::ERR)
776         {
777             tokVal = t.Value();
778 
779             b_tag = e_tag = "";
780 
781             space = " ";
782             next_t = token_end;
783             if(tit != Tokens.end())
784             {
785                 next_t = *tit;
786                 if(next_t.Type() == t_type::ERR)
787                     next_t.SetType(t_type::END);
788             }
789 
790             if(html)
791             {
792                 b_tag = "<FONT color=" + default_color + ">";
793                 if(t.Type() == t_type::NUMBER || t.prefix)
794                     b_tag = "<FONT color=" + number_color + ">";
795                 if(t.Type() == t_type::FUNCTION)
796                     b_tag = "<FONT color=" + function_color + ">";
797                 if(t.Type() == t_type::DELIMITER && t.Value() != ")" && t.Value() != "(" && !t.prefix)
798                     b_tag = "<FONT color=" + delimiter_color + ">";
799                 e_tag = "</FONT>";
800 
801                 if(t.Type() == t_type::FUNCTION)
802                     tokVal.remove('(');
803 
804                 mit = ToksHtml.find(tokVal);
805                 if(mit != ToksHtml.end())
806                     tokVal = mit->second;
807                 if(t.Type() == t_type::FUNCTION)
808                     tokVal += '(';
809             }
810                 if(tokVal == "(" || next_t.Value() == ")" || t.Type() == t_type::FUNCTION || next_t.Type() == t_type::END || t.prefix)
811                     space = "";
812 
813                 es.append(b_tag + tokVal + e_tag + space);
814         }
815     }
816 
817     if(t.Value() != "=")
818         es += eq;
819     if(empty)
820         Tokens.clear();
821     return es;
822 }
823 
824 
825 //----------------------------------------------------------------------------------------------------------------------
Space(Char c)826 bool CalcParser::Space(Char c)
827 {
828     if(c == ' ' || c == ' ' || c == '\n') //пробел или таб или перевод строки
829         return true;
830     return false;
831 }
832 
833 
834 //----------------------------------------------------------------------------------------------------------------------
strchr(String t,Char c)835 bool CalcParser::strchr(String t, Char c)
836 {
837     if (t.indexOf(c) >= 0)
838         return true;
839     return false;
840     }
841 
842 
843 //----------------------------------------------------------------------------------------------------------------------
Error(errors c_err,Token * current_token)844 void CalcParser::Error(errors c_err, Token *current_token)
845 {
846     Token t;
847 
848     err = c_err;
849     if(!current_token)
850         current_token = token;
851 
852     if(current_token->Type() == t_type::END)
853     {
854         t.SetType(t_type::ERR);
855         t.SetErr(err);
856         t.SetValue("ERR");
857 
858         Tokens.push_back(t);
859         i_toks = Tokens.end();
860     }
861     else
862         current_token->SetErr(err);
863 }
864 
865 
866 //----------------------------------------------------------------------------------------------------------------------
listErrors()867 const String CalcParser::listErrors()
868 {
869     String errs = "";
870     Token *t;
871 
872     for(auto it = Tokens.begin(); it != Tokens.end(); it++)
873     {
874         t = &(*it);
875         if(t->Err() != errors::SUCCESS)
876         {
877             if(static_cast<unsigned int>(t->Err()) < sizeof(_Errors) / sizeof(String))
878                 errs.append(QObject::tr(_Errors[static_cast<int>(t->Err())].toStdString().c_str()));
879             else
880                 errs.append("?");
881             errs += "\n";
882         }
883     }
884     return errs;
885 }
886 
887 
888 //----------------------------------------------------------------------------------------------------------------------
EraseErrors()889 void CalcParser::EraseErrors()
890 {
891    // if(err == -1)
892    //     return;
893 
894     Token *t;
895 
896     for(auto it = Tokens.begin(); it != Tokens.end(); ++it)
897     {
898         t = &(*it);
899 
900         if(t->Type() == t_type::ERR)
901         {
902             it = Tokens.erase(it);
903             --it;
904             continue;
905         }
906         if(t->Err() != errors::SUCCESS)
907             t->SetErr(errors::SUCCESS);
908     }
909     err = errors::SUCCESS;
910 }
911 
912 
913 //----------------------------------------------------------------------------------------------------------------------
isdigit(Char c)914 bool CalcParser::isdigit(Char c)
915 {
916     if((strchr("0123456789.ie", c) && scale == 10) || (((c >= 'A' && c <= 'F') || strchr("0123456789", c)) && scale == 16) ||
917             (strchr("01", c) && scale == 2) || (strchr("01234567", c) && scale == 8) ||
918             (((c >= 'A' && c <= 'F') || strchr("0123456789.e,", c)) && scale == 0))
919         return true;
920     return false;
921 }
922 
923 
924 //----------------------------------------------------------------------------------------------------------------------
isalpha(Char c)925 bool CalcParser::isalpha(Char c)
926 {
927     if((c >= 'a' && c <= 'z') || c == '_')
928         return true;
929     return false;
930 }
931 
932 
933 //----------------------------------------------------------------------------------------------------------------------
Add_exp(CValue * res)934 void CalcParser::Add_exp(CValue *res)
935 {
936     CValue temp;
937     Char op;
938 
939     Mul_exp(res);
940 
941     while(token->Value() == "+" || token->Value() == "-")
942     {
943         op = token->Value()[0];
944         GetToken();
945         Mul_exp(&temp);
946 
947         if(temp.Type() != res->Type())
948             Error(errors::TMS);
949 
950         if(op == '+')
951         {
952             if(temp.Type() == e_type_var::STRING)
953                 res->SetValue(res->ValueString() + temp.ValueString());
954             else
955                 res->SetValue(res->ValueFloat() + temp.ValueFloat());
956         }
957         if(op == '-')
958             res->SetValue(res->ValueFloat() - temp.ValueFloat());
959     }
960 }
961 
962 
963 //----------------------------------------------------------------------------------------------------------------------
Mul_exp(CValue * res)964 void CalcParser::Mul_exp(CValue *res)
965 {
966     CValue temp;
967     Char op;
968     char c_op;
969 
970     Step_exp(res);
971 
972     while(token->Value() == "*" || token->Value() == "/" || token->Value() == ">>" ||
973           token->Value() == "<<" || token->Value() == "%" ||
974         token->Value() == "&" || token->Value() == "|" || token->Value() == "!")
975     {
976         op = token->Value()[0];
977         c_op = static_cast<char>(op.toLatin1());
978 
979         GetToken();
980         Step_exp(&temp);
981 
982         if(temp.Type() != res->Type())
983         {
984             Error(errors::TMS);
985             break;
986         }
987 
988         switch(c_op)
989         {
990         case '*':
991             res->SetValue(RoundS((res->ValueFloat() * temp.ValueFloat()), PRECISION_FOR_DOUBLE));
992             break;
993         case '/':
994             if(CheckNumberZero(temp.ValueFloat()))
995                 Error(errors::DIVISION);
996             else
997                 res->SetValue(res->ValueFloat() / temp.ValueFloat());
998             break;
999         case '<':
1000             res->SetValue(static_cast<UINT>(res->ValueFloat()) << static_cast<UINT>(temp.ValueFloat()));
1001             break;
1002         case '>':
1003             res->SetValue(static_cast<UINT>(res->ValueFloat()) >> static_cast<UINT>(temp.ValueFloat()));
1004             break;
1005         case '%':
1006             if(CheckNumberZero(temp.ValueFloat()))
1007                 Error(errors::DIVISION);
1008             res->SetValue(fmod(res->ValueFloat(), temp.ValueFloat()));
1009             break;
1010         case '&':
1011             res->SetValue(static_cast<int>(res->ValueFloat()) & static_cast<int>(temp.ValueFloat()));
1012             break;
1013         case '|':
1014             res->SetValue(static_cast<int>(res->ValueFloat()) | static_cast<int>(temp.ValueFloat()));
1015             break;
1016         case '!':
1017             res->SetValue(static_cast<int>(res->ValueFloat()) ^ static_cast<int>(temp.ValueFloat()));
1018             break;
1019         }
1020 
1021     }
1022 }
1023 
1024 
1025 //----------------------------------------------------------------------------------------------------------------------
Step_exp(CValue * res)1026 void CalcParser::Step_exp(CValue *res)
1027 {
1028     CValue temp;
1029 
1030     Sign_exp(res);
1031 
1032     if((token->Type() == t_type::DELIMITER) && (token->Value() == "^"))
1033     {
1034         GetToken();
1035         Step_exp(&temp);
1036 
1037         if(temp.Type() != res->Type())
1038             Error(errors::TMS);
1039 
1040         res->SetValue(RoundS(pow(res->ValueFloat(), temp.ValueFloat()), PRECISION_FOR_DOUBLE));
1041     }
1042 }
1043 
1044 
1045 
1046 //----------------------------------------------------------------------------------------------------------------------
Sign_exp(CValue * res)1047 void CalcParser::Sign_exp(CValue *res)
1048 {
1049     Char op = ' ';
1050 
1051     if((token->Type() == t_type::DELIMITER) &&
1052         (token->Value() == "+" || token->Value() == "-" || token->Value() == "~"))
1053     {
1054         op = token->Value()[0];
1055         GetToken();
1056     }
1057     Scob_exp(res);
1058     if(op == '-')
1059         res->SetValue(-res->ValueFloat());
1060     else
1061         if(op == '~')
1062             res->SetValue(~static_cast<int>(res->ValueFloat()));
1063 }
1064 
1065 
1066 //----------------------------------------------------------------------------------------------------------------------
Scob_exp(CValue * res)1067 void CalcParser::Scob_exp(CValue *res)
1068 {
1069     CValue temp;
1070 
1071     if(token->Type() == t_type::DELIMITER && token->Value() == "(")
1072     {
1073         GetToken();
1074         if(token->Value() == ")")
1075             Error(errors::EMPTBKT);
1076         else
1077         {
1078             Add_exp(&temp);
1079 
1080             if(temp.Type() != res->Type())
1081                 Error(errors::TMS);
1082 
1083             res->SetValue(temp.ValueFloat());
1084             if(token->Value() != ")")
1085                 Error(errors::BKT);
1086 
1087         }
1088         GetToken();
1089         if(token->Type() == t_type::NUMBER)
1090             Error(errors::SYNTAX);
1091 
1092     }
1093     else
1094         GetNumber(res);
1095 }
1096 
1097 
1098 
1099 //----------------------------------------------------------------------------------------------------------------------
GetNumber(CValue * res)1100 void CalcParser::GetNumber(CValue *res)
1101 {
1102     CValue temp;
1103     CValue temp1;
1104     Function* f;
1105     unsigned f_n_par;
1106     String var;
1107     VarList::const_iterator var_it;
1108     Variable v;
1109     Token* ftok;
1110 
1111     switch(token->Type())
1112     {
1113     case t_type::NUMBER:
1114         {
1115         res->SetValue(ScaleToVal(token->Value(), scale));
1116         GetToken();
1117         break;
1118         }
1119     case t_type::FUNCTION:
1120         {
1121         ftok = token;
1122         auto fi = map_funcs.find(token->Value());
1123         if (fi != map_funcs.end())
1124         {
1125             f = fi->second;
1126             f_n_par = f->getCountAgrs();
1127             GetToken();
1128             Add_exp(&temp);
1129             switch(f_n_par)
1130             {
1131             case 1:
1132                 if(token->Value() != ")")
1133                     Error(errors::BKT);
1134                 res->SetValue(GetCheckedNumberZero(f->Calculate(temp.ValueFloat(), DRG_mode, ftok)));
1135                 break;
1136             case 2:
1137                 if(token->Type() != t_type::COMMA)
1138                 {
1139                     Error(errors::SYNTAX);
1140                     break;
1141                 }
1142                 GetToken();
1143                 Add_exp(&temp1);
1144                 if(token->Value() != ")")
1145                 {
1146                     Error(errors::BKT);
1147                     break;
1148                 }
1149                 res->SetValue(f->Calculate(temp.ValueFloat(), temp1.ValueFloat(), ftok));
1150                 break;
1151             default:
1152                 Error(errors::UNKNOWN);
1153                 }
1154             GetToken();
1155             break;
1156             }
1157         else
1158             Error(errors::UNDEFINED);
1159         break;
1160         }
1161     case t_type::VARIABLE:
1162         var = token->Value();
1163         if(!InitVariableFromExpression()) //если выражение содержит инициализацию переменных
1164             GetToken();
1165         var_it = Vars.find(var);
1166         if(var_it != Vars.end())
1167         {
1168             v = VariableByIterator(var_it);
1169             if(v.type == e_type_var::FLOAT)
1170                 res->SetValue(ScaleToVal(v.value));
1171             else
1172             {
1173                 res->SetType(v.type);
1174                 res->SetValue(v.value);
1175             }
1176 
1177         }
1178         else
1179             Error(errors::UNKVAR);
1180         break;
1181     case t_type::TEXT:
1182         res->SetType(token->type_var);
1183         res->SetValue(token->Value());
1184         GetToken();
1185         break;
1186     default:
1187         Error(errors::SYNTAX);
1188         GetToken();
1189     }
1190 }
1191 
1192 
1193 //----------------------------------------------------------------------------------------------------------------------
GetStrValueVariable(String varname)1194 String CalcParser::GetStrValueVariable(String varname)
1195 {
1196     auto var_it = Vars.find(varname);
1197     Variable v;
1198     if(var_it != Vars.end())
1199     {
1200         v = VariableByIterator(var_it);
1201         return v.value;
1202     }
1203     return "";
1204 }
1205 
1206 
1207 
1208 //----------------------------------------------------------------------------------------------------------------------
ScaleToVal(String s,int scale)1209 double CalcParser::ScaleToVal(String s, int scale)
1210 {
1211     int len, i, j;
1212     double res = 0;
1213     String tst = "";
1214     String::iterator val;
1215     if(!dec_point.isEmpty())
1216     {
1217         for(auto it = s.begin(); it != s.end(); ++it)
1218             if(*it == '.' && dec_point != ".")
1219                 *it = dec_point[0];
1220     }
1221 
1222     if(10 == scale)
1223     {
1224         if(s.indexOf('e') != -1)
1225         {
1226             val = s.begin() + s.indexOf('e') + 1;
1227             for(; val != s.end(); val++)
1228                 tst += *val;
1229             s.resize(s.indexOf('e'));
1230             res = atof(s.toStdString().c_str()) * pow(10, atoi(tst.toStdString().c_str()));
1231 
1232         }
1233         else
1234             res = atof(s.toStdString().c_str());
1235     }
1236     else
1237     {
1238         res = 0;
1239         len = s.size();
1240         j = 0;
1241         for(i = len - 1; i >= 0; i--)
1242         {
1243             tst = "";
1244             if(*(s.begin() + i) > '9')
1245             {
1246                 if(*(s.begin() + i) == 'A')
1247                     tst += "10";
1248                 if(*(s.begin() + i) == 'B')
1249                     tst += "11";
1250                 if(*(s.begin() + i) == 'C')
1251                     tst += "12";
1252                 if(*(s.begin() + i) == 'D')
1253                     tst += "13";
1254                 if(*(s.begin() + i) == 'E')
1255                     tst += "14";
1256                 if(*(s.begin() + i) == 'F')
1257                     tst += "15";
1258             }
1259             else
1260                 tst += *(s.begin() + i);
1261 
1262             res += pow(scale, j) * atoi(tst.toStdString().c_str());
1263             j++;
1264         }
1265     }
1266     return res;
1267 }
1268 
1269 
1270 
1271 //----------------------------------------------------------------------------------------------------------------------
RoundS(double arg,int precision)1272 double CalcParser::RoundS(double arg, int precision)
1273 {
1274     if(-1 == precision)
1275         return arg;
1276     String s = DoubleToString(arg, precision); // округление через строки...
1277     return ScaleToVal(s, scale);
1278 }
1279 
1280 
1281 
1282 
1283 //----------------------------------------------------------------------------------------------------------------------
DoubleToString(double n,int precision)1284 String CalcParser::DoubleToString(double n, int precision)
1285 {
1286     String res;
1287 
1288     n = GetCheckedNumberZero(n);
1289 
1290     if(10 == scale)
1291         res = String::number(n, 'g', precision);
1292     else
1293     {
1294         res = String::number(static_cast<ulong>(n), scale);
1295         res = res.toUpper();
1296     }
1297     return res;
1298 }
1299 
1300 
1301 //----------------------------------------------------------------------------------------------------------------------
VariableByIterator(VarList::const_iterator vit)1302 Variable CalcParser::VariableByIterator(VarList::const_iterator vit)
1303 {
1304     Variable v;
1305     v = vit->second;
1306     return v;
1307 }
1308 
1309 
1310 //----------------------------------------------------------------------------------------------------------------------
InitMapToksHtml()1311 void CalcParser::InitMapToksHtml()
1312 {
1313     ToksHtml["*"] = "&times;";
1314     ToksHtml["pi"] = "&pi;";
1315     ToksHtml["&"] = "&amp;";
1316     //ToksHtml["|"] = "&brvbar;";
1317     ToksHtml[">>"] = "&raquo;";
1318     ToksHtml["<<"] = "&laquo;";
1319     ToksHtml["sqrt"] = "&radic;";
1320     ToksHtml["terrt"] = "&sup3;&radic;";
1321     ToksHtml["%"] = "mod";
1322 }
1323 
1324 
1325 //----------------------------------------------------------------------------------------------------------------------
CheckNumberZero(double n)1326 bool CalcParser::CheckNumberZero(double n)
1327 {
1328     if(fabs(n) < (1.0 * pow(10.0, -15)))
1329         return true;
1330     return false;
1331 }
1332 
1333 
1334 //----------------------------------------------------------------------------------------------------------------------
RefTokens(void)1335 const TokenList& CalcParser::RefTokens(void)
1336 {
1337     return Tokens;
1338 }
1339 
1340 
1341 //----------------------------------------------------------------------------------------------------------------------
InitFuncs()1342 void CalcParser::InitFuncs()
1343 {
1344     Function* f;
1345     for(auto i = 0; i < static_cast<int>(EFunc::user); ++i)
1346     {
1347         EFunc ef = static_cast<EFunc>(i);
1348         f = new Function(ef);
1349         map_funcs[f->getStrFunc()] = f;
1350     }
1351 }
1352