diff --git a/inc/syntaxer.hpp b/inc/syntaxer.hpp index a7e2401..2229486 100644 --- a/inc/syntaxer.hpp +++ b/inc/syntaxer.hpp @@ -6,9 +6,7 @@ namespace Syntax { -void pre_process(std::vector& tv); -int check_syntax(const std::vector& tv); -void post_process(std::vector& tv); +int prepare_token_vector(std::vector& tv); std::vector build_op_vector(const std::vector& tv); Expression::TreeNode ov_to_tree(const std::vector tv, const std::vector& ov); void print_op_tree(const std::vector tv, const std::vector& ov); diff --git a/src/main.cpp b/src/main.cpp index 7a3bfe1..efdb27e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,15 +10,11 @@ int main(int argc, char **argv) std::vector tv = Parser::tokenize_input(argv[1]); - Syntax::pre_process(tv); - - if (Syntax::check_syntax(tv)) + if (Syntax::prepare_token_vector(tv)) { return 0; } - Syntax::post_process(tv); - std::vector ov = Syntax::build_op_vector(tv); Expression::TreeNode root = Syntax::ov_to_tree(tv, ov); diff --git a/src/syntaxer.cpp b/src/syntaxer.cpp index d166f52..94bf5e7 100644 --- a/src/syntaxer.cpp +++ b/src/syntaxer.cpp @@ -11,6 +11,24 @@ namespace Syntax { static int add_bracket_to(std::vector& tv, const int location, const int direction); +static int rank_op(const Expression::Token::Operator o) +{ + switch (o) + { + case Expression::Token::ADD: + case Expression::Token::SUB: + return 0; + case Expression::Token::MUL: + case Expression::Token::DIV: + return 1; + case Expression::Token::POW: + return 2; + default: + pr_warn("Operator is unrankable"); + return -1; + } +} + static void highlight_issue(const std::vector& tv, const int location) { int start = location - 7 < 0 ? 0 : location - 7; @@ -33,7 +51,651 @@ static void highlight_issue(const std::vector& tv, const int std::cout << "\n"; } -void pre_process(std::vector& tv) + +// get mop = Math OPerator location (=absolute index in std::vector) +// mapper of 'priority vector index' -> 'token vector 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_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 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 int write_operation( + std::vector& ov, + std::vector& cv, + 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); + + std::vector hl; + hl.emplace_back(left_location); + hl.emplace_back(location); + hl.emplace_back(right_location); + Parser::print_math_vector(mv, hl); + + Expression::Token &o = mv[location], + &l = mv[left_location], + &r = mv[right_location]; + +#if LAB2_EXCLUDE_COMPTIME_OP_WRITES == 1 + if (l.t == Expression::Token::CONST && r.t == Expression::Token::CONST) + { + pr_debug("CONST folding"); + + switch (o.v.o) + { + case Expression::Token::ADD: + o.v.d = l.v.d + r.v.d; + break; + case Expression::Token::SUB: + o.v.d = l.v.d - r.v.d; + break; + case Expression::Token::MUL: + o.v.d = l.v.d * r.v.d; + break; + case Expression::Token::DIV: + if (r.v.d != 0.0) + { + o.v.d = l.v.d / r.v.d; + } + else + { + pr_warn("Right operand is zero, invalid operation"); + return 1; + } + break; + case Expression::Token::POW: + o.v.d = std::pow(l.v.d, r.v.d); + break; + default: + pr_warn("Impossible operator, this is a bug!"); + break; + } + + l.t = Expression::Token::NAT; + r.t = Expression::Token::NAT; + o.t = Expression::Token::CONST; + + // sync &cv operator + cv[location].t = Expression::Token::CONST; + cv[location].v.d = o.v.d; + } + else + { +#endif + 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; +#if LAB2_EXCLUDE_COMPTIME_OP_WRITES == 1 + } +#endif + + // update mp + mp.erase(mp.begin() + position, mp.begin() + position + 1); + + return 0; +} + +static int 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) + { + if (tv[i].v.o == Expression::Token::CPA) + { + lv++; + } + + if (!lv) + { + tv.insert(tv.begin() + i + 1, Expression::Token(Expression::Token::OPA)); + return i + 1; + } + + if (tv[i].v.o == Expression::Token::OPA) + { + lv--; + } + } + } + + tv.insert(tv.begin(), Expression::Token(Expression::Token::OPA)); + return 0; + } + else if (direction == 1) + { + for (; i < l; i++) + { + if (tv[i].t == Expression::Token::OPERATOR) + { + if (tv[i].v.o == Expression::Token::OPA) + { + lv++; + } + + if (!lv) + { + tv.insert(tv.begin() + i, Expression::Token(Expression::Token::CPA)); + return i; + } + + if (tv[i].v.o == Expression::Token::CPA) + { + lv--; + } + } + } + + tv.emplace_back(Expression::Token::CPA); + return i; + } + else + { + pr_warn("Invalid direction given, this is a big bug!"); + return -1; + } +} + +static int add_opa_after_le_io(std::vector &tv, const int location) +{ + int base_rank = rank_op(tv[location].v.o); + + for (int i = location - 1, lv = 0; i >= 0; i--) + { + Expression::Token &t = tv[i]; + + if (t.t == Expression::Token::OPERATOR) + { + if (t.v.o == Expression::Token::CPA) + { + lv++; + } + + if (lv <= 0 && (base_rank - rank_op(t.v.o)) >= 0) + { + tv.insert(tv.begin() + i + 1, Expression::Token(Expression::Token::OPA)); + return i + 1; + } + + if (t.v.o == Expression::Token::OPA) + { + lv--; + } + } + } + + tv.insert(tv.begin(), Expression::Token(Expression::Token::OPA)); + return 0; +} + +static int add_cpa_before_le_io(std::vector &tv, const int location) +{ + int base_rank = rank_op(tv[location].v.o); + + for (int i = location + 1, lv = 0, l = tv.size(); i < l; i++) + { + Expression::Token &t = tv[i]; + + if (t.t == Expression::Token::OPERATOR) + { + if (t.v.o == Expression::Token::OPA) + { + lv++; + } + + if (lv <= 0 && (rank_op(t.v.o) - base_rank) <= 0) + { + tv.insert(tv.begin() + i, Expression::Token(Expression::Token::CPA)); + return i; + } + + if (t.v.o == Expression::Token::CPA) + { + lv--; + } + } + } + + tv.push_back(Expression::Token(Expression::Token::CPA)); + return tv.size() - 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) + { + switch (tv[i].v.o) + { + case Expression::Token::OPA: + cp++; + break; + case Expression::Token::CPA: + cp--; + break; + case Expression::Token::ADD: + case Expression::Token::SUB: + case Expression::Token::MUL: + case Expression::Token::DIV: + case Expression::Token::POW: + pv.emplace_back(cp); + break; + default: + pr_warn("Token vector has broken operator at " << i); + break; + } + } + } +} + +static void find_top_prio_op_range(const std::vector& mp, int& start, int& finish) +{ + for (int i = 0, l = mp.size(), prio = -1; i < l; i++) + { + if (mp[i] > prio) + { + prio = mp[i]; + start = finish = i; + } + else if (mp[i] == prio && finish == i - 1) + { + finish = i; + } + } +} + +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, i); + } + 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 find_parent_level_range(const std::vector& mp, int &p_start, int &p_finish, const int c_start, const int c_finish) +{ + // left side + for (int i = c_start; i >= 0; i--) + { + if (mp[i] < mp[c_start] - 1) + { + p_start = i + 1; + goto right; + } + } + + p_start = 0; + +right: + // right side + for (int i = c_finish; i < mp.size(); i++) + { + if (mp[i] < mp[c_finish] - 1) + { + p_finish = i + 1; + break; + } + } + + p_finish = mp.size() - 1; +} + +static void rank_inner_ops_raw(std::vector& inner_op_ranks, const std::vector& mv, const int start, const int finish, const int same_lvl_only = 0) +{ + for (int i = get_mop_location(mv, start), lvl = 0, f = get_mop_location(mv, finish); i <= f; i++) + { + //int idx = get_mop_location(mv, start + i); + const Expression::Token &t = mv[i]; + + if (t.t != Expression::Token::OPERATOR) + { + continue; + } + + switch (t.v.o) + { + case Expression::Token::ADD: + case Expression::Token::SUB: + if (same_lvl_only && lvl) + { + break; + } + inner_op_ranks.push_back(0); + break; + case Expression::Token::MUL: + case Expression::Token::DIV: + if (same_lvl_only && lvl) + { + break; + } + inner_op_ranks.push_back(1); + break; + case Expression::Token::POW: + if (same_lvl_only && lvl) + { + break; + } + inner_op_ranks.push_back(2); + break; + case Expression::Token::OPA: + lvl++; + break; + case Expression::Token::CPA: + lvl--; + 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++) + { + 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)); + } +} + +static int same_inner_level_ops(const std::vector& tv, const std::vector &mp, const Range &r, const int outer_lvl) +{ + int first_op_inner_level = rank_op(tv[get_mop_location(tv, r.start)].v.o); + + for (int i = r.start; i <= r.finish; i++) + { + if (mp[i] != outer_lvl) + { + continue; + } + + if (first_op_inner_level != rank_op(tv[get_mop_location(tv, i)].v.o)) + { + return 1; + } + } + + return 0; +} + +static Expression::Token::Operator get_prior_mop(const std::vector& tv, const int location) +{ + for (int i = location - 1; i >= 0; i--) + { + if (tv[i].t == Expression::Token::OPERATOR + && tv[i].v.o != Expression::Token::OPA + && tv[i].v.o != Expression::Token::CPA) + { + return tv[i].v.o; + } + } + + return Expression::Token::ADD; +} + +static void open_brackets(std::vector& tv, const Range &r) +{ + if (Expression::Token::Operator po = get_prior_mop(tv, get_mop_location(tv, r.start)); po == Expression::Token::SUB || po == Expression::Token::DIV) + { + for (int i = r.start; i <= r.finish; i++) + { + Expression::Token &t = tv[get_mop_location(tv, i)]; + + switch (t.v.o) + { + case Expression::Token::ADD: + t.v.o = Expression::Token::SUB; + break; + case Expression::Token::SUB: + t.v.o = Expression::Token::ADD; + break; + case Expression::Token::MUL: + t.v.o = Expression::Token::DIV; + break; + case Expression::Token::DIV: + t.v.o = Expression::Token::MUL; + break; + default: + break; + } + } + } + + tv.erase(tv.begin() + get_mop_location(tv, r.start) - 2); + tv.erase(tv.begin() + get_mop_location(tv, r.finish) + 2); +} + +static void remove_extra_brackets(std::vector& tv) +{ + std::vector mp; + create_prios_vector(tv, mp); + + // for everything excluding level 0 + for (int current_prio = mp[get_max_index(mp)]; current_prio > 0; current_prio--) + { + mp.clear(); + create_prios_vector(tv, mp); + + std::vector ranges; + find_select_prio_op_ranges(mp, ranges, current_prio); + + for (int r_no = ranges.size() - 1; r_no >= 0; r_no--) + { + mp.clear(); + create_prios_vector(tv, mp); + + ranges.clear(); + find_select_prio_op_ranges(mp, ranges, current_prio); + + const Range &r = ranges[r_no]; + + if (same_inner_level_ops(tv, mp, r, current_prio)) + { + continue; + } + + int ps, pf; + find_parent_level_range(mp, ps, pf, r.start, r.finish); + + const Range parent_r(ps, pf); + + if (same_inner_level_ops(tv, mp, parent_r, current_prio - 1)) + { + continue; + } + + open_brackets(tv, r); + } + } +} + +static void process_remove_empty_brackets(std::vector& tv) { pr_debug("Pre-process: remove empty brackets"); for (int i = 0; i < tv.size() - 1; i++) @@ -52,47 +714,55 @@ void pre_process(std::vector& tv) i--; } } +} - pr_debug("Pre-process: unary minus"); - int change = 1; - while (change) +static int check_bracket_match(const std::vector& tv) +{ + int problem_cnt = 0; + std::stack s; + + for (int i = 0, l = tv.size(); i < l; i++) { - change = 0; - - for (int i = 0; i < tv.size() - 2; i++) + if (tv[i].t == Expression::Token::OPERATOR) { - if (tv[i].t == Expression::Token::OPERATOR - && tv[i].v.o != Expression::Token::CPA - && tv[i+1].t == Expression::Token::OPERATOR - && tv[i+1].v.o == Expression::Token::SUB - && (tv[i+2].t == Expression::Token::CONST - || tv[i+2].t == Expression::Token::VAR - || (tv[i+2].t == Expression::Token::OPERATOR - && tv[i+2].v.o == Expression::Token::OPA))) + switch (tv[i].v.o) { - std::vector highlight; - - tv.insert(tv.begin() + i + 1, Expression::Token(0.0)); - tv.insert(tv.begin() + i + 1, Expression::Token(Expression::Token::OPA)); - highlight.emplace_back(add_bracket_to(tv, i + 3, 1)); - - highlight.emplace(highlight.begin(), i+2); - highlight.emplace(highlight.begin(), i+1); - Parser::print_math_vector(tv, highlight); - - i += 4; - - change++; + case Expression::Token::OPA: + s.push(i); + break; + case Expression::Token::CPA: + if (s.size()) + { + s.pop(); + } + else + { + pr_warn("Missing opening bracket at token " << i); + problem_cnt++; + highlight_issue(tv, i); + } + break; + default: + break; } } } + + for (int i = 0, l = s.size(); i < l; i++) + { + problem_cnt++; + pr_warn("Opening bracket at token " << s.top() << " expected a closing bracket, but none found"); + highlight_issue(tv, s.top()); + s.pop(); + } + + return problem_cnt; } -int check_syntax(const std::vector& tv) +static int check_start_finish_validity(const std::vector& tv) { int problem_cnt = 0; - // check start and finish validity if (tv.size()) { int pc = problem_cnt; @@ -159,7 +829,13 @@ int check_syntax(const std::vector& tv) } } - // check token type sequence + return problem_cnt; +} + +static int check_token_type_sequence(const std::vector& tv) +{ + int problem_cnt = 0; + if (tv.size() > 1) { for (int i = 0, l = tv.size() - 1, pc; pc = problem_cnt, i < l; i++) @@ -295,540 +971,203 @@ int check_syntax(const std::vector& tv) } } - // check bracket matching - { - std::stack s; - - for (int i = 0, l = tv.size(); i < l; i++) - { - if (tv[i].t == Expression::Token::OPERATOR) - { - switch (tv[i].v.o) - { - case Expression::Token::OPA: - s.push(i); - break; - case Expression::Token::CPA: - if (s.size()) - { - s.pop(); - } - else - { - pr_warn("Missing opening bracket at token " << i); - problem_cnt++; - highlight_issue(tv, i); - } - break; - default: - break; - } - } - } - - for (int i = 0, l = s.size(); i < l; i++) - { - problem_cnt++; - pr_warn("Opening bracket at token " << s.top() << " expected a closing bracket, but none found"); - highlight_issue(tv, s.top()); - s.pop(); - } - } - return problem_cnt; } -// get mop = Math OPerator location (=absolute index in std::vector) -// mapper of 'priority vector index' -> 'token vector index' -static int get_mop_location(const std::vector& v, int position) +static void process_unary_minus(std::vector& tv) { - 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; -} + pr_debug("Pre-process: unary minus"); -static int get_left_location(const std::vector& v, int location) -{ - for (int i = location - 1; i >= 0; i--) + int change = 1; + while (change) { - if (v[i].t != Expression::Token::OPERATOR && v[i].t != Expression::Token::NAT) + change = 0; + + for (int i = 0; i < tv.size() - 2; i++) { - 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_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 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, - std::vector& cv, - 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); - - std::vector hl; - hl.emplace_back(left_location); - hl.emplace_back(location); - hl.emplace_back(right_location); - Parser::print_math_vector(mv, hl); - - Expression::Token &o = mv[location], - &l = mv[left_location], - &r = mv[right_location]; - -#if LAB2_EXCLUDE_COMPTIME_OP_WRITES == 1 - if (l.t == Expression::Token::CONST && r.t == Expression::Token::CONST) - { - pr_debug("CONST folding"); - - switch (o.v.o) - { - case Expression::Token::ADD: - o.v.d = l.v.d + r.v.d; - break; - case Expression::Token::SUB: - o.v.d = l.v.d - r.v.d; - break; - case Expression::Token::MUL: - o.v.d = l.v.d * r.v.d; - break; - case Expression::Token::DIV: - o.v.d = l.v.d / r.v.d; - break; - case Expression::Token::POW: - o.v.d = std::pow(l.v.d, r.v.d); - break; - default: - pr_warn("Impossible operator, this is a bug!"); - break; - } - - l.t = Expression::Token::NAT; - r.t = Expression::Token::NAT; - o.t = Expression::Token::CONST; - - // sync &cv operator - cv[location].t = Expression::Token::CONST; - cv[location].v.d = o.v.d; - } - else - { -#endif - 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; -#if LAB2_EXCLUDE_COMPTIME_OP_WRITES == 1 - } -#endif - - // update mp - mp.erase(mp.begin() + position, mp.begin() + position + 1); -} - -static int 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) + if (tv[i].t == Expression::Token::OPERATOR + && tv[i].v.o != Expression::Token::CPA + && tv[i+1].t == Expression::Token::OPERATOR + && tv[i+1].v.o == Expression::Token::SUB + && (tv[i+2].t == Expression::Token::CONST + || tv[i+2].t == Expression::Token::VAR + || (tv[i+2].t == Expression::Token::OPERATOR + && tv[i+2].v.o == Expression::Token::OPA))) { - if (tv[i].v.o == Expression::Token::CPA) - { - lv++; - } + std::vector highlight; - if (!lv) - { - tv.insert(tv.begin() + i + 1, Expression::Token(Expression::Token::OPA)); - return i + 1; - } + tv.insert(tv.begin() + i + 1, Expression::Token(0.0)); + tv.insert(tv.begin() + i + 1, Expression::Token(Expression::Token::OPA)); + highlight.emplace_back(add_bracket_to(tv, i + 3, 1)); - if (tv[i].v.o == Expression::Token::OPA) - { - lv--; - } - } - } + highlight.emplace(highlight.begin(), i+2); + highlight.emplace(highlight.begin(), i+1); + Parser::print_math_vector(tv, highlight); - tv.insert(tv.begin(), Expression::Token(Expression::Token::OPA)); - return 0; - } - else if (direction == 1) - { - for (; i < l; i++) - { - if (tv[i].t == Expression::Token::OPERATOR) - { - if (tv[i].v.o == Expression::Token::OPA) - { - lv++; - } + i += 4; - if (!lv) - { - tv.insert(tv.begin() + i, Expression::Token(Expression::Token::CPA)); - return i; - } - - if (tv[i].v.o == Expression::Token::CPA) - { - lv--; - } - } - } - - tv.emplace_back(Expression::Token::CPA); - return i; - } - else - { - pr_warn("Invalid direction given, this is a big bug!"); - return -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) - { - switch (tv[i].v.o) - { - case Expression::Token::OPA: - cp++; - break; - case Expression::Token::CPA: - cp--; - break; - case Expression::Token::ADD: - case Expression::Token::SUB: - case Expression::Token::MUL: - case Expression::Token::DIV: - case Expression::Token::POW: - pv.emplace_back(cp); - break; - default: - pr_warn("Token vector has broken operator at " << i); - break; + change++; } } } } -static void find_top_prio_op_range(const std::vector& mp, int& start, int& finish) +// rl - relative level (outer priority) +// ip - inner priority +static int correct_operation_priorities(std::vector& tv, int op, int ip) { - for (int i = 0, l = mp.size(), prio = -1; i < l; i++) + int corrections = 0; + + for (int i = 0, same_lvl_op_cnt = -1, relative_level = -op; i < tv.size(); i++) { - if (mp[i] > prio) + Expression::Token& tok = tv[i]; + + if (tok.t == Expression::Token::OPERATOR) { - prio = mp[i]; - start = finish = i; - } - else if (mp[i] == prio && finish == i - 1) - { - finish = i; - } - } -} - -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, i); - } - 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++) - { - 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) + if (tok.v.o == Expression::Token::OPA) { - lvl = 1; - inner_top_ops.clear(); + relative_level++; } - - if (lvl == 1) - inner_top_ops.push_back(i); - - break; - case Expression::Token::POW: - if (lvl < 2) + else if (tok.v.o == Expression::Token::CPA) { - lvl = 2; - inner_top_ops.clear(); + relative_level--; + + if (relative_level < 0) + { + same_lvl_op_cnt = -1; + } } + else if (relative_level == 0) + { + // same operation inner priority + int target_op; + switch (ip) + { + case 0: + target_op = tok.v.o == Expression::Token::SUB; + break; + case 1: + target_op = tok.v.o == Expression::Token::DIV; + break; + } - if (lvl == 2) - inner_top_ops.push_back(i); + int same_op_ip; + switch (ip) + { + case 0: + same_op_ip = tok.v.o == Expression::Token::ADD || tok.v.o == Expression::Token::SUB; + break; + case 1: + same_op_ip = tok.v.o == Expression::Token::MUL || tok.v.o == Expression::Token::DIV; + break; + } - break; - default: - pr_warn("Operator is unrankable"); - break; + if (same_op_ip) + { + same_lvl_op_cnt++; + + if (same_lvl_op_cnt >= 1 && target_op) + { + same_lvl_op_cnt = 0; + + corrections++; + + switch (ip) + { + case 0: + tok.v.o = Expression::Token::ADD; + break; + case 1: + tok.v.o = Expression::Token::MUL; + break; + } + + // inverse order to keep location valid between calls + std::vector highlight_locations; + highlight_locations.emplace_back(i+1); + highlight_locations.emplace_back(add_cpa_before_le_io(tv, i) + 1); + highlight_locations.emplace(highlight_locations.begin(), add_opa_after_le_io(tv, i)); + Parser::print_math_vector(tv, highlight_locations); + + // advance one step to compensate for inserted left bracket + i++; + + // elevate one level to compensate for new brackets + relative_level++; + } + } + } } } + + return corrections; } -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 post_process(std::vector& tv) +static int post_process(std::vector& tv) { pr_debug("Post processing:"); Parser::print_math_vector(tv); + int total_corrections = 0; + // global prio evaluation std::vector mp; create_prios_vector(tv, mp); if (mp.size() == 0) { - return; + return total_corrections; } for (int current_prio_level = mp[get_max_index(mp)]; current_prio_level >= 0; current_prio_level--) { - int corrections = 1; - int relative_level = -current_prio_level; + int corrections = -1; while (corrections) { - corrections = 0; + total_corrections += corrections = correct_operation_priorities(tv, current_prio_level, 1); + } - int same_op_cnt = -1; - for (int i = 0; i < tv.size(); i++) - { - Expression::Token& tok = tv[i]; + corrections = -1; - if (tok.t == Expression::Token::OPERATOR) - { - if (tok.v.o == Expression::Token::OPA) - { - relative_level++; - } - else if (tok.v.o == Expression::Token::CPA) - { - relative_level--; - } - - if (relative_level < 0) - { - same_op_cnt = -1; - } - else if ((tok.v.o == Expression::Token::SUB || tok.v.o == Expression::Token::DIV) && !relative_level) - { - 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 - std::vector highlight_locations; - highlight_locations.emplace_back(i+1); - highlight_locations.emplace_back(add_bracket_to(tv, i, 1) + 1); - highlight_locations.emplace(highlight_locations.begin(), add_bracket_to(tv, i, -1)); - - // advance one step to compensate for inserted left bracket - i++; - - // elevate one level to compensate for new brackets - relative_level++; - - Parser::print_math_vector(tv, highlight_locations); - } - } - } - } + while (corrections) + { + total_corrections += corrections = correct_operation_priorities(tv, current_prio_level, 0); } } + + return total_corrections; +} + +int prepare_token_vector(std::vector& tv) +{ + process_remove_empty_brackets(tv); + + if (check_bracket_match(tv)) + { + return 1; + } + + process_unary_minus(tv); + + if (check_start_finish_validity(tv)) + { + return 1; + } + + if (check_token_type_sequence(tv)) + { + return 1; + } + + //for (int corrs = -1; corrs; ) + //{ + remove_extra_brackets(tv); + (void) post_process(tv); + remove_extra_brackets(tv); + //} + + return 0; } std::vector build_op_vector(const std::vector& tv) @@ -861,12 +1200,20 @@ std::vector build_op_vector(const std::vector operator_weights; weight_operators(operator_weights, mv, inner_top_ops, start); - write_operation(ov, cv, mv, mp, start + inner_top_ops[get_min_index(operator_weights)]); + if (write_operation(ov, cv, mv, mp, start + inner_top_ops[get_min_index(operator_weights)])) + { + pr_warn("Stopping"); + goto finish; + } finish--; } // process final operation w/out running selection algorithm - write_operation(ov, cv, mv, mp, start); + if (write_operation(ov, cv, mv, mp, start)) + { + pr_warn("Stopping"); + goto finish; + } } pr_debug("Final value:"); @@ -906,6 +1253,7 @@ std::vector build_op_vector(const std::vector o = Parser::tokenize_input("(1**5 * (1-2-3-4-5-6-7-8))"); - Syntax::post_process(o); + if (Syntax::prepare_token_vector(o)) + { + return 1; + } std::vector ov = Syntax::build_op_vector(o); return 0;