diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-11-07 07:22:35 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-11-07 07:22:35 +0100 |
commit | 2ed38e4d01d73d62b29a28d7540ca515f9ff3b09 (patch) | |
tree | 58c2c07513946285ca3a514d364aae5cb1ebb4e8 | |
parent | 8cd29b9b30400e4275f1a65744cd0b3c2669cc98 (diff) | |
download | sciteco-2ed38e4d01d73d62b29a28d7540ca515f9ff3b09.tar.gz |
expression stack based on THECO's ArithmeticStack
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | expressions.cpp | 184 | ||||
-rw-r--r-- | expressions.h | 160 | ||||
-rw-r--r-- | parser.cpp | 1 | ||||
-rw-r--r-- | undo.cpp | 3 | ||||
-rw-r--r-- | undo.h | 11 |
6 files changed, 355 insertions, 6 deletions
@@ -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 @@ -2,6 +2,7 @@ #include <glib/gprintf.h> #include "sciteco.h" +#include "undo.h" #include "parser.h" gint macro_pc = 0; @@ -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 @@ -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> |