#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"
#include "typetree.h"
#include "typegen.h"
static int is_integer_type(const type_t *type)
{
switch (type_get_type(type))
{
case TYPE_ENUM:
return TRUE;
case TYPE_BASIC:
switch (type_basic_get_type(type))
{
case TYPE_BASIC_INT8:
case TYPE_BASIC_INT16:
case TYPE_BASIC_INT32:
case TYPE_BASIC_INT64:
case TYPE_BASIC_INT:
case TYPE_BASIC_INT3264:
case TYPE_BASIC_LONG:
case TYPE_BASIC_CHAR:
case TYPE_BASIC_HYPER:
case TYPE_BASIC_BYTE:
case TYPE_BASIC_WCHAR:
case TYPE_BASIC_ERROR_STATUS_T:
return TRUE;
case TYPE_BASIC_FLOAT:
case TYPE_BASIC_DOUBLE:
case TYPE_BASIC_HANDLE:
return FALSE;
}
return FALSE;
default:
return FALSE;
}
}
static int is_signed_integer_type(const type_t *type)
{
switch (type_get_type(type))
{
case TYPE_ENUM:
return FALSE;
case TYPE_BASIC:
switch (type_basic_get_type(type))
{
case TYPE_BASIC_INT8:
case TYPE_BASIC_INT16:
case TYPE_BASIC_INT32:
case TYPE_BASIC_INT64:
case TYPE_BASIC_INT:
case TYPE_BASIC_INT3264:
case TYPE_BASIC_LONG:
return type_basic_get_sign(type) < 0;
case TYPE_BASIC_CHAR:
return TRUE;
case TYPE_BASIC_HYPER:
case TYPE_BASIC_BYTE:
case TYPE_BASIC_WCHAR:
case TYPE_BASIC_ERROR_STATUS_T:
case TYPE_BASIC_FLOAT:
case TYPE_BASIC_DOUBLE:
case TYPE_BASIC_HANDLE:
return FALSE;
}
default:
return FALSE;
}
}
static int is_float_type(const type_t *type)
{
return (type_get_type(type) == TYPE_BASIC &&
(type_basic_get_type(type) == TYPE_BASIC_FLOAT ||
type_basic_get_type(type) == TYPE_BASIC_DOUBLE));
}
expr_t *make_expr(enum expr_type type)
{
expr_t *e = xmalloc(sizeof(expr_t));
memset(e, 0, sizeof(*e));
e->type = type;
return e;
}
expr_t *make_exprl(enum expr_type type, const struct integer *integer)
{
expr_t *e = xmalloc(sizeof(expr_t));
memset(e, 0, sizeof(*e));
e->type = type;
e->u.integer = *integer;
if (type == EXPR_NUM || type == EXPR_TRUEFALSE)
{
assert(type != EXPR_TRUEFALSE || integer->value == 0 || integer->value == 1);
e->is_const = TRUE;
e->cval = integer->value;
}
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;
switch (type)
{
case 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;
}
break;
}
case EXPR_CHARCONST:
if (!val[0])
error_loc("empty character constant\n");
else if (val[1])
error_loc("multi-character constants are endian dependent\n");
else
{
e->is_const = TRUE;
e->cval = *val;
}
break;
default:
break;
}
return e;
}
expr_t *make_exprt(enum expr_type type, var_t *var, expr_t *expr)
{
expr_t *e;
type_t *tref;
if (var->declspec.stgclass != STG_NONE && var->declspec.stgclass != STG_REGISTER)
error_loc("invalid storage class for type expression\n");
tref = var->declspec.type;
e = xmalloc(sizeof(expr_t));
e->type = type;
e->ref = expr;
e->u.var = var;
e->is_const = FALSE;
if (type == EXPR_SIZEOF)
{
if (is_integer_type(tref) || is_float_type(tref))
{
e->is_const = TRUE;
e->cval = type_memsize(tref);
}
}
if (type == EXPR_CAST && expr->is_const)
{
if (is_integer_type(tref))
{
unsigned int cast_type_bits = type_memsize(tref) * 8;
unsigned int cast_mask;
e->is_const = TRUE;
if (is_signed_integer_type(tref))
{
cast_mask = (1u << (cast_type_bits - 1)) - 1;
if (expr->cval & (1u << (cast_type_bits - 1)))
e->cval = -((-expr->cval) & cast_mask);
else
e->cval = expr->cval & cast_mask;
}
else
{
cast_mask = ((1u << (cast_type_bits - 1)) - 1) |
1u << (cast_type_bits - 1);
e->cval = expr->cval & cast_mask;
}
}
else
{
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));
memset(e, 0, sizeof(*e));
e->type = type;
e->ref = expr;
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;
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;
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;
int is_temporary;
type_t *type;
};
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 ) && !is_float_type( type )))
error_at( &expr_loc->v->where, "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 ) && !is_float_type( type )))
error_at( &expr_loc->v->where, "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_at( &expr_loc->v->where, "integer type required in expression%s%s\n",
expr_loc->attr ? " for attribute " : "", expr_loc->attr ? expr_loc->attr : "" );
}
static type_t *find_identifier(const char *identifier, const type_t *cont_type, int *found_in_cont_type)
{
type_t *type = NULL;
const var_t *field;
const var_list_t *fields = NULL;
*found_in_cont_type = 0;
if (cont_type)
{
switch (type_get_type(cont_type))
{
case TYPE_FUNCTION:
fields = type_function_get_args(cont_type);
break;
case TYPE_STRUCT:
fields = type_struct_get_fields(cont_type);
break;
case TYPE_UNION:
case TYPE_ENCAPSULATED_UNION:
fields = type_union_get_cases(cont_type);
break;
case TYPE_VOID:
case TYPE_BASIC:
case TYPE_ENUM:
case TYPE_MODULE:
case TYPE_COCLASS:
case TYPE_INTERFACE:
case TYPE_POINTER:
case TYPE_ARRAY:
case TYPE_BITFIELD:
case TYPE_APICONTRACT:
case TYPE_RUNTIMECLASS:
case TYPE_PARAMETERIZED_TYPE:
case TYPE_PARAMETER:
case TYPE_DELEGATE:
break;
case TYPE_ALIAS:
assert(0);
break;
}
}
if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
if (field->name && !strcmp(identifier, field->name))
{
type = field->declspec.type;
*found_in_cont_type = 1;
break;
}
if (!type)
{
var_t *const_var = find_const(identifier, 0);
if (const_var) type = const_var->declspec.type;
}
return type;
}
static int is_valid_member_operand(const type_t *type)
{
switch (type_get_type(type))
{
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_ENUM:
return TRUE;
default:
return FALSE;
}
}
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_NUM:
case EXPR_TRUEFALSE:
result.is_temporary = FALSE;
result.type = type_new_int(e->u.integer.is_long ? TYPE_BASIC_LONG : TYPE_BASIC_INT, e->u.integer.is_unsigned);
break;
case EXPR_STRLIT:
result.is_temporary = TRUE;
result.type = type_new_pointer(type_new_int(TYPE_BASIC_CHAR, 0));
break;
case EXPR_WSTRLIT:
result.is_temporary = TRUE;
result.type = type_new_pointer(type_new_int(TYPE_BASIC_WCHAR, 0));
break;
case EXPR_CHARCONST:
result.is_temporary = TRUE;
result.type = type_new_int(TYPE_BASIC_CHAR, 0);
break;
case EXPR_DOUBLE:
result.is_temporary = TRUE;
result.type = type_new_basic(TYPE_BASIC_DOUBLE);
break;
case EXPR_IDENTIFIER:
{
int found_in_cont_type;
result.is_variable = TRUE;
result.is_temporary = FALSE;
result.type = find_identifier(e->u.sval, cont_type, &found_in_cont_type);
if (!result.type)
error_at( &expr_loc->v->where, "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 = type_new_int(TYPE_BASIC_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_at( &expr_loc->v->where, "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 = type_new_pointer(result.type);
break;
case EXPR_PPTR:
result = resolve_expression(expr_loc, cont_type, e->ref);
if (result.type && is_ptr(result.type))
result.type = type_pointer_get_ref_type(result.type);
else if(result.type && is_array(result.type)
&& type_array_is_decl_as_ptr(result.type))
result.type = type_array_get_element_type(result.type);
else
error_at( &expr_loc->v->where, "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.var->declspec.type;
break;
case EXPR_SIZEOF:
result.is_temporary = FALSE;
result.type = type_new_int(TYPE_BASIC_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);
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_temporary = FALSE;
result.type = type_new_int(TYPE_BASIC_INT, 0);
break;
}
case EXPR_MEMBER:
result = resolve_expression(expr_loc, cont_type, e->ref);
if (result.type && is_valid_member_operand(result.type))
result = resolve_expression(expr_loc, result.type, e->u.ext);
else
error_at( &expr_loc->v->where, "'.' 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);
check_scalar_type(expr_loc, cont_type, result_second.type);
check_scalar_type(expr_loc, cont_type, result_third.type);
if (!is_ptr( result_second.type ) ^ !is_ptr( result_third.type ))
error_at( &expr_loc->v->where, "type mismatch in ?: expression\n" );
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 = type_array_get_element_type(result.type);
index_result = resolve_expression(expr_loc, cont_type , e->u.ext);
if (!index_result.type || !is_integer_type( index_result.type ))
error_at( &expr_loc->v->where, "array subscript not of integral type in expression%s%s\n",
expr_loc->attr ? " for attribute " : "", expr_loc->attr ? expr_loc->attr : "" );
}
else
{
error_at( &expr_loc->v->where, "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,
int toplevel, const char *toplevel_prefix,
const type_t *cont_type, const char *local_var_prefix)
{
switch (e->type)
{
case EXPR_VOID:
break;
case EXPR_NUM:
if (e->u.integer.is_hex)
fprintf(h, "0x%x", e->u.integer.value);
else
fprintf(h, "%u", e->u.integer.value);
if (e->u.integer.is_unsigned)
fprintf(h, "u");
if (e->u.integer.is_long)
fprintf(h, "l");
break;
case EXPR_DOUBLE:
fprintf(h, "%#.15g", e->u.dval);
break;
case EXPR_TRUEFALSE:
if (e->u.integer.value == 0)
fprintf(h, "FALSE");
else
fprintf(h, "TRUE");
break;
case EXPR_IDENTIFIER:
if (toplevel && toplevel_prefix && cont_type)
{
int found_in_cont_type;
find_identifier(e->u.sval, cont_type, &found_in_cont_type);
if (found_in_cont_type)
{
fprintf(h, "%s%s", toplevel_prefix, e->u.sval);
break;
}
}
fprintf(h, "%s%s", local_var_prefix, e->u.sval);
break;
case EXPR_STRLIT:
fprintf(h, "\"%s\"", e->u.sval);
break;
case EXPR_WSTRLIT:
fprintf(h, "L\"%s\"", e->u.sval);
break;
case EXPR_CHARCONST:
fprintf(h, "'%s'", e->u.sval);
break;
case EXPR_LOGNOT:
fprintf(h, "!");
write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
break;
case EXPR_NOT:
fprintf(h, "~");
write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
break;
case EXPR_POS:
fprintf(h, "+");
write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
break;
case EXPR_NEG:
fprintf(h, "-");
write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
break;
case EXPR_ADDRESSOF:
fprintf(h, "&");
write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
break;
case EXPR_PPTR:
fprintf(h, "*");
write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
break;
case EXPR_CAST:
fprintf(h, "(");
write_type_decl(h, &e->u.var->declspec, NULL);
fprintf(h, ")");
write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
break;
case EXPR_SIZEOF:
fprintf(h, "sizeof(");
write_type_decl(h, &e->u.var->declspec, 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, toplevel, toplevel_prefix, cont_type, local_var_prefix);
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, toplevel, toplevel_prefix, cont_type, local_var_prefix);
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, toplevel, toplevel_prefix, cont_type, local_var_prefix);
fprintf(h, "->");
}
else
{
write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
fprintf(h, ".");
}
write_expr(h, e->u.ext, 1, 0, toplevel_prefix, cont_type, "");
if (brackets) fprintf(h, ")");
break;
case EXPR_COND:
if (brackets) fprintf(h, "(");
write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
fprintf(h, " ? ");
write_expr(h, e->u.ext, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
fprintf(h, " : ");
write_expr(h, e->ext2, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
if (brackets) fprintf(h, ")");
break;
case EXPR_ARRAY:
if (brackets) fprintf(h, "(");
write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
fprintf(h, "[");
write_expr(h, e->u.ext, 1, 1, toplevel_prefix, cont_type, local_var_prefix);
fprintf(h, "]");
if (brackets) fprintf(h, ")");
break;
}
}
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;
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_TRUEFALSE:
return a->u.integer.value - b->u.integer.value;
case EXPR_DOUBLE:
return a->u.dval - b->u.dval;
case EXPR_IDENTIFIER:
case EXPR_STRLIT:
case EXPR_WSTRLIT:
case EXPR_CHARCONST:
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.var->declspec.type, b->u.var->declspec.type);
if (ret != 0)
return ret;
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.var->declspec.type, b->u.var->declspec.type);
case EXPR_VOID:
return 0;
}
return -1;
}