parent
d493f79651
commit
37e9ec8030
6 changed files with 115 additions and 18 deletions
|
|
@ -49,15 +49,15 @@ namespace ledger {
|
|||
|
||||
class expr_t : public expr_base_t<value_t>
|
||||
{
|
||||
struct token_t;
|
||||
class parser_t;
|
||||
|
||||
class parser_t;
|
||||
typedef expr_base_t<value_t> base_type;
|
||||
|
||||
public:
|
||||
struct token_t;
|
||||
class op_t;
|
||||
typedef intrusive_ptr<op_t> ptr_op_t;
|
||||
typedef intrusive_ptr<const op_t> const_ptr_op_t;
|
||||
|
||||
protected:
|
||||
ptr_op_t ptr;
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,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, ')');
|
||||
tok = next_token(in, tflags, token_t::RPAREN);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -367,7 +367,7 @@ expr_t::parser_t::parse_querycolon_expr(std::istream& in,
|
|||
throw_(parse_error,
|
||||
_("%1 operator not followed by argument") << tok.symbol);
|
||||
|
||||
next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT), ':');
|
||||
next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT), token_t::COLON);
|
||||
prev = node->right();
|
||||
ptr_op_t subnode = new op_t(op_t::O_COLON);
|
||||
subnode->set_left(prev);
|
||||
|
|
|
|||
|
|
@ -53,11 +53,15 @@ class expr_t::parser_t : public noncopyable
|
|||
mutable bool use_lookahead;
|
||||
|
||||
token_t& next_token(std::istream& in, const parse_flags_t& tflags,
|
||||
const char expecting = '\0') const {
|
||||
const optional<token_t::kind_t>& expecting = none) const {
|
||||
if (use_lookahead)
|
||||
use_lookahead = false;
|
||||
else
|
||||
lookahead.next(in, tflags, expecting);
|
||||
lookahead.next(in, tflags);
|
||||
|
||||
if (expecting && lookahead.kind != *expecting)
|
||||
lookahead.expected(*expecting);
|
||||
|
||||
return lookahead;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -770,7 +770,7 @@ public:
|
|||
parent->HANDLER(total_)
|
||||
.set_expr(string("--percent"),
|
||||
"((is_account&parent&parent.total)?"
|
||||
" percent(scrub(total), scrub(parent.total)):0");
|
||||
" percent(scrub(total), scrub(parent.total)):0)");
|
||||
});
|
||||
|
||||
OPTION__
|
||||
|
|
|
|||
104
src/token.cc
104
src/token.cc
|
|
@ -137,8 +137,7 @@ 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,
|
||||
const char expecting)
|
||||
void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags)
|
||||
{
|
||||
if (in.eof()) {
|
||||
kind = TOK_EOF;
|
||||
|
|
@ -436,7 +435,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
|
|||
kind = ERROR;
|
||||
symbol[0] = c;
|
||||
symbol[1] = '\0';
|
||||
unexpected(expecting);
|
||||
throw_(parse_error, _("Failed to parse identifier"));
|
||||
}
|
||||
} else {
|
||||
if (! in.good()) {
|
||||
|
|
@ -505,10 +504,8 @@ void expr_t::token_t::unexpected(const char wanted)
|
|||
}
|
||||
}
|
||||
|
||||
void expr_t::token_t::expected(char wanted, char c)
|
||||
void expr_t::token_t::expected(const char wanted, char c)
|
||||
{
|
||||
kind = ERROR;
|
||||
|
||||
if (c == '\0' || c == -1) {
|
||||
if (wanted == '\0' || wanted == -1)
|
||||
throw_(parse_error, _("Unexpected end"));
|
||||
|
|
@ -518,8 +515,101 @@ void expr_t::token_t::expected(char wanted, char c)
|
|||
if (wanted == '\0' || wanted == -1)
|
||||
throw_(parse_error, _("Invalid char '%1'") << c);
|
||||
else
|
||||
throw_(parse_error, _("Invalid char '%1' (wanted '%2')") << c << wanted);
|
||||
throw_(parse_error,
|
||||
_("Invalid char '%1' (wanted '%2')") << c << wanted);
|
||||
}
|
||||
}
|
||||
|
||||
void expr_t::token_t::expected(const kind_t wanted)
|
||||
{
|
||||
try {
|
||||
if (wanted == '\0' || wanted == -1)
|
||||
throw_(parse_error, _("Invalid token '%1'") << *this);
|
||||
else
|
||||
throw_(parse_error,
|
||||
_("Invalid token '%1' (wanted '%2')") << *this << wanted);
|
||||
}
|
||||
catch (...) {
|
||||
kind = ERROR;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const expr_t::token_t::kind_t& kind)
|
||||
{
|
||||
switch (kind) {
|
||||
case expr_t::token_t::ERROR: out << "<error token>"; break;
|
||||
case expr_t::token_t::VALUE: out << "<value>"; break;
|
||||
case expr_t::token_t::IDENT: out << "<identifier>"; break;
|
||||
case expr_t::token_t::MASK: out << "<regex mask>"; break;
|
||||
|
||||
case expr_t::token_t::LPAREN: out << "("; break;
|
||||
case expr_t::token_t::RPAREN: out << ")"; break;
|
||||
case expr_t::token_t::LBRACE: out << "{"; break;
|
||||
case expr_t::token_t::RBRACE: out << "}"; break;
|
||||
|
||||
case expr_t::token_t::EQUAL: out << "=="; break;
|
||||
case expr_t::token_t::NEQUAL: out << "!="; break;
|
||||
case expr_t::token_t::LESS: out << "<"; break;
|
||||
case expr_t::token_t::LESSEQ: out << "<="; break;
|
||||
case expr_t::token_t::GREATER: out << ">"; break;
|
||||
case expr_t::token_t::GREATEREQ: out << ">="; break;
|
||||
|
||||
case expr_t::token_t::ASSIGN: out << "="; break;
|
||||
case expr_t::token_t::MATCH: out << "=~"; break;
|
||||
case expr_t::token_t::NMATCH: out << "!~"; break;
|
||||
case expr_t::token_t::MINUS: out << "-"; break;
|
||||
case expr_t::token_t::PLUS: out << "+"; break;
|
||||
case expr_t::token_t::STAR: out << "*"; break;
|
||||
case expr_t::token_t::SLASH: out << "/"; break;
|
||||
case expr_t::token_t::ARROW: out << "->"; break;
|
||||
case expr_t::token_t::KW_DIV: out << "div"; break;
|
||||
|
||||
case expr_t::token_t::EXCLAM: out << "!"; break;
|
||||
case expr_t::token_t::KW_AND: out << "and"; break;
|
||||
case expr_t::token_t::KW_OR: out << "or"; break;
|
||||
case expr_t::token_t::KW_MOD: out << "mod"; break;
|
||||
|
||||
case expr_t::token_t::KW_IF: out << "if"; break;
|
||||
case expr_t::token_t::KW_ELSE: out << "else"; break;
|
||||
|
||||
case expr_t::token_t::QUERY: out << "?"; break;
|
||||
case expr_t::token_t::COLON: out << ":"; break;
|
||||
|
||||
case expr_t::token_t::DOT: out << "."; break;
|
||||
case expr_t::token_t::COMMA: out << ","; break;
|
||||
case expr_t::token_t::SEMI: out << ";"; break;
|
||||
|
||||
case expr_t::token_t::TOK_EOF: out << "<end of input>"; break;
|
||||
case expr_t::token_t::UNKNOWN: out << "<unknown>"; break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const expr_t::token_t& token)
|
||||
{
|
||||
switch (token.kind) {
|
||||
case expr_t::token_t::VALUE:
|
||||
out << "<value '" << token.value << "'>";
|
||||
break;
|
||||
case expr_t::token_t::IDENT:
|
||||
out << "<ident '" << token.value << "'>";
|
||||
break;
|
||||
case expr_t::token_t::MASK:
|
||||
out << "<mask '" << token.value << "'>";
|
||||
break;
|
||||
|
||||
default:
|
||||
out << token.kind;
|
||||
break;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
|
|
|||
|
|
@ -123,13 +123,16 @@ 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,
|
||||
const char expecting = '\0');
|
||||
void next(std::istream& in, const parse_flags_t& flags);
|
||||
void rewind(std::istream& in);
|
||||
void unexpected(const char wanted = '\0');
|
||||
void expected(const char wanted, char c = '\0');
|
||||
void expected(const char wanted, const char c = '\0');
|
||||
void expected(const kind_t wanted);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const expr_t::token_t::kind_t& kind);
|
||||
std::ostream& operator<<(std::ostream& out, const expr_t::token_t& token);
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#endif // _TOKEN_H
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue