vpp_lite: add cpu pinning support (VPP-467)
[vpp.git] / vppapigen / node.c
1 /* 
2  *------------------------------------------------------------------
3  * node.c - the api generator's semantic back-end
4  *
5  * Copyright (c) 2004-2009 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <time.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <vppinfra/vec.h>
27 #include <vppinfra/hash.h>
28
29 #include "lex.h"
30 #include "node.h"
31
32 #define YYSTYPE void *
33
34 FILE *ofp;
35 FILE *pythonfp;
36 time_t starttime;
37 char *vlib_app_name;
38 char *input_filename;
39 node_vft_t *the_vft[NODE_N_TYPES];
40 static int indent;
41 static int dont_output_version;
42 int dump_tree;
43 static char *fixed_name;
44 static char tmpbuf [MAXNAME];
45 static char *current_def_name;
46 static char *current_union_name;
47 static char *current_type_fmt;
48 static char *current_type_cast;
49 static char current_id;
50 static char current_is_complex;
51 static char *current_endianfun;
52 static char *current_type_name;
53
54 void indent_me(FILE *ofp)
55 {
56     int i;
57
58     for (i = 0; i < indent; i++)
59         putc(' ', ofp);
60 }
61
62 char *uppercase (char *s)
63 {
64     char *cp;
65
66     cp = tmpbuf;
67
68     while (*s && (cp < tmpbuf + (sizeof(tmpbuf)-1))) {
69         if (*s >= 'a' && *s <= 'z')
70             *cp++ = *s++ - ('a' - 'A');
71         else
72             *cp++ = *s++;
73     }
74     *cp = 0;
75     return(tmpbuf);
76 }
77
78 char *lowercase (char *s)
79 {
80     char *cp;
81
82     cp = tmpbuf;
83
84     while (*s && (cp < tmpbuf + (sizeof(tmpbuf)-1))) {
85         if (*s >= 'A' && *s <= 'Z')
86             *cp++ = *s++ + ('a' - 'A');
87         else
88             *cp++ = *s++;
89     }
90     *cp = 0;
91     return(tmpbuf);
92 }
93
94 void primtype_recursive_print(node_t *this, i8 *fmt)
95 {
96     fputs((char *)fmt, stdout);
97
98     if (this->deeper) {
99         node_vft_t *vftp = the_vft[this->deeper->type];
100         vftp->print(this->deeper);
101     }
102 }
103
104 void primtype_recursive_generate(node_t *this, enum passid which, FILE *ofp,
105                                  i8 *type_name, i8 *type_fmt, i8 *type_cast)
106 {
107     node_vft_t *vftp;
108
109     current_type_name = (char *)type_name;
110     current_type_cast = (char *)type_cast;
111
112     switch(which) {
113     case TYPEDEF_PASS:
114         fputs((char *)type_name, ofp);
115         fputs(" ", ofp);
116         break;
117
118     case PRINTFUN_PASS:
119         current_type_fmt = (char *)type_fmt;
120         break;
121
122     case ENDIANFUN_PASS:
123         vftp = the_vft[this->type];
124         current_endianfun = vftp->endian_converter;
125         break;
126
127     case PYTHON_PASS:
128         fputs("('", pythonfp);
129         fputs((char *)type_name, pythonfp);
130         fputs("', ", pythonfp);
131         break;
132
133     default:
134         fprintf(stderr, "primtype_recursive_generate: unimp pass %d\n", which);
135         break;
136     }
137
138     if (this->deeper) {
139         vftp = the_vft[this->deeper->type];
140         vftp->generate(this->deeper, which, ofp);
141     }
142 }
143
144 void node_illegal_print (node_t *this)
145 {
146     fprintf(stderr, "node_illegal_print called\n");
147     exit(0);
148 }
149
150 void node_illegal_generate (node_t *this, enum passid notused, FILE *ofp)
151 {
152     fprintf(stderr, "node_illegal_generate called\n");
153     exit(0);
154 }
155
156 node_vft_t node_illegal_vft = {
157     node_illegal_print,
158     node_illegal_generate,
159     "illegal"
160 };
161
162 void node_u8_print (node_t *this)
163 {
164     primtype_recursive_print(this, "u8 ");
165 }
166
167 void node_u8_generate (node_t *this, enum passid which, FILE *ofp)
168 {
169     primtype_recursive_generate(this, which, ofp, "u8", "%u", "(unsigned)");
170 }
171
172 node_vft_t node_u8_vft = {
173     node_u8_print,
174     node_u8_generate,
175     NULL
176 };
177
178 void node_u16_print (node_t *this)
179 {
180     primtype_recursive_print(this, "u16 ");
181 }
182
183 void node_u16_generate (node_t *this, enum passid which, FILE *ofp)
184 {
185     primtype_recursive_generate(this, which, ofp, "u16", "%u", "(unsigned)");
186 }
187
188 node_vft_t node_u16_vft = {
189     node_u16_print,
190     node_u16_generate,
191     "clib_net_to_host_u16"
192 };
193
194 void node_u32_print (node_t *this)
195 {
196     primtype_recursive_print(this, "u32 ");
197 }
198
199 void node_u32_generate (node_t *this, enum passid which, FILE *ofp)
200 {
201     primtype_recursive_generate(this, which, ofp, "u32", "%u", "(unsigned)");
202 }
203
204 node_vft_t node_u32_vft = {
205     node_u32_print,
206     node_u32_generate,
207     "clib_net_to_host_u32",
208 };
209
210 void node_u64_print (node_t *this)
211 {
212     primtype_recursive_print(this, "u64 ");
213 }
214
215 void node_u64_generate (node_t *this, enum passid which, FILE *ofp)
216 {
217     primtype_recursive_generate(this, which, ofp, "u64", "%llu", 
218                                 "(long long)");
219 }
220
221 node_vft_t node_u64_vft = {
222     node_u64_print,
223     node_u64_generate,
224     "clib_net_to_host_u64"
225 };
226
227 void node_i8_print (node_t *this)
228 {
229     primtype_recursive_print(this, "i8 ");
230 }
231
232 void node_i8_generate (node_t *this, enum passid which, FILE *ofp)
233 {
234     primtype_recursive_generate(this, which, ofp, "i8", "%d", "(int)");
235 }
236
237 node_vft_t node_i8_vft = {
238     node_i8_print,
239     node_i8_generate,
240     ""
241 };
242
243 void node_i16_print (node_t *this)
244 {
245     primtype_recursive_print(this, "i16 ");
246 }
247
248 void node_i16_generate (node_t *this, enum passid which, FILE *ofp)
249 {
250     primtype_recursive_generate(this, which, ofp, "i16", "%d", "(int)");
251 }
252
253 node_vft_t node_i16_vft = {
254     node_i16_print,
255     node_i16_generate,
256     "clib_net_to_host_u16"
257 };
258
259 void node_i32_print (node_t *this)
260 {
261     primtype_recursive_print(this, "i32 ");
262 }
263
264 void node_i32_generate (node_t *this, enum passid which, FILE *ofp)
265 {
266     primtype_recursive_generate(this, which, ofp, "i32", "%ld", "(long)");
267 }
268
269 node_vft_t node_i32_vft = {
270     node_i32_print,
271     node_i32_generate,
272     "clib_net_to_host_u32"
273 };
274
275 void node_i64_print (node_t *this)
276 {
277     primtype_recursive_print(this, "i64 ");
278 }
279
280 void node_i64_generate (node_t *this, enum passid which, FILE *ofp)
281 {
282     primtype_recursive_generate(this, which, ofp, "i64", "%lld", 
283                                 "(long long)");
284 }
285
286 node_vft_t node_i64_vft = {
287     node_i64_print,
288     node_i64_generate,
289     "clib_net_to_host_u64"
290 };
291
292 void node_f64_print (node_t *this)
293 {
294     primtype_recursive_print(this, "f64 ");
295 }
296
297 void node_f64_generate (node_t *this, enum passid which, FILE *ofp)
298 {
299     primtype_recursive_generate(this, which, ofp, "f64", "%.2f", 
300                                 "(double)");
301 }
302
303 node_vft_t node_f64_vft = {
304     node_f64_print,
305     node_f64_generate,
306     " ",                        /* FP numbers are sent in host byte order */
307 };
308
309
310 void node_packed_print (node_t *this)
311 {
312     primtype_recursive_print (this, "packed ");
313 }
314
315 void node_packed_generate (node_t *this, enum passid which, FILE *ofp)
316 {
317     primtype_recursive_generate(this, which, ofp, "PACKED", "", "");
318 }
319
320 node_vft_t node_packed_vft = {
321     node_packed_print,
322     node_packed_generate,
323     0,
324 };
325
326 void node_define_print (node_t *this)
327 {
328     fprintf(stdout, "define %s {\n", CDATA0);
329     if (this->deeper) {
330         node_vft_t *vftp = the_vft[this->deeper->type];
331         fprintf(stdout, "    ");
332         vftp->print(this->deeper);
333     }
334     fprintf(stdout, "};\n");
335 }
336
337 void node_define_generate (node_t *this, enum passid which, FILE *fp)
338 {
339     node_t *child, *save_child;
340
341     switch(which) {
342     case TYPEDEF_PASS:
343         fprintf(fp, "typedef VL_API_PACKED(struct _vl_api_%s {\n", CDATA0);
344         child = this->deeper;
345         indent += 4;
346         while (child) {
347             node_vft_t *vftp = the_vft[child->type];
348             indent_me(fp);
349             vftp->generate(child, which, fp);
350             child = child->peer;
351         }
352         indent -= 4;
353         fprintf(fp, "}) vl_api_%s_t;\n\n", CDATA0);
354         break;
355
356     case ENDIANFUN_PASS:
357     case PRINTFUN_PASS:
358         child = this->deeper;
359         while (child) {
360             node_vft_t *vftp = the_vft[child->type];
361             vftp->generate(child, which, fp);
362             child = child->peer;
363         }
364         break;
365
366     case PYTHON_PASS:
367       fprintf(fp, "('%s',\n", CDATA0);
368         child = this->deeper;
369         indent += 4;
370         while (child) {
371             node_vft_t *vftp = the_vft[child->type];
372             indent_me(fp);
373             vftp->generate(child, which, fp);
374             child = child->peer;
375         }
376         indent -= 4;
377         fprintf(fp, "),\n\n");
378         break;
379
380     default:
381         fprintf(stderr, "node_define_generate: unimp pass %d\n", which);
382         break;
383     }
384 }
385
386 node_vft_t node_define_vft = {
387     node_define_print,
388     node_define_generate,
389     0,
390 };
391
392 void node_union_print (node_t *this)
393 {
394     primtype_recursive_print (this, "union ");
395 }
396
397 void node_union_generate (node_t *this, enum passid which, FILE *fp)
398 {
399     node_t *child;
400     node_t *uelem;
401     int case_id=1;
402
403     switch(which) {
404     case TYPEDEF_PASS:
405         fprintf(fp, "u8 _%s_which;\n", CDATA0);
406         indent_me(fp);
407         fprintf(fp, "union _%s {\n", CDATA0);
408         child = this->deeper;
409         indent += 4;
410     
411         while (child) {
412             node_vft_t *vftp = the_vft[child->type];
413             indent_me(fp);
414             vftp->generate(child, which, fp);
415             child = child->peer;
416         }
417         indent -= 4;
418         indent_me(fp);
419         fprintf(fp, "} %s;\n", CDATA0);
420         break;
421
422     case PRINTFUN_PASS:
423     case ENDIANFUN_PASS:
424         uelem = this->deeper;
425         
426         indent_me(fp);
427         fprintf(fp, "switch(a->_%s_which) {\n",
428                 CDATA0);
429         indent += 4;
430         current_union_name = CDATA0;
431
432         /* Walk the list of objects in this union */
433         while (uelem) {
434             node_vft_t *vftp = the_vft[uelem->type];
435             indent -= 4;
436             indent_me(fp);
437             fprintf(fp, "case %d:\n", case_id);
438             case_id++;
439             indent += 4;
440             /* Drill down on each element */
441             vftp->generate(uelem, which, fp);
442             indent_me(fp);
443             fprintf(fp, "break;\n");
444             uelem = uelem->peer;
445         }
446         current_union_name = 0;
447         indent -= 4;
448         indent_me(fp);
449         fprintf(fp, "default:\n");
450         indent += 4;
451         indent_me(fp);                 
452         if (which == PRINTFUN_PASS) {
453             fprintf(fp, 
454                     "vl_print(handle, \"WARNING: _%s_which not set.\\n\");\n",
455                     CDATA0);
456         }
457         indent_me(fp);
458         fprintf(fp, "break;\n");
459         indent -= 4;
460         indent_me(fp);
461         fprintf(fp, "}\n");
462         break;
463
464     default:
465         fprintf(stderr, "node_union_generate: unimp pass %d\n", which);
466         break;
467     }
468 }
469
470
471 node_vft_t node_union_vft = {
472     node_union_print,
473     node_union_generate,
474     0,
475 };
476
477 void node_scalar_print (node_t *this)
478 {
479     fprintf(stdout, "%s", CDATA0);
480     primtype_recursive_print (this, "");
481 }
482
483 void node_scalar_generate (node_t *this, enum passid which, FILE *fp)
484 {
485     char *union_prefix = "";
486
487     if (current_union_name) {
488         sprintf(tmpbuf, "%s.", current_union_name);
489         union_prefix = tmpbuf;
490     }
491
492     switch(which) {
493     case TYPEDEF_PASS:
494         fprintf(fp, "%s;\n", CDATA0);
495         break;
496
497     case PRINTFUN_PASS:
498         indent_me(fp);
499         if (current_is_complex) {
500             fprintf(fp, "vl_api_%s_t_print(a->%s%s, handle);\n", 
501                     current_type_name, union_prefix, CDATA0);
502         } else {
503             if (!strcmp(current_type_fmt, "uword")) {
504                 fprintf(fp, 
505            "vl_print(handle, \"%s%s: \" _uword_fmt \"\\n\", %s a->%s%s);\n", 
506                         union_prefix, CDATA0, "(_uword_cast)",
507                         union_prefix, CDATA0);
508             } else {
509                 fprintf(fp, 
510                         "vl_print(handle, \"%s%s: %s\\n\", %s a->%s%s);\n", 
511                         union_prefix, CDATA0, 
512                         current_type_fmt, current_type_cast,
513                         union_prefix, CDATA0);
514             }
515         }
516         break;
517
518     case ENDIANFUN_PASS:
519         indent_me(fp);
520         if (current_is_complex) {
521             fprintf(fp, "vl_api%s_t_endian(a->%s%s);\n", 
522                     current_type_name, union_prefix, CDATA0);
523         } else {
524             /* Current_endianfun == NULL means e.g. it's a u8... */
525             if (current_endianfun) {
526                 fprintf(fp, "a->%s%s = %s(a->%s%s);\n", union_prefix,
527                         CDATA0, current_endianfun, 
528                         union_prefix, CDATA0);
529             } else {
530                 fprintf(fp, "/* a->%s%s = a->%s%s (no-op) */\n",
531                         union_prefix, CDATA0, 
532                         union_prefix, CDATA0);
533             }
534         }
535         break;
536     case PYTHON_PASS:
537         fprintf(fp, "'%s'),\n", CDATA0);
538         break;
539
540     default:
541         fprintf(stderr, "node_scalar_generate: unimp pass %d\n", which);
542     }
543     if (this->deeper) {
544         fprintf(stderr, "broken recursion in node_scalar_generate\n");
545     }
546 }
547
548
549 node_vft_t node_scalar_vft = {
550     node_scalar_print,
551     node_scalar_generate,
552     0,
553 };
554
555 void node_vector_print (node_t *this)
556 {
557     primtype_recursive_print (this, "vector ");
558 }
559
560 void node_vector_generate (node_t *this, enum passid which, FILE *fp)
561 {
562     char *union_prefix = "";
563
564     if (current_union_name) {
565         sprintf(tmpbuf, "%s.", current_union_name);
566         union_prefix = tmpbuf;
567     }
568
569     switch(which) {
570     case TYPEDEF_PASS:
571         fprintf(fp, "%s[%d];\n", CDATA0, IDATA1);
572         break;
573
574     case PRINTFUN_PASS:
575         /* Don't bother about "u8 data [0];" et al. */
576         if (IDATA1 == 0)
577             break;
578
579         indent_me(fp);
580         fprintf(fp, "{\n");
581         indent += 4;
582         indent_me(fp);
583         fprintf(fp, "int _i;\n");
584         indent_me(fp);
585         fprintf(fp, "for (_i = 0; _i < %d; _i++) {\n", 
586                 IDATA1);
587         indent += 4;
588         indent_me(fp);
589         if (current_is_complex) {
590             fprintf(fp, "vl_print(handle, \"%s%s[%%d]: ",
591                     union_prefix, CDATA0);
592             fprintf(fp, 
593                     "vl_print_%s (handle, a->%s%s[_i]);\n", 
594                     CDATA0, union_prefix, CDATA0);
595         } else {
596             fprintf(fp, 
597          "vl_print(handle, \"%s%s[%%d]: %s\\n\", _i, a->%s%s[_i]);\n",
598                     union_prefix, CDATA0, 
599                     current_type_fmt, 
600                     union_prefix, CDATA0);
601         }
602         indent -= 4;
603         indent_me(fp);
604         fprintf(fp, "}\n");
605         indent -= 4;
606         indent_me(fp);
607         fprintf(fp, "}\n");
608         break;
609
610     case ENDIANFUN_PASS:
611         /* Don't bother about "u8 data [0];" et al. */
612         if (IDATA1 == 0)
613             break;
614         /* If this is a simple endian swap, but the endian swap method is a no-op,
615          * then indicate this is a no-op in a comment.
616          */
617         if (!current_is_complex && current_endianfun == NULL) {
618             indent_me(fp);
619             fprintf(fp, "/* a->%s%s[0..%d] = a->%s%s[0..%d] (no-op) */\n",
620                     union_prefix, CDATA0, IDATA1 - 1,
621                     union_prefix, CDATA0, IDATA1 - 1);
622             break;
623         }
624
625         indent_me(fp);
626         fprintf(fp, "{\n");
627         indent += 4;
628         indent_me(fp);
629         fprintf(fp, "int _i;\n");
630         indent_me(fp);
631         fprintf(fp, "for (_i = 0; _i < %d; _i++) {\n", 
632                 IDATA1);
633         indent += 4;
634         indent_me(fp);
635         if (current_is_complex) {
636             fprintf(fp, 
637                     "vl_api_%s_t_endian (a->%s%s[_i]);\n", 
638                     current_type_name, union_prefix, CDATA0);
639         } else {
640             fprintf(fp, 
641                     "a->%s%s[_i] = %s(a->%s%s[_i]);\n", 
642                     union_prefix, CDATA0, 
643                     current_endianfun, 
644                     union_prefix, CDATA0);
645         }
646         indent -= 4;
647         indent_me(fp);
648         fprintf(fp, "}\n");
649         indent -= 4;
650         indent_me(fp);
651         fprintf(fp, "}\n");
652         break;
653     case PYTHON_PASS:
654         if (CDATA2 != 0) { // variable length vector
655             fprintf(fp, "'%s', '%d', '%s'),\n", CDATA0, IDATA1, CDATA2);
656         } else {
657             fprintf(fp, "'%s', '%d'),\n", CDATA0, IDATA1);
658         }
659         break;
660
661     default:
662         fprintf(stderr, "node_vector_generate: unimp pass %d\n", which);
663     }
664     if (this->deeper) {
665         fprintf(stderr, "broken recursion in node_vector_generate\n");
666     }
667 }
668
669 node_vft_t node_vector_vft = {
670     node_vector_print,
671     node_vector_generate,
672     0,
673 };
674
675 void node_complex_print (node_t *this)
676 {
677     primtype_recursive_print (this, "complex ");
678 }
679
680 void node_complex_generate (node_t *this, enum passid which, FILE *fp)
681 {
682     node_t *deeper;
683     node_vft_t *vftp;
684     char *member_name = "broken!";
685     char *union_prefix = "";
686
687     if (current_union_name) {
688         sprintf(tmpbuf, "%s.", current_union_name);
689         union_prefix = tmpbuf;
690     }
691
692     current_is_complex++;
693     
694     switch(which) {
695     case TYPEDEF_PASS:
696         fprintf(fp, "%s ", CDATA0);
697         deeper = this->deeper;
698         if (deeper) {
699             vftp = the_vft[deeper->type];
700             vftp->generate(deeper, which, fp);
701         }
702         break;
703
704     case PRINTFUN_PASS:
705         deeper = this->deeper;
706         while (deeper) {
707             if (deeper->type == NODE_SCALAR ||
708                 deeper->type == NODE_VECTOR) {
709                 member_name = deeper->data[0];
710                 break;
711             }
712             deeper = deeper->deeper;
713         }
714         indent_me(fp);
715         fprintf(fp, "vl_print(handle, \"%s%s ----- \\n\");\n", 
716                 union_prefix, member_name);
717         indent_me(fp);
718         fprintf(fp, "%s_print(&a->%s%s, handle);\n", 
719                 CDATA0, union_prefix, member_name);
720         indent_me(fp);
721         fprintf(fp, "vl_print(handle, \"%s%s ----- END \\n\");\n", 
722                 union_prefix, member_name);
723         break;
724
725     case ENDIANFUN_PASS:
726         deeper = this->deeper;
727         while (deeper) {
728             if (deeper->type == NODE_SCALAR ||
729                 deeper->type == NODE_VECTOR) {
730                 member_name = deeper->data[0];
731                 break;
732             }
733             deeper = deeper->deeper;
734         }
735
736         indent_me(fp);
737         fprintf(fp, "%s_endian(&a->%s%s);\n", 
738                 CDATA0, union_prefix, member_name);
739         break;
740     case PYTHON_PASS:
741         fprintf(fp, "('%s',", CDATA0);
742         deeper = this->deeper;
743         if (deeper) {
744             vftp = the_vft[deeper->type];
745             vftp->generate(deeper, which, fp);
746         }
747         break;
748
749     default:
750         fprintf(stderr, "node_complex_generate unimp pass %d...\n", which);
751         break;
752     }
753     current_is_complex--;
754 }
755
756 node_vft_t node_complex_vft = {
757     node_complex_print,
758     node_complex_generate,
759     0,
760 };
761
762 void node_noversion_print (node_t *this)
763 {
764     primtype_recursive_print (this, "noversion ");
765 }
766
767 void node_noversion_generate (node_t *this, enum passid which, FILE *ofp)
768 {
769     fprintf(stderr, "node_noversion_generate called...\n");
770 }
771
772 node_vft_t node_noversion_vft = {
773     node_noversion_print,
774     node_noversion_generate,
775     0,
776 };
777
778 void node_uword_print (node_t *this)
779 {
780     primtype_recursive_print(this, "uword ");
781 }
782
783 void node_uword_generate (node_t *this, enum passid which, FILE *ofp)
784 {
785     primtype_recursive_generate(this, which, ofp, "uword", "uword", "");
786 }
787
788 node_vft_t node_uword_vft = {
789     node_uword_print,
790     node_uword_generate,
791     "clib_net_to_host_uword",
792 };
793
794 node_vft_t *the_vft[NODE_N_TYPES] = {
795     &node_illegal_vft,
796     &node_u8_vft,
797     &node_u16_vft,
798     &node_u32_vft,
799     &node_u64_vft,
800     &node_i8_vft,
801     &node_i16_vft,
802     &node_i32_vft,
803     &node_i64_vft,
804     &node_f64_vft,
805     &node_packed_vft,
806     &node_define_vft,
807     &node_union_vft,
808     &node_scalar_vft,
809     &node_vector_vft,
810     &node_complex_vft,
811     &node_noversion_vft,
812     &node_uword_vft,
813 };
814
815 void *make_node (enum node_subclass type)
816 {
817     node_t *rv;
818
819     rv = (node_t *) malloc (sizeof (*rv));
820     if (rv == 0) {
821         fprintf (stderr, "fatal: make_node out of memory\n");
822         exit (1);
823     }
824     bzero (rv, sizeof (*rv));
825     rv->type = type;
826     return ((void *) rv);
827 }
828
829 YYSTYPE deeper (YYSTYPE arg1, YYSTYPE arg2)
830 {
831     node_t *np1 = (node_t *) arg1;
832     node_t *np2 = (node_t *) arg2;
833     node_t *hook_point;
834     
835     hook_point = np1;
836
837     while (hook_point->deeper)
838         hook_point = hook_point->deeper;
839
840     hook_point->deeper = np2;
841     return (arg1);
842 }
843
844 YYSTYPE addpeer (YYSTYPE arg1, YYSTYPE arg2)
845 {
846     node_t *np1 = (node_t *) arg1;
847     node_t *np2 = (node_t *) arg2;
848     node_t *hook_point;
849     
850     hook_point = np1;
851
852     while (hook_point->peer)
853         hook_point = hook_point->peer;
854
855     hook_point->peer = np2;
856     return (arg1);
857 }
858
859 /*
860  * add_slist (stmt_list, stmt)
861  */
862
863 YYSTYPE add_slist (YYSTYPE a1, YYSTYPE a2)
864 {
865     if (a1 && a2)
866         return (addpeer(a1, a2));
867     else if(a1)
868         return(a1);
869     else 
870         return(a2);
871 }
872
873 /*
874  * add_define (char *name, defn_list);
875  */
876 YYSTYPE add_define (YYSTYPE a1, YYSTYPE a2)
877 {
878     node_t *np;
879
880     np = make_node(NODE_DEFINE);
881     np->data[0] = a1;
882     deeper((YYSTYPE)np, a2);
883     return ((YYSTYPE) np);
884 }
885
886 /*
887  * add_defbody (defn_list, new_defn)
888  */
889 YYSTYPE add_defbody (YYSTYPE a1, YYSTYPE a2)
890 {
891     return (addpeer(a1, a2));
892 }
893
894 /*
895  * add_primtype ([packed], primitive type, instance)
896  */ 
897
898 YYSTYPE add_primtype (YYSTYPE a1, YYSTYPE a2, YYSTYPE a3)
899 {
900     node_t *np1;
901
902     np1 = (node_t *)a1;
903     
904     /* Hook instance to type node */
905     deeper (a1, a2);
906     if (a3) {
907         deeper(a1, a3);
908     }
909     return (a1);
910 }
911
912 /*
913  * add_complex(char *type_name, instance)
914  */
915
916 YYSTYPE add_complex (YYSTYPE a1, YYSTYPE a2)
917 {
918     node_t *np;
919
920     np = make_node(NODE_COMPLEX);
921     np->data[0] = (void *) a1;
922
923     deeper((YYSTYPE)np, a2);
924     return ((YYSTYPE) np);
925 }
926
927 /*
928  * add_union(char *type_name, definition)
929  */
930
931 YYSTYPE add_union (YYSTYPE a1, YYSTYPE a2)
932 {
933     node_t *np;
934
935     np = make_node(NODE_UNION);
936     np->data[0] = (void *) a1;
937
938     deeper((YYSTYPE)np, a2);
939     return ((YYSTYPE) np);
940 }
941
942
943 /*
944  * add_vector_vbl (node_t *variable, YYSTYPE size)
945  */
946
947 YYSTYPE add_vector_vbl (YYSTYPE a1, YYSTYPE a2)
948 {
949     node_t *np;
950
951     np = make_node(NODE_VECTOR);
952     np->data[0] = (void *) a1;
953     np->data[1] = (void *) a2;
954     return ((YYSTYPE) np);
955 }
956
957 /*
958  * add_vector_vbl (char *vector_name, char *vector_length_var)
959  */
960
961 YYSTYPE add_variable_length_vector_vbl (YYSTYPE vector_name, YYSTYPE vector_length_var)
962 {
963     node_t *np;
964
965     np = make_node(NODE_VECTOR);
966     np->data[0] = (void *) vector_name;
967     np->data[1] = (void *) 0; // vector size used for vpe.api.h generation (array of length zero)
968     np->data[2] = (void *) vector_length_var; // name of the variable that stores vector length
969     return ((YYSTYPE) np);
970 }
971
972 /*
973  * add_scalar_vbl (char *name)
974  */
975 YYSTYPE add_scalar_vbl (YYSTYPE a1)
976 {
977     node_t *np;
978
979     np = make_node(NODE_SCALAR);
980     np->data[0] = (void *) a1;
981     return ((YYSTYPE) np);
982 }
983
984 /*
985  * set_flags (int flags, msg(=0?))
986  */ 
987 YYSTYPE set_flags(YYSTYPE a1, YYSTYPE a2)
988 {
989     node_t *np;
990     int flags;
991
992     np = (node_t *)a2;
993     if (!np)
994         return(0);
995
996     flags = (int)(uword) a1;
997
998     np->flags |= flags;
999     return (a2);
1000 }
1001 /*
1002  * suppress_version
1003  */
1004 YYSTYPE suppress_version (void)
1005 {
1006     dont_output_version = 1;
1007     return (0);
1008 }
1009
1010 void dump(node_t *np)
1011 {
1012     node_vft_t *vftp;
1013
1014     while (np) {
1015         vftp = the_vft[np->type];
1016         vftp->print(np);
1017         np = np->peer;
1018     }
1019 }
1020
1021 char *fixup_input_filename(void)
1022 {
1023     char *cp;
1024
1025     cp = (char *)input_filename;
1026
1027     while (*cp)
1028         cp++;
1029
1030     cp--;
1031
1032     while (cp > input_filename && *cp != '/')
1033         cp--;
1034     if (*cp == '/')
1035         cp++;
1036
1037     strncpy (tmpbuf, cp, sizeof(tmpbuf)-1);
1038
1039     cp = tmpbuf;
1040
1041     while (*cp)
1042         cp++;
1043
1044     cp--;
1045
1046     while (cp > tmpbuf && *cp != '.')
1047         cp--;
1048     
1049     if (*cp == '.')
1050         *cp = 0;
1051
1052     return (sxerox(tmpbuf));
1053 }
1054
1055 void generate_top_boilerplate(FILE *fp)
1056
1057 {
1058     char *datestring = ctime(&starttime);
1059     fixed_name = fixup_input_filename();
1060
1061     datestring[24] = 0;
1062
1063     fprintf (fp, "/*\n");
1064     fprintf (fp, " * VLIB API definitions %s\n", datestring);
1065     fprintf (fp, " * Input file: %s\n", input_filename);
1066     fprintf (fp, " * Automatically generated: please edit the input file ");
1067     fprintf (fp, "NOT this file!\n");
1068
1069     /* Moron Acme trigger workaround */
1070     fprintf (fp, " * %syright (c) %s by Cisco Systems, Inc.\n", "Cop", 
1071              &datestring[20]);
1072     fprintf (fp, " */\n\n");
1073     fprintf (fp, "#if defined(vl_msg_id)||defined(vl_union_id)||");
1074     fprintf (fp, "defined(vl_printfun) \\\n ||defined(vl_endianfun)||");
1075     fprintf (fp, " defined(vl_api_version)||defined(vl_typedefs) \\\n");
1076     fprintf (fp, " ||defined(vl_msg_name)\n");
1077     fprintf (fp, "/* ok, something was selected */\n");
1078     fprintf (fp, "#else\n");
1079     fprintf (fp, "#warning no content included from %s\n", input_filename);
1080     fprintf (fp, "#endif\n\n");
1081     fprintf (fp, "#define VL_API_PACKED(x) x __attribute__ ((packed))\n\n");
1082 }
1083
1084 void generate_bottom_boilerplate(FILE *fp)
1085
1086 {
1087     fprintf (fp, "\n#ifdef vl_api_version\n");
1088
1089     if (dont_output_version) {
1090         fprintf (fp, "/* WARNING: API FILE VERSION CHECK DISABLED */\n");
1091         input_crc = 0;
1092     }
1093
1094     fprintf (fp, "vl_api_version(%s, 0x%08x)\n\n", 
1095              fixed_name, (unsigned int)input_crc);
1096     fprintf (fp, "#endif\n\n");
1097 }
1098
1099 void generate_msg_ids(YYSTYPE a1, FILE *fp)
1100 {
1101     node_t *np = (node_t *)a1;
1102
1103     fprintf (fp, "\n/****** Message ID / handler enum ******/\n\n");
1104     fprintf (fp, "#ifdef vl_msg_id\n");
1105
1106     while (np) {
1107         if (np->type == NODE_DEFINE) {
1108             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
1109                 fprintf (fp, "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n", 
1110                          uppercase(np->data[0]), (i8 *)np->data[0]);
1111             } else {
1112                 fprintf (fp, "/* typeonly: %s */\n", (i8 *)np->data[0]);
1113             }
1114         }
1115         np = np->peer;
1116     }
1117     fprintf (fp, "#endif\n");
1118
1119 }
1120
1121 void generate_msg_names(YYSTYPE a1, FILE *fp)
1122 {
1123     node_t *np = (node_t *)a1;
1124
1125     fprintf (fp, "\n/****** Message names ******/\n\n");
1126
1127     fprintf (fp, "#ifdef vl_msg_name\n");
1128
1129     while (np) {
1130         if (np->type == NODE_DEFINE) {
1131             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
1132                 fprintf (fp, "vl_msg_name(vl_api_%s_t, %d)\n",
1133                          (i8 *) np->data[0], 
1134                          (np->flags & NODE_FLAG_DONT_TRACE ? 0 : 1));
1135             } else {
1136                 fprintf (fp, "/* typeonly: %s */\n", (i8 *)np->data[0]);
1137             }
1138         }
1139         np = np->peer;
1140     }
1141     fprintf (fp, "#endif\n\n");
1142 }
1143
1144 void generate_typedefs(YYSTYPE a1, FILE *fp)
1145 {
1146     node_t *np = (node_t *)a1;
1147     node_vft_t *vftp;
1148
1149     fprintf(fp, "\n/****** Typedefs *****/\n\n");
1150     fprintf(fp, "#ifdef vl_typedefs\n\n");
1151
1152     /* Walk the top-level node-list */
1153     while (np) {
1154         if (np->type == NODE_DEFINE) {
1155             /* Yeah, this is pedantic */
1156             vftp = the_vft[np->type];
1157             vftp->generate(np, TYPEDEF_PASS, fp);
1158         }
1159         np = np->peer;
1160     }
1161     fprintf(fp, "#endif /* vl_typedefs */\n\n");
1162 }
1163
1164 void union_walk_one_defn(node_t *np, FILE *fp)
1165 {
1166     node_t *vblp;
1167     node_t *uelem;
1168
1169     /* Walk the list of typed objects in this msg def */
1170     while (np) {
1171         if (np->type == NODE_UNION) {
1172             current_union_name = np->data[0];
1173             uelem = np->deeper;
1174
1175             /* Walk the list of objects in this union */
1176             while (uelem) {
1177                 vblp = uelem->deeper;
1178                 /* Drill down on each element, find the variable name */
1179                 while(vblp) {
1180                     if (vblp->type == NODE_SCALAR ||
1181                         vblp->type == NODE_VECTOR ||
1182                         vblp->type == NODE_COMPLEX) {
1183                         fprintf(ofp, "#define %s_", 
1184                                 uppercase(current_def_name));
1185                         fprintf(ofp, "%s_", uppercase(current_union_name));
1186                         fprintf(ofp, "%s %d\n",uppercase(vblp->data[0]),
1187                                 current_id);
1188                         current_id++;
1189                         break;
1190                     }
1191                     vblp = vblp->deeper;
1192                 }
1193                 uelem = uelem->peer;
1194             }
1195             current_union_name = 0;
1196             current_id = 1;
1197         }
1198         np = np->peer;
1199     }
1200 }
1201
1202 void generate_uniondefs(YYSTYPE a1, FILE *fp)
1203 {
1204     node_t *np = (node_t *)a1;
1205
1206     fprintf(fp, "/****** Discriminated Union Definitions *****/\n\n");
1207     fprintf(fp, "#ifdef vl_union_id\n\n");
1208
1209     /* Walk the top-level node-list */
1210     while (np) {
1211         if (np->type == NODE_DEFINE) {
1212             current_id = 1;
1213             current_def_name = np->data[0];
1214             union_walk_one_defn(np->deeper, fp);
1215         }
1216         np = np->peer;
1217     }
1218     fprintf(fp, "\n#endif /* vl_union_id */\n\n");
1219 }
1220
1221 void generate_printfun(YYSTYPE a1, FILE *fp)
1222 {
1223     node_t *np = (node_t *)a1;
1224     node_vft_t *vftp;
1225
1226     fprintf(fp, "/****** Print functions *****/\n\n");
1227     fprintf(fp, "#ifdef vl_printfun\n\n");
1228
1229     fprintf(fp, "#ifdef LP64\n");
1230     fputs ("#define _uword_fmt \"%lld\"\n", fp);
1231     fputs ("#define _uword_cast (long long)\n", fp);
1232     fprintf(fp, "#else\n");
1233     fputs("#define _uword_fmt \"%ld\"\n", fp);
1234     fputs ("#define _uword_cast long\n", fp);
1235     fprintf(fp, "#endif\n\n");
1236
1237     /* Walk the top-level node-list */
1238     while (np) {
1239         if (np->type == NODE_DEFINE) {
1240             if (!(np->flags & NODE_FLAG_MANUAL_PRINT)) {
1241                 fprintf(fp, 
1242        "static inline void *vl_api_%s_t_print (vl_api_%s_t *a,",
1243                         (i8 *)np->data[0], (i8 *) np->data[0]);
1244                 fprintf(fp, "void *handle)\n{\n");
1245                 /* output the message name */
1246                 fprintf(fp, 
1247                     "    vl_print(handle, \"vl_api_%s_t:\\n\");\n",
1248                         (i8 *)np->data[0]);
1249
1250                 indent += 4;
1251                 /* Yeah, this is pedantic */
1252                 vftp = the_vft[np->type];
1253                 vftp->generate(np, PRINTFUN_PASS, fp);
1254                 fprintf(fp, "    return handle;\n");
1255                 fprintf(fp, "}\n\n");
1256                 indent -= 4;
1257             } else {
1258                 fprintf(fp, "/***** manual: vl_api_%s_t_print  *****/\n\n",
1259                         (i8 *) np->data[0]);
1260             }
1261         }
1262         np = np->peer;
1263     }
1264     fprintf(fp, "#endif /* vl_printfun */\n\n");
1265 }
1266
1267 void generate_endianfun(YYSTYPE a1, FILE *fp)
1268 {
1269     node_t *np = (node_t *)a1;
1270     node_vft_t *vftp;
1271
1272     fprintf(fp, "\n/****** Endian swap functions *****/\n\n");
1273     fprintf(fp, "#ifdef vl_endianfun\n\n");
1274     fprintf(fp, "#undef clib_net_to_host_uword\n");
1275     fprintf(fp, "#ifdef LP64\n");
1276     fprintf(fp, "#define clib_net_to_host_uword clib_net_to_host_u64\n");
1277     fprintf(fp, "#else\n");
1278     fprintf(fp, "#define clib_net_to_host_uword clib_net_to_host_u32\n");
1279     fprintf(fp, "#endif\n\n");
1280
1281     /* Walk the top-level node-list */
1282     while (np) {
1283         if (np->type == NODE_DEFINE) {
1284             if (!(np->flags & NODE_FLAG_MANUAL_ENDIAN)) {
1285                 fprintf(fp, 
1286                "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)\n{\n",
1287                         (i8 *) np->data[0], (i8 *) np->data[0]);
1288                 indent += 4;
1289                 /* Yeah, this is pedantic */
1290                 vftp = the_vft[np->type];
1291                 vftp->generate(np, ENDIANFUN_PASS, fp);
1292                 fprintf(fp, "}\n\n");
1293                 indent -= 4;
1294             } else {
1295                 fprintf(fp, "/***** manual: vl_api_%s_t_endian  *****/\n\n",
1296                         (i8 *) np->data[0]);
1297             }
1298         }
1299         np = np->peer;
1300     }
1301     fprintf(fp, "#endif /* vl_endianfun */\n\n");
1302 }
1303
1304 void add_msg_ids(YYSTYPE a1)
1305 {
1306     node_t *np = (node_t *)a1;
1307     node_t *new_u16;
1308     node_t *new_vbl;
1309
1310     /* Walk the top-level node-list */
1311     while (np) {
1312         if (np->type == NODE_DEFINE) {
1313             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
1314                 /* add the parse tree for "u16 _vl_msg_id" */
1315                 new_u16 = make_node(NODE_U16);
1316                 new_u16->peer = np->deeper;
1317                 np->deeper = new_u16;
1318                 new_vbl = make_node(NODE_SCALAR);
1319                 new_vbl->data[0] = sxerox("_vl_msg_id");
1320                 new_u16->deeper = new_vbl;
1321             }
1322         }
1323         np = np->peer;
1324     }
1325 }
1326
1327 void generate_python_msg_definitions(YYSTYPE a1, FILE *fp)
1328 {
1329     node_t *np = (node_t *)a1;
1330     node_vft_t *vftp;
1331     fprintf (fp, "messages = [\n");
1332     /* Walk the top-level node-list */
1333     while (np) {
1334       if (np->type == NODE_DEFINE && !(np->flags & NODE_FLAG_TYPEONLY)) {
1335         /* Yeah, this is pedantic */
1336         vftp = the_vft[np->type];
1337         vftp->generate(np, PYTHON_PASS, fp);
1338       }
1339       np = np->peer;
1340     }
1341     fprintf (fp, "\n]\n");
1342 }
1343
1344 void generate_python_typeonly_definitions(YYSTYPE a1, FILE *fp)
1345 {
1346     node_t *np = (node_t *)a1;
1347     node_vft_t *vftp;
1348     fprintf (fp, "types = [\n");
1349     /* Walk the top-level node-list */
1350     while (np) {
1351       if (np->type == NODE_DEFINE && (np->flags & NODE_FLAG_TYPEONLY)) {
1352         vftp = the_vft[np->type];
1353         vftp->generate(np, PYTHON_PASS, fp);
1354       }
1355       np = np->peer;
1356     }
1357     fprintf (fp, "\n]\n");
1358 }
1359
1360 void generate_python(YYSTYPE a1, FILE *fp)
1361 {
1362     generate_python_typeonly_definitions(a1, fp);
1363     generate_python_msg_definitions(a1, fp);
1364
1365     /*
1366      * API CRC signature
1367      */
1368     fprintf (fp, "vl_api_version = 0x%08x\n\n", (unsigned int)input_crc);
1369 }
1370
1371 void generate(YYSTYPE a1)
1372 {
1373     if (dump_tree) {
1374         dump((node_t *)a1);
1375     }
1376
1377     add_msg_ids(a1);
1378
1379     if (ofp) {
1380         generate_top_boilerplate(ofp);
1381
1382         generate_msg_ids(a1, ofp);
1383         generate_msg_names(a1, ofp);
1384         generate_typedefs(a1, ofp);
1385         generate_uniondefs(a1, ofp);
1386         generate_printfun(a1, ofp);
1387         generate_endianfun(a1, ofp);
1388         
1389         generate_bottom_boilerplate(ofp);
1390     }
1391     if (pythonfp) {
1392       generate_python(a1, pythonfp);
1393     }
1394 }