Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Expression Abstract Syntax Tree Functions |
| 3 | * |
| 4 | * Copyright 2002 Ove Kaaven |
| 5 | * Copyright 2006-2008 Robert Shearman |
| 6 | * |
| 7 | * This library is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU Lesser General Public |
| 9 | * License as published by the Free Software Foundation; either |
| 10 | * version 2.1 of the License, or (at your option) any later version. |
| 11 | * |
| 12 | * This library is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | * Lesser General Public License for more details. |
| 16 | * |
| 17 | * You should have received a copy of the GNU Lesser General Public |
| 18 | * License along with this library; if not, write to the Free Software |
| 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| 20 | */ |
| 21 | |
| 22 | #include "config.h" |
| 23 | |
| 24 | #include <stdio.h> |
| 25 | #include <stdlib.h> |
| 26 | #include <stdarg.h> |
| 27 | #include <assert.h> |
| 28 | #include <ctype.h> |
| 29 | #include <string.h> |
| 30 | |
| 31 | #include "widl.h" |
| 32 | #include "utils.h" |
| 33 | #include "expr.h" |
| 34 | #include "header.h" |
Rob Shearman | 04a22cc | 2008-12-29 12:05:27 +0000 | [diff] [blame] | 35 | #include "typetree.h" |
Rob Shearman | ba91ee6 | 2009-02-23 13:47:57 +0000 | [diff] [blame] | 36 | #include "typegen.h" |
| 37 | |
Rob Shearman | b544014 | 2010-03-23 13:33:46 +0000 | [diff] [blame] | 38 | static int is_integer_type(const type_t *type) |
| 39 | { |
| 40 | switch (type_get_type(type)) |
| 41 | { |
| 42 | case TYPE_ENUM: |
| 43 | return TRUE; |
| 44 | case TYPE_BASIC: |
| 45 | switch (type_basic_get_type(type)) |
| 46 | { |
| 47 | case TYPE_BASIC_INT8: |
| 48 | case TYPE_BASIC_INT16: |
| 49 | case TYPE_BASIC_INT32: |
| 50 | case TYPE_BASIC_INT64: |
| 51 | case TYPE_BASIC_INT: |
| 52 | case TYPE_BASIC_INT3264: |
| 53 | case TYPE_BASIC_CHAR: |
| 54 | case TYPE_BASIC_HYPER: |
| 55 | case TYPE_BASIC_BYTE: |
| 56 | case TYPE_BASIC_WCHAR: |
| 57 | case TYPE_BASIC_ERROR_STATUS_T: |
| 58 | return TRUE; |
| 59 | case TYPE_BASIC_FLOAT: |
| 60 | case TYPE_BASIC_DOUBLE: |
| 61 | case TYPE_BASIC_HANDLE: |
| 62 | return FALSE; |
| 63 | } |
| 64 | return FALSE; |
| 65 | default: |
| 66 | return FALSE; |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | static int is_signed_integer_type(const type_t *type) |
| 71 | { |
| 72 | switch (type_get_type(type)) |
| 73 | { |
| 74 | case TYPE_ENUM: |
| 75 | return FALSE; |
| 76 | case TYPE_BASIC: |
| 77 | switch (type_basic_get_type(type)) |
| 78 | { |
| 79 | case TYPE_BASIC_INT8: |
| 80 | case TYPE_BASIC_INT16: |
| 81 | case TYPE_BASIC_INT32: |
| 82 | case TYPE_BASIC_INT64: |
| 83 | case TYPE_BASIC_INT: |
| 84 | case TYPE_BASIC_INT3264: |
| 85 | return type_basic_get_sign(type) < 0; |
| 86 | case TYPE_BASIC_CHAR: |
| 87 | return TRUE; |
| 88 | case TYPE_BASIC_HYPER: |
| 89 | case TYPE_BASIC_BYTE: |
| 90 | case TYPE_BASIC_WCHAR: |
| 91 | case TYPE_BASIC_ERROR_STATUS_T: |
| 92 | case TYPE_BASIC_FLOAT: |
| 93 | case TYPE_BASIC_DOUBLE: |
| 94 | case TYPE_BASIC_HANDLE: |
| 95 | return FALSE; |
| 96 | } |
Marcus Meissner | 0222ad7 | 2011-03-29 15:34:15 +0200 | [diff] [blame] | 97 | /* FALLTHROUGH */ |
Rob Shearman | b544014 | 2010-03-23 13:33:46 +0000 | [diff] [blame] | 98 | default: |
| 99 | return FALSE; |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | static int is_float_type(const type_t *type) |
| 104 | { |
| 105 | return (type_get_type(type) == TYPE_BASIC && |
| 106 | (type_basic_get_type(type) == TYPE_BASIC_FLOAT || |
| 107 | type_basic_get_type(type) == TYPE_BASIC_DOUBLE)); |
| 108 | } |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 109 | |
| 110 | expr_t *make_expr(enum expr_type type) |
| 111 | { |
| 112 | expr_t *e = xmalloc(sizeof(expr_t)); |
| 113 | e->type = type; |
| 114 | e->ref = NULL; |
| 115 | e->u.lval = 0; |
| 116 | e->is_const = FALSE; |
| 117 | e->cval = 0; |
| 118 | return e; |
| 119 | } |
| 120 | |
Alexandre Julliard | a83563a | 2010-03-26 11:42:28 +0100 | [diff] [blame] | 121 | expr_t *make_exprl(enum expr_type type, int val) |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 122 | { |
| 123 | expr_t *e = xmalloc(sizeof(expr_t)); |
| 124 | e->type = type; |
| 125 | e->ref = NULL; |
| 126 | e->u.lval = val; |
| 127 | e->is_const = FALSE; |
| 128 | /* check for numeric constant */ |
| 129 | if (type == EXPR_NUM || type == EXPR_HEXNUM || type == EXPR_TRUEFALSE) |
| 130 | { |
| 131 | /* make sure true/false value is valid */ |
| 132 | assert(type != EXPR_TRUEFALSE || val == 0 || val == 1); |
| 133 | e->is_const = TRUE; |
| 134 | e->cval = val; |
| 135 | } |
| 136 | return e; |
| 137 | } |
| 138 | |
| 139 | expr_t *make_exprd(enum expr_type type, double val) |
| 140 | { |
| 141 | expr_t *e = xmalloc(sizeof(expr_t)); |
| 142 | e->type = type; |
| 143 | e->ref = NULL; |
| 144 | e->u.dval = val; |
| 145 | e->is_const = TRUE; |
| 146 | e->cval = val; |
| 147 | return e; |
| 148 | } |
| 149 | |
| 150 | expr_t *make_exprs(enum expr_type type, char *val) |
| 151 | { |
| 152 | expr_t *e; |
| 153 | e = xmalloc(sizeof(expr_t)); |
| 154 | e->type = type; |
| 155 | e->ref = NULL; |
| 156 | e->u.sval = val; |
| 157 | e->is_const = FALSE; |
| 158 | /* check for predefined constants */ |
Rob Shearman | d9b83e8 | 2010-01-18 22:15:46 +0000 | [diff] [blame] | 159 | switch (type) |
| 160 | { |
| 161 | case EXPR_IDENTIFIER: |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 162 | { |
| 163 | var_t *c = find_const(val, 0); |
| 164 | if (c) |
| 165 | { |
| 166 | e->u.sval = c->name; |
| 167 | free(val); |
| 168 | e->is_const = TRUE; |
| 169 | e->cval = c->eval->cval; |
| 170 | } |
Rob Shearman | d9b83e8 | 2010-01-18 22:15:46 +0000 | [diff] [blame] | 171 | break; |
| 172 | } |
| 173 | case EXPR_CHARCONST: |
| 174 | if (!val[0]) |
| 175 | error_loc("empty character constant\n"); |
| 176 | else if (val[1]) |
| 177 | error_loc("multi-character constants are endian dependent\n"); |
| 178 | else |
| 179 | { |
| 180 | e->is_const = TRUE; |
| 181 | e->cval = *val; |
| 182 | } |
| 183 | break; |
| 184 | default: |
| 185 | break; |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 186 | } |
| 187 | return e; |
| 188 | } |
| 189 | |
Rob Shearman | 0228008 | 2009-11-07 15:55:22 +0100 | [diff] [blame] | 190 | expr_t *make_exprt(enum expr_type type, var_t *var, expr_t *expr) |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 191 | { |
| 192 | expr_t *e; |
Rob Shearman | 0228008 | 2009-11-07 15:55:22 +0100 | [diff] [blame] | 193 | type_t *tref; |
| 194 | |
| 195 | if (var->stgclass != STG_NONE && var->stgclass != STG_REGISTER) |
| 196 | error_loc("invalid storage class for type expression\n"); |
| 197 | |
| 198 | tref = var->type; |
| 199 | |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 200 | e = xmalloc(sizeof(expr_t)); |
| 201 | e->type = type; |
| 202 | e->ref = expr; |
| 203 | e->u.tref = tref; |
| 204 | e->is_const = FALSE; |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 205 | if (type == EXPR_SIZEOF) |
| 206 | { |
Rob Shearman | ba91ee6 | 2009-02-23 13:47:57 +0000 | [diff] [blame] | 207 | /* only do this for types that should be the same on all platforms */ |
| 208 | if (is_integer_type(tref) || is_float_type(tref)) |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 209 | { |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 210 | e->is_const = TRUE; |
Alexandre Julliard | cb6a225 | 2010-04-05 19:48:07 +0200 | [diff] [blame] | 211 | e->cval = type_memsize(tref); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 212 | } |
| 213 | } |
Rob Shearman | ba91ee6 | 2009-02-23 13:47:57 +0000 | [diff] [blame] | 214 | /* check for cast of constant expression */ |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 215 | if (type == EXPR_CAST && expr->is_const) |
| 216 | { |
Rob Shearman | b544014 | 2010-03-23 13:33:46 +0000 | [diff] [blame] | 217 | if (is_integer_type(tref)) |
| 218 | { |
Alexandre Julliard | cb6a225 | 2010-04-05 19:48:07 +0200 | [diff] [blame] | 219 | unsigned int cast_type_bits = type_memsize(tref) * 8; |
Alexandre Julliard | a83563a | 2010-03-26 11:42:28 +0100 | [diff] [blame] | 220 | unsigned int cast_mask; |
Rob Shearman | b544014 | 2010-03-23 13:33:46 +0000 | [diff] [blame] | 221 | |
| 222 | e->is_const = TRUE; |
| 223 | if (is_signed_integer_type(tref)) |
| 224 | { |
Jarkko Korpi | bb9b2f3 | 2016-06-21 09:23:22 +0300 | [diff] [blame] | 225 | cast_mask = (1u << (cast_type_bits - 1)) - 1; |
| 226 | if (expr->cval & (1u << (cast_type_bits - 1))) |
Rob Shearman | b544014 | 2010-03-23 13:33:46 +0000 | [diff] [blame] | 227 | e->cval = -((-expr->cval) & cast_mask); |
| 228 | else |
| 229 | e->cval = expr->cval & cast_mask; |
| 230 | } |
| 231 | else |
| 232 | { |
| 233 | /* calculate ((1 << cast_type_bits) - 1) avoiding overflow */ |
Jarkko Korpi | bb9b2f3 | 2016-06-21 09:23:22 +0300 | [diff] [blame] | 234 | cast_mask = ((1u << (cast_type_bits - 1)) - 1) | |
| 235 | 1u << (cast_type_bits - 1); |
Rob Shearman | b544014 | 2010-03-23 13:33:46 +0000 | [diff] [blame] | 236 | e->cval = expr->cval & cast_mask; |
| 237 | } |
| 238 | } |
| 239 | else |
| 240 | { |
| 241 | e->is_const = TRUE; |
| 242 | e->cval = expr->cval; |
| 243 | } |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 244 | } |
Rob Shearman | 0228008 | 2009-11-07 15:55:22 +0100 | [diff] [blame] | 245 | free(var); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 246 | return e; |
| 247 | } |
| 248 | |
| 249 | expr_t *make_expr1(enum expr_type type, expr_t *expr) |
| 250 | { |
| 251 | expr_t *e; |
| 252 | e = xmalloc(sizeof(expr_t)); |
| 253 | e->type = type; |
| 254 | e->ref = expr; |
| 255 | e->u.lval = 0; |
| 256 | e->is_const = FALSE; |
| 257 | /* check for compile-time optimization */ |
| 258 | if (expr->is_const) |
| 259 | { |
| 260 | e->is_const = TRUE; |
| 261 | switch (type) |
| 262 | { |
| 263 | case EXPR_LOGNOT: |
| 264 | e->cval = !expr->cval; |
| 265 | break; |
| 266 | case EXPR_POS: |
| 267 | e->cval = +expr->cval; |
| 268 | break; |
| 269 | case EXPR_NEG: |
| 270 | e->cval = -expr->cval; |
| 271 | break; |
| 272 | case EXPR_NOT: |
| 273 | e->cval = ~expr->cval; |
| 274 | break; |
| 275 | default: |
| 276 | e->is_const = FALSE; |
| 277 | break; |
| 278 | } |
| 279 | } |
| 280 | return e; |
| 281 | } |
| 282 | |
| 283 | expr_t *make_expr2(enum expr_type type, expr_t *expr1, expr_t *expr2) |
| 284 | { |
| 285 | expr_t *e; |
| 286 | e = xmalloc(sizeof(expr_t)); |
| 287 | e->type = type; |
| 288 | e->ref = expr1; |
| 289 | e->u.ext = expr2; |
| 290 | e->is_const = FALSE; |
| 291 | /* check for compile-time optimization */ |
| 292 | if (expr1->is_const && expr2->is_const) |
| 293 | { |
| 294 | e->is_const = TRUE; |
| 295 | switch (type) |
| 296 | { |
| 297 | case EXPR_ADD: |
| 298 | e->cval = expr1->cval + expr2->cval; |
| 299 | break; |
| 300 | case EXPR_SUB: |
| 301 | e->cval = expr1->cval - expr2->cval; |
| 302 | break; |
| 303 | case EXPR_MOD: |
| 304 | if (expr2->cval == 0) |
| 305 | { |
| 306 | error_loc("divide by zero in expression\n"); |
| 307 | e->cval = 0; |
| 308 | } |
| 309 | else |
| 310 | e->cval = expr1->cval % expr2->cval; |
| 311 | break; |
| 312 | case EXPR_MUL: |
| 313 | e->cval = expr1->cval * expr2->cval; |
| 314 | break; |
| 315 | case EXPR_DIV: |
| 316 | if (expr2->cval == 0) |
| 317 | { |
| 318 | error_loc("divide by zero in expression\n"); |
| 319 | e->cval = 0; |
| 320 | } |
| 321 | else |
| 322 | e->cval = expr1->cval / expr2->cval; |
| 323 | break; |
| 324 | case EXPR_OR: |
| 325 | e->cval = expr1->cval | expr2->cval; |
| 326 | break; |
| 327 | case EXPR_AND: |
| 328 | e->cval = expr1->cval & expr2->cval; |
| 329 | break; |
| 330 | case EXPR_SHL: |
| 331 | e->cval = expr1->cval << expr2->cval; |
| 332 | break; |
| 333 | case EXPR_SHR: |
| 334 | e->cval = expr1->cval >> expr2->cval; |
| 335 | break; |
| 336 | case EXPR_LOGOR: |
| 337 | e->cval = expr1->cval || expr2->cval; |
| 338 | break; |
| 339 | case EXPR_LOGAND: |
| 340 | e->cval = expr1->cval && expr2->cval; |
| 341 | break; |
| 342 | case EXPR_XOR: |
| 343 | e->cval = expr1->cval ^ expr2->cval; |
| 344 | break; |
| 345 | case EXPR_EQUALITY: |
| 346 | e->cval = expr1->cval == expr2->cval; |
| 347 | break; |
| 348 | case EXPR_INEQUALITY: |
| 349 | e->cval = expr1->cval != expr2->cval; |
| 350 | break; |
| 351 | case EXPR_GTR: |
| 352 | e->cval = expr1->cval > expr2->cval; |
| 353 | break; |
| 354 | case EXPR_LESS: |
| 355 | e->cval = expr1->cval < expr2->cval; |
| 356 | break; |
| 357 | case EXPR_GTREQL: |
| 358 | e->cval = expr1->cval >= expr2->cval; |
| 359 | break; |
| 360 | case EXPR_LESSEQL: |
| 361 | e->cval = expr1->cval <= expr2->cval; |
| 362 | break; |
| 363 | default: |
| 364 | e->is_const = FALSE; |
| 365 | break; |
| 366 | } |
| 367 | } |
| 368 | return e; |
| 369 | } |
| 370 | |
| 371 | expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, expr_t *expr3) |
| 372 | { |
| 373 | expr_t *e; |
| 374 | e = xmalloc(sizeof(expr_t)); |
| 375 | e->type = type; |
| 376 | e->ref = expr1; |
| 377 | e->u.ext = expr2; |
| 378 | e->ext2 = expr3; |
| 379 | e->is_const = FALSE; |
| 380 | /* check for compile-time optimization */ |
| 381 | if (expr1->is_const && expr2->is_const && expr3->is_const) |
| 382 | { |
| 383 | e->is_const = TRUE; |
| 384 | switch (type) |
| 385 | { |
| 386 | case EXPR_COND: |
| 387 | e->cval = expr1->cval ? expr2->cval : expr3->cval; |
| 388 | break; |
| 389 | default: |
| 390 | e->is_const = FALSE; |
| 391 | break; |
| 392 | } |
| 393 | } |
| 394 | return e; |
| 395 | } |
| 396 | |
| 397 | struct expression_type |
| 398 | { |
| 399 | int is_variable; /* is the expression resolved to a variable? */ |
| 400 | int is_temporary; /* should the type be freed? */ |
| 401 | type_t *type; |
| 402 | }; |
| 403 | |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 404 | static void check_scalar_type(const struct expr_loc *expr_loc, |
| 405 | const type_t *cont_type, const type_t *type) |
| 406 | { |
| 407 | if (!cont_type || (!is_integer_type(type) && !is_ptr(type) && |
Rob Shearman | ba91ee6 | 2009-02-23 13:47:57 +0000 | [diff] [blame] | 408 | !is_float_type(type))) |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 409 | error_loc_info(&expr_loc->v->loc_info, "scalar type required in expression%s%s\n", |
| 410 | expr_loc->attr ? " for attribute " : "", |
| 411 | expr_loc->attr ? expr_loc->attr : ""); |
| 412 | } |
| 413 | |
| 414 | static void check_arithmetic_type(const struct expr_loc *expr_loc, |
| 415 | const type_t *cont_type, const type_t *type) |
| 416 | { |
Rob Shearman | ba91ee6 | 2009-02-23 13:47:57 +0000 | [diff] [blame] | 417 | if (!cont_type || (!is_integer_type(type) && !is_float_type(type))) |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 418 | error_loc_info(&expr_loc->v->loc_info, "arithmetic type required in expression%s%s\n", |
| 419 | expr_loc->attr ? " for attribute " : "", |
| 420 | expr_loc->attr ? expr_loc->attr : ""); |
| 421 | } |
| 422 | |
| 423 | static void check_integer_type(const struct expr_loc *expr_loc, |
| 424 | const type_t *cont_type, const type_t *type) |
| 425 | { |
| 426 | if (!cont_type || !is_integer_type(type)) |
| 427 | error_loc_info(&expr_loc->v->loc_info, "integer type required in expression%s%s\n", |
| 428 | expr_loc->attr ? " for attribute " : "", |
| 429 | expr_loc->attr ? expr_loc->attr : ""); |
| 430 | } |
| 431 | |
Rob Shearman | 1a0d28b | 2008-04-22 11:37:07 +0100 | [diff] [blame] | 432 | static type_t *find_identifier(const char *identifier, const type_t *cont_type, int *found_in_cont_type) |
| 433 | { |
| 434 | type_t *type = NULL; |
| 435 | const var_t *field; |
| 436 | const var_list_t *fields = NULL; |
| 437 | |
| 438 | *found_in_cont_type = 0; |
| 439 | |
Rob Shearman | 04a22cc | 2008-12-29 12:05:27 +0000 | [diff] [blame] | 440 | if (cont_type) |
Rob Shearman | 1a0d28b | 2008-04-22 11:37:07 +0100 | [diff] [blame] | 441 | { |
Rob Shearman | ba91ee6 | 2009-02-23 13:47:57 +0000 | [diff] [blame] | 442 | switch (type_get_type(cont_type)) |
| 443 | { |
| 444 | case TYPE_FUNCTION: |
Rob Shearman | 04a22cc | 2008-12-29 12:05:27 +0000 | [diff] [blame] | 445 | fields = type_function_get_args(cont_type); |
Rob Shearman | ba91ee6 | 2009-02-23 13:47:57 +0000 | [diff] [blame] | 446 | break; |
| 447 | case TYPE_STRUCT: |
Rob Shearman | 04a22cc | 2008-12-29 12:05:27 +0000 | [diff] [blame] | 448 | fields = type_struct_get_fields(cont_type); |
Rob Shearman | ba91ee6 | 2009-02-23 13:47:57 +0000 | [diff] [blame] | 449 | break; |
| 450 | case TYPE_UNION: |
| 451 | case TYPE_ENCAPSULATED_UNION: |
Rob Shearman | 04a22cc | 2008-12-29 12:05:27 +0000 | [diff] [blame] | 452 | fields = type_union_get_cases(cont_type); |
Rob Shearman | ba91ee6 | 2009-02-23 13:47:57 +0000 | [diff] [blame] | 453 | break; |
| 454 | case TYPE_VOID: |
| 455 | case TYPE_BASIC: |
| 456 | case TYPE_ENUM: |
| 457 | case TYPE_MODULE: |
| 458 | case TYPE_COCLASS: |
| 459 | case TYPE_INTERFACE: |
| 460 | case TYPE_POINTER: |
| 461 | case TYPE_ARRAY: |
Rob Shearman | cdec0fe | 2009-11-07 15:55:09 +0100 | [diff] [blame] | 462 | case TYPE_BITFIELD: |
Rob Shearman | ba91ee6 | 2009-02-23 13:47:57 +0000 | [diff] [blame] | 463 | /* nothing to do */ |
| 464 | break; |
| 465 | case TYPE_ALIAS: |
| 466 | /* shouldn't get here because of using type_get_type above */ |
| 467 | assert(0); |
| 468 | break; |
| 469 | } |
Rob Shearman | 1a0d28b | 2008-04-22 11:37:07 +0100 | [diff] [blame] | 470 | } |
| 471 | |
| 472 | if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry ) |
| 473 | if (field->name && !strcmp(identifier, field->name)) |
| 474 | { |
| 475 | type = field->type; |
| 476 | *found_in_cont_type = 1; |
| 477 | break; |
| 478 | } |
| 479 | |
| 480 | if (!type) |
| 481 | { |
| 482 | var_t *const_var = find_const(identifier, 0); |
| 483 | if (const_var) type = const_var->type; |
| 484 | } |
| 485 | |
| 486 | return type; |
| 487 | } |
| 488 | |
Rob Shearman | ba91ee6 | 2009-02-23 13:47:57 +0000 | [diff] [blame] | 489 | static int is_valid_member_operand(const type_t *type) |
| 490 | { |
| 491 | switch (type_get_type(type)) |
| 492 | { |
| 493 | case TYPE_STRUCT: |
| 494 | case TYPE_UNION: |
| 495 | case TYPE_ENUM: |
| 496 | return TRUE; |
| 497 | default: |
| 498 | return FALSE; |
| 499 | } |
| 500 | } |
| 501 | |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 502 | static struct expression_type resolve_expression(const struct expr_loc *expr_loc, |
| 503 | const type_t *cont_type, |
| 504 | const expr_t *e) |
| 505 | { |
| 506 | struct expression_type result; |
| 507 | result.is_variable = FALSE; |
| 508 | result.is_temporary = FALSE; |
| 509 | result.type = NULL; |
| 510 | switch (e->type) |
| 511 | { |
| 512 | case EXPR_VOID: |
| 513 | break; |
| 514 | case EXPR_HEXNUM: |
| 515 | case EXPR_NUM: |
| 516 | case EXPR_TRUEFALSE: |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 517 | result.is_temporary = FALSE; |
Rob Shearman | 319a7a1 | 2009-03-05 08:21:51 +0000 | [diff] [blame] | 518 | result.type = type_new_int(TYPE_BASIC_INT, 0); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 519 | break; |
Rob Shearman | 33c891e | 2008-04-25 10:59:21 +0100 | [diff] [blame] | 520 | case EXPR_STRLIT: |
Rob Shearman | 33c891e | 2008-04-25 10:59:21 +0100 | [diff] [blame] | 521 | result.is_temporary = TRUE; |
Rob Shearman | 23673ca | 2009-03-07 23:23:44 +0000 | [diff] [blame] | 522 | result.type = type_new_pointer(RPC_FC_UP, type_new_int(TYPE_BASIC_CHAR, 0), NULL); |
Rob Shearman | 33c891e | 2008-04-25 10:59:21 +0100 | [diff] [blame] | 523 | break; |
| 524 | case EXPR_WSTRLIT: |
Rob Shearman | 33c891e | 2008-04-25 10:59:21 +0100 | [diff] [blame] | 525 | result.is_temporary = TRUE; |
Rob Shearman | 23673ca | 2009-03-07 23:23:44 +0000 | [diff] [blame] | 526 | result.type = type_new_pointer(RPC_FC_UP, type_new_int(TYPE_BASIC_WCHAR, 0), NULL); |
Rob Shearman | 33c891e | 2008-04-25 10:59:21 +0100 | [diff] [blame] | 527 | break; |
Rob Shearman | d9b83e8 | 2010-01-18 22:15:46 +0000 | [diff] [blame] | 528 | case EXPR_CHARCONST: |
Rob Shearman | d9b83e8 | 2010-01-18 22:15:46 +0000 | [diff] [blame] | 529 | result.is_temporary = TRUE; |
| 530 | result.type = type_new_int(TYPE_BASIC_CHAR, 0); |
| 531 | break; |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 532 | case EXPR_DOUBLE: |
Rob Shearman | 319a7a1 | 2009-03-05 08:21:51 +0000 | [diff] [blame] | 533 | result.is_temporary = TRUE; |
| 534 | result.type = type_new_basic(TYPE_BASIC_DOUBLE); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 535 | break; |
| 536 | case EXPR_IDENTIFIER: |
| 537 | { |
Rob Shearman | 1a0d28b | 2008-04-22 11:37:07 +0100 | [diff] [blame] | 538 | int found_in_cont_type; |
| 539 | result.is_variable = TRUE; |
| 540 | result.is_temporary = FALSE; |
| 541 | result.type = find_identifier(e->u.sval, cont_type, &found_in_cont_type); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 542 | if (!result.type) |
| 543 | { |
| 544 | error_loc_info(&expr_loc->v->loc_info, "identifier %s cannot be resolved in expression%s%s\n", |
| 545 | e->u.sval, expr_loc->attr ? " for attribute " : "", |
| 546 | expr_loc->attr ? expr_loc->attr : ""); |
| 547 | } |
| 548 | break; |
| 549 | } |
| 550 | case EXPR_LOGNOT: |
| 551 | result = resolve_expression(expr_loc, cont_type, e->ref); |
| 552 | check_scalar_type(expr_loc, cont_type, result.type); |
| 553 | result.is_variable = FALSE; |
| 554 | result.is_temporary = FALSE; |
Rob Shearman | 319a7a1 | 2009-03-05 08:21:51 +0000 | [diff] [blame] | 555 | result.type = type_new_int(TYPE_BASIC_INT, 0); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 556 | break; |
| 557 | case EXPR_NOT: |
| 558 | result = resolve_expression(expr_loc, cont_type, e->ref); |
| 559 | check_integer_type(expr_loc, cont_type, result.type); |
| 560 | result.is_variable = FALSE; |
| 561 | break; |
| 562 | case EXPR_POS: |
| 563 | case EXPR_NEG: |
| 564 | result = resolve_expression(expr_loc, cont_type, e->ref); |
| 565 | check_arithmetic_type(expr_loc, cont_type, result.type); |
| 566 | result.is_variable = FALSE; |
| 567 | break; |
| 568 | case EXPR_ADDRESSOF: |
| 569 | result = resolve_expression(expr_loc, cont_type, e->ref); |
| 570 | if (!result.is_variable) |
| 571 | error_loc_info(&expr_loc->v->loc_info, "address-of operator applied to non-variable type in expression%s%s\n", |
| 572 | expr_loc->attr ? " for attribute " : "", |
| 573 | expr_loc->attr ? expr_loc->attr : ""); |
Gerald Pfeifer | 3a64eb2 | 2015-06-30 00:21:08 +0200 | [diff] [blame] | 574 | result.is_variable = FALSE; |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 575 | result.is_temporary = TRUE; |
Rob Shearman | 23673ca | 2009-03-07 23:23:44 +0000 | [diff] [blame] | 576 | result.type = type_new_pointer(RPC_FC_UP, result.type, NULL); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 577 | break; |
| 578 | case EXPR_PPTR: |
| 579 | result = resolve_expression(expr_loc, cont_type, e->ref); |
| 580 | if (result.type && is_ptr(result.type)) |
Rob Shearman | 67ac03a | 2009-01-05 23:34:58 +0000 | [diff] [blame] | 581 | result.type = type_pointer_get_ref(result.type); |
Michael Karcher | 1c56d29 | 2009-01-11 15:00:18 +0100 | [diff] [blame] | 582 | else if(result.type && is_array(result.type) |
Rob Shearman | 7e08ff2 | 2009-03-05 08:21:35 +0000 | [diff] [blame] | 583 | && type_array_is_decl_as_ptr(result.type)) |
Michael Karcher | 1c56d29 | 2009-01-11 15:00:18 +0100 | [diff] [blame] | 584 | result.type = type_array_get_element(result.type); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 585 | else |
| 586 | error_loc_info(&expr_loc->v->loc_info, "dereference operator applied to non-pointer type in expression%s%s\n", |
| 587 | expr_loc->attr ? " for attribute " : "", |
| 588 | expr_loc->attr ? expr_loc->attr : ""); |
| 589 | break; |
| 590 | case EXPR_CAST: |
| 591 | result = resolve_expression(expr_loc, cont_type, e->ref); |
| 592 | result.type = e->u.tref; |
| 593 | break; |
| 594 | case EXPR_SIZEOF: |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 595 | result.is_temporary = FALSE; |
Rob Shearman | 319a7a1 | 2009-03-05 08:21:51 +0000 | [diff] [blame] | 596 | result.type = type_new_int(TYPE_BASIC_INT, 0); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 597 | break; |
| 598 | case EXPR_SHL: |
| 599 | case EXPR_SHR: |
| 600 | case EXPR_MOD: |
| 601 | case EXPR_MUL: |
| 602 | case EXPR_DIV: |
| 603 | case EXPR_ADD: |
| 604 | case EXPR_SUB: |
| 605 | case EXPR_AND: |
| 606 | case EXPR_OR: |
| 607 | case EXPR_XOR: |
| 608 | { |
| 609 | struct expression_type result_right; |
| 610 | result = resolve_expression(expr_loc, cont_type, e->ref); |
| 611 | result.is_variable = FALSE; |
| 612 | result_right = resolve_expression(expr_loc, cont_type, e->u.ext); |
| 613 | /* FIXME: these checks aren't strict enough for some of the operators */ |
| 614 | check_scalar_type(expr_loc, cont_type, result.type); |
| 615 | check_scalar_type(expr_loc, cont_type, result_right.type); |
| 616 | break; |
| 617 | } |
| 618 | case EXPR_LOGOR: |
| 619 | case EXPR_LOGAND: |
| 620 | case EXPR_EQUALITY: |
| 621 | case EXPR_INEQUALITY: |
| 622 | case EXPR_GTR: |
| 623 | case EXPR_LESS: |
| 624 | case EXPR_GTREQL: |
| 625 | case EXPR_LESSEQL: |
| 626 | { |
| 627 | struct expression_type result_left, result_right; |
| 628 | result_left = resolve_expression(expr_loc, cont_type, e->ref); |
| 629 | result_right = resolve_expression(expr_loc, cont_type, e->u.ext); |
| 630 | check_scalar_type(expr_loc, cont_type, result_left.type); |
| 631 | check_scalar_type(expr_loc, cont_type, result_right.type); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 632 | result.is_temporary = FALSE; |
Rob Shearman | 319a7a1 | 2009-03-05 08:21:51 +0000 | [diff] [blame] | 633 | result.type = type_new_int(TYPE_BASIC_INT, 0); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 634 | break; |
| 635 | } |
| 636 | case EXPR_MEMBER: |
| 637 | result = resolve_expression(expr_loc, cont_type, e->ref); |
Rob Shearman | ba91ee6 | 2009-02-23 13:47:57 +0000 | [diff] [blame] | 638 | if (result.type && is_valid_member_operand(result.type)) |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 639 | result = resolve_expression(expr_loc, result.type, e->u.ext); |
| 640 | else |
| 641 | 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", |
| 642 | expr_loc->attr ? " for attribute " : "", |
| 643 | expr_loc->attr ? expr_loc->attr : ""); |
| 644 | break; |
| 645 | case EXPR_COND: |
| 646 | { |
| 647 | struct expression_type result_first, result_second, result_third; |
| 648 | result_first = resolve_expression(expr_loc, cont_type, e->ref); |
| 649 | check_scalar_type(expr_loc, cont_type, result_first.type); |
| 650 | result_second = resolve_expression(expr_loc, cont_type, e->u.ext); |
| 651 | result_third = resolve_expression(expr_loc, cont_type, e->ext2); |
Alexandre Julliard | 82f33d3 | 2011-07-25 10:43:09 +0200 | [diff] [blame] | 652 | check_scalar_type(expr_loc, cont_type, result_second.type); |
| 653 | check_scalar_type(expr_loc, cont_type, result_third.type); |
| 654 | if (!is_ptr(result_second.type) ^ !is_ptr(result_third.type)) |
| 655 | error_loc_info(&expr_loc->v->loc_info, "type mismatch in ?: expression\n" ); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 656 | /* FIXME: determine the correct return type */ |
| 657 | result = result_second; |
| 658 | result.is_variable = FALSE; |
| 659 | break; |
| 660 | } |
| 661 | case EXPR_ARRAY: |
| 662 | result = resolve_expression(expr_loc, cont_type, e->ref); |
| 663 | if (result.type && is_array(result.type)) |
| 664 | { |
| 665 | struct expression_type index_result; |
Rob Shearman | 2b87d26 | 2009-01-05 23:34:52 +0000 | [diff] [blame] | 666 | result.type = type_array_get_element(result.type); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 667 | index_result = resolve_expression(expr_loc, cont_type /* FIXME */, e->u.ext); |
| 668 | if (!index_result.type || !is_integer_type(index_result.type)) |
| 669 | error_loc_info(&expr_loc->v->loc_info, "array subscript not of integral type in expression%s%s\n", |
| 670 | expr_loc->attr ? " for attribute " : "", |
| 671 | expr_loc->attr ? expr_loc->attr : ""); |
| 672 | } |
| 673 | else |
| 674 | error_loc_info(&expr_loc->v->loc_info, "array subscript operator applied to non-array type in expression%s%s\n", |
| 675 | expr_loc->attr ? " for attribute " : "", |
| 676 | expr_loc->attr ? expr_loc->attr : ""); |
| 677 | break; |
| 678 | } |
| 679 | return result; |
| 680 | } |
| 681 | |
| 682 | const type_t *expr_resolve_type(const struct expr_loc *expr_loc, const type_t *cont_type, const expr_t *expr) |
| 683 | { |
| 684 | struct expression_type expr_type; |
| 685 | expr_type = resolve_expression(expr_loc, cont_type, expr); |
| 686 | return expr_type.type; |
| 687 | } |
| 688 | |
Rob Shearman | 1a0d28b | 2008-04-22 11:37:07 +0100 | [diff] [blame] | 689 | void write_expr(FILE *h, const expr_t *e, int brackets, |
| 690 | int toplevel, const char *toplevel_prefix, |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 691 | const type_t *cont_type, const char *local_var_prefix) |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 692 | { |
| 693 | switch (e->type) |
| 694 | { |
| 695 | case EXPR_VOID: |
| 696 | break; |
| 697 | case EXPR_NUM: |
Alexandre Julliard | a83563a | 2010-03-26 11:42:28 +0100 | [diff] [blame] | 698 | fprintf(h, "%u", e->u.lval); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 699 | break; |
| 700 | case EXPR_HEXNUM: |
Alexandre Julliard | a83563a | 2010-03-26 11:42:28 +0100 | [diff] [blame] | 701 | fprintf(h, "0x%x", e->u.lval); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 702 | break; |
| 703 | case EXPR_DOUBLE: |
| 704 | fprintf(h, "%#.15g", e->u.dval); |
| 705 | break; |
| 706 | case EXPR_TRUEFALSE: |
| 707 | if (e->u.lval == 0) |
| 708 | fprintf(h, "FALSE"); |
| 709 | else |
| 710 | fprintf(h, "TRUE"); |
| 711 | break; |
| 712 | case EXPR_IDENTIFIER: |
Rob Shearman | 1a0d28b | 2008-04-22 11:37:07 +0100 | [diff] [blame] | 713 | if (toplevel && toplevel_prefix && cont_type) |
| 714 | { |
| 715 | int found_in_cont_type; |
| 716 | find_identifier(e->u.sval, cont_type, &found_in_cont_type); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 717 | if (found_in_cont_type) |
| 718 | { |
| 719 | fprintf(h, "%s%s", toplevel_prefix, e->u.sval); |
| 720 | break; |
| 721 | } |
Rob Shearman | 1a0d28b | 2008-04-22 11:37:07 +0100 | [diff] [blame] | 722 | } |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 723 | fprintf(h, "%s%s", local_var_prefix, e->u.sval); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 724 | break; |
Rob Shearman | 33c891e | 2008-04-25 10:59:21 +0100 | [diff] [blame] | 725 | case EXPR_STRLIT: |
| 726 | fprintf(h, "\"%s\"", e->u.sval); |
| 727 | break; |
| 728 | case EXPR_WSTRLIT: |
| 729 | fprintf(h, "L\"%s\"", e->u.sval); |
| 730 | break; |
Rob Shearman | d9b83e8 | 2010-01-18 22:15:46 +0000 | [diff] [blame] | 731 | case EXPR_CHARCONST: |
| 732 | fprintf(h, "'%s'", e->u.sval); |
| 733 | break; |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 734 | case EXPR_LOGNOT: |
| 735 | fprintf(h, "!"); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 736 | write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 737 | break; |
| 738 | case EXPR_NOT: |
| 739 | fprintf(h, "~"); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 740 | write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 741 | break; |
| 742 | case EXPR_POS: |
| 743 | fprintf(h, "+"); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 744 | write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 745 | break; |
| 746 | case EXPR_NEG: |
| 747 | fprintf(h, "-"); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 748 | write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 749 | break; |
| 750 | case EXPR_ADDRESSOF: |
| 751 | fprintf(h, "&"); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 752 | write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 753 | break; |
| 754 | case EXPR_PPTR: |
| 755 | fprintf(h, "*"); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 756 | write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 757 | break; |
| 758 | case EXPR_CAST: |
| 759 | fprintf(h, "("); |
| 760 | write_type_decl(h, e->u.tref, NULL); |
| 761 | fprintf(h, ")"); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 762 | write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 763 | break; |
| 764 | case EXPR_SIZEOF: |
| 765 | fprintf(h, "sizeof("); |
| 766 | write_type_decl(h, e->u.tref, NULL); |
| 767 | fprintf(h, ")"); |
| 768 | break; |
| 769 | case EXPR_SHL: |
| 770 | case EXPR_SHR: |
| 771 | case EXPR_MOD: |
| 772 | case EXPR_MUL: |
| 773 | case EXPR_DIV: |
| 774 | case EXPR_ADD: |
| 775 | case EXPR_SUB: |
| 776 | case EXPR_AND: |
| 777 | case EXPR_OR: |
| 778 | case EXPR_LOGOR: |
| 779 | case EXPR_LOGAND: |
| 780 | case EXPR_XOR: |
| 781 | case EXPR_EQUALITY: |
| 782 | case EXPR_INEQUALITY: |
| 783 | case EXPR_GTR: |
| 784 | case EXPR_LESS: |
| 785 | case EXPR_GTREQL: |
| 786 | case EXPR_LESSEQL: |
| 787 | if (brackets) fprintf(h, "("); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 788 | write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 789 | switch (e->type) |
| 790 | { |
| 791 | case EXPR_SHL: fprintf(h, " << "); break; |
| 792 | case EXPR_SHR: fprintf(h, " >> "); break; |
| 793 | case EXPR_MOD: fprintf(h, " %% "); break; |
| 794 | case EXPR_MUL: fprintf(h, " * "); break; |
| 795 | case EXPR_DIV: fprintf(h, " / "); break; |
| 796 | case EXPR_ADD: fprintf(h, " + "); break; |
| 797 | case EXPR_SUB: fprintf(h, " - "); break; |
| 798 | case EXPR_AND: fprintf(h, " & "); break; |
| 799 | case EXPR_OR: fprintf(h, " | "); break; |
| 800 | case EXPR_LOGOR: fprintf(h, " || "); break; |
| 801 | case EXPR_LOGAND: fprintf(h, " && "); break; |
| 802 | case EXPR_XOR: fprintf(h, " ^ "); break; |
| 803 | case EXPR_EQUALITY: fprintf(h, " == "); break; |
| 804 | case EXPR_INEQUALITY: fprintf(h, " != "); break; |
| 805 | case EXPR_GTR: fprintf(h, " > "); break; |
| 806 | case EXPR_LESS: fprintf(h, " < "); break; |
| 807 | case EXPR_GTREQL: fprintf(h, " >= "); break; |
| 808 | case EXPR_LESSEQL: fprintf(h, " <= "); break; |
| 809 | default: break; |
| 810 | } |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 811 | write_expr(h, e->u.ext, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 812 | if (brackets) fprintf(h, ")"); |
| 813 | break; |
| 814 | case EXPR_MEMBER: |
| 815 | if (brackets) fprintf(h, "("); |
| 816 | if (e->ref->type == EXPR_PPTR) |
| 817 | { |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 818 | write_expr(h, e->ref->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 819 | fprintf(h, "->"); |
| 820 | } |
| 821 | else |
| 822 | { |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 823 | write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 824 | fprintf(h, "."); |
| 825 | } |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 826 | write_expr(h, e->u.ext, 1, 0, toplevel_prefix, cont_type, ""); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 827 | if (brackets) fprintf(h, ")"); |
| 828 | break; |
| 829 | case EXPR_COND: |
| 830 | if (brackets) fprintf(h, "("); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 831 | write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 832 | fprintf(h, " ? "); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 833 | write_expr(h, e->u.ext, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 834 | fprintf(h, " : "); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 835 | write_expr(h, e->ext2, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 836 | if (brackets) fprintf(h, ")"); |
| 837 | break; |
| 838 | case EXPR_ARRAY: |
| 839 | if (brackets) fprintf(h, "("); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 840 | write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 841 | fprintf(h, "["); |
Alexandre Julliard | bf011b0 | 2008-09-15 16:46:01 +0200 | [diff] [blame] | 842 | write_expr(h, e->u.ext, 1, 1, toplevel_prefix, cont_type, local_var_prefix); |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 843 | fprintf(h, "]"); |
| 844 | if (brackets) fprintf(h, ")"); |
| 845 | break; |
| 846 | } |
| 847 | } |
| 848 | |
| 849 | /* This is actually fairly involved to implement precisely, due to the |
| 850 | effects attributes may have and things like that. Right now this is |
| 851 | only used for optimization, so just check for a very small set of |
| 852 | criteria that guarantee the types are equivalent; assume every thing |
| 853 | else is different. */ |
| 854 | static int compare_type(const type_t *a, const type_t *b) |
| 855 | { |
| 856 | if (a == b |
| 857 | || (a->name |
| 858 | && b->name |
| 859 | && strcmp(a->name, b->name) == 0)) |
| 860 | return 0; |
| 861 | /* Ordering doesn't need to be implemented yet. */ |
| 862 | return 1; |
| 863 | } |
| 864 | |
| 865 | int compare_expr(const expr_t *a, const expr_t *b) |
| 866 | { |
| 867 | int ret; |
| 868 | |
| 869 | if (a->type != b->type) |
| 870 | return a->type - b->type; |
| 871 | |
| 872 | switch (a->type) |
| 873 | { |
| 874 | case EXPR_NUM: |
| 875 | case EXPR_HEXNUM: |
| 876 | case EXPR_TRUEFALSE: |
| 877 | return a->u.lval - b->u.lval; |
| 878 | case EXPR_DOUBLE: |
| 879 | return a->u.dval - b->u.dval; |
| 880 | case EXPR_IDENTIFIER: |
Rob Shearman | 33c891e | 2008-04-25 10:59:21 +0100 | [diff] [blame] | 881 | case EXPR_STRLIT: |
| 882 | case EXPR_WSTRLIT: |
Rob Shearman | d9b83e8 | 2010-01-18 22:15:46 +0000 | [diff] [blame] | 883 | case EXPR_CHARCONST: |
Rob Shearman | 80ab2a7 | 2008-04-22 11:36:38 +0100 | [diff] [blame] | 884 | return strcmp(a->u.sval, b->u.sval); |
| 885 | case EXPR_COND: |
| 886 | ret = compare_expr(a->ref, b->ref); |
| 887 | if (ret != 0) |
| 888 | return ret; |
| 889 | ret = compare_expr(a->u.ext, b->u.ext); |
| 890 | if (ret != 0) |
| 891 | return ret; |
| 892 | return compare_expr(a->ext2, b->ext2); |
| 893 | case EXPR_OR: |
| 894 | case EXPR_AND: |
| 895 | case EXPR_ADD: |
| 896 | case EXPR_SUB: |
| 897 | case EXPR_MOD: |
| 898 | case EXPR_MUL: |
| 899 | case EXPR_DIV: |
| 900 | case EXPR_SHL: |
| 901 | case EXPR_SHR: |
| 902 | case EXPR_MEMBER: |
| 903 | case EXPR_ARRAY: |
| 904 | case EXPR_LOGOR: |
| 905 | case EXPR_LOGAND: |
| 906 | case EXPR_XOR: |
| 907 | case EXPR_EQUALITY: |
| 908 | case EXPR_INEQUALITY: |
| 909 | case EXPR_GTR: |
| 910 | case EXPR_LESS: |
| 911 | case EXPR_GTREQL: |
| 912 | case EXPR_LESSEQL: |
| 913 | ret = compare_expr(a->ref, b->ref); |
| 914 | if (ret != 0) |
| 915 | return ret; |
| 916 | return compare_expr(a->u.ext, b->u.ext); |
| 917 | case EXPR_CAST: |
| 918 | ret = compare_type(a->u.tref, b->u.tref); |
| 919 | if (ret != 0) |
| 920 | return ret; |
| 921 | /* Fall through. */ |
| 922 | case EXPR_NOT: |
| 923 | case EXPR_NEG: |
| 924 | case EXPR_PPTR: |
| 925 | case EXPR_ADDRESSOF: |
| 926 | case EXPR_LOGNOT: |
| 927 | case EXPR_POS: |
| 928 | return compare_expr(a->ref, b->ref); |
| 929 | case EXPR_SIZEOF: |
| 930 | return compare_type(a->u.tref, b->u.tref); |
| 931 | case EXPR_VOID: |
| 932 | return 0; |
| 933 | } |
| 934 | return -1; |
| 935 | } |