Improved error reporting in the expression parser

Fixes 15A80F68-F233-49D9-AF0C-9908BB6903BA
This commit is contained in:
John Wiegley 2010-05-22 18:45:42 -04:00
parent 3e1ec40551
commit a3482606dc
4 changed files with 45 additions and 23 deletions

View file

@ -79,9 +79,7 @@ expr_t::parser_t::parse_value_term(std::istream& in,
case token_t::LPAREN:
node = parse_value_expr(in, tflags.plus_flags(PARSE_PARTIAL)
.minus_flags(PARSE_SINGLE));
tok = next_token(in, tflags);
if (tok.kind != token_t::RPAREN)
tok.expected(')');
tok = next_token(in, tflags, ')');
if (node->kind == op_t::O_CONS) {
ptr_op_t prev(node);
@ -383,10 +381,7 @@ expr_t::parser_t::parse_querycolon_expr(std::istream& in,
throw_(parse_error,
_("%1 operator not followed by argument") << tok.symbol);
token_t& next_tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
if (next_tok.kind != token_t::COLON)
next_tok.expected(':');
next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT), ':');
prev = node->right();
ptr_op_t subnode = new op_t(op_t::O_COLON);
subnode->set_left(prev);

View file

@ -52,11 +52,12 @@ class expr_t::parser_t : public noncopyable
mutable token_t lookahead;
mutable bool use_lookahead;
token_t& next_token(std::istream& in, const parse_flags_t& tflags) const {
token_t& next_token(std::istream& in, const parse_flags_t& tflags,
const char expecting = '\0') const {
if (use_lookahead)
use_lookahead = false;
else
lookahead.next(in, tflags);
lookahead.next(in, tflags, expecting);
return lookahead;
}

View file

@ -138,7 +138,8 @@ void expr_t::token_t::parse_ident(std::istream& in)
value.set_string(buf);
}
void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags)
void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
const char expecting)
{
if (in.eof()) {
kind = TOK_EOF;
@ -423,6 +424,13 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags)
expected('\0', c);
parse_ident(in);
if (value.as_string().length() == 0) {
kind = ERROR;
symbol[0] = c;
symbol[1] = '\0';
unexpected(expecting);
}
} else {
kind = VALUE;
value = temp;
@ -447,21 +455,38 @@ void expr_t::token_t::rewind(std::istream& in)
}
void expr_t::token_t::unexpected()
void expr_t::token_t::unexpected(const char wanted)
{
kind_t prev_kind = kind;
kind = ERROR;
switch (prev_kind) {
case TOK_EOF:
throw_(parse_error, _("Unexpected end of expression"));
case IDENT:
throw_(parse_error, _("Unexpected symbol '%1'") << value);
case VALUE:
throw_(parse_error, _("Unexpected value '%1'") << value);
default:
throw_(parse_error, _("Unexpected token '%1'") << symbol);
if (wanted == '\0') {
switch (prev_kind) {
case TOK_EOF:
throw_(parse_error, _("Unexpected end of expression"));
case IDENT:
throw_(parse_error, _("Unexpected symbol '%1'") << value);
case VALUE:
throw_(parse_error, _("Unexpected value '%1'") << value);
default:
throw_(parse_error, _("Unexpected expression token '%1'") << symbol);
}
} else {
switch (prev_kind) {
case TOK_EOF:
throw_(parse_error,
_("Unexpected end of expression (wanted '%1')" << wanted));
case IDENT:
throw_(parse_error,
_("Unexpected symbol '%1' (wanted '%2')") << value << wanted);
case VALUE:
throw_(parse_error,
_("Unexpected value '%1' (wanted '%2')") << value << wanted);
default:
throw_(parse_error, _("Unexpected expression token '%1' (wanted '%2')")
<< symbol << wanted);
}
}
}

View file

@ -124,10 +124,11 @@ struct expr_t::token_t : public noncopyable
int parse_reserved_word(std::istream& in);
void parse_ident(std::istream& in);
void next(std::istream& in, const parse_flags_t& flags);
void next(std::istream& in, const parse_flags_t& flags,
const char expecting = '\0');
void rewind(std::istream& in);
void unexpected();
void expected(char wanted, char c = '\0');
void unexpected(const char wanted = '\0');
void expected(const char wanted, char c = '\0');
};
} // namespace ledger