From 6d1dfdac58f5ec313cfc66699e20c2ee1a4edd14 Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Mon, 5 Oct 2026 20:24:09 +0300 Subject: [PATCH] add operator conversion for efficient parallelizing --- inc/expression.hpp | 41 +++++++++ inc/parser.hpp | 1 + inc/syntaxer.hpp | 1 + src/parser.cpp | 11 +++ src/syntaxer.cpp | 212 ++++++++++++++++++++++++++++++++++++++++++++- src/test-cases.cpp | 16 +++- 6 files changed, 277 insertions(+), 5 deletions(-) diff --git a/inc/expression.hpp b/inc/expression.hpp index 89ff87a..f200d22 100644 --- a/inc/expression.hpp +++ b/inc/expression.hpp @@ -110,6 +110,12 @@ public: case OPERATOR: v.o = other.v.o; break; + case CV: + v.cv.w = other.v.cv.w; + v.cv.i = other.v.cv.i; + break; + case NAT: + break; default: std::cout << "Warning: token type is invalid\n"; break; @@ -131,12 +137,47 @@ public: case OPERATOR: v.o = other.v.o; break; + case CV: + v.cv.w = other.v.cv.w; + v.cv.i = other.v.cv.i; + break; + case NAT: + break; default: std::cout << "Warning: token type is invalid\n"; break; } } + Expression::Token& operator=(const Expression::Token& other) + { + t = other.t; + + switch (t) + { + case VAR: + v.s = other.v.s; + break; + case CONST: + v.d = other.v.d; + break; + case OPERATOR: + v.o = other.v.o; + break; + case CV: + v.cv.w = other.v.cv.w; + v.cv.i = other.v.cv.i; + break; + case NAT: + break; + default: + std::cout << "Warning: token type is invalid\n"; + break; + } + + return const_cast(other); + } + std::shared_ptr to_str(void) const { switch (t) diff --git a/inc/parser.hpp b/inc/parser.hpp index 7202f1f..f7a8ec9 100644 --- a/inc/parser.hpp +++ b/inc/parser.hpp @@ -8,5 +8,6 @@ namespace Parser { std::vector tokenize_input(const char * const input_string); int assert_same(const std::vector& a, const std::vector& b); void print_token_vector(const std::vector& tv); +void print_math_vector(const std::vector& tv); } diff --git a/inc/syntaxer.hpp b/inc/syntaxer.hpp index 7dde438..4d108aa 100644 --- a/inc/syntaxer.hpp +++ b/inc/syntaxer.hpp @@ -12,6 +12,7 @@ struct SyntaxIssue }; std::vector check_syntax(std::vector& tv); +void apply_corrections(std::vector& tv); std::vector build_op_vector(const std::vector& tv); } diff --git a/src/parser.cpp b/src/parser.cpp index ddbf0bd..ab08dfd 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -381,4 +381,15 @@ void print_token_vector(const std::vector& tv) std::cout << "(" << *tv[i].to_str() << ")\n"; } +void print_math_vector(const std::vector& tv) +{ + int i, l; + for (i = 0, l = tv.size() - 1; i < l; i++) + { + std::cout << *tv[i].to_math_str() << " "; + } + + std::cout << *tv[i].to_math_str() << "\n"; +} + } diff --git a/src/syntaxer.cpp b/src/syntaxer.cpp index 0468afc..61c7714 100644 --- a/src/syntaxer.cpp +++ b/src/syntaxer.cpp @@ -1,4 +1,5 @@ #include "syntaxer.hpp" +#include "parser.hpp" #include "expression.hpp" #include #include "print.h" @@ -83,7 +84,7 @@ static int get_operator_weight(const std::vector& v, int loca return weight; } -static int get_min(const std::vector& v) +static int get_min_index(const std::vector& v) { int idx = 0; @@ -98,6 +99,21 @@ static int get_min(const std::vector& v) return idx; } +static int get_max_index(const std::vector& v) +{ + int idx = 0; + + for (int i = 1, l = v.size(); i < l; i++) + { + if (v[i] > v[idx]) + { + idx = i; + } + } + + return idx; +} + static void write_operation( std::vector& ov, const std::vector& tv, @@ -138,6 +154,66 @@ static void write_operation( mp.erase(mp.begin() + position, mp.begin() + position + 1); } +static void add_bracket_to(std::vector& tv, const int location, const int direction) +{ + int i = location + direction, l = tv.size(), lv = 0; + + if (direction == -1) + { + for (; i >= 0; i--) + { + if (tv[i].t == Expression::Token::OPERATOR) + { + switch (tv[i].v.o) + { + case Expression::Token::OPA: + lv--; + break; + case Expression::Token::CPA: + lv++; + break; + default: + if (!lv) + { + tv.insert(tv.begin() + i + 1, Expression::Token(Expression::Token::OPA)); + return; + } + break; + } + } + } + + tv.insert(tv.begin(), Expression::Token(Expression::Token::OPA)); + } + else if (direction == 1) + { + for (; i < l; i++) + { + if (tv[i].t == Expression::Token::OPERATOR) + { + switch (tv[i].v.o) + { + case Expression::Token::OPA: + lv++; + break; + case Expression::Token::CPA: + lv--; + break; + default: + if (!lv) + { + tv.insert(tv.begin() + i, Expression::Token(Expression::Token::CPA)); + return; + } + break; + } + } + } + + tv.emplace_back(Expression::Token::CPA); + } +} + static void create_prios_vector(const std::vector& tv, std::vector& pv) { for (int i = 0, cp = 0, l = tv.size(); i < l; i++) @@ -183,6 +259,62 @@ static void find_top_prio_op_range(const std::vector& mp, int& start, int& } } +struct Range +{ + int start, finish; + + Range(int start, int finish) + : start(start), finish(finish) + { + } +}; + +static void find_select_prio_op_ranges(const std::vector& mp, std::vector& ranges, int target_prio) +{ + for (int i = 0, l = mp.size(), prio = 0, recording_range = 0; i < l; i++) + { + if (mp[i] == target_prio && !recording_range) + { + recording_range = 1; + ranges.emplace_back(i, 0); + } + else if (mp[i] == target_prio && recording_range) + { + ranges.back().finish = i; + } + else if (mp[i] != target_prio && recording_range) + { + recording_range = 0; + } + } +} + +static void rank_inner_ops_raw(std::vector& inner_op_ranks, const std::vector& mv, const int start, const int finish) +{ + for (int i = 0, lvl = 0; i < finish - start + 1; i++) + { + int idx = get_mop_location(mv, start + i); + + switch (mv[idx].v.o) + { + case Expression::Token::ADD: + case Expression::Token::SUB: + inner_op_ranks.push_back(0); + break; + case Expression::Token::MUL: + case Expression::Token::DIV: + inner_op_ranks.push_back(1); + break; + case Expression::Token::POW: + inner_op_ranks.push_back(2); + break; + default: + pr_warn("Operator is unrankable"); + break; + } + } +} + static void rank_inner_ops(std::vector& inner_top_ops, const std::vector& mv, const int start, const int finish) { for (int i = 0, lvl = 0; i < finish - start + 1; i++) @@ -238,7 +370,83 @@ static void weight_operators(std::vector& operator_weights, const std::vect void apply_corrections(std::vector& tv) { + pr_debug("Starting with vector:"); + Parser::print_math_vector(tv); + // global prio evaluation + std::vector mp; + create_prios_vector(tv, mp); + + for (int current_prio_level = mp[get_max_index(mp)]; current_prio_level >= 0; current_prio_level--) + { + // calculate how many ranges need to be processed at this level + std::vector rv; + find_select_prio_op_ranges(mp, rv, current_prio_level); + + for (int current_range = rv.size() - 1; current_range >= 0; current_range--) + { + Range &outer_range = rv[current_range]; + + std::vector inner_prios; + rank_inner_ops_raw(inner_prios, tv, outer_range.start, outer_range.finish); + + for (int inner_prio = inner_prios[get_max_index(inner_prios)]; inner_prio >= 0; inner_prio--) + { + std::vector inner_ranges; + find_select_prio_op_ranges(inner_prios, inner_ranges, inner_prio); + + for (int inner_range = inner_ranges.size() - 1; inner_range >= 0; inner_range--) + { + int corrections = 1; + + Range &range = inner_ranges[inner_range]; + while (corrections) + { + corrections = 0; + + int same_op_cnt = -1; + for (int i = outer_range.start + range.start; i < outer_range.start + range.finish + 1; i++) + { + int loc = get_mop_location(tv, i); + Expression::Token& tok = tv[loc]; + + if (tok.v.o == Expression::Token::SUB || tok.v.o == Expression::Token::DIV) + { + same_op_cnt++; + + if (same_op_cnt == 2) + { + same_op_cnt = 0; + + corrections++; + + switch (tok.v.o) + { + case Expression::Token::SUB: + tok.v.o = Expression::Token::ADD; + break; + case Expression::Token::DIV: + tok.v.o = Expression::Token::MUL; + break; + default: + pr_warn("Impossible operator in this branch, this is a bug!"); + break; + } + + // inverse order to keep location valid between calls + add_bracket_to(tv, loc, 1); + add_bracket_to(tv, loc, -1); + + pr_debug("Updated vector:"); + Parser::print_math_vector(tv); + } + } + } + } + } + } + } + } } std::vector build_op_vector(const std::vector& tv) @@ -272,7 +480,7 @@ std::vector build_op_vector(const std::vector operator_weights; weight_operators(operator_weights, mv, inner_top_ops, start); - write_operation(ov, tv, mv, mp, start + inner_top_ops[get_min(operator_weights)]); + write_operation(ov, tv, mv, mp, start + inner_top_ops[get_min_index(operator_weights)]); finish--; } diff --git a/src/test-cases.cpp b/src/test-cases.cpp index ae7f455..b372e86 100644 --- a/src/test-cases.cpp +++ b/src/test-cases.cpp @@ -6,7 +6,7 @@ TEST(parser_proper_test_1) { auto o = Parser::tokenize_input("(1+2-c)"); - Parser::print_token_vector(o); + Parser::print_math_vector(o); std::vector r; @@ -26,7 +26,7 @@ TEST(parser_proper_test_1) TEST(parser_proper_test_2) { auto o = Parser::tokenize_input("(1**5,-snake+marble*34*(35 / 63.2))"); - Parser::print_token_vector(o); + Parser::print_math_vector(o); std::vector r; @@ -56,7 +56,7 @@ TEST(parser_proper_test_2) TEST(parser_proper_test_3) { auto o = Parser::tokenize_input(")))25.4,, 33..4 35 37 39 41 // +-*/***()()()"); - Parser::print_token_vector(o); + Parser::print_math_vector(o); std::vector r; @@ -96,6 +96,15 @@ TEST(tree_proper_test_1) return 0; } +TEST(tree_proper_test_2) +{ + std::vector o = Parser::tokenize_input("(1**5 * (1-2-3-4-5-6-7-8))"); + Syntax::apply_corrections(o); + std::vector ov = Syntax::build_op_vector(o); + + return 0; +} + void register_tests(void) { REGISTER(parser_proper_test_1); @@ -103,4 +112,5 @@ void register_tests(void) REGISTER(parser_proper_test_3); REGISTER(tree_proper_test_1); + REGISTER(tree_proper_test_2); }