diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-12-04 17:29:01 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-12-04 22:07:08 +0100 |
commit | d8a316514c03d85b771a9dce4a8a51b875d955b3 (patch) | |
tree | 8966c29db767a155848f6d90f76771ce5b9de32e /src/goto.cpp | |
parent | b120616b6da52e951097f69ad267de06081d218a (diff) | |
download | sciteco-d8a316514c03d85b771a9dce4a8a51b875d955b3.tar.gz |
autoconf preparation: move everything into src/ subdir
Diffstat (limited to 'src/goto.cpp')
-rw-r--r-- | src/goto.cpp | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/src/goto.cpp b/src/goto.cpp new file mode 100644 index 0000000..7af5152 --- /dev/null +++ b/src/goto.cpp @@ -0,0 +1,147 @@ +#include <glib.h> +#include <glib/gprintf.h> + +#include "sciteco.h" +#include "expressions.h" +#include "parser.h" +#include "undo.h" +#include "goto.h" + +namespace States { + StateLabel label; + StateGotoCmd gotocmd; +} + +namespace Goto { + GotoTable *table = NULL; + gchar *skip_label = NULL; +} + +gint +GotoTable::remove(gchar *name) +{ + gint existing_pc = -1; + + Label label(name); + Label *existing = (Label *)RBTree::find(&label); + + if (existing) { + existing_pc = existing->pc; + RBTree::remove(existing); + delete existing; + } + + return existing_pc; +} + +gint +GotoTable::find(gchar *name) +{ + Label label(name); + Label *existing = (Label *)RBTree::find(&label); + + return existing ? existing->pc : -1; +} + +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 + dump(); +#endif + + return existing_pc; +} + +#ifdef DEBUG +void +GotoTable::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"); +} +#endif + +/* + * Command states + */ + +StateLabel::StateLabel() : State() +{ + transitions['\0'] = this; +} + +State * +StateLabel::custom(gchar chr) throw (Error) +{ + if (chr == '!') { + Goto::table->undo_set(strings[0], + Goto::table->set(strings[0], macro_pc)); + + if (!g_strcmp0(strings[0], Goto::skip_label)) { + g_free(undo.push_str(Goto::skip_label)); + Goto::skip_label = NULL; + + undo.push_var(mode) = MODE_NORMAL; + } + + g_free(undo.push_str(strings[0])); + strings[0] = NULL; + + return &States::start; + } + + String::append(undo.push_str(strings[0]), chr); + return this; +} + +State * +StateGotoCmd::done(const gchar *str) throw (Error) +{ + gint64 value; + gchar **labels; + + BEGIN_EXEC(&States::start); + + value = expressions.pop_num_calc(); + labels = g_strsplit(str, ",", -1); + + if (value > 0 && value <= g_strv_length(labels) && *labels[value-1]) { + gint pc = Goto::table->find(labels[value-1]); + + if (pc >= 0) { + macro_pc = pc; + } else { + /* skip till label is defined */ + undo.push_str(Goto::skip_label); + Goto::skip_label = g_strdup(labels[value-1]); + undo.push_var(mode) = MODE_PARSE_ONLY_GOTO; + } + } + + g_strfreev(labels); + return &States::start; +} |