aboutsummaryrefslogtreecommitdiffhomepage
path: root/goto.cpp
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-19 22:12:16 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-20 06:07:33 +0100
commit90f203bff189706c2dec34482475b89d0a232597 (patch)
treea13c16ca7f73b779f941e0543bcff81d97e84b4d /goto.cpp
parentb804417f36ef398f1223e439fd5ac9f2ade046eb (diff)
downloadsciteco-90f203bff189706c2dec34482475b89d0a232597.tar.gz
make goto tables local to macro invocation: they are declared on the C++ callstack since macro invocations result in nested macro_execute() calls
otherwise a macro could set labels with program counters which are invalid in other macros/the command line
Diffstat (limited to 'goto.cpp')
-rw-r--r--goto.cpp183
1 files changed, 55 insertions, 128 deletions
diff --git a/goto.cpp b/goto.cpp
index c64a896..0db7a2b 100644
--- a/goto.cpp
+++ b/goto.cpp
@@ -1,5 +1,3 @@
-#include <bsd/sys/tree.h>
-
#include <glib.h>
#include <glib/gprintf.h>
@@ -7,7 +5,6 @@
#include "expressions.h"
#include "parser.h"
#include "undo.h"
-#include "rbtree.h"
#include "goto.h"
namespace States {
@@ -17,146 +14,75 @@ namespace States {
static gchar *skip_label = NULL;
-class GotoTable : public RBTree {
- 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);
-#ifdef DEBUG
- table->dump();
-#endif
- }
- };
-
- class Label : public RBEntry {
- public:
- gchar *name;
- gint pc;
-
- Label(gchar *_name, gint _pc = -1)
- : name(g_strdup(_name)), pc(_pc) {}
- ~Label()
- {
- g_free(name);
- }
-
- int
- operator <(RBEntry &l2)
- {
- return g_strcmp0(name, ((Label &)l2).name);
- }
- };
-
-public:
- GotoTable() : RBTree() {}
-
- gint
- remove(gchar *name)
- {
- gint existing_pc = -1;
-
- Label label(name);
- Label *existing = (Label *)RBTree::find(&label);
+GotoTable *goto_table = NULL;
- if (existing) {
- existing_pc = existing->pc;
- RBTree::remove(existing);
- delete existing;
- }
-
- return existing_pc;
- }
+gint
+GotoTable::remove(gchar *name)
+{
+ gint existing_pc = -1;
- gint
- find(gchar *name)
- {
- Label label(name);
- Label *existing = (Label *)RBTree::find(&label);
+ Label label(name);
+ Label *existing = (Label *)RBTree::find(&label);
- return existing ? existing->pc : -1;
+ if (existing) {
+ existing_pc = existing->pc;
+ RBTree::remove(existing);
+ delete existing;
}
- 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 = (Label *)RBTree::find(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 {
- RBTree::insert(label);
- }
-
-#ifdef DEBUG
- dump();
-#endif
-
- return existing_pc;
- }
+ return existing_pc;
+}
- inline void
- undo_set(gchar *name, gint pc = -1)
- {
- undo.push(new UndoTokenSet(this, name, pc));
- }
+gint
+GotoTable::find(gchar *name)
+{
+ Label label(name);
+ Label *existing = (Label *)RBTree::find(&label);
- void
- clear(void)
- {
- Label *cur;
+ return existing ? existing->pc : -1;
+}
- while ((cur = (Label *)RBTree::min())) {
- RBTree::remove(cur);
- delete cur;
- }
+gint
+GotoTable::set(gchar *name, gint pc)
+{
+ if (pc < 0)
+ return remove(name);
+
+ Label *label = new Label(name, pc);
+ Label *existing;
+ gint existing_pc = -1;
+
+ existing = (Label *)RBTree::find(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 {
+ RBTree::insert(label);
}
#ifdef DEBUG
- void
- dump(void)
- {
- for (Label *cur = (Label *)RBTree::min();
- cur != NULL;
- cur = (Label *)cur->next())
- g_printf("table[\"%s\"] = %d\n", cur->name, cur->pc);
- g_printf("---END---\n");
- }
+ dump();
#endif
-};
-static GotoTable table;
+ return existing_pc;
+}
+#ifdef DEBUG
void
-goto_table_clear(void)
+GotoTable::dump(void)
{
- table.clear();
+ for (Label *cur = (Label *)RBTree::min();
+ cur != NULL;
+ cur = (Label *)cur->next())
+ g_printf("table[\"%s\"] = %d\n", cur->name, cur->pc);
+ g_printf("---END---\n");
}
+#endif
/*
* Command states
@@ -173,7 +99,8 @@ StateLabel::custom(gchar chr) throw (Error)
gchar *new_str;
if (chr == '!') {
- table.undo_set(strings[0], table.set(strings[0], macro_pc));
+ goto_table->undo_set(strings[0],
+ goto_table->set(strings[0], macro_pc));
if (!g_strcmp0(strings[0], skip_label)) {
undo.push_str(skip_label);
@@ -211,7 +138,7 @@ StateGotoCmd::done(const gchar *str) throw (Error)
labels = g_strsplit(str, ",", -1);
if (value > 0 && value <= g_strv_length(labels) && *labels[value-1]) {
- gint pc = table.find(labels[value-1]);
+ gint pc = goto_table->find(labels[value-1]);
if (pc >= 0) {
macro_pc = pc;