From 7dbb2831b81ff0174054d30b1fc105b2113c272d Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Thu, 8 Nov 2012 01:20:37 +0100 Subject: added support for labels, including the goto label table * uses BSD tree macros, might later be abstracted to a C++ table class --- goto.cpp | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 goto.cpp (limited to 'goto.cpp') 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 + +#include +#include + +#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_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; +} -- cgit v1.2.3