From bc4fbafec44156f777f81d84403d1297f2a8aef4 Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Mon, 5 Oct 2026 11:17:48 +0300 Subject: [PATCH] finish operation vector building --- inc/expression.hpp | 95 +++++++++++++- inc/parser.hpp | 2 +- inc/print.h | 6 +- inc/syntaxer.hpp | 3 +- src/parser.cpp | 41 +++--- src/syntaxer.cpp | 309 +++++++++++++++++++++++++++++++++++++++++---- src/test-cases.cpp | 16 +-- 7 files changed, 412 insertions(+), 60 deletions(-) diff --git a/inc/expression.hpp b/inc/expression.hpp index a3dcbd7..89ff87a 100644 --- a/inc/expression.hpp +++ b/inc/expression.hpp @@ -24,7 +24,9 @@ public: enum TokenType { VAR, CONST, - OPERATOR + OPERATOR, + CV, // compound value (result of an operation) + NAT, // not a token } t; enum Operator { @@ -41,6 +43,10 @@ public: std::shared_ptr s; double d; Operator o; + struct { + int w; // weight + int i; // index in operation vector + } cv; explicit TokenValue(std::string& s) : s(std::make_shared(s)) @@ -89,6 +95,27 @@ public: t = OPERATOR; } + Token(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; + default: + std::cout << "Warning: token type is invalid\n"; + break; + } + } + Token(Expression::Token&& other) { t = other.t; @@ -128,6 +155,24 @@ public: } } + std::shared_ptr to_math_str(void) const + { + switch (t) + { + case VAR: + return v.s; + case CONST: + { + char buffer[128] = {0}; + return std::make_shared((std::ostringstream() << v.d).str()); + } + case OPERATOR: + return std::make_shared(op_math_str()); + default: + return std::make_shared("Not a valid token!"); + } + } + const char *type_str(void) const { switch (t) @@ -170,6 +215,54 @@ public: return "Invalid operator"; } } + + const char *op_math_str(void) const + { + if (t != OPERATOR) + { + return "Token is not an operator!"; + } + + switch (v.o) + { + case OPA: + return "("; + case CPA: + return ")"; + case ADD: + return "+"; + case SUB: + return "-"; + case MUL: + return "*"; + case DIV: + return "/"; + case POW: + return "^"; + default: + return "Invalid operator"; + } + } +}; + +struct Operation +{ + Token o; // operator + + enum Type + { + NORMAL, + DERIVED, + } tl, tr; // type left, type right + + int il, ir; // index left, index right + int w; // operation weight + + Operation(enum Expression::Token::Operator o, enum Type tl, int il, enum Type tr, int ir, int w) + : o(o), tl(tl), tr(tr), il(il), ir(ir), w(w) + { + + } }; class TreeNode { diff --git a/inc/parser.hpp b/inc/parser.hpp index 8eb992f..7202f1f 100644 --- a/inc/parser.hpp +++ b/inc/parser.hpp @@ -5,7 +5,7 @@ namespace Parser { -std::shared_ptr> tokenize_input(const char * const input_string); +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); diff --git a/inc/print.h b/inc/print.h index 91b430e..b8775fa 100644 --- a/inc/print.h +++ b/inc/print.h @@ -4,9 +4,13 @@ #include "config.h" #if DEBUG == 1 -#define pr_debug(...) std::cout << "[" << __func__ << ":" << __LINE__ << "] debug: " << __VA_ARGS__ << "\n" +#define pr_debug(...) std::cout << "[" << __FILE__ << ":" << __LINE__ << " " << __func__ << "] debug: " << __VA_ARGS__ << "\n" +#define pri_debug(...) std::cout << __VA_ARGS__ +#define prs_debug(...) std::cout << "[" << __FILE__ << ":" << __LINE__ << " " << __func__ << "] debug: " << __VA_ARGS__ #else #define pr_debug(...) do {} while (0) +#define pri_debug(...) do {} while (0) +#define prs_debug(...) do {} while (0) #endif #define pr_warn(...) std::cout << "[" << __FILE__ << ":" << __LINE__ << " " << __func__ << "] warning: " << __VA_ARGS__ << "\n" diff --git a/inc/syntaxer.hpp b/inc/syntaxer.hpp index 2c85d76..7dde438 100644 --- a/inc/syntaxer.hpp +++ b/inc/syntaxer.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include "expression.hpp" namespace Syntax @@ -13,6 +12,6 @@ struct SyntaxIssue }; std::vector check_syntax(std::vector& tv); -std::shared_ptr build_op_tree(std::vector& tv); +std::vector build_op_vector(const std::vector& tv); } diff --git a/src/parser.cpp b/src/parser.cpp index e43f227..ddbf0bd 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -87,9 +87,9 @@ class Parser public: char buffer[256]; - std::shared_ptr>& pv; + std::vector& pv; - Parser(std::shared_ptr>& pv) + Parser(std::vector& pv) : s(I), pv(pv) { buf_clear(); @@ -210,7 +210,7 @@ public: } else { - pv->push_back(Expression::Token(value)); + pv.push_back(Expression::Token(value)); } return 0; @@ -234,7 +234,7 @@ public: } int leave_rv(void) { - pv->push_back(Expression::Token(buffer)); + pv.push_back(Expression::Token(buffer)); return 0; } @@ -261,37 +261,37 @@ public: { if (!strcmp(buffer, "(")) { - pv->push_back(Expression::Token(Expression::Token::OPA)); + pv.push_back(Expression::Token(Expression::Token::OPA)); break; } else if (!strcmp(buffer, ")")) { - pv->push_back(Expression::Token(Expression::Token::CPA)); + pv.push_back(Expression::Token(Expression::Token::CPA)); break; } else if (!strcmp(buffer, "+")) { - pv->push_back(Expression::Token(Expression::Token::ADD)); + pv.push_back(Expression::Token(Expression::Token::ADD)); break; } else if (!strcmp(buffer, "-")) { - pv->push_back(Expression::Token(Expression::Token::SUB)); + pv.push_back(Expression::Token(Expression::Token::SUB)); break; } else if (!strcmp(buffer, "*")) { - pv->push_back(Expression::Token(Expression::Token::MUL)); + pv.push_back(Expression::Token(Expression::Token::MUL)); break; } else if (!strcmp(buffer, "/")) { - pv->push_back(Expression::Token(Expression::Token::DIV)); + pv.push_back(Expression::Token(Expression::Token::DIV)); break; } else if (!strcmp(buffer, "**")) { - pv->push_back(Expression::Token(Expression::Token::POW)); + pv.push_back(Expression::Token(Expression::Token::POW)); break; } } @@ -308,9 +308,9 @@ public: } }; -std::shared_ptr> tokenize_input(const char * const input_string) +std::vector tokenize_input(const char * const input_string) { - std::shared_ptr> pv = std::make_shared>(); + std::vector pv; Parser p(pv); for (int i = 0, l = strlen(input_string) + 1; i < l; i++) @@ -361,8 +361,12 @@ int assert_same(const std::vector& a, const std::vector& tv) std::cout << "(" << *tv[i].to_str() << ")\n"; } -void print_token_vector(const std::vector& tv, const std::vector& colorcoding) -{ - int i, l; - for (i = 0, l = tv.size() - 1; i < l; i++) - { - std::cout << "(" << *tv[i].to_str() << ") "; - } - - std::cout << "(" << *tv[i].to_str() << ")\n"; -} - } diff --git a/src/syntaxer.cpp b/src/syntaxer.cpp index 2aefe48..b281468 100644 --- a/src/syntaxer.cpp +++ b/src/syntaxer.cpp @@ -5,11 +5,13 @@ namespace Syntax { +#if 0 struct OpImportance { - int pos; + //int pos; int prio; }; +#endif #if 0 std::vector check_syntax(std::vector& tv); @@ -18,19 +20,134 @@ std::vector check_syntax(std::vector& tv); } #endif -std::shared_ptr build_op_tree(const std::vector& tv) -{ - // define operator precedency - int prios_cnt = ({ - int i = 0, c = 0, l = tv.size(); - for (; i < l; c += tv[i].t == Expression::Token::OPERATOR - && tv[i].v.o != Expression::Token::CPA - && tv[i].v.o != Expression::Token::OPA, i++); - c; - }); - OpImportance prios[prios_cnt]; - for (int i = 0, p = 0, cp = 0, l = tv.size(); i < l; i++) +// get mop = Math OPerator index +static int get_mop_location(const std::vector& v, int position) +{ + int i = 0, l = v.size(), p = -1; + for (; p += v[i].t == Expression::Token::OPERATOR + && v[i].v.o != Expression::Token::OPA + && v[i].v.o != Expression::Token::CPA, p != position; i++); + return i; +} + +static int get_left_location(const std::vector& v, int location) +{ + for (int i = location - 1; i >= 0; i--) + { + if (v[i].t != Expression::Token::OPERATOR && v[i].t != Expression::Token::NAT) + { + return i; + } + } + + return -1; +} + +static int get_right_location(const std::vector& v, int location) +{ + for (int i = location + 1, l = v.size(); i < l; i++) + { + if (v[i].t != Expression::Token::OPERATOR && v[i].t != Expression::Token::NAT) + { + return i; + } + } + + return -1; +} + +static int get_operator_weight(const std::vector& v, int location) +{ + int weight = 0; + + switch (const Expression::Token &p = v[get_left_location(v, location)]; p.t) + { + case Expression::Token::VAR: + case Expression::Token::CONST: + break; + case Expression::Token::CV: + weight += p.v.cv.w; + break; + default: + pr_warn("Invalid token found to the left of operator"); + break; + } + + switch (const Expression::Token &p = v[get_right_location(v, location)]; p.t) + { + case Expression::Token::VAR: + case Expression::Token::CONST: + break; + case Expression::Token::CV: + weight += p.v.cv.w; + break; + default: + pr_warn("Invalid token found to the left of operator"); + break; + } + + return weight; +} + +static int get_min(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, + std::vector& mv, + std::vector& mp, + int position) +{ + int location = get_mop_location(mv, position); + int left_location = get_left_location(mv, location); + int right_location = get_right_location(mv, location); + + Expression::Token &o = mv[location], + &l = mv[left_location], + &r = mv[right_location]; + + int this_op_weight = get_operator_weight(mv, location) + 1; + + int il = l.t == Expression::Token::CV ? l.v.cv.i : left_location; + int ir = r.t == Expression::Token::CV ? r.v.cv.i : right_location; + + // write new operation + int this_ov_index = ov.size(); + ov.emplace_back(o.v.o, + l.t == Expression::Token::CV ? Expression::Operation::DERIVED : Expression::Operation::NORMAL, + il, + r.t == Expression::Token::CV ? Expression::Operation::DERIVED : Expression::Operation::NORMAL, + ir, + this_op_weight); + + // update mv + l.t = Expression::Token::NAT; + r.t = Expression::Token::NAT; + o.t = Expression::Token::CV; + o.v.cv.w = this_op_weight; + o.v.cv.i = this_ov_index; + + // update mp + mp.erase(mp.begin() + position, mp.begin() + position + 1); +} + +static void create_prios_vector(const std::vector& tv, std::vector& pv) +{ + for (int i = 0, cp = 0, l = tv.size(); i < l; i++) { if (tv[i].t == Expression::Token::OPERATOR) { @@ -47,9 +164,7 @@ std::shared_ptr build_op_tree(const std::vector build_op_tree(const std::vector& mp, int& start, int& finish) +{ + for (int i = 0, l = mp.size(), prio = -1; i < l; i++) { - pr_debug("pos=" << prios[i].pos << ",prio=" << prios[i].prio); + if (mp[i] > prio) + { + prio = mp[i]; + start = finish = i; + } + else if (mp[i] == prio && finish == i - 1) + { + finish = i; + } + } +} + +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++) + { + int idx = get_mop_location(mv, start + i); + + switch (mv[idx].v.o) + { + case Expression::Token::ADD: + case Expression::Token::SUB: + if (lvl == 0) + inner_top_ops.push_back(i); + + break; + case Expression::Token::MUL: + case Expression::Token::DIV: + if (lvl < 1) + { + lvl = 1; + inner_top_ops.clear(); + } + + if (lvl == 1) + inner_top_ops.push_back(i); + + break; + case Expression::Token::POW: + if (lvl < 2) + { + lvl = 2; + inner_top_ops.clear(); + } + + if (lvl == 2) + inner_top_ops.push_back(i); + + break; + default: + pr_warn("Operator is unrankable"); + break; + } + } +} + +static void weight_operators(std::vector& operator_weights, const std::vector& mv, const std::vector& inner_top_ops, const int start) +{ + for (int i = 0, l = inner_top_ops.size(); i < l; i++) + { + int operator_location = get_mop_location(mv, start + inner_top_ops[i]); + operator_weights.push_back(get_operator_weight(mv, operator_location)); + } +} + +void apply_corrections(std::vector& tv) +{ + +} + +std::vector build_op_vector(const std::vector& tv) +{ + // define operator precedency + std::vector g_prios; + create_prios_vector(tv, g_prios); + + for (int i = 0, l = g_prios.size(); i < l; i++) + { + pr_debug("prio=" << g_prios[i]); } - // build dependency graph + // build operation vector + std::vector ov; { std::vector mv = tv; + std::vector mp = g_prios; + + while (mp.size()) + { + int start, finish; + find_top_prio_op_range(mp, start, finish); + + // --- process current range --- + while (start != finish) + { + std::vector inner_top_ops; + rank_inner_ops(inner_top_ops, mv, start, finish); + + 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)]); + finish--; + } + + // process final operation w/out running selection algorithm + write_operation(ov, tv, mv, mp, start); + } } - - // build operation tree - Expression::TreeNode *root = new Expression::TreeNode; + for (int i = 0, l = ov.size(); i < l; i++) + { + const Expression::Operation &o = ov[i]; - return std::shared_ptr(root); + prs_debug("OP: "); + + if (o.tl == Expression::Operation::NORMAL) + { + const Expression::Token &real_value = tv[o.il]; + + if (real_value.t == Expression::Token::VAR) + { + pri_debug(*real_value.v.s); + } + else + { + pri_debug(real_value.v.d); + } + } + else + { + pri_debug("t" << o.il); + } + + pri_debug(" " << o.o.op_math_str() << " "); + + if (o.tr == Expression::Operation::NORMAL) + { + const Expression::Token &real_value = tv[o.ir]; + + if (real_value.t == Expression::Token::VAR) + { + pri_debug(*real_value.v.s); + } + else + { + pri_debug(real_value.v.d); + } + } + else + { + pri_debug("t" << o.ir); + } + + pri_debug(" = t" << i << "\n"); + } + + return ov; } } diff --git a/src/test-cases.cpp b/src/test-cases.cpp index d902f36..ae7f455 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_token_vector(o); std::vector r; @@ -18,7 +18,7 @@ TEST(parser_proper_test_1) r.push_back(Expression::Token("c")); r.push_back(Expression::Token(Expression::Token::CPA)); - CHECK(Parser::assert_same(*o, r)); + CHECK(Parser::assert_same(o, r)); return 0; } @@ -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_token_vector(o); std::vector r; @@ -48,7 +48,7 @@ TEST(parser_proper_test_2) r.push_back(Expression::Token(Expression::Token::CPA)); r.push_back(Expression::Token(Expression::Token::CPA)); - CHECK(Parser::assert_same(*o, r)); + CHECK(Parser::assert_same(o, r)); return 0; } @@ -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_token_vector(o); std::vector r; @@ -83,15 +83,15 @@ TEST(parser_proper_test_3) r.push_back(Expression::Token(Expression::Token::OPA)); r.push_back(Expression::Token(Expression::Token::CPA)); - CHECK(Parser::assert_same(*o, r)); + CHECK(Parser::assert_same(o, r)); return 0; } TEST(tree_proper_test_1) { - auto o = Parser::tokenize_input("(1**5 * (1 + 2 + 3 + 4))"); - Syntax::build_op_tree(*o); + std::vector o = Parser::tokenize_input("(1**5 * (1 - 2 - (3 + 4) - ((5 + 6) + (7 + 8))))"); + std::vector ov = Syntax::build_op_vector(o); return 0; }