chiark / gitweb /
Import upstream sources.
[cparse] / number.c
1 #include "cparse.h"
2 #include "platform.h"
3 #include <float.h>
4 #include <endian.h>
5
6 /* order is important. */
7 static const struct {
8   unsigned type;
9   unsigned long long max;
10 } int_info[] = {
11   { TS_INT, P_INT_MAX },
12   { TS_UNSIGNED, P_UINT_MAX },
13   { TS_LONG, P_LONG_MAX },
14   { TS_UNSIGNED|TS_LONG, P_ULONG_MAX },
15   { TS_LONGLONG, P_LLONG_MAX },
16   { TS_UNSIGNED|TS_LONGLONG, P_ULLONG_MAX },
17   /* XXX other built-in integral types should maybe go here too */
18 };
19
20 #define N_INT_INFO (sizeof int_info / sizeof *int_info)
21
22 /* Throw away the bottom few bits of a floating point number.
23  * Makes rather free assumptions about representation!
24  * XXX only tested on i386 linux
25  *
26  * Why on earth do we need this ridiculous thing?
27  *
28  * gcc's FLT_MAX is defined as 3.40282347e+38F
29  * which its strtold converts to xxxx407effffff048ff9eb4e
30  * but gcc converts it to        xxxx407effffff0000000000
31  *                               ----EEEEMMMMMMMMMMMMMMMM
32  * so we end up with 3.40282347e+38 > FLT_MAX being true and getting
33  * an error.
34  *
35  * Really gcc should have written it as e.g. 3.4028234663852885982e+38
36  * which strtold converts to the exact answer.
37  *
38  * At least potentially the same problem might exist for DBL_MAX (I've
39  * not checked).
40  */
41 static void massage_float(long double *ld,
42                           unsigned bits) {
43   unsigned char *ptr = (unsigned char *)ld;
44   size_t n;
45   unsigned left;
46
47 #if BYTE_ORDER == BIG_ENDIAN
48   memset(ptr + sizeof (long double) - bits / 8, 0, bits / 8);
49   n = sizeof (long double) - bits / 8 - 1;
50 #else
51   memset(ptr, 0, bits / 8);
52   n = bits / 8;
53 #endif
54   if((left = bits & 7))
55     ptr[n] &= 0xFFFFFFFF << left;
56 }
57
58 struct declarator *numbertype(const struct expression *e) {
59   unsigned long long u;
60   long double ld;
61   int hex, f_l = 0, f_u = 0, f_f = 0;
62   char *rest;
63   struct declarator *d;
64   unsigned ts;
65   size_t n;
66
67   /* . always means a floating constant
68    * E/e but no 0x means a floating constant
69    * 0x and P/p means a floating constant
70    * anything else is some kind of integer
71    */
72   hex = !strncmp(e->u.constant, "0x", 2);
73   if(strchr(e->u.constant, '.')
74      || (hex ? strchr(e->u.constant, 'p') || strchr(e->u.constant, 'P')
75              : strchr(e->u.constant, 'e') || strchr(e->u.constant, 'E'))) {
76     /* long double had better be as big as the target's long double */
77     errno = 0;
78     ld = strtold(e->u.constant, &rest);
79     if(errno) {
80       inputerror(&e->where, "floating constant '%s' out of range",
81                  e->u.constant);
82       return 0;
83     }
84     while(*rest) {
85       switch(*rest++) {
86       case 'f': case 'F': f_f++; break;
87       case 'l': case 'L': f_l++; break;
88       default:
89         inputerror(&e->where, "invalid suffix on floating constant '%s'",
90                    e->u.constant);
91         return 0;
92       }
93     }
94     if(f_f + f_l > 1) {
95       inputerror(&e->where, "too many suffixes on floating constant '%s'",
96                  e->u.constant);
97       return 0;
98     }
99     if(f_f) {
100       massage_float(&ld, LDBL_MANT_DIG - P_FLT_MANT_DIG);
101       if(ld > P_FLT_MAX) {
102         inputerror(&e->where, "float constant '%s' out of range",
103                    e->u.constant);
104         return 0;
105       }
106       ts = TS_FLOAT;
107     } else if(!f_l) {
108       massage_float(&ld, LDBL_MANT_DIG - P_DBL_MANT_DIG);
109       if(ld > P_DBL_MAX) {
110         inputerror(&e->where, "double constant '%s' out of range",
111                    e->u.constant);
112         return 0;
113       }
114       ts = TS_DOUBLE;
115     } else {
116       massage_float(&ld, LDBL_MANT_DIG - P_LDBL_MANT_DIG);
117       if(ld > P_LDBL_MAX) {
118         inputerror(&e->where, "double constant '%s' out of range",
119                    e->u.constant);
120         return 0;
121       }
122       ts = TS_LONG|TS_DOUBLE;
123     }
124     NEW(d);
125     NEW(d->declaration_specifiers);
126     d->declaration_specifiers->type_specifiers = ts;
127     return d;
128   } else {
129     errno = 0;
130     u = strtoull(e->u.constant, &rest, 0);
131     if(errno) {
132       inputerror(&e->where, "integral constant '%s' out of range",
133                  e->u.constant);
134       return 0;
135     }
136     while(*rest) {
137       switch(*rest++) {
138       case 'u': case 'U': f_u++; break;
139       case 'l': case 'L': f_l++; break;
140       default:
141         inputerror(&e->where, "invalid suffix on integral constant '%s'",
142                    e->u.constant);
143         return 0;
144       }
145     }
146     if(f_u > 1 || f_l > 2) {
147       inputerror(&e->where, "too many suffixes on integral constant '%s'",
148                  e->u.constant);
149       return 0;
150     }
151     if(hex || e->u.constant[0] == '0') {
152       /* hex or octal - first type that fits */
153       for(n = 2 * f_l; n < N_INT_INFO; ++n)
154         if(u <= int_info[n].max)
155           break;
156     } else {
157       /* decimal - unsigned only allowed if u/U specified */
158       for(n = 2 * f_l; n < N_INT_INFO; ++n)
159         if(u <= int_info[n].max)
160           if(f_u || !(int_info[n].type & TS_UNSIGNED))
161             break;
162     }
163     if(n >= N_INT_INFO) {
164       inputerror(&e->where, "integral constant '%s' out of range",
165                  e->u.constant);
166       return 0;
167     }
168     NEW(d);
169     NEW(d->declaration_specifiers);
170     d->declaration_specifiers->type_specifiers = int_info[n].type;
171     return d;
172   }
173 }
174
175 /*
176 Local Variables:
177 c-basic-offset:2
178 comment-column:40
179 End:
180 */