aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--expressions.h5
-rw-r--r--parser.cpp83
-rw-r--r--parser.h9
3 files changed, 93 insertions, 4 deletions
diff --git a/expressions.h b/expressions.h
index e456449..ef41b15 100644
--- a/expressions.h
+++ b/expressions.h
@@ -157,6 +157,11 @@ public:
Operator push(Operator op);
Operator push_calc(Operator op);
+ inline Operator
+ peek_op(int index = 1)
+ {
+ return operators.peek(index);
+ }
Operator pop_op(int index = 1);
void eval(bool pop_brace = false);
diff --git a/parser.cpp b/parser.cpp
index e37722e..a9bcabc 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -15,10 +15,11 @@
gint macro_pc = 0;
namespace States {
- StateStart start;
- StateControl control;
- StateECommand ecommand;
- StateInsert insert;
+ StateStart start;
+ StateControl control;
+ StateFlowCommand flowcommand;
+ StateECommand ecommand;
+ StateInsert insert;
State *current = &start;
}
@@ -199,6 +200,7 @@ StateStart::StateStart() : State()
transitions['!'] = &States::label;
transitions['^'] = &States::control;
+ transitions['F'] = &States::flowcommand;
transitions['E'] = &States::ecommand;
transitions['I'] = &States::insert;
transitions['Q'] = &States::getqreginteger;
@@ -517,6 +519,79 @@ StateStart::custom(gchar chr)
return this;
}
+StateFlowCommand::StateFlowCommand() : State()
+{
+ transitions['\0'] = this;
+}
+
+State *
+StateFlowCommand::custom(gchar chr)
+{
+ switch (chr) {
+ /*
+ * loop flow control
+ */
+ case '<':
+ BEGIN_EXEC(&States::start);
+ /* FIXME: what if in brackets? */
+ expressions.discard_args();
+ if (expressions.peek_op() == Expressions::OP_LOOP)
+ /* repeat loop */
+ macro_pc = expressions.peek_num();
+ else
+ macro_pc = -1;
+ break;
+
+ case '>': {
+ gint64 loop_pc, loop_cnt;
+
+ BEGIN_EXEC(&States::start);
+ /* FIXME: what if in brackets? */
+ 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);
+ } else {
+ /* skip to end of loop */
+ undo.push_var<Mode>(mode);
+ mode = MODE_PARSE_ONLY;
+ }
+ break;
+ }
+
+ /*
+ * conditional flow control
+ */
+ case '\'':
+ BEGIN_EXEC(&States::start);
+ /* skip to end of conditional */
+ undo.push_var<Mode>(mode);
+ mode = MODE_PARSE_ONLY;
+ undo.push_var<bool>(skip_else);
+ skip_else = true;
+ break;
+
+ case '|':
+ BEGIN_EXEC(&States::start);
+ /* skip to ELSE-part or end of conditional */
+ undo.push_var<Mode>(mode);
+ mode = MODE_PARSE_ONLY;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ return &States::start;
+}
+
StateControl::StateControl() : State()
{
transitions['\0'] = this;
diff --git a/parser.h b/parser.h
index be72249..ed50e49 100644
--- a/parser.h
+++ b/parser.h
@@ -96,6 +96,14 @@ private:
State *custom(gchar chr);
};
+class StateFlowCommand : public State {
+public:
+ StateFlowCommand();
+
+private:
+ State *custom(gchar chr);
+};
+
class StateECommand : public State {
public:
StateECommand();
@@ -116,6 +124,7 @@ extern gint macro_pc;
namespace States {
extern StateStart start;
extern StateControl control;
+ extern StateFlowCommand flowcommand;
extern StateECommand ecommand;
extern StateInsert insert;