aboutsummaryrefslogtreecommitdiffhomepage
path: root/parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'parser.cpp')
-rw-r--r--parser.cpp122
1 files changed, 65 insertions, 57 deletions
diff --git a/parser.cpp b/parser.cpp
index 59c5df2..7e4da4a 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -1,3 +1,4 @@
+#include <stdarg.h>
#include <string.h>
#include <glib.h>
@@ -43,8 +44,8 @@ static gint nest_level = 0;
gchar *strings[2] = {NULL, NULL};
gchar escape_char = '\x1B';
-bool
-macro_execute(const gchar *macro)
+void
+macro_execute(const gchar *macro) throw (State::Error)
{
while (macro[macro_pc]) {
#ifdef DEBUG
@@ -53,23 +54,15 @@ macro_execute(const gchar *macro)
States::current);
#endif
- if (!State::input(macro[macro_pc])) {
- interface.msg(Interface::MSG_ERROR,
- "Syntax error \"%c\"", macro[macro_pc]);
- return false;
- }
-
+ State::input(macro[macro_pc]);
macro_pc++;
}
-
- return true;
}
bool
file_execute(const gchar *filename)
{
gchar *macro, *p = NULL;
- bool rc;
macro_pc = 0;
States::current = &States::start;
@@ -80,16 +73,28 @@ file_execute(const gchar *filename)
if (macro[0] == '#')
p = MAX(strchr(macro, '\r'), strchr(macro, '\n'));
- rc = macro_execute(p ? p+1 : macro);
- g_free(macro);
- if (!rc)
+ try {
+ macro_execute(p ? p+1 : macro);
+ } catch (...) {
+ g_free(macro);
return false;
+ }
+ g_free(macro);
macro_pc = 0;
States::current = &States::start;
return true;
}
+State::Error::Error(const gchar *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ interface.vmsg(Interface::MSG_ERROR, fmt, ap);
+ va_end(ap);
+}
+
State::State()
{
for (guint i = 0; i < G_N_ELEMENTS(transitions); i++)
@@ -107,18 +112,14 @@ State::eval_colon(void)
return true;
}
-bool
-State::input(gchar chr)
+void
+State::input(gchar chr) throw (Error)
{
State *state = States::current;
for (;;) {
State *next = state->get_next_state(chr);
- if (!next)
- /* Syntax error */
- return false;
-
if (next == state)
break;
@@ -130,12 +131,10 @@ State::input(gchar chr)
undo.push_var<State *>(States::current);
States::current = state;
}
-
- return true;
}
State *
-State::get_next_state(gchar chr)
+State::get_next_state(gchar chr) throw (Error)
{
State *next = NULL;
guint upper = g_ascii_toupper(chr);
@@ -144,12 +143,14 @@ State::get_next_state(gchar chr)
next = transitions[upper];
if (!next)
next = custom(chr);
+ if (!next)
+ throw SyntaxError(chr);
return next;
}
gchar *
-StateExpectString::machine_input(gchar chr)
+StateExpectString::machine_input(gchar chr) throw (Error)
{
switch (machine.mode) {
case Machine::MODE_UPPER:
@@ -225,7 +226,7 @@ StateExpectString::machine_input(gchar chr)
reg = qregisters[g_ascii_toupper(chr)];
if (!reg)
- return NULL;
+ throw InvalidQRegError(chr);
return state == Machine::STATE_CTL_EQ
? reg->get_string()
@@ -243,7 +244,7 @@ original:
}
State *
-StateExpectString::custom(gchar chr)
+StateExpectString::custom(gchar chr) throw (Error)
{
gchar *insert, *new_str;
@@ -311,12 +312,12 @@ StateExpectQReg::StateExpectQReg() : State()
}
State *
-StateExpectQReg::custom(gchar chr)
+StateExpectQReg::custom(gchar chr) throw (Error)
{
QRegister *reg = qregisters[g_ascii_toupper(chr)];
if (!reg)
- return NULL;
+ throw InvalidQRegError(chr);
return got_register(reg);
}
@@ -418,7 +419,7 @@ StateStart::delete_words(gint64 n)
}
State *
-StateStart::custom(gchar chr)
+StateStart::custom(gchar chr) throw (Error)
{
gint64 v;
tecoBool rc;
@@ -656,7 +657,7 @@ StateStart::custom(gchar chr)
} else if (eval_colon()) {
expressions.push(FAILURE);
} else {
- return NULL; /* FIXME */
+ throw MoveError("J");
}
break;
@@ -666,7 +667,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw MoveError("C");
break;
case 'R':
@@ -675,7 +676,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw MoveError("R");
break;
case 'L':
@@ -684,7 +685,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw MoveError("L");
break;
case 'B':
@@ -693,7 +694,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw MoveError("B");
break;
case 'W': {
@@ -728,7 +729,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(FAILURE);
else
- return NULL; /* FIXME */
+ throw MoveError("W");
}
break;
}
@@ -739,7 +740,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw Error("Not enough words to delete with <V>");
break;
case 'Y':
@@ -748,7 +749,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw Error("Not enough words to delete with <Y>");
break;
case '=':
@@ -792,7 +793,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw RangeError(chr);
if (len == 0 || IS_FAILURE(rc))
break;
@@ -807,7 +808,7 @@ StateStart::custom(gchar chr)
}
default:
- return NULL;
+ throw SyntaxError(chr);
}
return this;
@@ -819,7 +820,7 @@ StateFlowCommand::StateFlowCommand() : State()
}
State *
-StateFlowCommand::custom(gchar chr)
+StateFlowCommand::custom(gchar chr) throw (Error)
{
switch (chr) {
/*
@@ -880,7 +881,7 @@ StateFlowCommand::custom(gchar chr)
break;
default:
- return NULL;
+ throw SyntaxError(chr);
}
return &States::start;
@@ -892,7 +893,7 @@ StateCondCommand::StateCondCommand() : State()
}
State *
-StateCondCommand::custom(gchar chr)
+StateCondCommand::custom(gchar chr) throw (Error)
{
gint64 value = 0;
bool result;
@@ -959,7 +960,7 @@ StateCondCommand::custom(gchar chr)
result = g_ascii_isupper((gchar)value);
break;
default:
- return NULL;
+ throw Error("Invalid conditional type \"%c\"", chr);
}
if (!result) {
@@ -978,7 +979,7 @@ StateControl::StateControl() : State()
}
State *
-StateControl::custom(gchar chr)
+StateControl::custom(gchar chr) throw (Error)
{
switch (g_ascii_toupper(chr)) {
case 'O':
@@ -1036,7 +1037,7 @@ StateControl::custom(gchar chr)
break;
default:
- return NULL;
+ throw Error("Unsupported command <^%c>", chr);
}
return &States::start;
@@ -1051,17 +1052,18 @@ StateECommand::StateECommand() : State()
}
State *
-StateECommand::custom(gchar chr)
+StateECommand::custom(gchar chr) throw (Error)
{
switch (g_ascii_toupper(chr)) {
case 'F':
BEGIN_EXEC(&States::start);
if (!ring.current)
- return NULL; /* FIXME */
+ throw Error("No buffer selected");
if (IS_FAILURE(expressions.pop_num_calc()) &&
ring.current->dirty)
- return NULL; /* FIXME */
+ throw Error("Buffer \"%s\" is dirty",
+ ring.current->filename ? : "(Unnamed)");
ring.close();
break;
@@ -1071,14 +1073,14 @@ StateECommand::custom(gchar chr)
if (IS_FAILURE(expressions.pop_num_calc()) &&
ring.is_any_dirty())
- return NULL; /* FIXME */
+ throw Error("Modified buffers exist");
undo.push_var<bool>(quit_requested);
quit_requested = true;
break;
default:
- return NULL;
+ throw SyntaxError(chr);
}
return &States::start;
@@ -1090,7 +1092,7 @@ StateECommand::custom(gchar chr)
* syntactically
*/
void
-StateInsert::initial(void)
+StateInsert::initial(void) throw (Error)
{
int args;
@@ -1112,7 +1114,7 @@ StateInsert::initial(void)
}
void
-StateInsert::process(const gchar *str, gint new_chars)
+StateInsert::process(const gchar *str, gint new_chars) throw (Error)
{
interface.ssm(SCI_BEGINUNDOACTION);
interface.ssm(SCI_ADDTEXT, new_chars,
@@ -1123,14 +1125,14 @@ StateInsert::process(const gchar *str, gint new_chars)
}
State *
-StateInsert::done(const gchar *str __attribute__((unused)))
+StateInsert::done(const gchar *str __attribute__((unused))) throw (Error)
{
/* nothing to be done when done */
return &States::start;
}
void
-StateSearch::initial(void)
+StateSearch::initial(void) throw (Error)
{
gint64 v;
@@ -1143,6 +1145,10 @@ StateSearch::initial(void)
parameters.count = 1;
parameters.from = (gint)v;
parameters.to = (gint)expressions.pop_num_calc();
+
+ if (!Validate::pos(parameters.from) ||
+ !Validate::pos(parameters.to))
+ throw RangeError("S");
} else {
parameters.count = (gint)v;
if (v >= 0) {
@@ -1246,7 +1252,8 @@ StateSearch::class2regexp(MatchState &state, const gchar *&pattern,
}
gchar *
-StateSearch::pattern2regexp(const gchar *&pattern, bool single_expr)
+StateSearch::pattern2regexp(const gchar *&pattern,
+ bool single_expr)
{
MatchState state = STATE_START;
gchar *re = NULL;
@@ -1357,7 +1364,8 @@ error:
}
void
-StateSearch::process(const gchar *str, gint new_chars __attribute__((unused)))
+StateSearch::process(const gchar *str,
+ gint new_chars __attribute__((unused))) throw (Error)
{
static const gint flags = G_REGEX_CASELESS | G_REGEX_MULTILINE |
G_REGEX_DOTALL | G_REGEX_RAW;
@@ -1447,7 +1455,7 @@ StateSearch::process(const gchar *str, gint new_chars __attribute__((unused)))
}
State *
-StateSearch::done(const gchar *str)
+StateSearch::done(const gchar *str) throw (Error)
{
BEGIN_EXEC(&States::start);