static bool parse_block_into(parser_t *parser, ast_block *block);
static bool parse_statement_or_block(parser_t *parser, ast_expression **out);
static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases);
-static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma);
+static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue);
static ast_expression* parse_expression(parser_t *parser, bool stopatcomma);
static void parseerror(parser_t *parser, const char *fmt, ...)
( (generated_op == INSTR_OR)
? (immediate_is_true(ctx, asvalue[0]) || immediate_is_true(ctx, asvalue[1]))
: (immediate_is_true(ctx, asvalue[0]) && immediate_is_true(ctx, asvalue[1])) )
- ? 0 : 1);
+ ? 1 : 0);
}
else
{
}
}
-static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma)
+static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue)
{
ast_expression *expr = NULL;
shunt sy;
bool wantop = false;
bool gotmemberof = false;
+ /* 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;
/* count the parens because an if starts with one, so the
* end of a condition is an unmatched closing paren
if (vec_size(sy.ops) && !vec_last(sy.ops).paren)
olast = &operators[vec_last(sy.ops).etype-1];
+#define IsAssignOp(x) (\
+ (x) == opid1('=') || \
+ (x) == opid2('+','=') || \
+ (x) == opid2('-','=') || \
+ (x) == opid2('*','=') || \
+ (x) == opid2('/','=') || \
+ (x) == opid2('%','=') || \
+ (x) == opid2('&','=') || \
+ (x) == opid2('|','=') || \
+ (x) == opid3('&','~','=') \
+ )
+ if (warn_truthvalue) {
+ if ( (olast && IsAssignOp(olast->id) && (op->id == opid2('&','&') || op->id == opid2('|','|'))) ||
+ (olast && IsAssignOp(op->id) && (olast->id == opid2('&','&') || olast->id == opid2('|','|'))) ||
+ (truthvalue && !vec_size(parser->pot) && IsAssignOp(op->id))
+ )
+ {
+ (void)!parsewarning(parser, WARN_PARENTHESIS, "suggesting parenthesis around assignment used as truth value");
+ warn_truthvalue = false;
+ }
+ }
+
while (olast && (
(op->prec < olast->prec) ||
(op->assoc == ASSOC_LEFT && op->prec <= olast->prec) ) )
static ast_expression* parse_expression(parser_t *parser, bool stopatcomma)
{
- ast_expression *e = parse_expression_leave(parser, stopatcomma);
+ ast_expression *e = parse_expression_leave(parser, stopatcomma, false);
if (!e)
return NULL;
if (!parser_next(parser)) {
return false;
}
/* parse the condition */
- cond = parse_expression_leave(parser, false);
+ cond = parse_expression_leave(parser, false, true);
if (!cond)
return false;
/* closing paren */
return false;
}
/* parse the condition */
- cond = parse_expression_leave(parser, false);
+ cond = parse_expression_leave(parser, false, true);
if (!cond)
return false;
/* closing paren */
return false;
}
/* parse the condition */
- cond = parse_expression_leave(parser, false);
+ cond = parse_expression_leave(parser, false, true);
if (!cond)
return false;
/* closing paren */
}
else if (parser->tok != ';')
{
- initexpr = parse_expression_leave(parser, false);
+ initexpr = parse_expression_leave(parser, false, false);
if (!initexpr)
goto onerr;
}
/* parse the condition */
if (parser->tok != ';') {
- cond = parse_expression_leave(parser, false);
+ cond = parse_expression_leave(parser, false, true);
if (!cond)
goto onerr;
}
/* parse the incrementor */
if (parser->tok != ')') {
- increment = parse_expression_leave(parser, false);
+ increment = parse_expression_leave(parser, false, false);
if (!increment)
goto onerr;
if (!ast_side_effects(increment)) {
return false;
}
/* parse the operand */
- operand = parse_expression_leave(parser, false);
+ operand = parse_expression_leave(parser, false, false);
if (!operand)
return false;
parseerror(parser, "expected expression for case");
return false;
}
- swcase.value = parse_expression_leave(parser, false);
+ swcase.value = parse_expression_leave(parser, false, false);
if (!swcase.value) {
ast_delete(switchnode);
parseerror(parser, "expected expression for case");
if (!parser_next(parser))
return false;
- framenum = parse_expression_leave(parser, true);
+ framenum = parse_expression_leave(parser, true, false);
if (!framenum) {
parseerror(parser, "expected a framenumber constant in[frame,think] notation");
return false;
nextthink = (ast_expression*)thinkfunc;
} else {
- nextthink = parse_expression_leave(parser, true);
+ nextthink = parse_expression_leave(parser, true, false);
if (!nextthink) {
ast_unref(framenum);
parseerror(parser, "expected a think-function in [frame,think] notation");
return NULL;
}
- cexp = parse_expression_leave(parser, true);
+ cexp = parse_expression_leave(parser, true, false);
if (!cexp || !ast_istype(cexp, ast_value)) {
if (cexp)
ast_expression *cexp;
ast_value *cval;
- cexp = parse_expression_leave(parser, true);
+ cexp = parse_expression_leave(parser, true, false);
if (!cexp)
break;