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;