chiark / gitweb /
Release 2.1.3.
[catacomb] / genlimits.c
1 /* -*-c-*-
2  *
3  * $Id$
4  *
5  * Generate limit MPs for C types
6  *
7  * (c) 2006 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------*
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.
18  *
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.
23  *
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
93 enum { NEG, POS, NSIGN };
94
95 umax cmap[TABSZ];
96 int gmap[TABSZ][NSIGN];
97 struct { int g, s; } qmap[TABSZ];
98 int dumpp = 0;
99
100 static int n, q;
101
102 static 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
121 static 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
143 found:
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
155 static 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
165 static void uemit(umax c, int *gg, int *qq) { doemit(c, POS, gg, qq); }
166
167 struct {
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
194 static 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
205 static 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
231 static 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\
248 extern mp mp_limits[];\n\
249 \n",
250         stdout);
251   dogen();
252
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
264 int 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 -------------------------------------------------*/