changes in include syntax round 2 or 3.
[dyninst.git] / igen / src / main.C
1 /*
2  * main.C - main function of the interface compiler igen.
3  *
4  * $Log: main.C,v $
5  * Revision 1.3  1994/01/27 20:36:29  hollings
6  * changes in include syntax round 2 or 3.
7  *
8  * Revision 1.2  1994/01/26  06:50:10  hollings
9  * made the output of igen pass through g++ -Wall.
10  *
11  * Revision 1.1  1994/01/25  20:48:43  hollings
12  * New utility for interfaces.
13  * new utility for interfaces.
14  *
15  *
16  */
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/file.h>
22
23 #include "util/h/list.h"
24 #include "util/h/stringPool.h"
25
26 #include "parse.h"
27
28 int yyparse();
29 int emitCode;
30 int emitHeader;
31 char *codeFile;
32 char *serverFile;
33 char *clientFile;
34 int generateXDR;
35 int generatePVM;
36 stringPool pool;
37 char *headerFile;
38 extern FILE *yyin;
39 int generateTHREAD;
40 char *transportBase;
41 char *serverTypeName;
42 List <typeDefn *> types;
43 interfaceSpec *currentInterface;
44
45 void usage(char *name)
46 {
47     printf("%s -xdr | -thread | -pvm [-header | -code] <fileName>\n", name);
48     exit(-1);
49 }
50
51 void interfaceSpec::generateThreadLoop()
52 {
53     List <remoteFunc*> cf;
54
55     unionName = genVariable();
56     printf("union %s {\n", unionName);
57     for (cf = methods; *cf; cf++) {
58         printf("    struct %s %s;\n", (*cf)->structName, (*cf)->name);
59     }
60     printf("};\n\n");
61
62     printf("int %s::mainLoop(void)\n", name);
63     printf("{\n");
64     printf("  unsigned int __len__;\n");
65     printf("  unsigned int __tag__;\n");
66     printf("  union %s __recvBuffer__;\n", unionName);
67     printf("\n");
68     printf("  __tag__ = MSG_TAG_ANY;\n");
69     printf("  __len__ = sizeof(__recvBuffer__);\n");
70     printf("  requestingThread = msg_recv(&__tag__, &__recvBuffer__, &__len__);\n");
71     printf("  switch (__tag__) {\n");
72     for (cf = methods; *cf; cf++) {
73         (*cf)->genSwitch(FALSE);
74     }
75     printf("    default:\n");
76     printf("        return(__tag__);\n");
77     printf("  }\n");
78     printf("  return(0);\n");
79     printf("}\n");
80 }
81
82 void interfaceSpec::generateXDRLoop()
83 {
84     List <remoteFunc*> cf;
85
86     printf("int %s::mainLoop(void)\n", name);
87     printf("{\n");
88     printf("    unsigned int __tag__, __status__;\n");
89     printf("    __xdrs__->x_op = XDR_DECODE;\n");
90     printf("    xdrrec_skiprecord(__xdrs__);\n");
91     printf("    __status__ = xdr_int(__xdrs__, &__tag__);\n");
92     printf("    if (!__status__) return(-1);\n");
93     printf("    switch (__tag__) {\n");
94
95     // generate the zero RPC that returns interface name & version.
96     printf("        case 0:\n");
97     printf("            char *__ProtocolName__ = \"%s\";\n", name);
98     printf("            int __val__;\n");
99     printf("            __xdrs__->x_op = XDR_ENCODE;\n");
100     printf("            __val__ = 0;\n");
101     printf("            xdr_int(__xdrs__, &__val__);\n");
102     printf("            xdr_String(__xdrs__, &__ProtocolName__);\n");
103     printf("            __val__ = %d;\n", version);
104     printf("            xdr_int(__xdrs__, &__val__);\n");
105     printf("            xdrrec_endofrecord(__xdrs__, TRUE);\n");
106     printf("            break;\n");
107
108     for (cf = methods; *cf; cf++) {
109         (*cf)->genSwitch(FALSE);
110     }
111     printf("    default:\n");
112     printf("        return(__tag__);\n");
113     printf("  }\n");
114     printf("  return(0);\n");
115     printf("}\n");
116 }
117
118
119
120 void interfaceSpec::genIncludes()
121 {
122     printf("#include <stdio.h>\n");
123     printf("#include <stdlib.h>\n");
124     printf("#include <assert.h>\n");
125     if (generateTHREAD) {
126         printf("extern \"C\" {\n");
127         printf("#include \"thread/h/thread.h\"\n");
128         printf("}\n");
129     }
130     if (generateXDR) {
131         printf("extern \"C\" {\n");
132         printf("#include <rpc/types.h>\n");
133         printf("#include <rpc/xdr.h>\n");
134         printf("}\n");
135     }
136
137     printf("#include \"%s\"\n\n", headerFile);
138 }
139
140 void interfaceSpec::generateServerCode()
141 {
142     List<remoteFunc*> cf;
143
144     if (generateTHREAD) {
145         generateThreadLoop();
146     } else if (generateXDR) {
147         FILE *sf;
148
149         // needs to go into a seperate file.
150         fflush(stdout);
151
152         sf = fopen(serverFile, "w");
153         dup2(sf->_file, 1);
154
155         genIncludes();
156
157         generateXDRLoop();
158     }
159
160     // generate stubs for upcalls.
161     for (cf = methods; *cf; cf++) {
162         (*cf)->genStub(name, TRUE);
163     }
164 }
165
166
167 void interfaceSpec::genWaitLoop() 
168 {
169     List<remoteFunc*> cf;
170
171     // generate a loop to wait for a tag, and call upcalls as the arrive.
172     printf("void %sUser::awaitResponce(int __targetTag__) {\n", name);
173     printf("    unsigned int __tag__;\n");
174     if (generateTHREAD) {
175         printf("  union %s __recvBuffer__;\n", unionName);
176         printf("  unsigned __len__ = sizeof(__recvBuffer__);\n");
177     }
178     printf("  while (1) {\n");
179     if (generateXDR) {
180         printf("    __xdrs__->x_op = XDR_DECODE;\n");
181         printf("    xdrrec_skiprecord(__xdrs__);\n");
182         printf("    xdr_int(__xdrs__, &__tag__);\n");
183     } else if (generateTHREAD) {
184         printf("  __tag__ = MSG_TAG_ANY;\n");
185         printf("    requestingThread = msg_recv(&__tag__, (void *) &__recvBuffer__, &__len__); \n");
186     }
187     printf("    if (__tag__ == __targetTag__) return;\n");
188     printf("    switch (__tag__) {\n");
189     for (cf = methods; *cf; cf++) {
190         (*cf)->genSwitch(TRUE);
191     }
192     printf("        default: \n        abort();\n");
193     printf("    }\n");
194     printf("    if (__targetTag__ == -1) return;\n");
195     printf("  }\n");
196     printf("}\n");
197
198     printf("int %sUser::isValidUpCall(int tag) {\n", name);
199     printf("    return((tag >= %d) && (tag <= %d));\n", baseTag, boundTag);
200     printf("}\n");
201 }
202
203 void interfaceSpec::genProtoVerify()
204 {
205     // generate stub to verify version.
206     printf("void %sUser::verifyProtocolAndVersion() {\n", name);
207     printf("    unsigned int __tag__;\n");
208     printf("    String proto;\n");
209     printf("    int version;\n");
210     printf("    __tag__ = 0;\n");
211     printf("    __xdrs__->x_op = XDR_ENCODE;\n");
212     printf("    xdr_int(__xdrs__, &__tag__);\n");
213     printf("    xdrrec_endofrecord(__xdrs__, TRUE);\n");
214     printf("    awaitResponce(0);\n");
215     printf("    xdr_String(__xdrs__, &(proto));\n");
216     printf("    xdr_int(__xdrs__, &(version));\n");
217     printf("    if ((version != %d) || (strcmp(proto, \"%s\"))) {\n",
218         version, name);
219     printf("        printf(\"protocol %s version %d expected\\n\");\n", 
220         name, version);
221     printf("        printf(\"protocol %%s version %%d found\\n\", proto, version);\n");
222     printf("        exit(-1);\n");
223     printf("    }\n");
224     printf("}\n");
225     printf("\n\n");
226     printf("%sUser::%sUser(int fd, xdrIOFunc r, xdrIOFunc w):\n", name, name);
227     printf("XDRrpc(fd, r, w) { if (__xdrs__) verifyProtocolAndVersion(); }\n");
228     printf("%sUser::%sUser(char *m,char *l,char *p,xdrIOFunc r,xdrIOFunc w):\n",
229         name, name);
230     printf("    XDRrpc(m, l, p, r, w) { if (__xdrs__) \n");
231     printf("       verifyProtocolAndVersion(); }\n");
232     printf("\n");
233 }
234
235
236 void interfaceSpec::generateStubs()
237 {
238     List <remoteFunc*> cf;
239     char className[80];
240
241     sprintf(className, "%sUser", name);
242     for (cf = methods; *cf; cf++) {
243         (*cf)->genStub(className, FALSE);
244     }
245 }
246
247 void interfaceSpec::generateClientCode()
248 {
249     if (generateXDR) {
250         FILE *cf;
251
252         // needs to go into a seperate file.
253         fflush(stdout);
254
255         cf = fopen(clientFile, "w");
256         dup2(cf->_file, 1);
257
258         genIncludes();
259     }
260
261     generateStubs();
262
263     if (generateXDR) {
264         genProtoVerify();
265     }
266
267     genWaitLoop();
268 }
269
270 void interfaceSpec::generateBundlers()
271 {
272     List <typeDefn*> cs;
273
274     for (cs = types; *cs; cs++) {
275         (*cs)->genBundler();
276     }
277 }
278
279 int main(int argc, char *argv[])
280 {
281     int i;
282     FILE *of;
283     char *temp;
284     char *file;
285
286     /* define pre-defined types */
287     (void) new typeDefn("int");
288     (void) new typeDefn("double");
289     (void) new typeDefn("String");
290     (void) new typeDefn("void");
291     (void) new typeDefn("Boolean");
292
293     emitCode = 1;
294     emitHeader = 1;
295     for (i=0; i < argc-1; i++) {
296         if (!strcmp("-pvm", argv[i])) {
297             generatePVM = 1;
298             generateXDR = 0;
299             generateTHREAD = 0;
300             serverTypeName = pool.findAndAdd("int");
301         } if (!strcmp("-xdr", argv[i])) {
302             generatePVM = 0;
303             generateXDR = 1;
304             generateTHREAD = 0;
305             (void) new typeDefn("XDRptr");
306             serverTypeName = pool.findAndAdd("XDRptr");
307             transportBase = "XDRrpc";
308         } if (!strcmp("-thread", argv[i])) {
309             generatePVM = 0;
310             generateXDR = 0;
311             generateTHREAD = 1;
312             serverTypeName = pool.findAndAdd("int");
313             transportBase = "THREADrpc";
314         } else if (!strcmp("-header", argv[i])) {
315             emitCode = 0;
316             emitHeader = 1;
317         } else if (!strcmp("-code", argv[i])) {
318             emitCode = 1;
319             emitHeader = 0;
320         }
321     }
322     if (!emitHeader && !emitCode) {
323         usage(argv[0]);
324     }
325     if (!generatePVM && !generateXDR && !generateTHREAD) {
326         usage(argv[0]);
327     }
328
329     file = argv[argc-1];
330
331     yyin = fopen(file, "r");
332     if (!yyin) {
333         printf("unable to open %s\n", file);
334         exit(-1);
335     }
336
337     // skip to trailing component of file name.
338     temp = strrchr(file, '/');
339     if (temp) file = temp+1;
340
341     temp = strstr(file, ".I");
342     if (!temp) {
343         printf("file names must end in .I\n");
344         exit(-1);
345     }
346     *(temp+1) = '\0';
347
348     headerFile = (char *) malloc(strlen(file)+1);
349     sprintf(headerFile, "%sh", file);
350
351     codeFile = (char *) malloc(strlen(file)+1);
352     sprintf(codeFile, "%sC", file);
353
354     serverFile = (char *) malloc(strlen(file)+6);
355     sprintf(serverFile, "%sSRVR.C", file);
356
357     clientFile = (char *) malloc(strlen(file)+6);
358     sprintf(clientFile, "%sCLNT.C", file);
359
360     if (emitHeader) {
361         of = fopen(headerFile, "w");
362         dup2(of->_file, 1);
363         printf("#include \"util/h/rpcUtil.h\"\n");
364     }
365
366     yyparse();
367
368     if (emitHeader) {
369         fflush(stdout);
370         fclose(of);
371     }
372
373     if (!currentInterface) {
374         printf("no interface defined\n");
375         exit(-1);
376     }
377
378     if (emitCode) {
379         FILE *cf;
380
381         cf = fopen(codeFile, "w");
382         dup2(cf->_file, 1);
383
384         currentInterface->genIncludes();
385         if (generateXDR || generatePVM) currentInterface->generateBundlers();
386
387         currentInterface->generateServerCode();
388
389         currentInterface->generateClientCode();
390         fflush(stdout);
391     }
392
393     exit(0);
394 }
395
396 char *interfaceSpec::genVariable()
397 {
398     static int count;
399     char *ret;
400
401     ret = (char *) malloc(20);
402     sprintf(ret, "%s__%d", name, count++);
403     return(ret);
404 }
405
406 int interfaceSpec::getNextTag()
407 {
408     return(++boundTag);
409 }
410
411 void remoteFunc::genMethodHeader(char *className)
412 {
413     int spitOne;
414     List <char *> cl;
415     List<argument*> lp;
416
417     if (className) {
418         printf("%s %s::%s(", retType, className, name);
419     } else {
420         printf("%s %s(", retType, name);
421     }
422     for (lp = args, spitOne = 0; *lp; lp++) {
423         if (spitOne) printf(",");
424         spitOne =1;
425         printf("%s ", (*lp)->type);
426         for (cl = *(*lp)->stars; *cl; cl++) printf("*");
427         printf("%s", (*lp)->name);
428     }
429     if (!spitOne) printf("void");
430     printf(")");
431 }
432
433 void remoteFunc::genSwitch(Boolean forUpcalls)
434 {
435     int first;
436     List <argument *> ca;
437
438
439     if (forUpcalls && (upcall == notUpcall)) return;
440     if (!forUpcalls && (upcall != notUpcall)) return;
441
442     printf("        case %s_%s_REQ: {\n", spec->getName(), name);
443     printf("            ");
444     if (generateTHREAD && (upcall != asyncUpcall)) 
445         printf("            int __val__;\n");
446     if (strcmp(retType, "void")) {
447         printf("            %s __ret__;\n", retType);
448     }
449     if (generateXDR) {
450         printf("            extern xdr_%s(XDR*, %s*);\n", retType, retType);
451         if (args.count()) {
452             printf("            %s __recvBuffer__;\n", structName);
453                 for (ca = args; *ca; ca++) {
454                 printf("            xdr_%s(__xdrs__, &__recvBuffer__.%s);\n", 
455                     (*ca)->type, (*ca)->name);
456             }
457         }
458     }
459     if (strcmp(retType, "void")) {
460         printf("            __ret__ = %s(", name);
461     } else {
462         printf("            %s(", name);
463     }
464     for (ca = args, first = 1; *ca; ca++) {
465         if (!first) printf(",");
466         first = 0;
467         if (generateTHREAD) {
468             printf("__recvBuffer__.%s.%s", name, (*ca)->name);
469         } else if (generateXDR) {
470             printf("__recvBuffer__.%s", (*ca)->name);
471         }
472     }
473     printf(");\n");
474     if (generateTHREAD && (upcall != asyncUpcall)) {
475         if (strcmp(retType, "void")) {
476             printf("        __val__ = msg_send(requestingThread, %s_%s_RESP, (void *) &__ret__, sizeof(%s));\n", spec->getName(), name, retType);
477         } else {
478             printf("        __val__ = msg_send(requestingThread, %s_%s_RESP, NULL, 0);\n", 
479                 spec->getName(), name);
480         }
481         printf("            assert(__val__ == THR_OKAY);\n");
482     } else if (generateXDR && (upcall != asyncUpcall)) {
483         printf("            __xdrs__->x_op = XDR_ENCODE;\n");
484         printf("            __tag__ = %s_%s_RESP;\n", spec->getName(), name);
485         printf("            xdr_int(__xdrs__, &__tag__);\n");
486         if (strcmp(retType, "void")) {
487             printf("            xdr_%s(__xdrs__,&__ret__);\n", retType);
488         }
489         printf("            xdrrec_endofrecord(__xdrs__, TRUE);\n");
490     }
491     printf("            break;\n         }\n\n");
492 }
493
494
495 void remoteFunc::genThreadStub(char *className)
496 {
497     List<argument*> lp;
498     char *retVar = spec->genVariable();
499     char *structUseName = spec->genVariable();
500
501     genMethodHeader(className);
502     printf(" {\n");
503
504     if (*args) printf("    struct %s %s;\n", structName, structUseName);
505     if (upcall != asyncUpcall) printf("    unsigned int __tag__;\n");
506     if (strcmp(retType, "void")) printf("    unsigned int __len__;\n");
507     printf("    int __val__;\n");
508     if (strcmp(retType, "void")) {
509         printf("    %s %s;\n", retType, retVar);
510     }
511     for (lp = args; *lp; lp++) {
512         printf("    %s.%s = %s;  \n",structUseName,
513             (*lp)->name, (*lp)->name);
514     }
515     if (*args) {
516         printf("    __val__ = msg_send(tid, %s_%s_REQ, (void *) &%s, sizeof(%s));\n",
517             spec->getName(), name, structUseName, structUseName);
518     } else {
519         printf("    __val__ = msg_send(tid, %s_%s_REQ, NULL, 0); \n", 
520             spec->getName(), name);
521     }
522     printf("    assert(__val__ == THR_OKAY);\n");
523     if (upcall != asyncUpcall) {
524         printf("    __tag__ = %s_%s_RESP;\n", spec->getName(), name);
525         if (strcmp(retType, "void")) {
526             printf("    __len__ = sizeof(%s);\n", retVar);
527             printf("    msg_recv(&__tag__, (void *) &%s, &__len__); \n",retVar);
528             printf("    assert(__len__ == sizeof(%s));\n", retVar);
529             printf("    return(%s);\n", retVar);
530         } else {
531             printf("    msg_recv(&__tag__, NULL, 0); \n",spec->getName(), name);
532         }
533         printf("    assert(__tag__ == %s_%s_RESP);\n",spec->getName(),name);
534     }
535     printf("}\n\n");
536 }
537
538 void remoteFunc::genXDRStub(char *className)
539 {
540     List<argument*> lp;
541     char *retVar = spec->genVariable();
542
543     genMethodHeader(className);
544     printf(" {\n");
545
546     printf("    unsigned int __tag__;\n");
547     if (strcmp(retType, "void")) {
548         printf("    %s %s;\n", retType, retVar);
549     }
550     printf("    __tag__ = %s_%s_REQ;\n", spec->getName(), name);
551     printf("    __xdrs__->x_op = XDR_ENCODE;\n");
552     printf("    xdr_int(__xdrs__, &__tag__);\n");
553     for (lp = args; *lp; lp++) {
554         printf("    xdr_%s(__xdrs__, &%s);\n", (*lp)->type, (*lp)->name);
555     }
556     printf("    xdrrec_endofrecord(__xdrs__, TRUE);\n");
557     if (upcall != asyncUpcall) {
558         if (upcall == notUpcall) {
559             printf("    awaitResponce(%s_%s_RESP);\n",spec->getName(), name);
560         } else if (upcall == syncUpcall) {
561             printf("    __xdrs__->x_op = XDR_DECODE;\n");
562             printf("    xdrrec_skiprecord(__xdrs__);\n");
563             printf("    xdr_int(__xdrs__, &__tag__);\n");
564             printf("    assert(__tag__ == %s_%s_RESP);\n", spec->getName(), name);
565         }
566         if (strcmp(retType, "void")) {
567             printf("    xdr_%s(__xdrs__, &(%s)); \n", retType, retVar);
568             printf("    return(%s);\n", retVar);
569         }
570     }
571     printf("}\n\n");
572 }
573
574 void remoteFunc::genStub(char *className, Boolean forUpcalls)
575 {
576     if (forUpcalls && (upcall == notUpcall)) return;
577     if (!forUpcalls && (upcall != notUpcall)) return;
578
579     printf("\n");
580     if (generateXDR) {
581         genXDRStub(className);
582     } else if (generateTHREAD) {
583         genThreadStub(className);
584     }
585 }
586
587 void remoteFunc::genHeader()
588 {
589     List<char *> cl;
590     List<argument*> lp;
591
592     printf("struct %s {\n", structName);
593     for (lp = args; *lp; lp++) {
594         printf("    %s ", (*lp)->type);
595         for (cl = *(*lp)->stars; *cl; cl++) printf("*");
596         printf("%s", (*lp)->name);
597         printf(";\n");
598     }
599     printf("};\n\n");
600
601     printf("#define %s_%s_REQ %d\n", spec->getName(),name, spec->getNextTag());
602     printf("#define %s_%s_RESP %d\n", spec->getName(), name,spec->getNextTag());
603 }
604
605 void typeDefn::genHeader()
606 {
607     List<field*> fp;
608
609     printf("#ifndef %s_TYPE\n", name);
610     printf("#define %s_TYPE\n", name);
611     printf("class %s {  \npublic:\n", name);
612     if (arrayType) {
613         printf("    int count;\n");
614         printf("    %s* data;\n", type);
615     } else {
616         for (fp = fields; *fp; fp++) {
617             (*fp)->genHeader();
618         }
619     }
620     printf("};\n\n");
621     printf("#endif\n");
622
623     if (generateXDR) {
624         if (userDefined) printf("extern xdr_%s(XDR*, %s*);\n", name, name);
625     }
626 }
627
628
629 void typeDefn::genBundler()
630 {
631     List<field*> fp;
632
633     if (!userDefined) return;
634
635     printf("bool_t xdr_%s(XDR *__xdrs__, %s *__ptr__) {\n", name, name);
636     if (arrayType) {
637         printf("if (__xdrs__->x_op == XDR_DECODE) __ptr__->data = NULL;\n");
638         printf("    xdr_array(__xdrs__, &(__ptr__->data), &__ptr__->count, ~0, sizeof(%s), xdr_%s);\n",
639             type, type);
640     } else {
641         for (fp = fields; *fp; fp++) {
642             (*fp)->genBundler();
643         }
644     }
645     printf("    return(TRUE);\n");
646     printf("}\n\n");
647 }
648
649
650 char *findAndAddArrayType(char *name) 
651 {
652     typeDefn *s;
653     char temp[80];
654     char *arrayTypeName;
655
656     // now find the associated array type.
657     sprintf(temp, "%s_Array", name);
658     arrayTypeName = pool.findAndAdd(temp);
659     if (!types.find(arrayTypeName)) {
660         s = new typeDefn(arrayTypeName, name);
661         s->genHeader();
662     }
663     return arrayTypeName;
664 }
665
666 void interfaceSpec::genClass()
667 {
668     List <remoteFunc *> curr; 
669
670     printf("class %sUser: public RPCUser, public %s {\n", name, transportBase);
671     printf("  public:\n");
672     if (generateXDR) {
673         printf("    virtual void verifyProtocolAndVersion();\n");
674         printf("    %sUser(int fd, xdrIOFunc r, xdrIOFunc w);\n", name);
675         printf("    %sUser(char *,char *,char*, xdrIOFunc r, xdrIOFunc w);\n", 
676                 name);
677     }
678     printf("    void awaitResponce(int);\n");
679     printf("    int isValidUpCall(int);\n");
680
681     for (curr = methods; *curr; curr++) {
682         printf("    ");
683         (*curr)->genMethodHeader(NULL);
684         printf(";\n");
685     }
686     printf("};\n");
687
688
689     printf("class %s: private RPCServer, public %s {\n", name, transportBase);
690     printf("  public:\n");
691     printf("    mainLoop(void);\n");
692     for (curr = methods; *curr; curr++) {
693         printf("    ");
694         (*curr)->genMethodHeader(NULL);
695         printf(";\n");
696     }
697     printf("};\n\n");
698 }