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

View file

@ -52,11 +52,12 @@ class expr_t::parser_t : public noncopyable
mutable token_t lookahead; mutable token_t lookahead;
mutable bool use_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) if (use_lookahead)
use_lookahead = false; use_lookahead = false;
else else
lookahead.next(in, tflags); lookahead.next(in, tflags, expecting);
return lookahead; return lookahead;
} }

View file

@ -138,7 +138,8 @@ void expr_t::token_t::parse_ident(std::istream& in)
value.set_string(buf); 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()) { if (in.eof()) {
kind = TOK_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); expected('\0', c);
parse_ident(in); parse_ident(in);
if (value.as_string().length() == 0) {
kind = ERROR;
symbol[0] = c;
symbol[1] = '\0';
unexpected(expecting);
}
} else { } else {
kind = VALUE; kind = VALUE;
value = temp; 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_t prev_kind = kind;
kind = ERROR; kind = ERROR;
switch (prev_kind) { if (wanted == '\0') {
case TOK_EOF: switch (prev_kind) {
throw_(parse_error, _("Unexpected end of expression")); case TOK_EOF:
case IDENT: throw_(parse_error, _("Unexpected end of expression"));
throw_(parse_error, _("Unexpected symbol '%1'") << value); case IDENT:
case VALUE: throw_(parse_error, _("Unexpected symbol '%1'") << value);
throw_(parse_error, _("Unexpected value '%1'") << value); case VALUE:
default: throw_(parse_error, _("Unexpected value '%1'") << value);
throw_(parse_error, _("Unexpected token '%1'") << symbol); 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); int parse_reserved_word(std::istream& in);
void parse_ident(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 rewind(std::istream& in);
void unexpected(); void unexpected(const char wanted = '\0');
void expected(char wanted, char c = '\0'); void expected(const char wanted, char c = '\0');
}; };
} // namespace ledger } // namespace ledger