9#include <framework/utilities/FormulaParser.h>
22 case EOperator::c_noop:
return ' ';
23 case EOperator::c_plus:
return '+';
24 case EOperator::c_minus:
return '-';
25 case EOperator::c_multiply:
return '*';
26 case EOperator::c_divide:
return '/';
27 case EOperator::c_power:
return '^';
28 case EOperator::c_roundBracketOpen:
return '(';
29 case EOperator::c_roundBracketClose:
return ')';
30 case EOperator::c_squareBracketOpen:
return '[';
31 case EOperator::c_squareBracketClose:
return ']';
44 default:
throw std::runtime_error(std::string(
"Cannot apply operator ") +
operatorToChar(op));
52 case ENumberStatus::c_Invalid:
54 return ENumberStatus::c_Invalid;
55 case ENumberStatus::c_Empty:
57 if (std::isdigit(next))
return ENumberStatus::c_Int;
58 if (next ==
'.')
return ENumberStatus::c_LeadingDot;
59 if (next ==
'+' or next ==
'-')
return ENumberStatus::c_Sign;
61 return ENumberStatus::c_Invalid;
62 case ENumberStatus::c_Sign:
64 if (std::isdigit(next))
return ENumberStatus::c_Int;
65 if (next ==
'.')
return ENumberStatus::c_Dot;
66 return ENumberStatus::c_Invalid;
67 case ENumberStatus::c_Int:
70 if (std::isdigit(next))
return ENumberStatus::c_Int;
71 if (next ==
'.')
return ENumberStatus::c_Dot;
72 if (next ==
'E' or next ==
'e')
return ENumberStatus::c_Exponent;
73 return ENumberStatus::c_Invalid;
74 case ENumberStatus::c_Dot:
76 if (std::isdigit(next))
return ENumberStatus::c_Float;
77 if (next ==
'E' or next ==
'e')
return ENumberStatus::c_Exponent;
78 return ENumberStatus::c_Invalid;
79 case ENumberStatus::c_LeadingDot:
81 if (std::isdigit(next))
return ENumberStatus::c_Float;
82 return ENumberStatus::c_Invalid;
84 case ENumberStatus::c_Float:
85 if (std::isdigit(next))
return ENumberStatus::c_Float;
86 if (next ==
'E' or next ==
'e')
return ENumberStatus::c_Exponent;
87 return ENumberStatus::c_Invalid;
88 case ENumberStatus::c_Exponent:
90 if (std::isdigit(next))
return ENumberStatus::c_Scientific;
91 if (next ==
'+' or next ==
'-')
return ENumberStatus::c_ExponentSign;
92 return ENumberStatus::c_Invalid;
93 case ENumberStatus::c_ExponentSign:
94 case ENumberStatus::c_Scientific:
96 if (std::isdigit(next))
return ENumberStatus::c_Scientific;
97 return ENumberStatus::c_Invalid;
99 return ENumberStatus::c_Invalid;
106 throw std::runtime_error(
"could not parse, stack of operands empty. Please report, this is most likely a bug");
108 throw std::runtime_error(
"Missing operand");
129 if (tok == wrong)
throw std::runtime_error(
"wrong type of closing bracket");
130 if (tok == correct)
return;
134 throw std::runtime_error(
"unmatched bracket");
143 int op_precedence = (int)op >> 4;
148 int tok_precedence = (int)tok >> 4;
153 if (tok_precedence < op_precedence or (tok_precedence == op_precedence and tok_right))
break;
168 throw std::runtime_error(
"missing closing bracket");
194 if (next ==
'+' or next ==
'-') {
197 auto isvalid = checkNumber(m_currentVariableNameNumberStatus, next);
198 if (isvalid != ENumberStatus::c_Invalid and checkNumber(isvalid, m_buffer.peek()) != ENumberStatus::c_Invalid) {
200 return EOperator::c_noop;
202 if (next ==
'+')
return EOperator::c_plus;
203 if (next ==
'-')
return EOperator::c_minus;
205 if (next ==
'/')
return EOperator::c_divide;
206 if (next ==
'^')
return EOperator::c_power;
210 if (m_buffer.peek() ==
'*') {
212 return EOperator::c_power;
215 return EOperator::c_multiply;
217 if (next ==
'(')
return EOperator::c_roundBracketOpen;
218 if (next ==
')')
return EOperator::c_roundBracketClose;
219 if (next ==
'[')
return EOperator::c_squareBracketOpen;
220 if (next ==
']')
return EOperator::c_squareBracketClose;
222 return EOperator::c_noop;
228 m_buffer = std::istringstream(formula);
239 for (
char next;
m_buffer.get(next);) {
245 if (next ==
'(') ++nestlevel;
246 if (next ==
')') --nestlevel;
274 if (next ==
' ' or next ==
'\n' or next ==
'\t' or next ==
'\r') {
288 if (nestlevel > 0)
throw std::runtime_error(
"unterminated variable arguments");
297 std::ostringstream message;
301 if (pos == -1) pos =
m_buffer.str().size() + 1;
303 message <<
"Error parsing formula at character " << pos <<
": " << e.what() << std::endl;
305 std::istringstream errbuff(
m_buffer.str());
307 bool arrowShown{
false};
308 for (std::string line; std::getline(errbuff, line);) {
310 message <<
" " << line << std::endl;
312 auto curpos = errbuff.tellg();
314 if (!arrowShown && (curpos == -1 || curpos >= pos)) {
316 for (
long i = lastpos - 1; i < pos; ++i) message <<
"-";
317 message <<
"^" << std::endl;
323 throw std::runtime_error(message.str());
EOperator checkForOperator(char next)
Check if the next character is a operator.
void flushPendingOperators()
Flush all pending operators at the end of processing.
void addOperator(EOperator op)
Add an operator to the internal state, convert them to reverse polish notation using the shunting yar...
void processString(const std::string &formula)
Process the given formula and store the final state.
static double applyOperator(EOperator op, double a, double b)
Apply operator on two values.
static void assertOperatorUsable(size_t stacksize)
Make sure we have enough operands to use an operator.
void raiseError(const std::runtime_error &e)
Format the given runtime_error with context information and rethrow a new one.
void flushCurrentVariable()
Flush the currently parsed variable name and add it to the state either as variable or number.
static char operatorToChar(EOperator op) noexcept
Convert operator code to character.
static ENumberStatus checkNumber(ENumberStatus current, char next)
Check if a string literal with a given number status continues to be a valid number if next is append...
Abstract base class for different kinds of events.