diff options
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(); |