Re-implemented ?: parsing in value expressions. "a ? b : c" is implemented by
translating it into the equivalent syntax tree "(a & b) | c", since this expression evaluates to the value of b if a is true, otherwise c.
This commit is contained in:
parent
567902b173
commit
c98be73173
3 changed files with 59 additions and 10 deletions
42
parser.cc
42
parser.cc
|
|
@ -134,7 +134,7 @@ expr_t::parser_t::parse_value_term(std::istream& in,
|
||||||
|
|
||||||
tok = next_token(in, tflags);
|
tok = next_token(in, tflags);
|
||||||
if (tok.kind != token_t::RPAREN)
|
if (tok.kind != token_t::RPAREN)
|
||||||
tok.unexpected(0xff, ')');
|
tok.expected(')');
|
||||||
|
|
||||||
node = call_node;
|
node = call_node;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -158,7 +158,7 @@ expr_t::parser_t::parse_value_term(std::istream& in,
|
||||||
|
|
||||||
tok = next_token(in, tflags);
|
tok = next_token(in, tflags);
|
||||||
if (tok.kind != token_t::RPAREN)
|
if (tok.kind != token_t::RPAREN)
|
||||||
tok.unexpected(0xff, ')');
|
tok.expected(')');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -382,11 +382,47 @@ expr_t::parser_t::parse_or_expr(std::istream& in,
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expr_t::ptr_op_t
|
||||||
|
expr_t::parser_t::parse_querycolon_expr(std::istream& in,
|
||||||
|
const flags_t tflags) const
|
||||||
|
{
|
||||||
|
ptr_op_t node(parse_or_expr(in, tflags));
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
token_t& tok = next_token(in, tflags);
|
||||||
|
|
||||||
|
if (tok.kind == token_t::QUERY) {
|
||||||
|
ptr_op_t prev(node);
|
||||||
|
node = new op_t(op_t::O_AND);
|
||||||
|
node->set_left(prev);
|
||||||
|
node->set_right(parse_or_expr(in, tflags));
|
||||||
|
if (! node->right())
|
||||||
|
throw_(parse_error,
|
||||||
|
tok.symbol << " operator not followed by argument");
|
||||||
|
|
||||||
|
token_t& next_tok = next_token(in, tflags);
|
||||||
|
if (next_tok.kind != token_t::COLON)
|
||||||
|
next_tok.expected(':');
|
||||||
|
|
||||||
|
prev = node;
|
||||||
|
node = new op_t(op_t::O_OR);
|
||||||
|
node->set_left(prev);
|
||||||
|
node->set_right(parse_or_expr(in, tflags));
|
||||||
|
if (! node->right())
|
||||||
|
throw_(parse_error,
|
||||||
|
tok.symbol << " operator not followed by argument");
|
||||||
|
} else {
|
||||||
|
push_token(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
expr_t::ptr_op_t
|
expr_t::ptr_op_t
|
||||||
expr_t::parser_t::parse_value_expr(std::istream& in,
|
expr_t::parser_t::parse_value_expr(std::istream& in,
|
||||||
const flags_t tflags) const
|
const flags_t tflags) const
|
||||||
{
|
{
|
||||||
ptr_op_t node(parse_or_expr(in, tflags));
|
ptr_op_t node(parse_querycolon_expr(in, tflags));
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
token_t& tok = next_token(in, tflags);
|
token_t& tok = next_token(in, tflags);
|
||||||
|
|
|
||||||
22
token.cc
22
token.cc
|
|
@ -164,7 +164,7 @@ void expr_t::token_t::next(std::istream& in, const unsigned int pflags)
|
||||||
char buf[256];
|
char buf[256];
|
||||||
READ_INTO_(in, buf, 255, c, length, c != ']');
|
READ_INTO_(in, buf, 255, c, length, c != ']');
|
||||||
if (c != ']')
|
if (c != ']')
|
||||||
unexpected(c, ']');
|
expected(']', c);
|
||||||
|
|
||||||
in.get(c);
|
in.get(c);
|
||||||
length++;
|
length++;
|
||||||
|
|
@ -182,7 +182,7 @@ void expr_t::token_t::next(std::istream& in, const unsigned int pflags)
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
READ_INTO_(in, buf, 4095, c, length, c != delim);
|
READ_INTO_(in, buf, 4095, c, length, c != delim);
|
||||||
if (c != delim)
|
if (c != delim)
|
||||||
unexpected(c, delim);
|
expected(delim, c);
|
||||||
in.get(c);
|
in.get(c);
|
||||||
length++;
|
length++;
|
||||||
kind = VALUE;
|
kind = VALUE;
|
||||||
|
|
@ -196,7 +196,7 @@ void expr_t::token_t::next(std::istream& in, const unsigned int pflags)
|
||||||
temp.parse(in, AMOUNT_PARSE_NO_MIGRATE);
|
temp.parse(in, AMOUNT_PARSE_NO_MIGRATE);
|
||||||
in.get(c);
|
in.get(c);
|
||||||
if (c != '}')
|
if (c != '}')
|
||||||
unexpected(c, '}');
|
expected('}', c);
|
||||||
length++;
|
length++;
|
||||||
kind = VALUE;
|
kind = VALUE;
|
||||||
value = temp;
|
value = temp;
|
||||||
|
|
@ -231,6 +231,16 @@ void expr_t::token_t::next(std::istream& in, const unsigned int pflags)
|
||||||
kind = STAR;
|
kind = STAR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
in.get(c);
|
||||||
|
kind = QUERY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ':':
|
||||||
|
in.get(c);
|
||||||
|
kind = COLON;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
case 'C':
|
case 'C':
|
||||||
case 'p':
|
case 'p':
|
||||||
|
|
@ -266,7 +276,7 @@ void expr_t::token_t::next(std::istream& in, const unsigned int pflags)
|
||||||
char buf[256];
|
char buf[256];
|
||||||
READ_INTO_(in, buf, 255, c, length, c != '/');
|
READ_INTO_(in, buf, 255, c, length, c != '/');
|
||||||
if (c != '/')
|
if (c != '/')
|
||||||
unexpected(c, '/');
|
expected('/', c);
|
||||||
in.get(c);
|
in.get(c);
|
||||||
length++;
|
length++;
|
||||||
|
|
||||||
|
|
@ -379,9 +389,9 @@ void expr_t::token_t::unexpected()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void expr_t::token_t::unexpected(char c, char wanted)
|
void expr_t::token_t::expected(char wanted, char c)
|
||||||
{
|
{
|
||||||
if (static_cast<unsigned char>(c) == 0xff) {
|
if (c == '\0') {
|
||||||
if (wanted)
|
if (wanted)
|
||||||
throw_(parse_error, "Missing '" << wanted << "'");
|
throw_(parse_error, "Missing '" << wanted << "'");
|
||||||
else
|
else
|
||||||
|
|
|
||||||
5
token.h
5
token.h
|
|
@ -71,6 +71,9 @@ struct expr_t::token_t : public noncopyable, public supports_flags<>
|
||||||
KW_OR, // |
|
KW_OR, // |
|
||||||
KW_MOD, // %
|
KW_MOD, // %
|
||||||
|
|
||||||
|
QUERY, // ?
|
||||||
|
COLON, // :
|
||||||
|
|
||||||
COMMA, // ,
|
COMMA, // ,
|
||||||
|
|
||||||
TOK_EOF,
|
TOK_EOF,
|
||||||
|
|
@ -111,7 +114,7 @@ struct expr_t::token_t : public noncopyable, public supports_flags<>
|
||||||
void rewind(std::istream& in);
|
void rewind(std::istream& in);
|
||||||
void unexpected();
|
void unexpected();
|
||||||
|
|
||||||
static void unexpected(char c, char wanted = '\0');
|
static void expected(char wanted, char c = '\0');
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue