widl: Move expression functions to a new file, expr.c.
diff --git a/tools/widl/Makefile.in b/tools/widl/Makefile.in
index a3145b2..a17a525 100644
--- a/tools/widl/Makefile.in
+++ b/tools/widl/Makefile.in
@@ -10,6 +10,7 @@
 
 C_SRCS = \
 	client.c \
+	expr.c \
 	hash.c \
 	header.c \
 	proxy.c \
diff --git a/tools/widl/client.c b/tools/widl/client.c
index d15dfdc..889d2f1 100644
--- a/tools/widl/client.c
+++ b/tools/widl/client.c
@@ -36,6 +36,7 @@
 
 #include "widltypes.h"
 #include "typegen.h"
+#include "expr.h"
 
 static FILE* client;
 static int indent = 0;
diff --git a/tools/widl/expr.c b/tools/widl/expr.c
new file mode 100644
index 0000000..ca9986a
--- /dev/null
+++ b/tools/widl/expr.c
@@ -0,0 +1,775 @@
+/*
+ * Expression Abstract Syntax Tree Functions
+ *
+ * Copyright 2002 Ove Kaaven
+ * Copyright 2006-2008 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "widl.h"
+#include "utils.h"
+#include "expr.h"
+#include "header.h"
+
+expr_t *make_expr(enum expr_type type)
+{
+    expr_t *e = xmalloc(sizeof(expr_t));
+    e->type = type;
+    e->ref = NULL;
+    e->u.lval = 0;
+    e->is_const = FALSE;
+    e->cval = 0;
+    return e;
+}
+
+expr_t *make_exprl(enum expr_type type, long val)
+{
+    expr_t *e = xmalloc(sizeof(expr_t));
+    e->type = type;
+    e->ref = NULL;
+    e->u.lval = val;
+    e->is_const = FALSE;
+    /* check for numeric constant */
+    if (type == EXPR_NUM || type == EXPR_HEXNUM || type == EXPR_TRUEFALSE)
+    {
+        /* make sure true/false value is valid */
+        assert(type != EXPR_TRUEFALSE || val == 0 || val == 1);
+        e->is_const = TRUE;
+        e->cval = val;
+    }
+    return e;
+}
+
+expr_t *make_exprd(enum expr_type type, double val)
+{
+    expr_t *e = xmalloc(sizeof(expr_t));
+    e->type = type;
+    e->ref = NULL;
+    e->u.dval = val;
+    e->is_const = TRUE;
+    e->cval = val;
+    return e;
+}
+
+expr_t *make_exprs(enum expr_type type, char *val)
+{
+    expr_t *e;
+    e = xmalloc(sizeof(expr_t));
+    e->type = type;
+    e->ref = NULL;
+    e->u.sval = val;
+    e->is_const = FALSE;
+    /* check for predefined constants */
+    if (type == EXPR_IDENTIFIER)
+    {
+        var_t *c = find_const(val, 0);
+        if (c)
+        {
+            e->u.sval = c->name;
+            free(val);
+            e->is_const = TRUE;
+            e->cval = c->eval->cval;
+        }
+    }
+    return e;
+}
+
+expr_t *make_exprt(enum expr_type type, type_t *tref, expr_t *expr)
+{
+    expr_t *e;
+    e = xmalloc(sizeof(expr_t));
+    e->type = type;
+    e->ref = expr;
+    e->u.tref = tref;
+    e->is_const = FALSE;
+    /* check for cast of constant expression */
+    if (type == EXPR_SIZEOF)
+    {
+        switch (tref->type)
+        {
+        case RPC_FC_BYTE:
+        case RPC_FC_CHAR:
+        case RPC_FC_SMALL:
+        case RPC_FC_USMALL:
+            e->is_const = TRUE;
+            e->cval = 1;
+            break;
+        case RPC_FC_WCHAR:
+        case RPC_FC_USHORT:
+        case RPC_FC_SHORT:
+            e->is_const = TRUE;
+            e->cval = 2;
+            break;
+        case RPC_FC_LONG:
+        case RPC_FC_ULONG:
+        case RPC_FC_FLOAT:
+        case RPC_FC_ERROR_STATUS_T:
+            e->is_const = TRUE;
+            e->cval = 4;
+            break;
+        case RPC_FC_HYPER:
+        case RPC_FC_DOUBLE:
+            e->is_const = TRUE;
+            e->cval = 8;
+            break;
+        }
+    }
+    if (type == EXPR_CAST && expr->is_const)
+    {
+        e->is_const = TRUE;
+        e->cval = expr->cval;
+    }
+    return e;
+}
+
+expr_t *make_expr1(enum expr_type type, expr_t *expr)
+{
+    expr_t *e;
+    e = xmalloc(sizeof(expr_t));
+    e->type = type;
+    e->ref = expr;
+    e->u.lval = 0;
+    e->is_const = FALSE;
+    /* check for compile-time optimization */
+    if (expr->is_const)
+    {
+        e->is_const = TRUE;
+        switch (type)
+        {
+        case EXPR_LOGNOT:
+            e->cval = !expr->cval;
+            break;
+        case EXPR_POS:
+            e->cval = +expr->cval;
+            break;
+        case EXPR_NEG:
+            e->cval = -expr->cval;
+            break;
+        case EXPR_NOT:
+            e->cval = ~expr->cval;
+            break;
+        default:
+            e->is_const = FALSE;
+            break;
+        }
+    }
+    return e;
+}
+
+expr_t *make_expr2(enum expr_type type, expr_t *expr1, expr_t *expr2)
+{
+    expr_t *e;
+    e = xmalloc(sizeof(expr_t));
+    e->type = type;
+    e->ref = expr1;
+    e->u.ext = expr2;
+    e->is_const = FALSE;
+    /* check for compile-time optimization */
+    if (expr1->is_const && expr2->is_const)
+    {
+        e->is_const = TRUE;
+        switch (type)
+        {
+        case EXPR_ADD:
+            e->cval = expr1->cval + expr2->cval;
+            break;
+        case EXPR_SUB:
+            e->cval = expr1->cval - expr2->cval;
+            break;
+        case EXPR_MOD:
+            if (expr2->cval == 0)
+            {
+                error_loc("divide by zero in expression\n");
+                e->cval = 0;
+            }
+            else
+                e->cval = expr1->cval % expr2->cval;
+            break;
+        case EXPR_MUL:
+            e->cval = expr1->cval * expr2->cval;
+            break;
+        case EXPR_DIV:
+            if (expr2->cval == 0)
+            {
+                error_loc("divide by zero in expression\n");
+                e->cval = 0;
+            }
+            else
+                e->cval = expr1->cval / expr2->cval;
+            break;
+        case EXPR_OR:
+            e->cval = expr1->cval | expr2->cval;
+            break;
+        case EXPR_AND:
+            e->cval = expr1->cval & expr2->cval;
+            break;
+        case EXPR_SHL:
+            e->cval = expr1->cval << expr2->cval;
+            break;
+        case EXPR_SHR:
+            e->cval = expr1->cval >> expr2->cval;
+            break;
+        case EXPR_LOGOR:
+            e->cval = expr1->cval || expr2->cval;
+            break;
+        case EXPR_LOGAND:
+            e->cval = expr1->cval && expr2->cval;
+            break;
+        case EXPR_XOR:
+            e->cval = expr1->cval ^ expr2->cval;
+            break;
+        case EXPR_EQUALITY:
+            e->cval = expr1->cval == expr2->cval;
+            break;
+        case EXPR_INEQUALITY:
+            e->cval = expr1->cval != expr2->cval;
+            break;
+        case EXPR_GTR:
+            e->cval = expr1->cval > expr2->cval;
+            break;
+        case EXPR_LESS:
+            e->cval = expr1->cval < expr2->cval;
+            break;
+        case EXPR_GTREQL:
+            e->cval = expr1->cval >= expr2->cval;
+            break;
+        case EXPR_LESSEQL:
+            e->cval = expr1->cval <= expr2->cval;
+            break;
+        default:
+            e->is_const = FALSE;
+            break;
+        }
+    }
+    return e;
+}
+
+expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, expr_t *expr3)
+{
+    expr_t *e;
+    e = xmalloc(sizeof(expr_t));
+    e->type = type;
+    e->ref = expr1;
+    e->u.ext = expr2;
+    e->ext2 = expr3;
+    e->is_const = FALSE;
+    /* check for compile-time optimization */
+    if (expr1->is_const && expr2->is_const && expr3->is_const)
+    {
+        e->is_const = TRUE;
+        switch (type)
+        {
+        case EXPR_COND:
+            e->cval = expr1->cval ? expr2->cval : expr3->cval;
+            break;
+        default:
+            e->is_const = FALSE;
+            break;
+        }
+    }
+    return e;
+}
+
+struct expression_type
+{
+    int is_variable; /* is the expression resolved to a variable? */
+    int is_temporary; /* should the type be freed? */
+    type_t *type;
+};
+
+static int is_integer_type(const type_t *type)
+{
+    switch (type->type)
+    {
+    case RPC_FC_BYTE:
+    case RPC_FC_CHAR:
+    case RPC_FC_SMALL:
+    case RPC_FC_USMALL:
+    case RPC_FC_WCHAR:
+    case RPC_FC_SHORT:
+    case RPC_FC_USHORT:
+    case RPC_FC_LONG:
+    case RPC_FC_ULONG:
+    case RPC_FC_INT3264:
+    case RPC_FC_UINT3264:
+    case RPC_FC_HYPER:
+    case RPC_FC_ENUM16:
+    case RPC_FC_ENUM32:
+        return TRUE;
+    default:
+        return FALSE;
+    }
+}
+
+static void check_scalar_type(const struct expr_loc *expr_loc,
+                              const type_t *cont_type, const type_t *type)
+{
+    if (!cont_type || (!is_integer_type(type) && !is_ptr(type) &&
+                       type->type != RPC_FC_FLOAT &&
+                       type->type != RPC_FC_DOUBLE))
+        error_loc_info(&expr_loc->v->loc_info, "scalar type required in expression%s%s\n",
+                       expr_loc->attr ? " for attribute " : "",
+                       expr_loc->attr ? expr_loc->attr : "");
+}
+
+static void check_arithmetic_type(const struct expr_loc *expr_loc,
+                                  const type_t *cont_type, const type_t *type)
+{
+    if (!cont_type || (!is_integer_type(type) &&
+                       type->type != RPC_FC_FLOAT &&
+                       type->type != RPC_FC_DOUBLE))
+        error_loc_info(&expr_loc->v->loc_info, "arithmetic type required in expression%s%s\n",
+                       expr_loc->attr ? " for attribute " : "",
+                       expr_loc->attr ? expr_loc->attr : "");
+}
+
+static void check_integer_type(const struct expr_loc *expr_loc,
+                               const type_t *cont_type, const type_t *type)
+{
+    if (!cont_type || !is_integer_type(type))
+        error_loc_info(&expr_loc->v->loc_info, "integer type required in expression%s%s\n",
+                       expr_loc->attr ? " for attribute " : "",
+                       expr_loc->attr ? expr_loc->attr : "");
+}
+
+static struct expression_type resolve_expression(const struct expr_loc *expr_loc,
+                                                 const type_t *cont_type,
+                                                 const expr_t *e)
+{
+    struct expression_type result;
+    result.is_variable = FALSE;
+    result.is_temporary = FALSE;
+    result.type = NULL;
+    switch (e->type)
+    {
+    case EXPR_VOID:
+        break;
+    case EXPR_HEXNUM:
+    case EXPR_NUM:
+    case EXPR_TRUEFALSE:
+        result.is_variable = FALSE;
+        result.is_temporary = FALSE;
+        result.type = find_type("int", 0);
+        break;
+    case EXPR_DOUBLE:
+        result.is_variable = FALSE;
+        result.is_temporary = FALSE;
+        result.type = find_type("double", 0);
+        break;
+    case EXPR_IDENTIFIER:
+    {
+        const var_t *field;
+        const var_list_t *fields = NULL;
+
+        if (cont_type && (cont_type->type == RPC_FC_FUNCTION || is_struct(cont_type->type)))
+            fields = cont_type->fields_or_args;
+        else if (cont_type && is_union(cont_type->type))
+        {
+            if (cont_type->type == RPC_FC_ENCAPSULATED_UNION)
+            {
+                const var_t *uv = LIST_ENTRY(list_tail(cont_type->fields_or_args), const var_t, entry);
+                fields = uv->type->fields_or_args;
+            }
+            else
+                fields = cont_type->fields_or_args;
+        }
+
+        if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
+            if (field->name && !strcmp(e->u.sval, field->name))
+            {
+                result.type = field->type;
+                break;
+            }
+
+        if (!result.type)
+        {
+            var_t *const_var = find_const(e->u.sval, 0);
+            if (const_var) result.type = const_var->type;
+        }
+        if (!result.type)
+        {
+            error_loc_info(&expr_loc->v->loc_info, "identifier %s cannot be resolved in expression%s%s\n",
+                           e->u.sval, expr_loc->attr ? " for attribute " : "",
+                           expr_loc->attr ? expr_loc->attr : "");
+        }
+        break;
+    }
+    case EXPR_LOGNOT:
+        result = resolve_expression(expr_loc, cont_type, e->ref);
+        check_scalar_type(expr_loc, cont_type, result.type);
+        result.is_variable = FALSE;
+        result.is_temporary = FALSE;
+        result.type = find_type("int", 0);
+        break;
+    case EXPR_NOT:
+        result = resolve_expression(expr_loc, cont_type, e->ref);
+        check_integer_type(expr_loc, cont_type, result.type);
+        result.is_variable = FALSE;
+        break;
+    case EXPR_POS:
+    case EXPR_NEG:
+        result = resolve_expression(expr_loc, cont_type, e->ref);
+        check_arithmetic_type(expr_loc, cont_type, result.type);
+        result.is_variable = FALSE;
+        break;
+    case EXPR_ADDRESSOF:
+        result = resolve_expression(expr_loc, cont_type, e->ref);
+        if (!result.is_variable)
+            error_loc_info(&expr_loc->v->loc_info, "address-of operator applied to non-variable type in expression%s%s\n",
+                           expr_loc->attr ? " for attribute " : "",
+                           expr_loc->attr ? expr_loc->attr : "");
+            result.is_variable = FALSE;
+        result.is_temporary = TRUE;
+        result.type = make_type(RPC_FC_RP, result.type);
+        break;
+    case EXPR_PPTR:
+        result = resolve_expression(expr_loc, cont_type, e->ref);
+        if (result.type && is_ptr(result.type))
+            result.type = result.type->ref;
+        else
+            error_loc_info(&expr_loc->v->loc_info, "dereference operator applied to non-pointer type in expression%s%s\n",
+                           expr_loc->attr ? " for attribute " : "",
+                           expr_loc->attr ? expr_loc->attr : "");
+        break;
+    case EXPR_CAST:
+        result = resolve_expression(expr_loc, cont_type, e->ref);
+        result.type = e->u.tref;
+        break;
+    case EXPR_SIZEOF:
+        result.is_variable = FALSE;
+        result.is_temporary = FALSE;
+        result.type = find_type("int", 0);
+        break;
+    case EXPR_SHL:
+    case EXPR_SHR:
+    case EXPR_MOD:
+    case EXPR_MUL:
+    case EXPR_DIV:
+    case EXPR_ADD:
+    case EXPR_SUB:
+    case EXPR_AND:
+    case EXPR_OR:
+    case EXPR_XOR:
+    {
+        struct expression_type result_right;
+        result = resolve_expression(expr_loc, cont_type, e->ref);
+        result.is_variable = FALSE;
+        result_right = resolve_expression(expr_loc, cont_type, e->u.ext);
+        /* FIXME: these checks aren't strict enough for some of the operators */
+        check_scalar_type(expr_loc, cont_type, result.type);
+        check_scalar_type(expr_loc, cont_type, result_right.type);
+        break;
+    }
+    case EXPR_LOGOR:
+    case EXPR_LOGAND:
+    case EXPR_EQUALITY:
+    case EXPR_INEQUALITY:
+    case EXPR_GTR:
+    case EXPR_LESS:
+    case EXPR_GTREQL:
+    case EXPR_LESSEQL:
+    {
+        struct expression_type result_left, result_right;
+        result_left = resolve_expression(expr_loc, cont_type, e->ref);
+        result_right = resolve_expression(expr_loc, cont_type, e->u.ext);
+        check_scalar_type(expr_loc, cont_type, result_left.type);
+        check_scalar_type(expr_loc, cont_type, result_right.type);
+        result.is_variable = FALSE;
+        result.is_temporary = FALSE;
+        result.type = find_type("int", 0);
+        break;
+    }
+    case EXPR_MEMBER:
+        result = resolve_expression(expr_loc, cont_type, e->ref);
+        if (result.type && (is_struct(result.type->type) || is_union(result.type->type) || result.type->type == RPC_FC_ENUM16 || result.type->type == RPC_FC_ENUM32))
+            result = resolve_expression(expr_loc, result.type, e->u.ext);
+        else
+            error_loc_info(&expr_loc->v->loc_info, "'.' or '->' operator applied to a type that isn't a structure, union or enumeration in expression%s%s\n",
+                           expr_loc->attr ? " for attribute " : "",
+                           expr_loc->attr ? expr_loc->attr : "");
+        break;
+    case EXPR_COND:
+    {
+        struct expression_type result_first, result_second, result_third;
+        result_first = resolve_expression(expr_loc, cont_type, e->ref);
+        check_scalar_type(expr_loc, cont_type, result_first.type);
+        result_second = resolve_expression(expr_loc, cont_type, e->u.ext);
+        result_third = resolve_expression(expr_loc, cont_type, e->ext2);
+        /* FIXME: determine the correct return type */
+        result = result_second;
+        result.is_variable = FALSE;
+        break;
+    }
+    case EXPR_ARRAY:
+        result = resolve_expression(expr_loc, cont_type, e->ref);
+        if (result.type && is_array(result.type))
+        {
+            struct expression_type index_result;
+            result.type = result.type->ref;
+            index_result = resolve_expression(expr_loc, cont_type /* FIXME */, e->u.ext);
+            if (!index_result.type || !is_integer_type(index_result.type))
+                error_loc_info(&expr_loc->v->loc_info, "array subscript not of integral type in expression%s%s\n",
+                               expr_loc->attr ? " for attribute " : "",
+                               expr_loc->attr ? expr_loc->attr : "");
+        }
+        else
+            error_loc_info(&expr_loc->v->loc_info, "array subscript operator applied to non-array type in expression%s%s\n",
+                           expr_loc->attr ? " for attribute " : "",
+                           expr_loc->attr ? expr_loc->attr : "");
+        break;
+    }
+    return result;
+}
+
+const type_t *expr_resolve_type(const struct expr_loc *expr_loc, const type_t *cont_type, const expr_t *expr)
+{
+    struct expression_type expr_type;
+    expr_type = resolve_expression(expr_loc, cont_type, expr);
+    return expr_type.type;
+}
+
+void write_expr(FILE *h, const expr_t *e, int brackets)
+{
+    switch (e->type)
+    {
+    case EXPR_VOID:
+        break;
+    case EXPR_NUM:
+        fprintf(h, "%lu", e->u.lval);
+        break;
+    case EXPR_HEXNUM:
+        fprintf(h, "0x%lx", e->u.lval);
+        break;
+    case EXPR_DOUBLE:
+        fprintf(h, "%#.15g", e->u.dval);
+        break;
+    case EXPR_TRUEFALSE:
+        if (e->u.lval == 0)
+            fprintf(h, "FALSE");
+        else
+            fprintf(h, "TRUE");
+        break;
+    case EXPR_IDENTIFIER:
+        fprintf(h, "%s", e->u.sval);
+        break;
+    case EXPR_LOGNOT:
+        fprintf(h, "!");
+        write_expr(h, e->ref, 1);
+        break;
+    case EXPR_NOT:
+        fprintf(h, "~");
+        write_expr(h, e->ref, 1);
+        break;
+    case EXPR_POS:
+        fprintf(h, "+");
+        write_expr(h, e->ref, 1);
+        break;
+    case EXPR_NEG:
+        fprintf(h, "-");
+        write_expr(h, e->ref, 1);
+        break;
+    case EXPR_ADDRESSOF:
+        fprintf(h, "&");
+        write_expr(h, e->ref, 1);
+        break;
+    case EXPR_PPTR:
+        fprintf(h, "*");
+        write_expr(h, e->ref, 1);
+        break;
+    case EXPR_CAST:
+        fprintf(h, "(");
+        write_type_decl(h, e->u.tref, NULL);
+        fprintf(h, ")");
+        write_expr(h, e->ref, 1);
+        break;
+    case EXPR_SIZEOF:
+        fprintf(h, "sizeof(");
+        write_type_decl(h, e->u.tref, NULL);
+        fprintf(h, ")");
+        break;
+    case EXPR_SHL:
+    case EXPR_SHR:
+    case EXPR_MOD:
+    case EXPR_MUL:
+    case EXPR_DIV:
+    case EXPR_ADD:
+    case EXPR_SUB:
+    case EXPR_AND:
+    case EXPR_OR:
+    case EXPR_LOGOR:
+    case EXPR_LOGAND:
+    case EXPR_XOR:
+    case EXPR_EQUALITY:
+    case EXPR_INEQUALITY:
+    case EXPR_GTR:
+    case EXPR_LESS:
+    case EXPR_GTREQL:
+    case EXPR_LESSEQL:
+        if (brackets) fprintf(h, "(");
+        write_expr(h, e->ref, 1);
+        switch (e->type)
+        {
+        case EXPR_SHL:          fprintf(h, " << "); break;
+        case EXPR_SHR:          fprintf(h, " >> "); break;
+        case EXPR_MOD:          fprintf(h, " %% "); break;
+        case EXPR_MUL:          fprintf(h, " * "); break;
+        case EXPR_DIV:          fprintf(h, " / "); break;
+        case EXPR_ADD:          fprintf(h, " + "); break;
+        case EXPR_SUB:          fprintf(h, " - "); break;
+        case EXPR_AND:          fprintf(h, " & "); break;
+        case EXPR_OR:           fprintf(h, " | "); break;
+        case EXPR_LOGOR:        fprintf(h, " || "); break;
+        case EXPR_LOGAND:       fprintf(h, " && "); break;
+        case EXPR_XOR:          fprintf(h, " ^ "); break;
+        case EXPR_EQUALITY:     fprintf(h, " == "); break;
+        case EXPR_INEQUALITY:   fprintf(h, " != "); break;
+        case EXPR_GTR:          fprintf(h, " > "); break;
+        case EXPR_LESS:         fprintf(h, " < "); break;
+        case EXPR_GTREQL:       fprintf(h, " >= "); break;
+        case EXPR_LESSEQL:      fprintf(h, " <= "); break;
+        default: break;
+        }
+        write_expr(h, e->u.ext, 1);
+        if (brackets) fprintf(h, ")");
+        break;
+    case EXPR_MEMBER:
+        if (brackets) fprintf(h, "(");
+        if (e->ref->type == EXPR_PPTR)
+        {
+            write_expr(h, e->ref->ref, 1);
+            fprintf(h, "->");
+        }
+        else
+        {
+            write_expr(h, e->ref, 1);
+            fprintf(h, ".");
+        }
+        write_expr(h, e->u.ext, 1);
+        if (brackets) fprintf(h, ")");
+        break;
+    case EXPR_COND:
+        if (brackets) fprintf(h, "(");
+        write_expr(h, e->ref, 1);
+        fprintf(h, " ? ");
+        write_expr(h, e->u.ext, 1);
+        fprintf(h, " : ");
+        write_expr(h, e->ext2, 1);
+        if (brackets) fprintf(h, ")");
+        break;
+    case EXPR_ARRAY:
+        if (brackets) fprintf(h, "(");
+        write_expr(h, e->ref, 1);
+        fprintf(h, "[");
+        write_expr(h, e->u.ext, 1);
+        fprintf(h, "]");
+        if (brackets) fprintf(h, ")");
+        break;
+    }
+}
+
+/* This is actually fairly involved to implement precisely, due to the
+   effects attributes may have and things like that.  Right now this is
+   only used for optimization, so just check for a very small set of
+   criteria that guarantee the types are equivalent; assume every thing
+   else is different.   */
+static int compare_type(const type_t *a, const type_t *b)
+{
+    if (a == b
+        || (a->name
+            && b->name
+            && strcmp(a->name, b->name) == 0))
+        return 0;
+    /* Ordering doesn't need to be implemented yet.  */
+    return 1;
+}
+
+int compare_expr(const expr_t *a, const expr_t *b)
+{
+    int ret;
+
+    if (a->type != b->type)
+        return a->type - b->type;
+
+    switch (a->type)
+    {
+        case EXPR_NUM:
+        case EXPR_HEXNUM:
+        case EXPR_TRUEFALSE:
+            return a->u.lval - b->u.lval;
+        case EXPR_DOUBLE:
+            return a->u.dval - b->u.dval;
+        case EXPR_IDENTIFIER:
+            return strcmp(a->u.sval, b->u.sval);
+        case EXPR_COND:
+            ret = compare_expr(a->ref, b->ref);
+            if (ret != 0)
+                return ret;
+            ret = compare_expr(a->u.ext, b->u.ext);
+            if (ret != 0)
+                return ret;
+            return compare_expr(a->ext2, b->ext2);
+        case EXPR_OR:
+        case EXPR_AND:
+        case EXPR_ADD:
+        case EXPR_SUB:
+        case EXPR_MOD:
+        case EXPR_MUL:
+        case EXPR_DIV:
+        case EXPR_SHL:
+        case EXPR_SHR:
+        case EXPR_MEMBER:
+        case EXPR_ARRAY:
+        case EXPR_LOGOR:
+        case EXPR_LOGAND:
+        case EXPR_XOR:
+        case EXPR_EQUALITY:
+        case EXPR_INEQUALITY:
+        case EXPR_GTR:
+        case EXPR_LESS:
+        case EXPR_GTREQL:
+        case EXPR_LESSEQL:
+            ret = compare_expr(a->ref, b->ref);
+            if (ret != 0)
+                return ret;
+            return compare_expr(a->u.ext, b->u.ext);
+        case EXPR_CAST:
+            ret = compare_type(a->u.tref, b->u.tref);
+            if (ret != 0)
+                return ret;
+            /* Fall through.  */
+        case EXPR_NOT:
+        case EXPR_NEG:
+        case EXPR_PPTR:
+        case EXPR_ADDRESSOF:
+        case EXPR_LOGNOT:
+        case EXPR_POS:
+            return compare_expr(a->ref, b->ref);
+        case EXPR_SIZEOF:
+            return compare_type(a->u.tref, b->u.tref);
+        case EXPR_VOID:
+            return 0;
+    }
+    return -1;
+}
diff --git a/tools/widl/expr.h b/tools/widl/expr.h
new file mode 100644
index 0000000..e32ec29
--- /dev/null
+++ b/tools/widl/expr.h
@@ -0,0 +1,40 @@
+/*
+ * Expression Abstract Syntax Tree Functions
+ *
+ * Copyright 2002 Ove Kaaven
+ * Copyright 2006-2008 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+struct expr_loc
+{
+    const var_t *v;
+    const char *attr;
+};
+
+extern expr_t *make_expr(enum expr_type type);
+extern expr_t *make_exprl(enum expr_type type, long val);
+extern expr_t *make_exprd(enum expr_type type, double val);
+extern expr_t *make_exprs(enum expr_type type, char *val);
+extern expr_t *make_exprt(enum expr_type type, type_t *tref, expr_t *expr);
+extern expr_t *make_expr1(enum expr_type type, expr_t *expr);
+extern expr_t *make_expr2(enum expr_type type, expr_t *exp1, expr_t *exp2);
+extern expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, expr_t *expr3);
+
+extern const type_t *expr_resolve_type(const struct expr_loc *expr_loc, const type_t *cont_type, const expr_t *expr);
+extern int compare_expr(const expr_t *a, const expr_t *b);
+
+extern void write_expr(FILE *h, const expr_t *e, int brackets);
diff --git a/tools/widl/header.c b/tools/widl/header.c
index dea7669..a22a3ec 100644
--- a/tools/widl/header.c
+++ b/tools/widl/header.c
@@ -33,6 +33,7 @@
 #include "utils.h"
 #include "parser.h"
 #include "header.h"
+#include "expr.h"
 
 typedef struct _user_type_t generic_handle_t;
 
@@ -472,143 +473,6 @@
   fprintf(header, ";\n");
 }
 
-void write_expr(FILE *h, const expr_t *e, int brackets)
-{
-  switch (e->type) {
-  case EXPR_VOID:
-    break;
-  case EXPR_NUM:
-    fprintf(h, "%lu", e->u.lval);
-    break;
-  case EXPR_HEXNUM:
-    fprintf(h, "0x%lx", e->u.lval);
-    break;
-  case EXPR_DOUBLE:
-    fprintf(h, "%#.15g", e->u.dval);
-    break;
-  case EXPR_TRUEFALSE:
-    if (e->u.lval == 0)
-      fprintf(h, "FALSE");
-    else
-      fprintf(h, "TRUE");
-    break;
-  case EXPR_IDENTIFIER:
-    fprintf(h, "%s", e->u.sval);
-    break;
-  case EXPR_LOGNOT:
-    fprintf(h, "!");
-    write_expr(h, e->ref, 1);
-    break;
-  case EXPR_NOT:
-    fprintf(h, "~");
-    write_expr(h, e->ref, 1);
-    break;
-  case EXPR_POS:
-    fprintf(h, "+");
-    write_expr(h, e->ref, 1);
-    break;
-  case EXPR_NEG:
-    fprintf(h, "-");
-    write_expr(h, e->ref, 1);
-    break;
-  case EXPR_ADDRESSOF:
-    fprintf(h, "&");
-    write_expr(h, e->ref, 1);
-    break;
-  case EXPR_PPTR:
-    fprintf(h, "*");
-    write_expr(h, e->ref, 1);
-    break;
-  case EXPR_CAST:
-    fprintf(h, "(");
-    write_type_decl(h, e->u.tref, NULL);
-    fprintf(h, ")");
-    write_expr(h, e->ref, 1);
-    break;
-  case EXPR_SIZEOF:
-    fprintf(h, "sizeof(");
-    write_type_decl(h, e->u.tref, NULL);
-    fprintf(h, ")");
-    break;
-  case EXPR_SHL:
-  case EXPR_SHR:
-  case EXPR_MOD:
-  case EXPR_MUL:
-  case EXPR_DIV:
-  case EXPR_ADD:
-  case EXPR_SUB:
-  case EXPR_AND:
-  case EXPR_OR:
-  case EXPR_LOGOR:
-  case EXPR_LOGAND:
-  case EXPR_XOR:
-  case EXPR_EQUALITY:
-  case EXPR_INEQUALITY:
-  case EXPR_GTR:
-  case EXPR_LESS:
-  case EXPR_GTREQL:
-  case EXPR_LESSEQL:
-      if (brackets) fprintf(h, "(");
-    write_expr(h, e->ref, 1);
-    switch (e->type) {
-    case EXPR_SHL:          fprintf(h, " << "); break;
-    case EXPR_SHR:          fprintf(h, " >> "); break;
-    case EXPR_MOD:          fprintf(h, " %% "); break;
-    case EXPR_MUL:          fprintf(h, " * "); break;
-    case EXPR_DIV:          fprintf(h, " / "); break;
-    case EXPR_ADD:          fprintf(h, " + "); break;
-    case EXPR_SUB:          fprintf(h, " - "); break;
-    case EXPR_AND:          fprintf(h, " & "); break;
-    case EXPR_OR:           fprintf(h, " | "); break;
-    case EXPR_LOGOR:        fprintf(h, " || "); break;
-    case EXPR_LOGAND:       fprintf(h, " && "); break;
-    case EXPR_XOR:          fprintf(h, " ^ "); break;
-    case EXPR_EQUALITY:     fprintf(h, " == "); break;
-    case EXPR_INEQUALITY:   fprintf(h, " != "); break;
-    case EXPR_GTR:          fprintf(h, " > "); break;
-    case EXPR_LESS:         fprintf(h, " < "); break;
-    case EXPR_GTREQL:       fprintf(h, " >= "); break;
-    case EXPR_LESSEQL:      fprintf(h, " <= "); break;
-    default: break;
-    }
-    write_expr(h, e->u.ext, 1);
-    if (brackets) fprintf(h, ")");
-    break;
-  case EXPR_MEMBER:
-    if (brackets) fprintf(h, "(");
-    if (e->ref->type == EXPR_PPTR)
-    {
-      write_expr(h, e->ref->ref, 1);
-      fprintf(h, "->");
-    }
-    else
-    {
-      write_expr(h, e->ref, 1);
-      fprintf(h, ".");
-    }
-    write_expr(h, e->u.ext, 1);
-    if (brackets) fprintf(h, ")");
-    break;
-  case EXPR_COND:
-    if (brackets) fprintf(h, "(");
-    write_expr(h, e->ref, 1);
-    fprintf(h, " ? ");
-    write_expr(h, e->u.ext, 1);
-    fprintf(h, " : ");
-    write_expr(h, e->ext2, 1);
-    if (brackets) fprintf(h, ")");
-    break;
-  case EXPR_ARRAY:
-    if (brackets) fprintf(h, "(");
-    write_expr(h, e->ref, 1);
-    fprintf(h, "[");
-    write_expr(h, e->u.ext, 1);
-    fprintf(h, "]");
-    if (brackets) fprintf(h, ")");
-    break;
-  }
-}
-
 void write_constdef(const var_t *v)
 {
   fprintf(header, "#define %s (", v->name);
diff --git a/tools/widl/header.h b/tools/widl/header.h
index e8fdbc9..5657328 100644
--- a/tools/widl/header.h
+++ b/tools/widl/header.h
@@ -56,7 +56,6 @@
 extern void write_coclass(type_t *cocl);
 extern void write_coclass_forward(type_t *cocl);
 extern void write_typedef(type_t *type);
-extern void write_expr(FILE *h, const expr_t *e, int brackets);
 extern void write_constdef(const var_t *v);
 extern void write_externdef(const var_t *v);
 extern void write_library(const char *name, const attr_list_t *attr);
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index 3428be1..bce194c 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -38,6 +38,7 @@
 #include "header.h"
 #include "typelib.h"
 #include "typegen.h"
+#include "expr.h"
 
 #if defined(YYBYACC)
 	/* Berkeley yacc (byacc) doesn't seem to know about these */
@@ -87,15 +88,6 @@
 static attr_t *make_attr(enum attr_type type);
 static attr_t *make_attrv(enum attr_type type, unsigned long val);
 static attr_t *make_attrp(enum attr_type type, void *val);
-static expr_t *make_expr(enum expr_type type);
-static expr_t *make_exprl(enum expr_type type, long val);
-static expr_t *make_exprd(enum expr_type type, double val);
-static expr_t *make_exprs(enum expr_type type, char *val);
-static expr_t *make_exprt(enum expr_type type, type_t *tref, expr_t *expr);
-static expr_t *make_expr1(enum expr_type type, expr_t *expr);
-static expr_t *make_expr2(enum expr_type type, expr_t *exp1, expr_t *exp2);
-static expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, expr_t *expr3);
-static type_t *make_type(unsigned char type, type_t *ref);
 static expr_list_t *append_expr(expr_list_t *list, expr_t *expr);
 static array_dims_t *append_array(array_dims_t *list, expr_t *expr);
 static void set_type(var_t *v, type_t *type, const pident_t *pident, array_dims_t *arr, int top);
@@ -114,14 +106,12 @@
 
 static type_t *reg_type(type_t *type, const char *name, int t);
 static type_t *reg_typedefs(type_t *type, var_list_t *names, attr_list_t *attrs);
-static type_t *find_type(const char *name, int t);
 static type_t *find_type2(char *name, int t);
 static type_t *get_type(unsigned char type, char *name, int t);
 static type_t *get_typev(unsigned char type, var_t *name, int t);
 static int get_struct_type(var_list_t *fields);
 
 static var_t *reg_const(var_t *var);
-static var_t *find_const(const char *name, int f);
 
 static void write_libid(const char *name, const attr_list_t *attr);
 static void write_clsid(type_t *cls);
@@ -1104,506 +1094,6 @@
   return a;
 }
 
-static expr_t *make_expr(enum expr_type type)
-{
-  expr_t *e = xmalloc(sizeof(expr_t));
-  e->type = type;
-  e->ref = NULL;
-  e->u.lval = 0;
-  e->is_const = FALSE;
-  e->cval = 0;
-  return e;
-}
-
-static expr_t *make_exprl(enum expr_type type, long val)
-{
-  expr_t *e = xmalloc(sizeof(expr_t));
-  e->type = type;
-  e->ref = NULL;
-  e->u.lval = val;
-  e->is_const = FALSE;
-  /* check for numeric constant */
-  if (type == EXPR_NUM || type == EXPR_HEXNUM || type == EXPR_TRUEFALSE) {
-    /* make sure true/false value is valid */
-    assert(type != EXPR_TRUEFALSE || val == 0 || val == 1);
-    e->is_const = TRUE;
-    e->cval = val;
-  }
-  return e;
-}
-
-static expr_t *make_exprd(enum expr_type type, double val)
-{
-  expr_t *e = xmalloc(sizeof(expr_t));
-  e->type = type;
-  e->ref = NULL;
-  e->u.dval = val;
-  e->is_const = TRUE;
-  e->cval = val;
-  return e;
-}
-
-static expr_t *make_exprs(enum expr_type type, char *val)
-{
-  expr_t *e;
-  e = xmalloc(sizeof(expr_t));
-  e->type = type;
-  e->ref = NULL;
-  e->u.sval = val;
-  e->is_const = FALSE;
-  /* check for predefined constants */
-  if (type == EXPR_IDENTIFIER) {
-    var_t *c = find_const(val, 0);
-    if (c) {
-      e->u.sval = c->name;
-      free(val);
-      e->is_const = TRUE;
-      e->cval = c->eval->cval;
-    }
-  }
-  return e;
-}
-
-static expr_t *make_exprt(enum expr_type type, type_t *tref, expr_t *expr)
-{
-  expr_t *e;
-  e = xmalloc(sizeof(expr_t));
-  e->type = type;
-  e->ref = expr;
-  e->u.tref = tref;
-  e->is_const = FALSE;
-  /* check for cast of constant expression */
-  if (type == EXPR_SIZEOF) {
-    switch (tref->type) {
-      case RPC_FC_BYTE:
-      case RPC_FC_CHAR:
-      case RPC_FC_SMALL:
-      case RPC_FC_USMALL:
-        e->is_const = TRUE;
-        e->cval = 1;
-        break;
-      case RPC_FC_WCHAR:
-      case RPC_FC_USHORT:
-      case RPC_FC_SHORT:
-        e->is_const = TRUE;
-        e->cval = 2;
-        break;
-      case RPC_FC_LONG:
-      case RPC_FC_ULONG:
-      case RPC_FC_FLOAT:
-      case RPC_FC_ERROR_STATUS_T:
-        e->is_const = TRUE;
-        e->cval = 4;
-        break;
-      case RPC_FC_HYPER:
-      case RPC_FC_DOUBLE:
-        e->is_const = TRUE;
-        e->cval = 8;
-        break;
-    }
-  }
-  if (type == EXPR_CAST && expr->is_const) {
-    e->is_const = TRUE;
-    e->cval = expr->cval;
-  }
-  return e;
-}
-
-static expr_t *make_expr1(enum expr_type type, expr_t *expr)
-{
-  expr_t *e;
-  e = xmalloc(sizeof(expr_t));
-  e->type = type;
-  e->ref = expr;
-  e->u.lval = 0;
-  e->is_const = FALSE;
-  /* check for compile-time optimization */
-  if (expr->is_const) {
-    e->is_const = TRUE;
-    switch (type) {
-    case EXPR_LOGNOT:
-      e->cval = !expr->cval;
-      break;
-    case EXPR_POS:
-      e->cval = +expr->cval;
-      break;
-    case EXPR_NEG:
-      e->cval = -expr->cval;
-      break;
-    case EXPR_NOT:
-      e->cval = ~expr->cval;
-      break;
-    default:
-      e->is_const = FALSE;
-      break;
-    }
-  }
-  return e;
-}
-
-static expr_t *make_expr2(enum expr_type type, expr_t *expr1, expr_t *expr2)
-{
-  expr_t *e;
-  e = xmalloc(sizeof(expr_t));
-  e->type = type;
-  e->ref = expr1;
-  e->u.ext = expr2;
-  e->is_const = FALSE;
-  /* check for compile-time optimization */
-  if (expr1->is_const && expr2->is_const) {
-    e->is_const = TRUE;
-    switch (type) {
-    case EXPR_ADD:
-      e->cval = expr1->cval + expr2->cval;
-      break;
-    case EXPR_SUB:
-      e->cval = expr1->cval - expr2->cval;
-      break;
-    case EXPR_MOD:
-      if (expr2->cval == 0) {
-        error_loc("divide by zero in expression\n");
-        e->cval = 0;
-      } else
-        e->cval = expr1->cval % expr2->cval;
-      break;
-    case EXPR_MUL:
-      e->cval = expr1->cval * expr2->cval;
-      break;
-    case EXPR_DIV:
-      if (expr2->cval == 0) {
-        error_loc("divide by zero in expression\n");
-        e->cval = 0;
-      } else
-        e->cval = expr1->cval / expr2->cval;
-      break;
-    case EXPR_OR:
-      e->cval = expr1->cval | expr2->cval;
-      break;
-    case EXPR_AND:
-      e->cval = expr1->cval & expr2->cval;
-      break;
-    case EXPR_SHL:
-      e->cval = expr1->cval << expr2->cval;
-      break;
-    case EXPR_SHR:
-      e->cval = expr1->cval >> expr2->cval;
-      break;
-    case EXPR_LOGOR:
-      e->cval = expr1->cval || expr2->cval;
-      break;
-    case EXPR_LOGAND:
-      e->cval = expr1->cval && expr2->cval;
-      break;
-    case EXPR_XOR:
-      e->cval = expr1->cval ^ expr2->cval;
-      break;
-    case EXPR_EQUALITY:
-      e->cval = expr1->cval == expr2->cval;
-      break;
-    case EXPR_INEQUALITY:
-      e->cval = expr1->cval != expr2->cval;
-      break;
-    case EXPR_GTR:
-      e->cval = expr1->cval > expr2->cval;
-      break;
-    case EXPR_LESS:
-      e->cval = expr1->cval < expr2->cval;
-      break;
-    case EXPR_GTREQL:
-      e->cval = expr1->cval >= expr2->cval;
-      break;
-    case EXPR_LESSEQL:
-      e->cval = expr1->cval <= expr2->cval;
-      break;
-    default:
-      e->is_const = FALSE;
-      break;
-    }
-  }
-  return e;
-}
-
-static expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, expr_t *expr3)
-{
-  expr_t *e;
-  e = xmalloc(sizeof(expr_t));
-  e->type = type;
-  e->ref = expr1;
-  e->u.ext = expr2;
-  e->ext2 = expr3;
-  e->is_const = FALSE;
-  /* check for compile-time optimization */
-  if (expr1->is_const && expr2->is_const && expr3->is_const) {
-    e->is_const = TRUE;
-    switch (type) {
-    case EXPR_COND:
-      e->cval = expr1->cval ? expr2->cval : expr3->cval;
-      break;
-    default:
-      e->is_const = FALSE;
-      break;
-    }
-  }
-  return e;
-}
-
-struct expression_type
-{
-    int is_variable; /* is the expression resolved to a variable? */
-    int is_temporary; /* should the type be freed? */
-    type_t *type;
-};
-
-struct expr_loc
-{
-    const var_t *v;
-    const char *attr;
-};
-
-static int is_integer_type(const type_t *type)
-{
-    switch (type->type)
-    {
-    case RPC_FC_BYTE:
-    case RPC_FC_CHAR:
-    case RPC_FC_SMALL:
-    case RPC_FC_USMALL:
-    case RPC_FC_WCHAR:
-    case RPC_FC_SHORT:
-    case RPC_FC_USHORT:
-    case RPC_FC_LONG:
-    case RPC_FC_ULONG:
-    case RPC_FC_INT3264:
-    case RPC_FC_UINT3264:
-    case RPC_FC_HYPER:
-    case RPC_FC_ENUM16:
-    case RPC_FC_ENUM32:
-        return TRUE;
-    default:
-        return FALSE;
-    }
-}
-
-static void check_scalar_type(const struct expr_loc *expr_loc,
-                              const type_t *cont_type, const type_t *type)
-{
-    if (!cont_type || (!is_integer_type(type) && !is_ptr(type) &&
-                          type->type != RPC_FC_FLOAT &&
-                          type->type != RPC_FC_DOUBLE))
-        error_loc_info(&expr_loc->v->loc_info, "scalar type required in expression%s%s\n",
-                       expr_loc->attr ? " for attribute " : "",
-                       expr_loc->attr ? expr_loc->attr : "");
-}
-
-static void check_arithmetic_type(const struct expr_loc *expr_loc,
-                                  const type_t *cont_type, const type_t *type)
-{
-    if (!cont_type || (!is_integer_type(type) &&
-                       type->type != RPC_FC_FLOAT &&
-                       type->type != RPC_FC_DOUBLE))
-        error_loc_info(&expr_loc->v->loc_info, "arithmetic type required in expression%s%s\n",
-                       expr_loc->attr ? " for attribute " : "",
-                       expr_loc->attr ? expr_loc->attr : "");
-}
-
-static void check_integer_type(const struct expr_loc *expr_loc,
-                               const type_t *cont_type, const type_t *type)
-{
-    if (!cont_type || !is_integer_type(type))
-        error_loc_info(&expr_loc->v->loc_info, "integer type required in expression%s%s\n",
-                       expr_loc->attr ? " for attribute " : "",
-                       expr_loc->attr ? expr_loc->attr : "");
-}
-
-static struct expression_type resolve_expression(const struct expr_loc *expr_loc,
-                                                 const type_t *cont_type,
-                                                 const expr_t *e)
-{
-    struct expression_type result;
-    result.is_variable = FALSE;
-    result.is_temporary = FALSE;
-    result.type = NULL;
-    switch (e->type)
-    {
-    case EXPR_VOID:
-        break;
-    case EXPR_HEXNUM:
-    case EXPR_NUM:
-    case EXPR_TRUEFALSE:
-        result.is_variable = FALSE;
-        result.is_temporary = FALSE;
-        result.type = find_type("int", 0);
-        break;
-    case EXPR_DOUBLE:
-        result.is_variable = FALSE;
-        result.is_temporary = FALSE;
-        result.type = find_type("double", 0);
-        break;
-    case EXPR_IDENTIFIER:
-    {
-        const var_t *field;
-        const var_list_t *fields = NULL;
-
-        if (cont_type && (cont_type->type == RPC_FC_FUNCTION || is_struct(cont_type->type)))
-            fields = cont_type->fields_or_args;
-        else if (cont_type && is_union(cont_type->type))
-        {
-            if (cont_type->type == RPC_FC_ENCAPSULATED_UNION)
-            {
-                const var_t *uv = LIST_ENTRY(list_tail(cont_type->fields_or_args), const var_t, entry);
-                fields = uv->type->fields_or_args;
-            }
-            else
-                fields = cont_type->fields_or_args;
-        }
-
-        if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
-            if (field->name && !strcmp(e->u.sval, field->name))
-            {
-                result.type = field->type;
-                break;
-            }
-
-        if (!result.type)
-        {
-            var_t *const_var = find_const(e->u.sval, 0);
-            if (const_var) result.type = const_var->type;
-        }
-        if (!result.type)
-        {
-            error_loc_info(&expr_loc->v->loc_info, "identifier %s cannot be resolved in expression%s%s\n",
-                           e->u.sval, expr_loc->attr ? " for attribute " : "",
-                           expr_loc->attr ? expr_loc->attr : "");
-        }
-        break;
-    }
-    case EXPR_LOGNOT:
-        result = resolve_expression(expr_loc, cont_type, e->ref);
-        check_scalar_type(expr_loc, cont_type, result.type);
-        result.is_variable = FALSE;
-        result.is_temporary = FALSE;
-        result.type = find_type("int", 0);
-        break;
-    case EXPR_NOT:
-        result = resolve_expression(expr_loc, cont_type, e->ref);
-        check_integer_type(expr_loc, cont_type, result.type);
-        result.is_variable = FALSE;
-        break;
-    case EXPR_POS:
-    case EXPR_NEG:
-        result = resolve_expression(expr_loc, cont_type, e->ref);
-        check_arithmetic_type(expr_loc, cont_type, result.type);
-        result.is_variable = FALSE;
-        break;
-    case EXPR_ADDRESSOF:
-        result = resolve_expression(expr_loc, cont_type, e->ref);
-        if (!result.is_variable)
-            error_loc_info(&expr_loc->v->loc_info, "address-of operator applied to non-variable type in expression%s%s\n",
-                           expr_loc->attr ? " for attribute " : "",
-                           expr_loc->attr ? expr_loc->attr : "");
-        result.is_variable = FALSE;
-        result.is_temporary = TRUE;
-        result.type = make_type(RPC_FC_RP, result.type);
-        break;
-    case EXPR_PPTR:
-        result = resolve_expression(expr_loc, cont_type, e->ref);
-        if (result.type && is_ptr(result.type))
-            result.type = result.type->ref;
-        else
-            error_loc_info(&expr_loc->v->loc_info, "dereference operator applied to non-pointer type in expression%s%s\n",
-                           expr_loc->attr ? " for attribute " : "",
-                           expr_loc->attr ? expr_loc->attr : "");
-        break;
-    case EXPR_CAST:
-        result = resolve_expression(expr_loc, cont_type, e->ref);
-        result.type = e->u.tref;
-        break;
-    case EXPR_SIZEOF:
-        result.is_variable = FALSE;
-        result.is_temporary = FALSE;
-        result.type = find_type("int", 0);
-        break;
-    case EXPR_SHL:
-    case EXPR_SHR:
-    case EXPR_MOD:
-    case EXPR_MUL:
-    case EXPR_DIV:
-    case EXPR_ADD:
-    case EXPR_SUB:
-    case EXPR_AND:
-    case EXPR_OR:
-    case EXPR_XOR:
-    {
-        struct expression_type result_right;
-        result = resolve_expression(expr_loc, cont_type, e->ref);
-        result.is_variable = FALSE;
-        result_right = resolve_expression(expr_loc, cont_type, e->u.ext);
-        /* FIXME: these checks aren't strict enough for some of the operators */
-        check_scalar_type(expr_loc, cont_type, result.type);
-        check_scalar_type(expr_loc, cont_type, result_right.type);
-        break;
-    }
-    case EXPR_LOGOR:
-    case EXPR_LOGAND:
-    case EXPR_EQUALITY:
-    case EXPR_INEQUALITY:
-    case EXPR_GTR:
-    case EXPR_LESS:
-    case EXPR_GTREQL:
-    case EXPR_LESSEQL:
-    {
-        struct expression_type result_left, result_right;
-        result_left = resolve_expression(expr_loc, cont_type, e->ref);
-        result_right = resolve_expression(expr_loc, cont_type, e->u.ext);
-        check_scalar_type(expr_loc, cont_type, result_left.type);
-        check_scalar_type(expr_loc, cont_type, result_right.type);
-        result.is_variable = FALSE;
-        result.is_temporary = FALSE;
-        result.type = find_type("int", 0);
-        break;
-    }
-    case EXPR_MEMBER:
-        result = resolve_expression(expr_loc, cont_type, e->ref);
-        if (result.type && (is_struct(result.type->type) || is_union(result.type->type) || result.type->type == RPC_FC_ENUM16 || result.type->type == RPC_FC_ENUM32))
-            result = resolve_expression(expr_loc, result.type, e->u.ext);
-        else
-            error_loc_info(&expr_loc->v->loc_info, "'.' or '->' operator applied to a type that isn't a structure, union or enumeration in expression%s%s\n",
-                           expr_loc->attr ? " for attribute " : "",
-                           expr_loc->attr ? expr_loc->attr : "");
-        break;
-    case EXPR_COND:
-    {
-        struct expression_type result_first, result_second, result_third;
-        result_first = resolve_expression(expr_loc, cont_type, e->ref);
-        check_scalar_type(expr_loc, cont_type, result_first.type);
-        result_second = resolve_expression(expr_loc, cont_type, e->u.ext);
-        result_third = resolve_expression(expr_loc, cont_type, e->ext2);
-        /* FIXME: determine the correct return type */
-        result = result_second;
-        result.is_variable = FALSE;
-        break;
-    }
-    case EXPR_ARRAY:
-        result = resolve_expression(expr_loc, cont_type, e->ref);
-        if (result.type && is_array(result.type))
-        {
-            struct expression_type index_result;
-            result.type = result.type->ref;
-            index_result = resolve_expression(expr_loc, cont_type /* FIXME */, e->u.ext);
-            if (!index_result.type || !is_integer_type(index_result.type))
-                error_loc_info(&expr_loc->v->loc_info, "array subscript not of integral type in expression%s%s\n",
-                               expr_loc->attr ? " for attribute " : "",
-                               expr_loc->attr ? expr_loc->attr : "");
-        }
-        else
-            error_loc_info(&expr_loc->v->loc_info, "array subscript operator applied to non-array type in expression%s%s\n",
-                           expr_loc->attr ? " for attribute " : "",
-                           expr_loc->attr ? expr_loc->attr : "");
-        break;
-    }
-    return result;
-}
-
 static expr_list_t *append_expr(expr_list_t *list, expr_t *expr)
 {
     if (!expr) return list;
@@ -1649,7 +1139,7 @@
     node->data.tfswrite = val;
 }
 
-static type_t *make_type(unsigned char type, type_t *ref)
+type_t *make_type(unsigned char type, type_t *ref)
 {
   type_t *t = alloc_type();
   t->name = NULL;
@@ -2120,7 +1610,7 @@
   return type;
 }
 
-static type_t *find_type(const char *name, int t)
+type_t *find_type(const char *name, int t)
 {
   struct rtype *cur = type_hash[hash_ident(name)];
   while (cur && (cur->t != t || strcmp(cur->name, name)))
@@ -2361,7 +1851,7 @@
   return var;
 }
 
-static var_t *find_const(const char *name, int f)
+var_t *find_const(const char *name, int f)
 {
   struct rconst *cur = const_hash[hash_ident(name)];
   while (cur && strcmp(cur->name, name))
@@ -2731,9 +2221,8 @@
     {
         if (dim->type != EXPR_VOID)
         {
-            struct expression_type expr_type;
-            expr_type = resolve_expression(&expr_loc, container_type, dim);
-            if (!is_allowed_conf_type(expr_type.type))
+            const type_t *expr_type = expr_resolve_type(&expr_loc, container_type, dim);
+            if (!is_allowed_conf_type(expr_type))
                 error_loc_info(&arg->loc_info, "expression must resolve to integral type <= 32bits for attribute %s\n",
                                attr_name);
         }
@@ -2780,11 +2269,11 @@
         expr_t *expr = get_attrp(arg->attrs, ATTR_IIDIS);
         if (expr->type != EXPR_VOID)
         {
-            struct expression_type expr_type;
+            const type_t *expr_type;
             expr_loc.v = arg;
             expr_loc.attr = "iid_is";
-            expr_type = resolve_expression(&expr_loc, container_type, expr);
-            if (!expr_type.type || !is_ptr_guid_type(expr_type.type))
+            expr_type = expr_resolve_type(&expr_loc, container_type, expr);
+            if (!expr_type || !is_ptr_guid_type(expr_type))
                 error_loc_info(&arg->loc_info, "expression must resolve to pointer to GUID type for attribute iid_is\n");
         }
     }
@@ -2794,11 +2283,11 @@
         expr_t *expr = get_attrp(arg->attrs, ATTR_SWITCHIS);
         if (expr->type != EXPR_VOID)
         {
-            struct expression_type expr_type;
+            const type_t *expr_type;
             expr_loc.v = arg;
             expr_loc.attr = "switch_is";
-            expr_type = resolve_expression(&expr_loc, container_type, expr);
-            if (!is_allowed_conf_type(expr_type.type))
+            expr_type = expr_resolve_type(&expr_loc, container_type, expr);
+            if (!expr_type || !is_allowed_conf_type(expr_type))
                 error_loc_info(&arg->loc_info, "expression must resolve to integral type <= 32bits for attribute %s\n",
                                expr_loc.attr);
         }
diff --git a/tools/widl/proxy.c b/tools/widl/proxy.c
index e0864f8..01ad4da 100644
--- a/tools/widl/proxy.c
+++ b/tools/widl/proxy.c
@@ -35,6 +35,7 @@
 #include "parser.h"
 #include "header.h"
 #include "typegen.h"
+#include "expr.h"
 
 #define END_OF_LIST(list)       \
   do {                          \
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c
index d725920..8a4b8f5 100644
--- a/tools/widl/typegen.c
+++ b/tools/widl/typegen.c
@@ -39,6 +39,7 @@
 #include "wine/list.h"
 
 #include "typegen.h"
+#include "expr.h"
 
 static const func_t *current_func;
 static const type_t *current_structure;
@@ -307,91 +308,6 @@
     return NULL;
 }
 
-/* This is actually fairly involved to implement precisely, due to the
-   effects attributes may have and things like that.  Right now this is
-   only used for optimization, so just check for a very small set of
-   criteria that guarantee the types are equivalent; assume every thing
-   else is different.   */
-static int compare_type(const type_t *a, const type_t *b)
-{
-    if (a == b
-        || (a->name
-            && b->name
-            && strcmp(a->name, b->name) == 0))
-        return 0;
-    /* Ordering doesn't need to be implemented yet.  */
-    return 1;
-}
-
-static int compare_expr(const expr_t *a, const expr_t *b)
-{
-    int ret;
-
-    if (a->type != b->type)
-        return a->type - b->type;
-
-    switch (a->type)
-    {
-        case EXPR_NUM:
-        case EXPR_HEXNUM:
-        case EXPR_TRUEFALSE:
-            return a->u.lval - b->u.lval;
-        case EXPR_DOUBLE:
-            return a->u.dval - b->u.dval;
-        case EXPR_IDENTIFIER:
-            return strcmp(a->u.sval, b->u.sval);
-        case EXPR_COND:
-            ret = compare_expr(a->ref, b->ref);
-            if (ret != 0)
-                return ret;
-            ret = compare_expr(a->u.ext, b->u.ext);
-            if (ret != 0)
-                return ret;
-            return compare_expr(a->ext2, b->ext2);
-        case EXPR_OR:
-        case EXPR_AND:
-        case EXPR_ADD:
-        case EXPR_SUB:
-        case EXPR_MOD:
-        case EXPR_MUL:
-        case EXPR_DIV:
-        case EXPR_SHL:
-        case EXPR_SHR:
-        case EXPR_MEMBER:
-        case EXPR_ARRAY:
-        case EXPR_LOGOR:
-        case EXPR_LOGAND:
-        case EXPR_XOR:
-        case EXPR_EQUALITY:
-        case EXPR_INEQUALITY:
-        case EXPR_GTR:
-        case EXPR_LESS:
-        case EXPR_GTREQL:
-        case EXPR_LESSEQL:
-            ret = compare_expr(a->ref, b->ref);
-            if (ret != 0)
-                return ret;
-            return compare_expr(a->u.ext, b->u.ext);
-        case EXPR_CAST:
-            ret = compare_type(a->u.tref, b->u.tref);
-            if (ret != 0)
-                return ret;
-            /* Fall through.  */
-        case EXPR_NOT:
-        case EXPR_NEG:
-        case EXPR_PPTR:
-        case EXPR_ADDRESSOF:
-        case EXPR_LOGNOT:
-        case EXPR_POS:
-            return compare_expr(a->ref, b->ref);
-        case EXPR_SIZEOF:
-            return compare_type(a->u.tref, b->u.tref);
-        case EXPR_VOID:
-            return 0;
-    }
-    return -1;
-}
-
 #define WRITE_FCTYPE(file, fctype, typestring_offset) \
     do { \
         if (file) \
diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h
index 37a883a..fd8b8dd 100644
--- a/tools/widl/widltypes.h
+++ b/tools/widl/widltypes.h
@@ -362,6 +362,10 @@
 int is_struct(unsigned char tc);
 int is_union(unsigned char tc);
 
+var_t *find_const(const char *name, int f);
+type_t *find_type(const char *name, int t);
+type_t *make_type(unsigned char type, type_t *ref);
+
 static inline type_t *get_func_return_type(const func_t *func)
 {
   return func->def->type->ref;