.gitignore: Ignore `ylwrap'.
[u/mdw/catacomb] / genlimits.c
CommitLineData
7eaaecf5
MW
1/* -*-c-*-
2 *
3 * $Id$
4 *
5 * Generate limit MPs for C types
6 *
7 * (c) 2006 Straylight/Edgeware
8 */
9
45c0fd36 10/*----- Licensing notice --------------------------------------------------*
7eaaecf5
MW
11 *
12 * This file is part of Catacomb.
13 *
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
45c0fd36 18 *
7eaaecf5
MW
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
45c0fd36 23 *
7eaaecf5
MW
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Header files ------------------------------------------------------*/
31
32#define _GNU_SOURCE
33#include <errno.h>
34#include <limits.h>
35#include <stdio.h>
36#include <string.h>
37
38#if __STDC_VERSION__ >= 199900l
39# include <stdint.h>
40# include <inttypes.h>
41#endif
42
43#include "mp.h"
44#include "mpint.h"
45
46/*----- Data types --------------------------------------------------------*/
47
48/* --- Hack for GCC --- *
49 *
50 * WG14 in their infinite wisdom decided not to use the GCC constant name.
51 */
52
53#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91)
54# define EXT __extension__
55#else
56# define EXT
57#endif
58
59#if defined(LONG_LONG_MIN) && !defined(LLONG_MIN)
60# define LLONG_MIN EXT LONG_LONG_MIN
61#endif
62
63#if defined(LONG_LONG_MAX) && !defined(LLONG_MAX)
64# define LLONG_MAX EXT LONG_LONG_MAX
65#endif
66
67#if defined(ULONG_LONG_MAX) && !defined(ULLONG_MAX)
68# define ULLONG_MAX EXT ULONG_LONG_MAX
69#endif
70
71/* --- Choose the largest integer type --- */
72
73#if defined(INTMAX_MAX)
74 typedef intmax_t imax;
75#elif defined(LLONG_MAX)
76 EXT typedef long long imax;
77#else
78 typedef long imax;
79#endif
80
81#if defined(UINTMAX_MAX)
82 typedef uintmax_t umax;
83#elif defined(ULLONG_MAX)
84 EXT typedef unsigned long long umax;
85#else
86 typedef unsigned long umax;
87#endif
88
89/*----- Main code ---------------------------------------------------------*/
90
91#define TABSZ 64
92
93enum { NEG, POS, NSIGN };
94
95umax cmap[TABSZ];
96int gmap[TABSZ][NSIGN];
97struct { int g, s; } qmap[TABSZ];
98int dumpp = 0;
99
100static int n, q;
101
102static void dump(mp *x)
103{
104 int i, w, n;
105
106 fputs(" ", stdout);
107 w = (MPW_BITS + 3)/4;
108 n = 1;
109 while (2 + 2 * n * (4 + w) < 72) n <<= 1;
110 i = 0;
111 for (;;) {
112 printf("0x%0*x", w, x->v[i]);
113 i++;
114 if (i >= MP_LEN(x)) break;
115 fputs(",", stdout);
116 if (i % n) fputs(" ", stdout); else fputs("\n ", stdout);
117 }
118 fputs("\n", stdout);
119}
120
121static void doemit(umax c, int s, int *gg, int *qq)
122{
123 int i;
124 mp *x = MP_NEW;
125
126 for (i = 0; i < n; i++) {
127 if (cmap[i] == c)
128 goto found;
129 }
130
131 assert(i < TABSZ);
132 n = i + 1;
133 cmap[i] = c;
134 gmap[i][POS] = gmap[i][NEG] = -1;
135 if (dumpp) {
136 MP_FROMINT(x, umax, c);
137 printf("static mpw guts_%d[] = {\n", q);
138 dump(x);
139 fputs("};\n\n", stdout);
140 MP_DROP(x);
141 }
142
143found:
144 *gg = i;
145 if (gmap[i][s] < 0) {
146 assert(q < TABSZ);
147 gmap[i][s] = q;
148 qmap[q].g = i;
149 qmap[q].s = s;
150 q++;
151 }
152 *qq = gmap[i][s];
153}
154
155static void emit(imax c, int *gg, int *qq)
156{
157 umax uc;
158 int s;
159
160 if (c >= 0) { uc = c; s = POS; }
161 else { uc = -c; s = NEG; }
162 doemit(uc, s, gg, qq);
163}
164
165static void uemit(umax c, int *gg, int *qq) { doemit(c, POS, gg, qq); }
166
167struct {
168 const char *name;
169 imax min;
170 umax max;
171 int gmin, gmax;
172 int qmin, qmax;
173} tab[] = {
174 { "SCHAR", SCHAR_MIN, SCHAR_MAX },
175 { "CHAR", CHAR_MIN, CHAR_MAX },
176 { "UCHAR", 0, UCHAR_MAX },
177 { "UINT8", 0, 0xff },
178 { "SHRT", SHRT_MIN, SHRT_MAX },
179 { "USHRT", 0, USHRT_MAX },
180 { "UINT16", 0, 0xffff },
181 { "INT", INT_MIN, INT_MAX },
182 { "UINT", 0, UINT_MAX },
183 { "LONG", LONG_MIN, LONG_MAX },
184 { "ULONG", 0, ULONG_MAX },
185 { "UINT32", 0, 0xffffffff },
186#ifdef LLONG_MAX
187 { "LLONG", LLONG_MIN, LLONG_MAX },
188 { "ULLONG", 0, ULLONG_MAX },
189#endif
190 { "SIZET", 0, ~(size_t)0 },
191 { 0 }
192};
193
194static void dogen(void)
195{
196 int i;
197
198 for (i = 0; tab[i].name; i++) {
199 if (tab[i].min)
200 emit(tab[i].min, &tab[i].gmin, &tab[i].qmin);
201 uemit(tab[i].max, &tab[i].gmax, &tab[i].qmax);
202 }
203}
204
205static void cgen(void)
206{
207 int i;
208
209 fputs("\
210/* -*-c-*-\n\
211 *\n\
212 * C integer limits [generated]\n\
213 */\n\
214\n\
215#include \"mplimits.h\"\n\
216\n\
217#define N(x) (sizeof(x)/sizeof(*x))\n\
218#define MPpos(x) { x, x + N(x), N(x), 0, MP_CONST, 0 }\n\
219#define MPneg(x) { x, x + N(x), N(x), 0, MP_CONST|MP_NEG, 0 }\n\
220\n",
221 stdout);
222 dumpp = 1;
223 dogen();
224
225 fputs("mp mp_limits[] = {\n", stdout);
226 for (i = 0; i < q; i++)
227 printf(" MP%s(guts_%d),\n", qmap[i].s ? "pos" : "neg", qmap[i].g);
228 fputs("};\n", stdout);
229}
230
231static void hgen(void)
232{
233 int i;
234
235 fputs("\
236/* -*-c-*-\n\
237 *\n\
238 * C integer limits [generated]\n\
239 */\n\
240\n\
241#ifndef CATACOMB_MPLIMITS_H\n\
242#define CATACOMB_MPLIMITS_H\n\
243\n\
244#ifndef CATACOMB_MP_H\n\
245# include \"mp.h\"\n\
246#endif\n\
247\n\
248extern mp mp_limits[];\n\
249\n",
250 stdout);
251 dogen();
45c0fd36 252
7eaaecf5
MW
253 for (i = 0; tab[i].name; i++) {
254 if (tab[i].min) {
255 printf("#define MP_%s_MIN (&mp_limits[%d])\n",
256 tab[i].name, gmap[tab[i].qmin][NEG]);
257 }
258 printf("#define MP_%s_MAX (&mp_limits[%d])\n",
259 tab[i].name, gmap[tab[i].qmax][POS]);
260 }
261 fputs("\n#endif\n", stdout);
262}
263
264int main(int argc, char *argv[])
265{
266 const char *what = argc == 2 ? argv[1] : "<bogus>";
267
268 switch (what[0]) {
269 case 'c': cgen(); break;
270 case 'h': hgen(); break;
271 default:
272 fprintf(stderr, "unknown action `%s'\n", what);
273 exit(1);
274 }
275 if (fflush(stdout) || fclose(stdout)) {
276 fprintf(stderr, "error writing output: %s\n", strerror(errno));
277 exit(1);
278 }
279 return (0);
280}
281
282/*----- That's all, folks -------------------------------------------------*/