X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=parser.c;h=9cbb8d16b017b1b7e45e7bc7104fb93604eb382d;hb=87b9fca732c94a8fddd36c23e7ece364259fa3b7;hp=8c585f52234fde0ae5298a7afb913e67e98ec129;hpb=3b4a5667ea8b1b7aa8a10734c57c02d1561fcdd7;p=xonotic%2Fgmqcc.git diff --git a/parser.c b/parser.c index 8c585f5..9cbb8d1 100644 --- a/parser.c +++ b/parser.c @@ -311,8 +311,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) ctx = vec_last(sy->ops).ctx; if (vec_size(sy->out) < op->operands) { - compile_error(ctx, "internal error: not enough operands: %i (operator %s (%i))", vec_size(sy->out), - op->op, (int)op->id); + if (op->flags & OP_PREFIX) + compile_error(ctx, "expected expression after unary operator `%s`", op->op, (int)op->id); + else /* this should have errored previously already */ + compile_error(ctx, "expected expression after operator `%s`", op->op, (int)op->id); return false; } @@ -1187,13 +1189,13 @@ static bool parser_close_call(parser_t *parser, shunt *sy) * intrinsic call and just evaluate it i.e constant fold it. */ if (fold && ast_istype(fun, ast_value) && ((ast_value*)fun)->intrinsic) { - ast_expression **exprs = NULL; - ast_expression *fold = NULL; + ast_expression **exprs = NULL; + ast_expression *foldval = NULL; for (i = 0; i < paramcount; i++) vec_push(exprs, sy->out[fid+1 + i].out); - if (!(fold = intrin_fold(parser->intrin, (ast_value*)fun, exprs))) { + if (!(foldval = intrin_fold(parser->intrin, (ast_value*)fun, exprs))) { vec_free(exprs); goto fold_leave; } @@ -1202,7 +1204,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) * Blub: what sorts of unreffing and resizing of * sy->out should I be doing here? */ - sy->out[fid] = syexp(fold->node.context, fold); + sy->out[fid] = syexp(foldval->node.context, foldval); vec_shrinkby(sy->out, 1); vec_free(exprs); @@ -1629,7 +1631,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma /* only warn once about an assignment in a truth value because the current code * would trigger twice on: if(a = b && ...), once for the if-truth-value, once for the && part */ - bool warn_truthvalue = true; + bool warn_parenthesis = true; /* count the parens because an if starts with one, so the * end of a condition is an unmatched closing paren @@ -1664,7 +1666,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma } } if (o == operator_count) { - compile_error(parser_ctx(parser), "unknown operator: %s", parser_tokval(parser)); + compile_error(parser_ctx(parser), "unexpected operator: %s", parser_tokval(parser)); goto onerr; } /* found an operator */ @@ -1692,6 +1694,17 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma if (vec_size(sy.ops) && !vec_last(sy.ops).isparen) olast = &operators[vec_last(sy.ops).etype-1]; + /* first only apply higher precedences, assoc_left+equal comes after we warn about precedence rules */ + while (olast && op->prec < olast->prec) + { + if (!parser_sy_apply_operator(parser, &sy)) + goto onerr; + if (vec_size(sy.ops) && !vec_last(sy.ops).isparen) + olast = &operators[vec_last(sy.ops).etype-1]; + else + olast = NULL; + } + #define IsAssignOp(x) (\ (x) == opid1('=') || \ (x) == opid2('+','=') || \ @@ -1703,14 +1716,29 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma (x) == opid2('|','=') || \ (x) == opid3('&','~','=') \ ) - if (warn_truthvalue) { + if (warn_parenthesis) { if ( (olast && IsAssignOp(olast->id) && (op->id == opid2('&','&') || op->id == opid2('|','|'))) || (olast && IsAssignOp(op->id) && (olast->id == opid2('&','&') || olast->id == opid2('|','|'))) || (truthvalue && !vec_size(sy.paren) && IsAssignOp(op->id)) ) { (void)!parsewarning(parser, WARN_PARENTHESIS, "suggesting parenthesis around assignment used as truth value"); - warn_truthvalue = false; + warn_parenthesis = false; + } + + if (olast && olast->id != op->id) { + if ((op->id == opid1('&') || op->id == opid1('|') || op->id == opid1('^')) && + (olast->id == opid1('&') || olast->id == opid1('|') || olast->id == opid1('^'))) + { + (void)!parsewarning(parser, WARN_PARENTHESIS, "suggesting parenthesis around bitwise operations"); + warn_parenthesis = false; + } + else if ((op->id == opid2('&','&') || op->id == opid2('|','|')) && + (olast->id == opid2('&','&') || olast->id == opid2('|','|'))) + { + (void)!parsewarning(parser, WARN_PARENTHESIS, "suggesting parenthesis around logical operations"); + warn_parenthesis = false; + } } } @@ -2738,7 +2766,15 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool * else if (!strcmp(parser_tokval(parser), "inline")) { flags |= AST_FLAG_INLINE; if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) { - parseerror(parser, "`noref` attribute has no parameters, expected `]]`"); + parseerror(parser, "`inline` attribute has no parameters, expected `]]`"); + *cvq = CV_WRONG; + return false; + } + } + else if (!strcmp(parser_tokval(parser), "eraseable")) { + flags |= AST_FLAG_ERASEABLE; + if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) { + parseerror(parser, "`eraseable` attribute has no parameters, expected `]]`"); *cvq = CV_WRONG; return false; }