aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/expressions.cpp
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-12-04 17:29:01 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-12-04 22:07:08 +0100
commitd8a316514c03d85b771a9dce4a8a51b875d955b3 (patch)
tree8966c29db767a155848f6d90f76771ce5b9de32e /src/expressions.cpp
parentb120616b6da52e951097f69ad267de06081d218a (diff)
downloadsciteco-d8a316514c03d85b771a9dce4a8a51b875d955b3.tar.gz
autoconf preparation: move everything into src/ subdir
Diffstat (limited to 'src/expressions.cpp')
-rw-r--r--src/expressions.cpp201
1 files changed, 201 insertions, 0 deletions
diff --git a/src/expressions.cpp b/src/expressions.cpp
new file mode 100644
index 0000000..ac06b43
--- /dev/null
+++ b/src/expressions.cpp
@@ -0,0 +1,201 @@
+#include <glib.h>
+
+#include "sciteco.h"
+#include "undo.h"
+#include "expressions.h"
+
+Expressions expressions;
+
+void
+Expressions::set_num_sign(gint sign)
+{
+ undo.push_var<gint>(num_sign);
+ num_sign = sign;
+}
+
+void
+Expressions::set_radix(gint r)
+{
+ undo.push_var<gint>(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();
+}