diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2013-02-13 23:10:44 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2013-02-14 05:21:02 +0100 |
commit | 91ae87c7ab0c26a387eb42243e50baf0ded30250 (patch) | |
tree | 80029def56294772dec508d6c2f7e88096547572 /src/parser.cpp | |
parent | cd132baf66da7ede169a9718e7473fa7bbb472ba (diff) | |
download | sciteco-91ae87c7ab0c26a387eb42243e50baf0ded30250.tar.gz |
rewritten string building state machine using a common MicroStateMachine base class
* uses label pointers instead of state-enum and switch case
(both faster and shorter to write)
* common interface for all micro state machines: makes them reusable
Diffstat (limited to 'src/parser.cpp')
-rw-r--r-- | src/parser.cpp | 189 |
1 files changed, 89 insertions, 100 deletions
diff --git a/src/parser.cpp b/src/parser.cpp index 15fcbdf..140a0a7 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -241,127 +241,124 @@ State::get_next_state(gchar chr) throw (Error, ReplaceCmdline) } gchar * -StateExpectString::machine_input(gchar chr) throw (Error) +StringBuildingMachine::input(gchar chr) throw (State::Error) { - switch (machine.mode) { - case Machine::MODE_UPPER: + switch (mode) { + case MODE_UPPER: chr = g_ascii_toupper(chr); break; - case Machine::MODE_LOWER: + case MODE_LOWER: chr = g_ascii_tolower(chr); break; default: break; } - if (machine.toctl) { - chr = CTL_KEY(g_ascii_toupper(chr)); - machine.toctl = false; + if (toctl) { + if (chr != '^') + chr = CTL_KEY(g_ascii_toupper(chr)); + undo.push_var(toctl) = false; + } else if (chr == '^') { + undo.push_var(toctl) = true; + return NULL; } - if (machine.state == Machine::STATE_ESCAPED) { - machine.state = Machine::STATE_START; - goto original; - } + if (state) + goto *state; - if (chr == '^') { - machine.toctl = true; - return NULL; + /* NULL state */ + switch (chr) { + case CTL_KEY('Q'): + case CTL_KEY('R'): set(&&StateEscaped); break; + case CTL_KEY('V'): set(&&StateLower); break; + case CTL_KEY('W'): set(&&StateUpper); break; + case CTL_KEY('E'): set(&&StateCtlE); break; + default: + goto StateEscaped; } - switch (machine.state) { - case Machine::STATE_START: - switch (chr) { - case CTL_KEY('Q'): - case CTL_KEY('R'): machine.state = Machine::STATE_ESCAPED; break; - case CTL_KEY('V'): machine.state = Machine::STATE_LOWER; break; - case CTL_KEY('W'): machine.state = Machine::STATE_UPPER; break; - case CTL_KEY('E'): machine.state = Machine::STATE_CTL_E; break; - default: - goto original; - } - break; + return NULL; - case Machine::STATE_LOWER: - machine.state = Machine::STATE_START; - if (chr != CTL_KEY('V')) - return g_strdup((gchar []){g_ascii_tolower(chr), '\0'}); - machine.mode = Machine::MODE_LOWER; - break; +StateLower: + set(NULL); - case Machine::STATE_UPPER: - machine.state = Machine::STATE_START; - if (chr != CTL_KEY('W')) - return g_strdup((gchar []){g_ascii_toupper(chr), '\0'}); - machine.mode = Machine::MODE_UPPER; - break; + if (chr != CTL_KEY('V')) + return g_strdup(CHR2STR(g_ascii_tolower(chr))); - case Machine::STATE_CTL_E: - switch (g_ascii_toupper(chr)) { - case 'Q': machine.state = Machine::STATE_CTL_EQ; break; - case 'U': machine.state = Machine::STATE_CTL_EU; break; - default: - machine.state = Machine::STATE_START; - return g_strdup((gchar []){CTL_KEY('E'), chr, '\0'}); - } - break; + undo.push_var(mode) = MODE_LOWER; + return NULL; - case Machine::STATE_CTL_EU: - if (chr == '.') { - machine.state = Machine::STATE_CTL_EU_LOCAL; - } else { - QRegister *reg; +StateUpper: + set(NULL); - machine.state = Machine::STATE_START; - reg = QRegisters::globals[g_ascii_toupper(chr)]; - if (!reg) - throw InvalidQRegError(chr); - return g_strdup(CHR2STR(reg->get_integer())); - } - break; + if (chr != CTL_KEY('W')) + return g_strdup(CHR2STR(g_ascii_toupper(chr))); + + undo.push_var(mode) = MODE_UPPER; + return NULL; - case Machine::STATE_CTL_EU_LOCAL: { +StateCtlE: + switch (g_ascii_toupper(chr)) { + case 'Q': set(&&StateCtlEQ); break; + case 'U': set(&&StateCtlEU); break; + default: + set(NULL); + return g_strdup((gchar []){CTL_KEY('E'), chr, '\0'}); + } + + return NULL; + +StateCtlEU: + if (chr == '.') { + set(&&StateCtlEULocal); + return NULL; + } else { QRegister *reg; - machine.state = Machine::STATE_START; - reg = (*QRegisters::locals)[g_ascii_toupper(chr)]; + reg = QRegisters::globals[g_ascii_toupper(chr)]; if (!reg) - throw InvalidQRegError(chr, true); + throw State::InvalidQRegError(chr); + set(NULL); return g_strdup(CHR2STR(reg->get_integer())); } - case Machine::STATE_CTL_EQ: - if (chr == '.') { - machine.state = Machine::STATE_CTL_EQ_LOCAL; - } else { - QRegister *reg; +StateCtlEULocal: { + QRegister *reg; - machine.state = Machine::STATE_START; - reg = QRegisters::globals[g_ascii_toupper(chr)]; - if (!reg) - throw InvalidQRegError(chr); - return reg->get_string(); - } - break; + reg = (*QRegisters::locals)[g_ascii_toupper(chr)]; + if (!reg) + throw State::InvalidQRegError(chr, true); + set(NULL); + return g_strdup(CHR2STR(reg->get_integer())); +} - case Machine::STATE_CTL_EQ_LOCAL: { +StateCtlEQ: + if (chr == '.') { + set(&&StateCtlEQLocal); + return NULL; + } else { QRegister *reg; - machine.state = Machine::STATE_START; - reg = (*QRegisters::locals)[g_ascii_toupper(chr)]; + reg = QRegisters::globals[g_ascii_toupper(chr)]; if (!reg) - throw InvalidQRegError(chr, true); + throw State::InvalidQRegError(chr); + set(NULL); return reg->get_string(); } - default: - g_assert(TRUE); - } +StateCtlEQLocal: { + QRegister *reg; - return NULL; + reg = (*QRegisters::locals)[g_ascii_toupper(chr)]; + if (!reg) + throw State::InvalidQRegError(chr, true); + set(NULL); + return reg->get_string(); +} -original: - return g_strdup((gchar []){chr, '\0'}); +StateEscaped: + set(NULL); + return g_strdup(CHR2STR(chr)); } State * @@ -393,17 +390,14 @@ StateExpectString::custom(gchar chr) throw (Error) if (escape_char == '{') { switch (chr) { case '{': - undo.push_var(nesting); - nesting++; + undo.push_var(nesting)++; break; case '}': - undo.push_var(nesting); - nesting--; + undo.push_var(nesting)--; break; } } else if (g_ascii_toupper(chr) == escape_char) { - undo.push_var(nesting); - nesting--; + undo.push_var(nesting)--; } if (!nesting) { @@ -415,12 +409,8 @@ StateExpectString::custom(gchar chr) throw (Error) undo.push_var(escape_char) = '\x1B'; nesting = 1; - if (string_building) { - undo.push_var(machine); - machine.state = Machine::STATE_START; - machine.mode = Machine::MODE_NORMAL; - machine.toctl = false; - } + if (string_building) + machine.reset(); next = done(string ? : ""); g_free(string); @@ -433,12 +423,11 @@ StateExpectString::custom(gchar chr) throw (Error) * String building characters */ if (string_building) { - undo.push_var(machine); - insert = machine_input(chr); + insert = machine.input(chr); if (!insert) return this; } else { - insert = g_strdup((gchar []){chr, '\0'}); + insert = g_strdup(CHR2STR(chr)); } /* |