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 DEBUG3("Parse the statement \"%s%s;\" (col_pos=%d)",
133 definition+gras_ddt_parse_col_pos,
134 gras_ddt_parse_col_pos);
135 definition[colon_pos] = ';';
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);
144 /**** get the type modifier of this statement ****/
145 parse_type_modifier(&tm);
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",
154 /**** get the base type, giving "short a" the needed love ****/
159 (tm.is_short || tm.is_long || tm.is_unsigned) &&
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") ) {
166 /* bastard user, they omited "int" ! */
167 identifier.type_name=strdup("int");
168 DEBUG0("the base type is 'int', which were omited");
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();
175 /**** build the base type for latter use ****/
177 ERROR1("Cannot handle union yet (need annotation to get the callback). Definition was:\n%s",
181 } else if (tm.is_enum) {
182 ERROR1("Cannot handle enum yet. Definition was:\n%s",
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_struct(buffname,&identifier.type));
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");
202 identifier.type = gras_datadesc_by_name("unsigned int");
205 } else if (!strcmp(identifier.type_name, "char")) {
206 identifier.type = gras_datadesc_by_name("unsigned char");
208 } else { /* impossible, gcc parses this shit before us */
212 } else if (!strcmp(identifier.type_name, "float")) {
213 /* no modificator allowed by gcc */
214 identifier.type = gras_datadesc_by_name("float");
216 } else if (!strcmp(identifier.type_name, "double")) {
218 ERROR0("long double not portable and thus not handled");
221 identifier.type = gras_datadesc_by_name("double");
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");
232 identifier.type = gras_datadesc_by_name("int");
235 } else if (!strcmp(identifier.type_name, "char")) {
236 identifier.type = gras_datadesc_by_name("char");
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);
247 ERROR1("Cannot handle references yet (need annotations), sorry. Definition was:\n%s",
250 /* Should build ref on the current identifier.type (beware of int****) */
253 /**** look for the symbols of this type ****/
254 for(expect_id_separator = 0;
256 ((gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_EMPTY) &&
257 (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_SEMI_COLON)) ;
259 gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump() ) {
261 if(expect_id_separator) {
262 if(gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_COLON) {
263 expect_id_separator = 0;
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,
274 } else if (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) {
276 long int size=strtol(gras_ddt_parse_text, &end, 10);
279 if (end == gras_ddt_parse_text ||
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,
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_array_fixed(array.type_name, identifier.type,
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=%ld",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_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_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_struct_append(struct_type, field.name, field.type));
403 free(field.type_name);
406 gras_datadesc_struct_close(struct_type);
407 if (errcode != mismatch_error)
408 return NULL; /* FIXME: LEAK! */
411 if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_RP) {
412 ERROR2("Unparasable symbol: Expected '}' at the end of struct definition, got '%s'. The definition was:\n%s",
413 gras_ddt_parse_text,definition);
417 gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
419 gras_dynar_free(fields);
423 static gras_datadesc_type_t * parse_typedef(char *definition) {
427 gras_datadesc_type_t *struct_desc=NULL;
428 gras_datadesc_type_t *typedef_desc=NULL;
430 memset(&tm,0,sizeof(tm));
432 /* get the aliased type */
433 parse_type_modifier(&tm);
436 struct_desc = parse_struct(definition);
439 parse_type_modifier(&tm);
442 ERROR1("Cannot handle reference without annotation. Definition was:\n%s",
447 /* get the aliasing name */
448 if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_WORD) {
449 ERROR2("Unparsable typedef: Expected the alias name, and got '%s'.\n%s",
450 gras_ddt_parse_text,definition);
454 /* (FIXME: should) build the alias */
455 ERROR1("Cannot handle typedef yet. Definition was: \n%s",definition);
458 // identifier.type=gras_ddt_type_new_typedef(bag, NULL, strdup(gras_ddt_parse_text) );
465 * gras_datadesc_parse:
467 * Create a datadescription from the result of parsing the C type description
469 gras_datadesc_type_t *
470 gras_datadesc_parse(const char *name,
471 const char *C_statement) {
473 gras_datadesc_type_t * res=NULL;
475 int semicolon_count=0;
476 int def_count,C_count;
477 /* reput the \n in place for debug */
478 for (C_count=0; C_statement[C_count] != '\0'; C_count++)
479 if (C_statement[C_count] == ';' || C_statement[C_count] == '{')
481 definition = malloc(C_count + semicolon_count + 1);
482 for (C_count=0,def_count=0; C_statement[C_count] != '\0'; C_count++) {
483 definition[def_count++] = C_statement[C_count];
484 if (C_statement[C_count] == ';' || C_statement[C_count] == '{') {
485 definition[def_count++] = '\n';
488 definition[def_count] = '\0';
491 VERB2("_gras_ddt_type_parse(%s) -> %d chars",definition, def_count);
492 gras_ddt_parse_pointer_string_init(definition);
494 /* Do I have a typedef, or a raw struct ?*/
495 gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
497 if ((gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) && (!strcmp(gras_ddt_parse_text,"struct"))) {
498 gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
499 res = parse_struct(definition);
501 } else if ((gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_WORD) && (!strcmp(gras_ddt_parse_text,"typedef"))) {
502 gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
503 res = parse_typedef(definition);
506 ERROR1("Failed to parse the following symbol (not a struct neither a typedef) :\n%s",definition);
510 gras_ddt_parse_pointer_string_close();
511 VERB0("end of _gras_ddt_type_parse()");
513 /* register it under the name provided as symbol */
514 if (strcmp(res->name,name)) {
515 ERROR2("In GRAS_DEFINE_TYPE, the provided symbol (here %s) must be the C type name (here %s)",