aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-07 07:22:35 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-07 07:22:35 +0100
commit2ed38e4d01d73d62b29a28d7540ca515f9ff3b09 (patch)
tree58c2c07513946285ca3a514d364aae5cb1ebb4e8
parent8cd29b9b30400e4275f1a65744cd0b3c2669cc98 (diff)
downloadsciteco-2ed38e4d01d73d62b29a28d7540ca515f9ff3b09.tar.gz
expression stack based on THECO's ArithmeticStack
-rw-r--r--Makefile2
-rw-r--r--expressions.cpp184
-rw-r--r--expressions.h160
-rw-r--r--parser.cpp1
-rw-r--r--undo.cpp3
-rw-r--r--undo.h11
6 files changed, 355 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index 673debf..e02134e 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ LDFLAGS:=$(GTK_LDFLAGS) $(SCI_LDFLAGS)
all : sciteco
-sciteco : main.o cmdline.o parser.o undo.o
+sciteco : main.o cmdline.o undo.o expressions.o parser.o
$(CXX) -o $@ $^ $(LDFLAGS)
clean:
diff --git a/expressions.cpp b/expressions.cpp
new file mode 100644
index 0000000..1e48d3e
--- /dev/null
+++ b/expressions.cpp
@@ -0,0 +1,184 @@
+#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 (numbers.peek() == G_MAXINT64)
+ pop_num();
+
+ push(OP_NUMBER);
+
+ undo.push(new UndoTokenPop<gint64>(numbers));
+ return numbers.push(number);
+}
+
+gint64
+Expressions::pop_num(int index)
+{
+ gint64 n = G_MAXINT64;
+
+ pop_op();
+ if (numbers.items() > 0) {
+ n = numbers.pop(index);
+ undo.push(new UndoTokenPush<gint64>(numbers, n, index));
+ }
+
+ return n;
+}
+
+gint64
+Expressions::pop_num_calc(int index, gint64 imply)
+{
+ gint64 n = G_MAXINT64;
+
+ eval();
+ if (args() > 0)
+ n = pop_num(index);
+ if (n == G_MAXINT64)
+ n = imply;
+
+ if (num_sign < 0)
+ set_num_sign(1);
+
+ return n;
+}
+
+gint64
+Expressions::add_digit(gchar digit)
+{
+ gint64 n = 0;
+
+ if (args() > 0) {
+ n = pop_num();
+ if (n == G_MAXINT64)
+ n = 0;
+ }
+
+ return push(n*radix + num_sign*(digit - '0'));
+}
+
+Expressions::Operator
+Expressions::push(Expressions::Operator op)
+{
+ undo.push(new UndoTokenPop<Operator>(operators));
+ return operators.push(op);
+}
+
+Expressions::Operator
+Expressions::push_calc(Expressions::Operator op)
+{
+ /* calculate if op has lower precedence than op on stack */
+ if (operators.peek(first_op()) <= op)
+ calc();
+
+ return push(op);
+}
+
+Expressions::Operator
+Expressions::pop_op(int index)
+{
+ Operator op = OP_NIL;
+
+ if (operators.items() > 0) {
+ op = operators.pop(index);
+ undo.push(new UndoTokenPush<Operator>(operators, 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:
+ result = 1;
+ while (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)
+{
+ if (numbers.items() < 2)
+ return;
+
+ for (;;) {
+ gint n = first_op();
+ Operator op;
+
+ if (!n)
+ 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;
+}
+
+void
+Expressions::discard_args(void)
+{
+ eval();
+ for (int i = args(); i; i--)
+ pop_num_calc();
+}
diff --git a/expressions.h b/expressions.h
new file mode 100644
index 0000000..2ff9c1a
--- /dev/null
+++ b/expressions.h
@@ -0,0 +1,160 @@
+#ifndef __EXPRESSIONS_H
+#define __EXPRESSIONS_H
+
+#include <glib.h>
+
+#include "undo.h"
+
+template <typename Type>
+class ValueStack {
+ int size;
+
+ Type *stack;
+ Type *top;
+
+public:
+ ValueStack(int _size = 1024) : size(_size)
+ {
+ top = stack = new Type[size];
+ }
+
+ ~ValueStack()
+ {
+ delete stack;
+ }
+
+ inline int
+ items(void)
+ {
+ return (top - stack)/sizeof(Type);
+ }
+
+ inline Type &
+ push(Type value, int index = 1)
+ {
+ for (int i = -index + 1; i; i++)
+ top[i+1] = top[i];
+
+ top++;
+ return peek(index) = value;
+ }
+
+ inline Type
+ pop(int index = 1)
+ {
+ Type v = peek(index);
+
+ top--;
+ while (--index)
+ top[-index] = top[-index + 1];
+
+ return v;
+ }
+
+ inline Type &
+ peek(int index = 1)
+ {
+ return top[-index];
+ }
+};
+
+template <typename Type>
+class UndoTokenPush : public UndoToken {
+ ValueStack<Type> *stack;
+
+ Type value;
+ int index;
+
+public:
+ UndoTokenPush(ValueStack<Type> &_stack, Type _value, int _index = 1)
+ : stack(&_stack), value(_value), index(_index) {}
+
+ void
+ run(void)
+ {
+ stack->push(value, index);
+ }
+};
+
+template <typename Type>
+class UndoTokenPop : public UndoToken {
+ ValueStack<Type> *stack;
+
+ int index;
+
+public:
+ UndoTokenPop(ValueStack<Type> &_stack, int _index = 1)
+ : stack(&_stack), index(_index) {}
+
+ void
+ run(void)
+ {
+ stack->pop(index);
+ }
+};
+
+/*
+ * Arithmetic expression stacks
+ */
+extern class Expressions {
+ /* reflects also operator precedence */
+ enum Operator {
+ OP_NIL = 0,
+ OP_POW, // ^*
+ OP_MUL, // *
+ OP_DIV, // /
+ OP_MOD, // ^/
+ OP_ADD, // +
+ OP_SUB, // -
+ OP_AND, // &
+ OP_OR, // #
+ // pseudo operators:
+ OP_BRACE,
+ OP_LOOP,
+ OP_NUMBER
+ };
+
+ ValueStack<gint64> numbers;
+ ValueStack<Operator> operators;
+
+ gint num_sign;
+ gint radix;
+
+public:
+ Expressions() : num_sign(1), radix(10) {}
+
+ void set_num_sign(gint sign);
+ void set_radix(gint r);
+
+ gint64 push(gint64 number);
+
+ gint64 pop_num(int index = 1);
+ gint64 pop_num_calc(int index, gint64 imply);
+ inline gint64
+ pop_num_calc(int index = 1)
+ {
+ return pop_num_calc(index, num_sign);
+ }
+
+ gint64 add_digit(gchar digit);
+
+ Operator push(Operator op);
+ Operator push_calc(Operator op);
+
+ Operator pop_op(int index = 1);
+
+ void calc(void);
+
+ void eval(bool pop_brace = false);
+
+ int args(void);
+ inline int
+ first_op(void)
+ {
+ return args() + 1;
+ }
+
+ void discard_args(void);
+} expressions;
+
+#endif
diff --git a/parser.cpp b/parser.cpp
index 0b218ab..bd31734 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -2,6 +2,7 @@
#include <glib/gprintf.h>
#include "sciteco.h"
+#include "undo.h"
#include "parser.h"
gint macro_pc = 0;
diff --git a/undo.cpp b/undo.cpp
index f5fc81d..106f812 100644
--- a/undo.cpp
+++ b/undo.cpp
@@ -21,8 +21,7 @@ UndoTokenMessage::run(void)
void
UndoStack::push_msg(unsigned int iMessage, uptr_t wParam, sptr_t lParam)
{
- UndoToken *token = new UndoTokenMessage(iMessage, wParam, lParam);
- SLIST_INSERT_HEAD(&head, token, tokens);
+ push(new UndoTokenMessage(iMessage, wParam, lParam));
}
#if 0
diff --git a/undo.h b/undo.h
index 29ec70f..9c7ac5f 100644
--- a/undo.h
+++ b/undo.h
@@ -58,15 +58,20 @@ public:
}
~UndoStack();
+ inline void
+ push(UndoToken *token)
+ {
+ SLIST_INSERT_HEAD(&head, token, tokens);
+ }
+
void push_msg(unsigned int iMessage,
uptr_t wParam = 0, sptr_t lParam = 0);
template <typename Type>
- void
+ inline void
push_var(Type &variable, Type value)
{
- UndoToken *token = new UndoTokenVariable<Type>(variable, value);
- SLIST_INSERT_HEAD(&head, token, tokens);
+ push(new UndoTokenVariable<Type>(variable, value));
}
template <typename Type>