aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-20 00:43:18 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-20 06:07:34 +0100
commitec510eda5f080d39906c396a36cba89188031640 (patch)
treef47468059f71cadb84a0699876310d0f1373411e
parent9e49e88d0cc3e6336754040eeaab7a760645dd79 (diff)
downloadsciteco-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.cpp13
-rw-r--r--parser.cpp90
-rw-r--r--parser.h18
-rw-r--r--qbuffers.cpp92
-rw-r--r--qbuffers.h59
-rwxr-xr-xteco.ini39
6 files changed, 201 insertions, 110 deletions
diff --git a/main.cpp b/main.cpp
index 552b1e0..312064f 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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) {
diff --git a/parser.cpp b/parser.cpp
index 59305bc..e7ff980 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -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, &macro, 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();
diff --git a/parser.h b/parser.h
index a704c83..2451a58 100644
--- a/parser.h
+++ b/parser.h
@@ -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 = &macro_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;
}
diff --git a/qbuffers.h b/qbuffers.h
index ce2645c..df05c08 100644
--- a/qbuffers.h
+++ b/qbuffers.h
@@ -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
diff --git a/teco.ini b/teco.ini
index 97ae766..9b27a6c 100755
--- a/teco.ini
+++ b/teco.ini
@@ -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