Import upstream sources.
[cparse] / number.c
CommitLineData
3cd4b0f8
MW
1#include "cparse.h"
2#include "platform.h"
3#include <float.h>
4#include <endian.h>
5
6/* order is important. */
7static 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 */
41static 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
58struct 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/*
176Local Variables:
177c-basic-offset:2
178comment-column:40
179End:
180*/