root/usr/src/tools/smatch/src/expression.c
/*
 * sparse/expression.c
 *
 * Copyright (C) 2003 Transmeta Corp.
 *               2003-2004 Linus Torvalds
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * This is the expression parsing part of parsing C.
 */
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>

#include "lib.h"
#include "allocate.h"
#include "token.h"
#include "parse.h"
#include "symbol.h"
#include "scope.h"
#include "expression.h"
#include "target.h"
#include "char.h"

static int match_oplist(int op, ...)
{
        va_list args;
        int nextop;

        va_start(args, op);
        do {
                nextop = va_arg(args, int);
        } while (nextop != 0 && nextop != op);
        va_end(args);

        return nextop != 0;
}

static struct token *comma_expression(struct token *, struct expression **);

struct token *parens_expression(struct token *token, struct expression **expr, const char *where)
{
        struct token *p;

        token = expect(token, '(', where);
        p = token;
        if (match_op(token, '{')) {
                struct expression *e = alloc_expression(token->pos, EXPR_STATEMENT);
                struct statement *stmt = alloc_statement(token->pos, STMT_COMPOUND);
                *expr = e;
                e->statement = stmt;
                start_symbol_scope(e->pos);
                token = compound_statement(token->next, stmt);
                end_symbol_scope();
                token = expect(token, '}', "at end of statement expression");
        } else
                token = parse_expression(token, expr);

        if (token == p)
                sparse_error(token->pos, "an expression is expected before ')'");
        return expect(token, ')', where);
}

/*
 * Handle __func__, __FUNCTION__ and __PRETTY_FUNCTION__ token
 * conversion
 */
static struct symbol *handle_func(struct token *token)
{
        struct ident *ident = token->ident;
        struct symbol *decl, *array;
        struct string *string;
        int len;

        if (ident != &__func___ident &&
            ident != &__FUNCTION___ident &&
            ident != &__PRETTY_FUNCTION___ident)
                return NULL;

        if (!current_fn || !current_fn->ident)
                return NULL;

        /* OK, it's one of ours */
        array = alloc_symbol(token->pos, SYM_ARRAY);
        array->ctype.base_type = &char_ctype;
        array->ctype.alignment = 1;
        array->endpos = token->pos;
        decl = alloc_symbol(token->pos, SYM_NODE);
        decl->ctype.base_type = array;
        decl->ctype.alignment = 1;
        decl->ctype.modifiers = MOD_STATIC;
        decl->endpos = token->pos;

        /* function-scope, but in NS_SYMBOL */
        bind_symbol(decl, ident, NS_LABEL);
        decl->namespace = NS_SYMBOL;

        len = current_fn->ident->len;
        string = __alloc_string(len + 1);
        memcpy(string->data, current_fn->ident->name, len);
        string->data[len] = 0;
        string->length = len + 1;

        decl->initializer = alloc_expression(token->pos, EXPR_STRING);
        decl->initializer->string = string;
        decl->initializer->ctype = decl;
        decl->array_size = alloc_const_expression(token->pos, len + 1);
        array->array_size = decl->array_size;
        decl->bit_size = array->bit_size = bytes_to_bits(len + 1);

        return decl;
}

static struct token *parse_type(struct token *token, struct expression **tree)
{
        struct symbol *sym;
        *tree = alloc_expression(token->pos, EXPR_TYPE);
        token = typename(token, &sym, NULL);
        if (sym->ident)
                sparse_error(token->pos,
                             "type expression should not include identifier "
                             "\"%s\"", sym->ident->name);
        (*tree)->symbol = sym;
        return token;
}

static struct token *builtin_types_compatible_p_expr(struct token *token,
                                                     struct expression **tree)
{
        struct expression *expr = alloc_expression(
                token->pos, EXPR_COMPARE);
        expr->op = SPECIAL_EQUAL;
        token = token->next;
        if (!match_op(token, '('))
                return expect(token, '(',
                              "after __builtin_types_compatible_p");
        token = token->next;
        token = parse_type(token, &expr->left);
        if (!match_op(token, ','))
                return expect(token, ',',
                              "in __builtin_types_compatible_p");
        token = token->next;
        token = parse_type(token, &expr->right);
        if (!match_op(token, ')'))
                return expect(token, ')',
                              "at end of __builtin_types_compatible_p");
        token = token->next;
        
        *tree = expr;
        return token;
}

static struct token *builtin_offsetof_expr(struct token *token,
                                           struct expression **tree)
{
        struct expression *expr = NULL;
        struct expression **p = &expr;
        struct symbol *sym;
        int op = '.';

        token = token->next;
        if (!match_op(token, '('))
                return expect(token, '(', "after __builtin_offset");

        token = token->next;
        token = typename(token, &sym, NULL);
        if (sym->ident)
                sparse_error(token->pos,
                             "type expression should not include identifier "
                             "\"%s\"", sym->ident->name);

        if (!match_op(token, ','))
                return expect(token, ',', "in __builtin_offset");

        while (1) {
                struct expression *e;
                switch (op) {
                case ')':
                        expr->in = sym;
                        *tree = expr;
                default:
                        return expect(token, ')', "at end of __builtin_offset");
                case SPECIAL_DEREFERENCE:
                        e = alloc_expression(token->pos, EXPR_OFFSETOF);
                        e->op = '[';
                        *p = e;
                        p = &e->down;
                        /* fall through */
                case '.':
                        token = token->next;
                        e = alloc_expression(token->pos, EXPR_OFFSETOF);
                        e->op = '.';
                        if (token_type(token) != TOKEN_IDENT) {
                                sparse_error(token->pos, "Expected member name");
                                return token;
                        }
                        e->ident = token->ident;
                        token = token->next;
                        break;
                case '[':
                        token = token->next;
                        e = alloc_expression(token->pos, EXPR_OFFSETOF);
                        e->op = '[';
                        token = parse_expression(token, &e->index);
                        token = expect(token, ']',
                                        "at end of array dereference");
                        if (!e->index)
                                return token;
                }
                *p = e;
                p = &e->down;
                op = token_type(token) == TOKEN_SPECIAL ? token->special : 0;
        }
}

#ifndef ULLONG_MAX
#define ULLONG_MAX (~0ULL)
#endif

static unsigned long long parse_num(const char *nptr, char **end)
{
        if (nptr[0] == '0' && tolower((unsigned char)nptr[1]) == 'b')
                return strtoull(&nptr[2], end, 2);
        return strtoull(nptr, end, 0);
}

static void get_number_value(struct expression *expr, struct token *token)
{
        const char *str = token->number;
        unsigned long long value;
        char *end;
        int size = 0, want_unsigned = 0;
        int overflow = 0, do_warn = 0;
        int try_unsigned = 1;
        int bits;

        errno = 0;
        value = parse_num(str, &end);
        if (end == str)
                goto Float;
        if (value == ULLONG_MAX && errno == ERANGE)
                overflow = 1;
        while (1) {
                char c = *end++;
                if (!c) {
                        break;
                } else if (c == 'u' || c == 'U') {
                        if (want_unsigned)
                                goto Enoint;
                        want_unsigned = 1;
                } else if (c == 'l' || c == 'L') {
                        if (size)
                                goto Enoint;
                        size = 1;
                        if (*end == c) {
                                size = 2;
                                end++;
                        }
                } else
                        goto Float;
        }
        if (overflow)
                goto Eoverflow;
        /* OK, it's a valid integer */
        /* decimals can be unsigned only if directly specified as such */
        if (str[0] != '0' && !want_unsigned)
                try_unsigned = 0;
        if (!size) {
                bits = bits_in_int - 1;
                if (!(value & (~1ULL << bits))) {
                        if (!(value & (1ULL << bits))) {
                                goto got_it;
                        } else if (try_unsigned) {
                                want_unsigned = 1;
                                goto got_it;
                        }
                }
                size = 1;
                do_warn = 1;
        }
        if (size < 2) {
                bits = bits_in_long - 1;
                if (!(value & (~1ULL << bits))) {
                        if (!(value & (1ULL << bits))) {
                                goto got_it;
                        } else if (try_unsigned) {
                                want_unsigned = 1;
                                goto got_it;
                        }
                        do_warn |= 2;
                }
                size = 2;
                do_warn |= 1;
        }
        bits = bits_in_longlong - 1;
        if (value & (~1ULL << bits))
                goto Eoverflow;
        if (!(value & (1ULL << bits)))
                goto got_it;
        if (!try_unsigned)
                warning(expr->pos, "decimal constant %s is too big for long long",
                        show_token(token));
        want_unsigned = 1;
got_it:
        if (do_warn && Wconstant_suffix)
                warning(expr->pos, "constant %s is so big it is%s%s%s",
                        show_token(token),
                        want_unsigned ? " unsigned":"",
                        size > 0 ? " long":"",
                        size > 1 ? " long":"");
        if (do_warn & 2)
                warning(expr->pos,
                        "decimal constant %s is between LONG_MAX and ULONG_MAX."
                        " For C99 that means long long, C90 compilers are very "
                        "likely to produce unsigned long (and a warning) here",
                        show_token(token));
        expr->type = EXPR_VALUE;
        expr->flags = CEF_SET_INT;
        expr->ctype = ctype_integer(size, want_unsigned);
        expr->value = value;
        return;
Eoverflow:
        error_die(expr->pos, "constant %s is too big even for unsigned long long",
                        show_token(token));
        return;
Float:
        expr->fvalue = string_to_ld(str, &end);
        if (str == end)
                goto Enoint;

        if (*end && end[1])
                goto Enoint;

        if (*end == 'f' || *end == 'F')
                expr->ctype = &float_ctype;
        else if (*end == 'l' || *end == 'L')
                expr->ctype = &ldouble_ctype;
        else if (!*end)
                expr->ctype = &double_ctype;
        else
                goto Enoint;

        expr->flags = CEF_SET_FLOAT;
        expr->type = EXPR_FVALUE;
        return;

Enoint:
        error_die(expr->pos, "constant %s is not a valid number", show_token(token));
}

struct token *primary_expression(struct token *token, struct expression **tree)
{
        struct expression *expr = NULL;

        switch (token_type(token)) {
        case TOKEN_CHAR ... TOKEN_WIDE_CHAR_EMBEDDED_3:
                expr = alloc_expression(token->pos, EXPR_VALUE);
                expr->flags = CEF_SET_CHAR;
                expr->ctype = token_type(token) < TOKEN_WIDE_CHAR ? &int_ctype : &long_ctype;
                get_char_constant(token, &expr->value);
                token = token->next;
                break;

        case TOKEN_NUMBER:
                expr = alloc_expression(token->pos, EXPR_VALUE);
                get_number_value(expr, token); /* will see if it's an integer */
                token = token->next;
                break;

        case TOKEN_ZERO_IDENT: {
                expr = alloc_expression(token->pos, EXPR_SYMBOL);
                expr->flags = CEF_SET_INT;
                expr->ctype = &int_ctype;
                expr->symbol = &zero_int;
                expr->symbol_name = token->ident;
                token = token->next;
                break;
        }

        case TOKEN_IDENT: {
                struct symbol *sym = lookup_symbol(token->ident, NS_SYMBOL | NS_TYPEDEF);
                struct token *next = token->next;

                if (!sym) {
                        sym = handle_func(token);
                        if (token->ident == &__builtin_types_compatible_p_ident) {
                                token = builtin_types_compatible_p_expr(token, &expr);
                                break;
                        }
                        if (token->ident == &__builtin_offsetof_ident) {
                                token = builtin_offsetof_expr(token, &expr);
                                break;
                        }
                } else if (sym->enum_member) {
                        expr = alloc_expression(token->pos, EXPR_VALUE);
                        *expr = *sym->initializer;
                        /* we want the right position reported, thus the copy */
                        expr->pos = token->pos;
                        expr->flags = CEF_SET_ENUM;
                        token = next;
                        break;
                }

                expr = alloc_expression(token->pos, EXPR_SYMBOL);

                /*
                 * We support types as real first-class citizens, with type
                 * comparisons etc:
                 *
                 *      if (typeof(a) == int) ..
                 */
                if (sym && sym->namespace == NS_TYPEDEF) {
                        sparse_error(token->pos, "typename in expression");
                        sym = NULL;
                }
                expr->symbol_name = token->ident;
                expr->symbol = sym;

                /*
                 * A pointer to an lvalue designating a static storage
                 * duration object is an address constant [6.6(9)].
                 */
                if (sym && (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_STATIC)))
                        expr->flags = CEF_ADDR;

                token = next;
                break;
        }

        case TOKEN_STRING:
        case TOKEN_WIDE_STRING:
                expr = alloc_expression(token->pos, EXPR_STRING);
                token = get_string_constant(token, expr);
                break;

        case TOKEN_SPECIAL:
                if (token->special == '(') {
                        expr = alloc_expression(token->pos, EXPR_PREOP);
                        expr->op = '(';
                        token = parens_expression(token, &expr->unop, "in expression");
                        break;
                }
                if (token->special == '[' && lookup_type(token->next)) {
                        expr = alloc_expression(token->pos, EXPR_TYPE);
                        token = typename(token->next, &expr->symbol, NULL);
                        token = expect(token, ']', "in type expression");
                        break;
                }
                        
        default:
                ;
        }
        *tree = expr;
        return token;
}

static struct token *expression_list(struct token *token, struct expression_list **list)
{
        while (!match_op(token, ')')) {
                struct expression *expr = NULL;
                token = assignment_expression(token, &expr);
                if (!expr)
                        break;
                add_expression(list, expr);
                if (!match_op(token, ','))
                        break;
                token = token->next;
        }
        return token;
}

/*
 * extend to deal with the ambiguous C grammar for parsing
 * a cast expressions followed by an initializer.
 */
static struct token *postfix_expression(struct token *token, struct expression **tree, struct expression *cast_init_expr)
{
        struct expression *expr = cast_init_expr;

        if (!expr)
                token = primary_expression(token, &expr);

        while (expr && token_type(token) == TOKEN_SPECIAL) {
                switch (token->special) {
                case '[': {                     /* Array dereference */
                        struct expression *deref = alloc_expression(token->pos, EXPR_PREOP);
                        struct expression *add = alloc_expression(token->pos, EXPR_BINOP);

                        deref->op = '*';
                        deref->unop = add;

                        add->op = '+';
                        add->left = expr;
                        token = parse_expression(token->next, &add->right);
                        token = expect(token, ']', "at end of array dereference");
                        expr = deref;
                        continue;
                }
                case SPECIAL_INCREMENT:         /* Post-increment */
                case SPECIAL_DECREMENT: {       /* Post-decrement */
                        struct expression *post = alloc_expression(token->pos, EXPR_POSTOP);
                        post->op = token->special;
                        post->unop = expr;
                        expr = post;
                        token = token->next;
                        continue;
                }
                case SPECIAL_DEREFERENCE: {     /* Structure pointer member dereference */
                        /* "x->y" is just shorthand for "(*x).y" */
                        struct expression *inner = alloc_expression(token->pos, EXPR_PREOP);
                        inner->op = '*';
                        inner->unop = expr;
                        expr = inner;
                }
                /* Fall through!! */
                case '.': {                     /* Structure member dereference */
                        struct expression *deref = alloc_expression(token->pos, EXPR_DEREF);
                        deref->op = '.';
                        deref->deref = expr;
                        token = token->next;
                        if (token_type(token) != TOKEN_IDENT) {
                                sparse_error(token->pos, "Expected member name");
                                break;
                        }
                        deref->member = token->ident;
                        deref->member_offset = -1;
                        token = token->next;
                        expr = deref;
                        continue;
                }

                case '(': {                     /* Function call */
                        struct expression *call = alloc_expression(token->pos, EXPR_CALL);
                        call->op = '(';
                        call->fn = expr;
                        token = expression_list(token->next, &call->args);
                        token = expect(token, ')', "in function call");
                        expr = call;
                        continue;
                }

                default:
                        break;
                }
                break;
        }
        *tree = expr;
        return token;
}

static struct token *cast_expression(struct token *token, struct expression **tree);
static struct token *unary_expression(struct token *token, struct expression **tree);

static struct token *type_info_expression(struct token *token,
        struct expression **tree, int type)
{
        struct expression *expr = alloc_expression(token->pos, type);
        struct token *p;

        *tree = expr;
        expr->flags = CEF_SET_ICE; /* XXX: VLA support will need that changed */
        token = token->next;
        if (!match_op(token, '(') || !lookup_type(token->next))
                return unary_expression(token, &expr->cast_expression);
        p = token;
        token = typename(token->next, &expr->cast_type, NULL);

        if (!match_op(token, ')')) {
                static const char * error[] = {
                        [EXPR_SIZEOF] = "at end of sizeof",
                        [EXPR_ALIGNOF] = "at end of __alignof__",
                        [EXPR_PTRSIZEOF] = "at end of __sizeof_ptr__"
                };
                return expect(token, ')', error[type]);
        }

        token = token->next;
        /*
         * C99 ambiguity: the typename might have been the beginning
         * of a typed initializer expression..
         */
        if (match_op(token, '{')) {
                struct expression *cast = alloc_expression(p->pos, EXPR_CAST);
                cast->cast_type = expr->cast_type;
                expr->cast_type = NULL;
                expr->cast_expression = cast;
                token = initializer(&cast->cast_expression, token);
                token = postfix_expression(token, &expr->cast_expression, cast);
        }
        return token;
}

static struct token *unary_expression(struct token *token, struct expression **tree)
{
        if (token_type(token) == TOKEN_IDENT) {
                struct ident *ident = token->ident;
                if (ident->reserved) {
                        static const struct {
                                struct ident *id;
                                int type;
                        } type_information[] = {
                                { &sizeof_ident, EXPR_SIZEOF },
                                { &__alignof___ident, EXPR_ALIGNOF },
                                { &__alignof_ident, EXPR_ALIGNOF },
                                { &_Alignof_ident, EXPR_ALIGNOF },
                                { &__sizeof_ptr___ident, EXPR_PTRSIZEOF },
                        };
                        int i;
                        for (i = 0; i < ARRAY_SIZE(type_information); i++) {
                                if (ident == type_information[i].id)
                                        return type_info_expression(token, tree, type_information[i].type);
                        }
                }
        }

        if (token_type(token) == TOKEN_SPECIAL) {
                if (match_oplist(token->special,
                    SPECIAL_INCREMENT, SPECIAL_DECREMENT,
                    '&', '*', 0)) {
                        struct expression *unop;
                        struct expression *unary;
                        struct token *next;

                        next = cast_expression(token->next, &unop);
                        if (!unop) {
                                sparse_error(token->pos, "Syntax error in unary expression");
                                *tree = NULL;
                                return next;
                        }
                        unary = alloc_expression(token->pos, EXPR_PREOP);
                        unary->op = token->special;
                        unary->unop = unop;
                        *tree = unary;
                        return next;
                }
                /* possibly constant ones */
                if (match_oplist(token->special, '+', '-', '~', '!', 0)) {
                        struct expression *unop;
                        struct expression *unary;
                        struct token *next;

                        next = cast_expression(token->next, &unop);
                        if (!unop) {
                                sparse_error(token->pos, "Syntax error in unary expression");
                                *tree = NULL;
                                return next;
                        }
                        unary = alloc_expression(token->pos, EXPR_PREOP);
                        unary->op = token->special;
                        unary->unop = unop;
                        *tree = unary;
                        return next;
                }
                /* Gcc extension: &&label gives the address of a label */
                if (match_op(token, SPECIAL_LOGICAL_AND) &&
                    token_type(token->next) == TOKEN_IDENT) {
                        struct expression *label = alloc_expression(token->pos, EXPR_LABEL);
                        struct symbol *sym = label_symbol(token->next);
                        if (!(sym->ctype.modifiers & MOD_ADDRESSABLE)) {
                                sym->ctype.modifiers |= MOD_ADDRESSABLE;
                                add_symbol(&function_computed_target_list, sym);
                        }
                        label->flags = CEF_ADDR;
                        label->label_symbol = sym;
                        *tree = label;
                        return token->next->next;
                }
                                                
        }
                        
        return postfix_expression(token, tree, NULL);
}

/*
 * Ambiguity: a '(' can be either a cast-expression or
 * a primary-expression depending on whether it is followed
 * by a type or not. 
 *
 * additional ambiguity: a "cast expression" followed by
 * an initializer is really a postfix-expression.
 */
static struct token *cast_expression(struct token *token, struct expression **tree)
{
        if (match_op(token, '(')) {
                struct token *next = token->next;
                if (lookup_type(next)) {
                        struct expression *cast = alloc_expression(next->pos, EXPR_CAST);
                        struct expression *v;
                        struct symbol *sym;
                        int is_force;

                        token = typename(next, &sym, &is_force);
                        cast->cast_type = sym;
                        token = expect(token, ')', "at end of cast operator");
                        if (match_op(token, '{')) {
                                if (toplevel(block_scope))
                                        sym->ctype.modifiers |= MOD_TOPLEVEL;
                                if (is_force)
                                        warning(sym->pos,
                                                "[force] in compound literal");
                                token = initializer(&cast->cast_expression, token);
                                return postfix_expression(token, tree, cast);
                        }
                        *tree = cast;
                        if (is_force)
                                cast->type = EXPR_FORCE_CAST;
                        token = cast_expression(token, &v);
                        if (!v)
                                return token;
                        cast->cast_expression = v;
                        return token;
                }
        }
        return unary_expression(token, tree);
}

/*
 * Generic left-to-right binop parsing
 *
 * This _really_ needs to be inlined, because that makes the inner
 * function call statically deterministic rather than a totally
 * unpredictable indirect call. But gcc-3 is so "clever" that it
 * doesn't do so by default even when you tell it to inline it.
 *
 * Making it a macro avoids the inlining problem, and also means
 * that we can pass in the op-comparison as an expression rather
 * than create a data structure for it.
 */

#define LR_BINOP_EXPRESSION(__token, tree, type, inner, compare)        \
        struct expression *left = NULL;                                 \
        struct token * next = inner(__token, &left);                    \
                                                                        \
        if (left) {                                                     \
                while (token_type(next) == TOKEN_SPECIAL) {             \
                        struct expression *top, *right = NULL;          \
                        int op = next->special;                         \
                                                                        \
                        if (!(compare))                                 \
                                goto out;                               \
                        top = alloc_expression(next->pos, type);        \
                        next = inner(next->next, &right);               \
                        if (!right) {                                   \
                                sparse_error(next->pos, "No right hand side of '%s'-expression", show_special(op));     \
                                break;                                  \
                        }                                               \
                        top->op = op;                                   \
                        top->left = left;                               \
                        top->right = right;                             \
                        left = top;                                     \
                }                                                       \
        }                                                               \
out:                                                                    \
        *tree = left;                                                   \
        return next;                                                    \

static struct token *multiplicative_expression(struct token *token, struct expression **tree)
{
        LR_BINOP_EXPRESSION(
                token, tree, EXPR_BINOP, cast_expression,
                (op == '*') || (op == '/') || (op == '%')
        );
}

static struct token *additive_expression(struct token *token, struct expression **tree)
{
        LR_BINOP_EXPRESSION(
                token, tree, EXPR_BINOP, multiplicative_expression,
                (op == '+') || (op == '-')
        );
}

static struct token *shift_expression(struct token *token, struct expression **tree)
{
        LR_BINOP_EXPRESSION(
                token, tree, EXPR_BINOP, additive_expression,
                (op == SPECIAL_LEFTSHIFT) || (op == SPECIAL_RIGHTSHIFT)
        );
}

static struct token *relational_expression(struct token *token, struct expression **tree)
{
        LR_BINOP_EXPRESSION(
                token, tree, EXPR_COMPARE, shift_expression,
                (op == '<') || (op == '>') ||
                (op == SPECIAL_LTE) || (op == SPECIAL_GTE)
        );
}

static struct token *equality_expression(struct token *token, struct expression **tree)
{
        LR_BINOP_EXPRESSION(
                token, tree, EXPR_COMPARE, relational_expression,
                (op == SPECIAL_EQUAL) || (op == SPECIAL_NOTEQUAL)
        );
}

static struct token *bitwise_and_expression(struct token *token, struct expression **tree)
{
        LR_BINOP_EXPRESSION(
                token, tree, EXPR_BINOP, equality_expression,
                (op == '&')
        );
}

static struct token *bitwise_xor_expression(struct token *token, struct expression **tree)
{
        LR_BINOP_EXPRESSION(
                token, tree, EXPR_BINOP, bitwise_and_expression,
                (op == '^')
        );
}

static struct token *bitwise_or_expression(struct token *token, struct expression **tree)
{
        LR_BINOP_EXPRESSION(
                token, tree, EXPR_BINOP, bitwise_xor_expression,
                (op == '|')
        );
}

static struct token *logical_and_expression(struct token *token, struct expression **tree)
{
        LR_BINOP_EXPRESSION(
                token, tree, EXPR_LOGICAL, bitwise_or_expression,
                (op == SPECIAL_LOGICAL_AND)
        );
}

static struct token *logical_or_expression(struct token *token, struct expression **tree)
{
        LR_BINOP_EXPRESSION(
                token, tree, EXPR_LOGICAL, logical_and_expression,
                (op == SPECIAL_LOGICAL_OR)
        );
}

struct token *conditional_expression(struct token *token, struct expression **tree)
{
        token = logical_or_expression(token, tree);
        if (*tree && match_op(token, '?')) {
                struct expression *expr = alloc_expression(token->pos, EXPR_CONDITIONAL);
                expr->op = token->special;
                expr->left = *tree;
                *tree = expr;
                token = parse_expression(token->next, &expr->cond_true);
                token = expect(token, ':', "in conditional expression");
                token = conditional_expression(token, &expr->cond_false);
        }
        return token;
}

struct token *assignment_expression(struct token *token, struct expression **tree)
{
        token = conditional_expression(token, tree);
        if (*tree && token_type(token) == TOKEN_SPECIAL) {
                static const int assignments[] = {
                        '=',
                        SPECIAL_ADD_ASSIGN, SPECIAL_SUB_ASSIGN,
                        SPECIAL_MUL_ASSIGN, SPECIAL_DIV_ASSIGN,
                        SPECIAL_MOD_ASSIGN, SPECIAL_SHL_ASSIGN,
                        SPECIAL_SHR_ASSIGN, SPECIAL_AND_ASSIGN,
                        SPECIAL_OR_ASSIGN,  SPECIAL_XOR_ASSIGN };
                int i, op = token->special;
                for (i = 0; i < ARRAY_SIZE(assignments); i++)
                        if (assignments[i] == op) {
                                struct expression * expr = alloc_expression(token->pos, EXPR_ASSIGNMENT);
                                expr->left = *tree;
                                expr->op = op;
                                *tree = expr;
                                return assignment_expression(token->next, &expr->right);
                        }
        }
        return token;
}

static struct token *comma_expression(struct token *token, struct expression **tree)
{
        LR_BINOP_EXPRESSION(
                token, tree, EXPR_COMMA, assignment_expression,
                (op == ',')
        );
}

struct token *parse_expression(struct token *token, struct expression **tree)
{
        return comma_expression(token,tree);
}