Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Take the gras.h from the current dir, not the installed one
[simgrid.git] / src / gras / DataDesc / ddt_parse.c
1 /* $Id$ */
2
3 /* DataDesc/ddt_parse.c -- automatic parsing of data structures */
4
5 /* Authors: Arnaud Legrand, Martin Quinson            */
6 /* Copyright (C) 2003, 2004 Martin Quinson.                                 */
7
8 /* This program is free software; you can redistribute it and/or modify it
9    under the terms of the license (GNU LGPL) which comes with this package. */
10
11 #include "DataDesc/datadesc_private.h"
12 #include "DataDesc/ddt_parse.yy.h"
13
14 GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(parse,datadesc);
15
16 typedef struct s_type_modifier{
17   short is_unsigned;
18   short is_short;
19   short is_long;
20
21   short is_struct;
22   short is_union;
23   short is_enum;
24
25   short is_ref;
26 } type_modifier_t;
27
28 typedef struct s_field {
29   gras_datadesc_type_t *type;
30   char *type_name;
31   char *name;
32 } identifier_t;
33  
34 extern char *gras_ddt_parse_text; /* text being considered in the parser */
35
36 /* prototypes */
37 static void parse_type_modifier(type_modifier_t         *type_modifier);
38 static void print_type_modifier(type_modifier_t          type_modifier);
39
40 static gras_error_t parse_statement(char                *definition,
41                                     gras_dynar_t        **dynar);
42 static gras_datadesc_type_t * parse_struct(char *definition);
43 static gras_datadesc_type_t * parse_typedef(char        *definition);
44
45 /* local functions */
46 static void parse_type_modifier(type_modifier_t         *type_modifier)  {
47   DEBUG0("Parse the modifiers");
48   do {
49     if (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_STAR) {
50       DEBUG0("This is a reference");
51       type_modifier->is_ref++;
52       
53     } else if (!strcmp(gras_ddt_parse_text,"unsigned")) {
54       DEBUG0("This is an unsigned");
55       type_modifier->is_unsigned = 1;
56       
57     } else if (!strcmp(gras_ddt_parse_text,"short")) {
58       DEBUG0("This is short");
59       type_modifier->is_short = 1;
60       
61     } else if (!strcmp(gras_ddt_parse_text,"long")) {
62       DEBUG0("This is long");
63       type_modifier->is_long++; /* handle "long long" */
64       
65     } else if (!strcmp(gras_ddt_parse_text,"struct")) {
66       DEBUG0("This is a struct");
67       type_modifier->is_struct = 1;
68       
69     } else if (!strcmp(gras_ddt_parse_text,"union")) {
70       DEBUG0("This is an union");
71       type_modifier->is_union = 1;
72       
73     } else if (!strcmp(gras_ddt_parse_text,"enum")) {
74       DEBUG0("This is an enum");
75       type_modifier->is_enum = 1;
76       
77     } else {
78       DEBUG1("Done with modifiers (got %s)",gras_ddt_parse_text);
79       break;
80     }
81
82     gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
83     if((gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_WORD) && 
84        (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_STAR)) {
85       DEBUG1("Done with modifiers (got %s)",gras_ddt_parse_text);      
86       break;
87     }
88   } while(1);
89 }
90
91 static void print_type_modifier(type_modifier_t tm) {
92   int i;
93
94   if (tm.is_unsigned)             printf("(unsigned) ");
95   if (tm.is_short)                printf("(short) ");
96   for (i=0 ; i<tm.is_long ; i++)  printf("(long) ");
97
98   if(tm.is_struct)                printf("(struct) ");
99   if(tm.is_enum)                  printf("(enum) ");
100   if(tm.is_union)                 printf("(union) ");
101
102   for (i=0 ; i<tm.is_ref ; i++)   printf("(ref) ");
103 }
104
105 static gras_error_t parse_statement(char                *definition,
106                                     gras_dynar_t        **dynar) {
107   gras_error_t errcode;
108   char buffname[512];
109
110   identifier_t identifier;
111   type_modifier_t tm;
112
113   int starred = 0;
114   int expect_id_separator = 0;
115
116   gras_dynar_reset(*dynar);
117   memset(&identifier,0,sizeof(identifier));
118   memset(&tm,0,sizeof(tm));
119     
120   gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
121   if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_RP) {
122     return mismatch_error; /* end of the englobing structure or union */
123   }
124   
125   if (GRAS_LOG_ISENABLED(parse,gras_log_priority_debug)) {
126     int colon_pos;
127     for (colon_pos = gras_ddt_parse_col_pos;
128          definition[colon_pos] != ';';
129          colon_pos++);
130     definition[colon_pos] = '\0';
131     DEBUG3("Parse the statement \"%s%s;\" (col_pos=%d)",
132            gras_ddt_parse_text,
133            definition+gras_ddt_parse_col_pos,
134            gras_ddt_parse_col_pos);
135     definition[colon_pos] = ';';
136   }
137
138   if(gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_WORD) {
139     ERROR2("Unparsable symbol: found a typeless statement (got '%s' instead). Definition was:\n%s",
140            gras_ddt_parse_text, definition);
141     gras_abort();
142   }
143
144   /**** get the type modifier of this statement ****/
145   parse_type_modifier(&tm);
146
147   /*  FIXME: This does not detect recursive definitions at all? */
148   if (tm.is_union || tm.is_enum || tm.is_struct) {
149     ERROR1("Cannot handle recursive type definition yet. Definition was:\n%s",
150            definition);
151     gras_abort();
152   }
153
154   /**** get the base type, giving "short a" the needed love ****/
155   if (!tm.is_union &&
156       !tm.is_enum  && 
157       !tm.is_struct &&
158
159       (tm.is_short || tm.is_long || tm.is_unsigned) &&
160
161       strcmp(gras_ddt_parse_text,"char") && 
162       strcmp(gras_ddt_parse_text,"float") && 
163       strcmp(gras_ddt_parse_text,"double") && 
164       strcmp(gras_ddt_parse_text,"int") ) {
165
166     /* bastard user, they omited "int" ! */
167     identifier.type_name=strdup("int");
168     DEBUG0("the base type is 'int', which were omited");
169   } else {
170     identifier.type_name=strdup(gras_ddt_parse_text);
171     DEBUG1("the base type is '%s'",identifier.type_name);
172     gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump(); 
173   }
174
175   /**** build the base type for latter use ****/
176   if (tm.is_union) {
177     ERROR1("Cannot handle union yet (need annotation to get the callback). Definition was:\n%s",
178             definition);
179     gras_abort();
180
181   } else if (tm.is_enum) {
182     ERROR1("Cannot handle enum yet. Definition was:\n%s",
183            definition);
184     gras_abort();
185
186   } else if (tm.is_struct) {
187     sprintf(buffname,"struct %s",identifier.type_name);
188     identifier.type = gras_datadesc_by_name(buffname);
189     if (!identifier.type) {
190       TRY(gras_datadesc_declare_struct(buffname,&identifier.type));
191     }
192
193   } else if (tm.is_unsigned) {
194     if (!strcmp(identifier.type_name,"int")) {
195       if (tm.is_long == 2) {
196         identifier.type = gras_datadesc_by_name("unsigned long long int");
197       } else if (tm.is_long) {
198         identifier.type = gras_datadesc_by_name("unsigned long int");
199       } else if (tm.is_short) {
200         identifier.type = gras_datadesc_by_name("unsigned short int");
201       } else {
202         identifier.type = gras_datadesc_by_name("unsigned int");
203       }
204
205     } else if (!strcmp(identifier.type_name, "char")) {
206       identifier.type = gras_datadesc_by_name("unsigned char");
207
208     } else { /* impossible, gcc parses this shit before us */
209       RAISE_IMPOSSIBLE;
210     }
211     
212   } else if (!strcmp(identifier.type_name, "float")) {
213     /* no modificator allowed by gcc */
214     identifier.type = gras_datadesc_by_name("float");
215
216   } else if (!strcmp(identifier.type_name, "double")) {
217     if (tm.is_long) {
218       ERROR0("long double not portable and thus not handled");
219       gras_abort();
220     }
221     identifier.type = gras_datadesc_by_name("double");
222
223   } else { /* signed integer elemental */
224     if (!strcmp(identifier.type_name,"int")) {
225       if (tm.is_long == 2) {
226         identifier.type = gras_datadesc_by_name("signed long long int");
227       } else if (tm.is_long) {
228         identifier.type = gras_datadesc_by_name("signed long int");
229       } else if (tm.is_short) {
230         identifier.type = gras_datadesc_by_name("signed short int");
231       } else {
232         identifier.type = gras_datadesc_by_name("int");
233       }
234
235     } else if (!strcmp(identifier.type_name, "char")) {
236       identifier.type = gras_datadesc_by_name("char");
237
238     } else { /* impossible */
239       ERROR3("The Impossible did happen at %d:%d of :\n%s",
240              gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,definition);
241       gras_abort();
242     }
243     
244   } 
245
246   if (tm.is_ref) {
247     ERROR1("Cannot handle references yet (need annotations), sorry. Definition was:\n%s",
248            definition);
249     gras_abort();
250     /* Should build ref on the current identifier.type (beware of int****) */
251   }
252   
253   /**** look for the symbols of this type ****/
254   for(expect_id_separator = 0;
255
256       ((gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_EMPTY) &&
257        (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_SEMI_COLON)) ; 
258
259       gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump()          ) {   
260
261     if(expect_id_separator) {
262       if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_COLON) {
263         expect_id_separator = 0;
264         continue;
265
266       } else if (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_LB) {
267         /* Handle fixed size arrays */
268         gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
269         if (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_RB) {
270           ERROR3("Cannot dynamically sized array at %d:%d of %s",
271                  gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,
272                  definition);
273           gras_abort();
274         } else if (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) {
275           char *end;
276           long int size=strtol(gras_ddt_parse_text, &end, 10);
277           identifier_t array;
278
279           if (end == gras_ddt_parse_text ||
280               *end != '\0') {
281             ERROR4("Unparsable size of array at %d:%d of %s. Found '%c', expected '\\0'",
282                    gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,
283                    definition,*end);
284             gras_abort();
285           }
286           /* replace the previously pushed type to an array of it */
287           gras_dynar_pop(*dynar,&identifier.type);
288           array.type_name=malloc(strlen(identifier.type->name)+20);
289           DEBUG2("Array specification (size=%ld, elm='%s'), change pushed type",
290                  size,identifier.type_name);
291           sprintf(array.type_name,"%s[%ld]",identifier.type_name,size);
292           free(identifier.type_name);
293           array.type = gras_datadesc_by_name(array.type_name);
294           if (array.type==NULL) {
295             TRY(gras_datadesc_declare_array_fixed(array.type_name,
296                                                   identifier.type,
297                                                   size, &array.type));
298           }
299           array.name = identifier.name;
300           TRY(gras_dynar_push(*dynar,&array));
301
302           /* eat the closing bracket */
303           gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
304           if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_RB) {
305             ERROR3("Unparsable size of array at %d:%d of %s",
306                    gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,
307                    definition);
308             gras_abort();
309           }
310         DEBUG1("Fixed size array, size=%ld",size);
311         continue;
312         } else {
313           ERROR3("Unparsable size of array at %d:%d of %s",
314                  gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,
315                  definition);
316           gras_abort();
317         }
318       } else {
319         ERROR2("Unparsable symbol: Expected a comma (','), got '%s' instead. Definition was:\n%s",
320                 gras_ddt_parse_text, definition);
321         gras_abort();
322       }
323     } else if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_COLON) {
324       ERROR1("Unparsable symbol: Unexpected comma (','). Definition was:\n%s",
325              definition);
326       gras_abort();
327     }
328
329     if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_STAR) {
330       starred = 1;
331     }
332
333     /* found a symbol name. Build the type and push it to dynar */
334     if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) {
335       if (starred) {
336         /* FIXME: Build a ref or array on the base type */
337         ERROR1("Cannot handle references yet (need annotations), sorry. Definition was:\n%s",
338                definition);
339         gras_abort();
340       }
341       identifier.name=strdup(gras_ddt_parse_text);
342       DEBUG1("Found the identifier \"%s\"",identifier.name);
343       
344       TRY(gras_dynar_push(*dynar, &identifier));
345       starred = 0;
346       expect_id_separator = 1;
347       continue;
348     } 
349
350     ERROR3("Unparasable symbol (maybe a def struct in a def struct or so) at %d:%d of\n%s",
351            gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,
352            definition);
353     gras_abort();
354   }
355
356   DEBUG0("End of this statement");
357   return no_error;
358 }
359
360 static gras_datadesc_type_t *parse_struct(char *definition) {
361
362   gras_error_t errcode;
363   char buffname[32];
364   static int anonymous_struct=0;
365
366   gras_dynar_t *fields;
367
368   identifier_t field;
369   int i;
370
371   gras_datadesc_type_t *struct_type;
372
373   errcode=gras_dynar_new(&fields,sizeof(identifier_t),NULL);
374   if (errcode != no_error) 
375     return NULL;
376
377   /* Create the struct descriptor */
378   if (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) {
379     TRYFAIL(gras_datadesc_declare_struct(gras_ddt_parse_text,&struct_type));
380     DEBUG1("Parse the struct '%s'", gras_ddt_parse_text);
381     gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
382   } else {
383     sprintf(buffname,"anonymous struct %d",anonymous_struct++); 
384     DEBUG1("Parse the anonymous struct nb %d", anonymous_struct);
385     TRYFAIL(gras_datadesc_declare_struct(buffname,&struct_type));
386   }
387
388   if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_LP) {
389     ERROR2("Unparasable symbol: Expecting struct definition, but got %s instead of '{'. The definition was:\n%s",
390             gras_ddt_parse_text,definition);
391     gras_abort();
392   }
393
394   /* Parse the fields */
395   for (errcode=parse_statement(definition,&fields);
396        errcode == no_error                            ;
397        errcode=parse_statement(definition,&fields)) {
398     
399     DEBUG1("This statement contained %d fields",gras_dynar_length(fields));
400     gras_dynar_foreach(fields,i, field) {
401       DEBUG1("Append field %s",field.name);      
402       TRYFAIL(gras_datadesc_declare_struct_append(struct_type,field.name,
403                                                   field.type));
404       free(field.name);
405       free(field.type_name);
406     }
407   }
408   gras_datadesc_declare_struct_close(struct_type);
409   if (errcode != mismatch_error)
410     return NULL; /* FIXME: LEAK! */
411
412   /* terminates */
413   if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_RP) {
414     ERROR2("Unparasable symbol: Expected '}' at the end of struct definition, got '%s'. The definition was:\n%s",
415            gras_ddt_parse_text,definition);
416     gras_abort();
417   } 
418
419   gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
420
421   gras_dynar_free(fields);
422   return struct_type;
423 }
424
425 static gras_datadesc_type_t * parse_typedef(char *definition) {
426
427   type_modifier_t tm;
428
429   gras_datadesc_type_t *struct_desc=NULL;
430   gras_datadesc_type_t *typedef_desc=NULL;
431
432   memset(&tm,0,sizeof(tm));
433
434   /* get the aliased type */
435   parse_type_modifier(&tm);
436
437   if (tm.is_struct) {
438     struct_desc = parse_struct(definition);
439   }
440
441   parse_type_modifier(&tm);
442
443   if (tm.is_ref) {
444     ERROR1("Cannot handle reference without annotation. Definition was:\n%s",
445            definition);
446     gras_abort();
447   }    
448
449   /* get the aliasing name */
450   if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_WORD) {
451     ERROR2("Unparsable typedef: Expected the alias name, and got '%s'.\n%s",
452            gras_ddt_parse_text,definition);
453     gras_abort();
454   }
455   
456   /* (FIXME: should) build the alias */
457   ERROR1("Cannot handle typedef yet. Definition was: \n%s",definition);
458   gras_abort();
459
460   //  identifier.type=gras_ddt_type_new_typedef(bag, NULL, strdup(gras_ddt_parse_text) );
461   
462   return typedef_desc;
463 }
464
465
466 /**
467  * gras_datadesc_declare_parse:
468  *
469  * Create a datadescription from the result of parsing the C type description
470  */
471 gras_datadesc_type_t *
472 gras_datadesc_parse(const char            *name,
473                     const char            *C_statement) {
474
475   gras_datadesc_type_t * res=NULL;
476   char *definition;
477   int semicolon_count=0;
478   int def_count,C_count;
479   /* reput the \n in place for debug */
480   for (C_count=0; C_statement[C_count] != '\0'; C_count++)
481     if (C_statement[C_count] == ';' || C_statement[C_count] == '{')
482       semicolon_count++;
483   definition = malloc(C_count + semicolon_count + 1);
484   for (C_count=0,def_count=0; C_statement[C_count] != '\0'; C_count++) {
485     definition[def_count++] = C_statement[C_count];
486     if (C_statement[C_count] == ';' || C_statement[C_count] == '{') {
487       definition[def_count++] = '\n';
488     }
489   }
490   definition[def_count] = '\0';
491
492   /* init */ 
493   VERB2("_gras_ddt_type_parse(%s) -> %d chars",definition, def_count);
494   gras_ddt_parse_pointer_string_init(definition);
495
496   /* Do I have a typedef, or a raw struct ?*/
497   gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
498   
499   if ((gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) && (!strcmp(gras_ddt_parse_text,"struct"))) {
500     gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
501     res = parse_struct(definition);
502       
503   } else if ((gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) && (!strcmp(gras_ddt_parse_text,"typedef"))) {
504     gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
505     res = parse_typedef(definition);
506
507   } else {
508     ERROR1("Failed to parse the following symbol (not a struct neither a typedef) :\n%s",definition);    
509     gras_abort();
510   }
511
512   gras_ddt_parse_pointer_string_close();
513   VERB0("end of _gras_ddt_type_parse()");
514   free(definition);
515   /* register it under the name provided as symbol */
516   if (strcmp(res->name,name)) {
517     ERROR2("In GRAS_DEFINE_TYPE, the provided symbol (here %s) must be the C type name (here %s)",
518            name,res->name);
519     gras_abort();
520   }    
521   return res;
522 }
523
524