diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-11-20 00:43:18 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-11-20 06:07:34 +0100 |
commit | ec510eda5f080d39906c396a36cba89188031640 (patch) | |
tree | f47468059f71cadb84a0699876310d0f1373411e | |
parent | 9e49e88d0cc3e6336754040eeaab7a760645dd79 (diff) | |
download | sciteco-ec510eda5f080d39906c396a36cba89188031640.tar.gz |
local Q-Register tables; :M command
* munged files use the same local Q-Registers as commandline
* :M calls macro without new set of local registers (local register names refer to the parent macro level)
* only .x names accepted at the moment. for string building characters, this will like stay that way (cannot refer to extended/long names)
-rw-r--r-- | main.cpp | 13 | ||||
-rw-r--r-- | parser.cpp | 90 | ||||
-rw-r--r-- | parser.h | 18 | ||||
-rw-r--r-- | qbuffers.cpp | 92 | ||||
-rw-r--r-- | qbuffers.h | 59 | ||||
-rwxr-xr-x | teco.ini | 39 |
6 files changed, 201 insertions, 110 deletions
@@ -101,6 +101,7 @@ int main(int argc, char **argv) { static GotoTable cmdline_goto_table; + static QRegisterTable local_qregs; process_options(argc, argv); @@ -116,7 +117,15 @@ main(int argc, char **argv) interface.ssm(SCI_STYLESETFONT, STYLE_DEFAULT, (sptr_t)"Courier"); interface.ssm(SCI_STYLECLEARALL); - qregisters.initialize(); + QRegisters::globals.initialize(); + /* search string and status register */ + QRegisters::globals.initialize("_"); + /* current buffer name and number ("*") */ + QRegisters::globals.insert(new QRegisterBufferInfo()); + + local_qregs.initialize(); + QRegisters::locals = &local_qregs; + ring.edit(NULL); /* add remaining arguments to unnamed buffer */ @@ -126,7 +135,7 @@ main(int argc, char **argv) } if (g_file_test(mung_file, G_FILE_TEST_IS_REGULAR)) { - if (!file_execute(mung_file)) + if (!file_execute(mung_file, false)) exit(EXIT_FAILURE); /* FIXME: make quit immediate in commandline mode (non-UNDO)? */ if (quit_requested) { @@ -64,14 +64,20 @@ macro_execute(const gchar *macro) throw (State::Error) * TODO: make this usable from other macro invocations as well */ bool -file_execute(const gchar *filename) +file_execute(const gchar *filename, bool locals) { gchar *macro, *p = NULL; GotoTable file_goto_table; + QRegisterTable *parent_locals = QRegisters::locals; macro_pc = 0; States::current = &States::start; + Goto::table = &file_goto_table; + if (locals) { + QRegisters::locals = new QRegisterTable(); + QRegisters::locals->initialize(); + } if (!g_file_get_contents(filename, ¯o, NULL, NULL)) return false; @@ -95,6 +101,9 @@ file_execute(const gchar *filename) macro_pc = 0; States::current = &States::start; Goto::table = NULL; + if (locals) + delete QRegisters::locals; + QRegisters::locals = parent_locals; return true; } @@ -227,22 +236,52 @@ StateExpectString::machine_input(gchar chr) throw (Error) } break; - /* - * FIXME: Q-Register specifications might get more complicated - */ case Machine::STATE_CTL_EU: - case Machine::STATE_CTL_EQ: { + if (chr == '.') { + machine.state = Machine::STATE_CTL_EU_LOCAL; + } else { + QRegister *reg; + + machine.state = Machine::STATE_START; + reg = QRegisters::globals[g_ascii_toupper(chr)]; + if (!reg) + throw InvalidQRegError(chr); + return g_strdup((gchar []){(gchar)reg->integer, '\0'}); + } + break; + + case Machine::STATE_CTL_EU_LOCAL: { QRegister *reg; - Machine::State state = machine.state; - machine.state = Machine::STATE_START; - reg = qregisters[g_ascii_toupper(chr)]; + machine.state = Machine::STATE_START; + reg = (*QRegisters::locals)[g_ascii_toupper(chr)]; if (!reg) - throw InvalidQRegError(chr); + throw InvalidQRegError(chr, true); + return g_strdup((gchar []){(gchar)reg->integer, '\0'}); + } + + case Machine::STATE_CTL_EQ: + if (chr == '.') { + machine.state = Machine::STATE_CTL_EQ_LOCAL; + } else { + QRegister *reg; - return state == Machine::STATE_CTL_EQ - ? reg->get_string() - : g_strdup((gchar []){(gchar)reg->integer, '\0'}); + machine.state = Machine::STATE_START; + reg = QRegisters::globals[g_ascii_toupper(chr)]; + if (!reg) + throw InvalidQRegError(chr); + return reg->get_string(); + } + break; + + case Machine::STATE_CTL_EQ_LOCAL: { + QRegister *reg; + + machine.state = Machine::STATE_START; + reg = (*QRegisters::locals)[g_ascii_toupper(chr)]; + if (!reg) + throw InvalidQRegError(chr, true); + return reg->get_string(); } default: @@ -340,7 +379,7 @@ StateExpectString::custom(gchar chr) throw (Error) return this; } -StateExpectQReg::StateExpectQReg() : State() +StateExpectQReg::StateExpectQReg() : State(), got_local(false) { transitions['\0'] = this; } @@ -348,10 +387,22 @@ StateExpectQReg::StateExpectQReg() : State() State * StateExpectQReg::custom(gchar chr) throw (Error) { - QRegister *reg = qregisters[g_ascii_toupper(chr)]; + QRegister *reg; + 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); + throw InvalidQRegError(chr, got_local); return got_register(reg); } @@ -613,7 +664,8 @@ StateStart::custom(gchar chr) throw (Error) case ';': BEGIN_EXEC(this); - rc = expressions.pop_num_calc(1, qregisters["_"]->integer); + v = QRegisters::globals["_"]->integer; + rc = expressions.pop_num_calc(1, v); if (eval_colon()) rc = ~rc; @@ -1312,7 +1364,7 @@ StateSearch::class2regexp(MatchState &state, const gchar *&pattern, case STATE_ANYQ: /* FIXME: Q-Register spec might get more complicated */ - reg = qregisters[g_ascii_toupper(*pattern)]; + reg = QRegisters::globals[g_ascii_toupper(*pattern)]; if (!reg) return NULL; @@ -1451,7 +1503,7 @@ StateSearch::process(const gchar *str, static const gint flags = G_REGEX_CASELESS | G_REGEX_MULTILINE | G_REGEX_DOTALL | G_REGEX_RAW; - QRegister *search_reg = qregisters["_"]; + QRegister *search_reg = QRegisters::globals["_"]; gchar *re_pattern; GRegex *re; GMatchInfo *info; @@ -1540,7 +1592,7 @@ StateSearch::done(const gchar *str) throw (Error) { BEGIN_EXEC(&States::start); - QRegister *search_reg = qregisters["_"]; + QRegister *search_reg = QRegisters::globals["_"]; if (*str) { search_reg->undo_set_string(); @@ -42,10 +42,12 @@ public: class InvalidQRegError : public Error { public: - InvalidQRegError(const gchar *name) - : Error("Invalid Q-Register \"%s\"", name) {} - InvalidQRegError(gchar name) - : Error("Invalid Q-Register \"%c\"", name) {} + InvalidQRegError(const gchar *name, bool local = false) + : Error("Invalid Q-Register \"%s%s\"", + local ? "." : "", name) {} + InvalidQRegError(gchar name, bool local = false) + : Error("Invalid Q-Register \"%s%c\"", + local ? "." : "", name) {} }; protected: @@ -95,7 +97,9 @@ class StateExpectString : public State { STATE_UPPER, STATE_CTL_E, STATE_CTL_EQ, - STATE_CTL_EU + STATE_CTL_EQ_LOCAL, + STATE_CTL_EU, + STATE_CTL_EU_LOCAL } state; enum Mode { @@ -134,6 +138,8 @@ class QRegister; * Super class for states accepting Q-Register specifications */ class StateExpectQReg : public State { + bool got_local; + public: StateExpectQReg(); @@ -261,6 +267,6 @@ extern gchar *strings[2]; extern gchar escape_char; void macro_execute(const gchar *macro) throw (State::Error); -bool file_execute(const gchar *filename); +bool file_execute(const gchar *filename, bool locals = true); #endif diff --git a/qbuffers.cpp b/qbuffers.cpp index e90b505..f58b479 100644 --- a/qbuffers.cpp +++ b/qbuffers.cpp @@ -38,8 +38,13 @@ namespace States { StateCopyToQReg copytoqreg; } -QRegisterTable qregisters; -static QRegisterStack qregister_stack; +namespace QRegisters { + QRegisterTable globals; + QRegisterTable *locals = NULL; + QRegister *current = NULL; + + static QRegisterStack stack; +} static QRegister *register_argument = NULL; @@ -53,8 +58,8 @@ current_save_dot(void) if (ring.current) ring.current->dot = dot; - else if (qregisters.current) - qregisters.current->dot = dot; + else if (QRegisters::current) + QRegisters::current->dot = dot; } static inline void @@ -62,8 +67,8 @@ current_edit(void) { if (ring.current) ring.current->edit(); - else if (qregisters.current) - qregisters.current->edit(); + else if (QRegisters::current) + QRegisters::current->edit(); } void @@ -85,8 +90,8 @@ QRegisterData::undo_set_string(void) current_save_dot(); if (ring.current) ring.current->undo_edit(); - else if (qregisters.current) - qregisters.current->undo_edit(); + else if (QRegisters::current) + QRegisters::current->undo_edit(); undo.push_var<gint>(dot); undo.push_msg(SCI_UNDO); @@ -141,11 +146,13 @@ QRegister::undo_edit(void) } void -QRegister::execute(void) throw (State::Error) +QRegister::execute(bool locals) throw (State::Error) { GotoTable *parent_goto_table = Goto::table; GotoTable macro_goto_table; + QRegisterTable *parent_locals = QRegisters::locals; + State *parent_state = States::current; gint parent_pc = macro_pc; gchar *str; @@ -160,7 +167,12 @@ QRegister::execute(void) throw (State::Error) macro_pc = 0; str = get_string(); + Goto::table = ¯o_goto_table; + if (locals) { + QRegisters::locals = new QRegisterTable(); + QRegisters::locals->initialize(); + } try { macro_execute(str); @@ -172,6 +184,9 @@ QRegister::execute(void) throw (State::Error) macro_pc = parent_pc; States::current = parent_state; Goto::table = parent_goto_table; + if (locals) + delete QRegisters::locals; + QRegisters::locals = parent_locals; g_free(Goto::skip_label); Goto::skip_label = NULL; throw; /* forward */ @@ -181,6 +196,9 @@ QRegister::execute(void) throw (State::Error) macro_pc = parent_pc; States::current = parent_state; Goto::table = parent_goto_table; + if (locals) + delete QRegisters::locals; + QRegisters::locals = parent_locals; } bool @@ -235,14 +253,9 @@ QRegisterTable::initialize(void) { /* general purpose registers */ for (gchar q = 'A'; q <= 'Z'; q++) - initialize_register((gchar []){q, '\0'}); + initialize(q); for (gchar q = '0'; q <= '9'; q++) - initialize_register((gchar []){q, '\0'}); - - /* search string and status register */ - initialize_register("_"); - /* current buffer name and number ("*") */ - insert(new QRegisterBufferInfo()); + initialize(q); } void @@ -252,17 +265,7 @@ QRegisterTable::edit(QRegister *reg) reg->edit(); ring.current = NULL; - current = reg; -} - -void -execute_hook(Hook type) -{ - if (!(Flags::ed & Flags::ED_HOOKS)) - return; - - expressions.push(type); - qregisters["0"]->execute(); + QRegisters::current = reg; } void @@ -335,6 +338,16 @@ QRegisterStack::~QRegisterStack() delete entry; } +void +QRegisters::hook(Hook type) +{ + if (!(Flags::ed & Flags::ED_HOOKS)) + return; + + expressions.push(type); + globals["0"]->execute(); +} + bool Buffer::load(const gchar *filename) { @@ -441,12 +454,12 @@ Ring::edit(const gchar *filename) current_save_dot(); - qregisters.current = NULL; + QRegisters::current = NULL; if (buffer) { current = buffer; buffer->edit(); - execute_hook(HOOK_EDIT); + QRegisters::hook(QRegisters::HOOK_EDIT); } else { buffer = new Buffer(); LIST_INSERT_HEAD(&head, buffer, buffers); @@ -472,7 +485,7 @@ Ring::edit(const gchar *filename) "Added new unnamed file to ring."); } - execute_hook(HOOK_ADD); + QRegisters::hook(QRegisters::HOOK_ADD); } } @@ -621,7 +634,7 @@ Ring::close(void) if (current) { current->edit(); - execute_hook(HOOK_EDIT); + QRegisters::hook(QRegisters::HOOK_EDIT); } else { edit(NULL); undo_close(); @@ -685,8 +698,8 @@ StateEditFile::do_edit(const gchar *filename) { if (ring.current) ring.undo_edit(); - else /* qregisters.current != NULL */ - qregisters.undo_edit(); + else /* QRegisters::current != NULL */ + QRegisters::undo_edit(); ring.edit(filename); } @@ -765,7 +778,7 @@ StatePushQReg::got_register(QRegister *reg) throw (Error) { BEGIN_EXEC(&States::start); - qregister_stack.push(reg); + QRegisters::stack.push(reg); return &States::start; } @@ -775,7 +788,7 @@ StatePopQReg::got_register(QRegister *reg) throw (Error) { BEGIN_EXEC(&States::start); - if (!qregister_stack.pop(reg)) + if (!QRegisters::stack.pop(reg)) throw Error("Q-Register stack is empty"); return &States::start; @@ -802,9 +815,9 @@ StateLoadQReg::done(const gchar *str) throw (Error) } else { if (ring.current) ring.undo_edit(); - else /* qregisters.current != NULL */ - qregisters.undo_edit(); - qregisters.edit(register_argument); + else /* QRegisters::current != NULL */ + QRegisters::undo_edit(); + QRegisters::globals.edit(register_argument); } return &States::start; @@ -868,7 +881,8 @@ StateMacro::got_register(QRegister *reg) throw (Error) { BEGIN_EXEC(&States::start); - reg->execute(); + /* don't create new local Q-Registers if colon modifier is given */ + reg->execute(!eval_colon()); return &States::start; } @@ -83,7 +83,7 @@ public: virtual void edit(void); virtual void undo_edit(void); - void execute(void) throw (State::Error); + void execute(bool locals = true) throw (State::Error); bool load(const gchar *filename); inline void @@ -107,21 +107,23 @@ public: void edit(void); }; -extern class QRegisterTable : public RBTree { +class QRegisterTable : public RBTree { +public: + QRegisterTable() : RBTree() {} + inline void - initialize_register(const gchar *name) + initialize(const gchar *name) { QRegister *reg = new QRegister(name); insert(reg); /* make sure document is initialized */ reg->get_document(); } - -public: - QRegister *current; - - QRegisterTable() : RBTree(), current(NULL) {} - + inline void + initialize(gchar name) + { + initialize((gchar []){name, '\0'}); + } void initialize(void); inline QRegister * @@ -147,15 +149,7 @@ public: edit(reg); return reg; } - inline void - undo_edit(void) - { - current->dot = interface.ssm(SCI_GETCURRENTPOS); - - undo.push_var<QRegister*>(current); - current->undo_edit(); - } -} qregisters; +}; class QRegisterStack { class Entry : public QRegisterData { @@ -459,12 +453,27 @@ namespace States { extern StateCopyToQReg copytoqreg; } -enum Hook { - HOOK_ADD = 1, - HOOK_EDIT, - HOOK_CLOSE, - HOOL_QUIT -}; -void execute_hook(Hook type); +namespace QRegisters { + extern QRegisterTable globals; + extern QRegisterTable *locals; + extern QRegister *current; + + inline void + undo_edit(void) + { + current->dot = interface.ssm(SCI_GETCURRENTPOS); + + undo.push_var<QRegister*>(current); + current->undo_edit(); + } + + enum Hook { + HOOK_ADD = 1, + HOOK_EDIT, + HOOK_CLOSE, + HOOK_QUIT + }; + void hook(Hook type); +} #endif @@ -5,33 +5,34 @@ @0{ Oadd,edit,close,quit -!add! [f[r[0[1[2 - EQ* HXf EQf +!add! + EQ* HX.f EQ.f - r - U2U1U0 (Q0*256 + Q1)*256 + Q2 + @.r{ + U.2U.1U.0 + (Q.0*256 + Q.1)*256 + Q.2 + } ZJ -:S.[cpp,c,h]"S Z-."= - EBQf + EBQ.f 3,4001ES 0,4005ESbreak case continue default do else for goto if return switch while - 0,255,0Mr,0,2051ES - 0,255,0Mr,1,2051ES 0,255,0Mr,2,2051ES - 255,255,0Mr,4,2051ES 255,0,0Mr,5,2051ES - 255,0,255Mr,6,2051ES - Oadd.end + 0,255,0:M.r,0,2051ES + 0,255,0:M.r,1,2051ES 0,255,0:M.r,2,2051ES + 255,255,0:M.r,4,2051ES 255,0,0:M.r,5,2051ES + 255,0,255:M.r,6,2051ES + Oend '' ZJ -:Smakefile"S Z-."= - EBQf + EBQ.f 11,4001ES - 0,255,0Mr,1,2051ES - Oadd.end + 0,255,0:M.r,1,2051ES + Oend '' - EBQf -!add.end! - ]2]1]0]r]f Oend + EBQ.f + Oend !edit! Oend @@ -46,7 +47,7 @@ ED#32ED ! open all files specified on the commandline ! -[f - <:L;R 0Xf EBQf EB L> -]f +[.f + <:L;R 0X.f EBQ.f EB L> +].f -EF |