#include #include "sciteco.h" #include "undo.h" #include "expressions.h" Expressions expressions; void Expressions::set_num_sign(gint sign) { undo.push_var(num_sign); num_sign = sign; } void Expressions::set_radix(gint r) { undo.push_var(radix); radix = r; } gint64 Expressions::push(gint64 number) { while (operators.items() && operators.peek() == OP_NEW) pop_op(); push(OP_NUMBER); if (num_sign < 0) { set_num_sign(1); number *= -1; } numbers.undo_pop(); return numbers.push(number); } gint64 Expressions::pop_num(int index) { gint64 n = 0; pop_op(); if (numbers.items() > 0) { n = numbers.pop(index); numbers.undo_push(n, index); } return n; } gint64 Expressions::pop_num_calc(int index, gint64 imply) { eval(); if (num_sign < 0) set_num_sign(1); return args() > 0 ? pop_num(index) : imply; } gint64 Expressions::add_digit(gchar digit) { gint64 n = args() > 0 ? pop_num() : 0; return push(n*radix + (n < 0 ? -1 : 1)*(digit - '0')); } Expressions::Operator Expressions::push(Expressions::Operator op) { operators.undo_pop(); return operators.push(op); } Expressions::Operator Expressions::push_calc(Expressions::Operator op) { int first = first_op(); /* calculate if op has lower precedence than op on stack */ if (first && operators.peek(first) <= op) calc(); return push(op); } Expressions::Operator Expressions::pop_op(int index) { Operator op = OP_NIL; if (operators.items() > 0) { op = operators.pop(index); operators.undo_push(op, index); } return op; } void Expressions::calc(void) { gint64 result; gint64 vright = pop_num(); Operator op = pop_op(); gint64 vleft = pop_num(); switch (op) { case OP_POW: for (result = 1; vright--; result *= vleft); break; case OP_MUL: result = vleft * vright; break; case OP_DIV: result = vleft / vright; break; case OP_MOD: result = vleft % vright; break; case OP_ADD: result = vleft + vright; break; case OP_SUB: result = vleft - vright; break; case OP_AND: result = vleft & vright; break; case OP_OR: result = vleft | vright; break; default: /* shouldn't happen */ g_assert(false); } push(result); } void Expressions::eval(bool pop_brace) { for (;;) { gint n = first_op(); Operator op; if (n < 2) break; op = operators.peek(n); if (op == OP_LOOP) break; if (op == OP_BRACE) { if (pop_brace) pop_op(n); break; } calc(); } } int Expressions::args(void) { int n = 0; int items = operators.items(); while (n < items && operators.peek(n+1) == OP_NUMBER) n++; return n; } int Expressions::find_op(Operator op) { int items = operators.items(); for (int i = 1; i <= items; i++) if (operators.peek(i) == op) return i; return 0; } int Expressions::first_op(void) { int items = operators.items(); for (int i = 1; i <= items; i++) { switch (operators.peek(i)) { case OP_NUMBER: case OP_NEW: break; default: return i; } } return 0; } void Expressions::discard_args(void) { eval(); for (int i = args(); i; i--) pop_num_calc(); }