advapi32/tests: Add some GetEventLogInformation tests.
[wine] / tools / widl / expr.c
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"
35 #include "typetree.h"
36 #include "typegen.h"
37
38 static int is_integer_type(const type_t *type);
39 static int is_float_type(const type_t *type);
40
41 expr_t *make_expr(enum expr_type type)
42 {
43     expr_t *e = xmalloc(sizeof(expr_t));
44     e->type = type;
45     e->ref = NULL;
46     e->u.lval = 0;
47     e->is_const = FALSE;
48     e->cval = 0;
49     return e;
50 }
51
52 expr_t *make_exprl(enum expr_type type, long val)
53 {
54     expr_t *e = xmalloc(sizeof(expr_t));
55     e->type = type;
56     e->ref = NULL;
57     e->u.lval = val;
58     e->is_const = FALSE;
59     /* check for numeric constant */
60     if (type == EXPR_NUM || type == EXPR_HEXNUM || type == EXPR_TRUEFALSE)
61     {
62         /* make sure true/false value is valid */
63         assert(type != EXPR_TRUEFALSE || val == 0 || val == 1);
64         e->is_const = TRUE;
65         e->cval = val;
66     }
67     return e;
68 }
69
70 expr_t *make_exprd(enum expr_type type, double val)
71 {
72     expr_t *e = xmalloc(sizeof(expr_t));
73     e->type = type;
74     e->ref = NULL;
75     e->u.dval = val;
76     e->is_const = TRUE;
77     e->cval = val;
78     return e;
79 }
80
81 expr_t *make_exprs(enum expr_type type, char *val)
82 {
83     expr_t *e;
84     e = xmalloc(sizeof(expr_t));
85     e->type = type;
86     e->ref = NULL;
87     e->u.sval = val;
88     e->is_const = FALSE;
89     /* check for predefined constants */
90     if (type == EXPR_IDENTIFIER)
91     {
92         var_t *c = find_const(val, 0);
93         if (c)
94         {
95             e->u.sval = c->name;
96             free(val);
97             e->is_const = TRUE;
98             e->cval = c->eval->cval;
99         }
100     }
101     return e;
102 }
103
104 expr_t *make_exprt(enum expr_type type, type_t *tref, expr_t *expr)
105 {
106     expr_t *e;
107     e = xmalloc(sizeof(expr_t));
108     e->type = type;
109     e->ref = expr;
110     e->u.tref = tref;
111     e->is_const = FALSE;
112     if (type == EXPR_SIZEOF)
113     {
114         /* only do this for types that should be the same on all platforms */
115         if (is_integer_type(tref) || is_float_type(tref))
116         {
117             unsigned int align = 0;
118             e->is_const = TRUE;
119             e->cval = type_memsize(tref, &align);
120         }
121     }
122     /* check for cast of constant expression */
123     if (type == EXPR_CAST && expr->is_const)
124     {
125         e->is_const = TRUE;
126         e->cval = expr->cval;
127     }
128     return e;
129 }
130
131 expr_t *make_expr1(enum expr_type type, expr_t *expr)
132 {
133     expr_t *e;
134     e = xmalloc(sizeof(expr_t));
135     e->type = type;
136     e->ref = expr;
137     e->u.lval = 0;
138     e->is_const = FALSE;
139     /* check for compile-time optimization */
140     if (expr->is_const)
141     {
142         e->is_const = TRUE;
143         switch (type)
144         {
145         case EXPR_LOGNOT:
146             e->cval = !expr->cval;
147             break;
148         case EXPR_POS:
149             e->cval = +expr->cval;
150             break;
151         case EXPR_NEG:
152             e->cval = -expr->cval;
153             break;
154         case EXPR_NOT:
155             e->cval = ~expr->cval;
156             break;
157         default:
158             e->is_const = FALSE;
159             break;
160         }
161     }
162     return e;
163 }
164
165 expr_t *make_expr2(enum expr_type type, expr_t *expr1, expr_t *expr2)
166 {
167     expr_t *e;
168     e = xmalloc(sizeof(expr_t));
169     e->type = type;
170     e->ref = expr1;
171     e->u.ext = expr2;
172     e->is_const = FALSE;
173     /* check for compile-time optimization */
174     if (expr1->is_const && expr2->is_const)
175     {
176         e->is_const = TRUE;
177         switch (type)
178         {
179         case EXPR_ADD:
180             e->cval = expr1->cval + expr2->cval;
181             break;
182         case EXPR_SUB:
183             e->cval = expr1->cval - expr2->cval;
184             break;
185         case EXPR_MOD:
186             if (expr2->cval == 0)
187             {
188                 error_loc("divide by zero in expression\n");
189                 e->cval = 0;
190             }
191             else
192                 e->cval = expr1->cval % expr2->cval;
193             break;
194         case EXPR_MUL:
195             e->cval = expr1->cval * expr2->cval;
196             break;
197         case EXPR_DIV:
198             if (expr2->cval == 0)
199             {
200                 error_loc("divide by zero in expression\n");
201                 e->cval = 0;
202             }
203             else
204                 e->cval = expr1->cval / expr2->cval;
205             break;
206         case EXPR_OR:
207             e->cval = expr1->cval | expr2->cval;
208             break;
209         case EXPR_AND:
210             e->cval = expr1->cval & expr2->cval;
211             break;
212         case EXPR_SHL:
213             e->cval = expr1->cval << expr2->cval;
214             break;
215         case EXPR_SHR:
216             e->cval = expr1->cval >> expr2->cval;
217             break;
218         case EXPR_LOGOR:
219             e->cval = expr1->cval || expr2->cval;
220             break;
221         case EXPR_LOGAND:
222             e->cval = expr1->cval && expr2->cval;
223             break;
224         case EXPR_XOR:
225             e->cval = expr1->cval ^ expr2->cval;
226             break;
227         case EXPR_EQUALITY:
228             e->cval = expr1->cval == expr2->cval;
229             break;
230         case EXPR_INEQUALITY:
231             e->cval = expr1->cval != expr2->cval;
232             break;
233         case EXPR_GTR:
234             e->cval = expr1->cval > expr2->cval;
235             break;
236         case EXPR_LESS:
237             e->cval = expr1->cval < expr2->cval;
238             break;
239         case EXPR_GTREQL:
240             e->cval = expr1->cval >= expr2->cval;
241             break;
242         case EXPR_LESSEQL:
243             e->cval = expr1->cval <= expr2->cval;
244             break;
245         default:
246             e->is_const = FALSE;
247             break;
248         }
249     }
250     return e;
251 }
252
253 expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, expr_t *expr3)
254 {
255     expr_t *e;
256     e = xmalloc(sizeof(expr_t));
257     e->type = type;
258     e->ref = expr1;
259     e->u.ext = expr2;
260     e->ext2 = expr3;
261     e->is_const = FALSE;
262     /* check for compile-time optimization */
263     if (expr1->is_const && expr2->is_const && expr3->is_const)
264     {
265         e->is_const = TRUE;
266         switch (type)
267         {
268         case EXPR_COND:
269             e->cval = expr1->cval ? expr2->cval : expr3->cval;
270             break;
271         default:
272             e->is_const = FALSE;
273             break;
274         }
275     }
276     return e;
277 }
278
279 struct expression_type
280 {
281     int is_variable; /* is the expression resolved to a variable? */
282     int is_temporary; /* should the type be freed? */
283     type_t *type;
284 };
285
286 static int is_integer_type(const type_t *type)
287 {
288     switch (type_get_type(type))
289     {
290     case TYPE_ENUM:
291         return TRUE;
292     case TYPE_BASIC:
293         switch (type_basic_get_type(type))
294         {
295         case TYPE_BASIC_INT8:
296         case TYPE_BASIC_INT16:
297         case TYPE_BASIC_INT32:
298         case TYPE_BASIC_INT64:
299         case TYPE_BASIC_INT:
300         case TYPE_BASIC_CHAR:
301         case TYPE_BASIC_HYPER:
302         case TYPE_BASIC_BYTE:
303         case TYPE_BASIC_WCHAR:
304         case TYPE_BASIC_ERROR_STATUS_T:
305             return TRUE;
306         default:
307             return FALSE;
308         }
309     default:
310         return FALSE;
311     }
312 }
313
314 static int is_float_type(const type_t *type)
315 {
316     return (type_get_type(type) == TYPE_BASIC &&
317         (type_basic_get_type(type) == TYPE_BASIC_FLOAT ||
318          type_basic_get_type(type) == TYPE_BASIC_DOUBLE));
319 }
320
321 static void check_scalar_type(const struct expr_loc *expr_loc,
322                               const type_t *cont_type, const type_t *type)
323 {
324     if (!cont_type || (!is_integer_type(type) && !is_ptr(type) &&
325                        !is_float_type(type)))
326         error_loc_info(&expr_loc->v->loc_info, "scalar type required in expression%s%s\n",
327                        expr_loc->attr ? " for attribute " : "",
328                        expr_loc->attr ? expr_loc->attr : "");
329 }
330
331 static void check_arithmetic_type(const struct expr_loc *expr_loc,
332                                   const type_t *cont_type, const type_t *type)
333 {
334     if (!cont_type || (!is_integer_type(type) && !is_float_type(type)))
335         error_loc_info(&expr_loc->v->loc_info, "arithmetic type required in expression%s%s\n",
336                        expr_loc->attr ? " for attribute " : "",
337                        expr_loc->attr ? expr_loc->attr : "");
338 }
339
340 static void check_integer_type(const struct expr_loc *expr_loc,
341                                const type_t *cont_type, const type_t *type)
342 {
343     if (!cont_type || !is_integer_type(type))
344         error_loc_info(&expr_loc->v->loc_info, "integer type required in expression%s%s\n",
345                        expr_loc->attr ? " for attribute " : "",
346                        expr_loc->attr ? expr_loc->attr : "");
347 }
348
349 static type_t *find_identifier(const char *identifier, const type_t *cont_type, int *found_in_cont_type)
350 {
351     type_t *type = NULL;
352     const var_t *field;
353     const var_list_t *fields = NULL;
354
355     *found_in_cont_type = 0;
356
357     if (cont_type)
358     {
359         switch (type_get_type(cont_type))
360         {
361         case TYPE_FUNCTION:
362             fields = type_function_get_args(cont_type);
363             break;
364         case TYPE_STRUCT:
365             fields = type_struct_get_fields(cont_type);
366             break;
367         case TYPE_UNION:
368         case TYPE_ENCAPSULATED_UNION:
369             fields = type_union_get_cases(cont_type);
370             break;
371         case TYPE_VOID:
372         case TYPE_BASIC:
373         case TYPE_ENUM:
374         case TYPE_MODULE:
375         case TYPE_COCLASS:
376         case TYPE_INTERFACE:
377         case TYPE_POINTER:
378         case TYPE_ARRAY:
379             /* nothing to do */
380             break;
381         case TYPE_ALIAS:
382             /* shouldn't get here because of using type_get_type above */
383             assert(0);
384             break;
385         }
386     }
387
388     if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
389         if (field->name && !strcmp(identifier, field->name))
390         {
391             type = field->type;
392             *found_in_cont_type = 1;
393             break;
394         }
395
396     if (!type)
397     {
398         var_t *const_var = find_const(identifier, 0);
399         if (const_var) type = const_var->type;
400     }
401
402     return type;
403 }
404
405 static int is_valid_member_operand(const type_t *type)
406 {
407     switch (type_get_type(type))
408     {
409     case TYPE_STRUCT:
410     case TYPE_UNION:
411     case TYPE_ENUM:
412         return TRUE;
413     default:
414         return FALSE;
415     }
416 }
417
418 static struct expression_type resolve_expression(const struct expr_loc *expr_loc,
419                                                  const type_t *cont_type,
420                                                  const expr_t *e)
421 {
422     struct expression_type result;
423     result.is_variable = FALSE;
424     result.is_temporary = FALSE;
425     result.type = NULL;
426     switch (e->type)
427     {
428     case EXPR_VOID:
429         break;
430     case EXPR_HEXNUM:
431     case EXPR_NUM:
432     case EXPR_TRUEFALSE:
433         result.is_variable = FALSE;
434         result.is_temporary = FALSE;
435         result.type = type_new_int(TYPE_BASIC_INT, 0);
436         break;
437     case EXPR_STRLIT:
438         result.is_variable = FALSE;
439         result.is_temporary = TRUE;
440         result.type = type_new_pointer(RPC_FC_UP, type_new_int(TYPE_BASIC_CHAR, 0), NULL);
441         break;
442     case EXPR_WSTRLIT:
443         result.is_variable = FALSE;
444         result.is_temporary = TRUE;
445         result.type = type_new_pointer(RPC_FC_UP, type_new_int(TYPE_BASIC_WCHAR, 0), NULL);
446         break;
447     case EXPR_DOUBLE:
448         result.is_variable = FALSE;
449         result.is_temporary = TRUE;
450         result.type = type_new_basic(TYPE_BASIC_DOUBLE);
451         break;
452     case EXPR_IDENTIFIER:
453     {
454         int found_in_cont_type;
455         result.is_variable = TRUE;
456         result.is_temporary = FALSE;
457         result.type = find_identifier(e->u.sval, cont_type, &found_in_cont_type);
458         if (!result.type)
459         {
460             error_loc_info(&expr_loc->v->loc_info, "identifier %s cannot be resolved in expression%s%s\n",
461                            e->u.sval, expr_loc->attr ? " for attribute " : "",
462                            expr_loc->attr ? expr_loc->attr : "");
463         }
464         break;
465     }
466     case EXPR_LOGNOT:
467         result = resolve_expression(expr_loc, cont_type, e->ref);
468         check_scalar_type(expr_loc, cont_type, result.type);
469         result.is_variable = FALSE;
470         result.is_temporary = FALSE;
471         result.type = type_new_int(TYPE_BASIC_INT, 0);
472         break;
473     case EXPR_NOT:
474         result = resolve_expression(expr_loc, cont_type, e->ref);
475         check_integer_type(expr_loc, cont_type, result.type);
476         result.is_variable = FALSE;
477         break;
478     case EXPR_POS:
479     case EXPR_NEG:
480         result = resolve_expression(expr_loc, cont_type, e->ref);
481         check_arithmetic_type(expr_loc, cont_type, result.type);
482         result.is_variable = FALSE;
483         break;
484     case EXPR_ADDRESSOF:
485         result = resolve_expression(expr_loc, cont_type, e->ref);
486         if (!result.is_variable)
487             error_loc_info(&expr_loc->v->loc_info, "address-of operator applied to non-variable type in expression%s%s\n",
488                            expr_loc->attr ? " for attribute " : "",
489                            expr_loc->attr ? expr_loc->attr : "");
490             result.is_variable = FALSE;
491         result.is_temporary = TRUE;
492         result.type = type_new_pointer(RPC_FC_UP, result.type, NULL);
493         break;
494     case EXPR_PPTR:
495         result = resolve_expression(expr_loc, cont_type, e->ref);
496         if (result.type && is_ptr(result.type))
497             result.type = type_pointer_get_ref(result.type);
498         else if(result.type && is_array(result.type)
499                             && type_array_is_decl_as_ptr(result.type))
500             result.type = type_array_get_element(result.type);
501         else
502             error_loc_info(&expr_loc->v->loc_info, "dereference operator applied to non-pointer type in expression%s%s\n",
503                            expr_loc->attr ? " for attribute " : "",
504                            expr_loc->attr ? expr_loc->attr : "");
505         break;
506     case EXPR_CAST:
507         result = resolve_expression(expr_loc, cont_type, e->ref);
508         result.type = e->u.tref;
509         break;
510     case EXPR_SIZEOF:
511         result.is_variable = FALSE;
512         result.is_temporary = FALSE;
513         result.type = type_new_int(TYPE_BASIC_INT, 0);
514         break;
515     case EXPR_SHL:
516     case EXPR_SHR:
517     case EXPR_MOD:
518     case EXPR_MUL:
519     case EXPR_DIV:
520     case EXPR_ADD:
521     case EXPR_SUB:
522     case EXPR_AND:
523     case EXPR_OR:
524     case EXPR_XOR:
525     {
526         struct expression_type result_right;
527         result = resolve_expression(expr_loc, cont_type, e->ref);
528         result.is_variable = FALSE;
529         result_right = resolve_expression(expr_loc, cont_type, e->u.ext);
530         /* FIXME: these checks aren't strict enough for some of the operators */
531         check_scalar_type(expr_loc, cont_type, result.type);
532         check_scalar_type(expr_loc, cont_type, result_right.type);
533         break;
534     }
535     case EXPR_LOGOR:
536     case EXPR_LOGAND:
537     case EXPR_EQUALITY:
538     case EXPR_INEQUALITY:
539     case EXPR_GTR:
540     case EXPR_LESS:
541     case EXPR_GTREQL:
542     case EXPR_LESSEQL:
543     {
544         struct expression_type result_left, result_right;
545         result_left = resolve_expression(expr_loc, cont_type, e->ref);
546         result_right = resolve_expression(expr_loc, cont_type, e->u.ext);
547         check_scalar_type(expr_loc, cont_type, result_left.type);
548         check_scalar_type(expr_loc, cont_type, result_right.type);
549         result.is_variable = FALSE;
550         result.is_temporary = FALSE;
551         result.type = type_new_int(TYPE_BASIC_INT, 0);
552         break;
553     }
554     case EXPR_MEMBER:
555         result = resolve_expression(expr_loc, cont_type, e->ref);
556         if (result.type && is_valid_member_operand(result.type))
557             result = resolve_expression(expr_loc, result.type, e->u.ext);
558         else
559             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",
560                            expr_loc->attr ? " for attribute " : "",
561                            expr_loc->attr ? expr_loc->attr : "");
562         break;
563     case EXPR_COND:
564     {
565         struct expression_type result_first, result_second, result_third;
566         result_first = resolve_expression(expr_loc, cont_type, e->ref);
567         check_scalar_type(expr_loc, cont_type, result_first.type);
568         result_second = resolve_expression(expr_loc, cont_type, e->u.ext);
569         result_third = resolve_expression(expr_loc, cont_type, e->ext2);
570         /* FIXME: determine the correct return type */
571         result = result_second;
572         result.is_variable = FALSE;
573         break;
574     }
575     case EXPR_ARRAY:
576         result = resolve_expression(expr_loc, cont_type, e->ref);
577         if (result.type && is_array(result.type))
578         {
579             struct expression_type index_result;
580             result.type = type_array_get_element(result.type);
581             index_result = resolve_expression(expr_loc, cont_type /* FIXME */, e->u.ext);
582             if (!index_result.type || !is_integer_type(index_result.type))
583                 error_loc_info(&expr_loc->v->loc_info, "array subscript not of integral type in expression%s%s\n",
584                                expr_loc->attr ? " for attribute " : "",
585                                expr_loc->attr ? expr_loc->attr : "");
586         }
587         else
588             error_loc_info(&expr_loc->v->loc_info, "array subscript operator applied to non-array type in expression%s%s\n",
589                            expr_loc->attr ? " for attribute " : "",
590                            expr_loc->attr ? expr_loc->attr : "");
591         break;
592     }
593     return result;
594 }
595
596 const type_t *expr_resolve_type(const struct expr_loc *expr_loc, const type_t *cont_type, const expr_t *expr)
597 {
598     struct expression_type expr_type;
599     expr_type = resolve_expression(expr_loc, cont_type, expr);
600     return expr_type.type;
601 }
602
603 void write_expr(FILE *h, const expr_t *e, int brackets,
604                 int toplevel, const char *toplevel_prefix,
605                 const type_t *cont_type, const char *local_var_prefix)
606 {
607     switch (e->type)
608     {
609     case EXPR_VOID:
610         break;
611     case EXPR_NUM:
612         fprintf(h, "%lu", e->u.lval);
613         break;
614     case EXPR_HEXNUM:
615         fprintf(h, "0x%lx", e->u.lval);
616         break;
617     case EXPR_DOUBLE:
618         fprintf(h, "%#.15g", e->u.dval);
619         break;
620     case EXPR_TRUEFALSE:
621         if (e->u.lval == 0)
622             fprintf(h, "FALSE");
623         else
624             fprintf(h, "TRUE");
625         break;
626     case EXPR_IDENTIFIER:
627         if (toplevel && toplevel_prefix && cont_type)
628         {
629             int found_in_cont_type;
630             find_identifier(e->u.sval, cont_type, &found_in_cont_type);
631             if (found_in_cont_type)
632             {
633                 fprintf(h, "%s%s", toplevel_prefix, e->u.sval);
634                 break;
635             }
636         }
637         fprintf(h, "%s%s", local_var_prefix, e->u.sval);
638         break;
639     case EXPR_STRLIT:
640         fprintf(h, "\"%s\"", e->u.sval);
641         break;
642     case EXPR_WSTRLIT:
643         fprintf(h, "L\"%s\"", e->u.sval);
644         break;
645     case EXPR_LOGNOT:
646         fprintf(h, "!");
647         write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
648         break;
649     case EXPR_NOT:
650         fprintf(h, "~");
651         write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
652         break;
653     case EXPR_POS:
654         fprintf(h, "+");
655         write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
656         break;
657     case EXPR_NEG:
658         fprintf(h, "-");
659         write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
660         break;
661     case EXPR_ADDRESSOF:
662         fprintf(h, "&");
663         write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
664         break;
665     case EXPR_PPTR:
666         fprintf(h, "*");
667         write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
668         break;
669     case EXPR_CAST:
670         fprintf(h, "(");
671         write_type_decl(h, e->u.tref, NULL);
672         fprintf(h, ")");
673         write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
674         break;
675     case EXPR_SIZEOF:
676         fprintf(h, "sizeof(");
677         write_type_decl(h, e->u.tref, NULL);
678         fprintf(h, ")");
679         break;
680     case EXPR_SHL:
681     case EXPR_SHR:
682     case EXPR_MOD:
683     case EXPR_MUL:
684     case EXPR_DIV:
685     case EXPR_ADD:
686     case EXPR_SUB:
687     case EXPR_AND:
688     case EXPR_OR:
689     case EXPR_LOGOR:
690     case EXPR_LOGAND:
691     case EXPR_XOR:
692     case EXPR_EQUALITY:
693     case EXPR_INEQUALITY:
694     case EXPR_GTR:
695     case EXPR_LESS:
696     case EXPR_GTREQL:
697     case EXPR_LESSEQL:
698         if (brackets) fprintf(h, "(");
699         write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
700         switch (e->type)
701         {
702         case EXPR_SHL:          fprintf(h, " << "); break;
703         case EXPR_SHR:          fprintf(h, " >> "); break;
704         case EXPR_MOD:          fprintf(h, " %% "); break;
705         case EXPR_MUL:          fprintf(h, " * "); break;
706         case EXPR_DIV:          fprintf(h, " / "); break;
707         case EXPR_ADD:          fprintf(h, " + "); break;
708         case EXPR_SUB:          fprintf(h, " - "); break;
709         case EXPR_AND:          fprintf(h, " & "); break;
710         case EXPR_OR:           fprintf(h, " | "); break;
711         case EXPR_LOGOR:        fprintf(h, " || "); break;
712         case EXPR_LOGAND:       fprintf(h, " && "); break;
713         case EXPR_XOR:          fprintf(h, " ^ "); break;
714         case EXPR_EQUALITY:     fprintf(h, " == "); break;
715         case EXPR_INEQUALITY:   fprintf(h, " != "); break;
716         case EXPR_GTR:          fprintf(h, " > "); break;
717         case EXPR_LESS:         fprintf(h, " < "); break;
718         case EXPR_GTREQL:       fprintf(h, " >= "); break;
719         case EXPR_LESSEQL:      fprintf(h, " <= "); break;
720         default: break;
721         }
722         write_expr(h, e->u.ext, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
723         if (brackets) fprintf(h, ")");
724         break;
725     case EXPR_MEMBER:
726         if (brackets) fprintf(h, "(");
727         if (e->ref->type == EXPR_PPTR)
728         {
729             write_expr(h, e->ref->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
730             fprintf(h, "->");
731         }
732         else
733         {
734             write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
735             fprintf(h, ".");
736         }
737         write_expr(h, e->u.ext, 1, 0, toplevel_prefix, cont_type, "");
738         if (brackets) fprintf(h, ")");
739         break;
740     case EXPR_COND:
741         if (brackets) fprintf(h, "(");
742         write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
743         fprintf(h, " ? ");
744         write_expr(h, e->u.ext, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
745         fprintf(h, " : ");
746         write_expr(h, e->ext2, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
747         if (brackets) fprintf(h, ")");
748         break;
749     case EXPR_ARRAY:
750         if (brackets) fprintf(h, "(");
751         write_expr(h, e->ref, 1, toplevel, toplevel_prefix, cont_type, local_var_prefix);
752         fprintf(h, "[");
753         write_expr(h, e->u.ext, 1, 1, toplevel_prefix, cont_type, local_var_prefix);
754         fprintf(h, "]");
755         if (brackets) fprintf(h, ")");
756         break;
757     }
758 }
759
760 /* This is actually fairly involved to implement precisely, due to the
761    effects attributes may have and things like that.  Right now this is
762    only used for optimization, so just check for a very small set of
763    criteria that guarantee the types are equivalent; assume every thing
764    else is different.   */
765 static int compare_type(const type_t *a, const type_t *b)
766 {
767     if (a == b
768         || (a->name
769             && b->name
770             && strcmp(a->name, b->name) == 0))
771         return 0;
772     /* Ordering doesn't need to be implemented yet.  */
773     return 1;
774 }
775
776 int compare_expr(const expr_t *a, const expr_t *b)
777 {
778     int ret;
779
780     if (a->type != b->type)
781         return a->type - b->type;
782
783     switch (a->type)
784     {
785         case EXPR_NUM:
786         case EXPR_HEXNUM:
787         case EXPR_TRUEFALSE:
788             return a->u.lval - b->u.lval;
789         case EXPR_DOUBLE:
790             return a->u.dval - b->u.dval;
791         case EXPR_IDENTIFIER:
792         case EXPR_STRLIT:
793         case EXPR_WSTRLIT:
794             return strcmp(a->u.sval, b->u.sval);
795         case EXPR_COND:
796             ret = compare_expr(a->ref, b->ref);
797             if (ret != 0)
798                 return ret;
799             ret = compare_expr(a->u.ext, b->u.ext);
800             if (ret != 0)
801                 return ret;
802             return compare_expr(a->ext2, b->ext2);
803         case EXPR_OR:
804         case EXPR_AND:
805         case EXPR_ADD:
806         case EXPR_SUB:
807         case EXPR_MOD:
808         case EXPR_MUL:
809         case EXPR_DIV:
810         case EXPR_SHL:
811         case EXPR_SHR:
812         case EXPR_MEMBER:
813         case EXPR_ARRAY:
814         case EXPR_LOGOR:
815         case EXPR_LOGAND:
816         case EXPR_XOR:
817         case EXPR_EQUALITY:
818         case EXPR_INEQUALITY:
819         case EXPR_GTR:
820         case EXPR_LESS:
821         case EXPR_GTREQL:
822         case EXPR_LESSEQL:
823             ret = compare_expr(a->ref, b->ref);
824             if (ret != 0)
825                 return ret;
826             return compare_expr(a->u.ext, b->u.ext);
827         case EXPR_CAST:
828             ret = compare_type(a->u.tref, b->u.tref);
829             if (ret != 0)
830                 return ret;
831             /* Fall through.  */
832         case EXPR_NOT:
833         case EXPR_NEG:
834         case EXPR_PPTR:
835         case EXPR_ADDRESSOF:
836         case EXPR_LOGNOT:
837         case EXPR_POS:
838             return compare_expr(a->ref, b->ref);
839         case EXPR_SIZEOF:
840             return compare_type(a->u.tref, b->u.tref);
841         case EXPR_VOID:
842             return 0;
843     }
844     return -1;
845 }