summaryrefslogtreecommitdiff
path: root/gcc/cp/parser.c
diff options
context:
space:
mode:
authorAndrew Sutton <andrew.n.sutton@gmail.com>2015-01-23 14:49:44 -0500
committerAndrew Sutton <andrew.n.sutton@gmail.com>2015-01-23 14:49:44 -0500
commit61736183be51ef19cffaefd3732262b8d8adee24 (patch)
tree33a9d5e8658467e2dffd1e1fe1604c32c10ebad1 /gcc/cp/parser.c
parent20ba0684ac43d2f4ceaaf3de5cf66d94ed4dc4c6 (diff)
downloadgcc-asutton/fold.tar.gz
Implement fold expressions.asutton/fold
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r--gcc/cp/parser.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e1b320ab1ab..d437cc5e623 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -4207,6 +4207,144 @@ cp_parser_statement_expr (cp_parser *parser)
/* Expressions [gram.expr] */
+
+/* A helper function for cp_parser_fold_operator. Consume the token
+ and return the matched tree CODE. */
+static inline int
+cp_parser_match_fold_op (cp_parser *parser, int code)
+{
+ cp_lexer_consume_token (parser->lexer);
+ return code;
+}
+
+/* Parse a fold-operator.
+
+ fold-operator:
+ - * / % ^ & | = < > << >>
+ = -= *= /= %= ^= &= |= <<= >>=
+ == != <= >= && || , .* ->*
+
+ This returns the tree code corresponding to the matched operator
+ as an int. When the current token matches a compound assignment
+ opertor, the resulting tree code is the negative value of the
+ non-assignment operator. */
+
+static int
+cp_parser_fold_operator (cp_parser *parser)
+{
+ cp_token* token = cp_lexer_peek_token (parser->lexer);
+ switch (token->type)
+ {
+ case CPP_PLUS: return cp_parser_match_fold_op (parser, PLUS_EXPR);
+ case CPP_MINUS: return cp_parser_match_fold_op (parser, MINUS_EXPR);
+ case CPP_MULT: return cp_parser_match_fold_op (parser, MULT_EXPR);
+ case CPP_DIV: return cp_parser_match_fold_op (parser, TRUNC_DIV_EXPR);
+ case CPP_MOD: return cp_parser_match_fold_op (parser, TRUNC_MOD_EXPR);
+ case CPP_XOR: return cp_parser_match_fold_op (parser, BIT_XOR_EXPR);
+ case CPP_AND: return cp_parser_match_fold_op (parser, BIT_AND_EXPR);
+ case CPP_OR: return cp_parser_match_fold_op (parser, BIT_IOR_EXPR);
+ case CPP_LSHIFT: return cp_parser_match_fold_op (parser, LSHIFT_EXPR);
+ case CPP_RSHIFT: return cp_parser_match_fold_op (parser, RSHIFT_EXPR);
+
+ case CPP_EQ: return cp_parser_match_fold_op (parser, -NOP_EXPR);
+ case CPP_PLUS_EQ: return cp_parser_match_fold_op (parser, -PLUS_EXPR);
+ case CPP_MINUS_EQ: return cp_parser_match_fold_op (parser, -MINUS_EXPR);
+ case CPP_MULT_EQ: return cp_parser_match_fold_op (parser, -MULT_EXPR);
+ case CPP_DIV_EQ: return cp_parser_match_fold_op (parser, -TRUNC_DIV_EXPR);
+ case CPP_MOD_EQ: return cp_parser_match_fold_op (parser, -TRUNC_MOD_EXPR);
+ case CPP_XOR_EQ: return cp_parser_match_fold_op (parser, -BIT_XOR_EXPR);
+ case CPP_AND_EQ: return cp_parser_match_fold_op (parser, -BIT_AND_EXPR);
+ case CPP_OR_EQ: return cp_parser_match_fold_op (parser, -BIT_IOR_EXPR);
+ case CPP_LSHIFT_EQ: return cp_parser_match_fold_op (parser, -LSHIFT_EXPR);
+ case CPP_RSHIFT_EQ: return cp_parser_match_fold_op (parser, -RSHIFT_EXPR);
+
+ case CPP_EQ_EQ: return cp_parser_match_fold_op (parser, EQ_EXPR);
+ case CPP_NOT_EQ: return cp_parser_match_fold_op (parser, NE_EXPR);
+ case CPP_LESS: return cp_parser_match_fold_op (parser, LT_EXPR);
+ case CPP_GREATER: return cp_parser_match_fold_op (parser, GT_EXPR);
+ case CPP_LESS_EQ: return cp_parser_match_fold_op (parser, LE_EXPR);
+ case CPP_GREATER_EQ: return cp_parser_match_fold_op (parser, GE_EXPR);
+
+ case CPP_AND_AND: return cp_parser_match_fold_op (parser, TRUTH_ANDIF_EXPR);
+ case CPP_OR_OR: return cp_parser_match_fold_op (parser, TRUTH_ORIF_EXPR);
+
+ case CPP_COMMA: return cp_parser_match_fold_op (parser, COMPOUND_EXPR);
+
+ case CPP_DOT_STAR: return cp_parser_match_fold_op (parser, DOTSTAR_EXPR);
+ case CPP_DEREF_STAR: return cp_parser_match_fold_op (parser, MEMBER_REF);
+
+ default: return ERROR_MARK;
+ }
+}
+
+/* Parse a fold-expression.
+
+ fold-expression:
+ ( ... folding-operator cast-expression)
+ ( cast-expression folding-operator ... )
+ ( cast-expression folding operator ... folding-operator cast-expression)
+
+ Note that the '(' and ')' are matched in primary expression. */
+
+static tree
+cp_parser_fold_expression (cp_parser *parser) {
+ cp_id_kind pidk;
+
+ // Left fold
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ int op = cp_parser_fold_operator (parser);
+ if (op == ERROR_MARK)
+ {
+ cp_parser_error (parser, "expected cast-expression");
+ return error_mark_node;
+ }
+
+ tree expr = cp_parser_cast_expression (parser, false, false, false, &pidk);
+ if (expr == error_mark_node)
+ return error_mark_node;
+ return finish_left_unary_fold_expr (expr, op);
+ }
+
+ tree expr1 = cp_parser_cast_expression (parser, false, false, false, &pidk);
+ if (expr1 == error_mark_node)
+ return error_mark_node;
+
+ const cp_token* token = cp_lexer_peek_token (parser->lexer);
+ int op = cp_parser_fold_operator (parser);
+ if (op == ERROR_MARK)
+ {
+ cp_parser_error (parser, "expected cast-expression");
+ return error_mark_node;
+ }
+
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_ELLIPSIS))
+ {
+ cp_parser_error (parser, "expected ...");
+ return error_mark_node;
+ }
+ cp_lexer_consume_token (parser->lexer);
+
+ // Right fold
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
+ return finish_right_unary_fold_expr (expr1, op);
+
+ if (cp_lexer_next_token_is_not (parser->lexer, token->type))
+ {
+ error ("mismatched fold-operator in cast expression");
+ return error_mark_node;
+ }
+ cp_lexer_consume_token (parser->lexer);
+
+ // Binary left or right fold
+ tree expr2 = cp_parser_cast_expression (parser, false, false, false, &pidk);
+ if (expr2 == error_mark_node)
+ return error_mark_node;
+ tree t = finish_binary_fold_expr (expr1, expr2, op);
+ return t;
+}
+
/* Parse a primary-expression.
primary-expression:
@@ -4413,6 +4551,16 @@ cp_parser_primary_expression (cp_parser *parser,
= parser->greater_than_is_operator_p;
parser->greater_than_is_operator_p = true;
+ // Try to parse a fold-expression.
+ cp_parser_parse_tentatively (parser);
+ tree fold = cp_parser_fold_expression (parser);
+ if (cp_parser_parse_definitely (parser))
+ {
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ cp_parser_skip_to_end_of_statement (parser);
+ return fold;
+ }
+
/* Parse the parenthesized expression. */
expr = cp_parser_expression (parser, idk, cast_p, decltype_p);
/* Let the front end know that this expression was