NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
flowctrl.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 NumeRe: Framework fuer Numerische Rechnungen
3 Copyright (C) 2014 Erik Haenel et al.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17******************************************************************************/
18
19
20// Implementation der FlowCtrl-Klasse
21#include "flowctrl.hpp"
22#include "../ui/error.hpp"
23#include "../../kernel.hpp"
24#include "../maths/parser_functions.hpp"
25#include "../built-in.hpp"
26#include "../utils/tools.hpp"
27
28// Definition of special return values
29#define FLOWCTRL_ERROR -1
30#define FLOWCTRL_RETURN -2
31#define FLOWCTRL_BREAK -3
32#define FLOWCTRL_CONTINUE -4
33#define FLOWCTRL_NO_CMD -5
34#define FLOWCTRL_OK 1
35
36// Definition of standard values of the jump table
37#define NO_FLOW_COMMAND -1
38#define BLOCK_END 0
39#define BLOCK_MIDDLE 1
40#define PROCEDURE_INTERFACE 2
41#define JUMP_TABLE_ELEMENTS 3 // The maximal number of elements
42extern value_type vAns;
43
44using namespace std;
45
46
56static std::string extractHeaderExpression(const std::string& sExpr)
57{
58 size_t p = sExpr.find('(');
59 return sExpr.substr(p + 1, sExpr.rfind(')') - p - 1);
60}
61
62
67{
68 _parserRef = nullptr;
69 _dataRef = nullptr;
70 _outRef = nullptr;
71 _optionRef = nullptr;
72 _functionRef = nullptr;
73 _pDataRef = nullptr;
74 _scriptRef = nullptr;
75
76 nLoopSafety = -1;
77
78 for (size_t i = 0; i < FC_COUNT; i++)
80
82 nDebuggerCode = 0;
83 sLoopNames = "";
85 bSilent = true;
86 bMask = false;
87 bLoopSupressAnswer = false;
88
89 bPrintedStatus = false;
90
91 bUseLoopParsingMode = false;
92 bLockedPauseMode = false;
93
94 bFunctionsReplaced = false;
95 nthRecursion = 0;
97
98 nReturnType = 1;
99 bReturnSignal = false;
100}
101
102
108{
109}
110
111
120{
121 int nCount = 0;
122
123 for (size_t i = 0; i < FC_COUNT; i++)
124 {
125 nCount += nFlowCtrlStatements[i];
126 }
127
128 return nCount;
129}
130
131
143int FlowCtrl::for_loop(int nth_Cmd, int nth_loop)
144{
145 int nVarAdress = 0;
146 int nInc = 1;
147 int nLoopCount = 0;
148 int nFirstVal;
149 int nLastVal;
150 bPrintedStatus = false;
151
152 int nNum = 0;
153 value_type* v = 0;
154
155 if (!vCmdArray[nth_Cmd].sFlowCtrlHeader.length())
156 {
157 vCmdArray[nth_Cmd].sFlowCtrlHeader = vCmdArray[nth_Cmd].sCommand.substr(vCmdArray[nth_Cmd].sCommand.find('=') + 1);
158 std::string sVar = vCmdArray[nth_Cmd].sCommand.substr(vCmdArray[nth_Cmd].sCommand.find(' ') + 1);
159 sVar = sVar.substr(0, sVar.find('='));
160 StripSpaces(sVar);
161
162 if (sVar.substr(0, 2) == "|>")
163 {
164 vCmdArray[nth_Cmd].sFlowCtrlHeader.insert(0, "|>");
165 sVar.erase(0, 2);
166 }
167
168 StripSpaces(sVar);
169
170 // Get the variable address of the loop
171 // index
172 for (size_t i = 0; i < sVarArray.size(); i++)
173 {
174 if (sVarArray[i] == sVar)
175 {
176 vCmdArray[nth_Cmd].nVarIndex = i;
177 break;
178 }
179 }
180 }
181
182 std::string sHead = vCmdArray[nth_Cmd].sFlowCtrlHeader;
183 nVarAdress = vCmdArray[nth_Cmd].nVarIndex;
184
185 // Evaluate the header of the for loop
186 v = evalHeader(nNum, sHead, true, nth_Cmd, "for");
187
188 // Store the left and right boundary of the
189 // loop index
190 nFirstVal = intCast(v[0]);
191 nLastVal = intCast(v[1]);
192
193 // Depending on the order of the boundaries, we
194 // have to consider the incrementation variable
195 if (nLastVal < nFirstVal)
196 nInc *= -1;
197
198 // Print to the terminal, if needed
199 if (bSilent && !nth_loop && !bMask)
200 {
201 NumeReKernel::printPreFmt("|FOR> " + _lang.get("COMMON_EVALUATING") + " ... 0 %");
202 bPrintedStatus = true;
203 }
204
205 // Evaluate the whole for loop. The outer loop does the
206 // loop index management (the actual "for" command), the
207 // inner loop runs through the contained command lines
208 for (int __i = nFirstVal; (nInc)*__i <= nInc * nLastVal; __i += nInc)
209 {
210 vVarArray[nVarAdress] = __i;
211
212 // Ensure that the loop is aborted, if the
213 // maximal number of repetitions has been
214 // performed
215 if (nLoopSafety > 0)
216 {
217 if (nLoopCount >= nLoopSafety)
218 return FLOWCTRL_ERROR;
219
220 nLoopCount++;
221 }
222
223 // This for loop handles the contained commands
224 for (int __j = nth_Cmd+1; __j < nJumpTable[nth_Cmd][BLOCK_END]; __j++)
225 {
226 nCurrentCommand = __j;
227
228 // If this is not the first line of the command block
229 // try to find control flow statements in the first column
230 if (vCmdArray[__j].fcFn)
231 {
232 // Evaluate the flow control commands
233 int nReturn = (this->*vCmdArray[__j].fcFn)(__j, nth_loop+1);
234
235 // Handle the return value
236 if (nReturn == FLOWCTRL_ERROR || nReturn == FLOWCTRL_RETURN)
237 return nReturn;
238 else if (nReturn == FLOWCTRL_BREAK)
239 return nJumpTable[nth_Cmd][BLOCK_END];
240 else if (nReturn == FLOWCTRL_CONTINUE)
241 break;
242 else if (nReturn != FLOWCTRL_NO_CMD)
243 __j = nReturn;
244
245 continue;
246 }
247
248 // Handle the "continue" and "break" flow
249 // control statements
251 break;
252 else if (nCalcType[__j] & CALCTYPE_BREAKCMD)
253 return nJumpTable[nth_Cmd][BLOCK_END];
254 else if (__i == nFirstVal && !nCalcType[__j])
255 {
256 std::string sCommand = findCommand(vCmdArray[__j].sCommand).sString;
257
258 // Evaluate the commands, store the bytecode
259 if (sCommand == "continue")
260 {
262
263 // "continue" is a break of the inner loop
264 break;
265 }
266
267 if (sCommand == "break")
268 {
270
271 // "break" requires to leave the current
272 // for loop. Therefore it is realized as
273 // return statement, returning the end index
274 // of the current block
275 return nJumpTable[nth_Cmd][BLOCK_END];
276 }
277 }
278
279 // Increment the parser index, if the loop parsing
280 // mode was activated
282 _parserRef->SetIndex(__j);
283
284 try
285 {
286 // Evaluate the command line with the calc function
287 if (calc(vCmdArray[__j].sCommand, __j) == FLOWCTRL_ERROR)
288 {
289 if (_optionRef->useDebugger())
290 {
295 }
296
297 return FLOWCTRL_ERROR;
298 }
299
300 if (bReturnSignal)
301 return FLOWCTRL_RETURN;
302 }
303 catch (...)
304 {
305 if (_optionRef->useDebugger())
306 {
311 }
312
313 NumeReKernel::getInstance()->getDebugger().showError(current_exception());
316 }
317 }
318
319 // The variable value might have been changed
320 // snychronize the index
321 __i = intCast(vVarArray[nVarAdress]);
322
323 // Print the status to the terminal, if it is required
324 if (!nth_loop && !bMask && bSilent)
325 {
326 if (abs(nLastVal - nFirstVal) < 99999
327 && abs(intCast((__i - nFirstVal) / double(nLastVal - nFirstVal) * 20.0))
328 > abs(intCast((__i - 1.0 - nFirstVal) / double(nLastVal - nFirstVal) * 20.0)))
329 {
330 NumeReKernel::printPreFmt("\r|FOR> " + _lang.get("COMMON_EVALUATING") + " ... "
331 + toString(abs(intCast((__i - nFirstVal) / double(nLastVal - nFirstVal) * 20.0)) * 5)
332 + " %");
333 bPrintedStatus = true;
334 }
335 else if (abs(nLastVal - nFirstVal) >= 99999
336 && abs(intCast((__i - nFirstVal) / double(nLastVal - nFirstVal) * 100.0))
337 > abs(intCast((__i - 1.0 - nFirstVal) / double(nLastVal - nFirstVal) * 100.0)))
338 {
339 NumeReKernel::printPreFmt("\r|FOR> " + _lang.get("COMMON_EVALUATING") + " ... "
340 + toString(abs(intCast((__i - nFirstVal) / double(nLastVal - nFirstVal) * 100.0)))
341 + " %");
342 bPrintedStatus = true;
343 }
344 }
345 }
346
347 return nJumpTable[nth_Cmd][BLOCK_END];
348}
349
350
356{
363
364
377int FlowCtrl::range_based_for_loop(int nth_Cmd, int nth_loop)
378{
379 int nVarAdress = 0;
380 int nLoopCount = 0;
381 bPrintedStatus = false;
383
384 if (!vCmdArray[nth_Cmd].sFlowCtrlHeader.length())
385 {
386 vCmdArray[nth_Cmd].sFlowCtrlHeader = vCmdArray[nth_Cmd].sCommand.substr(vCmdArray[nth_Cmd].sCommand.find("->") + 2);
387 std::string sVar = vCmdArray[nth_Cmd].sCommand.substr(vCmdArray[nth_Cmd].sCommand.find(' ') + 1);
388 sVar.erase(sVar.find("->")+2);
389 StripSpaces(sVar);
390
391 if (sVar.substr(0, 2) == "|>")
392 {
393 vCmdArray[nth_Cmd].sFlowCtrlHeader.insert(0, "|>");
394 sVar.erase(0, 2);
395 }
396
397 StripSpaces(sVar);
398
399 // Get the variable address of the loop
400 // index
401 for (size_t i = 0; i < sVarArray.size(); i++)
402 {
403 if (sVarArray[i] == sVar)
404 {
405 vCmdArray[nth_Cmd].nVarIndex = i;
406 sVarArray[i].erase(sVarArray[i].find("->"));
408
409 // The variable has not been declared yet
410 varType = DECLARE_NEW_VAR;
411 break;
412 }
413 }
414 }
415
416 std::string sHead = vCmdArray[nth_Cmd].sFlowCtrlHeader;
417 nVarAdress = vCmdArray[nth_Cmd].nVarIndex;
418
419 if (nVarAdress < 0)
420 return FLOWCTRL_ERROR;
421
423
424 // Evaluate the header of the for loop and
425 // assign the result to the iterator
426 NumeRe::Cluster range = evalRangeBasedHeader(sHead, nth_Cmd, "for");
427
428 // Shall we declare a new iterator variable? Otherwise try
429 // to detect the type of the already created iterator variable
430 if (varType == DECLARE_NEW_VAR)
431 {
432 if (sVarArray[nVarAdress].front() == '{')
433 {
434 EndlessVector<std::string> vIters = getAllArguments(sVarArray[nVarAdress].substr(1, sVarArray[nVarAdress].length()-2));
435
436 // Create a temporary cluster for all iterators and remove
437 // the trailing closing brace to change that to individual
438 // indices for every iterator
439 std::string sTempCluster = _dataRef->createTemporaryCluster(vIters.front());
440 sTempCluster.pop_back();
441
442 // Create single calls for every single iterator
443 for (size_t i = 0; i < vIters.size(); i++)
444 {
445 mVarMap[vIters[i]] = sTempCluster + toString(i+1) + "}";
446 replaceLocalVars(vIters[i], mVarMap[vIters[i]], nth_Cmd, nJumpTable[nth_Cmd][BLOCK_END]);
447
448 // Add or replace the iterators in the list of iterators
449 if (i)
450 sVarArray.push_back(mVarMap[vIters[i]]);
451 else
452 sVarArray[nVarAdress] = mVarMap[vIters[0]];
453 }
454
455 // Note the needed iterator stepping
456 vCmdArray[nth_Cmd].nRFStepping = vIters.size()-1;
457 varType = CLUSTERVAR;
458 }
459 else if (range.isDouble())
460 {
461 // Create a local variable
462 mVarMap[sVarArray[nVarAdress]] = "_~LOOP_" + sVarArray[nVarAdress] + "_" + toString(nthRecursion);
463 replaceLocalVars(sVarArray[nVarAdress], mVarMap[sVarArray[nVarAdress]], nth_Cmd, nJumpTable[nth_Cmd][BLOCK_END]);
464 sVarArray[nVarAdress] = mVarMap[sVarArray[nVarAdress]];
465 _parserRef->DefineVar(sVarArray[nVarAdress], &vVarArray[nVarAdress]);
466 varType = NUMVAR;
467 }
468 else if (range.isString())
469 {
470 // Create a local string variable
471 mVarMap[sVarArray[nVarAdress]] = "_~LOOP_" + sVarArray[nVarAdress] + "_" + toString(nthRecursion);
472 replaceLocalVars(sVarArray[nVarAdress], mVarMap[sVarArray[nVarAdress]], nth_Cmd, nJumpTable[nth_Cmd][BLOCK_END]);
473 sVarArray[nVarAdress] = mVarMap[sVarArray[nVarAdress]];
474 _stringParser.setStringValue(sVarArray[nVarAdress], "");
475 varType = STRINGVAR;
476 }
477 else
478 {
479 // Create a cluster in all other cases as this is the
480 // only variant type available
481 mVarMap[sVarArray[nVarAdress]] = _dataRef->createTemporaryCluster(sVarArray[nVarAdress]);
482 replaceLocalVars(sVarArray[nVarAdress], mVarMap[sVarArray[nVarAdress]], nth_Cmd, nJumpTable[nth_Cmd][BLOCK_END]);
483 sVarArray[nVarAdress] = mVarMap[sVarArray[nVarAdress]];
484 varType = CLUSTERVAR;
485 }
486 }
487 else
488 {
489 // Find the type of the current iterator variable
490 if (sVarArray[nVarAdress].find('{') != std::string::npos)
491 varType = CLUSTERVAR;
492 else if (_stringParser.isStringVar(sVarArray[nVarAdress]))
493 varType = STRINGVAR;
494 else
495 varType = NUMVAR;
496 }
497
498 // Print to the terminal, if needed
499 if (bSilent && !nth_loop && !bMask)
500 {
501 NumeReKernel::printPreFmt("|FOR> " + _lang.get("COMMON_EVALUATING") + " ... 0 %");
502 bPrintedStatus = true;
503 }
504
505 // Evaluate the whole for loop. The outer loop does the
506 // loop index management (the actual "for" command), the
507 // inner loop runs through the contained command lines
508 for (size_t i = 0; i < range.size(); i++)
509 {
510 // Set the value in the correct variable type
511 switch (varType)
512 {
513 case NUMVAR:
514 vVarArray[nVarAdress] = range.getDouble(i);
515 break;
516 case STRINGVAR:
517 _stringParser.setStringValue(sVarArray[nVarAdress], range.getInternalString(i));
518 break;
519 default:
520 {
521 NumeRe::Cluster& iterCluster = _dataRef->getCluster(sVarArray[nVarAdress]);
522
523 for (size_t n = 0; n <= vCmdArray[nth_Cmd].nRFStepping; n++)
524 {
526 iterCluster.setDouble(n, range.getDouble(i+n));
527 else
528 iterCluster.setString(n, range.getInternalString(i+n));
529 }
530
531 i += vCmdArray[nth_Cmd].nRFStepping;
532 }
533 }
534
535 // Ensure that the loop is aborted, if the
536 // maximal number of repetitions has been
537 // performed
538 if (nLoopSafety > 0)
539 {
540 if (nLoopCount >= nLoopSafety)
541 return FLOWCTRL_ERROR;
542
543 nLoopCount++;
544 }
545
546 // This for loop handles the contained commands
547 for (int __j = nth_Cmd+1; __j < nJumpTable[nth_Cmd][BLOCK_END]; __j++)
548 {
549 nCurrentCommand = __j;
550
551 // If this is not the first line of the command block
552 // try to find control flow statements in the first column
553 if (vCmdArray[__j].fcFn)
554 {
555 // Evaluate the flow control commands
556 int nReturn = (this->*vCmdArray[__j].fcFn)(__j, nth_loop+1);
557
558 // Handle the return value
559 if (nReturn == FLOWCTRL_ERROR || nReturn == FLOWCTRL_RETURN)
560 return nReturn;
561 else if (nReturn == FLOWCTRL_BREAK)
562 return nJumpTable[nth_Cmd][BLOCK_END];
563 else if (nReturn == FLOWCTRL_CONTINUE)
564 break;
565 else if (nReturn != FLOWCTRL_NO_CMD)
566 __j = nReturn;
567
568 continue;
569 }
570
571 // Handle the "continue" and "break" flow
572 // control statements
574 break;
575 else if (nCalcType[__j] & CALCTYPE_BREAKCMD)
576 return nJumpTable[nth_Cmd][BLOCK_END];
577 else if (!nCalcType[__j])
578 {
579 std::string sCommand = findCommand(vCmdArray[__j].sCommand).sString;
580
581 // Evaluate the commands, store the bytecode
582 if (sCommand == "continue")
583 {
585
586 // "continue" is a break of the inner loop
587 break;
588 }
589
590 if (sCommand == "break")
591 {
593
594 // "break" requires to leave the current
595 // for loop. Therefore it is realized as
596 // return statement, returning the end index
597 // of the current block
598 return nJumpTable[nth_Cmd][BLOCK_END];
599 }
600 }
601
602 // Increment the parser index, if the loop parsing
603 // mode was activated
605 _parserRef->SetIndex(__j);
606
607 try
608 {
609 // Evaluate the command line with the calc function
610 if (calc(vCmdArray[__j].sCommand, __j) == FLOWCTRL_ERROR)
611 {
612 if (_optionRef->useDebugger())
613 {
618 }
619
620 return FLOWCTRL_ERROR;
621 }
622
623 if (bReturnSignal)
624 return FLOWCTRL_RETURN;
625 }
626 catch (...)
627 {
628 if (_optionRef->useDebugger())
629 {
634 }
635
636 NumeReKernel::getInstance()->getDebugger().showError(current_exception());
639 }
640 }
641
642 // Print the status to the terminal, if it is required
643 if (!nth_loop && !bMask && bSilent)
644 {
645 if (range.size() < 99999
646 && intCast(i / (double)range.size() * 20.0) > intCast((i-1) / (double)range.size() * 20.0))
647 {
648 NumeReKernel::printPreFmt("\r|FOR> " + _lang.get("COMMON_EVALUATING") + " ... "
649 + toString(intCast(i / (double)range.size() * 20.0) * 5)
650 + " %");
651 bPrintedStatus = true;
652 }
653 else if (range.size() >= 99999
654 && intCast(i / (double)range.size() * 100.0) > intCast((i-1) / (double)range.size() * 100.0))
655 {
656 NumeReKernel::printPreFmt("\r|FOR> " + _lang.get("COMMON_EVALUATING") + " ... "
657 + toString(intCast(i / (double)range.size() * 100.0))
658 + " %");
659 bPrintedStatus = true;
660 }
661 }
662 }
663
664 return nJumpTable[nth_Cmd][BLOCK_END];
665}
666
667
679int FlowCtrl::while_loop(int nth_Cmd, int nth_loop)
680{
681 if (!vCmdArray[nth_Cmd].sFlowCtrlHeader.length())
682 vCmdArray[nth_Cmd].sFlowCtrlHeader = extractHeaderExpression(vCmdArray[nth_Cmd].sCommand);
683
684 std::string sWhile_Condition = vCmdArray[nth_Cmd].sFlowCtrlHeader;
685 std::string sWhile_Condition_Back = sWhile_Condition;
686 bPrintedStatus = false;
687 int nLoopCount = 0;
688 value_type* v = 0;
689 int nNum = 0;
690
691 // Show a working indicator, if it's necessary
692 if (bSilent && !bMask && !nth_loop)
693 {
694 NumeReKernel::printPreFmt("|WHL> " + _lang.get("COMMON_EVALUATING") + " ... ");
695 bPrintedStatus = true;
696 }
697
698 // The outer while loop realizes the "while" control
699 // flow statement and handles the checking of the
700 // while condition. The inner for loop runs through
701 // the contained commands
702 while (true)
703 {
704 // Evaluate the header (has to be done in every
705 // run)
706 v = evalHeader(nNum, sWhile_Condition, false, nth_Cmd, "while");
707
708 // Ensure that the loop is aborted, if the
709 // maximal number of repetitions has been
710 // performed
711 if (nLoopSafety > 0)
712 {
713 if (nLoopCount >= nLoopSafety)
714 return FLOWCTRL_ERROR;
715
716 nLoopCount++;
717 }
718
719 // Check, whether the header condition is true.
720 // NaN and INF are no "true" values. Return the
721 // end of the current block otherwise
722 if (v[0] == 0.0 || mu::isnan(v[0]))
723 return nJumpTable[nth_Cmd][BLOCK_END];
724
725 // This for loop handles the contained commands
726 for (int __j = nth_Cmd+1; __j < nJumpTable[nth_Cmd][BLOCK_END]; __j++)
727 {
728 nCurrentCommand = __j;
729
730 // If this is not the first line of the command block
731 // try to find control flow statements in the first column
732 if (vCmdArray[__j].fcFn)
733 {
734 // Evaluate the flow control commands
735 int nReturn = (this->*vCmdArray[__j].fcFn)(__j, nth_loop+1);
736
737 // Handle the return value
738 if (nReturn == FLOWCTRL_ERROR || nReturn == FLOWCTRL_RETURN)
739 return nReturn;
740 else if (nReturn == FLOWCTRL_BREAK)
741 return nJumpTable[nth_Cmd][BLOCK_END];
742 else if (nReturn == FLOWCTRL_CONTINUE)
743 break;
744 else if (nReturn != FLOWCTRL_NO_CMD)
745 __j = nReturn;
746
747 continue;
748 }
749
750 // Handle the "continue" and "break" flow
751 // control statements
753 break;
754 else if (nCalcType[__j] & CALCTYPE_BREAKCMD)
755 return nJumpTable[nth_Cmd][BLOCK_END];
756 else if (!nCalcType[__j])
757 {
758 std::string sCommand = findCommand(vCmdArray[__j].sCommand).sString;
759
760 // Evaluate the commands, store the bytecode
761 if (sCommand == "continue")
762 {
764
765 // "continue" is a break of the inner loop
766 break;
767 }
768
769 if (sCommand == "break")
770 {
772
773 // "break" requires to leave the current
774 // for loop. Therefore it is realized as
775 // return statement, returning the end index
776 // of the current block
777 return nJumpTable[nth_Cmd][BLOCK_END];
778 }
779 }
780
781 // Increment the parser index, if the loop parsing
782 // mode was activated
784 _parserRef->SetIndex(__j);
785
786 try
787 {
788 // Evaluate the command line with the calc function
789 if (calc(vCmdArray[__j].sCommand, __j) == FLOWCTRL_ERROR)
790 {
791 if (_optionRef->useDebugger())
792 {
797 }
798
799 return FLOWCTRL_ERROR;
800 }
801
802 if (bReturnSignal)
803 return FLOWCTRL_RETURN;
804 }
805 catch (...)
806 {
807 if (_optionRef->useDebugger())
808 {
813 }
814
815 NumeReKernel::getInstance()->getDebugger().showError(current_exception());
818 }
819 }
820
821 // If the while condition has changed during the evaluation
822 // re-use the original condition to ensure that the result of
823 // the condition is true
824 if (sWhile_Condition != sWhile_Condition_Back || _dataRef->containsTablesOrClusters(sWhile_Condition_Back))
825 sWhile_Condition = sWhile_Condition_Back;
826 }
827
828 return vCmdArray.size();
829}
830
831
843int FlowCtrl::if_fork(int nth_Cmd, int nth_loop)
844{
845 int nElse = nJumpTable[nth_Cmd][BLOCK_MIDDLE]; // Position of next else/elseif
846 int nEndif = nJumpTable[nth_Cmd][BLOCK_END];
847 bPrintedStatus = false;
848 value_type* v;
849 int nNum = 0;
850 std::string sHeadCommand = "if";
851
852 // The first command is always an "if", therefore always
853 // enter this section. The condition at the end will check
854 // whether a further iteration is needed to find the next
855 // "elseif" or directly leave the loop to continue with the
856 // "else" case.
857 do
858 {
859 if (!vCmdArray[nth_Cmd].sFlowCtrlHeader.length())
860 vCmdArray[nth_Cmd].sFlowCtrlHeader = extractHeaderExpression(vCmdArray[nth_Cmd].sCommand);
861
862 nElse = nJumpTable[nth_Cmd][BLOCK_MIDDLE];
863 nEndif = nJumpTable[nth_Cmd][BLOCK_END];
864 bPrintedStatus = false;
865 std::string sHead = vCmdArray[nth_Cmd].sFlowCtrlHeader;
866
867 // Evaluate the header of the current elseif case
868 v = evalHeader(nNum, sHead, false, nth_Cmd, sHeadCommand);
869
870 // If the condition is true, enter the if-case
871 if (v[0] != 0.0 && !mu::isnan(v[0]))
872 {
873 // The inner loop goes through the contained
874 // commands
875 for (int __i = nth_Cmd+1; __i < (int)vCmdArray.size(); __i++)
876 {
877 nCurrentCommand = __i;
878
879 // If we reach the line of the next else/
880 // elseif or the corresponding end of the
881 // current block, return with the last line
882 // of this block
883 if (__i == nElse || __i >= nEndif)
884 return nEndif;
885
886 // If this is not the first line of the command block
887 // try to find control flow statements in the first column
888 if (vCmdArray[__i].bFlowCtrlStatement)
889 {
890 // Evaluate the flow control commands
891 int nReturn = evalForkFlowCommands(__i, nth_loop);
892
893 // Handle the return value
894 if (nReturn == FLOWCTRL_ERROR
895 || nReturn == FLOWCTRL_RETURN
896 || nReturn == FLOWCTRL_BREAK
897 || nReturn == FLOWCTRL_CONTINUE)
898 return nReturn;
899 else if (nReturn != FLOWCTRL_NO_CMD)
900 __i = nReturn;
901
902 continue;
903 }
904
905 // Handle the "continue" and "break" flow
906 // control statements
908 return FLOWCTRL_CONTINUE;
909 else if (nCalcType[__i] & CALCTYPE_BREAKCMD)
910 return FLOWCTRL_BREAK;
911 else if (!nCalcType[__i])
912 {
913 std::string sCommand = findCommand(vCmdArray[__i].sCommand).sString;
914
915 // "continue" and "break" are both exiting the current
916 // condition, but they are yielding different signals
917 if (sCommand == "continue")
918 {
920 return FLOWCTRL_CONTINUE;
921 }
922
923 if (sCommand == "break")
924 {
926 return FLOWCTRL_BREAK;
927 }
928 }
929
930 // Increment the parser index, if the loop parsing
931 // mode was activated
933 _parserRef->SetIndex(__i);
934
935 try
936 {
937 // Evaluate the command line with the calc function
938 if (calc(vCmdArray[__i].sCommand, __i) == FLOWCTRL_ERROR)
939 {
940 if (_optionRef->useDebugger())
941 {
946 }
947
948 return FLOWCTRL_ERROR;
949 }
950
951 if (bReturnSignal)
952 return FLOWCTRL_RETURN;
953 }
954 catch (...)
955 {
956 if (_optionRef->useDebugger())
957 {
962 }
963
964 NumeReKernel::getInstance()->getDebugger().showError(current_exception());
967 }
968 }
969
970 return nEndif;
971 }
972 else
973 {
974 // Try to find the next elseif/else
975 // statement of the current block
976 if (nElse == NO_FLOW_COMMAND)
977 return nEndif;
978 else
979 nth_Cmd = nElse;
980
981 sHeadCommand = "elseif";
982 }
983 } while (vCmdArray[nth_Cmd].sCommand.find(">>elseif") != std::string::npos);
984
985 // This is the else-case, if it is available. Will enter this
986 // section, if the loop condition fails.
987 for (int __i = nth_Cmd+1; __i < (int)vCmdArray.size(); __i++)
988 {
989 nCurrentCommand = __i;
990
991 // If we're reaching the line with the
992 // corresponding endif statement, we'll
993 // return with this line as index
994 if (__i >= nEndif)
995 return nEndif;
996
997 // If this is not the first line of the command block
998 // try to find control flow statements in the first column
999 if (vCmdArray[__i].bFlowCtrlStatement)
1000 {
1001 // Evaluate the flow control commands
1002 int nReturn = evalForkFlowCommands(__i, nth_loop);
1003
1004 // Handle the return value
1005 if (nReturn == FLOWCTRL_ERROR
1006 || nReturn == FLOWCTRL_RETURN
1007 || nReturn == FLOWCTRL_BREAK
1008 || nReturn == FLOWCTRL_CONTINUE)
1009 return nReturn;
1010 else if (nReturn != FLOWCTRL_NO_CMD)
1011 __i = nReturn;
1012
1013 continue;
1014 }
1015
1017 return FLOWCTRL_CONTINUE;
1018 else if (nCalcType[__i] & CALCTYPE_BREAKCMD)
1019 return FLOWCTRL_BREAK;
1020 else if (!nCalcType[__i])
1021 {
1022 std::string sCommand = findCommand(vCmdArray[__i].sCommand).sString;
1023
1024 // "continue" and "break" are both exiting the current
1025 // condition, but they are yielding different signals
1026 if (sCommand == "continue")
1027 {
1029 return FLOWCTRL_CONTINUE;
1030 }
1031
1032 if (sCommand == "break")
1033 {
1035 return FLOWCTRL_BREAK;
1036 }
1037 }
1038
1040 _parserRef->SetIndex(__i);
1041
1042 try
1043 {
1044 // Evaluate the command line with the calc function
1045 if (calc(vCmdArray[__i].sCommand, __i) == FLOWCTRL_ERROR)
1046 {
1047 if (_optionRef->useDebugger())
1048 {
1053 }
1054
1055 return FLOWCTRL_ERROR;
1056 }
1057
1058 if (bReturnSignal)
1059 return FLOWCTRL_RETURN;
1060 }
1061 catch (...)
1062 {
1063 if (_optionRef->useDebugger())
1064 {
1069 }
1070
1071 NumeReKernel::getInstance()->getDebugger().showError(current_exception());
1072 nCalcType[__i] = CALCTYPE_NONE;
1074 }
1075 }
1076
1077 return vCmdArray.size();
1078}
1079
1080
1092int FlowCtrl::switch_fork(int nth_Cmd, int nth_loop)
1093{
1094 if (!vCmdArray[nth_Cmd].sFlowCtrlHeader.length())
1095 vCmdArray[nth_Cmd].sFlowCtrlHeader = extractHeaderExpression(vCmdArray[nth_Cmd].sCommand);
1096
1097 std::string sSwitch_Condition = vCmdArray[nth_Cmd].sFlowCtrlHeader;
1098 int nNextCase = nJumpTable[nth_Cmd][BLOCK_MIDDLE]; // Position of next case/default
1099 int nSwitchEnd = nJumpTable[nth_Cmd][BLOCK_END];
1100 bPrintedStatus = false;
1101 value_type* v;
1102 int nNum = 0;
1103
1104 // Evaluate the header of the current switch statement and its cases
1105 v = evalHeader(nNum, sSwitch_Condition, false, nth_Cmd, "switch");
1106
1107 // Search for the correct first(!) case
1108 for (int i = 0; i < nNum; i++)
1109 {
1110 if (v[i] == 0.0)
1111 nNextCase = nJumpTable[nNextCase][BLOCK_MIDDLE];
1112 else
1113 break;
1114
1115 if (nNextCase < 0)
1116 return nSwitchEnd;
1117 }
1118
1119 // Set the start index of the current switch case
1120 if (nNextCase == -1)
1121 return nSwitchEnd;
1122 else
1123 nth_Cmd = nNextCase;
1124
1125 // The inner loop goes through the contained
1126 // commands
1127 for (int __i = nth_Cmd+1; __i < (int)vCmdArray.size(); __i++)
1128 {
1129 nCurrentCommand = __i;
1130 // If we reach the end of the
1131 // current block, return with the last line
1132 // of this block
1133 if (__i >= nSwitchEnd)
1134 return nSwitchEnd;
1135
1136 // If this is not the first line of the command block
1137 // try to find control flow statements in the first column
1138 if (vCmdArray[__i].bFlowCtrlStatement)
1139 {
1140 // Evaluate the flow control commands
1141 int nReturn = evalForkFlowCommands(__i, nth_loop);
1142
1143 // Handle the return value
1144 if (nReturn == FLOWCTRL_ERROR
1145 || nReturn == FLOWCTRL_RETURN
1146 || nReturn == FLOWCTRL_CONTINUE)
1147 return nReturn;
1148 else if (nReturn == FLOWCTRL_BREAK)
1149 {
1150 // We don't propagate the break signal
1151 return nSwitchEnd;
1152 }
1153 else if (nReturn != FLOWCTRL_NO_CMD)
1154 __i = nReturn;
1155
1156 continue;
1157 }
1158
1159 // Handle the "continue" and "break" flow
1160 // control statements
1162 return FLOWCTRL_CONTINUE;
1163 else if (nCalcType[__i] & CALCTYPE_BREAKCMD)
1164 {
1165 // We don't propagate the break signal in this case
1166 return nSwitchEnd;
1167 }
1168 else if (!nCalcType[__i])
1169 {
1170 std::string sCommand = findCommand(vCmdArray[__i].sCommand).sString;
1171
1172 // "continue" and "break" are both exiting the current
1173 // condition, but they are yielding different signals
1174 if (sCommand == "continue")
1175 {
1177 return FLOWCTRL_CONTINUE;
1178 }
1179
1180 if (sCommand == "break")
1181 {
1182 // We don't propagate the break signal in this case
1184 return nSwitchEnd;
1185 }
1186 }
1187
1188 // Increment the parser index, if the loop parsing
1189 // mode was activated
1191 _parserRef->SetIndex(__i);
1192
1193 try
1194 {
1195 // Evaluate the command line with the calc function
1196 if (calc(vCmdArray[__i].sCommand, __i) == FLOWCTRL_ERROR)
1197 {
1198 if (_optionRef->useDebugger())
1199 {
1204 }
1205
1206 return FLOWCTRL_ERROR;
1207 }
1208
1209 if (bReturnSignal)
1210 return FLOWCTRL_RETURN;
1211 }
1212 catch (...)
1213 {
1214 if (_optionRef->useDebugger())
1215 {
1220 }
1221
1222 NumeReKernel::getInstance()->getDebugger().showError(current_exception());
1223 nCalcType[__i] = CALCTYPE_NONE;
1225 }
1226 }
1227
1228 return vCmdArray.size();
1229}
1230
1231
1240int FlowCtrl::try_catch(int nth_Cmd, int nth_loop)
1241{
1242 int nNextCatch = nJumpTable[nth_Cmd][BLOCK_MIDDLE]; // Position of next case/default
1243 int nTryEnd = nJumpTable[nth_Cmd][BLOCK_END];
1244 bPrintedStatus = false;
1245
1246 // The inner loop goes through the contained
1247 // commands
1248 for (int __i = nth_Cmd+1; __i < (int)vCmdArray.size(); __i++)
1249 {
1250 nCurrentCommand = __i;
1251 // If we reach the end of the
1252 // current block, return with the last line
1253 // of this block
1254 if (__i >= nTryEnd || (nNextCatch >= 0 && __i >= nNextCatch))
1255 return nTryEnd;
1256
1257 try
1258 {
1259 // If this is not the first line of the command block
1260 // try to find control flow statements in the first column
1261 if (vCmdArray[__i].bFlowCtrlStatement)
1262 {
1263 // Evaluate the flow control commands
1264 int nReturn = evalForkFlowCommands(__i, nth_loop);
1265
1266 // Handle the return value
1267 if (nReturn == FLOWCTRL_ERROR
1268 || nReturn == FLOWCTRL_RETURN
1269 || nReturn == FLOWCTRL_BREAK
1270 || nReturn == FLOWCTRL_CONTINUE)
1271 return nReturn;
1272 else if (nReturn != FLOWCTRL_NO_CMD)
1273 __i = nReturn;
1274
1275 continue;
1276 }
1277
1278 // Handle the "continue" and "break" flow
1279 // control statements
1281 return FLOWCTRL_CONTINUE;
1282 else if (nCalcType[__i] & CALCTYPE_BREAKCMD)
1283 return FLOWCTRL_BREAK;
1284 else if (!nCalcType[__i])
1285 {
1286 std::string sCommand = findCommand(vCmdArray[__i].sCommand).sString;
1287
1288 // "continue" and "break" are both exiting the current
1289 // condition, but they are yielding different signals
1290 if (sCommand == "continue")
1291 {
1293 return FLOWCTRL_CONTINUE;
1294 }
1295
1296 if (sCommand == "break")
1297 {
1298 // We don't propagate the break signal in this case
1300 return FLOWCTRL_BREAK;
1301 }
1302 }
1303
1304 // Increment the parser index, if the loop parsing
1305 // mode was activated
1307 _parserRef->SetIndex(__i);
1308
1309 // Evaluate the command line with the calc function
1310 if (calc(vCmdArray[__i].sCommand, __i) == FLOWCTRL_ERROR)
1311 {
1312 if (_optionRef->useDebugger())
1313 {
1318 }
1319
1320 return FLOWCTRL_ERROR;
1321 }
1322
1323 if (bReturnSignal)
1324 return FLOWCTRL_RETURN;
1325 }
1326 catch (...)
1327 {
1328 if (_optionRef->useDebugger())
1329 {
1334 }
1335
1336 NumeReKernel::getInstance()->getDebugger().showError(std::current_exception());
1337 nCalcType[__i] = CALCTYPE_NONE;
1338
1339 ErrorType type = getErrorType(std::current_exception());
1340
1341 // We won't catch every possible error
1342 if (type == TYPE_ABORT || type == TYPE_INTERNALERROR || type == TYPE_CRITICALERROR)
1344
1345 // Search for the correct first(!) case
1346 while (nNextCatch >= 0)
1347 {
1348 std::string sCatchExpression = vCmdArray[nNextCatch].sCommand;
1349 sCatchExpression.erase(0, sCatchExpression.find(">>catch")+7);
1350
1351 if (sCatchExpression.find_first_not_of(" :") == std::string::npos
1352 || sCatchExpression.find(" " + errorTypeToString(type)) != std::string::npos)
1353 break;
1354 else
1355 nNextCatch = nJumpTable[nNextCatch][BLOCK_MIDDLE];
1356 }
1357
1358 // Set the start index of the current switch case
1359 if (nNextCatch < 0)
1361
1362 nth_Cmd = nNextCatch;
1364 nNextCatch = nJumpTable[nNextCatch][BLOCK_MIDDLE];
1365
1366 // Execute handler code
1367 // The inner loop goes through the contained
1368 // commands
1369 for (int __i = nth_Cmd+1; __i < (int)vCmdArray.size(); __i++)
1370 {
1371 nCurrentCommand = __i;
1372 // If we reach the end of the
1373 // current block, return with the last line
1374 // of this block
1375 if (__i >= nTryEnd || (nNextCatch >= 0 && __i >= nNextCatch))
1376 return nTryEnd;
1377
1378 if (__i != nth_Cmd)
1379 {
1380 // If this is not the first line of the command block
1381 // try to find control flow statements in the first column
1382 if (vCmdArray[__i].bFlowCtrlStatement)
1383 {
1384 // Evaluate the flow control commands
1385 int nReturn = evalForkFlowCommands(__i, nth_loop);
1386
1387 // Handle the return value
1388 if (nReturn == FLOWCTRL_ERROR
1389 || nReturn == FLOWCTRL_RETURN
1390 || nReturn == FLOWCTRL_BREAK
1391 || nReturn == FLOWCTRL_CONTINUE)
1392 return nReturn;
1393 else if (nReturn != FLOWCTRL_NO_CMD)
1394 __i = nReturn;
1395
1396 continue;
1397 }
1398 }
1399
1400 // Handle the "continue" and "break" flow
1401 // control statements
1403 return FLOWCTRL_CONTINUE;
1404 else if (nCalcType[__i] & CALCTYPE_BREAKCMD)
1405 return FLOWCTRL_BREAK;
1406 else if (!nCalcType[__i])
1407 {
1408 std::string sCommand = findCommand(vCmdArray[__i].sCommand).sString;
1409
1410 // "continue" and "break" are both exiting the current
1411 // condition, but they are yielding different signals
1412 if (sCommand == "continue")
1413 {
1415 return FLOWCTRL_CONTINUE;
1416 }
1417
1418 if (sCommand == "break")
1419 {
1420 // We don't propagate the break signal in this case
1422 return FLOWCTRL_BREAK;
1423 }
1424 }
1425
1426 // Increment the parser index, if the loop parsing
1427 // mode was activated
1429 _parserRef->SetIndex(__i);
1430
1431 try
1432 {
1433 if (findCommand(vCmdArray[__i].sCommand).sString == "rethrow")
1434 rethrow_exception(current_exception());
1435
1436 // Evaluate the command line with the calc function
1437 if (calc(vCmdArray[__i].sCommand, __i) == FLOWCTRL_ERROR)
1438 {
1439 if (_optionRef->useDebugger())
1440 {
1445 }
1446
1447 return FLOWCTRL_ERROR;
1448 }
1449
1450 if (bReturnSignal)
1451 return FLOWCTRL_RETURN;
1452 }
1453 catch (...)
1454 {
1455 if (_optionRef->useDebugger())
1456 {
1461 }
1462
1463 NumeReKernel::getInstance()->getDebugger().showError(current_exception());
1464 nCalcType[__i] = CALCTYPE_NONE;
1466 }
1467 }
1468 }
1469 }
1470
1471 return vCmdArray.size();
1472}
1473
1474
1490value_type* FlowCtrl::evalHeader(int& nNum, std::string& sHeadExpression, bool bIsForHead, int nth_Cmd, const std::string& sHeadCommand)
1491{
1492 int nCurrentCalcType = nCalcType[nth_Cmd];
1493 std::string sCache;
1494 nCurrentCommand = nth_Cmd;
1495
1496 // Eval the debugger breakpoint first
1497 if (nCurrentCalcType & CALCTYPE_DEBUGBREAKPOINT
1498 || sHeadExpression.substr(sHeadExpression.find_first_not_of(' '), 2) == "|>"
1500 {
1501 if (sHeadExpression.substr(sHeadExpression.find_first_not_of(' '), 2) == "|>")
1503
1504 if (sHeadExpression.substr(sHeadExpression.find_first_not_of(' '), 2) == "|>")
1505 {
1506 sHeadExpression.erase(sHeadExpression.find_first_not_of(' '), 2);
1507 StripSpaces(sHeadExpression);
1508 }
1509
1510 if (_optionRef->useDebugger()
1513 {
1516 }
1517 }
1518
1519 // Check, whether the user tried to abort the
1520 // current evaluation
1522 {
1523 if (bPrintedStatus)
1524 NumeReKernel::printPreFmt(" " + _lang.get("COMMON_CANCEL"));
1525
1527 }
1528
1529 // Update the parser index, if the loop parsing
1530 // mode was activated
1532 _parserRef->SetIndex(nth_Cmd);
1533
1534 // Replace the function definitions, if not already done
1535 if (!bFunctionsReplaced)
1536 {
1537 if (!_functionRef->call(sHeadExpression))
1539 }
1540
1541 // If the expression is numerical-only, evaluate it here
1542 if (nCurrentCalcType & CALCTYPE_NUMERICAL)
1543 {
1544 mu::value_type* v;
1545
1546 // As long as bytecode parsing is not globally available,
1547 // this condition has to stay at this place
1549 && !_parserRef->IsAlreadyParsed(sHeadExpression))
1550 _parserRef->SetExpr(sHeadExpression);
1551
1552 // Evaluate all remaining equations in the stack
1553 do
1554 {
1555 v = _parserRef->Eval(nNum);
1556 } while (_parserRef->IsNotLastStackItem());
1557
1558 return v;
1559 }
1560
1561 // Include procedure and plugin calls
1562 if (nJumpTable[nth_Cmd][PROCEDURE_INTERFACE])
1563 {
1565 {
1568 }
1569
1570 // Call the procedure interface function
1571 ProcedureInterfaceRetVal nReturn = procedureInterface(sHeadExpression, *_parserRef,
1573 *_pDataRef, *_scriptRef, *_optionRef, nth_Cmd);
1574
1575 // Handle the return value
1576 if (nReturn == INTERFACE_ERROR)
1578 else if (nReturn == INTERFACE_EMPTY)
1579 sHeadExpression = "false";
1580
1582 {
1583 _parserRef->PauseLoopMode(false);
1584 _parserRef->LockPause(false);
1585 }
1586
1587 if (nReturn == INTERFACE_EMPTY || nReturn == INTERFACE_VALUE)
1588 nJumpTable[nth_Cmd][PROCEDURE_INTERFACE] = 1;
1589 else
1590 nJumpTable[nth_Cmd][PROCEDURE_INTERFACE] = 0;
1591 }
1592
1593 // Catch and evaluate all data and cache calls
1594 if (nCurrentCalcType & CALCTYPE_DATAACCESS || !nCurrentCalcType)
1595 {
1596 if ((nCurrentCalcType && !(nCurrentCalcType & CALCTYPE_STRING))
1597 || (_dataRef->containsTablesOrClusters(sHeadExpression)
1599 {
1600 if (!nCurrentCalcType)
1601 nCalcType[nth_Cmd] |= CALCTYPE_DATAACCESS;
1602
1605 && !_parserRef->GetCachedEquation().length())
1606 _parserRef->SetCompiling(true);
1607
1608 sCache = getDataElements(sHeadExpression, *_parserRef, *_dataRef, *_optionRef);
1609
1610 if (_parserRef->IsCompiling()
1612 {
1613 _parserRef->CacheCurrentEquation(sHeadExpression);
1615 }
1616
1617 _parserRef->SetCompiling(false);
1618 }
1619 }
1620
1621 // Evaluate std::strings
1622 if (nCurrentCalcType & CALCTYPE_STRING || !nCurrentCalcType)
1623 {
1624 if (nCurrentCalcType || NumeReKernel::getInstance()->getStringParser().isStringExpression(sHeadExpression))
1625 {
1626 if (!nCurrentCalcType)
1627 nCalcType[nth_Cmd] |= CALCTYPE_STRING;
1628
1631
1632 // Call the std::string parser
1633 auto retVal = NumeReKernel::getInstance()->getStringParser().evalAndFormat(sHeadExpression, sCache, true);
1634
1635 // Evaluate the return value
1637 {
1638 StripSpaces(sHeadExpression);
1639
1640 if (bIsForHead)
1641 {
1642 if (_optionRef->useDebugger())
1646
1648 sHeadExpression,
1650 }
1651 else
1652 {
1653 StripSpaces(sHeadExpression);
1654
1655 if (sHeadExpression != "\"\"")
1656 sHeadExpression = "true";
1657 else
1658 sHeadExpression = "false";
1659 }
1660 }
1661
1662 // It's possible that the user might have done
1663 // something weird with std::string operations transformed
1664 // into a regular expression. Replace the local
1665 // variables here
1666 replaceLocalVars(sHeadExpression);
1667
1669 _parserRef->PauseLoopMode(false);
1670 }
1671 }
1672
1673 // Evalute the already prepared equation
1674 if (!_parserRef->IsAlreadyParsed(sHeadExpression))
1675 _parserRef->SetExpr(sHeadExpression);
1676
1677 if (!nCalcType[nth_Cmd] && !nJumpTable[nth_Cmd][PROCEDURE_INTERFACE])
1678 nCalcType[nth_Cmd] |= CALCTYPE_NUMERICAL;
1679
1680 return _parserRef->Eval(nNum);
1681}
1682
1683
1696NumeRe::Cluster FlowCtrl::evalRangeBasedHeader(std::string& sHeadExpression, int nth_Cmd, const std::string& sHeadCommand)
1697{
1698 NumeRe::Cluster result;
1699 mu::value_type* v;
1700 int nNum;
1701 int nCurrentCalcType = nCalcType[nth_Cmd];
1702 std::string sCache;
1703 nCurrentCommand = nth_Cmd;
1704
1705 // Eval the debugger breakpoint first
1706 if (nCurrentCalcType & CALCTYPE_DEBUGBREAKPOINT
1707 || sHeadExpression.substr(sHeadExpression.find_first_not_of(' '), 2) == "|>"
1709 {
1710 if (sHeadExpression.substr(sHeadExpression.find_first_not_of(' '), 2) == "|>")
1712
1713 if (sHeadExpression.substr(sHeadExpression.find_first_not_of(' '), 2) == "|>")
1714 {
1715 sHeadExpression.erase(sHeadExpression.find_first_not_of(' '), 2);
1716 StripSpaces(sHeadExpression);
1717 }
1718
1719 if (_optionRef->useDebugger()
1722 {
1725 }
1726 }
1727
1728 // Check, whether the user tried to abort the
1729 // current evaluation
1731 {
1732 if (bPrintedStatus)
1733 NumeReKernel::printPreFmt(" " + _lang.get("COMMON_CANCEL"));
1734
1736 }
1737
1738 // Update the parser index, if the loop parsing
1739 // mode was activated
1741 _parserRef->SetIndex(nth_Cmd);
1742
1743 // Replace the function definitions, if not already done
1744 if (!bFunctionsReplaced)
1745 {
1746 if (!_functionRef->call(sHeadExpression))
1748 }
1749
1750 // If the expression is numerical-only, evaluate it here
1751 if (nCurrentCalcType & CALCTYPE_NUMERICAL)
1752 {
1753 // As long as bytecode parsing is not globally available,
1754 // this condition has to stay at this place
1756 && !_parserRef->IsAlreadyParsed(sHeadExpression))
1757 _parserRef->SetExpr(sHeadExpression);
1758
1759 // Evaluate all remaining equations in the stack
1760 do
1761 {
1762 v = _parserRef->Eval(nNum);
1763 } while (_parserRef->IsNotLastStackItem());
1764
1765 result.setDoubleArray(nNum, v);
1766 return result;
1767 }
1768
1769 // Include procedure and plugin calls
1770 if (nJumpTable[nth_Cmd][PROCEDURE_INTERFACE])
1771 {
1773 {
1776 }
1777
1778 // Call the procedure interface function
1779 ProcedureInterfaceRetVal nReturn = procedureInterface(sHeadExpression, *_parserRef,
1781 *_pDataRef, *_scriptRef, *_optionRef, nth_Cmd);
1782
1783 // Handle the return value
1784 if (nReturn == INTERFACE_ERROR)
1786 else if (nReturn == INTERFACE_EMPTY)
1787 sHeadExpression = "false";
1788
1790 {
1791 _parserRef->PauseLoopMode(false);
1792 _parserRef->LockPause(false);
1793 }
1794
1795 if (nReturn == INTERFACE_EMPTY || nReturn == INTERFACE_VALUE)
1796 nJumpTable[nth_Cmd][PROCEDURE_INTERFACE] = 1;
1797 else
1798 nJumpTable[nth_Cmd][PROCEDURE_INTERFACE] = 0;
1799 }
1800
1801 // Catch and evaluate all data and cache calls
1802 if (nCurrentCalcType & CALCTYPE_DATAACCESS || !nCurrentCalcType)
1803 {
1804 if ((nCurrentCalcType && !(nCurrentCalcType & CALCTYPE_STRING))
1805 || (_dataRef->containsTablesOrClusters(sHeadExpression)
1807 {
1808 if (!nCurrentCalcType)
1809 nCalcType[nth_Cmd] |= CALCTYPE_DATAACCESS;
1810
1813 && !_parserRef->GetCachedEquation().length())
1814 _parserRef->SetCompiling(true);
1815
1816 sCache = getDataElements(sHeadExpression, *_parserRef, *_dataRef, *_optionRef);
1817
1818 if (_parserRef->IsCompiling()
1820 {
1821 _parserRef->CacheCurrentEquation(sHeadExpression);
1823 }
1824
1825 _parserRef->SetCompiling(false);
1826 }
1827 }
1828
1829 // Evaluate std::strings
1830 if (nCurrentCalcType & CALCTYPE_STRING || !nCurrentCalcType)
1831 {
1832 if (nCurrentCalcType || NumeReKernel::getInstance()->getStringParser().isStringExpression(sHeadExpression))
1833 {
1834 if (!nCurrentCalcType)
1835 nCalcType[nth_Cmd] |= CALCTYPE_STRING;
1836
1839
1840 // Call the std::string parser
1841 auto retVal = NumeReKernel::getInstance()->getStringParser().evalAndFormat(sHeadExpression, sCache, true);
1842
1843 // Evaluate the return value
1845 {
1846 result = NumeReKernel::getInstance()->getAns();
1847
1849 _parserRef->PauseLoopMode(false);
1850
1851 return result;
1852 }
1853
1854 // It's possible that the user might have done
1855 // something weird with std::string operations transformed
1856 // into a regular expression. Replace the local
1857 // variables here
1858 replaceLocalVars(sHeadExpression);
1859
1861 _parserRef->PauseLoopMode(false);
1862 }
1863 }
1864
1865 // Evalute the already prepared equation
1866 if (!_parserRef->IsAlreadyParsed(sHeadExpression))
1867 _parserRef->SetExpr(sHeadExpression);
1868
1869 if (!nCalcType[nth_Cmd] && !nJumpTable[nth_Cmd][PROCEDURE_INTERFACE])
1870 nCalcType[nth_Cmd] |= CALCTYPE_NUMERICAL;
1871
1872 v = _parserRef->Eval(nNum);
1873 result.setDoubleArray(nNum, v);
1874 return result;
1875}
1876
1877
1888int FlowCtrl::evalForkFlowCommands(int __i, int nth_loop)
1889{
1890 // Do nothing,if here's no flow command
1891 if (nJumpTable[__i][BLOCK_END] == NO_FLOW_COMMAND || !vCmdArray[__i].fcFn)
1892 return FLOWCTRL_NO_CMD;
1893
1894 // Evaluate the possible flow control statements.
1895 // In this case, we have to consider the possiblity
1896 // that we need to display a status
1897 if (nth_loop <= -1)
1898 {
1899 if (vCmdArray[__i].sCommand.substr(0, 3) == "for")
1900 {
1901 bPrintedStatus = false;
1902 __i = (this->*vCmdArray[__i].fcFn)(__i, nth_loop+1);
1903
1904 if (!bReturnSignal && !bMask && __i != -1)
1905 {
1906 if (bSilent)
1907 NumeReKernel::printPreFmt("\r|FOR> " + _lang.get("COMMON_EVALUATING") + " ... 100 %: "
1908 + _lang.get("COMMON_SUCCESS") + ".\n");
1909 else
1910 NumeReKernel::printPreFmt("|FOR> " + _lang.get("COMMON_SUCCESS") + ".\n");
1911 }
1912
1913 return __i;
1914 }
1915 else if (vCmdArray[__i].sCommand.substr(0, 5) == "while")
1916 {
1917 bPrintedStatus = false;
1918 __i = (this->*vCmdArray[__i].fcFn)(__i, nth_loop+1);
1919
1920 if (!bReturnSignal && !bMask && __i != -1)
1921 {
1922 if (bSilent)
1923 NumeReKernel::printPreFmt("\r|WHL> " + _lang.get("COMMON_EVALUATING") + " ...: "
1924 + _lang.get("COMMON_SUCCESS") + ".\n");
1925 else
1926 NumeReKernel::printPreFmt("|WHL> " + _lang.get("COMMON_SUCCESS") + ".\n");
1927 }
1928
1929 return __i;
1930 }
1931 }
1932
1933 return (this->*vCmdArray[__i].fcFn)(__i, nth_loop+1);
1934}
1935
1936
1948void FlowCtrl::setCommand(std::string& __sCmd, int nCurrentLine)
1949{
1950 bool bDebuggingBreakPoint = (__sCmd.substr(__sCmd.find_first_not_of(' '), 2) == "|>");
1951 std::string sAppendedExpression = "";
1952
1953 // Remove the breakpoint syntax
1954 if (bDebuggingBreakPoint)
1955 {
1956 __sCmd.erase(__sCmd.find_first_not_of(' '), 2);
1957 StripSpaces(__sCmd);
1958 }
1959
1960 if (bReturnSignal)
1961 {
1962 bReturnSignal = false;
1963 nReturnType = 1;
1964 }
1965
1966 // If one passes the "abort" command, then NumeRe will
1967 // clean the internal buffer and return to the terminal
1968 if (__sCmd == "abort")
1969 {
1970 reset();
1971 NumeReKernel::print(_lang.get("LOOP_SETCOMMAND_ABORT"));
1972 return;
1973 }
1974
1975 // Remove unnecessary whitespaces
1976 StripSpaces(__sCmd);
1977
1978 // Find the command of the current command line
1979 // if there's any
1980 std::string command = findCommand(__sCmd).sString;
1981
1982 if (isAnyFlowCtrlStatement(command))
1983 {
1984 // Ensure that the parentheses are
1985 // matching each other
1986 if (!validateParenthesisNumber(__sCmd))
1987 {
1988 reset();
1989 throw SyntaxError(SyntaxError::UNMATCHED_PARENTHESIS, __sCmd, __sCmd.find('('));
1990 }
1991
1992 FlowCtrlFunction fn = nullptr;
1993
1994 if (command == "for")
1995 {
1996 sLoopNames += ";FOR";
1998
1999 bool isRangeBased = __sCmd.find("->") != std::string::npos;
2000
2001 // Check the flow control argument for completeness
2002 if (!checkFlowControlArgument(__sCmd, true))
2003 {
2004 reset();
2006 }
2007
2008 // Replace the colon operator with a comma, which is faster
2009 // because it can be parsed internally
2010 size_t nQuotes = 0;
2011 size_t nPos = std::string::npos;
2012
2013 for (size_t i = __sCmd.find('(')+1; i < getMatchingParenthesis(__sCmd); i++)
2014 {
2015 if (__sCmd[i] == '"' && __sCmd[i-1] != '\\')
2016 nQuotes++;
2017
2018 if (!(nQuotes % 2))
2019 {
2020 if (__sCmd[i] == '(' || __sCmd[i] == '{' || __sCmd[i] == '[')
2021 i += getMatchingParenthesis(StringView(__sCmd, i));
2022
2023 if (__sCmd[i] == ':')
2024 {
2025 nPos = i;
2026 break;
2027 }
2028 }
2029 }
2030
2031 if (nPos == std::string::npos && isRangeBased)
2033 else
2034 {
2035 if (nPos != std::string::npos)
2036 __sCmd[nPos] = ',';
2037
2038 replaceAll(__sCmd, "->", "=");
2039 fn = FlowCtrl::for_loop;
2040 }
2041 }
2042 else if (command == "while")
2043 {
2044 sLoopNames += ";WHL";
2046
2047 // check the flow control argument for completeness
2048 if (!checkFlowControlArgument(__sCmd, false))
2049 {
2050 reset();
2052 }
2053
2055 }
2056 else if (command == "if")
2057 {
2058 sLoopNames += ";IF";
2060
2061 // check the flow control argument for completeness
2062 if (!checkFlowControlArgument(__sCmd, false))
2063 {
2064 reset();
2066 }
2067
2068 __sCmd = toString(nFlowCtrlStatements[FC_IF]) + ">>" + __sCmd;
2069 fn = FlowCtrl::if_fork;
2070 }
2071 else if (command == "else" || command == "elseif")
2072 {
2073 if (nFlowCtrlStatements[FC_IF] && (getCurrentBlock() == "IF" || getCurrentBlock() == "ELIF"))
2074 {
2075 if (command == "elseif")
2076 {
2077 sLoopNames = sLoopNames.substr(0, sLoopNames.rfind(';')) + ";ELIF";
2078
2079 // check the flow control argument for completeness
2080 if (!checkFlowControlArgument(__sCmd, false))
2081 {
2082 reset();
2084 }
2085 }
2086 else
2087 {
2088 sLoopNames = sLoopNames.substr(0, sLoopNames.rfind(';')) + ";ELSE";
2089 }
2090
2091 __sCmd = toString(nFlowCtrlStatements[FC_IF]) + ">>" + __sCmd;
2092 }
2093 else
2094 return;
2095 }
2096 else if (command == "endif")
2097 {
2098 if (nFlowCtrlStatements[FC_IF] && (getCurrentBlock() == "IF" || getCurrentBlock() == "ELIF" || getCurrentBlock() == "ELSE"))
2099 {
2100 sLoopNames = sLoopNames.substr(0, sLoopNames.rfind(';'));
2101 __sCmd = toString(nFlowCtrlStatements[FC_IF]) + ">>" + __sCmd;
2103 }
2104 else
2105 return;
2106 }
2107 else if (command == "switch")
2108 {
2109 sLoopNames += ";SWCH";
2111
2112 // check the flow control argument for completeness
2113 if (!checkFlowControlArgument(__sCmd, false))
2114 {
2115 reset();
2117 }
2118
2119 __sCmd = toString(nFlowCtrlStatements[FC_SWITCH]) + ">>" + __sCmd;
2121 }
2122 else if (command == "case" || command == "default")
2123 {
2124 if (nFlowCtrlStatements[FC_SWITCH] && (getCurrentBlock() == "SWCH" || getCurrentBlock() == "CASE"))
2125 {
2126 // check the case definition for completeness
2127 if (!checkCaseValue(__sCmd))
2128 {
2129 reset();
2131 }
2132
2133 // Set the corresponding loop names
2134 if (command == "default")
2135 {
2136 sLoopNames = sLoopNames.substr(0, sLoopNames.rfind(';')) + ";DEF";
2137 }
2138 else
2139 {
2140 sLoopNames = sLoopNames.substr(0, sLoopNames.rfind(';')) + ";CASE";
2141 }
2142
2143 __sCmd = toString(nFlowCtrlStatements[FC_SWITCH]) + ">>" + __sCmd;
2144 }
2145 else
2146 return;
2147 }
2148 else if (command == "endswitch")
2149 {
2150 if (nFlowCtrlStatements[FC_SWITCH] && (getCurrentBlock() == "SWCH" || getCurrentBlock() == "CASE" || getCurrentBlock() == "DEF"))
2151 {
2152 sLoopNames = sLoopNames.substr(0, sLoopNames.rfind(';'));
2153 __sCmd = toString(nFlowCtrlStatements[FC_SWITCH]) + ">>" + __sCmd;
2155 }
2156 else
2157 return;
2158 }
2159 else if (command == "try")
2160 {
2161 sLoopNames += ";TRY";
2163
2164 __sCmd = toString(nFlowCtrlStatements[FC_TRY]) + ">>" + __sCmd;
2166 }
2167 else if (command == "catch")
2168 {
2169 if (nFlowCtrlStatements[FC_TRY] && (getCurrentBlock() == "TRY" || getCurrentBlock() == "CTCH"))
2170 {
2171 // check the case definition for completeness
2172 if (!checkCaseValue(__sCmd))
2173 {
2174 reset();
2176 }
2177
2178 // Set the corresponding loop names
2179 sLoopNames = sLoopNames.substr(0, sLoopNames.rfind(';')) + ";CTCH";
2180
2181 __sCmd = toString(nFlowCtrlStatements[FC_TRY]) + ">>" + __sCmd;
2182 }
2183 else
2184 return;
2185 }
2186 else if (command == "endtry")
2187 {
2188 if (nFlowCtrlStatements[FC_TRY] && (getCurrentBlock() == "TRY" || getCurrentBlock() == "CTCH"))
2189 {
2190 sLoopNames = sLoopNames.substr(0, sLoopNames.rfind(';'));
2191 __sCmd = toString(nFlowCtrlStatements[FC_TRY]) + ">>" + __sCmd;
2193 }
2194 else
2195 return;
2196 }
2197 else if (command == "endfor")
2198 {
2199 if (nFlowCtrlStatements[FC_FOR] && getCurrentBlock() == "FOR")
2200 {
2201 sLoopNames = sLoopNames.substr(0, sLoopNames.rfind(';'));
2203 }
2204 else
2205 return;
2206 }
2207 else if (command == "endwhile")
2208 {
2209 if (nFlowCtrlStatements[FC_WHILE] && getCurrentBlock() == "WHL")
2210 {
2211 sLoopNames = sLoopNames.substr(0, sLoopNames.rfind(';'));
2213 }
2214 else
2215 return;
2216 }
2217 else
2218 return;
2219
2220 // If there's something after the current flow
2221 // control statement (i.e. a continued command
2222 // line), then cache this part here
2223 if (__sCmd.find('(') != std::string::npos
2224 && (command == "for"
2225 || command == "if"
2226 || command == "elseif"
2227 || command == "switch"
2228 || command == "while"))
2229 {
2230 sAppendedExpression = __sCmd.substr(getMatchingParenthesis(__sCmd) + 1);
2231 __sCmd.erase(getMatchingParenthesis(__sCmd) + 1);
2232
2233 if (bDebuggingBreakPoint)
2234 __sCmd.insert(__sCmd.find('(')+1, "|>");
2235 }
2236 else if (command == "case" || command == "default" || command == "catch")
2237 {
2238 if (__sCmd.find(':', 4) != std::string::npos
2239 && __sCmd.find_first_not_of(": ", __sCmd.find(':', 4)) != std::string::npos)
2240 {
2241 sAppendedExpression = __sCmd.substr(__sCmd.find(':', 4)+1);
2242 __sCmd.erase(__sCmd.find(':', 4)+1);
2243 }
2244 }
2245 else if (__sCmd.find(' ', 4) != std::string::npos
2246 && __sCmd.find_first_not_of(' ', __sCmd.find(' ', 4)) != std::string::npos
2247 && __sCmd[__sCmd.find_first_not_of(' ', __sCmd.find(' ', 4))] != '-')
2248 {
2249 sAppendedExpression = __sCmd.substr(__sCmd.find(' ', 4));
2250 __sCmd.erase(__sCmd.find(' ', 4));
2251 }
2252
2253 StripSpaces(sAppendedExpression);
2254 StripSpaces(__sCmd);
2255
2256 if (sAppendedExpression.find_first_not_of(";") == std::string::npos)
2257 sAppendedExpression.clear();
2258
2259 // Store the current flow control statement
2260 vCmdArray.push_back(FlowCtrlCommand(__sCmd, nCurrentLine, true, fn));
2261 }
2262 else
2263 {
2264 // If there's a flow control statement somewhere
2265 // in the current std::string, then store this part in
2266 // a temporary cache
2267 size_t nQuotes = 0;
2268
2269 for (size_t n = 0; n < __sCmd.length(); n++)
2270 {
2271 if (__sCmd[n] == '"' && (!n || __sCmd[n-1] != '\\'))
2272 nQuotes++;
2273
2274 if (__sCmd[n] == ' ' && !(nQuotes % 2))
2275 {
2276 if (__sCmd.substr(n, 5) == " for "
2277 || __sCmd.substr(n, 5) == " for("
2278 || __sCmd.substr(n, 7) == " endfor"
2279 || __sCmd.substr(n, 4) == " if "
2280 || __sCmd.substr(n, 4) == " if("
2281 || __sCmd.substr(n, 5) == " else"
2282 || __sCmd.substr(n, 8) == " elseif "
2283 || __sCmd.substr(n, 8) == " elseif("
2284 || __sCmd.substr(n, 6) == " endif"
2285 || __sCmd.substr(n, 8) == " switch "
2286 || __sCmd.substr(n, 8) == " switch("
2287 || __sCmd.substr(n, 6) == " case "
2288 || __sCmd.substr(n, 9) == " default "
2289 || __sCmd.substr(n, 9) == " default:"
2290 || __sCmd.substr(n, 10) == " endswitch"
2291 || __sCmd.substr(n, 4) == " try"
2292 || __sCmd.substr(n, 7) == " catch "
2293 || __sCmd.substr(n, 7) == " catch:"
2294 || __sCmd.substr(n, 7) == " endtry"
2295 || __sCmd.substr(n, 7) == " while "
2296 || __sCmd.substr(n, 7) == " while("
2297 || __sCmd.substr(n, 9) == " endwhile")
2298 {
2299 sAppendedExpression = __sCmd.substr(n + 1);
2300 __sCmd.erase(n);
2301 break;
2302 }
2303 }
2304 }
2305
2306 // Add the breakpoint
2307 if (bDebuggingBreakPoint)
2308 __sCmd.insert(0, "|> ");
2309
2310 // Store the current command line
2311 vCmdArray.push_back(FlowCtrlCommand(__sCmd, nCurrentLine));
2312 }
2313
2314 // If there's a command available and all flow
2315 // control statements have been closed, evaluate
2316 // the complete block
2317 if (vCmdArray.size())
2318 {
2319 if (!getCurrentBlockDepth() && vCmdArray.back().bFlowCtrlStatement)
2320 eval();
2321 }
2322
2323 // If there's something left in the current cache,
2324 // call this function recursively
2325 if (sAppendedExpression.length())
2326 setCommand(sAppendedExpression, nCurrentLine);
2327
2328 return;
2329}
2330
2331
2341{
2342 nReturnType = 1;
2343 ReturnVal.clear();
2344 bUseLoopParsingMode = false;
2345 bFunctionsReplaced = false;
2347 bool bSupressAnswer_back = NumeReKernel::bSupressAnswer;
2348
2350 {
2351 reset();
2352 return;
2353 }
2354
2355 // Copy the references to the centeral objects
2363
2365 bLockedPauseMode = true;
2366
2369
2370 // Evaluate the user options
2372 bMask = true;
2373
2374 // Read the flow control statements only and
2375 // extract the index variables and the flow
2376 // control flags
2377 std::string sVars = extractFlagsAndIndexVariables();
2378
2379 // If already suppressed from somewhere else
2380 if (!_optionRef->systemPrints())
2381 bMask = true;
2382
2383 // If the loop parsing mode is active, ensure that only
2384 // inline procedures are used in this case. Otherwise
2385 // turn it off again. Additionally check for "to_cmd()"
2386 // function, which will also turn the loop parsing mode
2387 // off.
2388 // If no function definition commands are found in the
2389 // command block, replace the definitions with their
2390 // expanded form.
2391 try
2392 {
2395 }
2396 catch (...)
2397 {
2398 reset();
2399 NumeReKernel::bSupressAnswer = bSupressAnswer_back;
2400 throw;
2401 }
2402
2403 // Prepare the bytecode storage
2404 nCalcType.resize(vCmdArray.size(), CALCTYPE_NONE);
2405
2406 // Prepare the jump table
2407 nJumpTable.resize(vCmdArray.size(), std::vector<int>(JUMP_TABLE_ELEMENTS, NO_FLOW_COMMAND));
2408
2409 // Go again through the whole command set and fill
2410 // the jump table with the corresponding block ends
2411 // and pre-evaluate the recursive expressions.
2412 // Furthermore, determine, whether the loop parsing
2413 // mode is reasonable.
2415
2416 // Prepare the array for the local variables
2417 //
2418 // If a loop variable was defined before the
2419 // current loop, this one is used. All others
2420 // are create locally and therefore get
2421 // special names
2422 // prepareLocalVarsAndReplace(sVars);
2423
2424 // Activate the loop mode, if it is not locked
2427
2428 // Start the evaluation of the outermost
2429 // flow control statement
2430 try
2431 {
2432 // Determine the flow control command, which
2433 // is in the first line and call the corresponding
2434 // function for evaluation
2435 if (vCmdArray[0].sCommand.substr(0, 3) == "for")
2436 {
2437 if ((this->*vCmdArray[0].fcFn)(0, 0) == FLOWCTRL_ERROR)
2438 {
2439 if (bSilent || bMask)
2441
2443 }
2444 else if (!bReturnSignal && !bMask)
2445 {
2446 if (bSilent)
2447 NumeReKernel::printPreFmt("\r|FOR> " + _lang.get("COMMON_EVALUATING") + " ... 100 %: " + _lang.get("COMMON_SUCCESS") + ".\n");
2448 else
2449 NumeReKernel::printPreFmt("|FOR> " + _lang.get("COMMON_SUCCESS") + ".\n");
2450 }
2451 }
2452 else if (vCmdArray[0].sCommand.substr(0, 5) == "while")
2453 {
2454 if (while_loop() == FLOWCTRL_ERROR)
2455 {
2456 if (bSilent || bMask)
2458
2460 }
2461 else if (!bReturnSignal && !bMask)
2462 {
2463 if (bSilent)
2464 NumeReKernel::printPreFmt("\r|WHL> " + _lang.get("COMMON_EVALUATING") + " ...: " + _lang.get("COMMON_SUCCESS") + ".\n");
2465 else
2466 NumeReKernel::printPreFmt("|WHL> " + _lang.get("COMMON_SUCCESS") + ".\n");
2467 }
2468 }
2469 else if (vCmdArray[0].sCommand.find(">>if") != std::string::npos)
2470 {
2471 if (if_fork() == FLOWCTRL_ERROR)
2472 {
2473 if (bSilent || bMask)
2475
2477 }
2478 }
2479 else if (vCmdArray[0].sCommand.find(">>switch") != std::string::npos)
2480 {
2481 if (switch_fork() == FLOWCTRL_ERROR)
2482 {
2483 if (bSilent || bMask)
2485
2487 }
2488 }
2489 else if (vCmdArray[0].sCommand.find(">>try") != std::string::npos)
2490 {
2491 if (try_catch() == FLOWCTRL_ERROR)
2492 {
2493 if (bSilent || bMask)
2495
2497 }
2498 }
2499 else
2501 }
2502 catch (...)
2503 {
2504 reset();
2505 NumeReKernel::bSupressAnswer = bSupressAnswer_back;
2506
2508 bLoopSupressAnswer = false;
2509
2510 if (bPrintedStatus)
2512
2513 throw;
2514 }
2515
2516 // Clear memory
2517 reset();
2518
2520 bLoopSupressAnswer = false;
2521
2522 return;
2523}
2524
2525
2535{
2536 vCmdArray.clear();
2537
2538 for (size_t i = 0; i < sVarArray.size(); i++)
2539 {
2540 if (sVarArray[i].find('{') == std::string::npos && sVarArray[i].find("->") == std::string::npos)
2541 {
2542 if (NumeReKernel::getInstance()->getStringParser().isStringVar(sVarArray[i]))
2544 else
2546 }
2547 }
2548
2549 if (mVarMap.size())
2550 {
2551 for (size_t i = 0; i < sVarArray.size(); i++)
2552 {
2553 for (auto iter = mVarMap.begin(); iter != mVarMap.end(); ++iter)
2554 {
2555 if (iter->second == sVarArray[i])
2556 {
2557 mVarMap.erase(iter);
2558 break;
2559 }
2560 }
2561 }
2562
2563 if (!mVarMap.size())
2564 _parserRef->mVarMapPntr = nullptr;
2565 }
2566
2567 if (!vVars.empty())
2568 {
2569 varmap_type::const_iterator item = vVars.begin();
2570
2571 for (; item != vVars.end(); ++item)
2572 {
2573 _parserRef->DefineVar(item->first, item->second);
2574
2575 for (size_t i = 0; i < sVarArray.size(); i++)
2576 {
2577 if (item->first == sVarArray[i])
2578 *item->second = vVarArray[i];
2579 }
2580 }
2581
2582 vVars.clear();
2583 }
2584
2585 vVarArray.clear();
2586 sVarArray.clear();
2587 nJumpTable.clear();
2588 nCalcType.clear();
2589
2592
2593 nLoopSafety = -1;
2594
2595 for (size_t i = 0; i < FC_COUNT; i++)
2596 nFlowCtrlStatements[i] = 0;
2597
2598 bSilent = true;
2599 sLoopNames = "";
2600 sLoopPlotCompose = "";
2601 bMask = false;
2602 nCurrentCommand = 0;
2604
2606 {
2608 bUseLoopParsingMode = false;
2609 }
2610
2611 bLockedPauseMode = false;
2612 bFunctionsReplaced = false;
2613
2614 // Remove obsolete vector variables
2617
2618 for (const auto& cst : inlineClusters)
2619 _dataRef->removeCluster(cst.substr(0, cst.find('{')));
2620
2621 inlineClusters.clear();
2622 _parserRef = nullptr;
2623 _dataRef = nullptr;
2624 _outRef = nullptr;
2625 _optionRef = nullptr;
2626 _functionRef = nullptr;
2627 _pDataRef = nullptr;
2628 _scriptRef = nullptr;
2629
2630 return;
2631}
2632
2633
2646int FlowCtrl::compile(std::string sLine, int nthCmd)
2647{
2648 std::string sCache;
2649 std::string sCommand;
2650
2651 value_type* v = 0;
2652 int nNum = 0;
2653 Indices _idx;
2654 bool bCompiling = false;
2655 bool bWriteToCache = false;
2656 bool bWriteToCluster = false;
2657 bool returnCommand = false;
2660
2661 // Eval the assertion command
2662 if (findCommand(sLine, "assert").sString == "assert")
2663 {
2664 nCalcType[nthCmd] |= CALCTYPE_ASSERT;
2666 sLine.erase(findCommand(sLine, "assert").nPos, 6);
2667 StripSpaces(sLine);
2668 vCmdArray[nthCmd].sCommand.erase(findCommand(vCmdArray[nthCmd].sCommand, "assert").nPos, 6);
2669 StripSpaces(vCmdArray[nthCmd].sCommand);
2670 }
2671
2672
2673 // Eval the debugger breakpoint first
2674 if (sLine.substr(sLine.find_first_not_of(' '), 2) == "|>" || nDebuggerCode == NumeReKernel::DEBUGGER_STEP)
2675 {
2676 if (sLine.substr(sLine.find_first_not_of(' '), 2) == "|>")
2677 {
2679 sLine.erase(sLine.find("|>"), 2);
2680 StripSpaces(sLine);
2681 vCmdArray[nthCmd].sCommand.erase(vCmdArray[nthCmd].sCommand.find("|>"), 2);
2682 StripSpaces(vCmdArray[nthCmd].sCommand);
2683 }
2684
2686 {
2689 }
2690 }
2691
2692 // Handle the suppression semicolon
2693 if (sLine.find_last_not_of(" \t") != std::string::npos && sLine[sLine.find_last_not_of(" \t")] == ';')
2694 {
2695 sLine.erase(sLine.rfind(';'));
2696 bLoopSupressAnswer = true;
2698 vCmdArray[nthCmd].sCommand.erase(vCmdArray[nthCmd].sCommand.rfind(';'));
2699 }
2700 else
2701 bLoopSupressAnswer = false;
2702
2703 sCommand = findCommand(sLine).sString;
2704
2705 // Replace the custom defined functions, if it wasn't already done
2707 && sCommand != "define"
2708 && sCommand != "redef"
2709 && sCommand != "redefine"
2710 && sCommand != "undefine"
2711 && sCommand != "undef"
2712 && sCommand != "ifndef"
2713 && sCommand != "ifndefined")
2714 {
2715 if (!_functionRef->call(sLine))
2716 {
2718 }
2719 }
2720
2721 if (sCommand == "define"
2722 || sCommand == "redef"
2723 || sCommand == "redefine"
2724 || sCommand == "undefine"
2725 || sCommand == "undef"
2726 || sCommand == "ifndef"
2727 || sCommand == "ifndefined")
2728 {
2730 }
2731
2734
2735 // Handle the throw command
2736 if (sCommand == "throw" || sLine == "throw")
2737 {
2738 std::string sErrorToken;
2739
2740 if (sLine.length() > 6 && NumeReKernel::getInstance()->getStringParser().isStringExpression(sLine))
2741 {
2742 if (NumeReKernel::getInstance()->getStringParser().containsStringVars(sLine))
2744
2745 sErrorToken = sLine.substr(findCommand(sLine).nPos+6);
2746 sErrorToken += " -nq";
2748 }
2749
2752 }
2753
2754 // Handle the return command
2755 if (sCommand == "return")
2756 {
2758
2759 std::string sReturnValue = sLine.substr(sLine.find("return") + 6);
2760 StripSpaces(sReturnValue);
2761
2762 if (sReturnValue.back() == ';')
2763 sReturnValue.pop_back();
2764
2765 StripSpaces(sReturnValue);
2766
2767 if (sReturnValue == "void")
2768 {
2769 bReturnSignal = true;
2770 nReturnType = 0;
2771 return FLOWCTRL_RETURN;
2772 }
2773 else if (sReturnValue.find('(') != std::string::npos
2774 && sReturnValue.substr(sReturnValue.find('(')) == "()"
2775 && _dataRef->isTable(sReturnValue.substr(0, sReturnValue.find('('))))
2776 {
2777 ReturnVal.sReturnedTable = sReturnValue.substr(0, sReturnValue.find('('));
2778 bReturnSignal = true;
2779 return FLOWCTRL_RETURN;
2780 }
2781 else if (!sReturnValue.length())
2782 {
2783 ReturnVal.vNumVal.push_back(1.0);
2784 bReturnSignal = true;
2785 return FLOWCTRL_RETURN;
2786 }
2787
2788 sLine = sReturnValue;
2789 returnCommand = true;
2790 }
2791
2792 // Check, whether the user tried to abort the
2793 // current evaluation
2795 {
2796 if (bPrintedStatus)
2797 NumeReKernel::printPreFmt(" " + _lang.get("COMMON_CANCEL"));
2798
2800 }
2801
2802 // Is it a numerical expression, which was already
2803 // parsed? Evaluate it here
2805 {
2806 nCalcType[nthCmd] |= CALCTYPE_NUMERICAL;
2807 v = _parserRef->Eval(nNum);
2809
2810 vAns = v[0];
2812
2813 if (!bLoopSupressAnswer)
2814 {
2815 /* --> Der Benutzer will also die Ergebnisse sehen. Es gibt die Moeglichkeit,
2816 * dass der Parser mehrere Ausdruecke je Zeile auswertet. Dazu muessen die
2817 * Ausdruecke durch Kommata getrennt sein. Damit der Parser bemerkt, dass er
2818 * mehrere Ausdruecke auszuwerten hat, muss man die Auswerte-Funktion des
2819 * Parsers einmal aufgerufen werden <--
2820 */
2822 }
2823
2824 return FLOWCTRL_OK;
2825 }
2826
2827 // Does this contain a plot composition? Combine the
2828 // needed lines here. This is not necessary, if the lines
2829 // are read from a procedure, which will provide the compositon
2830 // in a single line
2831 if ((sCommand == "compose"
2832 || sCommand == "endcompose"
2833 || sLoopPlotCompose.length())
2834 && sCommand != "quit")
2835 {
2836 nCalcType[nthCmd] |= CALCTYPE_COMPOSE;
2837
2838 if (!sLoopPlotCompose.length() && sCommand == "compose")
2839 {
2840 sLoopPlotCompose = "plotcompose ";
2841 return FLOWCTRL_OK;
2842 }
2843 else if (sCommand == "abort")
2844 {
2845 sLoopPlotCompose = "";
2846 return FLOWCTRL_OK;
2847 }
2848 else if (sCommand != "endcompose")
2849 {
2850 if (sCommand.substr(0, 4) == "plot"
2851 || sCommand.substr(0, 4) == "grad"
2852 || sCommand.substr(0, 4) == "dens"
2853 || sCommand.substr(0, 4) == "vect"
2854 || sCommand.substr(0, 4) == "cont"
2855 || sCommand.substr(0, 4) == "surf"
2856 || sCommand.substr(0, 4) == "mesh")
2857 sLoopPlotCompose += sLine + " <<COMPOSE>> ";
2858
2859 return FLOWCTRL_OK;
2860 }
2861 else
2862 {
2863 sLine = sLoopPlotCompose;
2864 sLoopPlotCompose = "";
2865 }
2866 }
2867
2868 // Handle the "to_cmd()" function here
2869 if (sLine.find("to_cmd(") != std::string::npos)
2870 {
2872
2875
2876 unsigned int nPos = 0;
2877
2878 while (sLine.find("to_cmd(", nPos) != std::string::npos)
2879 {
2880 nPos = sLine.find("to_cmd(", nPos) + 6;
2881
2882 if (isInQuotes(sLine, nPos))
2883 continue;
2884
2885 unsigned int nParPos = getMatchingParenthesis(sLine.substr(nPos));
2886
2887 if (nParPos == std::string::npos)
2889
2890 std::string sCmdString = sLine.substr(nPos + 1, nParPos - 1);
2891 StripSpaces(sCmdString);
2892
2893 if (NumeReKernel::getInstance()->getStringParser().isStringExpression(sCmdString))
2894 {
2895 sCmdString += " -nq";
2896 NumeReKernel::getInstance()->getStringParser().evalAndFormat(sCmdString, sCache, true);
2897 sCache = "";
2898 }
2899
2900 sLine = sLine.substr(0, nPos - 6) + sCmdString + sLine.substr(nPos + nParPos + 1);
2901 nPos -= 5;
2902 }
2903
2904 replaceLocalVars(sLine);
2905
2907 _parserRef->PauseLoopMode(false);
2908
2909 sCommand = findCommand(sLine).sString;
2910 }
2911
2912 // Display a progress bar, if it is desired
2913 if (sCommand == "progress" && sLine.length() > 9)
2914 {
2915 nCalcType[nthCmd] |= CALCTYPE_PROGRESS;
2916
2917 value_type* vVals = 0;
2918 std::string sExpr;
2919 std::string sArgument;
2920 int nArgument;
2921
2922 if (NumeReKernel::getInstance()->getStringParser().isStringExpression(sLine))
2923 {
2926
2927 sLine = evaluateParameterValues(sLine);
2928
2930 _parserRef->PauseLoopMode(false);
2931 }
2932
2933 if (sLine.find("-set") != std::string::npos || sLine.find("--") != std::string::npos)
2934 {
2935 if (sLine.find("-set") != std::string::npos)
2936 sArgument = sLine.substr(sLine.find("-set"));
2937 else
2938 sArgument = sLine.substr(sLine.find("--"));
2939
2940 sLine.erase(sLine.find(sArgument));
2941
2942 if (findParameter(sArgument, "first", '='))
2943 {
2944 sExpr = getArgAtPos(sArgument, findParameter(sArgument, "first", '=') + 5) + ",";
2945 }
2946 else
2947 sExpr = "1,";
2948
2949 if (findParameter(sArgument, "last", '='))
2950 {
2951 sExpr += getArgAtPos(sArgument, findParameter(sArgument, "last", '=') + 4);
2952 }
2953 else
2954 sExpr += "100";
2955
2956 if (findParameter(sArgument, "type", '='))
2957 {
2958 sArgument = getArgAtPos(sArgument, findParameter(sArgument, "type", '=') + 4);
2959
2960 if (NumeReKernel::getInstance()->getStringParser().isStringExpression(sArgument))
2961 {
2962 if (sArgument.front() != '"')
2963 sArgument = "\"" + sArgument + "\" -nq";
2964
2967
2968 std::string sDummy;
2969 NumeReKernel::getInstance()->getStringParser().evalAndFormat(sArgument, sDummy, true);
2970
2972 _parserRef->PauseLoopMode(false);
2973 }
2974 }
2975 else
2976 sArgument = "std";
2977 }
2978 else
2979 {
2980 sArgument = "std";
2981 sExpr = "1,100";
2982 }
2983
2984 while (sLine.length() && (sLine[sLine.length() - 1] == ' ' || sLine[sLine.length() - 1] == '-'))
2985 sLine.pop_back();
2986
2987 if (!sLine.length())
2988 return FLOWCTRL_OK;
2989
2990 if (!_parserRef->IsAlreadyParsed(sLine.substr(findCommand(sLine).nPos + 8) + "," + sExpr))
2991 {
2992 _parserRef->SetExpr(sLine.substr(findCommand(sLine).nPos + 8) + "," + sExpr);
2993 }
2994
2995 vVals = _parserRef->Eval(nArgument);
2996 make_progressBar(intCast(vVals[0]), intCast(vVals[1]), intCast(vVals[2]), sArgument);
2997 return FLOWCTRL_OK;
2998 }
2999
3000 // Display the prompt to the user
3001 if (sLine.find("??") != std::string::npos)
3002 {
3004
3005 if (bPrintedStatus)
3007
3008 sLine = promptForUserInput(sLine);
3009 bPrintedStatus = false;
3010 }
3011
3012 // Include procedure and plugin calls
3013 if (nJumpTable[nthCmd][PROCEDURE_INTERFACE])
3014 {
3016 {
3019 }
3020
3021 // Prepend the return statement
3022 if (returnCommand)
3023 sLine.insert(0, "return ");
3024
3026
3028 {
3029 _parserRef->PauseLoopMode(false);
3030 _parserRef->LockPause(false);
3031 }
3032
3033 if (nReturn == INTERFACE_EMPTY || nReturn == INTERFACE_VALUE)
3034 nJumpTable[nthCmd][PROCEDURE_INTERFACE] = 1;
3035 else
3036 nJumpTable[nthCmd][PROCEDURE_INTERFACE] = 0;
3037
3038 if (bReturnSignal)
3039 return FLOWCTRL_RETURN;
3040 else if (returnCommand)
3041 sLine.erase(0, 7); // Rempve the return statement
3042
3043 if (nReturn == INTERFACE_ERROR)
3044 return FLOWCTRL_ERROR;
3045 else if (nReturn == INTERFACE_EMPTY)
3046 return FLOWCTRL_OK;
3047 }
3048
3049 // Handle the procedure commands like "namespace" here
3050 int nProcedureCmd = procedureCmdInterface(sLine);
3051
3052 if (nProcedureCmd)
3053 {
3054 if (nProcedureCmd == 1)
3055 {
3057 return FLOWCTRL_OK;
3058 }
3059 }
3060 else
3061 return FLOWCTRL_ERROR;
3062
3063 // Remove the "explicit" command here
3064 if (sCommand == "explicit")
3065 {
3066 nCalcType[nthCmd] |= CALCTYPE_EXPLICIT;
3067 sLine.erase(findCommand(sLine).nPos, 8);
3068 StripSpaces(sLine);
3069 }
3070
3071 // Evaluate the command, if this is a command
3074
3075 {
3076 bool bSupressAnswer_back = NumeReKernel::bSupressAnswer;
3077 std::string sPreCommandLine = sLine;
3079
3080 switch (commandHandler(sLine))
3081 {
3082 case NO_COMMAND:
3083 {
3084 StripSpaces(sPreCommandLine);
3085 std::string sCurrentLine = sLine;
3086 StripSpaces(sCurrentLine);
3087
3088 if (sPreCommandLine != sCurrentLine)
3089 nCalcType[nthCmd] |= CALCTYPE_COMMAND;
3090 }
3091
3092 break;
3093 case COMMAND_PROCESSED:
3094 NumeReKernel::bSupressAnswer = bSupressAnswer_back;
3095 nCalcType[nthCmd] |= CALCTYPE_COMMAND;
3096
3098 _parserRef->PauseLoopMode(false);
3099
3100 return FLOWCTRL_OK;
3101 case NUMERE_QUIT:
3102 NumeReKernel::bSupressAnswer = bSupressAnswer_back;
3103 nCalcType[nthCmd] |= CALCTYPE_COMMAND;
3104 return FLOWCTRL_OK;
3106 NumeReKernel::bSupressAnswer = bSupressAnswer_back;
3107 nCalcType[nthCmd] |= CALCTYPE_COMMAND;
3108 break;
3109 }
3110
3111 NumeReKernel::bSupressAnswer = bSupressAnswer_back;
3112
3113 // It may be possible that some procedure occures at this
3114 // position. Handle them here
3115 if (sLine.find('$') != std::string::npos)
3117 }
3118
3120 _parserRef->PauseLoopMode(false);
3121
3122 // Expand recursive expressions, if not already done
3124
3125 bool stringParserAdHoc = false;
3126
3127 // Get the data from the used data object
3128 if (!NumeReKernel::getInstance()->getStringParser().isStringExpression(sLine)
3130 {
3131 nCalcType[nthCmd] |= CALCTYPE_DATAACCESS;
3132
3134 {
3135 bCompiling = true;
3136 _parserRef->SetCompiling(true);
3137 }
3138
3139 sCache = getDataElements(sLine, *_parserRef, *_dataRef, *_optionRef);
3140
3141 if (sCache.length())
3142 bWriteToCache = true;
3143
3144 // Ad-hoc bytecode adaption
3145#warning NOTE (numere#1#08/21/21): Might need some adaption, if bytecode issues are experienced
3146 if (NumeReKernel::getInstance()->getStringParser().isStringExpression(sLine))
3147 stringParserAdHoc = true;
3148
3150 {
3153 }
3154
3155 _parserRef->SetCompiling(false);
3156 }
3157 else if (isClusterCandidate(sLine, sCache))
3158 {
3159 bWriteToCache = true;
3160 nCalcType[nthCmd] |= CALCTYPE_DATAACCESS;
3161 }
3162
3163
3164 // Evaluate std::string expressions
3165 if (NumeReKernel::getInstance()->getStringParser().isStringExpression(sLine)
3166 || NumeReKernel::getInstance()->getStringParser().isStringExpression(sCache))
3167 {
3168 // Do not add the byte code, if it was added ad-hoc
3169 if (!stringParserAdHoc)
3171
3172 //if (!bLockedPauseMode && bUseLoopParsingMode)
3173 // _parserRef->PauseLoopMode();
3174
3175 auto retVal = NumeReKernel::getInstance()->getStringParser().evalAndFormat(sLine, sCache, bLoopSupressAnswer, true);
3177
3179 {
3180 //if (!bLockedPauseMode && bUseLoopParsingMode)
3181 // _parserRef->PauseLoopMode(false);
3182
3183 if (returnCommand)
3184 {
3186 bReturnSignal = true;
3187 return FLOWCTRL_RETURN;
3188 }
3189
3190 return FLOWCTRL_OK;
3191 }
3192
3193 replaceLocalVars(sLine);
3194
3195#warning NOTE (erik.haenel#3#): This is changed due to double writes in combination with c{nlen+1} = VAL
3196 //if (sCache.length() && _dataRef->containsTablesOrClusters(sCache) && !bWriteToCache)
3197 // bWriteToCache = true;
3198
3199 if (sCache.length())
3200 {
3201 bWriteToCache = false;
3202 sCache.clear();
3203 }
3204
3205
3206 //if (!bLockedPauseMode && bUseLoopParsingMode)
3207 // _parserRef->PauseLoopMode(false);
3208 }
3209
3210 // Get the target indices of the target data object
3211 if (bWriteToCache)
3212 {
3213 size_t pos;
3214
3215 if (bCompiling)
3216 {
3217 _parserRef->SetCompiling(true);
3218 getIndices(sCache, _idx, *_parserRef, *_dataRef, *_optionRef);
3219
3220 if (sCache[(pos = sCache.find_first_of("({"))] == '{')
3221 bWriteToCluster = true;
3222
3223 if (!isValidIndexSet(_idx))
3224 throw SyntaxError(SyntaxError::INVALID_INDEX, sCache, "", _idx.row.to_string() + ", " + _idx.col.to_string());
3225
3226 if (!bWriteToCluster && _idx.row.isOpenEnd() && _idx.col.isOpenEnd())
3227 throw SyntaxError(SyntaxError::NO_MATRIX, sCache, "");
3228
3229 sCache.erase(pos);
3230 StripSpaces(sCache);
3231
3232 if (!bWriteToCluster)
3233 _parserRef->CacheCurrentTarget(sCache + "(" + _idx.sCompiledAccessEquation + ")");
3234 else
3235 _parserRef->CacheCurrentTarget(sCache + "{" + _idx.sCompiledAccessEquation + "}");
3236
3237 _parserRef->SetCompiling(false);
3238 }
3239 else
3240 {
3241 getIndices(sCache, _idx, *_parserRef, *_dataRef, *_optionRef);
3242 //_idx.col.front() = 0;
3243 //_idx.row.front() = 0;
3244
3245 if (sCache[(pos = sCache.find_first_of("({"))] == '{')
3246 bWriteToCluster = true;
3247
3248 if (!isValidIndexSet(_idx))
3249 throw SyntaxError(SyntaxError::INVALID_INDEX, sCache, "", _idx.row.to_string() + ", " + _idx.col.to_string());
3250
3251 if (!bWriteToCluster && _idx.row.isOpenEnd() && _idx.col.isOpenEnd())
3252 throw SyntaxError(SyntaxError::NO_MATRIX, sCache, "");
3253
3254 sCache.erase(pos);
3255 }
3256 }
3257
3258 // Parse the numerical expression, if it is not
3259 // already available as bytecode
3260 if (!_parserRef->IsAlreadyParsed(sLine))
3261 _parserRef->SetExpr(sLine);
3262
3263 // Calculate the result
3264 v = _parserRef->Eval(nNum);
3266
3267 vAns = v[0];
3269
3270 // Do only add the bytecode flag, if it does not depend on
3271 // previous operations
3272 if (!nJumpTable[nthCmd][PROCEDURE_INTERFACE]
3273 && !(nCalcType[nthCmd] & (CALCTYPE_DATAACCESS
3278 | CALCTYPE_PROMPT)))
3279 nCalcType[nthCmd] |= CALCTYPE_NUMERICAL;
3280
3281 if (!bLoopSupressAnswer)
3282 {
3283 /* --> Der Benutzer will also die Ergebnisse sehen. Es gibt die Moeglichkeit,
3284 * dass der Parser mehrere Ausdruecke je Zeile auswertet. Dazu muessen die
3285 * Ausdruecke durch Kommata getrennt sein. Damit der Parser bemerkt, dass er
3286 * mehrere Ausdruecke auszuwerten hat, muss man die Auswerte-Funktion des
3287 * Parsers einmal aufgerufen werden <--
3288 */
3290 }
3291
3292 // Write the result to a table or a cluster
3293 // this was implied by the syntax of the command
3294 // line
3295 if (bWriteToCache)
3296 {
3297 // Is it a cluster?
3298 if (bWriteToCluster)
3299 _dataRef->getCluster(sCache).assignResults(_idx, nNum, v);
3300 else
3301 _dataRef->writeToTable(_idx, sCache, v, nNum);
3302 }
3303
3304 if (returnCommand)
3305 {
3306 for (int i = 0; i < nNum; i++)
3307 ReturnVal.vNumVal.push_back(v[i]);
3308
3309 bReturnSignal = true;
3310 return FLOWCTRL_RETURN;
3311 }
3312
3313 return FLOWCTRL_OK;
3314}
3315
3316
3329int FlowCtrl::calc(StringView sLine, int nthCmd)
3330{
3331 value_type* v = 0;
3332 int nNum = 0;
3334
3335 // No great impact on calctime
3338
3339 // Get the current bytecode for this command
3340 int nCurrentCalcType = nCalcType[nthCmd];
3341
3342 // If the current line has no bytecode attached, then
3343 // change the function and calculate it. Using the determined
3344 // bytecode, we can omit many checks at the next
3345 // iteration
3346 if (!nCurrentCalcType)
3347 return compile(sLine.to_string(), nthCmd);
3348
3349 bLoopSupressAnswer = nCurrentCalcType & CALCTYPE_SUPPRESSANSWER;
3350 //return FLOWCTRL_OK;
3351
3352 std::string sBuffer;
3353
3354 // Eval the assertion command
3355 if (nCurrentCalcType & CALCTYPE_ASSERT)
3356 _assertionHandler.enable("assert " + sLine);
3357
3358 // Eval the debugger breakpoint first
3360 {
3362 {
3366 }
3367 }
3368
3369 // Replace the custom defined functions, if it wasn't already done
3370 if (!(nCurrentCalcType & CALCTYPE_DEFINITION) && !bFunctionsReplaced)
3371 {
3372 sBuffer = sLine.to_string();
3373
3374 if (!_functionRef->call(sBuffer))
3376
3377 sLine = StringView(sBuffer);
3378 }
3379
3380 // Handle the throw command
3381 if (nCurrentCalcType & CALCTYPE_THROWCOMMAND)
3382 {
3383 std::string sErrorToken;
3384 sBuffer = sLine.to_string();
3385
3386 if (sLine.length() > 6 && NumeReKernel::getInstance()->getStringParser().isStringExpression(sBuffer))
3387 {
3388 if (NumeReKernel::getInstance()->getStringParser().containsStringVars(sBuffer))
3390
3391 sErrorToken = sBuffer.substr(findCommand(sBuffer).nPos+6);
3392 sErrorToken += " -nq";
3393 std::string sDummy;
3395 }
3396
3398 }
3399
3400 // Handle the return command
3401 if (nCurrentCalcType & CALCTYPE_RETURNCOMMAND)
3402 {
3403
3404 std::string sReturnValue = sLine.subview(sLine.find("return") + 6).to_string();
3405 StripSpaces(sReturnValue);
3406
3407 if (sReturnValue.back() == ';')
3408 sReturnValue.pop_back();
3409
3410 StripSpaces(sReturnValue);
3411
3412 if (sReturnValue == "void")
3413 {
3414 bReturnSignal = true;
3415 nReturnType = 0;
3416 return FLOWCTRL_RETURN;
3417 }
3418 else if (sReturnValue.find('(') != std::string::npos
3419 && sReturnValue.substr(sReturnValue.find('(')) == "()"
3420 && _dataRef->isTable(sReturnValue.substr(0, sReturnValue.find('('))))
3421 {
3422 ReturnVal.sReturnedTable = sReturnValue.substr(0, sReturnValue.find('('));
3423 bReturnSignal = true;
3424 return FLOWCTRL_RETURN;
3425 }
3426 else if (!sReturnValue.length())
3427 {
3428 ReturnVal.vNumVal.push_back(1.0);
3429 bReturnSignal = true;
3430 return FLOWCTRL_RETURN;
3431 }
3432
3433 sBuffer = sReturnValue;
3434 sLine = StringView(sBuffer);
3435 }
3436
3437 // Check, whether the user tried to abort the
3438 // current evaluation
3440 {
3441 if (bPrintedStatus)
3442 NumeReKernel::printPreFmt(" " + _lang.get("COMMON_CANCEL"));
3443
3445 }
3446
3447 // Is it a numerical expression, which was already
3448 // parsed? Evaluate it here
3449 if (nCurrentCalcType & CALCTYPE_NUMERICAL)
3450 {
3451 // As long as bytecode parsing is not globally available,
3452 // this condition has to stay at this place
3454 _parserRef->SetExpr(sLine);
3455
3456 // Evaluate all remaining equations in the stack
3457 do
3458 {
3459 v = _parserRef->Eval(nNum);
3460 } while (_parserRef->IsNotLastStackItem());
3461
3462 // Check only the last expression
3464
3465 vAns = v[0];
3466 ans.setDoubleArray(nNum, v);
3467
3468 if (!bLoopSupressAnswer)
3470
3471 return FLOWCTRL_OK;
3472 }
3473
3474 // Does this contain a plot composition? Combine the
3475 // needed lines here. This is not necessary, if the lines
3476 // are read from a procedure, which will provide the compositon
3477 // in a single line
3478 if (nCurrentCalcType & CALCTYPE_COMPOSE)// || sLoopPlotCompose.length())
3479 {
3480 std::string sCommand = findCommand(sLine).sString;
3481
3482 if (sCommand == "compose"
3483 || sCommand == "endcompose"
3484 || sLoopPlotCompose.length())
3485 {
3486 if (!sLoopPlotCompose.length() && sCommand == "compose")
3487 {
3488 sLoopPlotCompose = "plotcompose ";
3489 return FLOWCTRL_OK;
3490 }
3491 else if (sCommand == "abort")
3492 {
3493 sLoopPlotCompose = "";
3494 return FLOWCTRL_OK;
3495 }
3496 else if (sCommand != "endcompose")
3497 {
3498 if (sCommand.substr(0, 4) == "plot"
3499 || sCommand.substr(0, 4) == "grad"
3500 || sCommand.substr(0, 4) == "dens"
3501 || sCommand.substr(0, 4) == "vect"
3502 || sCommand.substr(0, 4) == "cont"
3503 || sCommand.substr(0, 4) == "surf"
3504 || sCommand.substr(0, 4) == "mesh")
3505 sLoopPlotCompose += sLine.to_string() + " <<COMPOSE>> ";
3506
3507 return FLOWCTRL_OK;
3508 }
3509 else
3510 {
3511 sBuffer = sLoopPlotCompose;
3512 sLine = StringView(sBuffer);
3513 sLoopPlotCompose = "";
3514 }
3515 }
3516 }
3517
3518 // Handle the "to_cmd()" function here
3519 if (nCurrentCalcType & CALCTYPE_TOCOMMAND)
3520 {
3523
3524 unsigned int nPos = 0;
3525 sBuffer = sLine.to_string();
3526
3527 while (sBuffer.find("to_cmd(", nPos) != std::string::npos)
3528 {
3529 nPos = sBuffer.find("to_cmd(", nPos) + 6;
3530
3531 if (isInQuotes(sBuffer, nPos))
3532 continue;
3533
3534 unsigned int nParPos = getMatchingParenthesis(sBuffer.substr(nPos));
3535
3536 if (nParPos == std::string::npos)
3537 throw SyntaxError(SyntaxError::UNMATCHED_PARENTHESIS, sBuffer, nPos);
3538
3539 std::string sCmdString = sBuffer.substr(nPos + 1, nParPos - 1);
3540 StripSpaces(sCmdString);
3541
3542 if (NumeReKernel::getInstance()->getStringParser().isStringExpression(sCmdString))
3543 {
3544 sCmdString += " -nq";
3545 std::string sDummy;
3546 NumeReKernel::getInstance()->getStringParser().evalAndFormat(sCmdString, sDummy, true);
3547 }
3548
3549 sBuffer = sBuffer.substr(0, nPos - 6) + sCmdString + sBuffer.substr(nPos + nParPos + 1);
3550 nPos -= 5;
3551 }
3552
3553 replaceLocalVars(sBuffer);
3554 sLine = StringView(sBuffer);
3555
3557 _parserRef->PauseLoopMode(false);
3558 }
3559
3560 // Display a progress bar, if it is desired
3561 if (nCurrentCalcType & CALCTYPE_PROGRESS)
3562 {
3563 value_type* vVals = 0;
3564 std::string sExpr;
3565 std::string sArgument;
3566 int nArgument;
3567 sBuffer = sLine.to_string();
3568
3569 if (NumeReKernel::getInstance()->getStringParser().isStringExpression(sBuffer))
3570 {
3573
3574 sBuffer = evaluateParameterValues(sBuffer);
3575
3577 _parserRef->PauseLoopMode(false);
3578 }
3579
3580 if (sBuffer.find("-set") != std::string::npos || sBuffer.find("--") != std::string::npos)
3581 {
3582 if (sBuffer.find("-set") != std::string::npos)
3583 sArgument = sBuffer.substr(sBuffer.find("-set"));
3584 else
3585 sArgument = sBuffer.substr(sBuffer.find("--"));
3586
3587 sBuffer.erase(sBuffer.find(sArgument));
3588
3589 if (findParameter(sArgument, "first", '='))
3590 {
3591 sExpr = getArgAtPos(sArgument, findParameter(sArgument, "first", '=') + 5) + ",";
3592 }
3593 else
3594 sExpr = "1,";
3595
3596 if (findParameter(sArgument, "last", '='))
3597 {
3598 sExpr += getArgAtPos(sArgument, findParameter(sArgument, "last", '=') + 4);
3599 }
3600 else
3601 sExpr += "100";
3602
3603 if (findParameter(sArgument, "type", '='))
3604 {
3605 sArgument = getArgAtPos(sArgument, findParameter(sArgument, "type", '=') + 4);
3606
3607 if (NumeReKernel::getInstance()->getStringParser().isStringExpression(sArgument))
3608 {
3609 if (sArgument.front() != '"')
3610 sArgument = "\"" + sArgument + "\" -nq";
3611
3614
3615 std::string sDummy;
3616 NumeReKernel::getInstance()->getStringParser().evalAndFormat(sArgument, sDummy, true);
3617
3619 _parserRef->PauseLoopMode(false);
3620 }
3621 }
3622 else
3623 sArgument = "std";
3624 }
3625 else
3626 {
3627 sArgument = "std";
3628 sExpr = "1,100";
3629 }
3630
3631 while (sBuffer.length() && (sBuffer[sBuffer.length() - 1] == ' ' || sBuffer[sBuffer.length() - 1] == '-'))
3632 sBuffer.pop_back();
3633
3634 if (!sBuffer.length())
3635 return FLOWCTRL_OK;
3636
3637 if (!_parserRef->IsAlreadyParsed(sBuffer.substr(findCommand(sBuffer).nPos + 8) + "," + sExpr))
3638 {
3639 _parserRef->SetExpr(sBuffer.substr(findCommand(sBuffer).nPos + 8) + "," + sExpr);
3640 }
3641
3642 vVals = _parserRef->Eval(nArgument);
3643 make_progressBar(intCast(vVals[0]), intCast(vVals[1]), intCast(vVals[2]), sArgument);
3644 return FLOWCTRL_OK;
3645 }
3646
3647 // Display the prompt to the user
3648 if (nCurrentCalcType & CALCTYPE_PROMPT)
3649 {
3650 if (bPrintedStatus)
3652
3653 sBuffer = sLine.to_string();
3654 sBuffer = promptForUserInput(sBuffer);
3655 sLine = StringView(sBuffer);
3656 bPrintedStatus = false;
3657 }
3658
3659 // Include procedure and plugin calls
3660 if (nJumpTable[nthCmd][PROCEDURE_INTERFACE])
3661 {
3663 {
3666 }
3667
3668 sBuffer = sLine.to_string();
3669
3670 if (nCurrentCalcType & CALCTYPE_RETURNCOMMAND)
3671 sBuffer.insert(0, "return ");
3672
3674
3676 {
3677 _parserRef->PauseLoopMode(false);
3678 _parserRef->LockPause(false);
3679 }
3680
3681 if (nReturn == INTERFACE_EMPTY || nReturn == INTERFACE_VALUE)
3682 nJumpTable[nthCmd][PROCEDURE_INTERFACE] = 1;
3683 else
3684 nJumpTable[nthCmd][PROCEDURE_INTERFACE] = 0;
3685
3686 if (bReturnSignal)
3687 return FLOWCTRL_RETURN;
3688 else if (nCurrentCalcType & CALCTYPE_RETURNCOMMAND)
3689 sBuffer.erase(0, 7);
3690
3691 if (nReturn == INTERFACE_ERROR)
3692 return FLOWCTRL_ERROR;
3693 else if (nReturn == INTERFACE_EMPTY)
3694 return FLOWCTRL_OK;
3695
3696 sLine = StringView(sBuffer);
3697 }
3698
3699 // Handle the procedure commands like "namespace" here
3700 if (nCurrentCalcType & CALCTYPE_PROCEDURECMDINTERFACE)
3701 {
3702 sBuffer = sLine.to_string();
3703 int nProcedureCmd = procedureCmdInterface(sBuffer);
3704
3705 if (nProcedureCmd)
3706 {
3707 if (nProcedureCmd == 1)
3708 return FLOWCTRL_OK;
3709 }
3710 else
3711 return FLOWCTRL_ERROR;
3712
3713 sLine = StringView(sBuffer);
3714 }
3715
3716 // Remove the "explicit" command here
3717 if (nCurrentCalcType & CALCTYPE_EXPLICIT)
3718 {
3719 sBuffer = sLine.to_string();
3720 sBuffer.erase(findCommand(sBuffer).nPos, 8);
3721 sLine = StringView(sBuffer);
3722 sLine.strip();
3723 }
3724
3725 // Evaluate the command, if this is a command
3726 if (nCurrentCalcType & CALCTYPE_COMMAND)
3727 {
3730
3731 {
3732 bool bSupressAnswer_back = NumeReKernel::bSupressAnswer;
3733 std::string sPreCommandLine = sLine.to_string();
3734 sBuffer = sLine.to_string();
3736
3737 switch (commandHandler(sBuffer))
3738 {
3739 case NO_COMMAND:
3740 break;
3741 case COMMAND_PROCESSED:
3742 NumeReKernel::bSupressAnswer = bSupressAnswer_back;
3743
3745 _parserRef->PauseLoopMode(false);
3746
3747 return FLOWCTRL_OK;
3748 case NUMERE_QUIT:
3749 NumeReKernel::bSupressAnswer = bSupressAnswer_back;
3750 return FLOWCTRL_OK;
3752 NumeReKernel::bSupressAnswer = bSupressAnswer_back;
3753 break;
3754 }
3755
3756 NumeReKernel::bSupressAnswer = bSupressAnswer_back;
3757
3758 // It may be possible that some procedure occures at this
3759 // position. Handle them here
3760 if (sBuffer.find('$') != std::string::npos)
3762
3763 sLine = StringView(sBuffer);
3764 }
3765
3767 _parserRef->PauseLoopMode(false);
3768 }
3769
3770 // Expand recursive expressions, if not already done
3771 if (nCurrentCalcType & CALCTYPE_RECURSIVEEXPRESSION)
3772 {
3773 sBuffer = sLine.to_string();
3774 evalRecursiveExpressions(sBuffer);
3775 sLine = StringView(sBuffer);
3776 }
3777
3778 // Declare all further necessary variables
3779 std::string sDataObject;
3780 bool bCompiling = false;
3781 bool bWriteToCache = false;
3782 bool bWriteToCluster = false;
3783
3784 // Get the data from the used data object
3785 if (nCurrentCalcType & CALCTYPE_DATAACCESS)
3786 {
3787 sBuffer = sLine.to_string();
3788 // --> Datafile/Cache! <--
3789 if (!(nCurrentCalcType & CALCTYPE_STRING)
3790 || (!NumeReKernel::getInstance()->getStringParser().isStringExpression(sBuffer)
3791 && _dataRef->containsTablesOrClusters(sBuffer)))
3792 {
3794 {
3795 bCompiling = true;
3796 _parserRef->SetCompiling(true);
3797 }
3798
3799 sDataObject = getDataElements(sBuffer, *_parserRef, *_dataRef, *_optionRef);
3800
3801 if (sDataObject.length())
3802 bWriteToCache = true;
3803
3804 // Ad-hoc bytecode adaption
3805#warning NOTE (numere#1#08/21/21): Might need some adaption, if bytecode issues are experienced
3806 if (NumeReKernel::getInstance()->getStringParser().isStringExpression(sBuffer))
3807 nCurrentCalcType |= CALCTYPE_STRING;
3808
3810 {
3812 _parserRef->CacheCurrentTarget(sDataObject);
3813 }
3814
3815 _parserRef->SetCompiling(false);
3816 }
3817 else if (isClusterCandidate(sBuffer, sDataObject))
3818 bWriteToCache = true;
3819
3820 sLine = StringView(sBuffer);
3821 }
3822
3823 // Evaluate std::string expressions
3824 if (nCurrentCalcType & CALCTYPE_STRING)
3825 {
3826 //if (!bLockedPauseMode && bUseLoopParsingMode)
3827 // _parserRef->PauseLoopMode();
3828
3829 sBuffer = sLine.to_string();
3830 auto retVal = NumeReKernel::getInstance()->getStringParser().evalAndFormat(sBuffer, sDataObject, bLoopSupressAnswer, true);
3832
3834 {
3835 //if (!bLockedPauseMode && bUseLoopParsingMode)
3836 // _parserRef->PauseLoopMode(false);
3837
3838 if (nCurrentCalcType & CALCTYPE_RETURNCOMMAND)
3839 {
3840 bReturnSignal = true;
3842 return FLOWCTRL_RETURN;
3843 }
3844
3845 return FLOWCTRL_OK;
3846 }
3847
3848 replaceLocalVars(sBuffer);
3849
3850#warning NOTE (erik.haenel#3#): This is changed due to double writes in combination with c{nlen+1} = VAL
3851 //if (sDataObject.length() && _dataRef->containsTablesOrClusters(sDataObject) && !bWriteToCache)
3852 // bWriteToCache = true;
3853
3854 if (sDataObject.length())
3855 {
3856 bWriteToCache = false;
3857 sDataObject.clear();
3858 }
3859
3860 //if (!bLockedPauseMode && bUseLoopParsingMode)
3861 // _parserRef->PauseLoopMode(false);
3862
3863 sLine = StringView(sBuffer);
3864 }
3865
3866 // Prepare the indices for storing the data
3867 Indices _idx;
3868
3869 // Get the target indices of the target data object
3870 if (nCurrentCalcType & CALCTYPE_DATAACCESS)
3871 {
3872 if (bWriteToCache)
3873 {
3874 size_t pos;
3875
3876 if (bCompiling)
3877 {
3878 _parserRef->SetCompiling(true);
3879 getIndices(sDataObject, _idx, *_parserRef, *_dataRef, *_optionRef);
3880
3881 if (sDataObject[(pos = sDataObject.find_first_of("({"))] == '{')
3882 bWriteToCluster = true;
3883
3884 if (!isValidIndexSet(_idx))
3885 throw SyntaxError(SyntaxError::INVALID_INDEX, sDataObject, "", _idx.row.to_string() + ", " + _idx.col.to_string());
3886
3887 if (!bWriteToCluster && _idx.row.isOpenEnd() && _idx.col.isOpenEnd())
3888 throw SyntaxError(SyntaxError::NO_MATRIX, sDataObject, "");
3889
3890 sDataObject.erase(pos);
3891 StripSpaces(sDataObject);
3892
3893 if (!bWriteToCluster)
3894 _parserRef->CacheCurrentTarget(sDataObject + "(" + _idx.sCompiledAccessEquation + ")");
3895 else
3896 _parserRef->CacheCurrentTarget(sDataObject + "{" + _idx.sCompiledAccessEquation + "}");
3897
3898 _parserRef->SetCompiling(false);
3899 }
3900 else
3901 {
3902 getIndices(sDataObject, _idx, *_parserRef, *_dataRef, *_optionRef);
3903 //_idx.col.front() = 0;
3904 //_idx.row.front() = 0;
3905
3906 if (sDataObject[(pos = sDataObject.find_first_of("({"))] == '{')
3907 bWriteToCluster = true;
3908
3909 if (!isValidIndexSet(_idx))
3910 throw SyntaxError(SyntaxError::INVALID_INDEX, sDataObject, "", _idx.row.to_string() + ", " + _idx.col.to_string());
3911
3912 if (!bWriteToCluster && _idx.row.isOpenEnd() && _idx.col.isOpenEnd())
3913 throw SyntaxError(SyntaxError::NO_MATRIX, sDataObject, "");
3914
3915 sDataObject.erase(pos);
3916 }
3917 }
3918 }
3919
3920 // Parse the numerical expression, if it is not
3921 // already available as bytecode
3922 if (!_parserRef->IsAlreadyParsed(sLine))
3923 _parserRef->SetExpr(sLine);
3924
3925 // Calculate the result
3926 v = _parserRef->Eval(nNum);
3928
3929 vAns = v[0];
3930 ans.setDoubleArray(nNum, v);
3931
3932 if (!bLoopSupressAnswer)
3934
3935 // Write the result to a table or a cluster
3936 // this was implied by the syntax of the command
3937 // line
3938 if (bWriteToCache)
3939 {
3940 // Is it a cluster?
3941 if (bWriteToCluster)
3942 _dataRef->getCluster(sDataObject).assignResults(_idx, nNum, v);
3943 else
3944 _dataRef->writeToTable(_idx, sDataObject, v, nNum);
3945 }
3946
3947 if (nCurrentCalcType & CALCTYPE_RETURNCOMMAND)
3948 {
3949 for (int i = 0; i < nNum; i++)
3950 ReturnVal.vNumVal.push_back(v[i]);
3951
3952 bReturnSignal = true;
3953 return FLOWCTRL_RETURN;
3954 }
3955
3956 return FLOWCTRL_OK;
3957}
3958
3959
3969void FlowCtrl::replaceLocalVars(std::string& sLine)
3970{
3971 if (!mVarMap.size())
3972 return;
3973
3974 for (auto iter = mVarMap.begin(); iter != mVarMap.end(); ++iter)
3975 {
3976 for (unsigned int i = 0; i < sLine.length(); i++)
3977 {
3978 if (sLine.substr(i, (iter->first).length()) == iter->first)
3979 {
3980 if ((i && checkDelimiter(sLine.substr(i - 1, (iter->first).length() + 2)))
3981 || (!i && checkDelimiter(" " + sLine.substr(i, (iter->first).length() + 1))))
3982 {
3983 sLine.replace(i, (iter->first).length(), iter->second);
3984 }
3985 }
3986 }
3987 }
3988}
3989
3990
4003void FlowCtrl::replaceLocalVars(const std::string& sOldVar, const std::string& sNewVar, size_t from, size_t to)
4004{
4005 for (size_t i = from; i < std::min(to, vCmdArray.size()); i++)
4006 {
4007 // Replace it in the flow control
4008 // statements
4009 if (vCmdArray[i].sCommand.length())
4010 {
4011 vCmdArray[i].sCommand += " ";
4012
4013 for (unsigned int j = 0; j < vCmdArray[i].sCommand.length(); j++)
4014 {
4015 if (vCmdArray[i].sCommand.substr(j, sOldVar.length()) == sOldVar)
4016 {
4017 if (((!j && checkDelimiter(" " + vCmdArray[i].sCommand.substr(j, sOldVar.length() + 1)))
4018 || (j && checkDelimiter(vCmdArray[i].sCommand.substr(j - 1, sOldVar.length() + 2))))
4019 && !isInQuotes(vCmdArray[i].sCommand, j, true))
4020 {
4021 vCmdArray[i].sCommand.replace(j, sOldVar.length(), sNewVar);
4022 j += sNewVar.length() - sOldVar.length();
4023 }
4024 }
4025 }
4026
4027 StripSpaces(vCmdArray[i].sCommand);
4028 }
4029 }
4030}
4031
4032
4043bool FlowCtrl::checkFlowControlArgument(const std::string& sFlowControlArgument, bool isForLoop)
4044{
4045 // The argument shall be enclosed in parentheses
4046 if (sFlowControlArgument.find('(') == std::string::npos)
4047 return false;
4048
4049 std::string sArgument = sFlowControlArgument.substr(sFlowControlArgument.find('('));
4050 sArgument = sArgument.substr(1, getMatchingParenthesis(sArgument) - 1);
4051
4052 // Ensure that the argument is not empty
4053 if (!isNotEmptyExpression(sArgument))
4054 return false;
4055
4056 // That's everything for a non-for loop
4057 if (!isForLoop)
4058 return true;
4059
4060 // If it is a for loop, then it has to fulfill
4061 // another requirement: the index and its interval
4062 if (sArgument.find('=') == std::string::npos && sArgument.find("->") == std::string::npos)
4063 return false;
4064
4065 // Everything seems to be OK
4066 return true;
4067}
4068
4069
4078bool FlowCtrl::checkCaseValue(const std::string& sCaseDefinition)
4079{
4080 // Colon operator is missing
4081 if (sCaseDefinition.find(':') == std::string::npos)
4082 return false;
4083
4084 // Check, whether there's a valid value between
4085 // "case" and the colon operator
4086 if (sCaseDefinition.substr(0, 5) == "case ")
4087 {
4088 // Extract the value
4089 std::string sValue = sCaseDefinition.substr(4);
4090 sValue.erase(sValue.find(':'));
4091
4092 // Check, whether there are other characters
4093 // than the whitespace
4094 if (sValue.find_first_not_of(' ') == std::string::npos)
4095 return false;
4096
4097 // Cut of the first expression (in the possible list)
4098 getNextArgument(sValue, true);
4099
4100 // Check for more than one value (only one allowed)
4101 if (sValue.length() && sValue.find_first_not_of(' ') != std::string::npos)
4102 return false;
4103 }
4104 // Everything seems to be OK
4105 return true;
4106}
4107
4108
4118{
4119 std::string sVars = ";";
4120 std::string sVar;
4121 int nVarArray = 0;
4122
4123 for (size_t i = 0; i < vCmdArray.size(); i++)
4124 {
4125 // No flow control statement
4126 if (!vCmdArray[i].bFlowCtrlStatement)
4127 continue;
4128
4129 // Extract the index variables
4130 if (vCmdArray[i].sCommand.substr(0, 3) == "for")
4131 {
4132 sVar = vCmdArray[i].sCommand.substr(vCmdArray[i].sCommand.find('(') + 1);
4133
4134 if (sVar.find("->") != std::string::npos)
4135 sVar.erase(sVar.find("->")+2); // Has the arrow appended
4136 else
4137 sVar.erase(sVar.find('='));
4138
4139 if (sVar.substr(0, 2) == "|>")
4140 sVar.erase(0, 2);
4141
4142 StripSpaces(sVar);
4143
4144 if (sVars.find(";" + sVar + ";") == std::string::npos)
4145 {
4146 sVars += sVar + ";";
4147 nVarArray++;
4148 }
4149
4150 vCmdArray[i].sCommand[vCmdArray[i].sCommand.find('(')] = ' ';
4151 vCmdArray[i].sCommand.pop_back();
4152 }
4153
4154 // Extract the flow control flags
4155 if (vCmdArray[i].sCommand.find("end") != std::string::npos && findParameter(vCmdArray[i].sCommand, "sv"))
4156 bSilent = false;
4157
4158 if (vCmdArray[i].sCommand.find("end") != std::string::npos && findParameter(vCmdArray[i].sCommand, "mask"))
4159 bMask = true;
4160
4161 if (vCmdArray[i].sCommand.find("end") != std::string::npos && findParameter(vCmdArray[i].sCommand, "sp"))
4162 bMask = false;
4163
4164 if (vCmdArray[i].sCommand.find("end") != std::string::npos && findParameter(vCmdArray[i].sCommand, "lnumctrl"))
4165 nLoopSafety = 1000;
4166
4167 if (vCmdArray[i].sCommand.find("end") != std::string::npos && findParameter(vCmdArray[i].sCommand, "lnumctrl", '='))
4168 {
4169 _parserRef->SetExpr(getArgAtPos(vCmdArray[i].sCommand, findParameter(vCmdArray[i].sCommand, "lnumctrl", '=') + 8));
4171
4172 if (nLoopSafety <= 0)
4173 nLoopSafety = 1000;
4174 }
4175 }
4176
4177 sVarArray.resize(nVarArray);
4178 vVarArray.resize(nVarArray);
4179
4180 return sVars;
4181}
4182
4183
4195{
4196 for (size_t i = 0; i < vCmdArray.size(); i++)
4197 {
4198 // Fill the jump table and determine, whether
4199 // the loop parsing mode is reasonable
4200 if (vCmdArray[i].bFlowCtrlStatement)
4201 {
4202 if (vCmdArray[i].sCommand.substr(0, 3) == "for")
4203 {
4204 int nForCount = 0;
4205
4206 for (size_t j = i + 1; j < vCmdArray.size(); j++)
4207 {
4208 if (!vCmdArray[j].bFlowCtrlStatement)
4209 continue;
4210
4211 if (vCmdArray[j].sCommand.length() && vCmdArray[j].sCommand.substr(0, 6) == "endfor")
4212 {
4213 if (nForCount)
4214 nForCount--;
4215 else
4216 {
4217 nJumpTable[i][BLOCK_END] = j;
4218 break;
4219 }
4220 }
4221 else if (vCmdArray[j].sCommand.length() && vCmdArray[j].sCommand.substr(0, 3) == "for")
4222 nForCount++;
4223 }
4224 }
4225 else if (vCmdArray[i].sCommand.substr(0, 5) == "while")
4226 {
4227 int nWhileCount = 0;
4228
4229 for (size_t j = i + 1; j < vCmdArray.size(); j++)
4230 {
4231 if (!vCmdArray[j].bFlowCtrlStatement)
4232 continue;
4233
4234 if (vCmdArray[j].sCommand.length() && vCmdArray[j].sCommand.substr(0, 8) == "endwhile")
4235 {
4236 if (nWhileCount)
4237 nWhileCount--;
4238 else
4239 {
4240 nJumpTable[i][BLOCK_END] = j;
4241 break;
4242 }
4243 }
4244 else if (vCmdArray[j].sCommand.length() && vCmdArray[j].sCommand.substr(0, 5) == "while")
4245 nWhileCount++;
4246 }
4247 }
4248 else if (vCmdArray[i].sCommand.find(">>if") != std::string::npos)
4249 {
4250 std::string sNth_If = vCmdArray[i].sCommand.substr(0, vCmdArray[i].sCommand.find(">>"));
4251
4252 for (size_t j = i + 1; j < vCmdArray.size(); j++)
4253 {
4254 if (!vCmdArray[j].bFlowCtrlStatement)
4255 continue;
4256
4257 if (vCmdArray[j].sCommand.length()
4258 && vCmdArray[j].sCommand.substr(0, (sNth_If + ">>else").length()) == sNth_If + ">>else"
4260 nJumpTable[i][BLOCK_MIDDLE] = j;
4261 else if (vCmdArray[j].sCommand.length()
4262 && vCmdArray[j].sCommand.substr(0, (sNth_If + ">>elseif").length()) == sNth_If + ">>elseif"
4264 nJumpTable[i][BLOCK_MIDDLE] = j;
4265 else if (vCmdArray[j].sCommand.length()
4266 && vCmdArray[j].sCommand.substr(0, (sNth_If + ">>endif").length()) == sNth_If + ">>endif")
4267 {
4268 nJumpTable[i][BLOCK_END] = j;
4269 break;
4270 }
4271 }
4272 }
4273 else if (vCmdArray[i].sCommand.find(">>elseif") != std::string::npos)
4274 {
4275 std::string sNth_If = vCmdArray[i].sCommand.substr(0, vCmdArray[i].sCommand.find(">>"));
4276
4277 for (size_t j = i + 1; j < vCmdArray.size(); j++)
4278 {
4279 if (!vCmdArray[j].bFlowCtrlStatement)
4280 continue;
4281
4282 if (vCmdArray[j].sCommand.length()
4283 && vCmdArray[j].sCommand.substr(0, (sNth_If + ">>else").length()) == sNth_If + ">>else"
4285 nJumpTable[i][BLOCK_MIDDLE] = j;
4286 else if (vCmdArray[j].sCommand.length()
4287 && vCmdArray[j].sCommand.substr(0, (sNth_If + ">>elseif").length()) == sNth_If + ">>elseif"
4289 nJumpTable[i][BLOCK_MIDDLE] = j;
4290 else if (vCmdArray[j].sCommand.length()
4291 && vCmdArray[j].sCommand.substr(0, (sNth_If + ">>endif").length()) == sNth_If + ">>endif")
4292 {
4293 nJumpTable[i][BLOCK_END] = j;
4294 break;
4295 }
4296 }
4297 }
4298 else if (vCmdArray[i].sCommand.find(">>switch") != std::string::npos)
4299 {
4300 std::string sNth_Switch = vCmdArray[i].sCommand.substr(0, vCmdArray[i].sCommand.find(">>"));
4301
4302 for (size_t j = i + 1; j < vCmdArray.size(); j++)
4303 {
4304 if (!vCmdArray[j].bFlowCtrlStatement)
4305 continue;
4306
4307 if (vCmdArray[j].sCommand.length()
4308 && vCmdArray[j].sCommand.substr(0, (sNth_Switch + ">>case").length()) == sNth_Switch + ">>case"
4310 nJumpTable[i][BLOCK_MIDDLE] = j;
4311 else if (vCmdArray[j].sCommand.length()
4312 && vCmdArray[j].sCommand.substr(0, (sNth_Switch + ">>default").length()) == sNth_Switch + ">>default"
4314 nJumpTable[i][BLOCK_MIDDLE] = j;
4315 else if (vCmdArray[j].sCommand.length()
4316 && vCmdArray[j].sCommand.substr(0, (sNth_Switch + ">>endswitch").length()) == sNth_Switch + ">>endswitch")
4317 {
4318 nJumpTable[i][BLOCK_END] = j;
4319 break;
4320 }
4321 }
4322
4323 // For the switch case, all case values are gathered
4324 // as logical expression into one single expression,
4325 // which will be evaluated at once and the switch
4326 // will jump into the first non-zero case
4328 }
4329 else if (vCmdArray[i].sCommand.find(">>case") != std::string::npos)
4330 {
4331 std::string sNth_Switch = vCmdArray[i].sCommand.substr(0, vCmdArray[i].sCommand.find(">>"));
4332
4333 for (size_t j = i + 1; j < vCmdArray.size(); j++)
4334 {
4335 if (!vCmdArray[j].bFlowCtrlStatement)
4336 continue;
4337
4338 if (vCmdArray[j].sCommand.length()
4339 && vCmdArray[j].sCommand.substr(0, (sNth_Switch + ">>case").length()) == sNth_Switch + ">>case"
4341 nJumpTable[i][BLOCK_MIDDLE] = j;
4342 else if (vCmdArray[j].sCommand.length()
4343 && vCmdArray[j].sCommand.substr(0, (sNth_Switch + ">>default").length()) == sNth_Switch + ">>default"
4345 nJumpTable[i][BLOCK_MIDDLE] = j;
4346 else if (vCmdArray[j].sCommand.length()
4347 && vCmdArray[j].sCommand.substr(0, (sNth_Switch + ">>endswitch").length()) == sNth_Switch + ">>endswitch")
4348 {
4349 nJumpTable[i][BLOCK_END] = j;
4350 break;
4351 }
4352 }
4353 }
4354 else if (vCmdArray[i].sCommand.find(">>try") != std::string::npos)
4355 {
4356 std::string sNth_Try = vCmdArray[i].sCommand.substr(0, vCmdArray[i].sCommand.find(">>"));
4357
4358 for (size_t j = i + 1; j < vCmdArray.size(); j++)
4359 {
4360 if (!vCmdArray[j].bFlowCtrlStatement)
4361 continue;
4362
4363 if (vCmdArray[j].sCommand.length()
4364 && vCmdArray[j].sCommand.substr(0, (sNth_Try + ">>catch").length()) == sNth_Try + ">>catch"
4366 nJumpTable[i][BLOCK_MIDDLE] = j;
4367 else if (vCmdArray[j].sCommand.length()
4368 && vCmdArray[j].sCommand.substr(0, (sNth_Try + ">>endtry").length()) == sNth_Try + ">>endtry")
4369 {
4370 nJumpTable[i][BLOCK_END] = j;
4371 break;
4372 }
4373 }
4374 }
4375 else if (vCmdArray[i].sCommand.find(">>catch") != std::string::npos)
4376 {
4377 std::string sNth_Try = vCmdArray[i].sCommand.substr(0, vCmdArray[i].sCommand.find(">>"));
4378
4379 for (size_t j = i + 1; j < vCmdArray.size(); j++)
4380 {
4381 if (!vCmdArray[j].bFlowCtrlStatement)
4382 continue;
4383
4384 if (vCmdArray[j].sCommand.length()
4385 && vCmdArray[j].sCommand.substr(0, (sNth_Try + ">>catch").length()) == sNth_Try + ">>catch"
4387 nJumpTable[i][BLOCK_MIDDLE] = j;
4388 else if (vCmdArray[j].sCommand.length()
4389 && vCmdArray[j].sCommand.substr(0, (sNth_Try + ">>endtry").length()) == sNth_Try + ">>endtry")
4390 {
4391 nJumpTable[i][BLOCK_END] = j;
4392 break;
4393 }
4394 }
4395 }
4396
4397 continue;
4398 }
4399
4400 // Pre-evaluate all recursive expressions
4401 if (vCmdArray[i].sCommand.length())
4402 {
4403 vCmdArray[i].sCommand += " ";
4404
4405 // Do not expand the recursive expression
4406 // if it is part of a matrix operation
4407 if (findCommand(vCmdArray[i].sCommand).sString != "matop"
4408 && findCommand(vCmdArray[i].sCommand).sString != "mtrxop"
4409 && (vCmdArray[i].sCommand.find("+=") != std::string::npos
4410 || vCmdArray[i].sCommand.find("-=") != std::string::npos
4411 || vCmdArray[i].sCommand.find("*=") != std::string::npos
4412 || vCmdArray[i].sCommand.find("/=") != std::string::npos
4413 || vCmdArray[i].sCommand.find("^=") != std::string::npos
4414 || vCmdArray[i].sCommand.find("++") != std::string::npos
4415 || vCmdArray[i].sCommand.find("--") != std::string::npos))
4416 {
4417 // Store the breakpoint to insert
4418 // it after expanding the recursive
4419 // espression
4420 bool bBreakPoint = (vCmdArray[i].sCommand.substr(vCmdArray[i].sCommand.find_first_not_of(" \t"), 2) == "|>");
4421
4422 if (bBreakPoint)
4423 {
4424 vCmdArray[i].sCommand.erase(vCmdArray[i].sCommand.find_first_not_of(" \t"), 2);
4425 StripSpaces(vCmdArray[i].sCommand);
4426 }
4427
4429
4430 if (bBreakPoint)
4431 vCmdArray[i].sCommand.insert(0, "|> ");
4432 }
4433
4434 StripSpaces(vCmdArray[i].sCommand);
4435 }
4436 }
4437}
4438
4439
4449{
4450 // Extract the condition of the "switch"
4451 std::string sSwitchArgument = vCmdArray[nSwitchStart].sCommand;
4452 vCmdArray[nSwitchStart].sCommand.erase(sSwitchArgument.find('('));
4453 sSwitchArgument.erase(0, sSwitchArgument.find('(')+1);
4454 sSwitchArgument.erase(sSwitchArgument.rfind(')'));
4455
4456 std::string sArgument = "";
4457
4458 // Extract the switch level
4459 std::string sNth_Switch = vCmdArray[nSwitchStart].sCommand.substr(0, vCmdArray[nSwitchStart].sCommand.find(">>"));
4460
4461 // Search for all cases, which belong to the current
4462 // switch level
4463 for (size_t j = nSwitchStart + 1; j < vCmdArray.size(); j++)
4464 {
4465 // Extract the value of the found case and gather
4466 // it in the argument list
4467 if (vCmdArray[j].sCommand.length() && vCmdArray[j].sCommand.substr(0, (sNth_Switch + ">>case").length()) == sNth_Switch + ">>case")
4468 {
4469 if (sArgument.length())
4470 sArgument += ", ";
4471
4472 sArgument += vCmdArray[j].sCommand.substr(vCmdArray[j].sCommand.find(' ', vCmdArray[j].sCommand.find(">>case"))+1);
4473 sArgument.erase(sArgument.rfind(':'));
4474 }
4475 }
4476
4477 // If the argument list is not empty, transform it
4478 // into a vector and append it using the equality
4479 // operator to the switch condition
4480 if (sArgument.length())
4481 {
4482 std::string sExpr = sSwitchArgument;
4483 sSwitchArgument.clear();
4484
4485 while (sArgument.length())
4486 {
4487 sSwitchArgument += sExpr + " == " + getNextArgument(sArgument, true) + ",";
4488 }
4489
4490 sSwitchArgument.pop_back();
4491 }
4492
4493 // Append the new switch condition to the "switch" command
4494 vCmdArray[nSwitchStart].sCommand += "(" + sSwitchArgument + ")";
4495}
4496
4497
4512{
4513 const int INLINING_GLOBALINRETURN = 2;
4514
4515 for (size_t i = 0; i < vCmdArray.size(); i++)
4516 {
4517 if (vCmdArray[i].bFlowCtrlStatement)
4518 {
4519 if (vCmdArray[i].sCommand.substr(0, 3) == "for" || vCmdArray[i].sCommand.substr(0, 5) == "while")
4520 {
4522 bUseLoopParsingMode = true;
4523
4524 break;
4525 }
4526 }
4527 }
4528
4530 {
4531 // Check for inline procedures and "to_cmd()"
4532 for (size_t i = 0; i < vCmdArray.size(); i++)
4533 {
4534 if (vCmdArray[i].sCommand.find("to_cmd(") != std::string::npos)
4535 bUseLoopParsingMode = false;
4536
4537 if (vCmdArray[i].sCommand.find('$') != std::string::npos)
4538 {
4539 int nInlining = 0;
4540
4541 if (!(nInlining = isInline(vCmdArray[i].sCommand)))
4542 bUseLoopParsingMode = false;
4543 else if (!vCmdArray[i].bFlowCtrlStatement && nInlining != INLINING_GLOBALINRETURN)
4544 {
4545 std::vector<std::string> vExpandedProcedure = expandInlineProcedures(vCmdArray[i].sCommand);
4546 int nLine = vCmdArray[i].nInputLine;
4547
4548 for (size_t j = 0; j < vExpandedProcedure.size(); j++)
4549 {
4550 //g_logger.info("Emplaced '" + vExpandedProcedure[j] + "'");
4551 vCmdArray.emplace(vCmdArray.begin() + i + j, FlowCtrlCommand(vExpandedProcedure[j], nLine));
4552 }
4553
4554 i += vExpandedProcedure.size();
4555 }
4556 }
4557 }
4558
4559 bool bDefineCommands = false;
4560
4561 // Search for function definition commands
4562 for (size_t i = 0; i < vCmdArray.size(); i++)
4563 {
4564 if (findCommand(vCmdArray[i].sCommand).sString == "define"
4565 || findCommand(vCmdArray[i].sCommand).sString == "taylor"
4566 || findCommand(vCmdArray[i].sCommand).sString == "spline"
4567 || findCommand(vCmdArray[i].sCommand).sString == "redefine"
4568 || findCommand(vCmdArray[i].sCommand).sString == "redef"
4569 || findCommand(vCmdArray[i].sCommand).sString == "undefine"
4570 || findCommand(vCmdArray[i].sCommand).sString == "undef"
4571 || findCommand(vCmdArray[i].sCommand).sString == "ifndefined"
4572 || findCommand(vCmdArray[i].sCommand).sString == "ifndef")
4573 {
4574 bDefineCommands = true;
4575 break;
4576 }
4577 }
4578
4579 // No commands found? Then expand the defined
4580 // function. Otherwise deactivate the loop parsing
4581 // mode (temporary fix)
4582 if (!bDefineCommands)
4583 {
4584 for (size_t i = 0; i < vCmdArray.size(); i++)
4585 {
4586 if (!_functionRef->call(vCmdArray[i].sCommand))
4587 {
4589 }
4590
4591 StripSpaces(vCmdArray[i].sCommand);
4592 }
4593
4594 bFunctionsReplaced = true;
4595 }
4596 else
4597 bUseLoopParsingMode = false;
4598 }
4599
4601 bUseLoopParsingMode = false;
4602}
4603
4604
4616{
4617 sVars = sVars.substr(1, sVars.length() - 1);
4618
4619 // If a loop variable was defined before the
4620 // current loop, this one is used. All others
4621 // are create locally and therefore get
4622 // special names
4623 for (size_t i = 0; i < sVarArray.size(); i++)
4624 {
4625 sVarArray[i] = sVars.substr(0, sVars.find(';'));
4626 bool isRangeBased = sVarArray[i].find("->") != std::string::npos;
4627
4628 if (sVars.find(';') != std::string::npos)
4629 sVars = sVars.substr(sVars.find(';') + 1);
4630
4632
4633 // Is it already defined?
4634 if (sVarArray[i].substr(0, 2) == "_~" && getPointerToVariable(sVarArray[i], *_parserRef))
4636 else
4637 {
4638 // Create a local variable otherwise
4639 if (!isRangeBased)
4640 {
4641 mVarMap[sVarArray[i]] = "_~LOOP_" + sVarArray[i] + "_" + toString(nthRecursion);
4642 sVarArray[i] = mVarMap[sVarArray[i]];
4643 }
4644 }
4645
4646 if (!isRangeBased)
4648 }
4649
4651
4652 // Replace the local index variables in the
4653 // whole command set for this flow control
4654 // statement
4655 for (auto iter = mVarMap.begin(); iter != mVarMap.end(); ++iter)
4656 {
4657 replaceLocalVars(iter->first, iter->second);
4658 }
4659}
4660
4661
4670{
4671 if (sTestClusterName.length())
4672 {
4675
4676 testcluster.setDouble(1, double(total.nCheckedAssertions - baseline.nCheckedAssertions));
4678 testcluster.setDouble(5, double(total.nFailedAssertions - baseline.nFailedAssertions));
4679 }
4680}
4681
4682
4692{
4693 if (vCmdArray.size() > (size_t)nCurrentCommand)
4694 return vCmdArray[nCurrentCommand].nInputLine;
4695
4696 return 0;
4697}
4698
4699
4709{
4710 if (!vCmdArray.size())
4711 return "";
4712
4713 return vCmdArray[nCurrentCommand].sCommand;
4714}
4715
4716
4726bool FlowCtrl::isFlowCtrlStatement(const std::string& sCmd)
4727{
4728 return sCmd == "if" || sCmd == "for" || sCmd == "while" || sCmd == "switch" || sCmd == "try";
4729}
4730
4731
4742bool FlowCtrl::isAnyFlowCtrlStatement(const std::string& sCmd)
4743{
4744 return sCmd == "for"
4745 || sCmd == "endfor"
4746 || sCmd == "if"
4747 || sCmd == "endif"
4748 || sCmd == "else"
4749 || sCmd == "elseif"
4750 || sCmd == "switch"
4751 || sCmd == "endswitch"
4752 || sCmd == "case"
4753 || sCmd == "default"
4754 || sCmd == "try"
4755 || sCmd == "catch"
4756 || sCmd == "endtry"
4757 || sCmd == "while"
4758 || sCmd == "endwhile";
4759}
4760
4761
4762// VIRTUAL FUNCTION IMPLEMENTATIONS
4778FlowCtrl::ProcedureInterfaceRetVal FlowCtrl::procedureInterface(std::string& sLine, Parser& _parser, FunctionDefinitionManager& _functions, MemoryManager& _data, Output& _out, PlotData& _pData, Script& _script, Settings& _option, int nth_command)
4779{
4781}
4782
4783
4791int FlowCtrl::procedureCmdInterface(std::string& sLine)
4792{
4793 return 1;
4794}
4795
4796
4804int FlowCtrl::isInline(const std::string& sProc)
4805{
4806 return true;
4807}
4808
4809
4819{
4820 return 0;
4821}
4822
4823
4831{
4832 return 0;
4833}
4834
4835
4843vector<std::string> FlowCtrl::expandInlineProcedures(std::string& sLine)
4844{
4845 return std::vector<std::string>();
4846}
4847
4848
4858int FlowCtrl::catchExceptionForTest(exception_ptr e_ptr, bool bSupressAnswer_back, int nLine)
4859{
4860 return 0;
4861}
4862
string evaluateParameterValues(const string &sCmd)
This function evaluates a passed parameter string, so that the values of the parameters are only valu...
Definition: built-in.cpp:221
CommandReturnValues commandHandler(string &sCmd)
This function is the main command handling function.
Definition: built-in.cpp:42
@ COMMAND_PROCESSED
Definition: built-in.hpp:53
@ COMMAND_HAS_RETURNVALUE
Definition: built-in.hpp:54
@ NUMERE_QUIT
Definition: built-in.hpp:51
@ NO_COMMAND
Definition: built-in.hpp:52
void enable(const std::string &sExpr)
Enables the assertion handler using the passed expression.
Definition: error.cpp:228
void reset()
Resets the assertion handler.
Definition: error.cpp:196
AssertionStats getStats() const
Returns the current tests stats.
Definition: error.cpp:328
void checkAssertion(mu::value_type *v, int nNum)
Checks the return value of a muParser evaluated result.
Definition: error.cpp:244
This class extends the std::vector for endlessness.
Definition: structures.hpp:838
int if_fork(int nth_Cmd=0, int nth_Loop=-1)
This member function realizes the IF-ELSE control flow statement. The return value is either an error...
Definition: flowctrl.cpp:843
MemoryManager * _dataRef
Definition: flowctrl.hpp:52
void replaceLocalVars(std::string &sLine)
This member function is used to replace variable occurences with their (auto-determined) internal nam...
Definition: flowctrl.cpp:3969
int calc(StringView sLine, int nthCmd)
This member function does the hard work and calculates the numerical and std::string results for the ...
Definition: flowctrl.cpp:3329
int nLoopSafety
Definition: flowctrl.hpp:124
void eval()
This member function prepares the command array by pre-evaluating all constant stuff or function call...
Definition: flowctrl.cpp:2340
void fillJumpTableAndExpandRecursives()
Go again through the whole command set and fill the jump table with the corresponding block ends and ...
Definition: flowctrl.cpp:4194
std::vector< std::vector< int > > nJumpTable
Definition: flowctrl.hpp:106
bool bFunctionsReplaced
Definition: flowctrl.hpp:116
Script * _scriptRef
Definition: flowctrl.hpp:57
int getCurrentBlockDepth() const
Returns the current block depth while reading a flow control statement to memory.
Definition: flowctrl.cpp:119
std::vector< value_type > vVarArray
Definition: flowctrl.hpp:103
Parser * _parserRef
Definition: flowctrl.hpp:51
virtual int procedureCmdInterface(std::string &sLine)
Dummy implementation.
Definition: flowctrl.cpp:4791
bool checkCaseValue(const std::string &sCaseDefinition)
This member function checks, whether the entered case definition is valid or not.
Definition: flowctrl.cpp:4078
NumeRe::Cluster evalRangeBasedHeader(std::string &sHeadExpression, int nth_Cmd, const std::string &sHeadCommand)
This member function handles the evaluation of the range-based flow control headers....
Definition: flowctrl.cpp:1696
bool bReturnSignal
Definition: flowctrl.hpp:131
void prepareSwitchExpression(int nSwitchStart)
This member function will prepare the single logical switch expression.
Definition: flowctrl.cpp:4448
bool bMask
Definition: flowctrl.hpp:121
std::vector< std::string > sVarArray
Definition: flowctrl.hpp:104
static bool isAnyFlowCtrlStatement(const std::string &sCmd)
This static member function returns whether the passed command is any of the known flow control state...
Definition: flowctrl.cpp:4742
static bool isFlowCtrlStatement(const std::string &sCmd)
This static member function returns whether the passed command is a flow control statement.
Definition: flowctrl.cpp:4726
virtual int evalDebuggerBreakPoint(Parser &_parser, Settings &_option)
Dummy implementation.
Definition: flowctrl.cpp:4818
std::string sLoopPlotCompose
Definition: flowctrl.hpp:117
void checkParsingModeAndExpandDefinitions()
If the loop parsing mode is active, ensure that only inline procedures are used in this case....
Definition: flowctrl.cpp:4511
friend FlowCtrlCommand
Definition: flowctrl.hpp:46
Returnvalue ReturnVal
Definition: flowctrl.hpp:113
int switch_fork(int nth_Cmd=0, int nth_Loop=-1)
This member function realizes the SWITCH-CASE control flow statement. The return value is either an e...
Definition: flowctrl.cpp:1092
varmap_type vVars
Definition: flowctrl.hpp:105
std::map< std::string, std::string > mVarMap
Definition: flowctrl.hpp:118
bool bLoopSupressAnswer
Definition: flowctrl.hpp:49
std::set< std::string > inlineClusters
Definition: flowctrl.hpp:119
virtual int getErrorInformationForDebugger()
Dummy implementation.
Definition: flowctrl.cpp:4830
int evalForkFlowCommands(int __j, int nth_loop)
This member function handles the evaluation of flow control statements from the viewpoint of an if-el...
Definition: flowctrl.cpp:1888
std::string sLoopNames
Definition: flowctrl.hpp:108
std::string sTestClusterName
Definition: flowctrl.hpp:127
void setCommand(std::string &__sCmd, int nCurrentLine)
This member function is used to set a command line from the outside into the flow control statement c...
Definition: flowctrl.cpp:1948
void prepareLocalVarsAndReplace(std::string &sVars)
This method prepares the local variables including their names and replaces them in the command lines...
Definition: flowctrl.cpp:4615
std::string getCurrentBlock() const
Definition: flowctrl.hpp:175
bool bLockedPauseMode
Definition: flowctrl.hpp:115
PlotData * _pDataRef
Definition: flowctrl.hpp:56
int nReturnType
Definition: flowctrl.hpp:130
bool bPrintedStatus
Definition: flowctrl.hpp:122
virtual int isInline(const std::string &sProc)
Dummy implementation.
Definition: flowctrl.cpp:4804
std::vector< int > nCalcType
Definition: flowctrl.hpp:107
int while_loop(int nth_Cmd=0, int nth_Loop=0)
This member function realizes the WHILE control flow statement. The return value is either an error v...
Definition: flowctrl.cpp:679
Output * _outRef
Definition: flowctrl.hpp:53
int nthRecursion
Definition: flowctrl.hpp:128
bool checkFlowControlArgument(const std::string &sFlowControlArgument, bool isForLoop=false)
This member function checks, whether the passed flow control argument is valid or not.
Definition: flowctrl.cpp:4043
bool bUseLoopParsingMode
Definition: flowctrl.hpp:114
void reset()
This function clears the memory of this FlowCtrl object and sets everything back to its original stat...
Definition: flowctrl.cpp:2534
int range_based_for_loop(int nth_Cmd=0, int nth_Loop=0)
This member function realizes the FOR control flow statement for range based indices....
Definition: flowctrl.cpp:377
virtual std::vector< std::string > expandInlineProcedures(std::string &sLine)
Dummy implementation.
Definition: flowctrl.cpp:4843
int(FlowCtrl::* FlowCtrlFunction)(int, int)
Definition of a generic FlowCtrl entry point.
Definition: flowctrl.hpp:140
virtual ~FlowCtrl()
Destructor. Cleanes the memory, if necessary.
Definition: flowctrl.cpp:107
int nFlowCtrlStatements[FC_COUNT]
Definition: flowctrl.hpp:110
AssertionStats baseline
Definition: flowctrl.hpp:126
int getCurrentLineNumber() const
This member function returns the current line number as enumerated during passing the commands via "s...
Definition: flowctrl.cpp:4691
std::string extractFlagsAndIndexVariables()
Read the flow control statements only and extract the index variables and the flow control flags.
Definition: flowctrl.cpp:4117
int nDebuggerCode
Definition: flowctrl.hpp:125
bool bSilent
Definition: flowctrl.hpp:120
std::string getCurrentCommand() const
This member function returns the current command line, which will or has been evaluated in the curren...
Definition: flowctrl.cpp:4708
value_type * evalHeader(int &nNum, std::string &sHeadExpression, bool bIsForHead, int nth_Cmd, const std::string &sHeadCommand)
This member function abstracts the evaluation of all flow control headers. It will return an array of...
Definition: flowctrl.cpp:1490
@ CALCTYPE_EXPLICIT
Definition: flowctrl.hpp:73
@ CALCTYPE_RECURSIVEEXPRESSION
Definition: flowctrl.hpp:79
@ CALCTYPE_TOCOMMAND
Definition: flowctrl.hpp:74
@ CALCTYPE_COMMAND
Definition: flowctrl.hpp:63
@ CALCTYPE_BREAKCMD
Definition: flowctrl.hpp:77
@ CALCTYPE_PROCEDURECMDINTERFACE
Definition: flowctrl.hpp:75
@ CALCTYPE_SUPPRESSANSWER
Definition: flowctrl.hpp:80
@ CALCTYPE_PROGRESS
Definition: flowctrl.hpp:67
@ CALCTYPE_PROMPT
Definition: flowctrl.hpp:78
@ CALCTYPE_DEBUGBREAKPOINT
Definition: flowctrl.hpp:72
@ CALCTYPE_CONTINUECMD
Definition: flowctrl.hpp:76
@ CALCTYPE_DEFINITION
Definition: flowctrl.hpp:69
@ CALCTYPE_NONE
Definition: flowctrl.hpp:62
@ CALCTYPE_COMPOSE
Definition: flowctrl.hpp:68
@ CALCTYPE_NUMERICAL
Definition: flowctrl.hpp:64
@ CALCTYPE_RETURNCOMMAND
Definition: flowctrl.hpp:70
@ CALCTYPE_ASSERT
Definition: flowctrl.hpp:81
@ CALCTYPE_THROWCOMMAND
Definition: flowctrl.hpp:71
@ CALCTYPE_STRING
Definition: flowctrl.hpp:65
@ CALCTYPE_DATAACCESS
Definition: flowctrl.hpp:66
int compile(std::string sLine, int nthCmd)
This member function does the hard work and compiles the numerical and std::string results for the cu...
Definition: flowctrl.cpp:2646
int nCurrentCommand
Definition: flowctrl.hpp:112
int try_catch(int nth_Cmd=0, int nth_Loop=-1)
Implements a try-catch block.
Definition: flowctrl.cpp:1240
Settings * _optionRef
Definition: flowctrl.hpp:54
int for_loop(int nth_Cmd=0, int nth_Loop=0)
This member function realizes the FOR control flow statement. The return value is either an error val...
Definition: flowctrl.cpp:143
void updateTestStats()
Updates the test statistics with the total test statistics.
Definition: flowctrl.cpp:4669
virtual int catchExceptionForTest(std::exception_ptr e_ptr, bool bSupressAnswer_back, int nLine)
Dummy implementation.
Definition: flowctrl.cpp:4858
ProcedureInterfaceRetVal
Definition: flowctrl.hpp:85
@ INTERFACE_VALUE
Definition: flowctrl.hpp:89
@ INTERFACE_NONE
Definition: flowctrl.hpp:88
@ INTERFACE_EMPTY
Definition: flowctrl.hpp:86
@ INTERFACE_ERROR
Definition: flowctrl.hpp:87
bool bEvaluatingFlowControlStatements
Definition: flowctrl.hpp:123
std::vector< FlowCtrlCommand > vCmdArray
Definition: flowctrl.hpp:102
FunctionDefinitionManager * _functionRef
Definition: flowctrl.hpp:55
@ FC_COUNT
Definition: flowctrl.hpp:99
@ FC_SWITCH
Definition: flowctrl.hpp:97
@ FC_WHILE
Definition: flowctrl.hpp:96
virtual ProcedureInterfaceRetVal procedureInterface(std::string &sLine, Parser &_parser, FunctionDefinitionManager &_functions, MemoryManager &_data, Output &_out, PlotData &_pData, Script &_script, Settings &_option, int nth_command)
Dummy implementation.
Definition: flowctrl.cpp:4778
FlowCtrl()
Default constructor.
Definition: flowctrl.cpp:66
This class implements the function definition managing instance.
Definition: define.hpp:74
bool call(std::string &sExpr, int nRecursion=0)
This function searches for known custom definitions in the passed expression and replaces them with t...
Definition: define.cpp:801
std::string get(const std::string &sMessage, const std::vector< std::string > &vTokens) const
This member function returns the language string for the passed language identifier and replaces all ...
Definition: language.cpp:292
This class represents the central memory managing instance. It will handle all tables and clusters,...
bool isTable(const std::string &sTable) const
This member function returns, whether the passed table name corresponds to a known table.
bool containsTablesOrClusters(const std::string &sCmdLine)
This member function evaluates, whether the passed command line contains tables or clusters.
void writeToTable(int _nLine, int _nCol, const std::string &_sCache, const mu::value_type &_dData)
This class represents a whole cluster. The single items are stored as pointers to the abstract cluste...
Definition: cluster.hpp:325
bool isString() const
This member function returns, whether the data in the cluster have only string as type.
Definition: cluster.cpp:487
size_t size() const
This member function returns the size of the internal memory buffer as items.
Definition: cluster.cpp:356
void setDouble(size_t i, const mu::value_type &value)
This member function assigns a value as data for the i-th cluster item in memory. The type of the i-t...
Definition: cluster.cpp:561
void setString(size_t i, const std::string &strval)
This member function assigns a string as data for the i-th cluster item in memory....
Definition: cluster.cpp:801
void assignResults(Indices _idx, int nNum, mu::value_type *data)
This member function assigns calculation results as data for the cluster items in memory,...
Definition: cluster.cpp:720
std::vector< std::string > to_string() const
Converts all contents of this cluster to a vector of strings. Intended to be used for data transfer.
Definition: cluster.cpp:903
void setDoubleArray(const std::vector< mu::value_type > &vVals)
This member function assigns values as data for the all cluster items in memory. The type of the clus...
Definition: cluster.cpp:648
mu::value_type getDouble(size_t i) const
This member function returns the data of the i-th cluster item in memory as a value.
Definition: cluster.cpp:541
std::string getInternalString(size_t i) const
This member function returns the data of the i-th cluster item in memory as a string.
Definition: cluster.cpp:763
bool isDouble() const
This member function returns, whether the data in the cluster have only double as type.
Definition: cluster.cpp:451
unsigned short getType(size_t i) const
This member function returns the type of the i-th cluster item in the internal memory buffer.
Definition: cluster.cpp:524
void removeCluster(const std::string &sCluster)
This member function removes the cluster from memory, which corresponds to the passed cluster identif...
Definition: cluster.cpp:2173
Cluster & getCluster(StringView sCluster)
This member function returns a reference to the cluster indicated by the passed cluster identifier.
Definition: cluster.cpp:2077
std::string createTemporaryCluster(const std::string &suffix="")
This member function creates a temporary cluster with a unique name and returns this name to the call...
Definition: cluster.cpp:2191
This class is the central string expression parser. It is designed as being a singleton with a persis...
virtual bool isStringExpression(const std::string &sExpression) override
Returns true, if the passed expression is an expression containing strings, string variables or strin...
StringParserRetVal evalAndFormat(std::string &sLine, std::string &sCache, bool bSilent=false, bool bCheckAssertions=false)
This public member function evaluates the passed string expression and formats the results for the co...
bool isStringVar(const std::string &sVarName) const
Determine, whether the passed string is the identifier of a string variable.
void setStringValue(const std::string &sVar, const std::string &sValue)
This public member function creates or updates a string variable and fills it with the passed value.
void getStringValues(std::string &sLine)
This public member function resolves all string variable occurences and replaces them with their valu...
void removeTempStringVectorVars()
This member function removes all temporary string vector variables.
void removeStringVar(const std::string &sVar)
This public member function removes the selected string variable from memory.
void throwException(SyntaxError error)
This member function shows the debugger with the corresponding error message obtained by the passed S...
Definition: debugger.cpp:120
void finalizeCatched()
Definition: debugger.hpp:76
void gatherLoopBasedInformations(const std::string &_sErraticCommand, unsigned int _nLineNumber, std::map< std::string, std::string > &mVarMap, const std::vector< mu::value_type > &vVarArray, const std::vector< std::string > &sVarArray)
This member funciton gathers the necessary debugging informations from the current executed control f...
Definition: debugger.cpp:701
void showError(const std::string &sTitle)
This member function shows the debugger with the passed error message.
Definition: debugger.cpp:96
static NumeReKernel * getInstance()
This static member function returns a a pointer to the singleton instance of the kernel.
Definition: kernel.hpp:221
NumeRe::StringParser & getStringParser()
Definition: kernel.hpp:286
static bool bSupressAnswer
Definition: kernel.hpp:199
Script & getScript()
Definition: kernel.hpp:311
PlotData & getPlottingData()
Definition: kernel.hpp:301
Output & getOutput()
Definition: kernel.hpp:306
static void printPreFmt(const std::string &__sLine, bool printingEnabled=true)
This member function appends the pre- formatted string to the buffer and informs the terminal that we...
Definition: kernel.cpp:2683
mu::Parser & getParser()
Definition: kernel.hpp:281
NumeReDebugger & getDebugger()
Definition: kernel.hpp:326
MemoryManager & getMemoryManager()
Definition: kernel.hpp:263
static void print(const std::string &__sLine, bool printingEnabled=true)
This member function appends the passed string as a new output line to the buffer and informs the ter...
Definition: kernel.cpp:2636
@ DEBUGGER_LEAVE
Definition: kernel.hpp:134
@ DEBUGGER_STEPOVER
Definition: kernel.hpp:133
NumeRe::Cluster & getAns()
Definition: kernel.hpp:268
FunctionDefinitionManager & getDefinitions()
Definition: kernel.hpp:291
static bool GetAsyncCancelState()
This function is used by the kernel to get informed, when the user pressed ESC or used other means of...
Definition: kernel.cpp:3703
static std::string formatResultOutput(int nNum, mu::value_type *v)
This static function is used to format the result output in the terminal for numerical-only results.
Definition: kernel.cpp:2730
Settings & getSettings()
Definition: kernel.hpp:296
This class contains all the plot settings usable by the plotting algorithm.
Definition: plotdata.hpp:42
This class manages the setting values of the internal (kernel) settings of this application.
Definition: settings.hpp:663
bool systemPrints() const
Returns, whether system messages shall be printed to the terminal.
Definition: settings.hpp:1140
bool useMaskDefault() const
Returns, whether loop flow control statements shall use the mask option automatically.
Definition: settings.hpp:1192
bool useDebugger() const
Returns, whether the debugger is currently active.
Definition: settings.hpp:1150
void strip()
This member function shrinks the viewed section to remove all leading or trailing whitespace characte...
std::string to_string() const
This member function returns a copy of the viewed section of the string (via std::string::substr)....
size_t find(const std::string &findstr, size_t pos=0) const
Wrapper member function for std::string::find()
size_t length() const
This member function simply returns the length of the viewed section.
This class is the immutable (const) version of a string view. It can be constructed from a MutableStr...
StringView subview(size_t pos=0, size_t len=std::string::npos) const
This member function creates a new StringView class instance using the selected position and length a...
Common exception class for all exceptions thrown in NumeRe.
Definition: error.hpp:32
@ CANNOT_EVAL_SWITCH
Definition: error.hpp:86
@ LOOP_THROW
Definition: error.hpp:152
@ CANNOT_EVAL_IF
Definition: error.hpp:59
@ CANNOT_EVAL_FOR
Definition: error.hpp:58
@ CANNOT_EVAL_TRY
Definition: error.hpp:89
@ FUNCTION_ERROR
Definition: error.hpp:110
@ UNMATCHED_PARENTHESIS
Definition: error.hpp:224
@ CANNOT_EVAL_WHILE
Definition: error.hpp:60
@ INVALID_FLOWCTRL_STATEMENT
Definition: error.hpp:143
@ INVALID_INDEX
Definition: error.hpp:129
@ PROCEDURE_ERROR
Definition: error.hpp:197
@ PROCESS_ABORTED_BY_USER
Definition: error.hpp:202
static size_t invalid_position
Definition: error.hpp:235
bool isOpenEnd() const
This member function determines, whether the internal index set has an open end.
Definition: structures.hpp:614
std::string to_string() const
This member function converts the vector indexes contents into a human-readable string representation...
Definition: structures.hpp:770
void SetExpr(StringView a_sExpr)
Set the expression. Triggers first time calculation thus the creation of the bytecode and scanning of...
value_type Eval()
Single-value wrapper around the vectorized overload of this member function.
void CacheCurrentTarget(const std::string &sEquation)
Caches the passed target equation for this position.
int IsValidByteCode(unsigned int _nthLoopElement=-1, unsigned int _nthPartEquation=0)
This member function returns, whether the current equation is already parsed and there's a valid byte...
const std::string & GetCachedEquation() const
Returns the stored equation for this position.
void SetIndex(unsigned int _nLoopElement)
Activates the selected position in the internally stored bytecode.
void PauseLoopMode(bool _bPause=true)
This member function pauses the loop mode, so that the new assigned equation does not invalidate alre...
bool IsLockedPause() const
Check, whether the pause mode is locked.
void DeactivateLoopMode()
Deactivates the loop mode and resets the internal arrays.
void ClearVectorVars(bool bIgnoreProcedureVects=false)
This member function cleares the internal vector storage.
bool ActiveLoopMode() const
Check, whether the loop mode is active. This function returns true even if the loop mode is paused.
void DefineVar(const string_type &a_sName, value_type *a_fVar)
Add a user defined variable.
void RemoveVar(const string_type &a_strVarName)
Remove a variable from internal storage.
bool CanCacheAccess()
Check, whether the current position can cache any data accesses.
bool IsAlreadyParsed(StringView sNewEquation)
This member function checks, whether the passed expression is already parsed, so that the parsing ste...
bool IsCompiling()
Returns true, if the parser is currently in compiling step.
bool IsNotLastStackItem() const
Check, whether there are more elements on the parsing stack remaining.
void LockPause(bool _bLock=true)
This member function locks the pause mode so that it cannot be accidentally activated.
void ActivateLoopMode(unsigned int _nLoopLength)
Activates the loop mode and prepares the internal arrays for storing the necessary data.
void CacheCurrentEquation(const std::string &sEquation)
Caches the passed equation for this position.
size_t HasCachedAccess()
Evaluate, whether there are any cached data accesses for this position.
std::map< std::string, std::string > * mVarMapPntr
Definition: muParserBase.h:98
void SetCompiling(bool _bCompiling=true)
Activate the compiling step for the parser.
Mathematical expressions parser.
Definition: muParser.h:51
string getDataElements(string &sLine, Parser &_parser, MemoryManager &_data, const Settings &_option, int options)
Searches the passed string for calls to any table or cluster and replaces them with internal vectors ...
Definition: dataaccess.cpp:276
bool isNotEmptyExpression(const string &sExpr)
This function checks, whether the passed expression is non-empty (i.e. it contains more than white sp...
bool isClusterCandidate(string &sLine, string &sCluster, bool doCut)
This function checks, whether the passed command line contains the syntax for a cluster candidate,...
Indices getIndices(StringView sCmd, mu::Parser &_parser, MemoryManager &_data, const Settings &_option)
Wrapper for the new getIndices function interface.
Definition: indices.cpp:49
bool isValidIndexSet(const Indices &_idx)
Definition: dataaccess.hpp:81
Language _lang
Definition: kernel.cpp:39
ErrorType getErrorType(std::exception_ptr e_ptr)
This function obtains the error type of a catched exception and sets the last error message.
Definition: error.cpp:42
std::string errorTypeToString(ErrorType e)
Return the error type converted to a human readable string.
Definition: error.cpp:148
Assertion _assertionHandler
Definition: error.cpp:27
ErrorType
Defines the possible error types, which can be thrown in this application.
Definition: error.hpp:469
@ TYPE_INTERNALERROR
Definition: error.hpp:476
@ TYPE_CRITICALERROR
Definition: error.hpp:477
@ TYPE_ABORT
Definition: error.hpp:471
#define FLOWCTRL_NO_CMD
Definition: flowctrl.cpp:33
RangeForVarType
Simple enum to make the variable types of the range based for loop more readable.
Definition: flowctrl.cpp:356
@ STRINGVAR
Definition: flowctrl.cpp:360
@ DECLARE_NEW_VAR
Definition: flowctrl.cpp:357
@ NUMVAR
Definition: flowctrl.cpp:359
@ CLUSTERVAR
Definition: flowctrl.cpp:361
@ DETECT_VAR_TYPE
Definition: flowctrl.cpp:358
#define FLOWCTRL_RETURN
Definition: flowctrl.cpp:30
#define FLOWCTRL_BREAK
Definition: flowctrl.cpp:31
#define BLOCK_END
Definition: flowctrl.cpp:38
#define JUMP_TABLE_ELEMENTS
Definition: flowctrl.cpp:41
#define PROCEDURE_INTERFACE
Definition: flowctrl.cpp:40
#define FLOWCTRL_ERROR
Definition: flowctrl.cpp:29
static std::string extractHeaderExpression(const std::string &sExpr)
A simple helper function to extract the header expression of control flow statements.
Definition: flowctrl.cpp:56
#define FLOWCTRL_CONTINUE
Definition: flowctrl.cpp:32
#define NO_FLOW_COMMAND
Definition: flowctrl.cpp:37
value_type vAns
#define BLOCK_MIDDLE
Definition: flowctrl.cpp:39
#define FLOWCTRL_OK
Definition: flowctrl.cpp:34
string sErrorToken
unsigned int getMatchingParenthesis(const StringView &)
Returns the position of the closing parenthesis.
Definition: tools.cpp:414
CONSTCD11 std::chrono::duration< Rep, Period > abs(std::chrono::duration< Rep, Period > d)
Definition: date.h:1317
MUP_BASETYPE value_type
The numeric datatype used by the parser.
Definition: muParserDef.h:251
bool isnan(const value_type &v)
Definition: muParserDef.h:379
string promptForUserInput(const string &__sCommand)
This function is invoked, if a prompt operator ("??") was found in a string.
mu::value_type * getPointerToVariable(const string &sVarName, Parser &_parser)
This function returns the pointer to the passed variable.
#define min(a, b)
Definition: resampler.cpp:34
void StripSpaces(std::string &)
Removes leading and trailing white spaces and tabulator characters.
int findParameter(const std::string &sCmd, const std::string &sParam, const char cFollowing)
This function searches the passed parameter in the passed command string. If something is found,...
Definition: tools.cpp:113
std::string getNextArgument(std::string &sArgList, bool bCut)
Definition: tools.cpp:2294
void replaceAll(std::string &sToModify, const char *sToRep, const char *sNewValue, size_t nStart, size_t nEnd)
This function replaces all occurences of the string sToRep in the string sToModify with the new value...
This structure accumulates the statistics for the assertion handler.
Definition: error.hpp:496
size_t nFailedAssertions
Definition: error.hpp:498
size_t nCheckedAssertions
Definition: error.hpp:497
This structure is central for managing the indices of a table or cluster read or write data access....
VectorIndex col
VectorIndex row
std::string sCompiledAccessEquation
std::string sString
std::vector< std::string > vStringVal
std::string sReturnedTable
std::vector< mu::value_type > vNumVal
long long int intCast(const std::complex< double > &)
Casts the real part of the complex number to an integer and avoids rounding errors.
Definition: tools.cpp:1824
std::string toString(int)
Converts an integer to a string without the Settings bloat.
Match findCommand(StringView sCmd, const std::string &sCommand)
This function is very important for the command handler.
Definition: tools.cpp:1275
string getArgAtPos(const string &sCmd, unsigned int nPos, int extraction)
Extracts a options value at the selected position and applies automatic parsing, if necessary.
Definition: tools.cpp:1598
void evalRecursiveExpressions(string &sExpr)
This function converts the recursive assignments like VAR += VAL into VAR = VAR + (VAL)
Definition: tools.cpp:3346
bool isInQuotes(StringView sExpr, unsigned int nPos, bool bIgnoreVarParser)
Checks, whether the position in the passed expression is part of a string literal.
Definition: tools.cpp:1672
bool checkDelimiter(const string &sString, bool stringdelim)
Checks, whether the first and the last character in the passed string is a delimiter character.
Definition: tools.cpp:1982
bool validateParenthesisNumber(const string &sCmd)
This function is used to validate the number of parentheses, i.e. whether there's a closing parenthes...
Definition: tools.cpp:3512
EndlessVector< StringView > getAllArguments(StringView sArgList)
Splits up the complete argument list and returns them as an EndlessVector.
Definition: tools.cpp:2346
void make_progressBar(int nStep, int nFirstStep, int nFinalStep, const string &sType)
Wrapper for the static member function of the kernel.
Definition: tools.cpp:2425