/*      $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;
}