aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2013-02-14 00:55:04 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2013-02-14 05:21:03 +0100
commit9cd71e16b30e2f0061a6d74421a5357333721a70 (patch)
treebb362c1ffed48fe9af5ca0cf70c38caacfca2e45
parent91ae87c7ab0c26a387eb42243e50baf0ded30250 (diff)
downloadsciteco-9cd71e16b30e2f0061a6d74421a5357333721a70.tar.gz
micro state machine for Q-Register specifications: allow long Q-Reg names
syntax is as follows: ["."]("#" CHR1 CHR2 | "{" STRING_BUILDING "}" | CHR1) * the short one/two char names are turned upper case, while no case folding is performed on verbose names
-rw-r--r--src/qregisters.cpp93
-rw-r--r--src/qregisters.h23
2 files changed, 100 insertions, 16 deletions
diff --git a/src/qregisters.cpp b/src/qregisters.cpp
index 6eea64f..7fb5b27 100644
--- a/src/qregisters.cpp
+++ b/src/qregisters.cpp
@@ -357,11 +357,85 @@ QRegisters::hook(Hook type)
globals["0"]->execute();
}
+void
+QRegSpecMachine::reset(void)
+{
+ MicroStateMachine::reset();
+ string_machine.reset();
+ undo.push_var(is_local) = false;
+ undo.push_var(nesting) = 0;
+ undo.push_str(name);
+ g_free(name);
+ name = NULL;
+}
+
+QRegister *
+QRegSpecMachine::input(gchar chr) throw (State::Error)
+{
+ QRegister *reg;
+ gchar *insert;
+
+ if (state)
+ goto *state;
+
+ /* NULL state */
+ switch (chr) {
+ case '.': undo.push_var(is_local) = true; break;
+ case '#': set(&&StateFirstChar); break;
+ case '{': set(&&StateString); break;
+ default:
+ undo.push_str(name) = g_strdup(CHR2STR(g_ascii_toupper(chr)));
+ goto done;
+ }
+
+ return NULL;
+
+StateFirstChar:
+ undo.push_str(name) = (gchar *)g_malloc(3);
+ name[0] = g_ascii_toupper(chr);
+ set(&&StateSecondChar);
+ return NULL;
+
+StateSecondChar:
+ name[1] = g_ascii_toupper(chr);
+ name[2] = '\0';
+ goto done;
+
+StateString:
+ switch (chr) {
+ case '{':
+ undo.push_var(nesting)++;
+ break;
+ case '}':
+ if (!nesting)
+ goto done;
+ undo.push_var(nesting)--;
+ break;
+ }
+
+ insert = string_machine.input(chr);
+ if (!insert)
+ return NULL;
+
+ undo.push_str(name);
+ String::append(name, insert);
+ g_free(insert);
+ return NULL;
+
+done:
+ reg = is_local ? (*QRegisters::locals)[name]
+ : QRegisters::globals[name];
+ if (!reg)
+ throw State::InvalidQRegError(name, is_local);
+
+ return reg;
+}
+
/*
* Command states
*/
-StateExpectQReg::StateExpectQReg() : State(), got_local(false)
+StateExpectQReg::StateExpectQReg() : State()
{
transitions['\0'] = this;
}
@@ -369,22 +443,11 @@ StateExpectQReg::StateExpectQReg() : State(), got_local(false)
State *
StateExpectQReg::custom(gchar chr) throw (Error, ReplaceCmdline)
{
- QRegister *reg;
+ QRegister *reg = machine.input(chr);
- if (chr == '.') {
- undo.push_var(got_local) = true;
- return this;
- }
- chr = g_ascii_toupper(chr);
-
- if (got_local) {
- undo.push_var(got_local) = false;
- reg = (*QRegisters::locals)[chr];
- } else {
- reg = QRegisters::globals[chr];
- }
if (!reg)
- throw InvalidQRegError(chr, got_local);
+ return this;
+ machine.reset();
return got_register(*reg);
}
diff --git a/src/qregisters.h b/src/qregisters.h
index a5b20cb..2e1772a 100644
--- a/src/qregisters.h
+++ b/src/qregisters.h
@@ -254,6 +254,27 @@ public:
bool pop(QRegister &reg);
};
+class QRegSpecMachine : public MicroStateMachine<QRegister *> {
+ StringBuildingMachine string_machine;
+
+ bool is_local;
+ gint nesting;
+ gchar *name;
+
+public:
+ QRegSpecMachine() : MicroStateMachine(),
+ is_local(false), nesting(0), name(NULL) {}
+
+ ~QRegSpecMachine()
+ {
+ g_free(name);
+ }
+
+ void reset(void);
+
+ QRegister *input(gchar chr) throw (State::Error);
+};
+
/*
* Command states
*/
@@ -262,7 +283,7 @@ public:
* Super class for states accepting Q-Register specifications
*/
class StateExpectQReg : public State {
- bool got_local;
+ QRegSpecMachine machine;
public:
StateExpectQReg();