| |
| |
| |
| |
| |
| |
| #include <stdio.h> |
| |
| #include <cparser/ast/ast_t.h> |
| #include <cparser/ast/type.h> |
| #include <cparser/ast/type_t.h> |
| #include <cparser/ast/entity_t.h> |
| #include <cparser/ast/symbol_t.h> |
| |
| #include <apimagic/apimagic.h> |
| #include "apimagic_driver_impl.h" |
| |
| static int output_string( |
| FILE * fout, |
| const char * fmt, |
| const char * string, |
| const char * brace, |
| int * len) |
| { |
| int ret = fout |
| ? fprintf(fout,fmt,string,brace) |
| : snprintf(0,0,fmt,string,brace); |
| |
| if (len && (ret > 0)) |
| *len += ret; |
| |
| return ret; |
| } |
| |
| static int output_compound( |
| union entity_t const * entity, |
| int depth, |
| const struct amgc_layout * layout, |
| FILE * fout) |
| { |
| struct compound_t const * compound; |
| type_qualifiers_t tquals; |
| union entity_t const * subentity; |
| const union type_t * type; |
| const struct declaration_t * decl; |
| const char * fmt; |
| const char * name; |
| const char * brace; |
| bool ftabs; |
| bool fspace; |
| int len; |
| int width; |
| int ptrdepth; |
| int symwidth; |
| int i; |
| |
| if (entity->base.symbol && (depth == 0)) { |
| name = entity->base.symbol->string; |
| brace = " {"; |
| } else { |
| name = ""; |
| brace = "{"; |
| } |
| |
| compound = 0; |
| |
| if (entity->kind == ENTITY_STRUCT) |
| fmt = "struct %s%s\n"; |
| else if (entity->kind == ENTITY_UNION) |
| fmt = "union %s%s\n"; |
| else if (entity->kind != ENTITY_COMPOUND_MEMBER) |
| return -1; |
| else if (entity->declaration.type->kind == TYPE_COMPOUND_STRUCT) |
| fmt = "struct %s%s\n"; |
| else if (entity->declaration.type->kind == TYPE_COMPOUND_UNION) |
| fmt = "union %s%s\n"; |
| else if (entity->declaration.type->kind == TYPE_POINTER) { |
| type = entity->declaration.type; |
| |
| for (; type->kind == TYPE_POINTER; ) |
| type = type->pointer.points_to; |
| |
| compound = type->compound.compound; |
| entity = compound->members.first_entity; |
| |
| if (type->kind == TYPE_COMPOUND_STRUCT) |
| fmt = "struct %s%s\n"; |
| else if (type->kind == TYPE_COMPOUND_UNION) |
| fmt = "union %s%s\n"; |
| else |
| return -1; |
| } else |
| return -1; |
| |
| |
| if (compound) |
| (void)0; |
| else if (entity->kind == ENTITY_COMPOUND_MEMBER) { |
| compound = entity->declaration.type->compound.compound; |
| entity = compound->members.first_entity; |
| } else { |
| compound = &entity->compound; |
| entity = compound->members.first_entity; |
| } |
| |
| |
| if (depth && fout && (fputc('\n',fout) < 0)) |
| return -1; |
| |
| for (i=0; i<depth; i++) |
| if (output_string(fout,"\t","","",0) < 0) |
| return -1; |
| |
| if (output_string(fout,fmt,name,brace,&len) < 0) |
| return -1; |
| |
| |
| for (width=0,depth++; entity; entity=entity->base.next) { |
| type = entity->declaration.type; |
| len = 0; |
| |
| while (type->kind == TYPE_ARRAY) |
| type = type->array.element_type; |
| |
| for (ptrdepth=0; type->kind==TYPE_POINTER; ptrdepth++) |
| type = type->pointer.points_to; |
| |
| tquals = type->base.qualifiers; |
| ftabs = true; |
| |
| switch (type->kind) { |
| case TYPE_TYPEDEF: |
| fmt = "%s "; |
| name = type->typedeft.typedefe->base.symbol->string; |
| break; |
| |
| case TYPE_ATOMIC: |
| fmt = "%s "; |
| name = get_atomic_kind_name(type->atomic.akind); |
| break; |
| |
| case TYPE_COMPOUND_STRUCT: |
| case TYPE_COMPOUND_UNION: |
| compound = type->compound.compound; |
| subentity = compound->members.first_entity; |
| decl = type->typedeft.typedefe; |
| |
| if (!subentity || decl->base.symbol) { |
| name = decl->base.symbol->string; |
| fmt = (type->kind == TYPE_COMPOUND_STRUCT) |
| ? "struct %s " : "union %s "; |
| } else { |
| ftabs = false; |
| name = ""; |
| fmt = ""; |
| |
| if (output_compound( |
| entity,depth, |
| layout,fout) < 0) |
| return -1; |
| } |
| |
| break; |
| |
| case TYPE_VOID: |
| fmt = "%s "; |
| name = "void"; |
| break; |
| |
| default: |
| fmt = ""; |
| name = ""; |
| |
| if (fout) |
| fprintf(fout,"UNHANDLED TYPE! %d ", |
| type->kind); |
| |
| break; |
| } |
| |
| if (ftabs) |
| for (i=0; i<depth; i++) |
| if (output_string(fout,"\t","","",0) < 0) |
| return -1; |
| |
| if (tquals & TYPE_QUALIFIER_CONST) |
| if (output_string(fout,"const ","","",&len) < 0) |
| return -1; |
| |
| if (output_string(fout,fmt,name,"",&len) < 0) |
| return -1; |
| |
| for (fspace=ptrdepth; ptrdepth; ptrdepth--) { |
| type = entity->declaration.type; |
| |
| while (type->kind == TYPE_ARRAY) |
| type = type->array.element_type; |
| |
| for (i=0; i<ptrdepth; i++) |
| type = type->pointer.points_to; |
| |
| if (type->base.qualifiers & TYPE_QUALIFIER_CONST) |
| if (type->kind == TYPE_POINTER) |
| if (output_string(fout," const ", |
| "","",&len) < 0) |
| return -1; |
| |
| if (output_string(fout,"*","","",&len) < 0) |
| return -1; |
| } |
| |
| if (fspace) |
| len++; |
| |
| if (fout) { |
| symwidth = layout->symwidth; |
| |
| symwidth += layout->tabwidth; |
| symwidth &= (~(layout->tabwidth-1)); |
| |
| len &= (~(layout->tabwidth-1)); |
| |
| while (len < symwidth) { |
| if (fputc('\t',fout) < 0) |
| return -1; |
| else |
| len += layout->tabwidth; |
| } |
| } else if (len > width) |
| width = len; |
| |
| if (output_string(fout,"%s", |
| entity->base.symbol->string, |
| "",0) < 0) |
| return -1; |
| |
| type = entity->declaration.type; |
| |
| while (fout && type->kind == TYPE_ARRAY) { |
| if (fprintf(fout, |
| type->array.size ? "[%zu]" : "[]", |
| type->array.size) < 0) |
| return -1; |
| |
| type = type->array.element_type; |
| } |
| |
| if (fout && fputs(";\n",fout) < 0) |
| return -1; |
| |
| if (!ftabs && fout && entity->base.next) |
| if (fputc('\n',fout) < 0) |
| return -1; |
| } |
| |
| if (!fout) |
| return width; |
| |
| if (--depth) { |
| for (i=0; i<depth; i++) |
| if (output_string(fout,"\t","","",0) < 0) |
| return -1; |
| |
| if (output_string(fout,"} ","","",0) < 0) |
| return -1; |
| } else { |
| if (output_string(fout,"};\n","","",0) < 0) |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static int output_compound_entity( |
| const struct amgc_unit_ctx * uctx, |
| const struct amgc_entity * aentity, |
| const struct amgc_layout * layout, |
| FILE * fout) |
| { |
| struct amgc_layout elayout; |
| |
| (void)uctx; |
| |
| if (layout && layout->symwidth) |
| return output_compound(aentity->entity,0,layout,fout); |
| |
| if (layout) |
| memcpy(&elayout,layout,sizeof(elayout)); |
| else |
| memset(&elayout,0,sizeof(elayout)); |
| |
| if ((elayout.symwidth = output_compound(aentity->entity,0,layout,0)) < 0) |
| return -1; |
| |
| if (elayout.tabwidth == 0) |
| elayout.tabwidth = AMGC_TAB_WIDTH; |
| |
| if (output_compound(aentity->entity,0,&elayout,fout) < 0) |
| return -1; |
| |
| return 0; |
| } |
| |
| int amgc_output_compound( |
| const struct amgc_unit_ctx * uctx, |
| const struct amgc_entity * aentity, |
| const struct amgc_layout * layout, |
| FILE * fout) |
| { |
| union entity_t const * entity; |
| |
| entity = aentity->entity; |
| |
| if ((entity->kind == ENTITY_STRUCT) || (entity->kind == ENTITY_UNION)) |
| return output_compound_entity(uctx,aentity,layout,fout); |
| else |
| return -1; |
| } |
| |
| int amgc_output_struct( |
| const struct amgc_unit_ctx * uctx, |
| const struct amgc_entity * aentity, |
| const struct amgc_layout * layout, |
| FILE * fout) |
| { |
| union entity_t const * entity; |
| |
| entity = aentity->entity; |
| |
| if (entity->kind == ENTITY_STRUCT) |
| return output_compound_entity(uctx,aentity,layout,fout); |
| else |
| return -1; |
| } |
| |
| int amgc_output_union( |
| const struct amgc_unit_ctx * uctx, |
| const struct amgc_entity * aentity, |
| const struct amgc_layout * layout, |
| FILE * fout) |
| { |
| union entity_t const * entity; |
| |
| entity = aentity->entity; |
| |
| if (entity->kind == ENTITY_UNION) |
| return output_compound_entity(uctx,aentity,layout,fout); |
| else |
| return -1; |
| } |
| |
| int amgc_output_unit_structs( |
| const struct amgc_unit_ctx * uctx, |
| const struct amgc_layout * layout, |
| FILE * fout) |
| { |
| const struct amgc_entity * aentity; |
| |
| for (aentity=uctx->entities->structs; aentity->entity; aentity++) |
| if (output_compound_entity(uctx,aentity,layout,fout)) |
| return -1; |
| |
| return 0; |
| } |
| |
| int amgc_output_unit_unions( |
| const struct amgc_unit_ctx * uctx, |
| const struct amgc_layout * layout, |
| FILE * fout) |
| { |
| const struct amgc_entity * aentity; |
| |
| for (aentity=uctx->entities->unions; aentity->entity; aentity++) |
| if (output_compound_entity(uctx,aentity,layout,fout)) |
| return -1; |
| |
| return 0; |
| } |