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");
193 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;
211 if (m_buffer.peek() ==
'*') {
213 return EOperator::c_power;
216 return EOperator::c_multiply;
218 if (next ==
'(')
return EOperator::c_roundBracketOpen;
219 if (next ==
')')
return EOperator::c_roundBracketClose;
220 if (next ==
'[')
return EOperator::c_squareBracketOpen;
221 if (next ==
']')
return EOperator::c_squareBracketClose;
223 return EOperator::c_noop;
229 m_buffer = std::istringstream(formula);
240 for (
char next;
m_buffer.get(next);) {
246 if (next ==
'(') ++nestlevel;
247 if (next ==
')') --nestlevel;
275 if (next ==
' ' or next ==
'\n' or next ==
'\t' or next ==
'\r') {
289 if (nestlevel > 0)
throw std::runtime_error(
"unterminated variable arguments");
298 std::ostringstream message;
302 if (pos == -1) pos =
m_buffer.str().size() + 1;
304 message <<
"Error parsing formula at character " << pos <<
": " << e.what() << std::endl;
306 std::istringstream errbuff(
m_buffer.str());
308 bool arrowShown{
false};
309 for (std::string line; std::getline(errbuff, line);) {
311 message <<
" " << line << std::endl;
313 auto curpos = errbuff.tellg();
315 if (!arrowShown && (curpos == -1 || curpos >= pos)) {
317 for (
long i = lastpos - 1; i < pos; ++i) message <<
"-";
318 message <<
"^" << std::endl;
324 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.