/*
* Copyright (C) 2012-2015 Robin Haberkorn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef __EXPRESSIONS_H
#define __EXPRESSIONS_H
#include
#include "undo.h"
#include "error.h"
namespace SciTECO {
template
class ValueStack {
class UndoTokenPush : public UndoTokenWithSize {
/*
* FIXME: saving the UndoStack for each undo taken
* wastes a lot of memory
*/
ValueStack *stack;
Type value;
guint index;
public:
UndoTokenPush(ValueStack *_stack,
Type _value, guint _index = 0)
: stack(_stack), value(_value), index(_index) {}
void
run(void)
{
stack->push(value, index);
}
};
class UndoTokenPop : public UndoTokenWithSize {
ValueStack *stack;
guint index;
public:
UndoTokenPop(ValueStack *_stack, guint _index = 0)
: stack(_stack), index(_index) {}
void
run(void)
{
stack->pop(index);
}
};
/** Beginning of stack area */
Type *stack;
/** End of stack area */
Type *stack_top;
/** Pointer to top element on stack */
Type *sp;
public:
ValueStack(gsize size = 1024)
{
stack = new Type[size];
/* stack grows to smaller addresses */
sp = stack_top = stack+size;
}
~ValueStack()
{
delete[] stack;
}
inline guint
items(void)
{
return stack_top - sp;
}
inline Type &
push(Type value, guint index = 0)
{
if (G_UNLIKELY(sp == stack))
throw Error("Stack overflow");
/* reserve space for new element */
sp--;
g_assert(items() > index);
/* move away elements after index (index > 0) */
for (guint i = 0; i < index; i++)
sp[i] = sp[i+1];
return sp[index] = value;
}
inline void
undo_push(Type value, guint index = 0)
{
undo.push(new UndoTokenPush(this, value, index));
}
inline Type
pop(guint index = 0)
{
/* peek() already asserts */
Type v = peek(index);
/* elements after index are moved to index (index > 0) */
while (index--)
sp[index+1] = sp[index];
/* free space of element to pop */
sp++;
return v;
}
inline void
undo_pop(guint index = 0)
{
undo.push(new UndoTokenPop(this, index));
}
inline Type &
peek(guint index = 0)
{
g_assert(items() > index);
return sp[index];
}
inline void
clear(void)
{
sp = stack_top;
}
};
/*
* Arithmetic expression stacks
*/
extern class Expressions {
public:
/* reflects also operator precedence */
enum Operator {
OP_NIL = 0,
OP_POW, // ^*
OP_MUL, // *
OP_DIV, // /
OP_MOD, // ^/
OP_ADD, // +
OP_SUB, // -
OP_AND, // &
OP_XOR, // ^#
OP_OR, // #
// pseudo operators:
OP_NEW,
OP_BRACE,
OP_LOOP,
OP_NUMBER
};
private:
ValueStack numbers;
ValueStack operators;
public:
Expressions() : num_sign(1), radix(10) {}
gint num_sign;
inline void
set_num_sign(gint sign)
{
undo.push_var(num_sign) = sign;
}
gint radix;
inline void
set_radix(gint r)
{
undo.push_var(radix) = r;
}
tecoInt push(tecoInt number);
/**
* Push characters of a C-string.
* Could be overloaded on push(tecoInt)
* but this confuses GCC.
*/
inline void
push_str(const gchar *str)
{
while (*str)
push(*str++);
}
inline tecoInt
peek_num(guint index = 0)
{
return numbers.peek(index);
}
tecoInt pop_num(guint index = 0);
tecoInt pop_num_calc(guint index, tecoInt imply);
inline tecoInt
pop_num_calc(guint index = 0)
{
return pop_num_calc(index, num_sign);
}
tecoInt add_digit(gchar digit);
Operator push(Operator op);
Operator push_calc(Operator op);
inline Operator
peek_op(guint index = 0)
{
return operators.peek(index);
}
Operator pop_op(guint index = 0);
void eval(bool pop_brace = false);
guint args(void);
void discard_args(void);
gint find_op(Operator op);
inline void
clear(void)
{
numbers.clear();
operators.clear();
}
const gchar *format(tecoInt number);
private:
void calc(void);
gint first_op(void);
} expressions;
} /* namespace SciTECO */
#endif