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