/* Parse call to builtin symbol __builtin_va_start, which is the result of * calling va_start(arg, s). Return type depends on second input argument. */ static struct block *parse__builtin_va_start(struct block *block) { const struct typetree *type; struct symbol *sym; struct token param; int is_invalid; consume('('); block = assignment_expression(block); consume(','); param = consume(IDENTIFIER); sym = sym_lookup(&ns_ident, param.strval); type = ¤t_func()->symbol->type; is_invalid = !sym || sym->depth != 1 || !is_function(type); is_invalid = is_invalid || !nmembers(type) || strcmp( get_member(type, nmembers(type) - 1)->name, param.strval); if (is_invalid) { error("Second parameter of va_start must be last function argument."); exit(1); } consume(')'); block->expr = eval__builtin_va_start(block, block->expr); return block; }
void be_exception::GenerateAssignmentOperator (be_ClientImplementation& source) { ostream & os = source.Stream (); DDS_StdString that (""); be_Type * btype; if (nmembers ()) { that = " that"; } os << ScopedName () << " & " << ScopedName () << "::operator = (const " << LocalName () << " &" << that << ")" << nl; os << "{" << nl; UTL_Scope * s = (UTL_Scope*)narrow((long) & UTL_Scope::type_id); assert (s); UTL_ScopeActiveIterator *it; // Iterate through decls for ( it = new UTL_ScopeActiveIterator (s, UTL_Scope::IK_decls); ! it->is_done (); it->next () ) { AST_Decl * adecl = it->item (); assert (adecl); be_field *bfield = (be_field *) adecl->narrow ((long) & be_field::type_id); if (bfield) { btype = bfield->get_be_type (); if (btype && btype->IsArrayType ()) { // Need to copy array elements os << " " << (char*) BE_Globals::RelativeScope (ScopedName (), bfield->StructMemberTypeName ()) << "_copy (" << bfield->get_local_name () << ", that." << bfield->get_local_name () << ");" << nl; } else { os << " " << bfield->get_local_name () << " = that." << bfield->get_local_name() << ";" << nl; } } } delete it; os << " return *this;" << nl; os << "}" << nl << nl; }
/* FOLLOW(parameter-list) = { ')' }, peek to return empty list; even though K&R * require at least specifier: (void) * Set parameter-type-list = parameter-list, including the , ... */ static struct typetree *parameter_list(const struct typetree *base) { struct typetree *func = type_init(T_FUNCTION); func->next = base; while (peek().token != ')') { const char *name = NULL; struct typetree *type; type = declaration_specifiers(NULL); type = declarator(type, &name); if (is_void(type)) { if (nmembers(func)) { error("Incomplete type in parameter list."); } break; } type_add_member(func, name, type); if (peek().token != ',') { break; } consume(','); if (peek().token == ')') { error("Unexpected trailing comma in parameter list."); exit(1); } else if (peek().token == DOTS) { consume(DOTS); assert(!is_vararg(func)); type_add_member(func, "...", NULL); assert(is_vararg(func)); break; } } return func; }
void be_exception::Generate (be_ClientImplementation& source) { ostream & os = source.Stream(); be_Tab tab (source); UTL_String * repID = get_decl_pragmas().get_repositoryID(); const DDS_StdString corbaException = "DDS::Exception"; // convenience constructor if (nmembers()) { GenerateConvenienceConstructor(source); } // copy constructor GenerateCopyConstructor (source); // assignment operator GenerateAssignmentOperator (source); be_CodeGenerator::Generate (source); // name and id assert (repID); os << "const char * " << ScopedName () << "::m_name = \"" << LocalName () << "\";" << nl << nl; os << "const char * " << ScopedName () << "::m_id = \"" << repID->get_string () << "\";" << nl << nl; // downcast os << tab << ScopedName () << " * "; os << ScopedName () << "::"; os << "_downcast (DDS::Exception * e)" << nl; os << tab << "{" << nl; tab.indent (); os << tab << "if (e && (e->_rep_id () == m_id))" << nl; os << tab << "{" << nl; tab.indent (); os << tab << "return static_cast < " << LocalName () << "*> (e);" << nl; tab.outdent (); os << tab << "}" << nl; os << tab << "return 0;" << nl; tab.outdent (); os << tab << "}" << nl << nl; // const downcast os << tab << "const " << ScopedName() << " * "; os << ScopedName () << "::"; os << "_downcast (const DDS::Exception * e)" << nl; os << tab << "{" << nl; tab.indent (); os << tab << "if (e && (e->_rep_id () == m_id))" << nl; os << tab << "{" << nl; tab.indent (); os << tab << "return static_cast < " << LocalName () << "*> ((" << LocalName () << "*) e);" << nl; tab.outdent (); os << tab << "}" << nl; os << tab << "return 0;" << nl; tab.outdent (); os << tab << "}" << nl << nl; // _clone os << tab << corbaException << " * " << ScopedName (); os << "::_clone () const" << nl; os << tab << "{" << nl; tab.indent (); os << tab << "return (" << corbaException << "*) new "; os << ScopedName () << " (*this);" << nl; tab.outdent (); os << tab << "}" << nl << nl; // raise os << tab << "void " << ScopedName () << "::_raise (" << XBE_Ev::arg (XBE_ENV_ARG1) << ") const" << nl; os << tab << "{" << nl; tab.indent (); os << tab; XBE_Ev::throwex (os, "*this"); os << nl; tab.outdent (); os << tab << "}" << nl << nl; // factory os << tab << "DDS::Exception * " << ScopedName() << "::factory ()" << nl; os << tab << "{" << nl; tab.indent (); os << tab << "return new " << ScopedName () << ";" << nl; tab.outdent (); os << tab << "}" << nl << nl; // initilaizer os << "DDS::ExceptionInitializer " << ScopedName() << "::m_initializer ("; os << "\"" << repID->get_string () << "\""; os << ", " << ScopedName () << "::factory);" << nl; }
void be_exception::Generate (be_ClientHeader & source) { if (!Generated ()) { ostream & os = source.Stream (); be_Tab tab (source); DDS_StdString lname = LocalName (); Generated (pbtrue); be_root::AddGlobalDeclarations (this); be_root::AddAnyOps (*this); be_root::AddStreamOps (*this); be_root::AddTypedef (*this); be_root::AddTypecode (*this); GenerateOpenClassDefinition (source); GenerateClassDeclarations (source); SetAccess (source, CA_PUBLIC); // now define nested types be_CodeGenerator::Generate (source); // generate _downcast os << tab << "static " << lname << "* _downcast (" << "DDS::Exception *);" << nl; os << tab << "static const " << lname << "* _downcast (" << "const DDS::Exception *);" << nl; // generate factory and builder os << tab << "static DDS::Exception * factory ();" << nl; os << tab << "static DDS::ExceptionInitializer m_initializer;" << nl << nl; // generate inline default constructor os << tab << lname << " () {};" << nl; // generate convenience constructor if (nmembers()) { GenerateConvenienceConstructor (source); } // generate copy constructor os << tab << lname << " (const " << lname << " &);" << nl; // generate assignment operator os << tab << lname << "& operator = " << "(const " << lname << " &);" << nl; // generate duplicate os << tab << "virtual DDS::Exception * _clone () const;" << nl; // generate raise os << tab << "virtual void _raise (" << XBE_Ev::arg (XBE_ENV_ARG1) << ") const;" << nl; // generate name os << tab << "virtual const char * _name () const { return m_name; };" << nl; // generate repository id os << tab << "virtual const char * _rep_id () const { return m_id; };" << nl; // generate virtual destructor os << tab << "virtual ~" << lname << " () {}" << nl; GenerateMembers (source); SetAccess (source, CA_PRIVATE); os << tab << "static const char * m_name;" << nl; os << tab << "static const char * m_id;" << nl; GenerateCloseClassDefinition (source); be_root::GenerateDependants ( source, SequenceMemberTypeName (), EnclosingScope () ); } }
void be_exception::GenerateConvenienceConstructor (be_ClientImplementation & source) { ostream & os = source.Stream (); const char * argPrefix = "_"; pbbool first = pbtrue; be_Tab tab (source); be_Type * btype; os << ScopedName () << "::" << LocalName () << " ("; UTL_Scope * s = (UTL_Scope*)narrow ((long) & UTL_Scope::type_id); assert (s); // Iterate through decls UTL_ScopeActiveIterator * it; for ( it = new UTL_ScopeActiveIterator (s, UTL_Scope::IK_decls); !it->is_done (); it->next () ) { AST_Decl * adecl = it->item (); assert (adecl); be_field *bfield = (be_field *)adecl->narrow ((long) & be_field::type_id); if (bfield) { btype = bfield->get_be_type (); if (!first) { os << ", "; } first = pbfalse; if (btype && btype->IsStringType ()) { // Strings are special case os << (char*) BE_Globals::RelativeScope (ScopedName (), bfield->InTypeName ()); } else { os << (char*) BE_Globals::RelativeScope (ScopedName (), bfield->StructMemberTypeName ()); } os << " " << argPrefix << (char*) bfield->get_local_name (); } } delete it; os << ")" << nl; // Iterate thru members initializing if (nmembers ()) { source.Indent (); first = pbtrue; for ( it = new UTL_ScopeActiveIterator (s, UTL_Scope::IK_decls); !it->is_done (); it->next () ) { AST_Decl * adecl = it->item (); assert (adecl); be_field *bfield = (be_field *)adecl->narrow ((long) & be_field::type_id); if (bfield) { btype = bfield->get_be_type (); // Array members are assigned in body of method if (btype && ! btype->IsArrayType ()) { if (first) { first = pbfalse; os << " : " << nl; } else { os << "," << nl; } os << " " << (char*) bfield->get_local_name () << "(" << argPrefix << (char*) bfield->get_local_name () << ")"; } } } delete it; source.Outdent (); } os << nl; os << tab << "{" << nl; for ( it = new UTL_ScopeActiveIterator (s, UTL_Scope::IK_decls); ! it->is_done (); it->next () ) { AST_Decl * adecl = it->item (); assert (adecl); be_field *bfield = (be_field *) adecl->narrow ((long) & be_field::type_id); if (bfield) { btype = bfield->get_be_type (); if (btype && btype->IsArrayType ()) { // Need to copy array elements os << " " << (char*) BE_Globals::RelativeScope (ScopedName (), bfield->StructMemberTypeName ()) << "_copy (" << argPrefix << bfield->get_local_name () << ", " << bfield->get_local_name () << ");" << nl; } } } delete it; os << "}" << nl << nl; }
static struct block *postfix_expression(struct block *block) { struct var root; block = primary_expression(block); root = block->expr; while (1) { const struct member *field; const struct typetree *type; struct var expr, copy, *arg; struct token tok; int i, j; switch ((tok = peek()).token) { case '[': do { /* Evaluate a[b] = *(a + b). The semantics of pointer arithmetic * takes care of multiplying b with the correct width. */ consume('['); block = expression(block); root = eval_expr(block, IR_OP_ADD, root, block->expr); root = eval_deref(block, root); consume(']'); } while (peek().token == '['); break; case '(': type = root.type; if (is_pointer(root.type) && is_function(root.type->next)) type = type_deref(root.type); else if (!is_function(root.type)) { error("Expression must have type pointer to function, was %t.", root.type); exit(1); } consume('('); arg = calloc(nmembers(type), sizeof(*arg)); for (i = 0; i < nmembers(type); ++i) { if (peek().token == ')') { error("Too few arguments, expected %d but got %d.", nmembers(type), i); exit(1); } block = assignment_expression(block); arg[i] = block->expr; /* todo: type check here. */ if (i < nmembers(type) - 1) { consume(','); } } while (is_vararg(type) && peek().token != ')') { consume(','); arg = realloc(arg, (i + 1) * sizeof(*arg)); block = assignment_expression(block); arg[i] = block->expr; i++; } consume(')'); for (j = 0; j < i; ++j) param(block, arg[j]); free(arg); root = eval_call(block, root); break; case '.': consume('.'); tok = consume(IDENTIFIER); field = find_type_member(root.type, tok.strval); if (!field) { error("Invalid field access, no member named '%s'.", tok.strval); exit(1); } root.type = field->type; root.offset += field->offset; break; case ARROW: consume(ARROW); tok = consume(IDENTIFIER); if (is_pointer(root.type) && is_struct_or_union(root.type->next)) { field = find_type_member(type_deref(root.type), tok.strval); if (!field) { error("Invalid field access, no member named '%s'.", tok.strval); exit(1); } /* Make it look like a pointer to the field type, then perform * normal dereferencing. */ root.type = type_init(T_POINTER, field->type); root = eval_deref(block, root); root.offset = field->offset; } else { error("Invalid field access."); exit(1); } break; case INCREMENT: consume(INCREMENT); copy = create_var(root.type); eval_assign(block, copy, root); expr = eval_expr(block, IR_OP_ADD, root, var_int(1)); eval_assign(block, root, expr); root = copy; break; case DECREMENT: consume(DECREMENT); copy = create_var(root.type); eval_assign(block, copy, root); expr = eval_expr(block, IR_OP_SUB, root, var_int(1)); eval_assign(block, root, expr); root = copy; break; default: block->expr = root; return block; } } }
/* Cover both external declarations, functions, and local declarations (with * optional initialization code) inside functions. */ struct block *declaration(struct block *parent) { struct typetree *base; enum symtype symtype; enum linkage linkage; int stc = '$'; base = declaration_specifiers(&stc); switch (stc) { case EXTERN: symtype = SYM_DECLARATION; linkage = LINK_EXTERN; break; case STATIC: symtype = SYM_TENTATIVE; linkage = LINK_INTERN; break; case TYPEDEF: symtype = SYM_TYPEDEF; linkage = LINK_NONE; break; default: if (!ns_ident.current_depth) { symtype = SYM_TENTATIVE; linkage = LINK_EXTERN; } else { symtype = SYM_DEFINITION; linkage = LINK_NONE; } break; } while (1) { struct definition *def; const char *name = NULL; const struct typetree *type; struct symbol *sym; type = declarator(base, &name); if (!name) { consume(';'); return parent; } sym = sym_add(&ns_ident, name, type, symtype, linkage); if (ns_ident.current_depth) { assert(ns_ident.current_depth > 1); def = current_func(); def->locals = sym_list_add(def->locals, sym); } switch (peek().token) { case ';': consume(';'); return parent; case '=': if (sym->symtype == SYM_DECLARATION) { error("Extern symbol '%s' cannot be initialized.", sym->name); exit(1); } if (!sym->depth && sym->symtype == SYM_DEFINITION) { error("Symbol '%s' was already defined.", sym->name); exit(1); } consume('='); sym->symtype = SYM_DEFINITION; if (sym->linkage == LINK_NONE) { assert(parent); parent = initializer(parent, var_direct(sym)); } else { assert(sym->depth || !parent); def = push_back_definition(sym); initializer(def->body, var_direct(sym)); } assert(size_of(&sym->type) > 0); if (peek().token != ',') { consume(';'); return parent; } break; case '{': { int i; if (!is_function(&sym->type) || sym->depth) { error("Invalid function definition."); exit(1); } assert(!parent); assert(sym->linkage != LINK_NONE); sym->symtype = SYM_DEFINITION; def = push_back_definition(sym); push_scope(&ns_ident); define_builtin__func__(sym->name); for (i = 0; i < nmembers(&sym->type); ++i) { name = get_member(&sym->type, i)->name; type = get_member(&sym->type, i)->type; symtype = SYM_DEFINITION; linkage = LINK_NONE; if (!name) { error("Missing parameter name at position %d.", i + 1); exit(1); } def->params = sym_list_add(def->params, sym_add(&ns_ident, name, type, symtype, linkage)); } parent = block(def->body); pop_scope(&ns_ident); return parent; } default: break; } consume(','); } }
static struct block *object_initializer(struct block *block, struct var target) { int i, filled = target.offset; const struct typetree *type = target.type; assert(!is_tagged(type)); consume('{'); target.lvalue = 1; switch (type->type) { case T_UNION: /* C89 states that only the first element of a union can be * initialized. Zero the whole thing first if there is padding. */ if (size_of(get_member(type, 0)->type) < type->size) { target.type = (type->size % 8) ? type_init(T_ARRAY, &basic_type__char, type->size) : type_init(T_ARRAY, &basic_type__long, type->size / 8); zero_initialize(block, target); } target.type = get_member(type, 0)->type; block = initializer(block, target); if (peek().token != '}') { error("Excess elements in union initializer."); exit(1); } break; case T_STRUCT: for (i = 0; i < nmembers(type); ++i) { target.type = get_member(type, i)->type; target.offset = filled + get_member(type, i)->offset; block = initializer(block, target); if (peek().token == ',') { consume(','); } else break; if (peek().token == '}') { break; } } while (++i < nmembers(type)) { target.type = get_member(type, i)->type; target.offset = filled + get_member(type, i)->offset; zero_initialize(block, target); } break; case T_ARRAY: target.type = type->next; for (i = 0; !type->size || i < type->size / size_of(type->next); ++i) { target.offset = filled + i * size_of(type->next); block = initializer(block, target); if (peek().token == ',') { consume(','); } else break; if (peek().token == '}') { break; } } if (!type->size) { assert(!target.symbol->type.size); assert(is_array(&target.symbol->type)); /* Incomplete array type can only be in the root level of target * type tree, overwrite type directly in symbol. */ ((struct symbol *) target.symbol)->type.size = (i + 1) * size_of(type->next); } else { while (++i < type->size / size_of(type->next)) { target.offset = filled + i * size_of(type->next); zero_initialize(block, target); } } break; default: error("Block initializer only apply to aggregate or union type."); exit(1); } consume('}'); return block; }
static void member_declaration_list(struct typetree *type) { struct namespace ns = {0}; struct typetree *decl_base, *decl_type; const char *name; push_scope(&ns); do { decl_base = declaration_specifiers(NULL); do { name = NULL; decl_type = declarator(decl_base, &name); if (!name) { error("Missing name in member declarator."); exit(1); } else if (!size_of(decl_type)) { error("Field '%s' has incomplete type '%t'.", name, decl_type); exit(1); } else { sym_add(&ns, name, decl_type, SYM_DECLARATION, LINK_NONE); type_add_member(type, name, decl_type); } if (peek().token == ',') { consume(','); continue; } } while (peek().token != ';'); consume(';'); } while (peek().token != '}'); pop_scope(&ns); } static struct typetree *struct_or_union_declaration(void) { struct symbol *sym = NULL; struct typetree *type = NULL; enum type kind = (next().token == STRUCT) ? T_STRUCT : T_UNION; if (peek().token == IDENTIFIER) { const char *name = consume(IDENTIFIER).strval; sym = sym_lookup(&ns_tag, name); if (!sym) { type = type_init(kind); sym = sym_add(&ns_tag, name, type, SYM_TYPEDEF, LINK_NONE); } else if (is_integer(&sym->type)) { error("Tag '%s' was previously declared as enum.", sym->name); exit(1); } else if (sym->type.type != kind) { error("Tag '%s' was previously declared as %s.", sym->name, (sym->type.type == T_STRUCT) ? "struct" : "union"); exit(1); } /* Retrieve type from existing symbol, possibly providing a complete * definition that will be available for later declarations. Overwrites * existing type information from symbol table. */ type = &sym->type; if (peek().token == '{' && type->size) { error("Redefiniton of '%s'.", sym->name); exit(1); } } if (peek().token == '{') { if (!type) { /* Anonymous structure; allocate a new standalone type, * not part of any symbol. */ type = type_init(kind); } consume('{'); member_declaration_list(type); assert(type->size); consume('}'); } /* Return to the caller a copy of the root node, which can be overwritten * with new type qualifiers without altering the tag registration. */ return (sym) ? type_tagged_copy(&sym->type, sym->name) : type; } static void enumerator_list(void) { struct var val; struct symbol *sym; int enum_value = 0; consume('{'); do { const char *name = consume(IDENTIFIER).strval; if (peek().token == '=') { consume('='); val = constant_expression(); if (!is_integer(val.type)) { error("Implicit conversion from non-integer type in enum."); } enum_value = val.imm.i; } sym = sym_add( &ns_ident, name, &basic_type__int, SYM_ENUM_VALUE, LINK_NONE); sym->enum_value = enum_value++; if (peek().token != ',') break; consume(','); } while (peek().token != '}'); consume('}'); } static struct typetree *enum_declaration(void) { struct typetree *type = type_init(T_SIGNED, 4); consume(ENUM); if (peek().token == IDENTIFIER) { struct symbol *tag = NULL; const char *name = consume(IDENTIFIER).strval; tag = sym_lookup(&ns_tag, name); if (!tag || tag->depth < ns_tag.current_depth) { tag = sym_add(&ns_tag, name, type, SYM_TYPEDEF, LINK_NONE); } else if (!is_integer(&tag->type)) { error("Tag '%s' was previously defined as aggregate type.", tag->name); exit(1); } /* Use enum_value as a sentinel to represent definition, checked on * lookup to detect duplicate definitions. */ if (peek().token == '{') { if (tag->enum_value) { error("Redefiniton of enum '%s'.", tag->name); } enumerator_list(); tag->enum_value = 1; } } else { enumerator_list(); } /* Result is always integer. Do not care about the actual enum definition, * all enums are ints and no type checking is done. */ return type; } static struct typetree get_basic_type_from_specifier(unsigned short spec) { switch (spec) { case 0x0001: /* void */ return basic_type__void; case 0x0002: /* char */ case 0x0012: /* signed char */ return basic_type__char; case 0x0022: /* unsigned char */ return basic_type__unsigned_char; case 0x0004: /* short */ case 0x0014: /* signed short */ case 0x000C: /* short int */ case 0x001C: /* signed short int */ return basic_type__short; case 0x0024: /* unsigned short */ case 0x002C: /* unsigned short int */ return basic_type__unsigned_short; case 0x0008: /* int */ case 0x0010: /* signed */ case 0x0018: /* signed int */ return basic_type__int; case 0x0020: /* unsigned */ case 0x0028: /* unsigned int */ return basic_type__unsigned_int; case 0x0040: /* long */ case 0x0050: /* signed long */ case 0x0048: /* long int */ case 0x0058: /* signed long int */ case 0x00C0: /* long long */ case 0x00D0: /* signed long long */ case 0x00D8: /* signed long long int */ return basic_type__long; case 0x0060: /* unsigned long */ case 0x0068: /* unsigned long int */ case 0x00E0: /* unsigned long long */ case 0x00E8: /* unsigned long long int */ return basic_type__unsigned_long; case 0x0100: /* float */ return basic_type__float; case 0x0200: /* double */ case 0x0240: /* long double */ return basic_type__double; default: error("Invalid type specification."); exit(1); } } /* Parse type, qualifiers and storage class. Do not assume int by default, but * require at least one type specifier. Storage class is returned as token * value, unless the provided pointer is NULL, in which case the input is parsed * as specifier-qualifier-list. */ struct typetree *declaration_specifiers(int *stc) { struct typetree *type = NULL; struct token tok; int done = 0; /* Use a compact bit representation to hold state about declaration * specifiers. Initialize storage class to sentinel value. */ unsigned short spec = 0x0000; enum qualifier qual = Q_NONE; if (stc) *stc = '$'; #define set_specifier(d) \ if (spec & d) error("Duplicate type specifier '%s'.", tok.strval); \ next(); spec |= d; #define set_qualifier(d) \ if (qual & d) error("Duplicate type qualifier '%s'.", tok.strval); \ next(); qual |= d; #define set_storage_class(t) \ if (!stc) error("Unexpected storage class in qualifier list."); \ else if (*stc != '$') error("Multiple storage class specifiers."); \ next(); *stc = t; do { switch ((tok = peek()).token) { case VOID: set_specifier(0x001); break; case CHAR: set_specifier(0x002); break; case SHORT: set_specifier(0x004); break; case INT: set_specifier(0x008); break; case SIGNED: set_specifier(0x010); break; case UNSIGNED: set_specifier(0x020); break; case LONG: if (spec & 0x040) { set_specifier(0x080); } else { set_specifier(0x040); } break; case FLOAT: set_specifier(0x100); break; case DOUBLE: set_specifier(0x200); break; case CONST: set_qualifier(Q_CONST); break; case VOLATILE: set_qualifier(Q_VOLATILE); break; case IDENTIFIER: { struct symbol *tag = sym_lookup(&ns_ident, tok.strval); if (tag && tag->symtype == SYM_TYPEDEF && !type) { consume(IDENTIFIER); type = type_init(T_STRUCT); *type = tag->type; } else { done = 1; } break; } case UNION: case STRUCT: if (!type) { type = struct_or_union_declaration(); } else { done = 1; } break; case ENUM: if (!type) { type = enum_declaration(); } else { done = 1; } break; case AUTO: case REGISTER: case STATIC: case EXTERN: case TYPEDEF: set_storage_class(tok.token); break; default: done = 1; break; } if (type && spec) { error("Invalid combination of declaration specifiers."); exit(1); } } while (!done); #undef set_specifier #undef set_qualifier #undef set_storage_class if (type) { if (qual & type->qualifier) { error("Duplicate type qualifier:%s%s.", (qual & Q_CONST) ? " const" : "", (qual & Q_VOLATILE) ? " volatile" : ""); } } else if (spec) { type = type_init(T_STRUCT); *type = get_basic_type_from_specifier(spec); } else { error("Missing type specifier."); exit(1); } type->qualifier |= qual; return type; } /* Set var = 0, using simple assignment on members for composite types. This * rule does not consume any input, but generates a series of assignments on the * given variable. Point is to be able to zero initialize using normal simple * assignment rules, although IR can become verbose for large structures. */ static void zero_initialize(struct block *block, struct var target) { int i; struct var var; assert(target.kind == DIRECT); switch (target.type->type) { case T_STRUCT: case T_UNION: target.type = unwrapped(target.type); var = target; for (i = 0; i < nmembers(var.type); ++i) { target.type = get_member(var.type, i)->type; target.offset = var.offset + get_member(var.type, i)->offset; zero_initialize(block, target); } break; case T_ARRAY: assert(target.type->size); var = target; target.type = target.type->next; assert(is_struct(target.type) || !target.type->next); for (i = 0; i < var.type->size / var.type->next->size; ++i) { target.offset = var.offset + i * var.type->next->size; zero_initialize(block, target); } break; case T_POINTER: var = var_zero(8); var.type = type_init(T_POINTER, &basic_type__void); eval_assign(block, target, var); break; case T_UNSIGNED: case T_SIGNED: var = var_zero(target.type->size); eval_assign(block, target, var); break; default: error("Invalid type to zero-initialize, was '%t'.", target.type); exit(1); } }