Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
e49c7af452be776a76588182ed25c76f9744f6bc
[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     DEBUG2("Parse the statement \"%s%s;\"",
132            gras_ddt_parse_text,
133            definition+gras_ddt_parse_col_pos);
134     definition[colon_pos] = ';';
135   }
136
137   if(gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_WORD) {
138     ERROR2("Unparsable symbol: found a typeless statement (got '%s' instead). Definition was:\n%s",
139            gras_ddt_parse_text, definition);
140     gras_abort();
141   }
142
143   /**** get the type modifier of this statement ****/
144   parse_type_modifier(&tm);
145
146   /*  FIXME: This does not detect recursive definitions at all? */
147   if (tm.is_union || tm.is_enum || tm.is_struct) {
148     ERROR1("Cannot handle recursive type definition yet. Definition was:\n%s",
149            definition);
150     gras_abort();
151   }
152
153   /**** get the base type, giving "short a" the needed love ****/
154   if (!tm.is_union &&
155       !tm.is_enum  && 
156       !tm.is_struct &&
157
158       (tm.is_short || tm.is_long || tm.is_unsigned) &&
159
160       strcmp(gras_ddt_parse_text,"char") && 
161       strcmp(gras_ddt_parse_text,"float") && 
162       strcmp(gras_ddt_parse_text,"double") && 
163       strcmp(gras_ddt_parse_text,"int") ) {
164
165     /* bastard user, they omited "int" ! */
166     identifier.type_name=strdup("int");
167     DEBUG0("the base type is 'int', which were omited");
168   } else {
169     identifier.type_name=strdup(gras_ddt_parse_text);
170     DEBUG1("the base type is '%s'",identifier.type_name);
171     gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump(); 
172   }
173
174   /**** build the base type for latter use ****/
175   if (tm.is_union) {
176     ERROR1("Cannot handle union yet (need annotation to get the callback). Definition was:\n%s",
177             definition);
178     gras_abort();
179
180   } else if (tm.is_enum) {
181     ERROR1("Cannot handle enum yet. Definition was:\n%s",
182            definition);
183     gras_abort();
184
185   } else if (tm.is_struct) {
186     sprintf(buffname,"struct %s",identifier.type_name);
187     identifier.type = gras_datadesc_by_name(buffname);
188     if (!identifier.type) {
189       TRY(gras_datadesc_declare_struct(buffname,&identifier.type));
190     }
191
192   } else if (tm.is_unsigned) {
193     if (!strcmp(identifier.type_name,"int")) {
194       if (tm.is_long == 2) {
195         identifier.type = gras_datadesc_by_name("unsigned long long int");
196       } else if (tm.is_long) {
197         identifier.type = gras_datadesc_by_name("unsigned long int");
198       } else if (tm.is_short) {
199         identifier.type = gras_datadesc_by_name("unsigned short int");
200       } else {
201         identifier.type = gras_datadesc_by_name("unsigned int");
202       }
203
204     } else if (!strcmp(identifier.type_name, "char")) {
205       identifier.type = gras_datadesc_by_name("unsigned char");
206
207     } else { /* impossible, gcc parses this shit before us */
208       RAISE_IMPOSSIBLE;
209     }
210     
211   } else if (!strcmp(identifier.type_name, "float")) {
212     /* no modificator allowed by gcc */
213     identifier.type = gras_datadesc_by_name("float");
214
215   } else if (!strcmp(identifier.type_name, "double")) {
216     if (tm.is_long) {
217       ERROR0("long double not portable and thus not handled");
218       gras_abort();
219     }
220     identifier.type = gras_datadesc_by_name("double");
221
222   } else { /* signed integer elemental */
223     if (!strcmp(identifier.type_name,"int")) {
224       if (tm.is_long == 2) {
225         identifier.type = gras_datadesc_by_name("signed long long int");
226       } else if (tm.is_long) {
227         identifier.type = gras_datadesc_by_name("signed long int");
228       } else if (tm.is_short) {
229         identifier.type = gras_datadesc_by_name("signed short int");
230       } else {
231         identifier.type = gras_datadesc_by_name("int");
232       }
233
234     } else if (!strcmp(identifier.type_name, "char")) {
235       identifier.type = gras_datadesc_by_name("char");
236
237     } else { /* impossible */
238       ERROR3("The Impossible did happen at %d:%d of :\n%s",
239              gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,definition);
240       gras_abort();
241     }
242     
243   } 
244
245   if (tm.is_ref) {
246     ERROR1("Cannot handle references yet (need annotations), sorry. Definition was:\n%s",
247            definition);
248     gras_abort();
249     /* Should build ref on the current identifier.type (beware of int****) */
250   }
251   
252   /**** look for the symbols of this type ****/
253   for(expect_id_separator = 0;
254
255       ((gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_EMPTY) &&
256        (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_SEMI_COLON)) ; 
257
258       gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump()          ) {   
259
260     if(expect_id_separator) {
261       if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_COLON) {
262         expect_id_separator = 0;
263         continue;
264
265       } else if (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_LB) {
266         /* Handle fixed size arrays */
267         gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
268         if (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_RB) {
269           ERROR3("Cannot dynamically sized array at %d:%d of %s",
270                  gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,
271                  definition);
272           gras_abort();
273         } else if (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) {
274           char *end;
275           long int size=strtol(gras_ddt_parse_text, &end, 10);
276           identifier_t array;
277
278           if (end == gras_ddt_parse_text ||
279               *end != '\0') {
280             ERROR4("Unparsable size of array at %d:%d of %s. Found '%c', expected '\\0'",
281                    gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,
282                    definition,*end);
283             gras_abort();
284           }
285           /* replace the previously pushed type to an array of it */
286           gras_dynar_pop(*dynar,&identifier.type);
287           array.type_name=malloc(strlen(identifier.type->name)+20);
288           DEBUG2("Array specification (size=%ld, elm='%s'), change pushed type",
289                  size,identifier.type_name);
290           sprintf(array.type_name,"%s[%ld]",identifier.type_name,size);
291           free(identifier.type_name);
292           array.type = gras_datadesc_by_name(array.type_name);
293           if (array.type==NULL) {
294             TRY(gras_datadesc_declare_array_fixed(array.type_name,
295                                                   identifier.type,
296                                                   size, &array.type));
297           }
298           array.name = identifier.name;
299           TRY(gras_dynar_push(*dynar,&array));
300
301           /* eat the closing bracket */
302           gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
303           if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_RB) {
304             ERROR3("Unparsable size of array at %d:%d of %s",
305                    gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,
306                    definition);
307             gras_abort();
308           }
309         DEBUG1("Fixed size array, size=%d",size);
310         continue;
311         } else {
312           ERROR3("Unparsable size of array at %d:%d of %s",
313                  gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,
314                  definition);
315           gras_abort();
316         }
317       } else {
318         ERROR2("Unparsable symbol: Expected a comma (','), got '%s' instead. Definition was:\n%s",
319                 gras_ddt_parse_text, definition);
320         gras_abort();
321       }
322     } else if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_COLON) {
323       ERROR1("Unparsable symbol: Unexpected comma (','). Definition was:\n%s",
324              definition);
325       gras_abort();
326     }
327
328     if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_STAR) {
329       starred = 1;
330     }
331
332     /* found a symbol name. Build the type and push it to dynar */
333     if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) {
334       if (starred) {
335         /* FIXME: Build a ref or array on the base type */
336         ERROR1("Cannot handle references yet (need annotations), sorry. Definition was:\n%s",
337                definition);
338         gras_abort();
339       }
340       identifier.name=strdup(gras_ddt_parse_text);
341       DEBUG1("Found the identifier \"%s\"",identifier.name);
342       
343       TRY(gras_dynar_push(*dynar, &identifier));
344       starred = 0;
345       expect_id_separator = 1;
346       continue;
347     } 
348
349     ERROR3("Unparasable symbol (maybe a def struct in a def struct or so) at %d:%d of\n%s",
350            gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,
351            definition);
352     gras_abort();
353   }
354
355   DEBUG0("End of this statement");
356   return no_error;
357 }
358
359 static gras_datadesc_type_t *parse_struct(char *definition) {
360
361   gras_error_t errcode;
362   char buffname[32];
363   static int anonymous_struct=0;
364
365   gras_dynar_t *fields;
366
367   identifier_t field;
368   int i;
369
370   gras_datadesc_type_t *struct_type;
371
372   errcode=gras_dynar_new(&fields,sizeof(identifier_t),NULL);
373   if (errcode != no_error) 
374     return NULL;
375
376   /* Create the struct descriptor */
377   if (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) {
378     TRYFAIL(gras_datadesc_declare_struct(gras_ddt_parse_text,&struct_type));
379     DEBUG1("Parse the struct '%s'", gras_ddt_parse_text);
380     gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
381   } else {
382     sprintf(buffname,"anonymous struct %d",anonymous_struct++); 
383     DEBUG1("Parse the anonymous struct nb %d", anonymous_struct);
384     TRYFAIL(gras_datadesc_declare_struct(buffname,&struct_type));
385   }
386
387   if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_LP) {
388     ERROR2("Unparasable symbol: Expecting struct definition, but got %s instead of '{'. The definition was:\n%s",
389             gras_ddt_parse_text,definition);
390     gras_abort();
391   }
392
393   /* Parse the fields */
394   for (errcode=parse_statement(definition,&fields);
395        errcode == no_error                            ;
396        errcode=parse_statement(definition,&fields)) {
397     
398     DEBUG1("This statement contained %d fields",gras_dynar_length(fields));
399     gras_dynar_foreach(fields,i, field) {
400       DEBUG1("Append field %s",field.name);      
401       TRYFAIL(gras_datadesc_declare_struct_append(struct_type,field.name,
402                                                   field.type));
403       free(field.name);
404       free(field.type_name);
405     }
406   }
407   gras_datadesc_declare_struct_close(struct_type);
408   if (errcode != mismatch_error)
409     return NULL; /* FIXME: LEAK! */
410
411   /* terminates */
412   if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_RP) {
413     ERROR2("Unparasable symbol: Expected '}' at the end of struct definition, got '%s'. The definition was:\n%s",
414            gras_ddt_parse_text,definition);
415     gras_abort();
416   } 
417
418   gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
419
420   gras_dynar_free(fields);
421   return struct_type;
422 }
423
424 static gras_datadesc_type_t * parse_typedef(char *definition) {
425
426   type_modifier_t tm;
427
428   gras_datadesc_type_t *struct_desc=NULL;
429   gras_datadesc_type_t *typedef_desc=NULL;
430
431   memset(&tm,0,sizeof(tm));
432
433   /* get the aliased type */
434   parse_type_modifier(&tm);
435
436   if (tm.is_struct) {
437     struct_desc = parse_struct(definition);
438   }
439
440   parse_type_modifier(&tm);
441
442   if (tm.is_ref) {
443     ERROR1("Cannot handle reference without annotation. Definition was:\n%s",
444            definition);
445     gras_abort();
446   }    
447
448   /* get the aliasing name */
449   if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_WORD) {
450     ERROR2("Unparsable typedef: Expected the alias name, and got '%s'.\n%s",
451            gras_ddt_parse_text,definition);
452     gras_abort();
453   }
454   
455   /* (FIXME: should) build the alias */
456   ERROR1("Cannot handle typedef yet. Definition was: \n%s",definition);
457   gras_abort();
458
459   //  identifier.type=gras_ddt_type_new_typedef(bag, NULL, strdup(gras_ddt_parse_text) );
460   
461   return typedef_desc;
462 }
463
464
465 /**
466  * gras_datadesc_declare_parse:
467  *
468  * Create a datadescription from the result of parsing the C type description
469  */
470 gras_datadesc_type_t *
471 gras_datadesc_parse(const char            *name,
472                     const char            *C_statement) {
473
474   gras_datadesc_type_t * res=NULL;
475   char *definition;
476   int semicolon_count=0;
477   int def_count,C_count;
478   /* reput the \n in place for debug */
479   for (C_count=0; C_statement[C_count] != '\0'; C_count++)
480     if (C_statement[C_count] == ';' || C_statement[C_count] == '{')
481       semicolon_count++;
482   definition = malloc(C_count + semicolon_count + 1);
483   for (C_count=0,def_count=0; C_statement[C_count] != '\0'; C_count++) {
484     definition[def_count++] = C_statement[C_count];
485     if (C_statement[C_count] == ';' || C_statement[C_count] == '{') {
486       definition[def_count++] = '\n';
487     }
488   }
489   definition[def_count] = '\0';
490
491   /* init */ 
492   VERB1("_gras_ddt_type_parse(%s)",definition);
493   gras_ddt_parse_pointer_string_init(definition);
494
495   /* Do I have a typedef, or a raw struct ?*/
496   gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
497   
498   if ((gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) && (!strcmp(gras_ddt_parse_text,"struct"))) {
499     gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
500     res = parse_struct(definition);
501       
502   } else if ((gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) && (!strcmp(gras_ddt_parse_text,"typedef"))) {
503     gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
504     res = parse_typedef(definition);
505
506   } else {
507     ERROR1("Failed to parse the following symbol (not a struct neither a typedef) :\n%s",definition);    
508     gras_abort();
509   }
510
511   gras_ddt_parse_pointer_string_close();
512   VERB0("end of _gras_ddt_type_parse()");
513   free(definition);
514   /* register it under the name provided as symbol */
515   if (strcmp(res->name,name)) {
516     ERROR2("In GRAS_DEFINE_TYPE, the provided symbol (here %s) must be the C type name (here %s)",
517            name,res->name);
518     gras_abort();
519   }    
520   return res;
521 }
522
523