aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-07 23:06:38 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-07 23:06:38 +0100
commit1707fcabca80e2e664bef9c02ec5cc9d793ce37b (patch)
tree004935397db5972a44d423ad2c2596db4909f8dc
parent69419eceaca8e347016ccbe42326bcdc881355fc (diff)
downloadsciteco-1707fcabca80e2e664bef9c02ec5cc9d793ce37b.tar.gz
additional commands implemented
-rw-r--r--expressions.h8
-rw-r--r--parser.cpp209
-rw-r--r--parser.h1
3 files changed, 214 insertions, 4 deletions
diff --git a/expressions.h b/expressions.h
index 148a991..e456449 100644
--- a/expressions.h
+++ b/expressions.h
@@ -140,6 +140,11 @@ public:
gint64 push(gint64 number);
+ inline gint64
+ peek_num(int index = 1)
+ {
+ return numbers.peek(index);
+ }
gint64 pop_num(int index = 1);
gint64 pop_num_calc(int index, gint64 imply);
inline gint64
@@ -152,6 +157,7 @@ public:
Operator push(Operator op);
Operator push_calc(Operator op);
+ Operator pop_op(int index = 1);
void eval(bool pop_brace = false);
@@ -160,8 +166,6 @@ public:
void discard_args(void);
private:
- Operator pop_op(int index = 1);
-
void calc(void);
int first_op(void);
diff --git a/parser.cpp b/parser.cpp
index 2c15da7..afcff41 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -19,16 +19,21 @@ static struct {
bool at;
} modifiers = {false, false};
-static enum {
+static enum Mode {
MODE_NORMAL = 0,
MODE_PARSE_ONLY
} mode = MODE_NORMAL;
+/* FIXME: perhaps integrate into Mode */
+static bool skip_else = false;
+
#define BEGIN_EXEC(STATE) G_STMT_START { \
if (mode != MODE_NORMAL) \
return STATE; \
} G_STMT_END
+static gint nest_level = 0;
+
bool
macro_execute(const gchar *macro)
{
@@ -118,6 +123,15 @@ StateStart::move(gint64 n)
undo.push_msg(SCI_GOTOPOS, pos);
}
+void
+StateStart::move_lines(gint64 n)
+{
+ sptr_t pos = editor_msg(SCI_GETCURRENTPOS);
+ sptr_t line = editor_msg(SCI_LINEFROMPOSITION, pos);
+ editor_msg(SCI_GOTOPOS, editor_msg(SCI_POSITIONFROMLINE, line + n));
+ undo.push_msg(SCI_GOTOPOS, pos);
+}
+
State *
StateStart::custom(gchar chr)
{
@@ -138,19 +152,23 @@ StateStart::custom(gchar chr)
return this;
}
- switch (g_ascii_toupper(chr)) {
+ chr = g_ascii_toupper(chr);
+ switch (chr) {
case '/':
BEGIN_EXEC(this);
expressions.push_calc(Expressions::OP_DIV);
break;
+
case '*':
BEGIN_EXEC(this);
expressions.push_calc(Expressions::OP_MUL);
break;
+
case '+':
BEGIN_EXEC(this);
expressions.push_calc(Expressions::OP_ADD);
break;
+
case '-':
BEGIN_EXEC(this);
if (!expressions.args())
@@ -158,14 +176,17 @@ StateStart::custom(gchar chr)
else
expressions.push_calc(Expressions::OP_SUB);
break;
+
case '&':
BEGIN_EXEC(this);
expressions.push_calc(Expressions::OP_AND);
break;
+
case '#':
BEGIN_EXEC(this);
expressions.push_calc(Expressions::OP_OR);
break;
+
case '(':
BEGIN_EXEC(this);
if (expressions.num_sign < 0) {
@@ -174,47 +195,231 @@ StateStart::custom(gchar chr)
}
expressions.push(Expressions::OP_BRACE);
break;
+
case ')':
BEGIN_EXEC(this);
expressions.eval(true);
break;
+
case ',':
BEGIN_EXEC(this);
expressions.eval();
expressions.push(Expressions::OP_NEW);
break;
+
case '.':
BEGIN_EXEC(this);
expressions.eval();
expressions.push(editor_msg(SCI_GETCURRENTPOS));
break;
+
case 'Z':
BEGIN_EXEC(this);
expressions.eval();
expressions.push(editor_msg(SCI_GETLENGTH));
break;
+
case 'H':
BEGIN_EXEC(this);
expressions.eval();
expressions.push(0);
expressions.push(editor_msg(SCI_GETLENGTH));
break;
+
+ /*
+ * control structures (loops)
+ */
+ case '<':
+ if (mode == MODE_PARSE_ONLY) {
+ undo.push_var<gint>(nest_level);
+ nest_level++;
+ return this;
+ }
+
+ expressions.eval();
+ if (!expressions.args())
+ /* infinite loop */
+ expressions.push(-1);
+
+ if (!expressions.peek_num()) {
+ expressions.pop_num();
+
+ /* skip to end of loop */
+ undo.push_var<Mode>(mode);
+ mode = MODE_PARSE_ONLY;
+ } else {
+ expressions.push(macro_pc);
+ expressions.push(Expressions::OP_LOOP);
+ }
+ break;
+
+ case '>':
+ if (mode == MODE_PARSE_ONLY) {
+ if (!nest_level) {
+ undo.push_var<Mode>(mode);
+ mode = MODE_NORMAL;
+ } else {
+ undo.push_var<gint>(nest_level);
+ nest_level--;
+ }
+ } else {
+ gint64 loop_pc, loop_cnt;
+
+ expressions.discard_args();
+ g_assert(expressions.pop_op() == Expressions::OP_LOOP);
+ loop_pc = expressions.pop_num();
+ loop_cnt = expressions.pop_num();
+
+ if (loop_cnt != 1) {
+ /* repeat loop */
+ macro_pc = loop_pc;
+ expressions.push(MAX(loop_cnt - 1, -1));
+ expressions.push(loop_pc);
+ expressions.push(Expressions::OP_LOOP);
+ }
+ }
+ break;
+
+ case ';': {
+ BEGIN_EXEC(this);
+ /* TODO: search Q-reg */
+ gint64 v = expressions.pop_num_calc();
+ if (eval_colon())
+ v = ~v;
+
+ if (v >= 0) {
+ expressions.discard_args();
+ g_assert(expressions.pop_op() == Expressions::OP_LOOP);
+ expressions.pop_num(); /* pc */
+ expressions.pop_num(); /* counter */
+
+ /* skip to end of loop */
+ undo.push_var<Mode>(mode);
+ mode = MODE_PARSE_ONLY;
+ }
+ break;
+ }
+
+ /*
+ * control structures (conditionals)
+ */
+ case '|':
+ if (mode == MODE_PARSE_ONLY) {
+ if (!skip_else && !nest_level) {
+ undo.push_var<Mode>(mode);
+ mode = MODE_NORMAL;
+ }
+ return this;
+ }
+
+ /* skip to end of conditional; skip ELSE-part */
+ undo.push_var<Mode>(mode);
+ mode = MODE_PARSE_ONLY;
+ break;
+
+ case '\'':
+ if (mode == MODE_NORMAL)
+ break;
+
+ if (!nest_level) {
+ undo.push_var<Mode>(mode);
+ mode = MODE_NORMAL;
+ undo.push_var<bool>(skip_else);
+ skip_else = false;
+ } else {
+ undo.push_var<gint>(nest_level);
+ nest_level--;
+ }
+ break;
+
+ /*
+ * modifiers
+ */
+ case '@':
+ BEGIN_EXEC(this);
+ undo.push_var<bool>(modifiers.at);
+ modifiers.at = true;
+ break;
+
+ case ':':
+ BEGIN_EXEC(this);
+ undo.push_var<bool>(modifiers.colon);
+ modifiers.colon = true;
+ break;
+
/*
* commands
*/
+ case 'J':
+ BEGIN_EXEC(this);
+ undo.push_msg(SCI_GOTOPOS, editor_msg(SCI_GETCURRENTPOS));
+ editor_msg(SCI_GOTOPOS, expressions.pop_num_calc(1, 0));
+ break;
+
case 'C':
BEGIN_EXEC(this);
move(expressions.pop_num_calc());
break;
+
case 'R':
BEGIN_EXEC(this);
move(-expressions.pop_num_calc());
break;
+
+ case 'L':
+ BEGIN_EXEC(this);
+ move_lines(expressions.pop_num_calc());
+ break;
+
+ case 'B':
+ BEGIN_EXEC(this);
+ move_lines(-expressions.pop_num_calc());
+ break;
+
case '=':
BEGIN_EXEC(this);
message_display(GTK_MESSAGE_OTHER, "%" G_GINT64_FORMAT,
expressions.pop_num_calc());
break;
+
+ case 'K':
+ case 'D': {
+ gint64 from, len;
+
+ BEGIN_EXEC(this);
+ expressions.eval();
+
+ if (expressions.args() <= 1) {
+ from = editor_msg(SCI_GETCURRENTPOS);
+ if (chr == 'D') {
+ len = expressions.pop_num_calc();
+ } else /* chr == 'K' */ {
+ sptr_t line = editor_msg(SCI_LINEFROMPOSITION, from) +
+ expressions.pop_num_calc();
+ len = editor_msg(SCI_POSITIONFROMLINE, line) - from;
+ }
+ if (len < 0) {
+ from += len;
+ len *= -1;
+ }
+ } else {
+ gint64 to = expressions.pop_num();
+ from = expressions.pop_num();
+ len = to - from;
+ }
+
+ if (len > 0) {
+ undo.push_msg(SCI_GOTOPOS,
+ editor_msg(SCI_GETCURRENTPOS));
+ undo.push_msg(SCI_UNDO);
+
+ editor_msg(SCI_BEGINUNDOACTION);
+ editor_msg(SCI_DELETERANGE, from, len);
+ editor_msg(SCI_ENDUNDOACTION);
+ }
+ break;
+ }
+
default:
return NULL;
}
diff --git a/parser.h b/parser.h
index 40a8c9f..007b942 100644
--- a/parser.h
+++ b/parser.h
@@ -45,6 +45,7 @@ public:
private:
void move(gint64 n);
+ void move_lines(gint64 n);
State *custom(gchar chr);
};