Add API calls for packet generator
[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     ""
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 */\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
615         indent_me(fp);
616         fprintf(fp, "{\n");
617         indent += 4;
618         indent_me(fp);
619         fprintf(fp, "int _i;\n");
620         indent_me(fp);
621         fprintf(fp, "for (_i = 0; _i < %d; _i++) {\n", 
622                 IDATA1);
623         indent += 4;
624         indent_me(fp);
625         if (current_is_complex) {
626             fprintf(fp, 
627                     "vl_api_%s_t_endian (a->%s%s[_i]);\n", 
628                     current_type_name, union_prefix, CDATA0);
629         } else {
630             fprintf(fp, 
631                     "a->%s%s[_i] = %s(a->%s%s[_i]);\n", 
632                     union_prefix, CDATA0, 
633                     current_endianfun, 
634                     union_prefix, CDATA0);
635         }
636         indent -= 4;
637         indent_me(fp);
638         fprintf(fp, "}\n");
639         indent -= 4;
640         indent_me(fp);
641         fprintf(fp, "}\n");
642         break;
643     case PYTHON_PASS:
644         if (CDATA2 != 0) { // variable length vector
645             fprintf(fp, "'%s', '%d', '%s'),\n", CDATA0, IDATA1, CDATA2);
646         } else {
647             fprintf(fp, "'%s', '%d'),\n", CDATA0, IDATA1);
648         }
649         break;
650
651     default:
652         fprintf(stderr, "node_vector_generate: unimp pass %d\n", which);
653     }
654     if (this->deeper) {
655         fprintf(stderr, "broken recursion in node_vector_generate\n");
656     }
657 }
658
659 node_vft_t node_vector_vft = {
660     node_vector_print,
661     node_vector_generate,
662     0,
663 };
664
665 void node_complex_print (node_t *this)
666 {
667     primtype_recursive_print (this, "complex ");
668 }
669
670 void node_complex_generate (node_t *this, enum passid which, FILE *fp)
671 {
672     node_t *deeper;
673     node_vft_t *vftp;
674     char *member_name = "broken!";
675     char *union_prefix = "";
676
677     if (current_union_name) {
678         sprintf(tmpbuf, "%s.", current_union_name);
679         union_prefix = tmpbuf;
680     }
681
682     current_is_complex++;
683     
684     switch(which) {
685     case TYPEDEF_PASS:
686         fprintf(fp, "%s ", CDATA0);
687         deeper = this->deeper;
688         if (deeper) {
689             vftp = the_vft[deeper->type];
690             vftp->generate(deeper, which, fp);
691         }
692         break;
693
694     case PRINTFUN_PASS:
695         deeper = this->deeper;
696         while (deeper) {
697             if (deeper->type == NODE_SCALAR ||
698                 deeper->type == NODE_VECTOR) {
699                 member_name = deeper->data[0];
700                 break;
701             }
702             deeper = deeper->deeper;
703         }
704         indent_me(fp);
705         fprintf(fp, "vl_print(handle, \"%s%s ----- \\n\");\n", 
706                 union_prefix, member_name);
707         indent_me(fp);
708         fprintf(fp, "%s_print(&a->%s%s, handle);\n", 
709                 CDATA0, union_prefix, member_name);
710         indent_me(fp);
711         fprintf(fp, "vl_print(handle, \"%s%s ----- END \\n\");\n", 
712                 union_prefix, member_name);
713         break;
714
715     case ENDIANFUN_PASS:
716         deeper = this->deeper;
717         while (deeper) {
718             if (deeper->type == NODE_SCALAR ||
719                 deeper->type == NODE_VECTOR) {
720                 member_name = deeper->data[0];
721                 break;
722             }
723             deeper = deeper->deeper;
724         }
725
726         indent_me(fp);
727         fprintf(fp, "%s_endian(&a->%s%s);\n", 
728                 CDATA0, union_prefix, member_name);
729         break;
730     case PYTHON_PASS:
731         fprintf(fp, "('%s',", CDATA0);
732         deeper = this->deeper;
733         if (deeper) {
734             vftp = the_vft[deeper->type];
735             vftp->generate(deeper, which, fp);
736         }
737         break;
738
739     default:
740         fprintf(stderr, "node_complex_generate unimp pass %d...\n", which);
741         break;
742     }
743     current_is_complex--;
744 }
745
746 node_vft_t node_complex_vft = {
747     node_complex_print,
748     node_complex_generate,
749     0,
750 };
751
752 void node_noversion_print (node_t *this)
753 {
754     primtype_recursive_print (this, "noversion ");
755 }
756
757 void node_noversion_generate (node_t *this, enum passid which, FILE *ofp)
758 {
759     fprintf(stderr, "node_noversion_generate called...\n");
760 }
761
762 node_vft_t node_noversion_vft = {
763     node_noversion_print,
764     node_noversion_generate,
765     0,
766 };
767
768 void node_uword_print (node_t *this)
769 {
770     primtype_recursive_print(this, "uword ");
771 }
772
773 void node_uword_generate (node_t *this, enum passid which, FILE *ofp)
774 {
775     primtype_recursive_generate(this, which, ofp, "uword", "uword", "");
776 }
777
778 node_vft_t node_uword_vft = {
779     node_uword_print,
780     node_uword_generate,
781     "clib_net_to_host_uword",
782 };
783
784 node_vft_t *the_vft[NODE_N_TYPES] = {
785     &node_illegal_vft,
786     &node_u8_vft,
787     &node_u16_vft,
788     &node_u32_vft,
789     &node_u64_vft,
790     &node_i8_vft,
791     &node_i16_vft,
792     &node_i32_vft,
793     &node_i64_vft,
794     &node_f64_vft,
795     &node_packed_vft,
796     &node_define_vft,
797     &node_union_vft,
798     &node_scalar_vft,
799     &node_vector_vft,
800     &node_complex_vft,
801     &node_noversion_vft,
802     &node_uword_vft,
803 };
804
805 void *make_node (enum node_subclass type)
806 {
807     node_t *rv;
808
809     rv = (node_t *) malloc (sizeof (*rv));
810     if (rv == 0) {
811         fprintf (stderr, "fatal: make_node out of memory\n");
812         exit (1);
813     }
814     bzero (rv, sizeof (*rv));
815     rv->type = type;
816     return ((void *) rv);
817 }
818
819 YYSTYPE deeper (YYSTYPE arg1, YYSTYPE arg2)
820 {
821     node_t *np1 = (node_t *) arg1;
822     node_t *np2 = (node_t *) arg2;
823     node_t *hook_point;
824     
825     hook_point = np1;
826
827     while (hook_point->deeper)
828         hook_point = hook_point->deeper;
829
830     hook_point->deeper = np2;
831     return (arg1);
832 }
833
834 YYSTYPE addpeer (YYSTYPE arg1, YYSTYPE arg2)
835 {
836     node_t *np1 = (node_t *) arg1;
837     node_t *np2 = (node_t *) arg2;
838     node_t *hook_point;
839     
840     hook_point = np1;
841
842     while (hook_point->peer)
843         hook_point = hook_point->peer;
844
845     hook_point->peer = np2;
846     return (arg1);
847 }
848
849 /*
850  * add_slist (stmt_list, stmt)
851  */
852
853 YYSTYPE add_slist (YYSTYPE a1, YYSTYPE a2)
854 {
855     if (a1 && a2)
856         return (addpeer(a1, a2));
857     else if(a1)
858         return(a1);
859     else 
860         return(a2);
861 }
862
863 /*
864  * add_define (char *name, defn_list);
865  */
866 YYSTYPE add_define (YYSTYPE a1, YYSTYPE a2)
867 {
868     node_t *np;
869
870     np = make_node(NODE_DEFINE);
871     np->data[0] = a1;
872     deeper((YYSTYPE)np, a2);
873     return ((YYSTYPE) np);
874 }
875
876 /*
877  * add_defbody (defn_list, new_defn)
878  */
879 YYSTYPE add_defbody (YYSTYPE a1, YYSTYPE a2)
880 {
881     return (addpeer(a1, a2));
882 }
883
884 /*
885  * add_primtype ([packed], primitive type, instance)
886  */ 
887
888 YYSTYPE add_primtype (YYSTYPE a1, YYSTYPE a2, YYSTYPE a3)
889 {
890     node_t *np1;
891
892     np1 = (node_t *)a1;
893     
894     /* Hook instance to type node */
895     deeper (a1, a2);
896     if (a3) {
897         deeper(a1, a3);
898     }
899     return (a1);
900 }
901
902 /*
903  * add_complex(char *type_name, instance)
904  */
905
906 YYSTYPE add_complex (YYSTYPE a1, YYSTYPE a2)
907 {
908     node_t *np;
909
910     np = make_node(NODE_COMPLEX);
911     np->data[0] = (void *) a1;
912
913     deeper((YYSTYPE)np, a2);
914     return ((YYSTYPE) np);
915 }
916
917 /*
918  * add_union(char *type_name, definition)
919  */
920
921 YYSTYPE add_union (YYSTYPE a1, YYSTYPE a2)
922 {
923     node_t *np;
924
925     np = make_node(NODE_UNION);
926     np->data[0] = (void *) a1;
927
928     deeper((YYSTYPE)np, a2);
929     return ((YYSTYPE) np);
930 }
931
932
933 /*
934  * add_vector_vbl (node_t *variable, YYSTYPE size)
935  */
936
937 YYSTYPE add_vector_vbl (YYSTYPE a1, YYSTYPE a2)
938 {
939     node_t *np;
940
941     np = make_node(NODE_VECTOR);
942     np->data[0] = (void *) a1;
943     np->data[1] = (void *) a2;
944     return ((YYSTYPE) np);
945 }
946
947 /*
948  * add_vector_vbl (char *vector_name, char *vector_length_var)
949  */
950
951 YYSTYPE add_variable_length_vector_vbl (YYSTYPE vector_name, YYSTYPE vector_length_var)
952 {
953     node_t *np;
954
955     np = make_node(NODE_VECTOR);
956     np->data[0] = (void *) vector_name;
957     np->data[1] = (void *) 0; // vector size used for vpe.api.h generation (array of length zero)
958     np->data[2] = (void *) vector_length_var; // name of the variable that stores vector length
959     return ((YYSTYPE) np);
960 }
961
962 /*
963  * add_scalar_vbl (char *name)
964  */
965 YYSTYPE add_scalar_vbl (YYSTYPE a1)
966 {
967     node_t *np;
968
969     np = make_node(NODE_SCALAR);
970     np->data[0] = (void *) a1;
971     return ((YYSTYPE) np);
972 }
973
974 /*
975  * set_flags (int flags, msg(=0?))
976  */ 
977 YYSTYPE set_flags(YYSTYPE a1, YYSTYPE a2)
978 {
979     node_t *np;
980     int flags;
981
982     np = (node_t *)a2;
983     if (!np)
984         return(0);
985
986     flags = (int)(uword) a1;
987
988     np->flags |= flags;
989     return (a2);
990 }
991 /*
992  * suppress_version
993  */
994 YYSTYPE suppress_version (void)
995 {
996     dont_output_version = 1;
997     return (0);
998 }
999
1000 void dump(node_t *np)
1001 {
1002     node_vft_t *vftp;
1003
1004     while (np) {
1005         vftp = the_vft[np->type];
1006         vftp->print(np);
1007         np = np->peer;
1008     }
1009 }
1010
1011 char *fixup_input_filename(void)
1012 {
1013     char *cp;
1014
1015     cp = (char *)input_filename;
1016
1017     while (*cp)
1018         cp++;
1019
1020     cp--;
1021
1022     while (cp > input_filename && *cp != '/')
1023         cp--;
1024     if (*cp == '/')
1025         cp++;
1026
1027     strcpy (tmpbuf, cp);
1028
1029     cp = tmpbuf;
1030
1031     while (*cp)
1032         cp++;
1033
1034     cp--;
1035
1036     while (cp > tmpbuf && *cp != '.')
1037         cp--;
1038     
1039     if (*cp == '.')
1040         *cp = 0;
1041
1042     return (sxerox(tmpbuf));
1043 }
1044
1045 void generate_top_boilerplate(FILE *fp)
1046
1047 {
1048     char *datestring = ctime(&starttime);
1049     fixed_name = fixup_input_filename();
1050
1051     datestring[24] = 0;
1052
1053     fprintf (fp, "/*\n");
1054     fprintf (fp, " * VLIB API definitions %s\n", datestring);
1055     fprintf (fp, " * Input file: %s\n", input_filename);
1056     fprintf (fp, " * Automatically generated: please edit the input file ");
1057     fprintf (fp, "NOT this file!\n");
1058
1059     /* Moron Acme trigger workaround */
1060     fprintf (fp, " * %syright (c) %s by Cisco Systems, Inc.\n", "Cop", 
1061              &datestring[20]);
1062     fprintf (fp, " */\n\n");
1063     fprintf (fp, "#if defined(vl_msg_id)||defined(vl_union_id)||");
1064     fprintf (fp, "defined(vl_printfun) \\\n ||defined(vl_endianfun)||");
1065     fprintf (fp, " defined(vl_api_version)||defined(vl_typedefs) \\\n");
1066     fprintf (fp, " ||defined(vl_msg_name)\n");
1067     fprintf (fp, "/* ok, something was selected */\n");
1068     fprintf (fp, "#else\n");
1069     fprintf (fp, "#warning no content included from %s\n", input_filename);
1070     fprintf (fp, "#endif\n\n");
1071     fprintf (fp, "#define VL_API_PACKED(x) x __attribute__ ((packed))\n\n");
1072 }
1073
1074 void generate_bottom_boilerplate(FILE *fp)
1075
1076 {
1077     fprintf (fp, "\n#ifdef vl_api_version\n");
1078
1079     if (dont_output_version) {
1080         fprintf (fp, "/* WARNING: API FILE VERSION CHECK DISABLED */\n");
1081         input_crc = 0;
1082     }
1083
1084     fprintf (fp, "vl_api_version(%s, 0x%08x)\n\n", 
1085              fixed_name, (unsigned int)input_crc);
1086     fprintf (fp, "#endif\n\n");
1087 }
1088
1089 void generate_msg_ids(YYSTYPE a1, FILE *fp)
1090 {
1091     node_t *np = (node_t *)a1;
1092
1093     fprintf (fp, "\n/****** Message ID / handler enum ******/\n\n");
1094     fprintf (fp, "#ifdef vl_msg_id\n");
1095
1096     while (np) {
1097         if (np->type == NODE_DEFINE) {
1098             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
1099                 fprintf (fp, "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n", 
1100                          uppercase(np->data[0]), (i8 *)np->data[0]);
1101             } else {
1102                 fprintf (fp, "/* typeonly: %s */\n", (i8 *)np->data[0]);
1103             }
1104         }
1105         np = np->peer;
1106     }
1107     fprintf (fp, "#endif\n");
1108
1109 }
1110
1111 void generate_msg_names(YYSTYPE a1, FILE *fp)
1112 {
1113     node_t *np = (node_t *)a1;
1114
1115     fprintf (fp, "\n/****** Message names ******/\n\n");
1116
1117     fprintf (fp, "#ifdef vl_msg_name\n");
1118
1119     while (np) {
1120         if (np->type == NODE_DEFINE) {
1121             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
1122                 fprintf (fp, "vl_msg_name(vl_api_%s_t, %d)\n",
1123                          (i8 *) np->data[0], 
1124                          (np->flags & NODE_FLAG_DONT_TRACE ? 0 : 1));
1125             } else {
1126                 fprintf (fp, "/* typeonly: %s */\n", (i8 *)np->data[0]);
1127             }
1128         }
1129         np = np->peer;
1130     }
1131     fprintf (fp, "#endif\n\n");
1132 }
1133
1134 void generate_typedefs(YYSTYPE a1, FILE *fp)
1135 {
1136     node_t *np = (node_t *)a1;
1137     node_vft_t *vftp;
1138
1139     fprintf(fp, "\n/****** Typedefs *****/\n\n");
1140     fprintf(fp, "#ifdef vl_typedefs\n\n");
1141
1142     /* Walk the top-level node-list */
1143     while (np) {
1144         if (np->type == NODE_DEFINE) {
1145             /* Yeah, this is pedantic */
1146             vftp = the_vft[np->type];
1147             vftp->generate(np, TYPEDEF_PASS, fp);
1148         }
1149         np = np->peer;
1150     }
1151     fprintf(fp, "#endif /* vl_typedefs */\n\n");
1152 }
1153
1154 void union_walk_one_defn(node_t *np, FILE *fp)
1155 {
1156     node_t *vblp;
1157     node_t *uelem;
1158
1159     /* Walk the list of typed objects in this msg def */
1160     while (np) {
1161         if (np->type == NODE_UNION) {
1162             current_union_name = np->data[0];
1163             uelem = np->deeper;
1164
1165             /* Walk the list of objects in this union */
1166             while (uelem) {
1167                 vblp = uelem->deeper;
1168                 /* Drill down on each element, find the variable name */
1169                 while(vblp) {
1170                     if (vblp->type == NODE_SCALAR ||
1171                         vblp->type == NODE_VECTOR ||
1172                         vblp->type == NODE_COMPLEX) {
1173                         fprintf(ofp, "#define %s_", 
1174                                 uppercase(current_def_name));
1175                         fprintf(ofp, "%s_", uppercase(current_union_name));
1176                         fprintf(ofp, "%s %d\n",uppercase(vblp->data[0]),
1177                                 current_id);
1178                         current_id++;
1179                         break;
1180                     }
1181                     vblp = vblp->deeper;
1182                 }
1183                 uelem = uelem->peer;
1184             }
1185             current_union_name = 0;
1186             current_id = 1;
1187         }
1188         np = np->peer;
1189     }
1190 }
1191
1192 void generate_uniondefs(YYSTYPE a1, FILE *fp)
1193 {
1194     node_t *np = (node_t *)a1;
1195
1196     fprintf(fp, "/****** Discriminated Union Definitions *****/\n\n");
1197     fprintf(fp, "#ifdef vl_union_id\n\n");
1198
1199     /* Walk the top-level node-list */
1200     while (np) {
1201         if (np->type == NODE_DEFINE) {
1202             current_id = 1;
1203             current_def_name = np->data[0];
1204             union_walk_one_defn(np->deeper, fp);
1205         }
1206         np = np->peer;
1207     }
1208     fprintf(fp, "\n#endif /* vl_union_id */\n\n");
1209 }
1210
1211 void generate_printfun(YYSTYPE a1, FILE *fp)
1212 {
1213     node_t *np = (node_t *)a1;
1214     node_vft_t *vftp;
1215
1216     fprintf(fp, "/****** Print functions *****/\n\n");
1217     fprintf(fp, "#ifdef vl_printfun\n\n");
1218
1219     fprintf(fp, "#ifdef LP64\n");
1220     fputs ("#define _uword_fmt \"%lld\"\n", fp);
1221     fputs ("#define _uword_cast (long long)\n", fp);
1222     fprintf(fp, "#else\n");
1223     fputs("#define _uword_fmt \"%ld\"\n", fp);
1224     fputs ("#define _uword_cast long\n", fp);
1225     fprintf(fp, "#endif\n\n");
1226
1227     /* Walk the top-level node-list */
1228     while (np) {
1229         if (np->type == NODE_DEFINE) {
1230             if (!(np->flags & NODE_FLAG_MANUAL_PRINT)) {
1231                 fprintf(fp, 
1232        "static inline void *vl_api_%s_t_print (vl_api_%s_t *a,",
1233                         (i8 *)np->data[0], (i8 *) np->data[0]);
1234                 fprintf(fp, "void *handle)\n{\n");
1235                 /* output the message name */
1236                 fprintf(fp, 
1237                     "    vl_print(handle, \"vl_api_%s_t:\\n\");\n",
1238                         (i8 *)np->data[0]);
1239
1240                 indent += 4;
1241                 /* Yeah, this is pedantic */
1242                 vftp = the_vft[np->type];
1243                 vftp->generate(np, PRINTFUN_PASS, fp);
1244                 fprintf(fp, "    return handle;\n");
1245                 fprintf(fp, "}\n\n");
1246                 indent -= 4;
1247             } else {
1248                 fprintf(fp, "/***** manual: vl_api_%s_t_print  *****/\n\n",
1249                         (i8 *) np->data[0]);
1250             }
1251         }
1252         np = np->peer;
1253     }
1254     fprintf(fp, "#endif /* vl_printfun */\n\n");
1255 }
1256
1257 void generate_endianfun(YYSTYPE a1, FILE *fp)
1258 {
1259     node_t *np = (node_t *)a1;
1260     node_vft_t *vftp;
1261
1262     fprintf(fp, "\n/****** Endian swap functions *****/\n\n");
1263     fprintf(fp, "#ifdef vl_endianfun\n\n");
1264     fprintf(fp, "#undef clib_net_to_host_uword\n");
1265     fprintf(fp, "#ifdef LP64\n");
1266     fprintf(fp, "#define clib_net_to_host_uword clib_net_to_host_u64\n");
1267     fprintf(fp, "#else\n");
1268     fprintf(fp, "#define clib_net_to_host_uword clib_net_to_host_u32\n");
1269     fprintf(fp, "#endif\n\n");
1270
1271     /* Walk the top-level node-list */
1272     while (np) {
1273         if (np->type == NODE_DEFINE) {
1274             if (!(np->flags & NODE_FLAG_MANUAL_ENDIAN)) {
1275                 fprintf(fp, 
1276                "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)\n{\n",
1277                         (i8 *) np->data[0], (i8 *) np->data[0]);
1278                 indent += 4;
1279                 /* Yeah, this is pedantic */
1280                 vftp = the_vft[np->type];
1281                 vftp->generate(np, ENDIANFUN_PASS, fp);
1282                 fprintf(fp, "}\n\n");
1283                 indent -= 4;
1284             } else {
1285                 fprintf(fp, "/***** manual: vl_api_%s_t_endian  *****/\n\n",
1286                         (i8 *) np->data[0]);
1287             }
1288         }
1289         np = np->peer;
1290     }
1291     fprintf(fp, "#endif /* vl_endianfun */\n\n");
1292 }
1293
1294 void add_msg_ids(YYSTYPE a1)
1295 {
1296     node_t *np = (node_t *)a1;
1297     node_t *new_u16;
1298     node_t *new_vbl;
1299
1300     /* Walk the top-level node-list */
1301     while (np) {
1302         if (np->type == NODE_DEFINE) {
1303             if (!(np->flags & NODE_FLAG_TYPEONLY)) {
1304                 /* add the parse tree for "u16 _vl_msg_id" */
1305                 new_u16 = make_node(NODE_U16);
1306                 new_u16->peer = np->deeper;
1307                 np->deeper = new_u16;
1308                 new_vbl = make_node(NODE_SCALAR);
1309                 new_vbl->data[0] = sxerox("_vl_msg_id");
1310                 new_u16->deeper = new_vbl;
1311             }
1312         }
1313         np = np->peer;
1314     }
1315 }
1316
1317 void generate_python (YYSTYPE a1, FILE *fp)
1318 {
1319   node_t *np = (node_t *)a1;
1320   node_vft_t *vftp;
1321   fprintf (fp, "vppapidef = [\n");
1322   /* Walk the top-level node-list */
1323   while (np) {
1324     if (np->type == NODE_DEFINE && !(np->flags & NODE_FLAG_TYPEONLY)) {
1325       /* Yeah, this is pedantic */
1326       vftp = the_vft[np->type];
1327       vftp->generate(np, PYTHON_PASS, fp);
1328     }
1329     np = np->peer;
1330   }
1331   fprintf (fp, "\n]\n");
1332 }
1333
1334 void generate(YYSTYPE a1)
1335 {
1336     if (dump_tree) {
1337         dump((node_t *)a1);
1338     }
1339
1340     add_msg_ids(a1);
1341
1342     if (ofp) {
1343         generate_top_boilerplate(ofp);
1344
1345         generate_msg_ids(a1, ofp);
1346         generate_msg_names(a1, ofp);
1347         generate_typedefs(a1, ofp);
1348         generate_uniondefs(a1, ofp);
1349         generate_printfun(a1, ofp);
1350         generate_endianfun(a1, ofp);
1351         
1352         generate_bottom_boilerplate(ofp);
1353     }
1354     if (pythonfp) {
1355       generate_python(a1, pythonfp);
1356     }
1357 }