7 #ifndef JADE_SHUNTING_YARD_HPP__
8 #define JADE_SHUNTING_YARD_HPP__
10 #include "jade.error.hpp"
21 template <
typename TFloat>
33 typedef std::map<std::string, float_type>
args_type;
44 std::vector<_token> tokens;
48 for (
const auto & t : _queue)
49 if (t.type == _token::variable)
64 std::istringstream in (expression);
86 std::vector<float_type> stack;
88 for (
const auto & t : _queue)
90 if (t.type == _token::number)
92 stack.push_back(t.get_value());
94 else if (t.type == _token::variable)
96 const auto item =
args.find(t.text);
98 if (item ==
args.end())
100 <<
"undefined variable '"
104 stack.push_back(item->second);
108 if (stack.size() < 2)
111 const auto n2 = stack.back();
113 const auto n1 = stack.back();
116 if (t.type == _token::plus ) stack.push_back(n1 + n2);
117 else if (t.type == _token::minus) stack.push_back(n1 - n2);
118 else if (t.type == _token::star ) stack.push_back(n1 * n2);
119 else if (t.type == _token::slash) stack.push_back(n1 / n2);
124 if (stack.size() != 1)
161 explicit _token(
const type_t type_)
168 int get_precedence()
const
170 return type == plus || type == minus ? 1 :
171 type == star || type == slash ? 2 :
179 std::istringstream(text) >> value;
184 bool is_numeric()
const
186 return type == variable || type == number;
190 bool is_operator()
const
192 return type == plus || type == minus
193 || type == star || type == slash;
201 void _enqueue(
const std::vector<_token> & tokens)
203 std::vector<_token> stack;
205 for (
size_t i = 0; i < tokens.size(); i++)
207 const auto & t1 = tokens[i];
211 _queue.push_back(t1);
213 else if (t1.is_operator())
215 while (!stack.empty())
217 const auto & t2 = stack.back();
219 if (!t2.is_operator())
221 if (t1.get_precedence() > t2.get_precedence())
224 _queue.push_back(t2);
230 else if (t1.type == _token::paren_lhs)
234 else if (t1.type == _token::paren_rhs)
236 while (!stack.empty())
238 const auto & t2 = stack.back();
240 if (t2.type == _token::paren_lhs)
243 _queue.push_back(t2);
254 while (!stack.empty())
256 const auto & t2 = stack.back();
258 if (t2.type == _token::paren_lhs)
261 _queue.push_back(t2);
267 static void _scan(std::istream & in, std::vector<_token> & tokens)
269 const auto cat = [&tokens](
const int ch)
271 tokens.back().text.push_back(
static_cast<char>(ch));
274 for (
auto ch = in.get(); ch >= 0; ch = in.get())
276 if (std::isspace(ch))
continue;
277 else if (ch ==
'(') tokens.emplace_back(_token::paren_lhs);
278 else if (ch ==
')') tokens.emplace_back(_token::paren_rhs);
279 else if (ch ==
'+') tokens.emplace_back(_token::plus);
280 else if (ch ==
'-') tokens.emplace_back(_token::minus);
281 else if (ch ==
'*') tokens.emplace_back(_token::star);
282 else if (ch ==
'/') tokens.emplace_back(_token::slash);
283 else if (std::isalpha(ch))
285 tokens.emplace_back(_token::variable);
288 while (in.peek() ==
'_' || 0 != std::isalnum(in.peek()))
291 else if (std::isdigit(ch))
293 tokens.emplace_back(_token::number);
296 while (std::isdigit(in.peek()))
299 if (in.peek() ==
'.')
303 while (std::isdigit(in.peek()))
310 <<
"invalid symbol '"
311 <<
static_cast<char>(ch)
316 tokens.emplace_back(_token::end);
320 std::vector<_token> _queue;
324 #endif // JADE_SHUNTING_YARD_HPP__