From e3de20197cb0155ca909bf40d5b009f2694a107e Mon Sep 17 00:00:00 2001 From: peter-winter <78534905+peter-winter@users.noreply.github.com> Date: Wed, 17 Nov 2021 16:10:21 +0100 Subject: [PATCH] Typed terms feature. Minors. (#3) Typed terms feature added. --- ctpg.hpp | 145 ++++++++++++++++++++++++-------- examples/ctjs.cpp | 4 + examples/simple-expr-parser.cpp | 1 - examples/typed_terms.cpp | 92 ++++++++++++++++++++ 4 files changed, 208 insertions(+), 34 deletions(-) create mode 100644 examples/typed_terms.cpp diff --git a/ctpg.hpp b/ctpg.hpp index 30ecab4..3531f2e 100644 --- a/ctpg.hpp +++ b/ctpg.hpp @@ -1,7 +1,7 @@ #ifndef CTPG_H #define CTPG_H -constexpr const char* version_str = "1.0.0"; +constexpr const char* version_str = "1.1.0"; #include #include @@ -370,6 +370,12 @@ namespace stdex namespace utils { + template + constexpr T construct_default(Args...) + { + return T(); + } + template constexpr void copy_array(T *a1, const T* a2, std::index_sequence) { @@ -644,13 +650,19 @@ namespace regex }; } +namespace detail +{ + constexpr std::string_view pass_sv(const std::string_view& sv) { return sv; } + constexpr char first_sv_char(const std::string_view& sv) { return sv[0]; } +} + template class regex_term : public term { public: - using value_type = term_value; + using internal_value_type = std::string_view; + static const size_t dfa_size = regex::analyze_dfa_size(Pattern); - static const bool is_single_char = false; static const bool is_trivial = false; static const size_t pattern_size = std::size(Pattern); @@ -676,6 +688,8 @@ class regex_term : public term constexpr const char* get_id() const { return id; } constexpr auto get_data() const { return regex::regex_pattern_data{ Pattern }; } + constexpr const auto& get_ftor() const { return detail::pass_sv; } + private: char id[pattern_size + 2] = {}; const char* custom_name = nullptr; @@ -684,9 +698,9 @@ class regex_term : public term class char_term : public term { public: - using value_type = term_value; + using internal_value_type = char; + static const size_t dfa_size = 2; - static const bool is_single_char = true; static const bool is_trivial = true; constexpr char_term(char c, int precedence = 0, associativity a = associativity::no_assoc): @@ -700,6 +714,8 @@ class char_term : public term constexpr char get_char() const { return c; } constexpr char get_data() const { return c; } + constexpr const auto& get_ftor() const { return detail::first_sv_char; } + private: char c; char id[utils::char_names::name_size] = {}; @@ -709,9 +725,8 @@ template class string_term : public term { public: - using value_type = term_value; + using internal_value_type = std::string_view; static const size_t dfa_size = (DataSize - 1) * 2; - static const bool is_single_char = false; static const bool is_trivial = true; template @@ -725,10 +740,65 @@ class string_term : public term constexpr const char* get_name() const { return get_id(); } constexpr const auto& get_data() const { return data; } + constexpr const auto& get_ftor() const { return detail::pass_sv; } + private: char data[DataSize] = {}; }; +template +class typed_term +{ +public: + using internal_value_type = std::invoke_result_t; + static const size_t dfa_size = Term::dfa_size; + static const bool is_trivial = Term::is_trivial; + + constexpr typed_term(Term t, Ftor f): + term(t), ftor(f) + {} + + constexpr const char* get_id() const { return term.get_id(); } + constexpr const char* get_name() const { return term.get_name(); } + constexpr decltype(auto) get_data() const { return term.get_data(); } + + constexpr associativity get_associativity() const { return term.get_associativity(); } + constexpr int get_precedence() const { return term.get_precedence(); } + + using ftor_type = Ftor; + + constexpr const ftor_type& get_ftor() const { return ftor; } + +private: + Term term; + ftor_type ftor; +}; + +template +struct value_type +{}; + +template +struct value_type>> +{ + using type = term_value; +}; + +template +struct value_type> +{ + using type = ValueType; +}; + +template +struct value_type> +{ + using type = term_value::internal_value_type>; +}; + +template +using value_type_t = typename value_type::type; + struct parse_options { constexpr parse_options& set_verbose(bool val = true) { verbose = val; return *this; } @@ -1081,43 +1151,46 @@ namespace regex class regex_digit_af : public term { public: - using value_type = term_value; + using internal_value_type = char; static const size_t dfa_size = 2; - static const bool is_single_char = true; static const bool is_trivial = true; constexpr const char* get_id() const { return "$regex_digit_af$"; } constexpr const char* get_name() const { return get_id(); } constexpr auto get_data() const { return regex_af_digit_chars{}; } + + constexpr const auto& get_ftor() const { return detail::first_sv_char; } }; class regex_digit_09 : public term { public: - using value_type = term_value; + using internal_value_type = char; static const size_t dfa_size = 2; - static const bool is_single_char = true; static const bool is_trivial = true; constexpr const char* get_id() const { return "$regex_digit_09$"; } constexpr const char* get_name() const { return get_id(); } constexpr auto get_data() const { return regex_09_digit_chars{}; } + + constexpr const auto& get_ftor() const { return detail::first_sv_char; } }; class regex_regular_char : public term { public: - using value_type = term_value; + using internal_value_type = char; static const size_t dfa_size = 2; - static const bool is_single_char = true; static const bool is_trivial = true; constexpr const char* get_id() const { return "$regex_regular$"; } constexpr const char* get_name() const { return get_id(); } constexpr auto get_data() const { return regex_regular_chars_data{}; } + + constexpr const auto& get_ftor() const { return detail::first_sv_char; } }; template @@ -1769,10 +1842,10 @@ class parser< using value_variant_type = meta::unique_types_variant_t< std::nullptr_t, - term_value, - term_value, - NTermValueType... + NTermValueType..., + value_type_t... >; + using term_subset = stdex::cbitset; using nterm_subset = stdex::cbitset; using right_side_slice_subset = stdex::cbitset; @@ -1847,15 +1920,14 @@ class parser< term_associativities[eof_idx] = associativity::no_assoc; } - template - constexpr void analyze_term(const Term& t, size16_t idx) + template + constexpr void analyze_term(const Term& t) { - term_precedences[idx] = t.get_precedence(); - term_associativities[idx] = t.get_associativity(); - term_names[idx] = t.get_name(); - term_ids[idx] = t.get_id(); - if constexpr (Term::is_single_char) - single_char_terms.set(idx); + term_precedences[TermIdx] = t.get_precedence(); + term_associativities[TermIdx] = t.get_associativity(); + term_names[TermIdx] = t.get_name(); + term_ids[TermIdx] = t.get_id(); + term_ftors[TermIdx] = string_view_to_term_value; } template @@ -1885,7 +1957,7 @@ class parser< template constexpr void analyze_terms(std::index_sequence) { - (void(analyze_term(std::get(term_tuple), I)), ...); + (void(analyze_term(std::get(term_tuple))), ...); } template @@ -1949,9 +2021,6 @@ class parser< return associativity::no_assoc; } - template - using value_type_t = typename T::value_type; - template constexpr void analyze_rule(const detail::rule& r, std::index_sequence) { @@ -2297,6 +2366,14 @@ class parser< } } + template + constexpr static value_variant_type string_view_to_term_value(const term_tuple_type& term_tuple, const std::string_view& sv, source_point sp) + { + const auto &t = std::get(term_tuple); + using term_value_type = value_type_t>; + return value_variant_type(term_value_type(t.get_ftor()(sv), sp)); + } + template constexpr static LValueType reduce_value_impl(const F& f, value_variant_type* start, std::index_sequence) { @@ -2321,10 +2398,8 @@ class parser< ps.error_stream << ps.current_sp << " PARSE: Shift to " << new_cursor_value << ", term: " << sv << "\n"; ps.cursor_stack.push_back(new_cursor_value); - if (single_char_terms.test(term_idx)) - ps.value_stack.emplace_back(term_value(sv[0], ps.current_sp)); - else - ps.value_stack.emplace_back(term_value(sv, ps.current_sp)); + const auto& ftor = term_ftors[term_idx]; + ps.value_stack.emplace_back(ftor(term_tuple, sv, ps.current_sp)); } template @@ -2465,9 +2540,13 @@ class parser< term_tuple_type term_tuple; nterm_tuple_type nterm_tuple; rule_tuple_type rule_tuple; + using value_reductor = value_variant_type(*)(const rule_tuple_type&, value_variant_type*); value_reductor value_reductors[rule_count] = {}; - term_subset single_char_terms = {}; + + using string_view_to_term_value_t = value_variant_type(*)(const term_tuple_type&, const std::string_view&, source_point); + string_view_to_term_value_t term_ftors[term_count] = {}; + using dfa_type = regex::dfa; dfa_type lexer_sm = {}; }; diff --git a/examples/ctjs.cpp b/examples/ctjs.cpp index b2408d6..781637d 100644 --- a/examples/ctjs.cpp +++ b/examples/ctjs.cpp @@ -1,3 +1,7 @@ +/* +Compile Time JSON Parser example +*/ + #include "../ctpg.hpp" #include diff --git a/examples/simple-expr-parser.cpp b/examples/simple-expr-parser.cpp index 1565827..9429724 100644 --- a/examples/simple-expr-parser.cpp +++ b/examples/simple-expr-parser.cpp @@ -4,7 +4,6 @@ using namespace ctpg; using namespace ctpg::buffers; using namespace ctpg::ftors; -using namespace std::placeholders; struct binary_op { diff --git a/examples/typed_terms.cpp b/examples/typed_terms.cpp new file mode 100644 index 0000000..79cdd52 --- /dev/null +++ b/examples/typed_terms.cpp @@ -0,0 +1,92 @@ +#include "../ctpg.hpp" +#include + +using namespace ctpg; +using namespace ctpg::buffers; +using namespace ctpg::ftors; + +struct plus_op {}; +struct minus_op {}; +struct mul_op {}; +struct div_op {}; + +struct calculator +{ + constexpr int operator()(int x1, plus_op, int x2) const + { + return x1 + x2; + } + + constexpr int operator()(int x1, minus_op, int x2) const + { + return x1 - x2; + } + + constexpr int operator()(int x1, mul_op, int x2) const + { + return x1 * x2; + } + + constexpr int operator()(int x1, div_op, int x2) const + { + return x1 / x2; + } + + constexpr int operator()(minus_op, int x) const + { + return -x; + } +}; + +constexpr int get_int(std::string_view sv) +{ + int sum = 0; + for (size_t i = 0; i < sv.size(); ++i) + { + sum *= 10; + int digit = sv[i] - '0'; + sum += digit; + } + return sum; +} + +constexpr nterm expr("expr"); + +constexpr typed_term o_plus(char_term('+', 1, associativity::ltor), create{}); +constexpr typed_term o_minus(char_term('-', 1, associativity::ltor), create{}); +constexpr typed_term o_mul(char_term('*', 2, associativity::ltor), create{}); +constexpr typed_term o_div(char_term('/', 2, associativity::ltor), create{}); + +constexpr char number_pattern[] = "[1-9][0-9]*"; +constexpr typed_term number(regex_term("number"), get_int); + +constexpr calculator c; + +constexpr parser p( + expr, + terms(number, o_plus, o_minus, o_mul, o_div, '(', ')'), + nterms(expr), + rules( + expr(expr, o_plus, expr) >= c, + expr(expr, o_minus, expr) >= c, + expr(expr, o_mul, expr) >= c, + expr(expr, o_div, expr) >= c, + expr(o_minus, expr)[3] >= c, + expr('(', expr, ')') >= _e2, + expr(number) + ) +); + +int main(int argc, char* argv[]) +{ + if (argc != 2) + return -1; + + auto res = p.parse(parse_options{}.set_verbose(), string_buffer(argv[1]), std::cerr); + if (res.has_value()) + { + int rv = res.value(); + std::cout << "runtime parse: " << rv << std::endl; + } + return 0; +}