From 2e34cc59062ae51b1005f755bff7f418eab84b69 Mon Sep 17 00:00:00 2001 From: Stephane Del Pino <stephane.delpino44@gmail.com> Date: Fri, 21 Jun 2019 18:56:06 +0200 Subject: [PATCH] Begin reorganization of AST construction to reduce compilation time Code is quite crappy and will require lots of clean-up --- src/language/ASTBuilder.cpp | 267 +++ src/language/ASTBuilder.hpp | 10 + src/language/ASTNode.hpp | 88 + .../ASTNodeAffectationExpressionBuilder.cpp | 228 ++ .../ASTNodeAffectationExpressionBuilder.hpp | 11 + ...ASTNodeBinaryOperatorExpressionBuilder.cpp | 357 +++ ...ASTNodeBinaryOperatorExpressionBuilder.hpp | 11 + src/language/ASTNodeDataType.cpp | 48 + src/language/ASTNodeDataType.hpp | 28 + src/language/ASTNodeExpressionBuilder.cpp | 613 +++++ src/language/ASTNodeExpressionBuilder.hpp | 11 + src/language/CMakeLists.txt | 5 + src/language/PEGGrammar.hpp | 331 +++ src/language/PugsParser.cpp | 1977 +---------------- src/language/SymbolTable.hpp | 126 ++ 15 files changed, 2143 insertions(+), 1968 deletions(-) create mode 100644 src/language/ASTBuilder.cpp create mode 100644 src/language/ASTBuilder.hpp create mode 100644 src/language/ASTNode.hpp create mode 100644 src/language/ASTNodeAffectationExpressionBuilder.cpp create mode 100644 src/language/ASTNodeAffectationExpressionBuilder.hpp create mode 100644 src/language/ASTNodeBinaryOperatorExpressionBuilder.cpp create mode 100644 src/language/ASTNodeBinaryOperatorExpressionBuilder.hpp create mode 100644 src/language/ASTNodeDataType.cpp create mode 100644 src/language/ASTNodeDataType.hpp create mode 100644 src/language/ASTNodeExpressionBuilder.cpp create mode 100644 src/language/ASTNodeExpressionBuilder.hpp create mode 100644 src/language/PEGGrammar.hpp create mode 100644 src/language/SymbolTable.hpp diff --git a/src/language/ASTBuilder.cpp b/src/language/ASTBuilder.cpp new file mode 100644 index 000000000..5f8eb02e7 --- /dev/null +++ b/src/language/ASTBuilder.cpp @@ -0,0 +1,267 @@ +#include <ASTBuilder.hpp> + +using namespace TAO_PEGTL_NAMESPACE; + +#include <ASTNode.hpp> +#include <PEGGrammar.hpp> + +#include <pegtl/contrib/parse_tree.hpp> + +namespace language +{ +struct rearrange : parse_tree::apply<rearrange> +{ + template <typename... States> + static void + transform(std::unique_ptr<Node>& n, States&&... st) + { + if (n->children.size() == 1) { + n = std::move(n->children.back()); + } else { + // First we rearrange tree + { + n->remove_content(); + auto& children = n->children; + auto rhs = std::move(children.back()); + children.pop_back(); + auto op = std::move(children.back()); + children.pop_back(); + op->children.emplace_back(std::move(n)); + op->children.emplace_back(std::move(rhs)); + n = std::move(op); + transform(n->children.front(), st...); + } + // Then we eventually simplify operations + { + if (n->is<language::minus_op>()) { + Assert(n->children.size() == 2); + auto& rhs = n->children[1]; + if (rhs->is<language::unary_minus>()) { + rhs->remove_content(); + n->id = typeid(language::plus_op); + rhs = std::move(rhs->children[0]); + } + } else if (n->is<language::plus_op>()) { + Assert(n->children.size() == 2); + auto& rhs = n->children[1]; + if (rhs->is<language::unary_minus>()) { + rhs->remove_content(); + n->id = typeid(language::minus_op); + rhs = std::move(rhs->children[0]); + } + } + } + } + } +}; + +struct simplify_unary : parse_tree::apply<simplify_unary> +{ + template <typename... States> + static void + transform(std::unique_ptr<Node>& n, States&&... st) + { + if (n->children.size() == 1) { + if (n->is<unary_expression>()) { + n->remove_content(); + n = std::move(n->children.back()); + transform(n, st...); + } else if (n->is<unary_minus>()) { + auto& child = n->children[0]; + if (child->is<unary_minus>()) { + n->remove_content(); + child->remove_content(); + n = std::move(child->children[0]); + transform(n, st...); + } + } else if (n->is<unary_not>()) { + auto& child = n->children[0]; + if (child->is<unary_not>()) { + n->remove_content(); + child->remove_content(); + n = std::move(child->children[0]); + transform(n, st...); + } + } + } else if (n->children.size() == 2) { + if (n->children[0]->is<language::unary_plus>()) { + n->remove_content(); + n = std::move(n->children[1]); + transform(n, st...); + } else if (n->children[0]->is<language::unary_minus>() or n->children[0]->is<language::unary_not>() or + n->children[0]->is<language::unary_minusminus>() or n->children[0]->is<language::unary_plusplus>()) { + n->remove_content(); + auto expression = std::move(n->children[1]); + auto unary_operator = std::move(n->children[0]); + unary_operator->children.emplace_back(std::move(expression)); + n = std::move(unary_operator); + n->remove_content(); + transform(n, st...); + } else if (n->children[1]->is<language::post_minusminus>() or n->children[1]->is<language::post_plusplus>()) { + n->remove_content(); + auto expression = std::move(n->children[0]); + auto unary_operator = std::move(n->children[1]); + unary_operator->children.emplace_back(std::move(expression)); + n = std::move(unary_operator); + n->remove_content(); + transform(n, st...); + } + } + } +}; + +struct simplify_statement_bloc : parse_tree::apply<simplify_statement_bloc> +{ + template <typename... States> + static void + transform(std::unique_ptr<Node>& n, States&&... st) + { + if (n->children.size() == 1) { + if (not n->children[0]->is<language::declaration>()) { + n->remove_content(); + n = std::move(n->children.back()); + transform(n, st...); + } else { + n->id = typeid(language::bloc); + } + } + } +}; + +struct simplify_for_statement_bloc : parse_tree::apply<simplify_for_statement_bloc> +{ + template <typename... States> + static void + transform(std::unique_ptr<Node>& n, States&&... st) + { + if (n->children.size() == 1) { + n->remove_content(); + n = std::move(n->children.back()); + transform(n, st...); + } + } +}; + +struct simplify_for_init : parse_tree::apply<simplify_for_init> +{ + template <typename... States> + static void + transform(std::unique_ptr<Node>& n, States&&...) + { + Assert(n->children.size() <= 1); + if (n->children.size() == 1) { + n->remove_content(); + n = std::move(n->children.back()); + } + } +}; + +struct simplify_for_test : parse_tree::apply<simplify_for_test> +{ + template <typename... States> + static void + transform(std::unique_ptr<Node>& n, States&&...) + { + Assert(n->children.size() <= 1); + if (n->children.size() == 1) { + n->remove_content(); + n = std::move(n->children.back()); + } + } +}; + +struct simplify_for_post : parse_tree::apply<simplify_for_post> +{ + template <typename... States> + static void + transform(std::unique_ptr<Node>& n, States&&...) + { + Assert(n->children.size() <= 1); + if (n->children.size() == 1) { + n->remove_content(); + n = std::move(n->children.back()); + } + } +}; + +struct simplify_stream_statement : parse_tree::apply<simplify_stream_statement> +{ + template <typename... States> + static void + transform(std::unique_ptr<Node>& n, States&&...) + { + for (size_t i = 1; i < n->children.size(); ++i) { + n->children[0]->children.emplace_back(std::move(n->children[i])); + } + n->remove_content(); + n = std::move(n->children[0]); + } +}; + +template <typename Rule> +using selector = parse_tree::selector<Rule, + parse_tree::store_content::on<true_kw, + false_kw, + integer, + real, + name, + B_set, + N_set, + Z_set, + R_set, + cout_kw, + cerr_kw, + clog_kw, + declaration, + if_statement, + do_while_statement, + while_statement, + for_statement, + break_kw, + continue_kw>, + rearrange::on<product, affectation, expression>, + simplify_unary::on<unary_minus, unary_plus, unary_not, unary_expression>, + parse_tree::remove_content::on<plus_op, + minus_op, + multiply_op, + divide_op, + lesser_op, + lesser_or_eq_op, + greater_op, + greater_or_eq_op, + eqeq_op, + not_eq_op, + and_op, + or_op, + xor_op, + bitand_op, + bitor_op, + eq_op, + multiplyeq_op, + divideeq_op, + pluseq_op, + minuseq_op, + // shift_left_op, + // shift_right_op, + bit_andeq_op, + bit_xoreq_op, + bit_oreq_op, + unary_plusplus, + unary_minusminus, + post_minusminus, + post_plusplus>, + simplify_for_statement_bloc::on<for_statement_bloc>, + parse_tree::discard_empty::on<ignored, semicol, bloc>, + simplify_statement_bloc::on<statement_bloc>, + simplify_for_init::on<for_init>, + simplify_for_test::on<for_test>, + simplify_for_post::on<for_post>, + simplify_stream_statement::on<ostream_statement>>; + +} // namespace language + +std::unique_ptr<language::Node> +buildAST(read_input<>& input) +{ + return parse_tree::parse<language::grammar, language::Node, language::selector, nothing, language::errors>(input); +} diff --git a/src/language/ASTBuilder.hpp b/src/language/ASTBuilder.hpp new file mode 100644 index 000000000..d6ccc2c8b --- /dev/null +++ b/src/language/ASTBuilder.hpp @@ -0,0 +1,10 @@ +#ifndef AST_BUILDER_HPP +#define AST_BUILDER_HPP + +#include <pegtl.hpp> + +#include <ASTNode.hpp> + +std::unique_ptr<language::Node> buildAST(read_input<>& input); + +#endif // AST_BUILDER_HPP diff --git a/src/language/ASTNode.hpp b/src/language/ASTNode.hpp new file mode 100644 index 000000000..f237cdab0 --- /dev/null +++ b/src/language/ASTNode.hpp @@ -0,0 +1,88 @@ +#ifndef AST_NODE_HPP +#define AST_NODE_HPP + +#include <PugsAssert.hpp> +#include <PugsMacros.hpp> + +#include <ASTNodeDataType.hpp> + +#include <pegtl/contrib/parse_tree.hpp> + +using namespace TAO_PEGTL_NAMESPACE; + +namespace language +{ +struct ExecUntilBreakOrContinue +{ + enum class JumpType + { + no_jump, + break_jump, + continue_jump + }; + + private: + JumpType m_jump_type{JumpType::no_jump}; + bool m_exec{true}; + + public: + PUGS_INLINE + bool + exec() const + { + return m_exec; + } + + PUGS_INLINE + JumpType + jumpType() const + { + return m_jump_type; + } + + ExecUntilBreakOrContinue& operator=(const ExecUntilBreakOrContinue&) = delete; + ExecUntilBreakOrContinue& operator=(ExecUntilBreakOrContinue&&) = default; + + ExecUntilBreakOrContinue() = default; + + constexpr ExecUntilBreakOrContinue(const JumpType& jump_type) + : m_jump_type(jump_type), m_exec((jump_type == JumpType::no_jump)) + { + ; + } +}; + +class SymbolTable; +class INodeProcessor +{ + public: + virtual void execute(ExecUntilBreakOrContinue& exec_policy) = 0; + + INodeProcessor(const INodeProcessor& node) = delete; + + INodeProcessor() {} + + virtual ~INodeProcessor() {} +}; + +struct Node : public parse_tree::basic_node<Node> +{ + std::shared_ptr<SymbolTable> m_symbol_table; + std::unique_ptr<INodeProcessor> m_node_processor; + + PUGS_INLINE + void + execute(ExecUntilBreakOrContinue& exec_policy) + { + Assert(static_cast<bool>(m_node_processor)); + if (exec_policy.exec()) { + m_node_processor->execute(exec_policy); + } + } + + DataType m_data_type{DataType::undefined_t}; + DataVariant m_value; +}; +} // namespace language + +#endif // AST_NODE_HPP diff --git a/src/language/ASTNodeAffectationExpressionBuilder.cpp b/src/language/ASTNodeAffectationExpressionBuilder.cpp new file mode 100644 index 000000000..afc79af35 --- /dev/null +++ b/src/language/ASTNodeAffectationExpressionBuilder.cpp @@ -0,0 +1,228 @@ +#include <ASTNodeAffectationExpressionBuilder.hpp> +#include <PEGGrammar.hpp> +#include <SymbolTable.hpp> + +namespace language +{ +template <typename Op> +struct AffOp; + +template <> +struct AffOp<language::eq_op> +{ + template <typename A, typename B> + PUGS_INLINE void + eval(A& a, const B& b) + { + a = b; + } +}; + +template <> +struct AffOp<language::multiplyeq_op> +{ + template <typename A, typename B> + PUGS_INLINE void + eval(A& a, const B& b) + { + a *= b; + } +}; + +template <> +struct AffOp<language::divideeq_op> +{ + template <typename A, typename B> + PUGS_INLINE void + eval(A& a, const B& b) + { + a /= b; + } +}; + +template <> +struct AffOp<language::pluseq_op> +{ + template <typename A, typename B> + PUGS_INLINE void + eval(A& a, const B& b) + { + a += b; + } +}; + +template <> +struct AffOp<language::minuseq_op> +{ + template <typename A, typename B> + PUGS_INLINE void + eval(A& a, const B& b) + { + a -= b; + } +}; + +template <> +struct AffOp<language::bit_andeq_op> +{ + template <typename A, typename B> + PUGS_INLINE void + eval(A& a, const B& b) + { + a &= b; + } +}; + +template <> +struct AffOp<language::bit_xoreq_op> +{ + template <typename A, typename B> + PUGS_INLINE void + eval(A& a, const B& b) + { + a ^= b; + } +}; + +template <> +struct AffOp<language::bit_oreq_op> +{ + template <typename A, typename B> + PUGS_INLINE void + eval(A& a, const B& b) + { + a |= b; + } +}; + +template <typename OperatorT, typename ValueT, typename DataT> +class AffectationProcessor final : public INodeProcessor +{ + private: + Node& m_node; + DataVariant* p_value{nullptr}; + + static inline const bool _is_defined{[] { + if constexpr (std::is_same_v<OperatorT, language::bit_andeq_op> or + std::is_same_v<OperatorT, language::bit_xoreq_op> or + std::is_same_v<OperatorT, language::bit_oreq_op>) { + return std::is_same_v<std::decay_t<ValueT>, std::decay_t<DataT>> and std::is_integral_v<std::decay_t<ValueT>>; + } else if constexpr (std::is_same_v<std::decay_t<ValueT>, bool>) { + if constexpr (not std::is_same_v<OperatorT, language::eq_op>) { + return false; + } + } + return true; + }()}; + + public: + AffectationProcessor(Node& node) : m_node{node} + { + if constexpr (_is_defined) { + const std::string& symbol = m_node.children[0]->string(); + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol); + Assert(found); + p_value = &i_symbol->second.value(); + } else { + throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()}); + } + } + + void + execute(ExecUntilBreakOrContinue& exec_policy) + { + if constexpr (_is_defined) { + m_node.children[1]->execute(exec_policy); + + if constexpr (std::is_same_v<OperatorT, language::eq_op>) { + if constexpr (std::is_same_v<ValueT, DataT>) { + *p_value = m_node.children[1]->m_value; + } else { + *p_value = static_cast<ValueT>(std::get<DataT>(m_node.children[1]->m_value)); + } + } else { + AffOp<OperatorT>().eval(std::get<ValueT>(*p_value), std::get<DataT>(m_node.children[1]->m_value)); + } + } + } +}; + +void +set_affectation_processor(Node& n) +{ + auto set_affectation_processor = [](Node& n, const auto& operator_v) { + auto set_affectation_processor_for_data = [&](const auto& value, const DataType& data_type) { + using OperatorT = std::decay_t<decltype(operator_v)>; + using ValueT = std::decay_t<decltype(value)>; + switch (data_type) { + case DataType::bool_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, bool>>(n); + break; + } + case DataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, uint64_t>>(n); + break; + } + case DataType::int_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, int64_t>>(n); + break; + } + case DataType::double_t: { + n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, double>>(n); + break; + } + default: { + throw parse_error("undefined operand type for affectation", std::vector{n.children[0]->begin()}); + } + } + }; + + auto set_affectation_processor_for_value = [&](const DataType& value_type) { + const DataType data_type = n.children[1]->m_data_type; + switch (value_type) { + case DataType::bool_t: { + set_affectation_processor_for_data(bool{}, data_type); + break; + } + case DataType::unsigned_int_t: { + set_affectation_processor_for_data(uint64_t{}, data_type); + break; + } + case DataType::int_t: { + set_affectation_processor_for_data(int64_t{}, data_type); + break; + } + case DataType::double_t: { + set_affectation_processor_for_data(double{}, data_type); + break; + } + default: { + throw parse_error("undefined value type for affectation", std::vector{n.begin()}); + } + } + }; + + set_affectation_processor_for_value(n.m_data_type); + }; + + if (n.is<language::eq_op>()) { + set_affectation_processor(n, language::eq_op{}); + } else if (n.is<language::multiplyeq_op>()) { + set_affectation_processor(n, language::multiplyeq_op{}); + } else if (n.is<language::divideeq_op>()) { + set_affectation_processor(n, language::divideeq_op{}); + } else if (n.is<language::pluseq_op>()) { + set_affectation_processor(n, language::pluseq_op{}); + } else if (n.is<language::minuseq_op>()) { + set_affectation_processor(n, language::minuseq_op{}); + } else if (n.is<language::bit_andeq_op>()) { + set_affectation_processor(n, language::bit_andeq_op{}); + } else if (n.is<language::bit_xoreq_op>()) { + set_affectation_processor(n, language::bit_xoreq_op{}); + } else if (n.is<language::bit_oreq_op>()) { + set_affectation_processor(n, language::bit_oreq_op{}); + } else { + throw parse_error("unexpected error: undefined affectation operator", std::vector{n.begin()}); + } +} +} // namespace language diff --git a/src/language/ASTNodeAffectationExpressionBuilder.hpp b/src/language/ASTNodeAffectationExpressionBuilder.hpp new file mode 100644 index 000000000..eb80e6c8a --- /dev/null +++ b/src/language/ASTNodeAffectationExpressionBuilder.hpp @@ -0,0 +1,11 @@ +#ifndef AST_NODE_AFFECTATION_EXPRESSION_BUILDER_HPP +#define AST_NODE_AFFECTATION_EXPRESSION_BUILDER_HPP + +#include <ASTNode.hpp> + +namespace language +{ +void set_affectation_processor(Node& node); +} // namespace language + +#endif // AST_NODE_AFFECTATION_EXPRESSION_BUILDER_HPP diff --git a/src/language/ASTNodeBinaryOperatorExpressionBuilder.cpp b/src/language/ASTNodeBinaryOperatorExpressionBuilder.cpp new file mode 100644 index 000000000..8af0d4d5e --- /dev/null +++ b/src/language/ASTNodeBinaryOperatorExpressionBuilder.cpp @@ -0,0 +1,357 @@ +#include <ASTNodeBinaryOperatorExpressionBuilder.hpp> +#include <PEGGrammar.hpp> +#include <SymbolTable.hpp> + +namespace language +{ +template <typename Op> +struct BinOp; + +template <> +struct BinOp<language::and_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a and b) + { + return a and b; + } +}; + +template <> +struct BinOp<language::or_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a or b) + { + return a or b; + } +}; + +template <> +struct BinOp<language::xor_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a xor b) + { + return a xor b; + } +}; + +template <> +struct BinOp<language::bitand_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a & b) + { + return a & b; + } +}; + +template <> +struct BinOp<language::bitor_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a | b) + { + return a | b; + } +}; + +template <> +struct BinOp<language::eqeq_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a == b) + { + return a == b; + } +}; + +template <> +struct BinOp<language::not_eq_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a != b) + { + return a != b; + } +}; + +template <> +struct BinOp<language::lesser_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a < b) + { + return a < b; + } +}; + +template <> +struct BinOp<language::lesser_or_eq_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a <= b) + { + return a <= b; + } +}; + +template <> +struct BinOp<language::greater_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a > b) + { + return a > b; + } +}; + +template <> +struct BinOp<language::greater_or_eq_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a >= b) + { + return a >= b; + } +}; + +template <> +struct BinOp<language::plus_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a + b) + { + return a + b; + } +}; + +template <> +struct BinOp<language::minus_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a - b) + { + return a - b; + } +}; + +template <> +struct BinOp<language::multiply_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a * b) + { + return a * b; + } +}; + +template <> +struct BinOp<language::divide_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a / b) + { + return a / b; + } +}; + +template <typename BinaryOpT, typename ValueT, typename A_DataT, typename B_DataT> +class BinaryExpressionProcessor final : public INodeProcessor +{ + Node& m_node; + + PUGS_INLINE ValueT + eval(const DataVariant& a, const DataVariant& b) + { + // Add 'signed' when necessary to avoid signed/unsigned comparison warnings + if constexpr ((not(std::is_same_v<A_DataT, bool> or std::is_same_v<B_DataT, bool>)) and + (std::is_same_v<BinaryOpT, language::and_op> or std::is_same_v<BinaryOpT, language::or_op> or + std::is_same_v<BinaryOpT, language::xor_op> or std::is_same_v<BinaryOpT, language::bitand_op> or + std::is_same_v<BinaryOpT, language::bitor_op> or std::is_same_v<BinaryOpT, language::eqeq_op> or + std::is_same_v<BinaryOpT, language::not_eq_op> or std::is_same_v<BinaryOpT, language::lesser_op> or + std::is_same_v<BinaryOpT, language::lesser_or_eq_op> or + std::is_same_v<BinaryOpT, language::greater_op> or + std::is_same_v<BinaryOpT, language::greater_or_eq_op>) and + (std::is_signed_v<A_DataT> xor std::is_signed_v<B_DataT>)) { + if constexpr (std::is_unsigned_v<A_DataT>) { + using signed_A_DataT = std::make_signed_t<A_DataT>; + const signed_A_DataT signed_a = static_cast<signed_A_DataT>(std::get<A_DataT>(a)); + return BinOp<BinaryOpT>().eval(signed_a, std::get<B_DataT>(b)); + } else { + using signed_B_DataT = std::make_signed_t<B_DataT>; + const signed_B_DataT signed_b = static_cast<signed_B_DataT>(std::get<B_DataT>(b)); + return BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), signed_b); + } + } else { + return BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::get<B_DataT>(b)); + } + } + + static inline const bool _is_defined{[] { + if constexpr (std::is_same_v<BinaryOpT, language::bitand_op> or std::is_same_v<BinaryOpT, language::xor_op> or + std::is_same_v<BinaryOpT, language::bitor_op>) { + return std::is_same_v<std::decay_t<A_DataT>, std::decay_t<B_DataT>> and std::is_integral_v<std::decay_t<A_DataT>>; + } + return true; + }()}; + + public: + BinaryExpressionProcessor(Node& node) : m_node{node} + { + if constexpr (not _is_defined) { + throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()}); + } + } + + void + execute(ExecUntilBreakOrContinue& exec_policy) + { + if constexpr (_is_defined) { + m_node.children[0]->execute(exec_policy); + m_node.children[1]->execute(exec_policy); + + m_node.m_value = eval(m_node.children[0]->m_value, m_node.children[1]->m_value); + } + } +}; + +void +set_binary_operator_processor(Node& n) +{ + auto set_binary_operator_processor = [](Node& n, const auto& operator_v) { + auto set_binary_operator_processor_for_data_b = [&](const auto value, const auto data_a, + const DataType& data_type_b) { + using OperatorT = std::decay_t<decltype(operator_v)>; + using ValueT = std::decay_t<decltype(value)>; + using DataTA = std::decay_t<decltype(data_a)>; + switch (data_type_b) { + case DataType::bool_t: { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, bool>>(n); + break; + } + case DataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, uint64_t>>(n); + break; + } + case DataType::int_t: { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, int64_t>>(n); + break; + } + case DataType::double_t: { + n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, double>>(n); + break; + } + default: { + throw parse_error("undefined operand type for binary operator", std::vector{n.children[1]->begin()}); + } + } + }; + + auto set_binary_operator_processor_for_data_a = [&](const auto value, const DataType& data_type_a) { + const DataType data_type_b = n.children[1]->m_data_type; + switch (data_type_a) { + case DataType::bool_t: { + set_binary_operator_processor_for_data_b(value, bool{}, data_type_b); + break; + } + case DataType::unsigned_int_t: { + set_binary_operator_processor_for_data_b(value, uint64_t{}, data_type_b); + break; + } + case DataType::int_t: { + set_binary_operator_processor_for_data_b(value, int64_t{}, data_type_b); + break; + } + case DataType::double_t: { + set_binary_operator_processor_for_data_b(value, double{}, data_type_b); + break; + } + default: { + throw parse_error("undefined operand type for binary operator", std::vector{n.children[0]->begin()}); + } + } + }; + + auto set_binary_operator_processor_for_value = [&](const DataType& value_type) { + const DataType data_type_a = n.children[0]->m_data_type; + switch (value_type) { + case DataType::bool_t: { + set_binary_operator_processor_for_data_a(bool{}, data_type_a); + break; + } + case DataType::unsigned_int_t: { + set_binary_operator_processor_for_data_a(uint64_t{}, data_type_a); + break; + } + case DataType::int_t: { + set_binary_operator_processor_for_data_a(int64_t{}, data_type_a); + break; + } + case DataType::double_t: { + set_binary_operator_processor_for_data_a(double{}, data_type_a); + break; + } + default: { + throw parse_error("undefined value type for binary operator", std::vector{n.begin()}); + } + } + }; + + set_binary_operator_processor_for_value(n.m_data_type); + }; + + if (n.is<language::multiply_op>()) { + set_binary_operator_processor(n, language::multiply_op{}); + } else if (n.is<language::divide_op>()) { + set_binary_operator_processor(n, language::divide_op{}); + } else if (n.is<language::plus_op>()) { + set_binary_operator_processor(n, language::plus_op{}); + } else if (n.is<language::minus_op>()) { + set_binary_operator_processor(n, language::minus_op{}); + } else if (n.is<language::or_op>()) { + set_binary_operator_processor(n, language::or_op{}); + } else if (n.is<language::and_op>()) { + set_binary_operator_processor(n, language::and_op{}); + + } else if (n.is<language::xor_op>()) { + set_binary_operator_processor(n, language::xor_op{}); + } else if (n.is<language::bitand_op>()) { + set_binary_operator_processor(n, language::bitand_op{}); + } else if (n.is<language::bitor_op>()) { + set_binary_operator_processor(n, language::bitor_op{}); + + } else if (n.is<language::greater_op>()) { + set_binary_operator_processor(n, language::greater_op{}); + } else if (n.is<language::greater_or_eq_op>()) { + set_binary_operator_processor(n, language::greater_or_eq_op{}); + } else if (n.is<language::lesser_op>()) { + set_binary_operator_processor(n, language::lesser_op{}); + } else if (n.is<language::lesser_or_eq_op>()) { + set_binary_operator_processor(n, language::lesser_or_eq_op{}); + } else if (n.is<language::eqeq_op>()) { + set_binary_operator_processor(n, language::eqeq_op{}); + } else if (n.is<language::not_eq_op>()) { + set_binary_operator_processor(n, language::not_eq_op{}); + } else { + throw parse_error("unexpected error: undefined binary operator", std::vector{n.begin()}); + } +} + +} // namespace language diff --git a/src/language/ASTNodeBinaryOperatorExpressionBuilder.hpp b/src/language/ASTNodeBinaryOperatorExpressionBuilder.hpp new file mode 100644 index 000000000..ac1ceae20 --- /dev/null +++ b/src/language/ASTNodeBinaryOperatorExpressionBuilder.hpp @@ -0,0 +1,11 @@ +#ifndef AST_NODE_BINARY_OPERATOR_EXPRESSION_BUILDER_HPP +#define AST_NODE_BINARY_OPERATOR_EXPRESSION_BUILDER_HPP + +#include <ASTNode.hpp> + +namespace language +{ +void set_binary_operator_processor(Node& node); +} // namespace language + +#endif // AST_NODE_BINARY_OPERATOR_EXPRESSION_BUILDER_HPP diff --git a/src/language/ASTNodeDataType.cpp b/src/language/ASTNodeDataType.cpp new file mode 100644 index 000000000..33d809c33 --- /dev/null +++ b/src/language/ASTNodeDataType.cpp @@ -0,0 +1,48 @@ +#include <ASTNodeDataType.hpp> + +namespace language +{ +std::string +dataTypeName(const DataType& data_type) +{ + std::string name; + switch (data_type) { + case DataType::undefined_t: + name = "undefined"; + break; + case DataType::bool_t: + name = "B"; + break; + case DataType::unsigned_int_t: + name = "N"; + break; + case DataType::int_t: + name = "Z"; + break; + case DataType::double_t: + name = "R"; + break; + case DataType::typename_t: + name = "typename"; + break; + case DataType::void_t: + name = "void"; + break; + } + return name; +} + +DataType +dataTypePromotion(const DataType& data_type_1, const DataType& data_type_2) +{ + if (data_type_1 == data_type_2) { + return data_type_1; + } else if ((std::max(data_type_1, data_type_2) <= DataType::double_t) and + (std::min(data_type_1, data_type_2) >= DataType::bool_t)) { + return std::max(data_type_1, data_type_2); + } else { + return DataType::undefined_t; + } +} + +} // namespace language diff --git a/src/language/ASTNodeDataType.hpp b/src/language/ASTNodeDataType.hpp new file mode 100644 index 000000000..51a668184 --- /dev/null +++ b/src/language/ASTNodeDataType.hpp @@ -0,0 +1,28 @@ +#ifndef AST_NODE_DATATYPE_HPP +#define AST_NODE_DATATYPE_HPP + +#include <string> +#include <variant> + +namespace language +{ +enum class DataType +{ + undefined_t = -1, + bool_t = 0, + unsigned_int_t = 1, + int_t = 2, + double_t = 3, + typename_t = 10, + void_t = 9999 +}; + +std::string dataTypeName(const DataType& data_type); + +DataType dataTypePromotion(const DataType& data_type_1, const DataType& data_type_2); + +using DataVariant = std::variant<std::monostate, bool, uint64_t, int64_t, double>; + +} // namespace language + +#endif // AST_NODE_DATATYPE_HPP diff --git a/src/language/ASTNodeExpressionBuilder.cpp b/src/language/ASTNodeExpressionBuilder.cpp new file mode 100644 index 000000000..6101a778c --- /dev/null +++ b/src/language/ASTNodeExpressionBuilder.cpp @@ -0,0 +1,613 @@ +#include <ASTNodeExpressionBuilder.hpp> + +#include <ASTNodeAffectationExpressionBuilder.hpp> +#include <ASTNodeBinaryOperatorExpressionBuilder.hpp> + +#include <PEGGrammar.hpp> +#include <SymbolTable.hpp> + +namespace language +{ +class NodeList final : public INodeProcessor +{ + Node& m_node; + + public: + NodeList(Node& node) : m_node{node} {} + + void + execute(ExecUntilBreakOrContinue& exec_policy) + { + for (auto& child : m_node.children) { + child->execute(exec_policy); + } + } +}; + +class NoProcess final : public INodeProcessor +{ + public: + NoProcess() {} + + PUGS_INLINE + void + execute(ExecUntilBreakOrContinue&) + { + ; + } +}; + +template <typename Op> +struct UnaryOp; + +template <> +struct UnaryOp<language::unary_minus> +{ + template <typename A> + PUGS_INLINE A + eval(const A& a) + { + return -a; + } +}; + +template <> +struct UnaryOp<language::unary_not> +{ + template <typename A> + PUGS_INLINE bool + eval(const A& a) + { + return not a; + } +}; + +template <typename UnaryOpT, typename ValueT, typename DataT> +class UnaryExpressionProcessor final : public INodeProcessor +{ + Node& m_node; + + public: + PUGS_INLINE ValueT + eval(const DataVariant& a) + { + return UnaryOp<UnaryOpT>().eval(std::get<DataT>(a)); + } + + public: + UnaryExpressionProcessor(Node& node) : m_node{node} {} + + void + execute(ExecUntilBreakOrContinue& exec_policy) + { + m_node.children[0]->execute(exec_policy); + m_node.m_value = eval(m_node.children[0]->m_value); + } +}; + +template <typename Op> +struct IncDecOp; + +template <> +struct IncDecOp<language::unary_minusminus> +{ + template <typename A> + PUGS_INLINE A + eval(A& a) + { + return --a; + } +}; + +template <> +struct IncDecOp<language::unary_plusplus> +{ + template <typename A> + PUGS_INLINE A + eval(A& a) + { + return ++a; + } +}; + +template <> +struct IncDecOp<language::post_minusminus> +{ + template <typename A> + PUGS_INLINE A + eval(A& a) + { + return a--; + } +}; + +template <> +struct IncDecOp<language::post_plusplus> +{ + template <typename A> + PUGS_INLINE A + eval(A& a) + { + return a++; + } +}; + +template <typename IncDecOpT, typename ValueT, typename DataT> +class IncDecExpressionProcessor final : public INodeProcessor +{ + Node& m_node; + DataVariant* p_value{nullptr}; + + static inline const bool _is_defined{[] { + if constexpr (std::is_same_v<IncDecOpT, language::unary_minusminus> or + std::is_same_v<IncDecOpT, language::unary_plusplus> or + std::is_same_v<IncDecOpT, language::post_minusminus> or + std::is_same_v<IncDecOpT, language::post_plusplus>) { + return not std::is_same_v<std::decay_t<DataT>, bool>; + } + return true; + }()}; + + public: + IncDecExpressionProcessor(Node& node) : m_node{node} + { + if constexpr (_is_defined) { + Assert(m_node.children[0]->is<language::name>()); + // It is sure at this point that children 0 is a variable name + const std::string& symbol = m_node.children[0]->string(); + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol); + Assert(found); + p_value = &i_symbol->second.value(); + } else { + throw parse_error("invalid operand to unary operator", std::vector{m_node.begin()}); + } + } + void + execute(ExecUntilBreakOrContinue&) + { + if constexpr (_is_defined) { + m_node.m_value = IncDecOp<IncDecOpT>().eval(std::get<DataT>(*p_value)); + } + } +}; + +class IfStatement final : public INodeProcessor +{ + Node& m_node; + + public: + IfStatement(Node& node) : m_node{node} {} + + void + execute(ExecUntilBreakOrContinue& exec_policy) + { + m_node.children[0]->execute(exec_policy); + const bool is_true = static_cast<bool>(std::visit( + [](const auto& value) -> bool { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_same_v<T, std::monostate>) { + return false; + } else { + return value; + } + }, + m_node.children[0]->m_value)); + if (is_true) { + Assert(m_node.children[1] != nullptr); + m_node.children[1]->execute(exec_policy); + } else { + if (m_node.children.size() == 3) { + // else statement + Assert(m_node.children[2] != nullptr); + m_node.children[2]->execute(exec_policy); + } + } + } +}; + +class DoWhileStatement final : public INodeProcessor +{ + Node& m_node; + + public: + DoWhileStatement(Node& node) : m_node{node} {} + + void + execute(ExecUntilBreakOrContinue& exec_policy) + { + bool continuation_test = true; + ExecUntilBreakOrContinue exec_until_jump; + do { + m_node.children[0]->execute(exec_until_jump); + if (not exec_until_jump.exec()) { + if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::break_jump) { + break; + } else if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::continue_jump) { + exec_until_jump = ExecUntilBreakOrContinue{}; // getting ready for next loop traversal + } + } + m_node.children[1]->execute(exec_policy); + continuation_test = static_cast<bool>(std::visit( + [](const auto& value) -> bool { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_same_v<T, std::monostate>) { + return false; + } else { + return value; + } + }, + m_node.children[1]->m_value)); + } while (continuation_test); + } +}; + +class WhileStatement final : public INodeProcessor +{ + Node& m_node; + + public: + WhileStatement(Node& node) : m_node{node} {} + + void + execute(ExecUntilBreakOrContinue& exec_policy) + { + ExecUntilBreakOrContinue exec_until_jump; + while ([&]() { + m_node.children[0]->execute(exec_policy); + return static_cast<bool>(std::visit( + [](const auto& value) -> bool { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_same_v<T, std::monostate>) { + return false; + } else { + return value; + } + }, + m_node.children[0]->m_value)); + }()) { + m_node.children[1]->execute(exec_until_jump); + if (not exec_until_jump.exec()) { + if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::break_jump) { + break; + } else if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::continue_jump) { + exec_until_jump = ExecUntilBreakOrContinue{}; // getting ready for next loop traversal + } + } + } + } +}; + +class ForStatement final : public INodeProcessor +{ + Node& m_node; + + public: + ForStatement(Node& node) : m_node{node} {} + + void + execute(ExecUntilBreakOrContinue& exec_policy) + { + ExecUntilBreakOrContinue exec_until_jump; + m_node.children[0]->execute(exec_policy); + while ([&]() { + m_node.children[1]->execute(exec_policy); + return static_cast<bool>(std::visit( + [](const auto& value) -> bool { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_same_v<T, std::monostate>) { + return false; + } else { + return value; + } + }, + m_node.children[1]->m_value)); + }()) { + m_node.children[3]->execute(exec_until_jump); + if (not exec_until_jump.exec()) { + if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::break_jump) { + break; + } else if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::continue_jump) { + exec_until_jump = ExecUntilBreakOrContinue{}; // getting ready for next loop traversal + } + } + + m_node.children[2]->execute(exec_policy); + } + } +}; + +class NameExpression final : public INodeProcessor +{ + Node& m_node; + DataVariant* p_value{nullptr}; + + public: + NameExpression(Node& node) : m_node{node} + { + const std::string& symbol = m_node.string(); + auto [i_symbol, found] = m_node.m_symbol_table->find(symbol); + Assert(found); + p_value = &(i_symbol->second.value()); + } + + void + execute(ExecUntilBreakOrContinue&) + { + m_node.m_value = *p_value; + } +}; + +class BreakExpression final : public INodeProcessor +{ + public: + BreakExpression() {} + + void + execute(ExecUntilBreakOrContinue& exec_policy) + { + exec_policy = ExecUntilBreakOrContinue(ExecUntilBreakOrContinue::JumpType::break_jump); + } +}; + +class ContinueExpression final : public INodeProcessor +{ + public: + ContinueExpression() {} + + void + execute(ExecUntilBreakOrContinue& exec_policy) + { + exec_policy = ExecUntilBreakOrContinue(ExecUntilBreakOrContinue::JumpType::continue_jump); + } +}; + +class OStreamObject final : public INodeProcessor +{ + Node& m_node; + std::ostream& m_os; + + public: + OStreamObject(Node& node, std::ostream& os) : m_node{node}, m_os(os) + { + ; + } + + void + execute(ExecUntilBreakOrContinue& exec_policy) + { + for (size_t i = 0; i < m_node.children.size(); ++i) { + m_node.children[i]->execute(exec_policy); + std::visit( + [&](auto&& value) { + using ValueT = std::decay_t<decltype(value)>; + if constexpr (not std::is_same_v<std::monostate, ValueT>) { + if constexpr (std::is_same_v<bool, ValueT>) { + m_os << std::boolalpha << value; + } else { + m_os << value; + } + } + }, + m_node.children[i]->m_value); + } + } +}; + +namespace internal +{ +void +build_node_type(Node& n) +{ + auto set_unary_operator_processor = [](Node& n, const auto& operator_v) { + auto set_unary_operator_processor_for_data = [&](const auto& value, const DataType& data_type) { + using OperatorT = std::decay_t<decltype(operator_v)>; + using ValueT = std::decay_t<decltype(value)>; + switch (data_type) { + case DataType::bool_t: { + n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, bool>>(n); + break; + } + case DataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, uint64_t>>(n); + break; + } + case DataType::int_t: { + n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, int64_t>>(n); + break; + } + case DataType::double_t: { + n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, double>>(n); + break; + } + default: { + throw parse_error("undefined operand type for unary operator", std::vector{n.children[0]->begin()}); + } + } + }; + + auto set_unary_operator_processor_for_value = [&](const DataType& value_type) { + const DataType data_type = n.children[0]->m_data_type; + switch (value_type) { + case DataType::bool_t: { + set_unary_operator_processor_for_data(bool{}, data_type); + break; + } + case DataType::unsigned_int_t: { + set_unary_operator_processor_for_data(uint64_t{}, data_type); + break; + } + case DataType::int_t: { + set_unary_operator_processor_for_data(int64_t{}, data_type); + break; + } + case DataType::double_t: { + set_unary_operator_processor_for_data(double{}, data_type); + break; + } + default: { + throw parse_error("undefined value type for unary operator", std::vector{n.begin()}); + } + } + }; + + set_unary_operator_processor_for_value(n.m_data_type); + }; + + auto set_inc_dec_operator_processor = [](Node& n, const auto& operator_v) { + auto set_inc_dec_operator_processor_for_data = [&](const auto& value, const DataType& data_type) { + using OperatorT = std::decay_t<decltype(operator_v)>; + using ValueT = std::decay_t<decltype(value)>; + switch (data_type) { + case DataType::bool_t: { + n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, bool>>(n); + break; + } + case DataType::unsigned_int_t: { + n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, uint64_t>>(n); + break; + } + case DataType::int_t: { + n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, int64_t>>(n); + break; + } + case DataType::double_t: { + n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, double>>(n); + break; + } + default: { + throw parse_error("undefined operand type for unary operator", std::vector{n.children[0]->begin()}); + } + } + }; + + auto set_inc_dec_processor_for_value = [&](const DataType& value_type) { + const DataType data_type = n.children[0]->m_data_type; + switch (value_type) { + case DataType::bool_t: { + set_inc_dec_operator_processor_for_data(bool{}, data_type); + break; + } + case DataType::unsigned_int_t: { + set_inc_dec_operator_processor_for_data(uint64_t{}, data_type); + break; + } + case DataType::int_t: { + set_inc_dec_operator_processor_for_data(int64_t{}, data_type); + break; + } + case DataType::double_t: { + set_inc_dec_operator_processor_for_data(double{}, data_type); + break; + } + default: { + throw parse_error("undefined value type for unary operator", std::vector{n.begin()}); + } + } + }; + + if (not n.children[0]->is<language::name>()) { + throw parse_error("invalid operand type for unary operator", std::vector{n.begin()}); + } + + set_inc_dec_processor_for_value(n.m_data_type); + }; + + if (n.is_root() or n.is<language::bloc>()) { + n.m_node_processor = std::make_unique<NodeList>(n); + } else if (n.is<language::declaration>()) { + n.m_node_processor = std::make_unique<NoProcess>(); + + } else if ((n.is<language::eq_op>() or n.is<language::multiplyeq_op>() or n.is<language::divideeq_op>() or + n.is<language::pluseq_op>() or n.is<language::minuseq_op>() or n.is<language::bit_andeq_op>() or + n.is<language::bit_xoreq_op>() or n.is<language::bit_oreq_op>())) { + set_affectation_processor(n); + + } else if (n.is<language::real>()) { + n.m_node_processor = std::make_unique<NoProcess>(); + } else if (n.is<language::integer>()) { + n.m_node_processor = std::make_unique<NoProcess>(); + + } else if (n.is<language::name>()) { + n.m_node_processor = std::make_unique<NameExpression>(n); + + } else if (n.is<language::unary_minus>()) { + set_unary_operator_processor(n, language::unary_minus{}); + } else if (n.is<language::unary_not>()) { + set_unary_operator_processor(n, language::unary_not{}); + + } else if (n.is<language::unary_minusminus>()) { + set_inc_dec_operator_processor(n, language::unary_minusminus{}); + } else if (n.is<language::unary_plusplus>()) { + set_inc_dec_operator_processor(n, language::unary_plusplus{}); + } else if (n.is<language::post_minusminus>()) { + set_inc_dec_operator_processor(n, language::post_minusminus{}); + } else if (n.is<language::post_plusplus>()) { + set_inc_dec_operator_processor(n, language::post_plusplus{}); + + } else if (n.is<language::multiply_op>() or n.is<language::divide_op>() or n.is<language::plus_op>() or + n.is<language::minus_op>() or n.is<language::or_op>() or n.is<language::and_op>() or + n.is<language::xor_op>() or n.is<language::bitand_op>() or n.is<language::bitor_op>() or + n.is<language::greater_op>() or n.is<language::greater_or_eq_op>() or n.is<language::lesser_op>() or + n.is<language::lesser_or_eq_op>() or n.is<language::eqeq_op>() or n.is<language::not_eq_op>()) { + set_binary_operator_processor(n); + + } else if (n.is<language::B_set>()) { + } else if (n.is<language::N_set>()) { + } else if (n.is<language::Z_set>()) { + } else if (n.is<language::cout_kw>()) { + n.m_node_processor = std::make_unique<OStreamObject>(n, std::cout); + } else if (n.is<language::cerr_kw>()) { + n.m_node_processor = std::make_unique<OStreamObject>(n, std::cerr); + } else if (n.is<language::clog_kw>()) { + n.m_node_processor = std::make_unique<OStreamObject>(n, std::clog); + } else if (n.is<language::R_set>()) { + } else if (n.is<language::if_statement>()) { + n.m_node_processor = std::make_unique<IfStatement>(n); + } else if (n.is<language::statement_bloc>()) { + n.m_node_processor = std::make_unique<NodeList>(n); + } else if (n.is<language::do_while_statement>()) { + n.m_node_processor = std::make_unique<DoWhileStatement>(n); + } else if (n.is<language::while_statement>()) { + n.m_node_processor = std::make_unique<WhileStatement>(n); + } else if (n.is<language::for_statement>()) { + n.m_node_processor = std::make_unique<ForStatement>(n); + } else if (n.is<language::for_statement_bloc>()) { + n.m_node_processor = std::make_unique<NodeList>(n); + } else if (n.is<language::for_init>()) { + n.m_node_processor = std::make_unique<NoProcess>(); + } else if (n.is<language::for_post>()) { + n.m_node_processor = std::make_unique<NoProcess>(); + } else if (n.is<language::for_test>()) { + n.m_node_processor = std::make_unique<NoProcess>(); + } else if (n.is<language::break_kw>()) { + n.m_node_processor = std::make_unique<BreakExpression>(); + } else if (n.is<language::continue_kw>()) { + n.m_node_processor = std::make_unique<ContinueExpression>(); + } else if (n.is<language::true_kw>()) { + n.m_node_processor = std::make_unique<NoProcess>(); + } else if (n.is<language::false_kw>()) { + n.m_node_processor = std::make_unique<NoProcess>(); + } else { + std::ostringstream error_message; + error_message << "undefined node type '" << rang::fgB::red << n.name() << rang::fg::reset << "'"; + throw parse_error{error_message.str(), std::vector{n.begin()}}; + } + + for (auto& child : n.children) { + internal::build_node_type(*child); + } +} +} // namespace internal + +void +build_node_type(Node& n) +{ + Assert(n.is_root()); + Assert(n.is<void>()); + n.m_node_processor = std::make_unique<NodeList>(n); + for (auto& child : n.children) { + internal::build_node_type(*child); + } + std::cout << " - build node types\n"; +} +} // namespace language diff --git a/src/language/ASTNodeExpressionBuilder.hpp b/src/language/ASTNodeExpressionBuilder.hpp new file mode 100644 index 000000000..4dc02c93b --- /dev/null +++ b/src/language/ASTNodeExpressionBuilder.hpp @@ -0,0 +1,11 @@ +#ifndef AST_NODE_EXPRESSION_BUILDER_HPP +#define AST_NODE_EXPRESSION_BUILDER_HPP + +#include <ASTNode.hpp> + +namespace language +{ +void build_node_type(Node& n); +} + +#endif // AST_NODE_EXPRESSION_BUILDER_HPP diff --git a/src/language/CMakeLists.txt b/src/language/CMakeLists.txt index 2a9e7547f..8436a645f 100644 --- a/src/language/CMakeLists.txt +++ b/src/language/CMakeLists.txt @@ -5,6 +5,11 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_library( PugsLanguage + ASTBuilder.cpp + ASTNodeDataType.cpp + ASTNodeAffectationExpressionBuilder.cpp + ASTNodeBinaryOperatorExpressionBuilder.cpp + ASTNodeExpressionBuilder.cpp PugsParser.cpp) #include_directories(${PUGS_SOURCE_DIR}/utils) diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp new file mode 100644 index 000000000..e4c8a55af --- /dev/null +++ b/src/language/PEGGrammar.hpp @@ -0,0 +1,331 @@ +#ifndef PEG_GRAMMAR_HPP +#define PEG_GRAMMAR_HPP + +#include <pegtl.hpp> + +using namespace TAO_PEGTL_NAMESPACE; + +namespace language +{ +// clang-format off + +struct slashslash : TAO_PEGTL_STRING("//") {}; +struct slashstar : TAO_PEGTL_STRING("/*") {}; +struct starslash : TAO_PEGTL_STRING("*/") {}; + +struct comment + : sor< if_must< slashslash, until< eolf > >, + try_catch< slashstar, until< starslash> >, + // error management + if_must<at<slashstar>,raise<slashstar>, until< eof> > > {}; + +struct ignored : star< sor< space, comment> >{}; + +struct integer + : plus< digit > {}; +struct INTEGER : seq< integer, ignored >{}; + +struct real + : seq< sor< seq< + plus< digit >, + one < '.' >, + star< digit > + >, + seq< + one < '.' >, + plus< digit > + > + >, + opt< + seq< + one< 'E', + 'e' >, + opt< one< '+', + '-' > + >, + plus<digit> + > + > + >{}; + +struct semicol : one< ';' >{}; + +struct REAL : seq< real, ignored >{}; + +struct B_set : one< 'B' >{}; +struct N_set : one< 'N' >{}; +struct Z_set : one< 'Z' >{}; +struct R_set : one< 'R' >{}; + +struct basic_type : sor < B_set, R_set, Z_set, N_set > {}; + +struct TYPESPECIFIER : seq< basic_type, ignored> {}; + +struct and_kw : TAO_PEGTL_KEYWORD("and") {}; +struct or_kw : TAO_PEGTL_KEYWORD("or") {}; + +struct xor_kw : TAO_PEGTL_KEYWORD("xor") {}; +struct bitand_kw : TAO_PEGTL_KEYWORD("bitand") {}; +struct bitor_kw : TAO_PEGTL_KEYWORD("bitor") {}; + +struct and_eq_kw : TAO_PEGTL_KEYWORD("and_eq") {}; +struct xor_eq_kw : TAO_PEGTL_KEYWORD("xor_eq") {}; +struct or_eq_kw : TAO_PEGTL_KEYWORD("or_eq") {}; + +struct not_kw : TAO_PEGTL_KEYWORD("not") {}; +struct true_kw : TAO_PEGTL_KEYWORD("true") {}; +struct false_kw : TAO_PEGTL_KEYWORD("false") {}; + +struct BOOL : seq< sor<true_kw, false_kw>, ignored > {}; + +struct do_kw : TAO_PEGTL_KEYWORD("do") {}; +struct DO : seq < do_kw, ignored > {}; + +struct while_kw : TAO_PEGTL_KEYWORD("while") {}; +struct WHILE : seq < while_kw, ignored > {}; + +struct for_kw : TAO_PEGTL_KEYWORD("for") {}; +struct FOR : seq < for_kw, ignored > {}; + +struct if_kw : TAO_PEGTL_KEYWORD("if") {}; +struct IF : seq < if_kw, ignored > {}; + +struct else_kw : TAO_PEGTL_KEYWORD("else") {}; +struct ELSE : seq < else_kw, ignored > {}; + +struct break_kw : TAO_PEGTL_KEYWORD("break") {}; +struct BREAK : seq < break_kw, ignored > {}; + +struct continue_kw : TAO_PEGTL_KEYWORD("continue") {}; +struct CONTINUE : seq < continue_kw, ignored > {}; + +struct cout_kw : TAO_PEGTL_KEYWORD("cout") {}; +struct cerr_kw : TAO_PEGTL_KEYWORD("cerr") {}; +struct clog_kw : TAO_PEGTL_KEYWORD("clog") {}; + +struct keywork : sor < basic_type, true_kw, false_kw, do_kw, while_kw, for_kw, if_kw, else_kw, and_kw, or_kw, xor_kw, bitand_kw, bitor_kw, and_eq_kw, xor_eq_kw, or_eq_kw, break_kw, continue_kw, cout_kw, cerr_kw, clog_kw > {}; + +struct name : minus< identifier, keywork > {}; +struct NAME : seq < name, ignored > {}; + +struct SEMICOL : seq< semicol , ignored > {}; + +struct open_parent : seq< one< '(' >, ignored > {}; +struct close_parent : seq< one< ')' >, ignored > {}; + +struct expression; +struct parented_expression : if_must< open_parent, expression, close_parent > {}; + +struct primary_expression : sor< BOOL, REAL, INTEGER , NAME, parented_expression > {}; + +struct unary_plusplus : TAO_PEGTL_STRING("++") {}; +struct unary_minusminus : TAO_PEGTL_STRING("--") {}; + +struct unary_plus : one< '+' > {}; +struct unary_minus : one< '-' > {}; + +struct unary_not : sor< one< '!'> , not_kw > {}; + +struct unary_operator : seq< sor< unary_plusplus, unary_minusminus, unary_plus, unary_minus, unary_not>, ignored > {}; + +struct post_plusplus : TAO_PEGTL_STRING("++") {}; +struct post_minusminus : TAO_PEGTL_STRING("--") {}; + +struct postfix_operator : seq< sor< post_plusplus, post_minusminus>, ignored > {}; + +struct postfix_expression : seq< primary_expression, star<postfix_operator> > {}; + +struct unary_expression : sor< seq< unary_operator, unary_expression >, + postfix_expression > {}; + +struct and_op : seq< sor<TAO_PEGTL_STRING("&&"), and_kw>, ignored > {}; +struct or_op : seq< sor<TAO_PEGTL_STRING("||"), or_kw>, ignored > {}; + +struct xor_op : seq< sor< one< '^' >, xor_kw>, ignored >{}; +struct bitand_op : seq< sor< seq< one< '&' >, not_at< one< '&' > > >, bitand_kw>, ignored >{}; +struct bitor_op : seq< sor< seq< one< '|' >, not_at< one< '|' > > >, bitor_kw>, ignored >{}; + +struct eqeq_op : seq< TAO_PEGTL_STRING("=="), ignored > {}; +struct not_eq_op : seq< TAO_PEGTL_STRING("!="), ignored > {}; + +struct lesser_op : seq< one< '<' >, not_at< one< '<' > >, ignored > {}; +struct lesser_or_eq_op : seq< TAO_PEGTL_STRING("<="), ignored > {}; +struct greater_op : seq< one< '>' >, not_at< one< '>' > >, ignored > {}; +struct greater_or_eq_op : seq< TAO_PEGTL_STRING(">="), ignored > {}; + +struct shift_left_op : seq< TAO_PEGTL_STRING("<<"), ignored > {}; +struct shift_right_op : seq< TAO_PEGTL_STRING(">>"), ignored > {}; + +struct plus_op : seq< one< '+' >, not_at< one< '+' > >, ignored > {}; +struct minus_op : seq< one< '-' >, not_at< one< '-' > >, ignored > {}; +struct multiply_op : seq< one< '*' >, ignored > {}; +struct divide_op : seq< one< '/' >, ignored > {}; + +struct eq_op : seq< one<'='>, not_at< one< '=' > >, ignored > {}; +struct multiplyeq_op : seq< TAO_PEGTL_STRING("*="), ignored > {}; +struct divideeq_op : seq< TAO_PEGTL_STRING("/="), ignored > {}; +struct pluseq_op : seq< TAO_PEGTL_STRING("+="), ignored > {}; +struct minuseq_op : seq< TAO_PEGTL_STRING("-="), ignored > {}; + +struct bit_andeq_op : seq< sor< TAO_PEGTL_STRING("&="), and_eq_kw >, ignored > {}; +struct bit_xoreq_op : seq< sor< TAO_PEGTL_STRING("^="), xor_eq_kw >, ignored > {}; +struct bit_oreq_op : seq< sor< TAO_PEGTL_STRING("|="), or_eq_kw >, ignored > {}; + +struct product : list_must< unary_expression, sor< multiply_op, divide_op > > {}; + +struct sum : list_must< product, sor< plus_op, minus_op > > {}; + +struct compare : list_must<sum, sor< lesser_or_eq_op, greater_or_eq_op, lesser_op, greater_op > >{}; + +struct equality : list_must< compare, sor< eqeq_op, not_eq_op > >{}; + +struct bitwise_and : list_must < equality, bitand_op >{}; + +struct bitwise_xor : list_must< bitwise_and, xor_op >{}; + +struct bitwise_or : list_must< bitwise_xor, bitor_op >{}; + +struct logical_and : list_must< bitwise_or, and_op >{}; + +struct logical_or : list_must< logical_and, or_op >{}; + +struct expression : logical_or {}; + +struct affect_op : sor< eq_op, multiplyeq_op, divideeq_op, pluseq_op, minuseq_op, bit_andeq_op, + bit_xoreq_op, bit_oreq_op > {}; + +struct affectation : seq< NAME , if_must< affect_op, expression > >{}; + +struct declaration : if_must<TYPESPECIFIER, NAME, opt<if_must<seq<one<'='>,ignored>, expression>> >{}; + +struct open_brace : seq< one< '{' >, ignored >{}; +struct close_brace : seq< one< '}' >, ignored >{}; + +struct instruction_list; + +struct braced_instruction_list + : sor<try_catch< open_brace, instruction_list, close_brace >, + // non matching braces management + if_must< at< one< '{' > >, raise<open_brace>, until<eof> > >{}; + +struct bloc : braced_instruction_list {}; + +struct statement_bloc; + +struct if_statement : if_must< IF, parented_expression, statement_bloc, opt< if_must<ELSE, statement_bloc > > >{}; + +struct do_while_statement : if_must< DO, statement_bloc, WHILE, parented_expression >{}; + +struct while_statement : if_must< WHILE, parented_expression, statement_bloc >{}; + +struct for_init : opt< sor< declaration, affectation, expression > >{}; +struct for_test : opt< sor< affectation, expression > >{}; +struct for_post : opt< sor< affectation, expression > >{}; + +struct for_statement_bloc; + +struct for_statement : if_must< FOR, open_parent, for_init, SEMICOL, for_test, SEMICOL, for_post, close_parent, for_statement_bloc >{}; + +struct ostream_object : seq< sor< cout_kw, cerr_kw, clog_kw >, ignored >{}; +struct ostream_statement : seq< ostream_object, star< if_must< shift_left_op, expression, ignored > > >{}; + +struct instruction + : sor<if_must< declaration, semicol >, + if_must< affectation, semicol >, + if_statement, + if_must<do_while_statement, semicol>, + while_statement, + for_statement, + if_must< ostream_statement, semicol >, + if_must< BREAK, semicol >, + if_must< CONTINUE, semicol >, + if_must< expression, semicol >, + bloc, + semicol> +{}; + +struct INSTRUCTION : seq<instruction, ignored> {}; +struct statement_bloc : seq< sor< bloc, instruction >, ignored >{}; + +struct for_statement_bloc : seq< sor< braced_instruction_list, + instruction >, + ignored >{}; + +struct instruction_list : star< INSTRUCTION >{}; +struct grammar : must<ignored, instruction_list, eof>{}; + +template <typename Rule> +struct errors : public normal<Rule> +{ + static const std::string error_message; + + template <typename Input, typename... States> + static void + raise(const Input& in, States&&... /*unused*/) + { + throw parse_error(error_message, std::vector{in.position()}); + } +}; + +template <typename Rule> +inline const std::string errors<Rule>::error_message = "parse error matching "+ internal::demangle< Rule >(); + +template <> +inline const std::string errors<language::semicol>::error_message = "parse error, missing ';'"; +template <> +inline const std::string errors<language::SEMICOL>::error_message = "parse error, missing ';'"; + +template <> +inline const std::string errors<language::name>::error_message = "parse error, missing identifier"; +template <> +inline const std::string errors<language::NAME>::error_message = "parse error, missing identifier"; + +template <> +inline const std::string errors<language::expression>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::product>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::sum>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::compare>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::equality>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::bitwise_and>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::bitwise_xor>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::bitwise_or>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::logical_and>::error_message = "parse error, missing expression"; +template <> +inline const std::string errors<language::logical_or>::error_message = "parse error, missing expression"; + +template <> +inline const std::string errors<language::parented_expression>::error_message = "parse error, missing parented expression"; + +template <> +inline const std::string errors<language::statement_bloc>::error_message = "parse error, missing instruction"; + +template <> +inline const std::string errors<language::WHILE>::error_message = "parse error, missing 'while' statement"; +template <> +inline const std::string errors<language::while_kw>::error_message = "parse error, missing 'while' statement"; + +template <> +inline const std::string errors<language::open_parent>::error_message = "parse error, missing open parent '('"; + +template <> +inline const std::string errors<language::for_statement_bloc>::error_message = "parse error, missing for-loop body"; + +template <> +inline const std::string errors<language::slashstar>::error_message = "bloc comment was never terminated, missing '*/'"; + +template <> +inline const std::string errors<language::open_brace>::error_message = "open brace was never closed, missing '}'"; + +// clang-format on + +} // namespace language + +#endif // PEG_GRAMMAR_HPP diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp index ff0c37f6d..092ff2bd0 100644 --- a/src/language/PugsParser.cpp +++ b/src/language/PugsParser.cpp @@ -9,1979 +9,20 @@ #include <rang.hpp> -#include <pegtl.hpp> #include <pegtl/analyze.hpp> #include <pegtl/contrib/parse_tree.hpp> #include <pegtl/contrib/parse_tree_to_dot.hpp> -using namespace TAO_PEGTL_NAMESPACE; +#include <ASTNode.hpp> -namespace language -{ -// clang-format off - -struct slashslash : TAO_PEGTL_STRING("//") {}; -struct slashstar : TAO_PEGTL_STRING("/*") {}; -struct starslash : TAO_PEGTL_STRING("*/") {}; - -struct comment - : sor< if_must< slashslash, until< eolf > >, - try_catch< slashstar, until< starslash> >, - // error management - if_must<at<slashstar>,raise<slashstar>, until< eof> > > {}; - -struct ignored : star< sor< space, comment> >{}; - -struct integer - : plus< digit > {}; -struct INTEGER : seq< integer, ignored >{}; - -struct real - : seq< sor< seq< - plus< digit >, - one < '.' >, - star< digit > - >, - seq< - one < '.' >, - plus< digit > - > - >, - opt< - seq< - one< 'E', - 'e' >, - opt< one< '+', - '-' > - >, - plus<digit> - > - > - >{}; - -struct semicol : one< ';' >{}; - -struct REAL : seq< real, ignored >{}; - -struct B_set : one< 'B' >{}; -struct N_set : one< 'N' >{}; -struct Z_set : one< 'Z' >{}; -struct R_set : one< 'R' >{}; - -struct basic_type : sor < B_set, R_set, Z_set, N_set > {}; - -struct TYPESPECIFIER : seq< basic_type, ignored> {}; - -struct and_kw : TAO_PEGTL_KEYWORD("and") {}; -struct or_kw : TAO_PEGTL_KEYWORD("or") {}; - -struct xor_kw : TAO_PEGTL_KEYWORD("xor") {}; -struct bitand_kw : TAO_PEGTL_KEYWORD("bitand") {}; -struct bitor_kw : TAO_PEGTL_KEYWORD("bitor") {}; - -struct and_eq_kw : TAO_PEGTL_KEYWORD("and_eq") {}; -struct xor_eq_kw : TAO_PEGTL_KEYWORD("xor_eq") {}; -struct or_eq_kw : TAO_PEGTL_KEYWORD("or_eq") {}; - -struct not_kw : TAO_PEGTL_KEYWORD("not") {}; -struct true_kw : TAO_PEGTL_KEYWORD("true") {}; -struct false_kw : TAO_PEGTL_KEYWORD("false") {}; - -struct BOOL : seq< sor<true_kw, false_kw>, ignored > {}; - -struct do_kw : TAO_PEGTL_KEYWORD("do") {}; -struct DO : seq < do_kw, ignored > {}; - -struct while_kw : TAO_PEGTL_KEYWORD("while") {}; -struct WHILE : seq < while_kw, ignored > {}; - -struct for_kw : TAO_PEGTL_KEYWORD("for") {}; -struct FOR : seq < for_kw, ignored > {}; - -struct if_kw : TAO_PEGTL_KEYWORD("if") {}; -struct IF : seq < if_kw, ignored > {}; - -struct else_kw : TAO_PEGTL_KEYWORD("else") {}; -struct ELSE : seq < else_kw, ignored > {}; - -struct break_kw : TAO_PEGTL_KEYWORD("break") {}; -struct BREAK : seq < break_kw, ignored > {}; - -struct continue_kw : TAO_PEGTL_KEYWORD("continue") {}; -struct CONTINUE : seq < continue_kw, ignored > {}; - -struct cout_kw : TAO_PEGTL_KEYWORD("cout") {}; -struct cerr_kw : TAO_PEGTL_KEYWORD("cerr") {}; -struct clog_kw : TAO_PEGTL_KEYWORD("clog") {}; - -struct keywork : sor < basic_type, true_kw, false_kw, do_kw, while_kw, for_kw, if_kw, else_kw, and_kw, or_kw, xor_kw, bitand_kw, bitor_kw, and_eq_kw, xor_eq_kw, or_eq_kw, break_kw, continue_kw, cout_kw, cerr_kw, clog_kw > {}; - -struct name : minus< identifier, keywork > {}; -struct NAME : seq < name, ignored > {}; - -struct SEMICOL : seq< semicol , ignored > {}; - -struct open_parent : seq< one< '(' >, ignored > {}; -struct close_parent : seq< one< ')' >, ignored > {}; - -struct expression; -struct parented_expression : if_must< open_parent, expression, close_parent > {}; - -struct primary_expression : sor< BOOL, REAL, INTEGER , NAME, parented_expression > {}; - -struct unary_plusplus : TAO_PEGTL_STRING("++") {}; -struct unary_minusminus : TAO_PEGTL_STRING("--") {}; - -struct unary_plus : one< '+' > {}; -struct unary_minus : one< '-' > {}; - -struct unary_not : sor< one< '!'> , not_kw > {}; - -struct unary_operator : seq< sor< unary_plusplus, unary_minusminus, unary_plus, unary_minus, unary_not>, ignored > {}; - -struct post_plusplus : TAO_PEGTL_STRING("++") {}; -struct post_minusminus : TAO_PEGTL_STRING("--") {}; - -struct postfix_operator : seq< sor< post_plusplus, post_minusminus>, ignored > {}; - -struct postfix_expression : seq< primary_expression, star<postfix_operator> > {}; - -struct unary_expression : sor< seq< unary_operator, unary_expression >, - postfix_expression > {}; - -struct and_op : seq< sor<TAO_PEGTL_STRING("&&"), and_kw>, ignored > {}; -struct or_op : seq< sor<TAO_PEGTL_STRING("||"), or_kw>, ignored > {}; - -struct xor_op : seq< sor< one< '^' >, xor_kw>, ignored >{}; -struct bitand_op : seq< sor< seq< one< '&' >, not_at< one< '&' > > >, bitand_kw>, ignored >{}; -struct bitor_op : seq< sor< seq< one< '|' >, not_at< one< '|' > > >, bitor_kw>, ignored >{}; - -struct eqeq_op : seq< TAO_PEGTL_STRING("=="), ignored > {}; -struct not_eq_op : seq< TAO_PEGTL_STRING("!="), ignored > {}; - -struct lesser_op : seq< one< '<' >, not_at< one< '<' > >, ignored > {}; -struct lesser_or_eq_op : seq< TAO_PEGTL_STRING("<="), ignored > {}; -struct greater_op : seq< one< '>' >, not_at< one< '>' > >, ignored > {}; -struct greater_or_eq_op : seq< TAO_PEGTL_STRING(">="), ignored > {}; - -struct shift_left_op : seq< TAO_PEGTL_STRING("<<"), ignored > {}; -struct shift_right_op : seq< TAO_PEGTL_STRING(">>"), ignored > {}; - -struct plus_op : seq< one< '+' >, not_at< one< '+' > >, ignored > {}; -struct minus_op : seq< one< '-' >, not_at< one< '-' > >, ignored > {}; -struct multiply_op : seq< one< '*' >, ignored > {}; -struct divide_op : seq< one< '/' >, ignored > {}; - -struct eq_op : seq< one<'='>, not_at< one< '=' > >, ignored > {}; -struct multiplyeq_op : seq< TAO_PEGTL_STRING("*="), ignored > {}; -struct divideeq_op : seq< TAO_PEGTL_STRING("/="), ignored > {}; -struct pluseq_op : seq< TAO_PEGTL_STRING("+="), ignored > {}; -struct minuseq_op : seq< TAO_PEGTL_STRING("-="), ignored > {}; - -struct bit_andeq_op : seq< sor< TAO_PEGTL_STRING("&="), and_eq_kw >, ignored > {}; -struct bit_xoreq_op : seq< sor< TAO_PEGTL_STRING("^="), xor_eq_kw >, ignored > {}; -struct bit_oreq_op : seq< sor< TAO_PEGTL_STRING("|="), or_eq_kw >, ignored > {}; - -struct product : list_must< unary_expression, sor< multiply_op, divide_op > > {}; - -struct sum : list_must< product, sor< plus_op, minus_op > > {}; - -struct compare : list_must<sum, sor< lesser_or_eq_op, greater_or_eq_op, lesser_op, greater_op > >{}; - -struct equality : list_must< compare, sor< eqeq_op, not_eq_op > >{}; - -struct bitwise_and : list_must < equality, bitand_op >{}; - -struct bitwise_xor : list_must< bitwise_and, xor_op >{}; - -struct bitwise_or : list_must< bitwise_xor, bitor_op >{}; - -struct logical_and : list_must< bitwise_or, and_op >{}; - -struct logical_or : list_must< logical_and, or_op >{}; - -struct expression : logical_or {}; - -struct affect_op : sor< eq_op, multiplyeq_op, divideeq_op, pluseq_op, minuseq_op, bit_andeq_op, - bit_xoreq_op, bit_oreq_op > {}; - -struct affectation : seq< NAME , if_must< affect_op, expression > >{}; - -struct declaration : if_must<TYPESPECIFIER, NAME, opt<if_must<seq<one<'='>,ignored>, expression>> >{}; - -struct open_brace : seq< one< '{' >, ignored >{}; -struct close_brace : seq< one< '}' >, ignored >{}; - -struct instruction_list; - -struct braced_instruction_list - : sor<try_catch< open_brace, instruction_list, close_brace >, - // non matching braces management - if_must< at< one< '{' > >, raise<open_brace>, until<eof> > >{}; - -struct bloc : braced_instruction_list {}; - -struct statement_bloc; - -struct if_statement : if_must< IF, parented_expression, statement_bloc, opt< if_must<ELSE, statement_bloc > > >{}; - -struct do_while_statement : if_must< DO, statement_bloc, WHILE, parented_expression >{}; - -struct while_statement : if_must< WHILE, parented_expression, statement_bloc >{}; - -struct for_init : opt< sor< declaration, affectation, expression > >{}; -struct for_test : opt< sor< affectation, expression > >{}; -struct for_post : opt< sor< affectation, expression > >{}; - -struct for_statement_bloc; - -struct for_statement : if_must< FOR, open_parent, for_init, SEMICOL, for_test, SEMICOL, for_post, close_parent, for_statement_bloc >{}; - -struct ostream_object : seq< sor< cout_kw, cerr_kw, clog_kw >, ignored >{}; -struct ostream_statement : seq< ostream_object, star< if_must< shift_left_op, expression, ignored > > >{}; - -struct instruction - : sor<if_must< declaration, semicol >, - if_must< affectation, semicol >, - if_statement, - if_must<do_while_statement, semicol>, - while_statement, - for_statement, - if_must< ostream_statement, semicol >, - if_must< BREAK, semicol >, - if_must< CONTINUE, semicol >, - if_must< expression, semicol >, - bloc, - semicol> -{}; - -struct INSTRUCTION : seq<instruction, ignored> {}; -struct statement_bloc : seq< sor< bloc, instruction >, ignored >{}; - -struct for_statement_bloc : seq< sor< braced_instruction_list, - instruction >, - ignored >{}; - -struct instruction_list : star< INSTRUCTION >{}; -struct grammar : must<ignored, instruction_list, eof>{}; - -template <typename Rule> -struct errors : public normal<Rule> -{ - static const std::string error_message; - - template <typename Input, typename... States> - static void - raise(const Input& in, States&&... /*unused*/) - { - throw parse_error(error_message, std::vector{in.position()}); - } -}; - -template <typename Rule> -inline const std::string errors<Rule>::error_message = "parse error matching "+ internal::demangle< Rule >(); - -template <> -inline const std::string errors<language::semicol>::error_message = "parse error, missing ';'"; -template <> -inline const std::string errors<language::SEMICOL>::error_message = "parse error, missing ';'"; - -template <> -inline const std::string errors<language::name>::error_message = "parse error, missing identifier"; -template <> -inline const std::string errors<language::NAME>::error_message = "parse error, missing identifier"; - -template <> -inline const std::string errors<language::expression>::error_message = "parse error, missing expression"; -template <> -inline const std::string errors<language::product>::error_message = "parse error, missing expression"; -template <> -inline const std::string errors<language::sum>::error_message = "parse error, missing expression"; -template <> -inline const std::string errors<language::compare>::error_message = "parse error, missing expression"; -template <> -inline const std::string errors<language::equality>::error_message = "parse error, missing expression"; -template <> -inline const std::string errors<language::bitwise_and>::error_message = "parse error, missing expression"; -template <> -inline const std::string errors<language::bitwise_xor>::error_message = "parse error, missing expression"; -template <> -inline const std::string errors<language::bitwise_or>::error_message = "parse error, missing expression"; -template <> -inline const std::string errors<language::logical_and>::error_message = "parse error, missing expression"; -template <> -inline const std::string errors<language::logical_or>::error_message = "parse error, missing expression"; - -template <> -inline const std::string errors<language::parented_expression>::error_message = "parse error, missing parented expression"; - -template <> -inline const std::string errors<language::statement_bloc>::error_message = "parse error, missing instruction"; - -template <> -inline const std::string errors<language::WHILE>::error_message = "parse error, missing 'while' statement"; -template <> -inline const std::string errors<language::while_kw>::error_message = "parse error, missing 'while' statement"; - -template <> -inline const std::string errors<language::open_parent>::error_message = "parse error, missing open parent '('"; - -template <> -inline const std::string errors<language::for_statement_bloc>::error_message = "parse error, missing for-loop body"; - -template <> -inline const std::string errors<language::slashstar>::error_message = "bloc comment was never terminated, missing '*/'"; - -template <> -inline const std::string errors<language::open_brace>::error_message = "open brace was never closed, missing '}'"; - -// clang-format on - -enum class DataType -{ - undefined_t = -1, - bool_t = 0, - unsigned_int_t = 1, - int_t = 2, - double_t = 3, - typename_t = 10, - void_t = 9999 -}; - -std::string -dataTypeName(const DataType& data_type) -{ - std::string name; - switch (data_type) { - case DataType::undefined_t: - name = "undefined"; - break; - case DataType::bool_t: - name = "B"; - break; - case DataType::unsigned_int_t: - name = "N"; - break; - case DataType::int_t: - name = "Z"; - break; - case DataType::double_t: - name = "R"; - break; - case DataType::typename_t: - name = "typename"; - break; - case DataType::void_t: - name = "void"; - break; - } - return name; -} - -DataType -dataTypePromotion(const DataType& data_type_1, const DataType& data_type_2) -{ - if (data_type_1 == data_type_2) { - return data_type_1; - } else if ((std::max(data_type_1, data_type_2) <= DataType::double_t) and - (std::min(data_type_1, data_type_2) >= DataType::bool_t)) { - return std::max(data_type_1, data_type_2); - } else { - return DataType::undefined_t; - } -} - -using DataVariant = std::variant<std::monostate, bool, uint64_t, int64_t, double>; - -struct ExecUntilBreakOrContinue -{ - enum class JumpType - { - no_jump, - break_jump, - continue_jump - }; - - private: - JumpType m_jump_type{JumpType::no_jump}; - bool m_exec{true}; - - public: - PUGS_INLINE - bool - exec() const - { - return m_exec; - } - - PUGS_INLINE - JumpType - jumpType() const - { - return m_jump_type; - } - - ExecUntilBreakOrContinue& operator=(const ExecUntilBreakOrContinue&) = delete; - ExecUntilBreakOrContinue& operator=(ExecUntilBreakOrContinue&&) = default; - - ExecUntilBreakOrContinue() = default; - - constexpr ExecUntilBreakOrContinue(const JumpType& jump_type) - : m_jump_type(jump_type), m_exec((jump_type == JumpType::no_jump)) - { - ; - } -}; - -class SymbolTable; -class INodeProcessor -{ - public: - virtual void execute(ExecUntilBreakOrContinue& exec_policy) = 0; - - INodeProcessor(const INodeProcessor& node) = delete; - - INodeProcessor() {} - - virtual ~INodeProcessor() {} -}; - -struct Node : public parse_tree::basic_node<Node> -{ - std::shared_ptr<SymbolTable> m_symbol_table; - std::unique_ptr<INodeProcessor> m_node_processor; - - PUGS_INLINE - void - execute(ExecUntilBreakOrContinue& exec_policy) - { - Assert(static_cast<bool>(m_node_processor)); - if (exec_policy.exec()) { - m_node_processor->execute(exec_policy); - } - } - - DataType m_data_type{DataType::undefined_t}; - DataVariant m_value; -}; - -struct rearrange : parse_tree::apply<rearrange> -{ - template <typename... States> - static void - transform(std::unique_ptr<Node>& n, States&&... st) - { - if (n->children.size() == 1) { - n = std::move(n->children.back()); - } else { - // First we rearrange tree - { - n->remove_content(); - auto& children = n->children; - auto rhs = std::move(children.back()); - children.pop_back(); - auto op = std::move(children.back()); - children.pop_back(); - op->children.emplace_back(std::move(n)); - op->children.emplace_back(std::move(rhs)); - n = std::move(op); - transform(n->children.front(), st...); - } - // Then we eventually simplify operations - { - if (n->is<language::minus_op>()) { - Assert(n->children.size() == 2); - auto& rhs = n->children[1]; - if (rhs->is<language::unary_minus>()) { - rhs->remove_content(); - n->id = typeid(language::plus_op); - rhs = std::move(rhs->children[0]); - } - } else if (n->is<language::plus_op>()) { - Assert(n->children.size() == 2); - auto& rhs = n->children[1]; - if (rhs->is<language::unary_minus>()) { - rhs->remove_content(); - n->id = typeid(language::minus_op); - rhs = std::move(rhs->children[0]); - } - } - } - } - } -}; - -struct simplify_unary : parse_tree::apply<simplify_unary> -{ - template <typename... States> - static void - transform(std::unique_ptr<Node>& n, States&&... st) - { - if (n->children.size() == 1) { - if (n->is<unary_expression>()) { - n->remove_content(); - n = std::move(n->children.back()); - transform(n, st...); - } else if (n->is<unary_minus>()) { - auto& child = n->children[0]; - if (child->is<unary_minus>()) { - n->remove_content(); - child->remove_content(); - n = std::move(child->children[0]); - transform(n, st...); - } - } else if (n->is<unary_not>()) { - auto& child = n->children[0]; - if (child->is<unary_not>()) { - n->remove_content(); - child->remove_content(); - n = std::move(child->children[0]); - transform(n, st...); - } - } - } else if (n->children.size() == 2) { - if (n->children[0]->is<language::unary_plus>()) { - n->remove_content(); - n = std::move(n->children[1]); - transform(n, st...); - } else if (n->children[0]->is<language::unary_minus>() or n->children[0]->is<language::unary_not>() or - n->children[0]->is<language::unary_minusminus>() or n->children[0]->is<language::unary_plusplus>()) { - n->remove_content(); - auto expression = std::move(n->children[1]); - auto unary_operator = std::move(n->children[0]); - unary_operator->children.emplace_back(std::move(expression)); - n = std::move(unary_operator); - n->remove_content(); - transform(n, st...); - } else if (n->children[1]->is<language::post_minusminus>() or n->children[1]->is<language::post_plusplus>()) { - n->remove_content(); - auto expression = std::move(n->children[0]); - auto unary_operator = std::move(n->children[1]); - unary_operator->children.emplace_back(std::move(expression)); - n = std::move(unary_operator); - n->remove_content(); - transform(n, st...); - } - } - } -}; - -struct simplify_statement_bloc : parse_tree::apply<simplify_statement_bloc> -{ - template <typename... States> - static void - transform(std::unique_ptr<Node>& n, States&&... st) - { - if (n->children.size() == 1) { - if (not n->children[0]->is<language::declaration>()) { - n->remove_content(); - n = std::move(n->children.back()); - transform(n, st...); - } else { - n->id = typeid(language::bloc); - } - } - } -}; - -struct simplify_for_statement_bloc : parse_tree::apply<simplify_for_statement_bloc> -{ - template <typename... States> - static void - transform(std::unique_ptr<Node>& n, States&&... st) - { - if (n->children.size() == 1) { - n->remove_content(); - n = std::move(n->children.back()); - transform(n, st...); - } - } -}; - -struct simplify_for_init : parse_tree::apply<simplify_for_init> -{ - template <typename... States> - static void - transform(std::unique_ptr<Node>& n, States&&...) - { - Assert(n->children.size() <= 1); - if (n->children.size() == 1) { - n->remove_content(); - n = std::move(n->children.back()); - } - } -}; - -struct simplify_for_test : parse_tree::apply<simplify_for_test> -{ - template <typename... States> - static void - transform(std::unique_ptr<Node>& n, States&&...) - { - Assert(n->children.size() <= 1); - if (n->children.size() == 1) { - n->remove_content(); - n = std::move(n->children.back()); - } - } -}; - -struct simplify_for_post : parse_tree::apply<simplify_for_post> -{ - template <typename... States> - static void - transform(std::unique_ptr<Node>& n, States&&...) - { - Assert(n->children.size() <= 1); - if (n->children.size() == 1) { - n->remove_content(); - n = std::move(n->children.back()); - } - } -}; - -struct simplify_stream_statement : parse_tree::apply<simplify_stream_statement> -{ - template <typename... States> - static void - transform(std::unique_ptr<Node>& n, States&&...) - { - for (size_t i = 1; i < n->children.size(); ++i) { - n->children[0]->children.emplace_back(std::move(n->children[i])); - } - n->remove_content(); - n = std::move(n->children[0]); - } -}; - -template <typename Rule> -using selector = parse_tree::selector<Rule, - parse_tree::store_content::on<true_kw, - false_kw, - integer, - real, - name, - B_set, - N_set, - Z_set, - R_set, - cout_kw, - cerr_kw, - clog_kw, - declaration, - if_statement, - do_while_statement, - while_statement, - for_statement, - break_kw, - continue_kw>, - rearrange::on<product, affectation, expression>, - simplify_unary::on<unary_minus, unary_plus, unary_not, unary_expression>, - parse_tree::remove_content::on<plus_op, - minus_op, - multiply_op, - divide_op, - lesser_op, - lesser_or_eq_op, - greater_op, - greater_or_eq_op, - eqeq_op, - not_eq_op, - and_op, - or_op, - xor_op, - bitand_op, - bitor_op, - eq_op, - multiplyeq_op, - divideeq_op, - pluseq_op, - minuseq_op, - // shift_left_op, - // shift_right_op, - bit_andeq_op, - bit_xoreq_op, - bit_oreq_op, - unary_plusplus, - unary_minusminus, - post_minusminus, - post_plusplus>, - simplify_for_statement_bloc::on<for_statement_bloc>, - parse_tree::discard_empty::on<ignored, semicol, bloc>, - simplify_statement_bloc::on<statement_bloc>, - simplify_for_init::on<for_init>, - simplify_for_test::on<for_test>, - simplify_for_post::on<for_post>, - simplify_stream_statement::on<ostream_statement>>; - -class SymbolTable -{ - class Attributes - { - bool m_is_initialized{false}; - DataType m_data_type{DataType::undefined_t}; - DataVariant m_value; - - public: - auto& - value() - { - return m_value; - } - - const auto& - value() const - { - return m_value; - } - - const bool& - isInitialized() const - { - return m_is_initialized; - } - - void - setIsInitialized() - { - m_is_initialized = true; - } - - const DataType& - dataType() const - { - return m_data_type; - } - - void - setDataType(const DataType& data_type) - { - m_data_type = data_type; - } - - friend std::ostream& - operator<<(std::ostream& os, const Attributes& attributes) - { - std::visit( - [&](const auto& value) { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, std::monostate>) { - os << "--"; - } else { - os << value; - } - }, - attributes.m_value); - - return os; - } - }; - - private: - std::vector<std::pair<std::string, Attributes>> m_symbol_list; - std::shared_ptr<SymbolTable> m_parent_table; - - public: - friend std::ostream& - operator<<(std::ostream& os, const SymbolTable& symbol_table) - { - os << "-- Symbol table state -- parent : " << symbol_table.m_parent_table.get() << "\n"; - for (auto i_symbol : symbol_table.m_symbol_list) { - os << ' ' << i_symbol.first << ": " << std::boolalpha << i_symbol.second << '\n'; - } - os << "------------------------\n"; - return os; - } - - auto - find(const std::string& symbol) - { - auto i_symbol = m_symbol_list.end(); - - for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) { - if (i_stored_symbol->first == symbol) { - i_symbol = i_stored_symbol; - break; - } - } - - if (i_symbol != m_symbol_list.end()) { - return std::make_pair(i_symbol, true); - } else { - if (m_parent_table) { - return m_parent_table->find(symbol); - } else { - return std::make_pair(i_symbol, false); - } - } - } - - auto - add(const std::string& symbol) - { - for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) { - if (i_stored_symbol->first == symbol) { - return std::make_pair(i_stored_symbol, false); - } - } - return std::make_pair(m_symbol_list.emplace(m_symbol_list.end(), std::make_pair(symbol, Attributes())), true); - } - - SymbolTable(const std::shared_ptr<SymbolTable>& parent_table = nullptr) : m_parent_table(parent_table) - { - ; - } -}; - -class NodeList final : public INodeProcessor -{ - Node& m_node; - - public: - NodeList(Node& node) : m_node{node} {} - - void - execute(ExecUntilBreakOrContinue& exec_policy) - { - for (auto& child : m_node.children) { - child->execute(exec_policy); - } - } -}; - -template <typename Op> -struct AffOp; - -template <> -struct AffOp<language::eq_op> -{ - template <typename A, typename B> - PUGS_INLINE void - eval(A& a, const B& b) - { - a = b; - } -}; - -template <> -struct AffOp<language::multiplyeq_op> -{ - template <typename A, typename B> - PUGS_INLINE void - eval(A& a, const B& b) - { - a *= b; - } -}; - -template <> -struct AffOp<language::divideeq_op> -{ - template <typename A, typename B> - PUGS_INLINE void - eval(A& a, const B& b) - { - a /= b; - } -}; - -template <> -struct AffOp<language::pluseq_op> -{ - template <typename A, typename B> - PUGS_INLINE void - eval(A& a, const B& b) - { - a += b; - } -}; - -template <> -struct AffOp<language::minuseq_op> -{ - template <typename A, typename B> - PUGS_INLINE void - eval(A& a, const B& b) - { - a -= b; - } -}; - -template <> -struct AffOp<language::bit_andeq_op> -{ - template <typename A, typename B> - PUGS_INLINE void - eval(A& a, const B& b) - { - a &= b; - } -}; - -template <> -struct AffOp<language::bit_xoreq_op> -{ - template <typename A, typename B> - PUGS_INLINE void - eval(A& a, const B& b) - { - a ^= b; - } -}; - -template <> -struct AffOp<language::bit_oreq_op> -{ - template <typename A, typename B> - PUGS_INLINE void - eval(A& a, const B& b) - { - a |= b; - } -}; - -template <typename OperatorT, typename ValueT, typename DataT> -class AffectationProcessor final : public INodeProcessor -{ - private: - Node& m_node; - DataVariant* p_value{nullptr}; - - static inline const bool _is_defined{[] { - if constexpr (std::is_same_v<OperatorT, language::bit_andeq_op> or - std::is_same_v<OperatorT, language::bit_xoreq_op> or - std::is_same_v<OperatorT, language::bit_oreq_op>) { - return std::is_same_v<std::decay_t<ValueT>, std::decay_t<DataT>> and std::is_integral_v<std::decay_t<ValueT>>; - } else if constexpr (std::is_same_v<std::decay_t<ValueT>, bool>) { - if constexpr (not std::is_same_v<OperatorT, language::eq_op>) { - return false; - } - } - return true; - }()}; - - public: - AffectationProcessor(Node& node) : m_node{node} - { - if constexpr (_is_defined) { - const std::string& symbol = m_node.children[0]->string(); - auto [i_symbol, found] = m_node.m_symbol_table->find(symbol); - Assert(found); - p_value = &i_symbol->second.value(); - } else { - throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()}); - } - } - - void - execute(ExecUntilBreakOrContinue& exec_policy) - { - if constexpr (_is_defined) { - m_node.children[1]->execute(exec_policy); - - if constexpr (std::is_same_v<OperatorT, language::eq_op>) { - if constexpr (std::is_same_v<ValueT, DataT>) { - *p_value = m_node.children[1]->m_value; - } else { - *p_value = static_cast<ValueT>(std::get<DataT>(m_node.children[1]->m_value)); - } - } else { - AffOp<OperatorT>().eval(std::get<ValueT>(*p_value), std::get<DataT>(m_node.children[1]->m_value)); - } - } - } -}; - -class NoProcess final : public INodeProcessor -{ - public: - NoProcess() {} - - PUGS_INLINE - void - execute(ExecUntilBreakOrContinue&) - { - ; - } -}; - -template <typename Op> -struct UnaryOp; - -template <> -struct UnaryOp<language::unary_minus> -{ - template <typename A> - PUGS_INLINE A - eval(const A& a) - { - return -a; - } -}; - -template <> -struct UnaryOp<language::unary_not> -{ - template <typename A> - PUGS_INLINE bool - eval(const A& a) - { - return not a; - } -}; - -template <typename UnaryOpT, typename ValueT, typename DataT> -class UnaryExpressionProcessor final : public INodeProcessor -{ - Node& m_node; - - public: - PUGS_INLINE ValueT - eval(const DataVariant& a) - { - return UnaryOp<UnaryOpT>().eval(std::get<DataT>(a)); - } - - public: - UnaryExpressionProcessor(Node& node) : m_node{node} {} - - void - execute(ExecUntilBreakOrContinue& exec_policy) - { - m_node.children[0]->execute(exec_policy); - m_node.m_value = eval(m_node.children[0]->m_value); - } -}; - -template <typename Op> -struct IncDecOp; - -template <> -struct IncDecOp<language::unary_minusminus> -{ - template <typename A> - PUGS_INLINE A - eval(A& a) - { - return --a; - } -}; - -template <> -struct IncDecOp<language::unary_plusplus> -{ - template <typename A> - PUGS_INLINE A - eval(A& a) - { - return ++a; - } -}; - -template <> -struct IncDecOp<language::post_minusminus> -{ - template <typename A> - PUGS_INLINE A - eval(A& a) - { - return a--; - } -}; - -template <> -struct IncDecOp<language::post_plusplus> -{ - template <typename A> - PUGS_INLINE A - eval(A& a) - { - return a++; - } -}; - -template <typename IncDecOpT, typename ValueT, typename DataT> -class IncDecExpressionProcessor final : public INodeProcessor -{ - Node& m_node; - DataVariant* p_value{nullptr}; - - static inline const bool _is_defined{[] { - if constexpr (std::is_same_v<IncDecOpT, language::unary_minusminus> or - std::is_same_v<IncDecOpT, language::unary_plusplus> or - std::is_same_v<IncDecOpT, language::post_minusminus> or - std::is_same_v<IncDecOpT, language::post_plusplus>) { - return not std::is_same_v<std::decay_t<DataT>, bool>; - } - return true; - }()}; - - public: - IncDecExpressionProcessor(Node& node) : m_node{node} - { - if constexpr (_is_defined) { - Assert(m_node.children[0]->is<language::name>()); - // It is sure at this point that children 0 is a variable name - const std::string& symbol = m_node.children[0]->string(); - auto [i_symbol, found] = m_node.m_symbol_table->find(symbol); - Assert(found); - p_value = &i_symbol->second.value(); - } else { - throw parse_error("invalid operand to unary operator", std::vector{m_node.begin()}); - } - } - void - execute(ExecUntilBreakOrContinue&) - { - if constexpr (_is_defined) { - m_node.m_value = IncDecOp<IncDecOpT>().eval(std::get<DataT>(*p_value)); - } - } -}; - -template <typename Op> -struct BinOp; - -template <> -struct BinOp<language::and_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a and b) - { - return a and b; - } -}; - -template <> -struct BinOp<language::or_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a or b) - { - return a or b; - } -}; - -template <> -struct BinOp<language::xor_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a xor b) - { - return a xor b; - } -}; - -template <> -struct BinOp<language::bitand_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a & b) - { - return a & b; - } -}; - -template <> -struct BinOp<language::bitor_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a | b) - { - return a | b; - } -}; - -template <> -struct BinOp<language::eqeq_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a == b) - { - return a == b; - } -}; - -template <> -struct BinOp<language::not_eq_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a != b) - { - return a != b; - } -}; - -template <> -struct BinOp<language::lesser_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a < b) - { - return a < b; - } -}; - -template <> -struct BinOp<language::lesser_or_eq_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a <= b) - { - return a <= b; - } -}; - -template <> -struct BinOp<language::greater_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a > b) - { - return a > b; - } -}; - -template <> -struct BinOp<language::greater_or_eq_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a >= b) - { - return a >= b; - } -}; - -template <> -struct BinOp<language::plus_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a + b) - { - return a + b; - } -}; - -template <> -struct BinOp<language::minus_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a - b) - { - return a - b; - } -}; - -template <> -struct BinOp<language::multiply_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a * b) - { - return a * b; - } -}; - -template <> -struct BinOp<language::divide_op> -{ - template <typename A, typename B> - PUGS_INLINE auto - eval(const A& a, const B& b) -> decltype(a / b) - { - return a / b; - } -}; - -template <typename BinaryOpT, typename ValueT, typename A_DataT, typename B_DataT> -class BinaryExpressionProcessor final : public INodeProcessor -{ - Node& m_node; - - PUGS_INLINE ValueT - eval(const DataVariant& a, const DataVariant& b) - { - // Add 'signed' when necessary to avoid signed/unsigned comparison warnings - if constexpr ((not(std::is_same_v<A_DataT, bool> or std::is_same_v<B_DataT, bool>)) and - (std::is_same_v<BinaryOpT, language::and_op> or std::is_same_v<BinaryOpT, language::or_op> or - std::is_same_v<BinaryOpT, language::xor_op> or std::is_same_v<BinaryOpT, language::bitand_op> or - std::is_same_v<BinaryOpT, language::bitor_op> or std::is_same_v<BinaryOpT, language::eqeq_op> or - std::is_same_v<BinaryOpT, language::not_eq_op> or std::is_same_v<BinaryOpT, language::lesser_op> or - std::is_same_v<BinaryOpT, language::lesser_or_eq_op> or - std::is_same_v<BinaryOpT, language::greater_op> or - std::is_same_v<BinaryOpT, language::greater_or_eq_op>) and - (std::is_signed_v<A_DataT> xor std::is_signed_v<B_DataT>)) { - if constexpr (std::is_unsigned_v<A_DataT>) { - using signed_A_DataT = std::make_signed_t<A_DataT>; - const signed_A_DataT signed_a = static_cast<signed_A_DataT>(std::get<A_DataT>(a)); - return BinOp<BinaryOpT>().eval(signed_a, std::get<B_DataT>(b)); - } else { - using signed_B_DataT = std::make_signed_t<B_DataT>; - const signed_B_DataT signed_b = static_cast<signed_B_DataT>(std::get<B_DataT>(b)); - return BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), signed_b); - } - } else { - return BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::get<B_DataT>(b)); - } - } - - static inline const bool _is_defined{[] { - if constexpr (std::is_same_v<BinaryOpT, language::bitand_op> or std::is_same_v<BinaryOpT, language::xor_op> or - std::is_same_v<BinaryOpT, language::bitor_op>) { - return std::is_same_v<std::decay_t<A_DataT>, std::decay_t<B_DataT>> and std::is_integral_v<std::decay_t<A_DataT>>; - } - return true; - }()}; - - public: - BinaryExpressionProcessor(Node& node) : m_node{node} - { - if constexpr (not _is_defined) { - throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()}); - } - } - - void - execute(ExecUntilBreakOrContinue& exec_policy) - { - if constexpr (_is_defined) { - m_node.children[0]->execute(exec_policy); - m_node.children[1]->execute(exec_policy); - - m_node.m_value = eval(m_node.children[0]->m_value, m_node.children[1]->m_value); - } - } -}; - -class IfStatement final : public INodeProcessor -{ - Node& m_node; - - public: - IfStatement(Node& node) : m_node{node} {} - - void - execute(ExecUntilBreakOrContinue& exec_policy) - { - m_node.children[0]->execute(exec_policy); - const bool is_true = static_cast<bool>(std::visit( - [](const auto& value) -> bool { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, std::monostate>) { - return false; - } else { - return value; - } - }, - m_node.children[0]->m_value)); - if (is_true) { - Assert(m_node.children[1] != nullptr); - m_node.children[1]->execute(exec_policy); - } else { - if (m_node.children.size() == 3) { - // else statement - Assert(m_node.children[2] != nullptr); - m_node.children[2]->execute(exec_policy); - } - } - } -}; - -class DoWhileStatement final : public INodeProcessor -{ - Node& m_node; - - public: - DoWhileStatement(Node& node) : m_node{node} {} - - void - execute(ExecUntilBreakOrContinue& exec_policy) - { - bool continuation_test = true; - ExecUntilBreakOrContinue exec_until_jump; - do { - m_node.children[0]->execute(exec_until_jump); - if (not exec_until_jump.exec()) { - if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::break_jump) { - break; - } else if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::continue_jump) { - exec_until_jump = ExecUntilBreakOrContinue{}; // getting ready for next loop traversal - } - } - m_node.children[1]->execute(exec_policy); - continuation_test = static_cast<bool>(std::visit( - [](const auto& value) -> bool { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, std::monostate>) { - return false; - } else { - return value; - } - }, - m_node.children[1]->m_value)); - } while (continuation_test); - } -}; - -class WhileStatement final : public INodeProcessor -{ - Node& m_node; - - public: - WhileStatement(Node& node) : m_node{node} {} - - void - execute(ExecUntilBreakOrContinue& exec_policy) - { - ExecUntilBreakOrContinue exec_until_jump; - while ([&]() { - m_node.children[0]->execute(exec_policy); - return static_cast<bool>(std::visit( - [](const auto& value) -> bool { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, std::monostate>) { - return false; - } else { - return value; - } - }, - m_node.children[0]->m_value)); - }()) { - m_node.children[1]->execute(exec_until_jump); - if (not exec_until_jump.exec()) { - if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::break_jump) { - break; - } else if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::continue_jump) { - exec_until_jump = ExecUntilBreakOrContinue{}; // getting ready for next loop traversal - } - } - } - } -}; - -class ForStatement final : public INodeProcessor -{ - Node& m_node; - - public: - ForStatement(Node& node) : m_node{node} {} - - void - execute(ExecUntilBreakOrContinue& exec_policy) - { - ExecUntilBreakOrContinue exec_until_jump; - m_node.children[0]->execute(exec_policy); - while ([&]() { - m_node.children[1]->execute(exec_policy); - return static_cast<bool>(std::visit( - [](const auto& value) -> bool { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, std::monostate>) { - return false; - } else { - return value; - } - }, - m_node.children[1]->m_value)); - }()) { - m_node.children[3]->execute(exec_until_jump); - if (not exec_until_jump.exec()) { - if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::break_jump) { - break; - } else if (exec_until_jump.jumpType() == ExecUntilBreakOrContinue::JumpType::continue_jump) { - exec_until_jump = ExecUntilBreakOrContinue{}; // getting ready for next loop traversal - } - } - - m_node.children[2]->execute(exec_policy); - } - } -}; - -class NameExpression final : public INodeProcessor -{ - Node& m_node; - DataVariant* p_value{nullptr}; - - public: - NameExpression(Node& node) : m_node{node} - { - const std::string& symbol = m_node.string(); - auto [i_symbol, found] = m_node.m_symbol_table->find(symbol); - Assert(found); - p_value = &(i_symbol->second.value()); - } - - void - execute(ExecUntilBreakOrContinue&) - { - m_node.m_value = *p_value; - } -}; - -class BreakExpression final : public INodeProcessor -{ - public: - BreakExpression() {} - - void - execute(ExecUntilBreakOrContinue& exec_policy) - { - exec_policy = ExecUntilBreakOrContinue(ExecUntilBreakOrContinue::JumpType::break_jump); - } -}; - -class ContinueExpression final : public INodeProcessor -{ - public: - ContinueExpression() {} - - void - execute(ExecUntilBreakOrContinue& exec_policy) - { - exec_policy = ExecUntilBreakOrContinue(ExecUntilBreakOrContinue::JumpType::continue_jump); - } -}; - -class OStreamObject final : public INodeProcessor -{ - Node& m_node; - std::ostream& m_os; - - public: - OStreamObject(Node& node, std::ostream& os) : m_node{node}, m_os(os) - { - ; - } - - void - execute(ExecUntilBreakOrContinue& exec_policy) - { - for (size_t i = 0; i < m_node.children.size(); ++i) { - m_node.children[i]->execute(exec_policy); - std::visit( - [&](auto&& value) { - using ValueT = std::decay_t<decltype(value)>; - if constexpr (not std::is_same_v<std::monostate, ValueT>) { - if constexpr (std::is_same_v<bool, ValueT>) { - m_os << std::boolalpha << value; - } else { - m_os << value; - } - } - }, - m_node.children[i]->m_value); - } - } -}; - -namespace internal -{ -void -build_node_type(Node& n) -{ - auto set_unary_operator_processor = [](Node& n, const auto& operator_v) { - auto set_unary_operator_processor_for_data = [&](const auto& value, const DataType& data_type) { - using OperatorT = std::decay_t<decltype(operator_v)>; - using ValueT = std::decay_t<decltype(value)>; - switch (data_type) { - case DataType::bool_t: { - n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, bool>>(n); - break; - } - case DataType::unsigned_int_t: { - n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, uint64_t>>(n); - break; - } - case DataType::int_t: { - n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, int64_t>>(n); - break; - } - case DataType::double_t: { - n.m_node_processor = std::make_unique<UnaryExpressionProcessor<OperatorT, ValueT, double>>(n); - break; - } - default: { - throw parse_error("undefined operand type for unary operator", std::vector{n.children[0]->begin()}); - } - } - }; - - auto set_unary_operator_processor_for_value = [&](const DataType& value_type) { - const DataType data_type = n.children[0]->m_data_type; - switch (value_type) { - case DataType::bool_t: { - set_unary_operator_processor_for_data(bool{}, data_type); - break; - } - case DataType::unsigned_int_t: { - set_unary_operator_processor_for_data(uint64_t{}, data_type); - break; - } - case DataType::int_t: { - set_unary_operator_processor_for_data(int64_t{}, data_type); - break; - } - case DataType::double_t: { - set_unary_operator_processor_for_data(double{}, data_type); - break; - } - default: { - throw parse_error("undefined value type for unary operator", std::vector{n.begin()}); - } - } - }; - - set_unary_operator_processor_for_value(n.m_data_type); - }; - - auto set_inc_dec_operator_processor = [](Node& n, const auto& operator_v) { - auto set_inc_dec_operator_processor_for_data = [&](const auto& value, const DataType& data_type) { - using OperatorT = std::decay_t<decltype(operator_v)>; - using ValueT = std::decay_t<decltype(value)>; - switch (data_type) { - case DataType::bool_t: { - n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, bool>>(n); - break; - } - case DataType::unsigned_int_t: { - n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, uint64_t>>(n); - break; - } - case DataType::int_t: { - n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, int64_t>>(n); - break; - } - case DataType::double_t: { - n.m_node_processor = std::make_unique<IncDecExpressionProcessor<OperatorT, ValueT, double>>(n); - break; - } - default: { - throw parse_error("undefined operand type for unary operator", std::vector{n.children[0]->begin()}); - } - } - }; - - auto set_inc_dec_processor_for_value = [&](const DataType& value_type) { - const DataType data_type = n.children[0]->m_data_type; - switch (value_type) { - case DataType::bool_t: { - set_inc_dec_operator_processor_for_data(bool{}, data_type); - break; - } - case DataType::unsigned_int_t: { - set_inc_dec_operator_processor_for_data(uint64_t{}, data_type); - break; - } - case DataType::int_t: { - set_inc_dec_operator_processor_for_data(int64_t{}, data_type); - break; - } - case DataType::double_t: { - set_inc_dec_operator_processor_for_data(double{}, data_type); - break; - } - default: { - throw parse_error("undefined value type for unary operator", std::vector{n.begin()}); - } - } - }; - - if (not n.children[0]->is<language::name>()) { - throw parse_error("invalid operand type for unary operator", std::vector{n.begin()}); - } - - set_inc_dec_processor_for_value(n.m_data_type); - }; - - auto set_binary_operator_processor = [](Node& n, const auto& operator_v) { - auto set_binary_operator_processor_for_data_b = [&](const auto value, const auto data_a, - const DataType& data_type_b) { - using OperatorT = std::decay_t<decltype(operator_v)>; - using ValueT = std::decay_t<decltype(value)>; - using DataTA = std::decay_t<decltype(data_a)>; - switch (data_type_b) { - case DataType::bool_t: { - n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, bool>>(n); - break; - } - case DataType::unsigned_int_t: { - n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, uint64_t>>(n); - break; - } - case DataType::int_t: { - n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, int64_t>>(n); - break; - } - case DataType::double_t: { - n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, DataTA, double>>(n); - break; - } - default: { - throw parse_error("undefined operand type for binary operator", std::vector{n.children[1]->begin()}); - } - } - }; - - auto set_binary_operator_processor_for_data_a = [&](const auto value, const DataType& data_type_a) { - const DataType data_type_b = n.children[1]->m_data_type; - switch (data_type_a) { - case DataType::bool_t: { - set_binary_operator_processor_for_data_b(value, bool{}, data_type_b); - break; - } - case DataType::unsigned_int_t: { - set_binary_operator_processor_for_data_b(value, uint64_t{}, data_type_b); - break; - } - case DataType::int_t: { - set_binary_operator_processor_for_data_b(value, int64_t{}, data_type_b); - break; - } - case DataType::double_t: { - set_binary_operator_processor_for_data_b(value, double{}, data_type_b); - break; - } - default: { - throw parse_error("undefined operand type for binary operator", std::vector{n.children[0]->begin()}); - } - } - }; - - auto set_binary_operator_processor_for_value = [&](const DataType& value_type) { - const DataType data_type_a = n.children[0]->m_data_type; - switch (value_type) { - case DataType::bool_t: { - set_binary_operator_processor_for_data_a(bool{}, data_type_a); - break; - } - case DataType::unsigned_int_t: { - set_binary_operator_processor_for_data_a(uint64_t{}, data_type_a); - break; - } - case DataType::int_t: { - set_binary_operator_processor_for_data_a(int64_t{}, data_type_a); - break; - } - case DataType::double_t: { - set_binary_operator_processor_for_data_a(double{}, data_type_a); - break; - } - default: { - throw parse_error("undefined value type for binary operator", std::vector{n.begin()}); - } - } - }; - - set_binary_operator_processor_for_value(n.m_data_type); - }; - - auto set_affectation_processor = [](Node& n, const auto& operator_v) { - auto set_affectation_processor_for_data = [&](const auto& value, const DataType& data_type) { - using OperatorT = std::decay_t<decltype(operator_v)>; - using ValueT = std::decay_t<decltype(value)>; - switch (data_type) { - case DataType::bool_t: { - n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, bool>>(n); - break; - } - case DataType::unsigned_int_t: { - n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, uint64_t>>(n); - break; - } - case DataType::int_t: { - n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, int64_t>>(n); - break; - } - case DataType::double_t: { - n.m_node_processor = std::make_unique<AffectationProcessor<OperatorT, ValueT, double>>(n); - break; - } - default: { - throw parse_error("undefined operand type for affectation", std::vector{n.children[0]->begin()}); - } - } - }; - - auto set_affectation_processor_for_value = [&](const DataType& value_type) { - const DataType data_type = n.children[1]->m_data_type; - switch (value_type) { - case DataType::bool_t: { - set_affectation_processor_for_data(bool{}, data_type); - break; - } - case DataType::unsigned_int_t: { - set_affectation_processor_for_data(uint64_t{}, data_type); - break; - } - case DataType::int_t: { - set_affectation_processor_for_data(int64_t{}, data_type); - break; - } - case DataType::double_t: { - set_affectation_processor_for_data(double{}, data_type); - break; - } - default: { - throw parse_error("undefined value type for affectation", std::vector{n.begin()}); - } - } - }; - - set_affectation_processor_for_value(n.m_data_type); - }; - - if (n.is_root()) { - n.m_node_processor = std::make_unique<NodeList>(n); - } else if (n.is<language::bloc>()) { - n.m_node_processor = std::make_unique<NodeList>(n); - } else if (n.is<language::declaration>()) { - n.m_node_processor = std::make_unique<NoProcess>(); - } else if (n.is<language::eq_op>()) { - set_affectation_processor(n, language::eq_op{}); - } else if (n.is<language::multiplyeq_op>()) { - set_affectation_processor(n, language::multiplyeq_op{}); - } else if (n.is<language::divideeq_op>()) { - set_affectation_processor(n, language::divideeq_op{}); - } else if (n.is<language::pluseq_op>()) { - set_affectation_processor(n, language::pluseq_op{}); - } else if (n.is<language::minuseq_op>()) { - set_affectation_processor(n, language::minuseq_op{}); - } else if (n.is<language::bit_andeq_op>()) { - set_affectation_processor(n, language::bit_andeq_op{}); - } else if (n.is<language::bit_xoreq_op>()) { - set_affectation_processor(n, language::bit_xoreq_op{}); - } else if (n.is<language::bit_oreq_op>()) { - set_affectation_processor(n, language::bit_oreq_op{}); - - } else if (n.is<language::real>()) { - n.m_node_processor = std::make_unique<NoProcess>(); - } else if (n.is<language::integer>()) { - n.m_node_processor = std::make_unique<NoProcess>(); - - } else if (n.is<language::name>()) { - n.m_node_processor = std::make_unique<NameExpression>(n); - - } else if (n.is<language::unary_minus>()) { - set_unary_operator_processor(n, language::unary_minus{}); - } else if (n.is<language::unary_not>()) { - set_unary_operator_processor(n, language::unary_not{}); - - } else if (n.is<language::unary_minusminus>()) { - set_inc_dec_operator_processor(n, language::unary_minusminus{}); - } else if (n.is<language::unary_plusplus>()) { - set_inc_dec_operator_processor(n, language::unary_plusplus{}); - } else if (n.is<language::post_minusminus>()) { - set_inc_dec_operator_processor(n, language::post_minusminus{}); - } else if (n.is<language::post_plusplus>()) { - set_inc_dec_operator_processor(n, language::post_plusplus{}); +#include <ASTBuilder.hpp> +#include <PEGGrammar.hpp> +#include <SymbolTable.hpp> - } else if (n.is<language::multiply_op>()) { - set_binary_operator_processor(n, language::multiply_op{}); - } else if (n.is<language::divide_op>()) { - set_binary_operator_processor(n, language::divide_op{}); - } else if (n.is<language::plus_op>()) { - set_binary_operator_processor(n, language::plus_op{}); - } else if (n.is<language::minus_op>()) { - set_binary_operator_processor(n, language::minus_op{}); - } else if (n.is<language::or_op>()) { - set_binary_operator_processor(n, language::or_op{}); - } else if (n.is<language::and_op>()) { - set_binary_operator_processor(n, language::and_op{}); +#include <ASTNodeExpressionBuilder.hpp> - } else if (n.is<language::xor_op>()) { - set_binary_operator_processor(n, language::xor_op{}); - } else if (n.is<language::bitand_op>()) { - set_binary_operator_processor(n, language::bitand_op{}); - } else if (n.is<language::bitor_op>()) { - set_binary_operator_processor(n, language::bitor_op{}); - - } else if (n.is<language::greater_op>()) { - set_binary_operator_processor(n, language::greater_op{}); - } else if (n.is<language::greater_or_eq_op>()) { - set_binary_operator_processor(n, language::greater_or_eq_op{}); - } else if (n.is<language::lesser_op>()) { - set_binary_operator_processor(n, language::lesser_op{}); - } else if (n.is<language::lesser_or_eq_op>()) { - set_binary_operator_processor(n, language::lesser_or_eq_op{}); - } else if (n.is<language::eqeq_op>()) { - set_binary_operator_processor(n, language::eqeq_op{}); - } else if (n.is<language::not_eq_op>()) { - set_binary_operator_processor(n, language::not_eq_op{}); - } else if (n.is<language::B_set>()) { - } else if (n.is<language::N_set>()) { - } else if (n.is<language::Z_set>()) { - } else if (n.is<language::cout_kw>()) { - n.m_node_processor = std::make_unique<OStreamObject>(n, std::cout); - } else if (n.is<language::cerr_kw>()) { - n.m_node_processor = std::make_unique<OStreamObject>(n, std::cerr); - } else if (n.is<language::clog_kw>()) { - n.m_node_processor = std::make_unique<OStreamObject>(n, std::clog); - } else if (n.is<language::R_set>()) { - } else if (n.is<language::if_statement>()) { - n.m_node_processor = std::make_unique<IfStatement>(n); - } else if (n.is<language::statement_bloc>()) { - n.m_node_processor = std::make_unique<NodeList>(n); - } else if (n.is<language::do_while_statement>()) { - n.m_node_processor = std::make_unique<DoWhileStatement>(n); - } else if (n.is<language::while_statement>()) { - n.m_node_processor = std::make_unique<WhileStatement>(n); - } else if (n.is<language::for_statement>()) { - n.m_node_processor = std::make_unique<ForStatement>(n); - } else if (n.is<language::for_statement_bloc>()) { - n.m_node_processor = std::make_unique<NodeList>(n); - } else if (n.is<language::for_init>()) { - n.m_node_processor = std::make_unique<NoProcess>(); - } else if (n.is<language::for_post>()) { - n.m_node_processor = std::make_unique<NoProcess>(); - } else if (n.is<language::for_test>()) { - n.m_node_processor = std::make_unique<NoProcess>(); - } else if (n.is<language::break_kw>()) { - n.m_node_processor = std::make_unique<BreakExpression>(); - } else if (n.is<language::continue_kw>()) { - n.m_node_processor = std::make_unique<ContinueExpression>(); - } else if (n.is<language::true_kw>()) { - n.m_node_processor = std::make_unique<NoProcess>(); - } else if (n.is<language::false_kw>()) { - n.m_node_processor = std::make_unique<NoProcess>(); - } else { - std::ostringstream error_message; - error_message << "undefined node type '" << rang::fgB::red << n.name() << rang::fg::reset << "'"; - throw parse_error{error_message.str(), std::vector{n.begin()}}; - } - - for (auto& child : n.children) { - internal::build_node_type(*child); - } -} -} // namespace internal - -void -build_node_type(Node& n) +namespace language { - Assert(n.is_root()); - Assert(n.is<void>()); - n.m_node_processor = std::make_unique<NodeList>(n); - for (auto& child : n.children) { - internal::build_node_type(*child); - } - std::cout << " - build node types\n"; -} - namespace internal { void @@ -2478,9 +519,9 @@ parser(const std::string& filename) << rang::style::reset << " ...\n"; std::unique_ptr<language::Node> root_node; - read_input in(filename); + read_input input(filename); try { - root_node = parse_tree::parse<language::grammar, language::Node, language::selector, nothing, language::errors>(in); + root_node = buildAST(input); std::cout << " - AST is built ...... [done]\n"; language::build_symbol_table_and_check_declarations(*root_node); @@ -2515,7 +556,7 @@ parser(const std::string& filename) std::cerr << rang::style::bold << p.source << ':' << p.line << ':' << p.byte_in_line << ": " << rang::style::reset << rang::fgB::red << "error: " << rang::fg::reset << rang::style::bold << e.what() << rang::style::reset << '\n' - << in.line_at(p) << '\n' + << input.line_at(p) << '\n' << std::string(p.byte_in_line, ' ') << rang::fgB::yellow << '^' << rang::fg::reset << std::endl; std::exit(1); } diff --git a/src/language/SymbolTable.hpp b/src/language/SymbolTable.hpp new file mode 100644 index 000000000..e2e874f5b --- /dev/null +++ b/src/language/SymbolTable.hpp @@ -0,0 +1,126 @@ +#ifndef SYMBOL_TABLE_HPP +#define SYMBOL_TABLE_HPP + +namespace language +{ +class SymbolTable +{ + class Attributes + { + bool m_is_initialized{false}; + DataType m_data_type{DataType::undefined_t}; + DataVariant m_value; + + public: + auto& + value() + { + return m_value; + } + + const auto& + value() const + { + return m_value; + } + + const bool& + isInitialized() const + { + return m_is_initialized; + } + + void + setIsInitialized() + { + m_is_initialized = true; + } + + const DataType& + dataType() const + { + return m_data_type; + } + + void + setDataType(const DataType& data_type) + { + m_data_type = data_type; + } + + friend std::ostream& + operator<<(std::ostream& os, const Attributes& attributes) + { + std::visit( + [&](const auto& value) { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_same_v<T, std::monostate>) { + os << "--"; + } else { + os << value; + } + }, + attributes.m_value); + + return os; + } + }; + + private: + std::vector<std::pair<std::string, Attributes>> m_symbol_list; + std::shared_ptr<SymbolTable> m_parent_table; + + public: + friend std::ostream& + operator<<(std::ostream& os, const SymbolTable& symbol_table) + { + os << "-- Symbol table state -- parent : " << symbol_table.m_parent_table.get() << "\n"; + for (auto i_symbol : symbol_table.m_symbol_list) { + os << ' ' << i_symbol.first << ": " << std::boolalpha << i_symbol.second << '\n'; + } + os << "------------------------\n"; + return os; + } + + auto + find(const std::string& symbol) + { + auto i_symbol = m_symbol_list.end(); + + for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) { + if (i_stored_symbol->first == symbol) { + i_symbol = i_stored_symbol; + break; + } + } + + if (i_symbol != m_symbol_list.end()) { + return std::make_pair(i_symbol, true); + } else { + if (m_parent_table) { + return m_parent_table->find(symbol); + } else { + return std::make_pair(i_symbol, false); + } + } + } + + auto + add(const std::string& symbol) + { + for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) { + if (i_stored_symbol->first == symbol) { + return std::make_pair(i_stored_symbol, false); + } + } + return std::make_pair(m_symbol_list.emplace(m_symbol_list.end(), std::make_pair(symbol, Attributes())), true); + } + + SymbolTable(const std::shared_ptr<SymbolTable>& parent_table = nullptr) : m_parent_table(parent_table) + { + ; + } +}; +} // namespace language + +#endif // SYMBOL_TABLE_HPP -- GitLab