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["*"] = "×";
1314 ToksHtml["pi"] = "π";
1315 ToksHtml["&"] = "&";
1316 //ToksHtml["|"] = "¦";
1317 ToksHtml[">>"] = "»";
1318 ToksHtml["<<"] = "«";
1319 ToksHtml["sqrt"] = "√";
1320 ToksHtml["terrt"] = "³√";
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