1 /*
2  * vec_h.c -- vec.h generator.
3  *
4  * Outputs a file containing vector macros for dimensions 2..maxdim,
5  * where maxdim is specified on the command line.
6  *
7  * Usage: vec_h <maxdim>
8  */
9 
10 static const char *intro[] = {
11  " vec.h --  Vector macros for %2..d-1, and %d dimensions,",
12  "           for any  combination of C scalar types.",
13  "",
14  " Author:              Don Hatch (hatch@hadron.org)",
15  " Last modified:       Tue Apr 13 21:58:39 PDT 1999",
16  "",
17  " General description:",
18  "",
19  "      The macro name describes its arguments; e.g.",
20  "              MXS3 is \"matrix times scalar in 3 dimensions\";",
21  "              VMV2 is \"vector minus vector in 2 dimensions\".",
22  "",
23  "      If the result of an operation is a scalar, then the macro \"returns\"",
24  "      the value; e.g.",
25  "              result = DOT3(v,w);",
26  "              result = DET4(m);",
27  "",
28  "      If the result of an operation is a vector or matrix, then",
29  "      the first argument is the destination; e.g.",
30  "              SET2(tovec, fromvec);",
31  "              MXM3(result, m1, m2);",
32  "",
33  "  WARNING: For the operations that are not done \"componentwise\"",
34  "          (e.g. vector cross products and matrix multiplies)",
35  "          the destination should not be either of the arguments,",
36  "          for obvious reasons.  For example, the following is wrong:",
37  "              VXM2(v,v,m);",
38  "          For such \"unsafe\" macros, there are safe versions provided,",
39  "          but you have to specify a type for the temporary",
40  "          result vector or matrix.  For example, the safe versions",
41  "          of VXM2 are:",
42  "              VXM2d(v,v,m)    if v's scalar type is double or float",
43  "              VXM2f(v,v,m)    if v's scalar type is float",
44  "              VXM2i(v,v,m)    if v's scalar type is int or char",
45  "              VXM2l(v,v,m)    if v's scalar type is long",
46  "              VXM2r(v,v,m)    if v's scalar type is real",
47  "              VXM2safe(type,v,v,m) for other scalar types.",
48  "",
49  "          These \"safe\" macros and INVERTMAT do not evaluate to C expressions",
50  "          (so, for example, they can't be used inside the parentheses of",
51  "          a for(...)).",
52  "",
53  "  Specific descriptions:",
54  "",
55  "      The \"?\"'s in the following can be 2, 3, or 4.",
56  "",
57  "      EXPAND?(v)                      comma-separated list of elements of v",
58  "",
59  "      SET?(to,from)                   to = from",
60  "      SETMAT?(to,from)                to = from",
61  "      ROUNDVEC?(to,from)              to = from with entries rounded",
62  "                                                      to nearest integer",
63  "      ROUNDMAT?(to,from)              to = from with entries rounded",
64  "                                                      to nearest integer",
65  "      FILLVEC?(v,s)                   set each entry of vector v to be s",
66  "      FILLMAT?(m,s)                   set each entry of matrix m to be s",
67  "      ZEROVEC?(v)                     v = 0",
68  "      ISZEROVEC?(v)                   v == 0",
69  "      EQVEC?(v,w)                     v == w",
70  "      EQMAT?(m1,m2)                   m1 == m2",
71  "      ZEROMAT?(m)                     m = 0",
72  "      IDENTMAT?(m)                    m = 1",
73  "      TRANSPOSE?(to,from)             (matrix to) = (transpose of matrix from)",
74  "      ADJOINT?(to,from)               (matrix to) = (adjoint of matrix from)",
75  "                                       i.e. its determinant times its inverse",
76  "      INVERTMAT?{d,f,i,l,r}(to,from)  (matrix to) = (inverse of matrix from)",
77  "                               with temp adjoint and determinant type",
78  "                               double, float, int, long, or real respectively",
79  "",
80  "      V{P,M}V?(to,v,w)                to = v {+,-} w",
81  "      M{P,M}M?(to,m1,m2)              to = m1 {+,-} m2",
82  "      SX{V,M}?(to,s,from)             to = s * from",
83  "      VPSXV?(to,v,s,w)                to = v + s*w",
84  "      VPVXS?(to,v,w,s)                to = v + w*s",
85  "      M{V,M}?(to,from)                to = -from",
86  "      {V,M}{X,D}S?(to,from,s)         to = from {*,/} s",
87  "      MXM?(to,m1,m2)                  to = m1 * m2",
88  "      VXM?(to,v,m)                    (row vec to) = (row vec v) * m",
89  "      MXV?(to,m,v)                    (column vec to) = m * (column vec v)",
90  "      VMODS?(to,v,s)                  to = v mod s (always >= 0)",
91  "      VMODV?(to,v0,v1)                to = v0 mod v1 componentwise",
92  "      VDIVS?(to,v,s)                  to = (v-(v mod s))/s",
93  "      VDIVV?(to,v0,v1)                to = (v0-(v0 mod v1))/v1 componentwise",
94  "      V{MIN,MAX}S?(to,v,s)            to = {MIN,MAX}(v, s)",
95  "      V{MIN,MAX}V?(to,v0,v1)          to = {MIN,MAX}(v0, v1)",
96  "      LERP?(to,v0,v1,t)               to = v0 + t*(v1-v0)",
97  "",
98  "      DET?(m)                         determinant of m",
99  "      TRACE?(m)                       trace (sum of diagonal entries) of m",
100  "      DOT?(v,w)                       dot (scalar) product of v and w",
101  "      NORMSQRD?(v)                    square of |v|",
102  "      DISTSQRD?(v,w)                  square of |v-w|",
103  "",
104  "      XV2(to,v)                       to = v rotated by 90 degrees",
105  "      VXV3(to,v1,v2)                  to = cross (vector) product of v1 and v2",
106  "      VXVXV4(to,v1,v2,v3)             to = 4-dimensional vector cross product",
107  "                                       of v1,v2,v3 (a vector orthogonal to",
108  "                                       v1,v2,v3 whose length equals the",
109  "                                       volume of the spanned parallelotope)",
110  "      VXV2(v0,v1)                     determinant of matrix with rows v0,v1",
111  "      VXVXV3(v0,v1,v2)                determinant of matrix with rows v0,v1,v2",
112  "      VXVXVXV4(v0,v1,v2,v3)           determinant of matrix with rows v0,..,v3",
113  "",
114  "   The following macros mix objects from different dimensions.",
115  "   For example, V3XM4 would be used to apply a composite",
116  "   4x4 rotation-and-translation matrix to a 3d vector.",
117  "",
118  "      SET3from2(to,from,pad)          (3d vec to) = (2d vec from) with pad",
119  "      SET4from3(to,from,pad)          (4d vec to) = (3d vec from) with pad",
120  "      SETMAT3from2(to,from,pad0,pad1) (3x3 mat to) = (2x2 mat from)",
121  "                                       padded with pad0 on the sides",
122  "                                       and pad1 in the corner",
123  "      SETMAT4from3(to,from,pad0,pad1) (4x4 mat to) = (3x3 mat from)",
124  "                                       padded with pad0 on the sides",
125  "                                       and pad1 in the corner",
126  "      V2XM3(to2,v2,m3)       (2d row vec to2) = (2d row vec v2) * (3x3 mat m3)",
127  "      V3XM4(to3,v3,m4)       (3d row vec to3) = (3d row vec v2) * (4x4 mat m4)",
128  "      M3XV2(to2,m3,v2)       (2d col vec to2) = (3x3 mat m3) * (2d col vec v2)",
129  "      M4XV3(to3,m4,v3)       (3d col vec to3) = (4x4 mat m4) * (3d col vec v3)",
130  "      M2XM3(to3,m2,m3)       (3x3 mat to3) = (2x2 mat m2) * (3x3 mat m3)",
131  "      M3XM4(to4,m3,m4)       (4x4 mat to4) = (3x3 mat m3) * (4x4 mat m4)",
132  "      M3XM2(to3,m3,m2)       (3x3 mat to3) = (3x3 mat m3) * (2x2 mat m2)",
133  "      M4XM3(to4,m4,m3)       (4x4 mat to4) = (4x4 mat m4) * (3x3 mat m3)",
134  "",
135  "",
136  "   This file is machine-generated and can be regenerated",
137  "   for any number of dimensions.",
138  "   The program that generated it is available upon request.",
139 0
140 };
141 
142 static struct {
143     const char *abbr, *full;
144 } types[] = {
145     {"d", "double"},
146     {"f", "float"},
147     {"i", "int"},
148     {"l", "long"},
149     {"r", "real"},
150 };
151 
152 static struct definition {
153     int safety; /* 0 means already safe, i.e. returns a scalar or is done
154                    "componentwise".  1 means unsafe and returns a vector.
155                                      2 means unsafe and returns a matrix. */
156     const char *name_and_args, *all_but_last, *sep, *last;
157 } defs[] = {
158     {0, "SET%d(to,from)",     "(to)[%i] = (from)[%i]",                     ","},
159     {0, "SETMAT%d(to,from)",  "SET%d((to)[%i], (from)[%i])",               ","},
160     {0, "ROUNDVEC%d(to,from)","(to)[%i] = (int)floor((from)[%i]+.5)",      ","},
161     {0, "ROUNDMAT%d(to,from)","ROUNDVEC%d((to)[%i], (from)[%i])",          ","},
162     {0, "FILLVEC%d(v,s)",     "(v)[%i] = (s)",                             ","},
163     {0, "FILLMAT%d(m,s)",     "FILLVEC%d((m)[%i], s)",                     ","},
164     {0, "ZEROVEC%d(v)",       "(v)[%i] = 0",                               ","},
165     {0, "ISZEROVEC%d(v)",     "(v)[%i] == 0",                            " &&"},
166     {0, "EQVEC%d(v,w)",       "(v)[%i] == (w)[%i]",                      " &&"},
167     {0, "EQMAT%d(m1,m2)",     "EQVEC%d((m1)[%i], (m2)[%i])",             " &&"},
168     {0, "ZEROMAT%d(m)",       "ZEROVEC%d((m)[%i])",                        ","},
169     {0, "IDENTMAT%d(m)",      "ZEROVEC%d((m)[%i]), (m)[%i][%i]=1",         ","},
170     {2, "TRANSPOSE%d(to,from)", "_SETcol%d((to)[%i], from, %i)",           ","},
171     {0, "VPSXV%d(to,v,s,w)",  "(to)[%i] = (v)[%i] + (s) * (w)[%i]",        ","},
172     {0, "VPVXS%d(to,v,w,s)",  "(to)[%i] = (v)[%i] + (w)[%i] * (s)",        ","},
173     {0, "VPV%d(to,v,w)",      "(to)[%i] = (v)[%i] + (w)[%i]",              ","},
174     {0, "VMV%d(to,v,w)",      "(to)[%i] = (v)[%i] - (w)[%i]",              ","},
175     {0, "MPM%d(to,m1,m2)",    "VPV%d((to)[%i], (m1)[%i], (m2)[%i])",       ","},
176     {0, "MMM%d(to,m1,m2)",    "VMV%d((to)[%i], (m1)[%i], (m2)[%i])",       ","},
177     {0, "SXV%d(to,s,from)",   "(to)[%i] = (s) * (from)[%i]",               ","},
178     {0, "SXM%d(to,s,from)",   "SXV%d((to)[%i], s, (from)[%i])",            ","},
179     {0, "MV%d(to,from)",      "(to)[%i] = -(from)[%i]",                    ","},
180     {0, "MM%d(to,from)",      "MV%d((to)[%i], (from)[%i])",                ","},
181     {0, "VXS%d(to,from,s)",   "(to)[%i] = (from)[%i] * (s)",               ","},
182     {0, "VDS%d(to,from,s)",   "(to)[%i] = (from)[%i] / (s)",               ","},
183     {0, "MXS%d(to,from,s)",   "VXS%d((to)[%i], (from)[%i], s)",            ","},
184     {0, "MDS%d(to,from,s)",   "VDS%d((to)[%i], (from)[%i], s)",            ","},
185     {2, "MXM%d(to,m1,m2)",    "VXM%d((to)[%i], (m1)[%i], m2)",             ","},
186     {1, "VXM%d(to,v,m)",      "(to)[%i] = _DOTcol%d(v, m, %i)",            ","},
187     {1, "MXV%d(to,m,v)",      "(to)[%i] = DOT%d((m)[%i], v)",              ","},
188     {0, "VMODS%d(to,v,s)",    "(to)[%i] = SMODS1((v)[%i], s)",             ","},
189     {0, "VMODV%d(to,v0,v1)",  "(to)[%i] = SMODS1((v0)[%i], (v1)[%i])",     ","},
190     {0, "VDIVS%d(to,v,s)",    "(to)[%i] = SDIVS1((v)[%i], s)",             ","},
191     {0, "VDIVV%d(to,v0,v1)",  "(to)[%i] = SDIVS1((v0)[%i], (v1)[%i])",     ","},
192     {0, "VMINS%d(to,v,s)",    "(to)[%i] = SMINS1((v)[%i], s)",             ","},
193     {0, "VMINV%d(to,v0,v1)",  "(to)[%i] = SMINS1((v0)[%i], (v1)[%i])",     ","},
194     {0, "VMAXS%d(to,v,s)",    "(to)[%i] = SMAXS1((v)[%i], s)",             ","},
195     {0, "VMAXV%d(to,v0,v1)",  "(to)[%i] = SMAXS1((v0)[%i], (v1)[%i])",     ","},
196     {0, "LERP%d(to,v0,v1,t)", "(to)[%i]=(v0)[%i]+(t)*((v1)[%i]-(v0)[%i])", ","},
197     {0, "TRACE%d(m)",         "(m)[%i][%i]",                              " +"},
198     {0, "DOT%d(v,w)",         "(v)[%i] * (w)[%i]",                        " +"},
199     {0, "NORMSQRD%d(v)",      "(v)[%i] * (v)[%i]",                        " +"},
200     {0, "DISTSQRD%d(v,w)",    "((v)[%i]-(w)[%i])*((v)[%i]-(w)[%i])",      " +"},
201     {0, "_DOTcol%d(v,m,j)",   "(v)[%i] * (m)[%i][j]",                     " +"},
202     /* following two aren't really "safe", but shouldn't be used anyway */
203     {0, "_SETcol%d(v,m,j)",   "(v)[%i] = (m)[%i][j]",                      ","},
204     {0, "_MXVcol%d(to,m,M,j)","(to)[%i][j] = _DOTcol%d((m)[%i],M,j)",      ","},
205     {0, "_DET%d(v%0..d-1,i%0..d-1)","(v0)[i%i]*%-_DET%d-1(v%1..d-1,i%~i)"," +"},
206     {1, "%XV%d(to,v%1..d-1)",     "(to)[%i] = %-%-_DET%d-1(v%1..d-1, %~i)",","},
207     /* careful! don't use v%0..d-1 for the above or the hack utility routines
208        for making "safe" macros won't be able to find the first arg. */
209 
210     /*
211      * dimension-mixing macros for which d (= the dimension of the destination)
212      * is the larger of the two dimensions.  This is deduced from
213      * the fact that the macro name contains %d-1.
214      */
215     {0, "SET%dfrom%d-1(to,from,pad)", "(to)[%i] = (from)[%i]", ",",
216                                       "(to)[%i] = (pad)"},
217     {0, "SETMAT%dfrom%d-1(to,from,pad0,pad1)",
218                         "SET%dfrom%d-1((to)[%i], (from)[%i], pad0)", ",",
219                         "FILLVEC%d-1((to)[%i], (pad0)), (to)[%i][%i] = (pad1)"},
220     {2, "M%d-1XM%d(to%d,m%d-1,m%d)",
221        "_MXVcol%d-1(to%d,m%d-1,m%d,%i), (to%d)[%d-1][%i]=(m%d)[%d-1][%i]", ","},
222     {2, "M%dXM%d-1(to%d,m%d,m%d-1)",
223   "VXM%d-1((to%d)[%i],(m%d)[%i],m%d-1), (to%d)[%i][%d-1]=(m%d)[%i][%d-1]", ","},
224 
225     /*
226      * dimension-mixing macros for which d (= the dimension of the destination)
227      * is the smaller of the two dimensions.  This is deduced from
228      * the fact that the macro name contains %d+1.
229      */
230     {1, "V%dXM%d+1(to%d,v%d,m%d+1)",
231             "(to%d)[%i] = _DOTcol%d(v%d,m%d+1,%i) + (m%d+1)[%d][%i]",   ","},
232     {1, "M%d+1XV%d(to%d,m%d+1,v%d)",
233             "(to%d)[%i] = DOT%d((m%d+1)[%i],v%d) + (m%d+1)[%i][%d]",    ","},
234 
235     /*
236      * definitions that don't get vector-expanded.
237      * This is deduced from the fact that the "sep" field is empty.
238      */
239     {0, "_DET1(v0,i0)",         "(v0)[i0]"},
240     {0, "%VXV%d(v%0..d-1)",     "_DET%d(v%0..d-1,%0..d-1)"},
241     {0, "DET%d(m)",             "%VXV%d((m)[%0..d-1])"},
242     {0, "SMODS1(a,b)",          "(((a)%%(b)+(b))%%(b))"},
243     {0, "SDIVS1(a,b)",          "(((a)-SMODS1(a,b))/(b))"},
244     {0, "SMINS1(a,b)",          "((a) < (b) ? (a) : (b))"},
245     {0, "SMAXS1(a,b)",          "((a) > (b) ? (a) : (b))"},
246 
247     /*
248      * New adjoint stuff.
249      */
250     {2, "ADJOINT%d(to,m)",      "%__ADJOINTcol%d(to,%i,m,%~i)", ","},
251     {0, "_ADJOINTcol%d(to,col,m,i%1..d-1)",
252                           "(to)[%i][col] = %-_DET%d-1((m)[i%1..d-1], %~i)",  ","},
253     {0, "__ADJOINTcol%d(to,col,m,i%1..d-1)",
254                           "(to)[%i][col] = %--_DET%d-1((m)[i%1..d-1], %~i)", ","},
255     /*
256      * Inverse-- completely special case, defined in terms of adjoint and det
257      */
258     {2, "INVERTMAT%d(to,from)"}
259 };
260 
261 #include <stdio.h>
262 #include <stdlib.h>
263 #include <assert.h>
264 #include <ctype.h>
265 #include <string.h>
266 #define MIN(a,b) ((a)<(b)?(a):(b))
267 #define MAX(a,b) ((a)>(b)?(a):(b))
268 #define numberof(sextoys)  (sizeof(sextoys) / sizeof(*(sextoys)))
269 
isprefix(const char * pre,const char * s)270 static int isprefix(const char *pre, const char *s)
271 {
272     return strncmp(pre, s, strlen(pre)) == 0;
273 }
274 
275 /*
276  * s is pointing to the last char of the prefix;
277  * to a space, ',' or a '(', taking into account nesting parens
278  */
getprefix(const char * s)279 static const char *getprefix(const char *s)
280 {
281     static char buf[100];
282     char *bufptr = buf + sizeof(buf);
283     int i, nest = 0;
284     *--bufptr = 0;
285     for (i = 0; nest || !strchr(" ,(", s[i]); --i) {
286         nest += (s[i] == ')') - (s[i] == '(');
287         *--bufptr = s[i];
288     }
289     return bufptr;
290 }
291 
292 /*
293  * s is pointing to the beginning of the suffix;
294  * get the suffix up to but not including a space, ',' or ')'.
295  */
getsuffix(const char * s)296 static const char *getsuffix(const char *s)
297 {
298     static char buf[100];
299     int i;
300     for (i = 0; !strchr(" ,)", s[i]); ++i)
301         buf[i] = s[i];
302     buf[i] = 0;
303     return buf;
304 }
305 
306 /*
307  * Print the string s with the following substitutions:
308  *      %d turns into d
309  *      %i turns into i
310  *      %- turns into "-" if i is odd, " " otherwise
311  *      %-- turns into "-" if i is even, " " otherwise
312  *      %_ turns into "_" if i is odd, " " otherwise
313  *      %-%- turns into "-" if d+i is even, " " otherwise (sorry this is stupid)
314  *      %i+1 turns into (i+1)%d etc.
315  *      %d-1 turns into d-1 etc.
316  *      %% turns into %
317  *      blah%0..d-1bleh turns into blah0bleh,blah1bleh,...,blahd-1bleh
318  *      blah%~ibleh  is same as blah%0..d-1bleh but excluding i
319  *      %XV turns into VXVX...XV with d-1 V's (or XV if d==2)
320  *      %VXV turns into VXVX...XV with d V's
321  */
printformatted_to(const char * s,const char * tochars,int d,int i)322 static void printformatted_to(const char *s, const char *tochars, int d, int i)
323 {
324     const char *prefix, *suffix;
325     int num, j, lastj;
326 
327     for (; *s && !strchr(tochars, *s); s++) {
328         if (*s == '%') {
329             ++s;
330 
331             prefix = NULL;
332             if (isdigit(*s) && !strncmp(s+1, "..d-1", 5)) {
333                 prefix = getprefix(s-2);        /* one char before the % */
334                 suffix = getsuffix(s+6);
335             } else if (!strncmp(s, "~i", 2)) {
336                 prefix = getprefix(s-2);        /* one char before the % */
337                 suffix = getsuffix(s+2);
338             }
339             if (prefix) {
340                 lastj = d-1 - (*s == '~');
341                 for (j = atoi(s); j <= lastj; ++j) {
342                     printf("%d", j + (*s == '~' && j >= i));
343                     printf("%s", suffix);
344                     if (j < lastj)
345                         printf(",%s", prefix);
346                 }
347                 s += (*s == '~' ? 2 : 6) + strlen(suffix) - 1;
348             } else {
349                 switch(*s) {
350                     case '-': case '_':
351                         if (!strncmp(s, "-%-", 3)) {
352                             printf("%c", (i+d)%2==0 ? *s : ' ');
353                             s += 2;
354                         } else if (!strncmp(s, "--", 2)) {
355                             printf("%c", i%2==0 ? *s : ' ');
356                             s++;
357                         } else {
358                             printf("%c", i%2==1 ? *s : ' ');
359                         }
360                         break;
361                     case 'i': case 'd':
362                         num = (*s == 'i' ? i : d);
363                         if (strchr("+-", s[1])) {
364                             num += (s[1] == '-' ? -1 : 1) * atoi(s+2);
365                             if (*s == 'i')
366                                 num = (num+d) % d;
367                             s += 2;
368                             /* s is now pointing to the first digit */
369                             while (isdigit(s[1]))
370                                 s++;
371                             /* s is now pointing to the last digit */
372                         }
373                         printf("%d", num);
374                         break;
375                     case 'X': case 'V':
376                         if (*s == 'X' && d == 2)
377                             printf("X");
378                         for (j = 0; j < d-2; ++j)
379                             printf("VX");
380                         if (*s == 'V')
381                             printf("V");
382                         break;
383                     case '%':
384                             printf("%%");
385                         break;
386                     default:
387                         assert(0);
388                 }
389             }
390         } else
391             putchar(*s);
392     }
393 }
394 
printformatted(const char * s,int d,int i)395 static void printformatted(const char *s, int d, int i)
396 {
397     printformatted_to(s, "", d, i);
398 }
399 
define(int d,const char * name_and_args,const char * all_but_last,const char * sep,const char * last)400 static void define(int d, const char *name_and_args, const char *all_but_last, const char *sep, const char *last)
401 {
402     int i;
403 
404     printf("#define ");
405     printformatted(name_and_args, d, 0);
406     printf("\t\\\n\t\t");
407     printf("(");
408 
409         if (sep)
410             for (i = 0; i < d-1; ++i) {         /* loop for all but last */
411                 printformatted(all_but_last, d, i);
412                 printformatted(sep, d, i);
413                 printf(" \\\n\t\t ");
414             }
415         printformatted(last, d, i);
416 
417     printf(")\n");
418 }
419 
is_substring(const char * a,const char * b)420 static int is_substring(const char *a, const char *b)
421 {
422     for (; *b; b++)
423         if (strncmp(a, b, strlen(a)) == 0)
424             return 1;
425     return 0;
426 }
427 
428 
429 /*
430  * Hack utility routines...
431  */
print_name_and_args_with_stuff_inserted(const char * name_and_arg,const char * suff,const char * arg0,int d)432 static void print_name_and_args_with_stuff_inserted(const char *name_and_arg, const char *suff, const char *arg0, int d)
433 {
434     printformatted_to(name_and_arg, "(", d, 0);
435     printformatted(suff, d, 0);
436     printf("(");
437     if (arg0) {
438         printformatted(arg0, d, 0);
439         printf(",");
440     }
441     printformatted(strchr(name_and_arg, '(' /*)*/ ) + 1, d, 0);
442 }
443 
print_name_and_args_with_first_arg_changed(const char * name_and_arg,const char * arg0,int d)444 static void print_name_and_args_with_first_arg_changed(const char *name_and_arg, const char *arg0, int d)
445 {
446     printformatted_to(name_and_arg, "(", d, 0);
447     printf("(");
448     printformatted(arg0, d, 0);
449     printformatted(strchr(name_and_arg, ','), d, 0);
450 }
451 
print_first_arg(const char * name_and_arg,int d)452 static void print_first_arg(const char *name_and_arg, int d)
453 {
454     printformatted_to(strchr(name_and_arg, '(' /*)*/ ) + 1, ",)", d, 0);
455 }
456 
print_second_arg(const char * name_and_arg,int d)457 static void print_second_arg(const char *name_and_arg, int d)
458 {
459     printformatted_to(strchr(name_and_arg, ',') + 1, ",)", d, 0);
460 }
461 
462 
463 #define MINDIM 2
464 
main(int argc,char ** argv)465 main(int argc, char **argv)
466 {
467     int i, d, maxdim;
468 
469     if (argc != 2 || ! (maxdim = atoi(argv[argc-1])))
470         fprintf(stderr, "Usage: %s [<maxdim>]\n", argv[0]), exit(1);
471 
472 
473     printf("/*\n");
474     for (i  = 0; intro[i]; ++i) {
475         printf(" *");
476         printformatted(intro[i], maxdim, 0);
477         printf("\n");
478     }
479     printf(" */\n\n");
480 
481     printf("#ifndef VEC_H\n");
482     printf("#define VEC_H %d\n", maxdim);
483     printf("\n");
484     printf("#undef TRACE2\n");
485     printf("#undef TRACE3\n");
486     printf("\n");
487     printf("#include <math.h>   /* for definition of floor() */\n");
488     printf("\n");
489 
490     for (d = MINDIM; d <= maxdim; ++d) {
491         printf("#define EXPAND%d(v) ", d);
492         for (i = 0; i < d; ++i)
493             printf("%s(v)[%d]", i==0 ? "" : ", ", i);
494         printf("\n");
495     }
496     for (d = MINDIM; d <= maxdim; ++d)
497         for (i = 0; i < numberof(defs); ++i) {
498             if (is_substring("%d-1", defs[i].name_and_args) && d-1 < MINDIM
499              || is_substring("%d+1", defs[i].name_and_args) && d+1 > maxdim)
500                 continue;
501             if (!is_substring("%d", defs[i].name_and_args) && d != MINDIM)
502                 continue;       /* don't redefine if it's the same */
503             if (!defs[i].all_but_last)
504                 continue;       /* no definition here */
505             define(d, defs[i].name_and_args,
506                       defs[i].all_but_last,
507                       defs[i].sep,
508                       defs[i].last ? defs[i].last : defs[i].all_but_last);
509         }
510     for (d = MINDIM; d <= maxdim; ++d)
511         for (i = 0; i < numberof(defs); ++i) {
512             if (is_substring("%d-1", defs[i].name_and_args) && d-1 < MINDIM
513              || is_substring("%d+1", defs[i].name_and_args) && d+1 > maxdim)
514                 continue;
515             if (!is_substring("%d", defs[i].name_and_args) && d != MINDIM)
516                 continue;       /* don't redefine if it's the same */
517             if (defs[i].safety > 0) {
518                 int t;
519                 printf("#define ");
520                 print_name_and_args_with_stuff_inserted(defs[i].name_and_args,
521                                                             "safe", "type", d);
522                 printf(" \\\n\t\t");
523                 printformatted("do {type _vec_h_temp_[%d]", d, 0);
524                 if (defs[i].safety > 1)
525                     printformatted("[%d]", d, 0);
526                 printf("; \\\n\t\t    ");
527 
528                 if (isprefix("INVERTMAT", defs[i].name_and_args)) {
529                     printf("type _vec_h_temp_invdet_;\\\n\t\t    ");
530                     printformatted("ADJOINT%d(_vec_h_temp_, ", d, 0);
531                     print_second_arg(defs[i].name_and_args, d);
532                     printf("); \\\n\t\t    ");
533                     printformatted("_vec_h_temp_invdet_ = (type)1/(type)DET%d(from); \\\n\t\t    ", d, 0);
534                     printformatted("SXM%d(", d, 0);
535                     print_first_arg(defs[i].name_and_args, d);
536                     printf(", _vec_h_temp_invdet_");
537                 } else {
538                     print_name_and_args_with_first_arg_changed(
539                             defs[i].name_and_args, "_vec_h_temp_", d);
540                     printf("; \\\n\t\t    ");
541 
542                     if (defs[i].safety > 1)
543                         printformatted("SETMAT%d(", d, 0);
544                     else
545                         printformatted("SET%d(", d, 0);
546                     print_first_arg(defs[i].name_and_args, d);
547                 }
548                 printf(", _vec_h_temp_); \\\n\t\t} while (0)\n");
549 
550                 for (t = 0; t < numberof(types); ++t) {
551                     printf("#define ");
552                     print_name_and_args_with_stuff_inserted(
553                         defs[i].name_and_args, types[t].abbr, (char *)NULL, d);
554                     printf(" ");
555                     print_name_and_args_with_stuff_inserted(
556                         defs[i].name_and_args, "safe", types[t].full, d);
557                     printf("\n");
558                 }
559             }
560         }
561     printf("#endif /* VEC_H */\n");
562 
563     return 0;
564 }
565 
566