3 /* DataDesc/ddt_parse.c -- automatic parsing of data structures */
5 /* Authors: Arnaud Legrand, Martin Quinson */
6 /* Copyright (C) 2003, 2004 Martin Quinson. */
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. */
11 #include "DataDesc/datadesc_private.h"
12 #include "DataDesc/ddt_parse.yy.h"
14 GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(parse,datadesc);
16 typedef struct s_type_modifier{
28 typedef struct s_field {
29 gras_datadesc_type_t *type;
34 extern char *gras_ddt_parse_text; /* text being considered in the parser */
37 static void parse_type_modifier(type_modifier_t *type_modifier);
38 static void print_type_modifier(type_modifier_t type_modifier);
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);
46 static void parse_type_modifier(type_modifier_t *type_modifier) {
47 DEBUG0("Parse the modifiers");
49 if (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_STAR) {
50 DEBUG0("This is a reference");
51 type_modifier->is_ref++;
53 } else if (!strcmp(gras_ddt_parse_text,"unsigned")) {
54 DEBUG0("This is an unsigned");
55 type_modifier->is_unsigned = 1;
57 } else if (!strcmp(gras_ddt_parse_text,"short")) {
58 DEBUG0("This is short");
59 type_modifier->is_short = 1;
61 } else if (!strcmp(gras_ddt_parse_text,"long")) {
62 DEBUG0("This is long");
63 type_modifier->is_long++; /* handle "long long" */
65 } else if (!strcmp(gras_ddt_parse_text,"struct")) {
66 DEBUG0("This is a struct");
67 type_modifier->is_struct = 1;
69 } else if (!strcmp(gras_ddt_parse_text,"union")) {
70 DEBUG0("This is an union");
71 type_modifier->is_union = 1;
73 } else if (!strcmp(gras_ddt_parse_text,"enum")) {
74 DEBUG0("This is an enum");
75 type_modifier->is_enum = 1;
78 DEBUG1("Done with modifiers (got %s)",gras_ddt_parse_text);
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);
91 static void print_type_modifier(type_modifier_t tm) {
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) ");
98 if(tm.is_struct) printf("(struct) ");
99 if(tm.is_enum) printf("(enum) ");
100 if(tm.is_union) printf("(union) ");
102 for (i=0 ; i<tm.is_ref ; i++) printf("(ref) ");
105 static gras_error_t parse_statement(char *definition,
106 gras_dynar_t **dynar) {
107 gras_error_t errcode;
110 identifier_t identifier;
114 int expect_id_separator = 0;
116 gras_dynar_reset(*dynar);
117 memset(&identifier,0,sizeof(identifier));
118 memset(&tm,0,sizeof(tm));
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 */
125 if (GRAS_LOG_ISENABLED(parse,gras_log_priority_debug)) {
127 for (colon_pos = gras_ddt_parse_col_pos;
128 definition[colon_pos] != ';';
130 definition[colon_pos] = '\0';
131 DEBUG2("Parse the statement \"%s%s;\"",
133 definition+gras_ddt_parse_col_pos);
134 definition[colon_pos] = ';';
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);
143 /**** get the type modifier of this statement ****/
144 parse_type_modifier(&tm);
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",
153 /**** get the base type, giving "short a" the needed love ****/
158 (tm.is_short || tm.is_long || tm.is_unsigned) &&
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") ) {
165 /* bastard user, they omited "int" ! */
166 identifier.type_name=strdup("int");
167 DEBUG0("the base type is 'int', which were omited");
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();
174 /**** build the base type for latter use ****/
176 ERROR1("Cannot handle union yet (need annotation to get the callback). Definition was:\n%s",
180 } else if (tm.is_enum) {
181 ERROR1("Cannot handle enum yet. Definition was:\n%s",
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));
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");
201 identifier.type = gras_datadesc_by_name("unsigned int");
204 } else if (!strcmp(identifier.type_name, "char")) {
205 identifier.type = gras_datadesc_by_name("unsigned char");
207 } else { /* impossible, gcc parses this shit before us */
211 } else if (!strcmp(identifier.type_name, "float")) {
212 /* no modificator allowed by gcc */
213 identifier.type = gras_datadesc_by_name("float");
215 } else if (!strcmp(identifier.type_name, "double")) {
217 ERROR0("long double not portable and thus not handled");
220 identifier.type = gras_datadesc_by_name("double");
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");
231 identifier.type = gras_datadesc_by_name("int");
234 } else if (!strcmp(identifier.type_name, "char")) {
235 identifier.type = gras_datadesc_by_name("char");
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);
246 ERROR1("Cannot handle references yet (need annotations), sorry. Definition was:\n%s",
249 /* Should build ref on the current identifier.type (beware of int****) */
252 /**** look for the symbols of this type ****/
253 for(expect_id_separator = 0;
255 ((gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_EMPTY) &&
256 (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_SEMI_COLON)) ;
258 gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump() ) {
260 if(expect_id_separator) {
261 if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_COLON) {
262 expect_id_separator = 0;
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,
273 } else if (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) {
275 long int size=strtol(gras_ddt_parse_text, &end, 10);
278 if (end == gras_ddt_parse_text ||
280 ERROR3("Unparsable size of array at %d:%d of %s",
281 gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,
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,
298 array.name = identifier.name;
299 TRY(gras_dynar_push(*dynar,&array));
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,
309 DEBUG1("Fixed size array, size=%d",size);
312 ERROR3("Unparsable size of array at %d:%d of %s",
313 gras_ddt_parse_line_pos,gras_ddt_parse_char_pos,
318 ERROR2("Unparsable symbol: Expected a comma (','), got '%s' instead. Definition was:\n%s",
319 gras_ddt_parse_text, definition);
322 } else if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_COLON) {
323 ERROR1("Unparsable symbol: Unexpected comma (','). Definition was:\n%s",
328 if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_STAR) {
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) {
335 /* FIXME: Build a ref or array on the base type */
336 ERROR1("Cannot handle references yet (need annotations), sorry. Definition was:\n%s",
340 identifier.name=strdup(gras_ddt_parse_text);
341 DEBUG1("Found the identifier \"%s\"",identifier.name);
343 TRY(gras_dynar_push(*dynar, &identifier));
345 expect_id_separator = 1;
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,
355 DEBUG0("End of this statement");
359 static gras_datadesc_type_t *parse_struct(char *definition) {
361 gras_error_t errcode;
363 static int anonymous_struct=0;
365 gras_dynar_t *fields;
370 gras_datadesc_type_t *struct_type;
372 errcode=gras_dynar_new(&fields,sizeof(identifier_t),NULL);
373 if (errcode != no_error)
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();
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));
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);
393 /* Parse the fields */
394 for (errcode=parse_statement(definition,&fields);
395 errcode == no_error ;
396 errcode=parse_statement(definition,&fields)) {
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,
404 free(field.type_name);
407 gras_datadesc_declare_struct_close(struct_type);
408 if (errcode != mismatch_error)
409 return NULL; /* FIXME: LEAK! */
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);
418 gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
420 gras_dynar_free(fields);
424 static gras_datadesc_type_t * parse_typedef(char *definition) {
428 gras_datadesc_type_t *struct_desc=NULL;
429 gras_datadesc_type_t *typedef_desc=NULL;
431 memset(&tm,0,sizeof(tm));
433 /* get the aliased type */
434 parse_type_modifier(&tm);
437 struct_desc = parse_struct(definition);
440 parse_type_modifier(&tm);
443 ERROR1("Cannot handle reference without annotation. Definition was:\n%s",
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);
455 /* (FIXME: should) build the alias */
456 ERROR1("Cannot handle typedef yet. Definition was: \n%s",definition);
459 // identifier.type=gras_ddt_type_new_typedef(bag, NULL, strdup(gras_ddt_parse_text) );
466 * gras_datadesc_declare_parse:
468 * Create a datadescription from the result of parsing the C type description
470 gras_datadesc_type_t *
471 gras_datadesc_parse(const char *name,
472 const char *C_statement) {
474 gras_datadesc_type_t * res=NULL;
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] == '{')
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';
489 definition[def_count] = '\0';
492 VERB1("_gras_ddt_type_parse(%s)",definition);
493 gras_ddt_parse_pointer_string_init(definition);
495 /* Do I have a typedef, or a raw struct ?*/
496 gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
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);
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);
507 ERROR1("Failed to parse the following symbol (not a struct neither a typedef) :\n%s",definition);
511 gras_ddt_parse_pointer_string_close();
512 VERB0("end of _gras_ddt_type_parse()");
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)",