diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/output/amgc_output_compound.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/src/output/amgc_output_compound.c b/src/output/amgc_output_compound.c new file mode 100644 index 0000000..bbc85d9 --- /dev/null +++ b/src/output/amgc_output_compound.c @@ -0,0 +1,300 @@ +/**********************************************************/ +/* apimagic: cparser-based API normalization utility */ +/* Copyright (C) 2015--2016 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.APIMAGIC. */ +/**********************************************************/ + +#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; +} + +int amgc_output_compound( + const struct amgc_unit_ctx * uctx, + const struct amgc_entity * aentity, + const struct amgc_layout * layout, + FILE * fout) +{ + struct amgc_layout elayout; + + 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; +} |