/*	$NetBSD: expr_precedence.c,v 1.12 2024/05/01 07:40:11 rillig Exp $	*/
# 3 "expr_precedence.c"

/*
 * Tests for the precedence among operators.
 */

/* lint1-extra-flags: -X 351 */

int var;

/*
 * An initializer needs an assignment-expression; the comma must be
 * interpreted as a separator, not an operator.
 */
/* expect+1: error: syntax error '4' [249] */
int init_error = 3, 4;

/* expect+1: error: non-constant initializer [177] */
int init_syntactically_ok = var = 1 ? 2 : 3;

/*
 * The arguments of __attribute__ must be constant-expression, but for
 * simplicity of implementation, they are parsed just like function arguments,
 * even though this allows assignment-expression.
 */
void __attribute__((format(printf,
    /*
     * Inside of __attribute__((...)), symbol lookup works differently.  For
     * example, 'printf' is a keyword, and since all arguments to
     * __attribute__ are constant expressions, looking up global variables
     * would not make sense.  Therefore, 'var' is undefined.
     *
     * See lex.c, function 'search', keyword 'in_gcc_attribute'.
     */
    var = 1,
    /* Syntactically ok, must be a constant expression though. */
    var > 0 ? 2 : 1)))
my_printf(const char *, ...);

void
assignment_associativity(int arg)
{
	int left, right;

	/*
	 * Assignments are right-associative.  If they were left-associative,
	 * the result of (left = right) would be an rvalue, resulting in this
	 * error message: 'left operand of '=' must be lvalue [114]'.
	 */
	left = right = arg;

	left = arg;
}

void
conditional_associativity(_Bool cond1, _Bool cond2, int a, int b, int c)
{
	/* The then-expression can be an arbitrary expression. */
	var = cond1 ? cond2 ? a : b : c;
	var = cond1 ? (cond2 ? a : b) : c;

	/* The then-expression can even be a comma-expression. */
	var = cond1 ? cond2 ? a, b : (b, a) : c;

	var = cond1 ? a : cond2 ? b : c;
	/*
	 * In almost all programming languages, '?:' is right-associative,
	 * which allows for easy chaining.
	 */
	var = cond1 ? a : (cond2 ? b : c);
	/*
	 * In PHP, '?:' is left-associative, which is rather surprising and
	 * requires more parentheses to get the desired effect.
	 */
	var = (cond1 ? a : cond2) ? b : c;
}
