diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2013-02-14 00:55:04 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2013-02-14 05:21:03 +0100 |
commit | 9cd71e16b30e2f0061a6d74421a5357333721a70 (patch) | |
tree | bb362c1ffed48fe9af5ca0cf70c38caacfca2e45 /src | |
parent | 91ae87c7ab0c26a387eb42243e50baf0ded30250 (diff) | |
download | sciteco-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
Diffstat (limited to 'src')
-rw-r--r-- | src/qregisters.cpp | 93 | ||||
-rw-r--r-- | src/qregisters.h | 23 |
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 ®); }; +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(); |