update Releasing with changes discovered in 1.8.3 release process
[fw/altos] / src / scheme / ao_scheme_make_const.c
1 /*
2  * Copyright © 2016 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 #include "ao_scheme.h"
16 #include <stdlib.h>
17 #include <ctype.h>
18 #include <unistd.h>
19 #include <getopt.h>
20
21 static struct ao_scheme_builtin *
22 ao_scheme_make_builtin(enum ao_scheme_builtin_id func, int args) {
23         struct ao_scheme_builtin *b = ao_scheme_alloc(sizeof (struct ao_scheme_builtin));
24
25         b->type = AO_SCHEME_BUILTIN;
26         b->func = func;
27         b->args = args;
28         return b;
29 }
30
31 struct builtin_func {
32         char    *name;
33         int     args;
34         enum ao_scheme_builtin_id       func;
35 };
36
37 #define AO_SCHEME_BUILTIN_CONSTS
38 #include "ao_scheme_builtin.h"
39
40 #define N_FUNC (sizeof funcs / sizeof funcs[0])
41
42 struct ao_scheme_frame  *globals;
43
44 static int
45 is_atom(int offset)
46 {
47         struct ao_scheme_atom *a;
48
49         for (a = ao_scheme_atoms; a; a = ao_scheme_poly_atom(a->next))
50                 if (((uint8_t *) a->name - ao_scheme_const) == offset)
51                         return strlen(a->name);
52         return 0;
53 }
54
55 #define AO_FEC_CRC_INIT 0xffff
56
57 static inline uint16_t
58 ao_fec_crc_byte(uint8_t byte, uint16_t crc)
59 {
60         uint8_t bit;
61
62         for (bit = 0; bit < 8; bit++) {
63                 if (((crc & 0x8000) >> 8) ^ (byte & 0x80))
64                         crc = (crc << 1) ^ 0x8005;
65                 else
66                         crc = (crc << 1);
67                 byte <<= 1;
68         }
69         return crc;
70 }
71
72 uint16_t
73 ao_fec_crc(const uint8_t *bytes, uint8_t len)
74 {
75         uint16_t        crc = AO_FEC_CRC_INIT;
76
77         while (len--)
78                 crc = ao_fec_crc_byte(*bytes++, crc);
79         return crc;
80 }
81
82 struct ao_scheme_macro_stack {
83         struct ao_scheme_macro_stack *next;
84         ao_poly p;
85 };
86
87 struct ao_scheme_macro_stack *macro_stack;
88
89 int
90 ao_scheme_macro_push(ao_poly p)
91 {
92         struct ao_scheme_macro_stack *m = macro_stack;
93
94         while (m) {
95                 if (m->p == p)
96                         return 1;
97                 m = m->next;
98         }
99         m = malloc (sizeof (struct ao_scheme_macro_stack));
100         m->p = p;
101         m->next = macro_stack;
102         macro_stack = m;
103         return 0;
104 }
105
106 void
107 ao_scheme_macro_pop(void)
108 {
109         struct ao_scheme_macro_stack *m = macro_stack;
110
111         macro_stack = m->next;
112         free(m);
113 }
114
115 #define DBG_MACRO 0
116 #if DBG_MACRO
117 int macro_scan_depth;
118
119 void indent(void)
120 {
121         int i;
122         for (i = 0; i < macro_scan_depth; i++)
123                 printf("  ");
124 }
125 #define MACRO_DEBUG(a)  a
126 #else
127 #define MACRO_DEBUG(a)
128 #endif
129
130 ao_poly
131 ao_has_macro(ao_poly p);
132
133 ao_poly
134 ao_macro_test_get(ao_poly atom)
135 {
136         ao_poly *ref = ao_scheme_atom_ref(atom, NULL);
137         if (ref)
138                 return *ref;
139         return AO_SCHEME_NIL;
140 }
141
142 ao_poly
143 ao_is_macro(ao_poly p)
144 {
145         struct ao_scheme_builtin        *builtin;
146         struct ao_scheme_lambda *lambda;
147         ao_poly ret;
148
149         MACRO_DEBUG(indent(); printf ("is macro "); ao_scheme_poly_write(p); printf("\n"); ++macro_scan_depth);
150         switch (ao_scheme_poly_type(p)) {
151         case AO_SCHEME_ATOM:
152                 if (ao_scheme_macro_push(p))
153                         ret = AO_SCHEME_NIL;
154                 else {
155                         if (ao_is_macro(ao_macro_test_get(p)))
156                                 ret = p;
157                         else
158                                 ret = AO_SCHEME_NIL;
159                         ao_scheme_macro_pop();
160                 }
161                 break;
162         case AO_SCHEME_CONS:
163                 ret = ao_has_macro(p);
164                 break;
165         case AO_SCHEME_BUILTIN:
166                 builtin = ao_scheme_poly_builtin(p);
167                 if ((builtin->args & AO_SCHEME_FUNC_MASK) == AO_SCHEME_FUNC_MACRO)
168                         ret = p;
169                 else
170                         ret = 0;
171                 break;
172
173         case AO_SCHEME_LAMBDA:
174                 lambda = ao_scheme_poly_lambda(p);
175                 if (lambda->args == AO_SCHEME_FUNC_MACRO)
176                         ret = p;
177                 else
178                         ret = ao_has_macro(lambda->code);
179                 break;
180         default:
181                 ret = AO_SCHEME_NIL;
182                 break;
183         }
184         MACRO_DEBUG(--macro_scan_depth; indent(); printf ("... "); ao_scheme_poly_write(ret); printf("\n"));
185         return ret;
186 }
187
188 ao_poly
189 ao_has_macro(ao_poly p)
190 {
191         struct ao_scheme_cons   *cons;
192         struct ao_scheme_lambda *lambda;
193         ao_poly                 m;
194         ao_poly                 list;
195
196         if (p == AO_SCHEME_NIL)
197                 return AO_SCHEME_NIL;
198
199         MACRO_DEBUG(indent(); printf("has macro "); ao_scheme_poly_write(p); printf("\n"); ++macro_scan_depth);
200         switch (ao_scheme_poly_type(p)) {
201         case AO_SCHEME_LAMBDA:
202                 lambda = ao_scheme_poly_lambda(p);
203                 p = ao_has_macro(lambda->code);
204                 break;
205         case AO_SCHEME_CONS:
206                 cons = ao_scheme_poly_cons(p);
207                 if ((p = ao_is_macro(cons->car)))
208                         break;
209
210                 list = cons->cdr;
211                 p = AO_SCHEME_NIL;
212                 while (list != AO_SCHEME_NIL && ao_scheme_poly_type(list) == AO_SCHEME_CONS) {
213                         cons = ao_scheme_poly_cons(list);
214                         m = ao_has_macro(cons->car);
215                         if (m) {
216                                 p = m;
217                                 break;
218                         }
219                         list = cons->cdr;
220                 }
221                 break;
222
223         default:
224                 p = AO_SCHEME_NIL;
225                 break;
226         }
227         MACRO_DEBUG(--macro_scan_depth; indent(); printf("... "); ao_scheme_poly_write(p); printf("\n"));
228         return p;
229 }
230
231 int
232 ao_scheme_read_eval_abort(void)
233 {
234         ao_poly in, out = AO_SCHEME_NIL;
235         for(;;) {
236                 in = ao_scheme_read();
237                 if (in == _ao_scheme_atom_eof)
238                         break;
239                 out = ao_scheme_eval(in);
240                 if (ao_scheme_exception)
241                         return 0;
242                 ao_scheme_poly_write(out);
243                 putchar ('\n');
244         }
245         return 1;
246 }
247
248 static FILE     *in;
249 static FILE     *out;
250
251 int
252 ao_scheme_getc(void)
253 {
254         return getc(in);
255 }
256
257 static const struct option options[] = {
258         { .name = "out", .has_arg = 1, .val = 'o' },
259         { 0, 0, 0, 0 }
260 };
261
262 static void usage(char *program)
263 {
264         fprintf(stderr, "usage: %s [--out=<output>] [input]\n", program);
265         exit(1);
266 }
267
268 int
269 main(int argc, char **argv)
270 {
271         int     f, o;
272         ao_poly val;
273         struct ao_scheme_atom   *a;
274         struct ao_scheme_builtin        *b;
275         int     in_atom = 0;
276         char    *out_name = NULL;
277         int     c;
278         enum ao_scheme_builtin_id       prev_func;
279
280         in = stdin;
281         out = stdout;
282
283         while ((c = getopt_long(argc, argv, "o:", options, NULL)) != -1) {
284                 switch (c) {
285                 case 'o':
286                         out_name = optarg;
287                         break;
288                 default:
289                         usage(argv[0]);
290                         break;
291                 }
292         }
293
294         ao_scheme_frame_init();
295
296         /* Boolean values #f and #t */
297         ao_scheme_bool_get(0);
298         ao_scheme_bool_get(1);
299
300         prev_func = _builtin_last;
301         for (f = 0; f < (int) N_FUNC; f++) {
302                 if (funcs[f].func != prev_func)
303                         b = ao_scheme_make_builtin(funcs[f].func, funcs[f].args);
304                 a = ao_scheme_atom_intern(funcs[f].name);
305                 ao_scheme_atom_def(ao_scheme_atom_poly(a),
306                                  ao_scheme_builtin_poly(b));
307         }
308
309         /* end of file value */
310         a = ao_scheme_atom_intern("eof");
311         ao_scheme_atom_def(ao_scheme_atom_poly(a),
312                          ao_scheme_atom_poly(a));
313
314         /* 'else' */
315         a = ao_scheme_atom_intern("else");
316
317         if (argv[optind]){
318                 in = fopen(argv[optind], "r");
319                 if (!in) {
320                         perror(argv[optind]);
321                         exit(1);
322                 }
323         }
324         if (!ao_scheme_read_eval_abort()) {
325                 fprintf(stderr, "eval failed\n");
326                 exit(1);
327         }
328
329         /* Reduce to referenced values */
330         ao_scheme_collect(AO_SCHEME_COLLECT_FULL);
331
332         for (f = 0; f < ao_scheme_frame_global->num; f++) {
333                 struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(ao_scheme_frame_global->vals);
334                 val = ao_has_macro(vals->vals[f].val);
335                 if (val != AO_SCHEME_NIL) {
336                         printf("error: function %s contains unresolved macro: ",
337                                ao_scheme_poly_atom(vals->vals[f].atom)->name);
338                         ao_scheme_poly_write(val);
339                         printf("\n");
340                         exit(1);
341                 }
342         }
343
344         if (out_name) {
345                 out = fopen(out_name, "w");
346                 if (!out) {
347                         perror(out_name);
348                         exit(1);
349                 }
350         }
351
352         fprintf(out, "/* Generated file, do not edit */\n\n");
353
354         fprintf(out, "#define AO_SCHEME_POOL_CONST %d\n", ao_scheme_top);
355         fprintf(out, "extern const uint8_t ao_scheme_const[AO_SCHEME_POOL_CONST] __attribute__((aligned(4)));\n");
356         fprintf(out, "#define ao_builtin_atoms 0x%04x\n", ao_scheme_atom_poly(ao_scheme_atoms));
357         fprintf(out, "#define ao_builtin_frame 0x%04x\n", ao_scheme_frame_poly(ao_scheme_frame_global));
358         fprintf(out, "#define ao_scheme_const_checksum ((uint16_t) 0x%04x)\n", ao_fec_crc(ao_scheme_const, ao_scheme_top));
359
360         fprintf(out, "#define _ao_scheme_bool_false 0x%04x\n", ao_scheme_bool_poly(ao_scheme_false));
361         fprintf(out, "#define _ao_scheme_bool_true 0x%04x\n", ao_scheme_bool_poly(ao_scheme_true));
362
363         for (a = ao_scheme_atoms; a; a = ao_scheme_poly_atom(a->next)) {
364                 char    *n = a->name, c;
365                 fprintf(out, "#define _ao_scheme_atom_");
366                 while ((c = *n++)) {
367                         if (isalnum(c))
368                                 fprintf(out, "%c", c);
369                         else
370                                 fprintf(out, "%02x", c);
371                 }
372                 fprintf(out, "  0x%04x\n", ao_scheme_atom_poly(a));
373         }
374         fprintf(out, "#ifdef AO_SCHEME_CONST_BITS\n");
375         fprintf(out, "const uint8_t ao_scheme_const[AO_SCHEME_POOL_CONST] __attribute((aligned(4))) = {");
376         for (o = 0; o < ao_scheme_top; o++) {
377                 uint8_t c;
378                 if ((o & 0xf) == 0)
379                         fprintf(out, "\n\t");
380                 else
381                         fprintf(out, " ");
382                 c = ao_scheme_const[o];
383                 if (!in_atom)
384                         in_atom = is_atom(o);
385                 if (in_atom) {
386                         fprintf(out, " '%c',", c);
387                         in_atom--;
388                 } else {
389                         fprintf(out, "0x%02x,", c);
390                 }
391         }
392         fprintf(out, "\n};\n");
393         fprintf(out, "#endif /* AO_SCHEME_CONST_BITS */\n");
394         exit(0);
395 }