summaryrefslogtreecommitdiffstats
path: root/src/libixion/formula_interpreter.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libixion/formula_interpreter.hpp')
-rw-r--r--src/libixion/formula_interpreter.hpp125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/libixion/formula_interpreter.hpp b/src/libixion/formula_interpreter.hpp
new file mode 100644
index 0000000..73721f6
--- /dev/null
+++ b/src/libixion/formula_interpreter.hpp
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_IXION_FORMULA_INTERPRETER_HPP
+#define INCLUDED_IXION_FORMULA_INTERPRETER_HPP
+
+#include "ixion/global.hpp"
+#include "ixion/formula_tokens.hpp"
+#include "ixion/formula_result.hpp"
+
+#include "formula_value_stack.hpp"
+
+#include <sstream>
+#include <unordered_set>
+#include <deque>
+
+namespace ixion {
+
+class formula_cell;
+
+namespace iface {
+
+class session_handler;
+
+}
+
+/**
+ * The formula interpreter parses a series of formula tokens representing a
+ * formula expression, and calculates the result of that expression.
+ *
+ * <p>Intermediate result of each handler is pushed onto the stack and
+ * popped from it for the calling method to retrieve. By the end of the
+ * interpretation there should only be one result left on the stack which is
+ * the final result of the interpretation of the expression. The number of
+ * intermediate results (or stack values) on the stack is normally one at
+ * the end of each handler, except for the function handler where the number
+ * of stack values may be more than one when the function may take more than
+ * one argument.</p>
+ */
+class formula_interpreter
+{
+ using name_set = std::unordered_set<std::string>;
+ using fv_stacks_type = std::deque<formula_value_stack>;
+
+public:
+ typedef ::std::vector<const formula_token*> local_tokens_type;
+
+ formula_interpreter() = delete;
+ formula_interpreter(const formula_interpreter&) = delete;
+ formula_interpreter& operator= (formula_interpreter) = delete;
+
+ formula_interpreter(const formula_cell* cell, model_context& cxt);
+ ~formula_interpreter();
+
+ void set_origin(const abs_address_t& pos);
+ bool interpret();
+ formula_result transfer_result();
+ formula_error_t get_error() const;
+
+private:
+ /**
+ * Expand all named expressions into a flat set of tokens. This is also
+ * where we detect circular referencing of named expressions.
+ */
+ void init_tokens();
+
+ void pop_result();
+
+ void expand_named_expression(const named_expression_t* expr, name_set& used_names);
+
+ void ensure_token_exists() const;
+ bool has_token() const;
+ void next();
+ const formula_token& token() const;
+ const formula_token& token_or_throw() const;
+ const formula_token& next_token();
+ const std::string& string_or_throw() const;
+
+ // The following methods are handlers. In each handler, the initial
+ // position is always set to the first unprocessed token. Each handler is
+ // responsible for setting the token position to the next unprocessed
+ // position when it finishes.
+
+ void expression();
+ void term();
+ void factor();
+ bool sign();
+ void paren();
+ void single_ref();
+ void range_ref();
+ void table_ref();
+ void constant();
+ void literal();
+ void array();
+ void function();
+
+ void clear_stacks();
+ void push_stack();
+ void pop_stack();
+
+ formula_value_stack& get_stack();
+
+private:
+ const formula_cell* m_parent_cell;
+ model_context& m_context;
+ std::unique_ptr<iface::session_handler> mp_handler;
+ abs_address_t m_pos;
+
+ fv_stacks_type m_stacks;
+ local_tokens_type m_tokens;
+ local_tokens_type::const_iterator m_cur_token_itr;
+ local_tokens_type::const_iterator m_end_token_pos;
+
+ formula_result m_result;
+ formula_error_t m_error;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */