aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-08 01:20:37 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-08 01:20:37 +0100
commit7dbb2831b81ff0174054d30b1fc105b2113c272d (patch)
treefde5c878e2c9a89e6f41c8535034e1b16927c154
parent1707fcabca80e2e664bef9c02ec5cc9d793ce37b (diff)
downloadsciteco-7dbb2831b81ff0174054d30b1fc105b2113c272d.tar.gz
added support for labels, including the goto label table
* uses BSD tree macros, might later be abstracted to a C++ table class
-rw-r--r--Makefile3
-rw-r--r--cmdline.cpp2
-rw-r--r--goto.cpp193
-rw-r--r--goto.h14
-rw-r--r--parser.cpp14
-rw-r--r--parser.h18
-rw-r--r--sciteco.h5
-rw-r--r--undo.h37
8 files changed, 272 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index e02134e..9f380eb 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,8 @@ LDFLAGS:=$(GTK_LDFLAGS) $(SCI_LDFLAGS)
all : sciteco
-sciteco : main.o cmdline.o undo.o expressions.o parser.o
+sciteco : main.o cmdline.o undo.o expressions.o \
+ parser.o goto.o
$(CXX) -o $@ $^ $(LDFLAGS)
clean:
diff --git a/cmdline.cpp b/cmdline.cpp
index 2135f9a..e0159ec 100644
--- a/cmdline.cpp
+++ b/cmdline.cpp
@@ -4,6 +4,8 @@
#include <glib/gprintf.h>
#include "sciteco.h"
+#include "parser.h"
+#include "undo.h"
static gchar *macro_echo(const gchar *macro, const gchar *prefix = "");
diff --git a/goto.cpp b/goto.cpp
new file mode 100644
index 0000000..f183ca1
--- /dev/null
+++ b/goto.cpp
@@ -0,0 +1,193 @@
+#include <bsd/sys/tree.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+
+#include "sciteco.h"
+#include "parser.h"
+#include "undo.h"
+#include "goto.h"
+
+static gchar *skip_label = NULL;
+
+class GotoTable {
+ class UndoTokenSet : public UndoToken {
+ GotoTable *table;
+
+ gchar *name;
+ gint pc;
+
+ public:
+ UndoTokenSet(GotoTable *_table, gchar *_name, gint _pc = -1)
+ : table(_table), name(g_strdup(_name)), pc(_pc) {}
+ ~UndoTokenSet()
+ {
+ g_free(name);
+ }
+
+ void
+ run(void)
+ {
+ table->set(name, pc);
+ g_free(name);
+ name = NULL;
+#if 0
+ table->dump();
+#endif
+ }
+ };
+
+ class Label {
+ public:
+ RB_ENTRY(Label) nodes;
+
+ gchar *name;
+ gint pc;
+
+ Label(gchar *_name, gint _pc = -1)
+ : name(g_strdup(_name)), pc(_pc) {}
+ ~Label()
+ {
+ g_free(name);
+ }
+
+ static inline int
+ cmp(Label *l1, Label *l2)
+ {
+ return g_strcmp0(l1->name, l2->name);
+ }
+ };
+
+ RB_HEAD(Table, Label) head;
+
+ RB_GENERATE(Table, Label, nodes, Label::cmp);
+
+public:
+ GotoTable()
+ {
+ RB_INIT(&head);
+ }
+
+ ~GotoTable()
+ {
+ clear();
+ }
+
+ gint
+ remove(gchar *name)
+ {
+ gint existing_pc = -1;
+
+ Label label(name);
+ Label *existing = RB_FIND(Table, &head, &label);
+
+ if (existing) {
+ existing_pc = existing->pc;
+ RB_REMOVE(Table, &head, existing);
+ delete existing;
+ }
+
+ return existing_pc;
+ }
+
+ gint
+ find(gchar *name)
+ {
+ Label label(name);
+ Label *existing = RB_FIND(Table, &head, &label);
+
+ return existing ? existing->pc : -1;
+ }
+
+ gint
+ set(gchar *name, gint pc)
+ {
+ if (pc < 0)
+ return remove(name);
+
+ Label *label = new Label(name, pc);
+ Label *existing;
+ gint existing_pc = -1;
+
+ existing = RB_FIND(Table, &head, label);
+ if (existing) {
+ existing_pc = existing->pc;
+ g_free(existing->name);
+ existing->name = label->name;
+ existing->pc = label->pc;
+
+ label->name = NULL;
+ delete label;
+ } else {
+ RB_INSERT(Table, &head, label);
+ }
+
+#if 0
+ dump();
+#endif
+ return existing_pc;
+ }
+
+ inline void
+ undo_set(gchar *name, gint pc = -1)
+ {
+ undo.push(new UndoTokenSet(this, name, pc));
+ }
+
+ void
+ clear(void)
+ {
+ Label *cur;
+
+ while ((cur = RB_MIN(Table, &head))) {
+ RB_REMOVE(Table, &head, cur);
+ delete cur;
+ }
+ }
+
+#if 0
+ void
+ dump(void)
+ {
+ Label *cur;
+
+ RB_FOREACH(cur, Table, &head)
+ g_printf("table[\"%s\"] = %d\n", cur->name, cur->pc);
+ g_printf("---END---\n");
+ }
+#endif
+};
+
+static GotoTable table;
+
+State *
+StateLabel::custom(gchar chr)
+{
+ gchar *new_str;
+
+ if (chr == '!') {
+ table.undo_set(strings[0], table.set(strings[0], macro_pc));
+
+ if (!g_strcmp0(strings[0], skip_label)) {
+ undo.push_str(skip_label);
+ g_free(skip_label);
+ skip_label = NULL;
+
+ undo.push_var<Mode>(mode);
+ mode = MODE_NORMAL;
+ }
+
+ undo.push_str(strings[0]);
+ g_free(strings[0]);
+ strings[0] = NULL;
+
+ return &states.start;
+ }
+
+ undo.push_str(strings[0]);
+ new_str = g_strdup_printf("%s%c", strings[0] ? : "", chr);
+ g_free(strings[0]);
+ strings[0] = new_str;
+
+ return this;
+}
diff --git a/goto.h b/goto.h
new file mode 100644
index 0000000..87324d8
--- /dev/null
+++ b/goto.h
@@ -0,0 +1,14 @@
+#ifndef __GOTO_H
+#define __GOTO_H
+
+#include <glib.h>
+
+#include "sciteco.h"
+#include "parser.h"
+
+class StateLabel : public State {
+private:
+ State *custom(gchar chr);
+};
+
+#endif
diff --git a/parser.cpp b/parser.cpp
index afcff41..4519c75 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -8,9 +8,7 @@
gint macro_pc = 0;
-static struct {
- StateStart start;
-} states;
+States states;
static State *current_state = &states.start;
@@ -19,10 +17,7 @@ static struct {
bool at;
} modifiers = {false, false};
-static enum Mode {
- MODE_NORMAL = 0,
- MODE_PARSE_ONLY
-} mode = MODE_NORMAL;
+enum Mode mode = MODE_NORMAL;
/* FIXME: perhaps integrate into Mode */
static bool skip_else = false;
@@ -34,6 +29,8 @@ static bool skip_else = false;
static gint nest_level = 0;
+gchar *strings[2] = {NULL, NULL};
+
bool
macro_execute(const gchar *macro)
{
@@ -113,6 +110,8 @@ StateStart::StateStart() : State()
{
transitions['\0'] = this;
init(" \r\n\v");
+
+ transitions['!'] = &states.label;
}
void
@@ -426,4 +425,3 @@ StateStart::custom(gchar chr)
return this;
}
-
diff --git a/parser.h b/parser.h
index 007b942..3eba297 100644
--- a/parser.h
+++ b/parser.h
@@ -50,4 +50,22 @@ private:
State *custom(gchar chr);
};
+#include "goto.h"
+
+extern gint macro_pc;
+
+extern struct States {
+ StateStart start;
+ StateLabel label;
+} states;
+
+extern enum Mode {
+ MODE_NORMAL = 0,
+ MODE_PARSE_ONLY
+} mode;
+
+extern gchar *strings[2];
+
+bool macro_execute(const gchar *macro);
+
#endif
diff --git a/sciteco.h b/sciteco.h
index b0c2c84..88b41cc 100644
--- a/sciteco.h
+++ b/sciteco.h
@@ -8,10 +8,7 @@
#include <Scintilla.h>
-#include "undo.h"
-
extern gchar *cmdline;
-extern gint macro_pc;
void message_display(GtkMessageType type,
const gchar *fmt, ...) G_GNUC_PRINTF(2, 3);
@@ -21,8 +18,6 @@ void cmdline_display(const gchar *cmdline);
sptr_t editor_msg(unsigned int iMessage, uptr_t wParam = 0, sptr_t lParam = 0);
-bool macro_execute(const gchar *macro);
-
#define IS_CTL(C) ((C) < ' ')
#define CTL_ECHO(C) ((C) | 0x40)
diff --git a/undo.h b/undo.h
index 17a8ba8..aeefb09 100644
--- a/undo.h
+++ b/undo.h
@@ -4,6 +4,7 @@
#include <bsd/sys/queue.h>
#include <glib.h>
+#include <glib/gprintf.h>
#include <Scintilla.h>
@@ -48,6 +49,31 @@ public:
}
};
+class UndoTokenString : public UndoToken {
+ gchar **ptr;
+ gchar *str;
+
+public:
+ UndoTokenString(gchar *&variable, gchar *_str)
+ : UndoToken(), ptr(&variable)
+ {
+ str = _str ? g_strdup(_str) : NULL;
+ }
+
+ ~UndoTokenString()
+ {
+ g_free(str);
+ }
+
+ void
+ run(void)
+ {
+ g_free(*ptr);
+ *ptr = str;
+ str = NULL;
+ }
+};
+
extern class UndoStack {
SLIST_HEAD(undo_head, UndoToken) head;
@@ -86,6 +112,17 @@ public:
push_var<Type>(variable, variable);
}
+ inline void
+ push_str(gchar *&variable, gchar *str)
+ {
+ push(new UndoTokenString(variable, str));
+ }
+ inline void
+ push_str(gchar *&variable)
+ {
+ push_str(variable, variable);
+ }
+
void pop(gint pos);
} undo;