Init basesystem source codes.
[staging/basesystem.git] / otherservice / rpc_library / tool / apidef.y
1 /**
2  * @file apidef.y
3  * @brief RPC tools--API definition file syntax definition and read/front-end processing
4  *
5  */
6
7 /*---------------------------------------------------------------------------*/
8 /* C declarative statement                                                   */
9 /*---------------------------------------------------------------------------*/
10 %{
11 #define YYDEBUG 1
12 #define YYERROR_VERBOSE 1
13
14 #include <stdio.h>
15 #include <stdlib.h>
16
17 /*
18  * YACC to C I/F functions
19  */
20 extern int yylex(void); /* LEX I/F */
21 extern int yyerror(const char *); /* dummy */
22
23 #include "apidef.h"
24
25 /* YACC to C I/F functions */
26 static void AddHeader(const char *header_file);
27 static int push_function_arg(int arg_type, int num_of_bytes,
28            int is_pointer,
29            int is_vararray, int is_array_size,
30            const char *var_type_name,
31            int is_out, const char *var_name);
32 static void process_function(const char *funcname);
33 static void free_string(char *funcname);
34
35 static int var_type;
36 static int num_of_bytes;
37 static int is_pointer;
38 static int in_out;
39 static int is_vararray;
40 static int is_array_size;
41 static char *var_type_name = NULL;
42
43 %}
44
45 /*---------------------------------------------------------------------------*/
46 /* Bison declarations                                                        */
47 /*---------------------------------------------------------------------------*/
48 %union {
49   int ival;
50   char *strval;
51 }
52
53 %token '"'
54 %left ','
55 %left '('
56 %right ')'
57 %left '*'
58 %token '{'
59 %token '}'
60 %token ';'
61 %token '\n'
62 %token <strval> rpc_INCLUDE 257
63 %token <strval> RPC_RESULT 258
64 %token <strval> rpc_NAME_DOT 259
65 %token <strval> rpc_NAME 260
66 %type <strval> funcdefs funcdef args
67 %type <strval> nonvoid_args arg var_type
68 %type <strval> var_primitive_type var_string_type var_user_defined_type
69 /*
70 %token <strval> rpc_OUT
71 */
72 %token <strval> rpc_INOUT 261
73 %token <strval> rpc_CONST 262
74 %token <strval> rpc_VARARRAY 263
75 %token <strval> rpc_ARRAYSIZE 264
76 %token <ival> rpc_NUM 265
77 %token <strval> rpc_VOID 266
78 %token <ival> rpc_CHAR 267
79 %token <ival> rpc_INT 268
80 %token <ival> rpc_SINT 269
81 %token <ival> rpc_UINT 270
82 %token <ival> rpc_INT8 271
83 %token <ival> rpc_INT16 272
84 %token <ival> rpc_INT32 273
85 %token <ival> rpc_INT64 274
86 %token <ival> rpc_UINT8 275
87 %token <ival> rpc_UINT16 276
88 %token <ival> rpc_UINT32 277
89 %token <ival> rpc_UINT64 278
90 %token <ival> rpc_FLOAT 279
91 %token <ival> rpc_DOUBLE 280
92 %token <ival> rpc_STRING 281
93 %token <ival> rpc_USER_DEFINED 282
94 %token <ival> rpc_UNKNOWN 283
95
96 /*---------------------------------------------------------------------------*/
97 /* Grammar rule                                                              */
98 /*---------------------------------------------------------------------------*/
99 %%
100 input:  includes funcdefs
101 ;
102
103 includes:  /* empty input */
104   | includes include
105 ;
106
107 include:  rpc_INCLUDE '<' rpc_NAME_DOT '>'
108   { AddHeader($3); free_string($3); }
109 ;
110
111 funcdefs:  funcdef
112   | funcdefs funcdef
113 ;
114
115 funcdef:  RPC_RESULT rpc_NAME '(' args ')' ';'
116     { process_function($2); free_string($2);}
117 ;
118
119 args:  rpc_VOID
120   | nonvoid_args
121 ;
122
123 nonvoid_args:  arg
124     | nonvoid_args ',' arg
125 ;
126
127 arg:  var_type rpc_NAME
128     {
129       if (push_function_arg(var_type, num_of_bytes, is_pointer,
130           is_vararray, is_array_size,
131           var_type_name, in_out, $2) < 0) {
132         YYERROR;
133       }
134       if (var_type_name) { free_string(var_type_name); }
135       var_type_name = NULL;
136       free_string($2);
137     }
138   | var_type
139     {
140       if (push_function_arg(var_type, num_of_bytes, is_pointer,
141           is_vararray, is_array_size,
142           var_type_name, in_out, NULL) < 0) {
143         YYERROR;
144       }
145       if (var_type_name) { free_string(var_type_name); }
146       var_type_name = NULL;
147     }
148 ;
149
150 /*
151  * Standard IN pointers are not allowed.
152  *   When used as an array address, it is not clear how many bytes to copy.
153  *   ->You are asked to declare the type and pass the address.
154  *   Otherwise, you can simply pass it by value.
155  */
156 var_type:  var_primitive_type /* INT8, .. DOUBLE */
157     { is_pointer = 0; is_vararray = 0; is_array_size = 0; in_out =RPC_IN_ARG; }
158   | var_primitive_type '*' /* OUT INT8 *, ... OUT DOUBLE * */
159     { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_OUT_ARG; }
160   /* if allow primitive IN pointer
161   | rpc_CONST var_primitive_type '*'
162     { is_pointer = 1; in_out = RPC_IN_ARG; }
163   */
164   | var_string_type
165     /* OUT STRING128, ... */
166     { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_OUT_ARG; }
167   | rpc_CONST var_string_type
168     /* IN STRING128, ... */
169     { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_IN_ARG; }
170   | var_user_defined_type
171     { is_pointer = 0; is_vararray = 0; is_array_size = 0; in_out = RPC_IN_ARG; }
172   | var_user_defined_type '*'
173     { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_OUT_ARG; }
174   | rpc_CONST var_user_defined_type '*'
175     { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_IN_ARG; }
176
177   /* INOUT specification */
178   | rpc_INOUT var_string_type
179     /* IN STRING128, ... */
180     { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_INOUT_ARG; }
181   | rpc_INOUT var_user_defined_type '*'
182     { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_INOUT_ARG; }
183
184   /* Variable-length arrays */
185   | rpc_CONST rpc_VARARRAY var_primitive_type '*'
186     { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_IN_ARG; }
187   | rpc_VARARRAY var_primitive_type '*'
188     { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_OUT_ARG; }
189   | rpc_INOUT rpc_VARARRAY var_primitive_type '*'
190     { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_INOUT_ARG; }
191   | rpc_CONST rpc_VARARRAY var_user_defined_type '*'
192     { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_IN_ARG; }
193   | rpc_VARARRAY var_user_defined_type '*'
194     { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_OUT_ARG; }
195   | rpc_INOUT rpc_VARARRAY var_user_defined_type '*'
196     { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_INOUT_ARG; }
197
198   /* Variable length array size */
199   | rpc_ARRAYSIZE var_primitive_type
200     { is_pointer = 0; is_vararray = 0; is_array_size = 1; in_out = RPC_IN_ARG; }
201 ;
202
203 var_primitive_type:
204   rpc_CHAR { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
205   | rpc_INT { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
206   | rpc_SINT { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
207   | rpc_UINT { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
208   | rpc_INT8 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
209   | rpc_UINT8 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
210   | rpc_INT16 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
211   | rpc_UINT16 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
212   | rpc_INT32 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
213   | rpc_UINT32 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
214   | rpc_INT64 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
215   | rpc_UINT64 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
216   | rpc_FLOAT { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
217   | rpc_DOUBLE { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
218 ;
219
220 var_string_type:  rpc_STRING rpc_NUM
221     { var_type = $1; num_of_bytes = $2; var_type_name = NULL; }
222 ;
223
224 var_user_defined_type:  rpc_NAME
225   { var_type = rpc_USER_DEFINED; num_of_bytes = 0; var_type_name = $1; }
226 ;
227
228 %%
229
230 /*---------------------------------------------------------------------------*/
231 /* C additional code                                                         */
232 /*---------------------------------------------------------------------------*/
233 /* Including an older bison results in an error */
234 /*#include "apidef.tab.h"*/
235
236 #include <unistd.h>
237 #include <assert.h>
238 #include <string.h>
239 /*
240  * YACC/Lex interface functions/variables
241  */
242 extern int yydebug; /* for YACC debug */
243 extern int yyparse(void);
244 extern FILE *yyin;
245 extern int yy_flex_debug; /* for FLEX debug */
246 /* my own function to free the buffer flex allocates */
247 extern void free_flex_buffer(void);
248
249 #ifdef DBG_ENABLE
250 char rpc_log_enable;
251 #endif
252
253 /**/
254 static void
255 AddHeader(const char *filename)
256 {
257   ApidefAddHeader(filename);
258 }
259
260 static int
261 push_function_arg(int arg_type, int num_of_bytes, int is_pointer,
262       int is_vararray, int is_array_size,
263       const char *var_type_name, int in_out, const char *var_name)
264 {
265   switch(arg_type) {
266   case rpc_CHAR:
267   case rpc_INT:
268   case rpc_SINT:
269   case rpc_UINT:
270   case rpc_INT8:
271   case rpc_INT16:
272   case rpc_INT32:
273   case rpc_INT64:
274   case rpc_UINT8:
275   case rpc_UINT16:
276   case rpc_UINT32:
277   case rpc_UINT64:
278   case rpc_FLOAT:
279   case rpc_DOUBLE:
280   case rpc_STRING:
281   case rpc_USER_DEFINED:
282     return ApidefPushFunctionArg(arg_type, num_of_bytes, is_pointer,
283             is_vararray, is_array_size,
284             var_type_name, in_out, var_name);
285     break;
286
287   default:
288     return -1;
289     break;
290   }
291 }
292
293 static void
294 process_function(const char *funcname)
295 {
296   ApidefProcessFunction(funcname);
297 }
298
299 static void
300 free_string(char *s)
301 {
302 #ifdef DEBUG
303   fprintf(stderr, "freed %s\n", s);
304 #endif
305   free(s);
306 }
307
308 static void
309 extract_id(const char *filename, char **id)
310 {
311   char *dotapi;
312   char *slash;
313   const char *start;
314
315   if (id == NULL) {
316     return;
317   }
318   dotapi = strrchr(filename, '.');
319   if (dotapi == NULL) {
320     return;
321   }
322   if (strcmp(dotapi, ".api")) {
323     return;
324   }
325
326   slash = strrchr(filename, '/');
327   start = filename;
328   if (slash != NULL) {
329     start = slash + 1;
330   }
331
332   *id = malloc((size_t)(dotapi - start + 1));
333   if (*id == NULL) {
334     return;
335   }
336   strncpy(*id, start, (size_t)(dotapi - start));
337   (*id)[dotapi - start] = '\0';
338 }
339
340 static void
341 usage(const char *prog)
342 {
343   fprintf(stdout,
344     "How to use: %s [CPPFLAGS] ... API definition file name\n",
345     prog);
346   fprintf(stdout, "Examples1: %s XXX.api\n", prog);
347   fprintf(stdout, "Examples2: %s -DSOME_DEFINES XXX.api\n", prog);
348 }
349
350 #define CPP_PROG "cpp"
351 static void free_cpp_argv(char **argv);
352
353 static char **
354 prepare_cpp_argv(int argc, char *argv[])
355 {
356   char **cpp_argv;
357   char **ret;
358
359   cpp_argv = malloc(sizeof(char *) * (long unsigned int)(argc+1));
360   if (cpp_argv == NULL) {
361     return NULL;
362   }
363   memset(cpp_argv, 0, sizeof(char *) * (long unsigned int)(argc+1));
364   ret = cpp_argv;
365
366   cpp_argv[0] = malloc(strlen(CPP_PROG)+1);
367   if (cpp_argv[0] == NULL) {
368     free_cpp_argv(ret);
369     return NULL;
370   }
371   strcpy(cpp_argv[0], CPP_PROG);
372   cpp_argv++;
373
374   for( ; *argv != NULL ; argv++, cpp_argv++) {
375     *cpp_argv = malloc(strlen(*argv)+1);
376     if (*cpp_argv == NULL) {
377       free_cpp_argv(ret);
378       return NULL;
379     }
380     strcpy(*cpp_argv, *argv);
381   }
382   *cpp_argv = NULL;
383   return ret;
384 }
385
386 static void
387 free_cpp_argv(char **argv)
388 {
389   char **orig; orig = argv;
390   while(*argv != NULL) {
391     free(*argv);
392     argv++;
393   }
394   free(orig);
395 }
396
397 /** @ingroup RPCtool
398  * @brief RPCtool main functions
399  *
400  * Perform the following processing.
401  *
402  * - Lexical context analysis of the API definition file(See apidef.y and apidef.l)
403  * - The API function definition read from the definition file is stored in the APIDef class.
404  * - Outputs stub and header files from function definitions stored in APIDef after a successful read
405  */
406 int
407 main(int argc, char *argv[])
408 {
409   int start;
410   char **cpp_argv;
411   int pipefd[2];
412   int pid;
413   int ret;
414
415   if (argc < 2) {
416     usage(argv[0]);
417     return 1;
418   }
419
420   start = 1;
421   yy_flex_debug = 0;
422
423   if (!strcmp(argv[1], "-d")) {
424     yydebug=1;
425     yy_flex_debug = 1;
426     if (argc > 2) {
427       start++;
428     } else {
429       usage(argv[0]);
430       return 1;
431     }
432   }
433
434 #ifdef DBG_ENABLE
435   /*
436    * If the second-to-last argument is a log specification
437    */
438   if ( ( argc >= 2 ) && (!strcmp(argv[argc-2], "-log")) ) {
439     rpc_log_enable = 1;
440   } else {
441     rpc_log_enable = 0;
442   }
443 #endif
444
445   /*
446    * Extract ID from last argument (API definition file name)
447    */
448   {
449     char *moduleid;
450     moduleid = NULL;
451     extract_id(argv[argc-1], &moduleid);
452     if (moduleid == NULL) {
453       fprintf(stdout, "%s: The API definition file name is invalid.\n", argv[0]);
454       usage(argv[0]);
455       return 1;
456     }
457     ApidefDefineId(moduleid);
458     free(moduleid);
459   }
460
461   /*
462    * Preparing options to exec CPPs
463    */
464   cpp_argv = prepare_cpp_argv(argc, argv + start);
465   if (cpp_argv == NULL) {
466     printf("No Memory!\n");
467     return 1;
468   }
469
470 #define PIPE_READ 0
471 #define PIPE_WRITE 1
472
473   if (pipe(pipefd) != 0) {
474     perror("pipe");
475     return 1;
476   }
477
478   pid = fork();
479   if (pid < 0) {/* fork error */
480     close(pipefd[PIPE_READ]);
481     close(pipefd[PIPE_WRITE]);
482     perror("fork");
483     return 1;
484   }
485   if (pid == 0) {/* child process */
486     int must_be_1;
487     /*
488      * force stdout to be pipefd[PIPE_WRITE]
489      */
490     close(pipefd[PIPE_READ]);
491     close(1);
492     must_be_1 = dup(pipefd[PIPE_WRITE]);
493     assert(must_be_1 == 1);
494     close(pipefd[PIPE_WRITE]);
495     /*
496      * invoke C preprocessor with flags
497      */
498     execvp(CPP_PROG, cpp_argv);
499     perror("execvp");
500     exit(0);
501   } else {
502     /*
503      * parent process
504      */
505     int must_be_0;
506     free_cpp_argv(cpp_argv);
507
508     /*
509      * force stdin to be pipefd[PIPE_READ]
510      */
511     close(pipefd[PIPE_WRITE]);
512     close(0);
513     must_be_0 = dup(pipefd[PIPE_READ]);
514     assert(must_be_0 == 0);
515     close(pipefd[PIPE_READ]);
516   }
517
518   ret = yyparse();
519
520   free_flex_buffer();
521
522   if (ret == 0) {/* Parsed successfully */
523     //ApidefListFunctions(1);
524     ApidefMakeStubs();
525   } else {/* Parse error occurred */
526     fputs("The APIs that have been analyzed so far are as follows.\n", stdout);
527     fputs("-----start-----\n", stdout);
528     ApidefListFunctions(0);
529     fputs("------end------\n", stdout);
530     fputs("Check this API definition\n", stdout);
531   }
532   ApidefFreeAllocation();
533
534   return ret;
535 }
536
537 int
538 yyerror(const char *s)
539 {
540   printf("\nError: %s\n", s);
541   return 0;
542 }
543
544 int
545 yywrap()
546 {
547   return 1;
548 }
549
550 static char const *Types[] = {
551   "char",
552   "int",
553   "signed int",
554   "unsigned int",
555   "INT8",
556   "INT16",
557   "INT32",
558   "INT64",
559   "UINT8",
560   "UINT16",
561   "UINT32",
562   "UINT64",
563   "float",
564   "double",
565   "char *",
566 };
567
568 static const int TypeCodes[] = {
569   rpc_CHAR,
570   rpc_INT,
571   rpc_SINT,
572   rpc_UINT,
573   rpc_INT8,
574   rpc_INT16,
575   rpc_INT32,
576   rpc_INT64,
577   rpc_UINT8,
578   rpc_UINT16,
579   rpc_UINT32,
580   rpc_UINT64,
581   rpc_FLOAT,
582   rpc_DOUBLE,
583   rpc_STRING,
584 };
585
586 const char *
587 TypeCodeString(const int code)
588 {
589   int i;
590   int num;
591   num = sizeof(TypeCodes) / sizeof(int);
592
593   for(i = 0 ; i < num ; i++) {
594     if (code == TypeCodes[i]) {
595       return Types[i];
596     }
597   }
598   return NULL;
599 }
600
601 int
602 IsTypeCodeNumeric( const int code )
603 {
604   int i;
605
606   for(i = 0 ; i < sizeof(TypeCodes) / sizeof(TypeCodes[0]) ; i++) {
607     if (TypeCodes[i] == rpc_FLOAT) {
608       break;
609     }
610     if (code == TypeCodes[i]) {
611       return 1;
612     }
613   }
614   return 0;
615 }