/* %Z%%M% %I% %E% */ /* * Copyright (c) 1992, 1993, 1995 by Wayne C. Gramlich. * All rights reserved. * * Permission to use, copy, modify, distribute, and sell this software * for any purpose is hereby granted without fee provided that the above * copyright notice and this permission are retained. The author makes * no representations about the suitability of this software for any purpose. * It is provided "as is" without express or implied warranty. */ #ifndef ERROR_EXPORTS_H #include "error_exports.h" #endif #ifndef GEN_DEFS_H #include "gen_defs.h" #endif #ifndef GENERATE_EXPORTS_H #include "generate_exports.h" #endif #ifndef HEAP_EXPORTS_H #include "heap_exports.h" #endif #ifndef LINT_H #include "lint.h" #endif #ifndef LIBC_EXPORTS_H #include "libc_exports.h" #endif #ifndef MSG_EXPORTS_H #include "msg_exports.h" #endif #ifndef OBJECT_EXPORTS_H #include "object_exports.h" #endif #ifndef OUT_EXPORTS_H #include "out_exports.h" #endif #ifndef PARSER_EXPORTS_H #include "parser_exports.h" #endif #ifndef ROUTINE_DEFS_H #include "routine_defs.h" #endif #ifndef STR_EXPORTS_H #include "str_exports.h" #endif #ifndef TABLE_EXPORTS_H #include "table_exports.h" #endif #ifndef TYPE_DEFS_H #include "type_defs.h" #endif #ifndef UNIX_ASSERT_H #include "unix_assert.h" #endif #ifndef UNIX_CTYPE_H #include "unix_ctype.h" #endif #ifndef UNIX_MEMORY_H #include "unix_memory.h" #endif #ifndef UNIX_UNISTD_H #include "unix_unistd.h" #endif #ifndef VECTOR_DEFS_H #include "vector_defs.h" #endif /* Local routines: */ LOCAL void type_def_enumeration_gen(Type_def, Gen); LOCAL void type_def_external_gen(Type_def, Gen); LOCAL void type_def_initialization_gen(Type_def, Gen); LOCAL Type_def type_def_read(Stdio, Heap, Type_tables, int); LOCAL void type_def_structure_gen(Type_def, Gen); LOCAL void type_def_write(Type_def, Stdio, Type_tables); LOCAL void type_field_print(Type_field, Stdio); LOCAL Type_field type_field_read(Stdio, Heap, Type_tables); LOCAL int type_field_write(Type_field, Stdio, Type_tables); LOCAL void type_fields_print(Type_fields, Stdio, int); LOCAL Type_fields type_fields_read(Stdio, Heap, Type_tables); LOCAL void type_fields_write(Type_fields, Stdio, Type_tables); LOCAL void type_item_print(Type_item, Stdio, int); LOCAL Type_item type_item_read(Stdio, Heap, int); LOCAL int type_item_write(Type_item, Stdio, int); LOCAL void type_items_print(Vec(Type_item), Stdio, int); /* * type_def_create(name, position, type_tables, heap) * This routine will create and return a new type definition object * with values of "name" and "position" allocated from "heap". */ /* ARGSUSED */ Type_def type_def_create( Str name, int position, Type_tables type_tables, Heap heap) { Type_def type_def; type_def = heap_allocate(heap, Type_def); type_def->imported = 0; type_def->generates = vec_create(Type_predefined, heap); type_def->value.undefined = 0; type_def->name = name; type_def->position = position; type_def->routine_name = (Str)0; type_def->routine_types = vec_create(Type_routine, heap); type_def->structure_needed = 1; return type_def; } /* * type_def_enumeration_gen(type_def, gen) * This routine will generate the structure declarations for "type_def" * using "gen". */ LOCAL void type_def_enumeration_gen( Type_def type_def, Gen gen) { Str type_def_name; int imported; type_def_name = type_def->name; imported = type_def->imported; switch (type_def->kind) { case Type_kind_enumeration: { int index; int limit; Type_item type_item; Str type_item_name; Vec(Type_item) type_items; int size; type_items = type_def->value.enumeration->items; gen_out(gen, "enum %s___enum {\n", type_def_name); size = vec_size(Type_item, type_items); limit = imported ? size : size - 1; for (index = 0; index < limit; index++) { type_item = vec_fetch(Type_item, type_items, index); gen_out(gen, "%\t%s__item__%s,\n", 1, type_def_name, type_item->name); } if (imported) { type_item_name = "_none"; } else { type_item = vec_fetch(Type_item, type_items, size - 1); type_item_name = type_item->name; } gen_out(gen, "%\t%s__item__%s\n", 1, type_def_name, type_item_name); gen_out(gen, "};\n"); break; } } } /* * type_def_external_gen(type_def, gen) * This routine will generate the external type declarations for * "type_def" to "gen". */ LOCAL void type_def_external_gen( Type_def type_def, Gen gen) { Str type_def_name; type_def_name = type_def->name; switch (type_def->kind) { case Type_kind_enumeration: if (type_def->imported && type_def->structure_needed) { gen_out(gen, "static %s___type *%s___convert;\n", type_def_name, type_def_name); gen_out(gen, "extern int %s__enumeration__size;\n", type_def_name); } break; case Type_kind_external: gen_out(gen, "extern void %s__external__initialize(void);\n", type_def_name); break; } if (type_ref_is_parameterized(type_def->type_ref)) { gen_out(gen, "extern int %s__object__size;\n", type_def_name); } } /* * type_def_initialization_gen(type_def, gen) * This routine will generate initialization code for "type_def" * to "gen". */ LOCAL void type_def_initialization_gen( Type_def type_def, Gen gen) { Type_enumeration enumeration; Str name; int imported; Str item_name; Type_item item; Vec(Type_item) items; imported = type_def->imported; name = type_def->name; switch (type_def->kind) { case Type_kind_enumeration: if (imported && type_def->structure_needed) { enumeration = type_def->value.enumeration; items = enumeration->items; gen_out(gen, "%\t%s___convert = (%s___type *)" "run__time__convert__create(" "%s__enumeration__size, " "(int)%s__item___none, %\");\n", 1, name, name, name, name, name, name); VEC_LOOP(Type_item, items, item) { item_name = item->name; gen_out(gen, "%\t%s___convert[(int)%s__%s]" " = %s__item__%s;\n", 1, name, name, item_name, name, item_name); } } break; case Type_kind_external: if (!imported) { gen_out(gen, "%\t%s__external__initialize();\n", 1, name); } break; case Type_kind_record: case Type_kind_variant: if (!imported && !type_ref_is_parameterized(type_def->type_ref)) { gen_out(gen, "%\t%s__erase(&%s___initial_object);\n", 1, name, name); } break; } } /* * type_def_print(type_def, out_file) * This routine will print "type_def" to "out_file". */ void type_def_print( Type_def type_def, Stdio out_file) { Generate generate; Vec(Generate) generates; int index; int size; out(out_file, "%s", type_def->name); if (type_ref_is_parameterized(type_def->type_ref)) { out(out_file, "["); type_refs_print(type_def->type_ref->parameters, out_file); out(out_file, "]"); } if (type_def->routine_name != (Str)0) { out(out_file, "@%s", type_def->routine_name); } out(out_file, "%\n", type_def->comment); switch (type_def->kind) { case Type_kind_enumeration: { Type_enumeration enumeration; enumeration = type_def->value.enumeration; out(out_file, "%\tenumeration\n", 1); type_items_print(enumeration->items, out_file, 2); break; } case Type_kind_external: out(out_file, "%\texternal\n", 1); break; case Type_kind_proto: { Type_proto type_proto; type_proto = type_def->value.proto; switch (type_proto->kind) { case Type_proto_procedure: out(out_file, "%\tprocedure\n", 1); break; case Type_proto_iterator: out(out_file, "%\titerator\n", 2); break; default: assert_fail(); } type_refs_keyword_print(type_proto->takes, out_file, "takes", 2); type_refs_keyword_print(type_proto->returns, out_file, "returns", 2); type_refs_keyword_print(type_proto->yields, out_file, "yields", 2); /*XXX: Signals and needs belong here: */ break; } case Type_kind_record: { Type_record record; record = type_def->value.record; out(out_file, "%\trecord\n", 1); type_fields_print(record->fields, out_file, 2); break; } case Type_kind_variant: { Type_variant variant; variant = type_def->value.variant; out(out_file, "%\tvariant ", 1); type_field_print(variant->tag_field, out_file); out(out_file, "\n"); type_fields_print(variant->fields, out_file, 2); break; } case Type_kind_undefined: default: error_abort("Unknown type"); break; } generates = type_def->generates; size = vec_size(Generate, generates); if (size > 0) { out(out_file, "%\tgenerate ", 1); for (index = 0; index < size; index++) { generate = vec_fetch(Generate, generates, index); generate_print(generate, out_file); if (index + 1 == size) { out(out_file, "\n"); } else { out(out_file, ", "); } } } out(out_file, "\n"); } /* * type_def_read(in_file, heap, type_tables, position) * This routine will read in a type from "in_file" using "type_tables'. */ LOCAL Type_def type_def_read( Stdio in_file, Heap heap, Type_tables type_tables, int position) { Type_def type_def; Type_refs parameters; type_def = heap_allocate(heap, Type_def); type_def->imported = 1; type_def->name = strread(in_file, heap); type_def->structure_needed = 0; type_def->position = position; type_def->generates = vec_create(Type_predefined, heap); parameters = type_refs_read(in_file, heap, type_tables); type_def->type_ref = type_ref_parameters_create(type_def->name, parameters, type_tables); type_def->kind = (Type_kind)(getc(in_file) & 0xff); switch (type_def->kind) { case Type_kind_enumeration: type_def->value.enumeration = heap_allocate(heap, Type_enumeration); type_def->value.enumeration->items = vec_read(Type_item, type_item_read, in_file, heap, 0); break; case Type_kind_proto: { type_def->value.proto = type_proto_read(in_file, heap, type_tables); break; } case Type_kind_simple: type_def->value.simple = 0; break; case Type_kind_record: { Type_record record; record = heap_allocate(heap, Type_record); type_def->value.record = record; record->fields = type_fields_read(in_file, heap, type_tables); break; } case Type_kind_variant: { Type_variant variant; variant = heap_allocate(heap, Type_variant); type_def->value.variant = variant; variant->tag_field = type_field_read(in_file, heap, type_tables); variant->fields = type_fields_read(in_file, heap, type_tables); break; } case Type_kind_undefined: break; case Type_kind_external: break; default: error_abort("type_read: unimplemented\n"); } assert(type_def_table_insert(type_tables->type_def_table, type_def) == 0); return type_def; } /* * type_def_structure_gen(type_def, gen) * This routine will generate the structure declarations for "type_def" * using "gen". */ LOCAL void type_def_structure_gen( Type_def type_def, Gen gen) { Str type_def_name; int imported; type_def_name = type_def->name; imported = type_def->imported; switch (type_def->kind) { case Type_kind_record: { Heap heap; Type_field field; Type_fields fields; if (imported) { break; } heap = gen->heap; gen_out(gen, "struct %s___record {\n", type_def_name); fields = type_def->value.record->fields; VEC_LOOP(Type_field, fields, field) { if (type_ref_is_parameter(field->type_ref)) { gen_out(gen, "%\tvoid *%S;\n", 1, field->name); } else { gen_out(gen, "%\t%s %S;\n", 1, type_ref_string(field->type_ref, heap), field->name); } } gen_out(gen, "};\n"); if (!imported) { gen_out(gen, "int %s__object__size = " "sizeof(struct %s___record);\n", type_def_name, type_def_name); } break; } case Type_kind_variant: { Type_field field; Type_variant variant; variant = type_def->value.variant; gen_out(gen, "union %s___variant {\n", type_def_name); gen_out(gen, "%\tdouble _entire_;\n", 1); field = variant->tag_field; gen_out(gen, "%\tstruct {\n", 1); gen_out(gen, "%\tvoid *_value_;\n", 2); gen_out(gen, "%\t%T %s;\n", 2, field->type_ref->name, field->name); gen_out(gen, "%\t} _tag_;\n", 1); VEC_LOOP(Type_field, variant->fields, field) { if (imported) { gen_out(gen, "%\tvoid *%S;\n", 1, field->name); } else { gen_out(gen, "%\t%T %S;\n", 1, field->type_ref->name, field->name); } } gen_out(gen, "};\n"); if (!imported) { gen_out(gen, "int %s__object__size = " "sizeof(union %s___variant);\n", type_def_name, type_def_name); } break; } } } /* * type_def_structure_needed(type_def) * This routine will mark "type_def" so that its structure is in the * output file. */ void type_def_structure_needed( Type_def type_def) { type_def->structure_needed = 1; } /* * type_def_typedef_gen(type_def, gen) * This routine will output the typedef associated with "type_def" * using "gen". */ LOCAL void type_def_typedef_gen( Type_def type_def, Gen gen) { Str type_name; type_name = type_def->name; switch (type_def->kind) { case Type_kind_enumeration: gen_out(gen, "typedef enum %s___enum %T;\n", type_name, type_name); break; case Type_kind_record: gen_out(gen, "typedef struct %s___record *%T;\n", type_name, type_name); break; case Type_kind_variant: gen_out(gen, "typedef union %s___variant *%T;\n", type_name, type_name); break; case Type_kind_external: { Str translated; int size; translated = type_translate(type_name, gen->heap); size = strlen(type_name); if ((strncmp(translated, type_name, size) == 0) && (strequal(translated + size, "___type"))) { gen_out(gen, "typedef void *%T;\n", type_name); } else { gen_out(gen, "typedef %s %T;\n", translated, type_name); } break; } default: assert_fail(); } } /* * type_def_write(type_def, out_file, type_tables) * This routine will write "type_def" to "out_file". 0 is always * returned. */ LOCAL void type_def_write( Type_def type_def, Stdio out_file, Type_tables type_tables) { (void)strwrite(type_def->name, out_file); type_refs_write(type_def->type_ref->parameters, out_file, type_tables); (void)putc((char)type_def->kind, out_file); switch (type_def->kind) { case Type_kind_enumeration: vec_write(Type_item, type_def->value.enumeration->items, type_item_write, out_file, 0); break; case Type_kind_proto: type_proto_write(type_def->value.proto, out_file, type_tables); break; case Type_kind_simple: break; case Type_kind_record: type_fields_write(type_def->value.record->fields, out_file, type_tables); break; case Type_kind_variant: (void)type_field_write(type_def->value.variant->tag_field, out_file, type_tables); type_fields_write(type_def->value.record->fields, out_file, type_tables); break; case Type_kind_undefined: break; case Type_kind_external: break; default: error_abort("type_def_write: unimplemented\n"); } } /* * Type_defs routines: */ /* * type_defs_dump(type_defs, out_file) * This routine will dump the contents of each type definition in * "type_defs" to "out_file" in human readable form. */ void type_defs_dump( Type_defs type_defs, Stdio out_file) { Type_def type_def; VEC_LOOP(Type_def, type_defs, type_def) { type_def_print(type_def, out_file); } } /* * type_defs_enumeration_gen(type_defs, gen) * This will generate all of the enumeration type definitions for * each type definition in "type_defs" to "gen". */ void type_defs_enumeration_gen( Type_defs type_defs, Gen gen) { Type_def type_def; VEC_LOOP(Type_def, type_defs, type_def) { type_def_enumeration_gen(type_def, gen); } } /* * type_defs_external_gen(type_defs, gen) * This routine will generate the external type declarations for * each type definition in "type_defs" to "gen". */ void type_defs_external_gen( Type_defs type_defs, Gen gen) { Type_def type_def; VEC_LOOP(Type_def, type_defs, type_def) { type_def_external_gen(type_def, gen); } } /* * type_defs_initializion_gen(type_defs, gen) * This routine will generate any needed initialization code * for each type definition in "type_defs" to "gen". */ void type_defs_initialization_gen( Type_defs type_defs, Gen gen) { Type_def type_def; VEC_LOOP(Type_def, type_defs, type_def) { type_def_initialization_gen(type_def, gen); } } /* * type_defs_insert(type_defs, type_tables, object_table, heap) * This routine will insert each type definition in "type_defs" * into the appropriate table in "type_tables". Any implied * types resulting from a variant are appended to "type_defs". */ void type_defs_insert( Type_defs type_defs, Type_tables type_tables, Object_table object_table, Msg msg, Heap heap) { Type_def previous_type_def; Type_def type_def; Type_def_table type_def_table; Type_defs implied_type_defs; implied_type_defs = vec_create(Type_def, heap); type_def_table = type_tables->type_def_table; VEC_LOOP(Type_def, type_defs, type_def) { if (type_def->imported) { continue; } /* Deal with implied type definitions: */ switch (type_def->kind) { case Type_kind_enumeration: { int position; Type_enumeration type_enumeration; Type_item type_item; Vec(Type_item) type_items; Type_ref type_ref; type_ref = type_def->type_ref; position = type_def->position; type_enumeration = type_def->value.enumeration; type_items = type_enumeration->items; VEC_LOOP(Type_item, type_items, type_item) { object_create(object_table, type_item->name, type_ref, type_def, position); } object_create(object_table, "first", type_ref, type_def, position); object_create(object_table, "last", type_ref, type_def, position); break; } case Type_kind_variant: { Type_variant variant; Type_field tag_field; Str tag_type_name; Type_def tag_type_def; variant = type_def->value.variant; tag_field = variant->tag_field; tag_type_name = tag_field->type_ref->name; tag_type_def = type_def_table_lookup(type_def_table, tag_type_name); if (tag_type_def == (Type_def)0) { /* Create the associated enumeration type: */ Type_enumeration enumeration; Type_field field; Type_fields fields; Type_item item; Vec(Type_item) items; int item_value; Type_ref type_ref; tag_type_def = type_def_create(tag_type_name, type_def->position, type_tables, heap); item_value = 0; items = vec_create(Type_item, heap); fields = variant->fields; VEC_LOOP(Type_field, fields, field) { item = heap_allocate(heap, Type_item); item->comment = (Str)0; item->name = field->name; item->position = field->position; item->value = item_value++; vec_append(Type_item, items, item); } enumeration = heap_allocate(heap, Type_enumeration); enumeration->items = items; tag_type_def->value.enumeration = enumeration; tag_type_def->kind = Type_kind_enumeration; type_ref = type_ref_create(tag_type_def->name, type_tables); tag_type_def->type_ref = type_ref; vec_append(Type_def, implied_type_defs, tag_type_def); assert(type_def_table_insert(type_def_table, tag_type_def) == 0); } else { /* Should check for consistency: */ } break; } } } if (!vec_empty(Type_def, implied_type_defs)) { type_defs_insert(implied_type_defs, type_tables, object_table, msg, heap); vec_vec_append(Type_def, type_defs, implied_type_defs); } } /* * type_defs_read(in_file, heap, type_tables, position) * This routine will read in and return a list of type definitions * from "in_file" using "heap" and "type_tables" for allocation * purposes. "position" is the assigned to each type definition. */ Type_defs type_defs_read( Stdio in_file, Heap heap, Type_tables type_tables, int position) { int index; int size; Type_def type_def; Type_defs type_defs; type_defs = vec_create(Type_defs, heap); size = getw(in_file); for (index = 0; index < size; index++) { type_def = type_def_read(in_file, heap, type_tables, position); vec_append(Type_def, type_defs, type_def); } return type_defs; } /* * type_defs_structure_gen(type_defs, gen) * This will generate all of the type defintions and get/set/new * routines for each type defintion in "type_defs" using "gen". */ void type_defs_structure_gen( Type_defs type_defs, Gen gen) { Type_def type_def; VEC_LOOP(Type_def, type_defs, type_def) { type_def_structure_gen(type_def, gen); } gen_out(gen, "\n"); VEC_LOOP(Type_def, type_defs, type_def) { if (!type_def->imported) { type_def_initial_object_gen(type_def, gen); } } gen_out(gen, "\n"); } /* * type_defs_typedef_gen(type_defs, gen) * This routine will generate all of the typedef's for each type * definition in "typedefs" using "gen". */ void type_defs_typedef_gen( Type_defs type_defs, Gen gen) { Type_def type_def; VEC_LOOP(Type_def, type_defs, type_def) { type_def_typedef_gen(type_def, gen); } } /* * Type_def_table routines: */ /* * type_def_table_create(heap) * This routine will return a new type definition table allocated from * "heap". */ Type_def_table type_def_table_create( Heap heap) { Type_def_table type_def_table; type_def_table = heap_allocate(heap, Type_def_table); type_def_table->table = table_create(Str, Type_def, 100, strequal, strhash, (Type_def)0, heap); return type_def_table; } /* * type_def_table_lookup(type_def_table, type_name) * This routine will return the type defintion associated with "type_name" * in "type_def_table"; otherwise, (Type_def)0 is returned. */ Type_def type_def_table_lookup( Type_def_table type_def_table, Str type_name) { return table_lookup(Str, Type_def, type_def_table->table, type_name); } /* * type_def_table_insert(type_def_table, type_name, type_def) * This routine will insert "type_def" into "type_def_table" under * "type_name". 1 is returned if "type_name" is already in * "type_def_table"; otherwise, 0 is returned. */ int type_def_table_insert( Type_def_table type_def_table, Type_def type_def) { return table_insert(Str, Type_def, type_def_table->table, type_def->name, type_def); } /* * type_defs_write(type_defs, out_file, type_tables) * This routine will write each type definition in "type_defs" * to "out_file" using "type_tables". */ void type_defs_write( Type_defs type_defs, Stdio out_file, Type_tables type_tables) { Type_def type_def; (void)putw(vec_size(Type_def, type_defs), out_file); VEC_LOOP(Type_def, type_defs, type_def) { type_def_write(type_def, out_file, type_tables); } } /* * Type_field routines; */ /* * type_field_print(type_field, out_file) * This will print "type_field" to "out_file". */ LOCAL void type_field_print( Type_field type_field, Stdio out_file) { out(out_file, "%s %r", type_field->name, type_field->type_ref); } /* * type_field_read(in_file, heap, type_tables) * This routine will read in and return a type field from "in_file" * using "type_tables". */ LOCAL Type_field type_field_read( Stdio in_file, Heap heap, Type_tables type_tables) { Type_field type_field; type_field = heap_allocate(heap, Type_field); type_field->name = strread(in_file, heap); type_field->type_ref = type_ref_read(in_file, heap, type_tables); return type_field; } /* * type_field_write(type_field, out_file, type_tables) * This routine will write "type_field" to "out_file". 0 is always * returned. */ /* ARGSUSED */ LOCAL int type_field_write( Type_field type_field, Stdio out_file, Type_tables type_tables) { (void)strwrite(type_field->name, out_file); type_ref_write(type_field->type_ref, out_file, type_tables); return 0; } /* * Type_fields routines: */ /* * type_fields_print(type_fields, gen, indent) * This routine will print each field in "type_fields" to "gen" indented * by "indent". */ LOCAL void type_fields_print( Type_fields type_fields, Stdio out_file, int indent) { Type_field type_field; VEC_LOOP(Type_field, type_fields, type_field) { out(out_file, "%\t", indent); type_field_print(type_field, out_file); out(out_file, "\n"); } } /* * type_fields_read(in_file, heap, type_tables) * This routine will read in a vector of type fields from "in_file" * using "type_tables". */ LOCAL Type_fields type_fields_read( Stdio in_file, Heap heap, Type_tables type_tables) { Type_fields type_fields; type_fields = vec_read(Type_field, type_field_read, in_file, heap, type_tables); return type_fields; } /* * type_fields_write(fields, out_file, type_tables) * This routine will write "fields" to "out_file". */ LOCAL void type_fields_write( Type_fields type_fields, Stdio out_file, Type_tables type_tables) { vec_write(Type_field, type_fields, type_field_write, out_file, type_tables); } /* * Type_item routines: */ /* * type_item_print(type_item, out_file, indent) * This routine will print "type_item" to "out_file indented by "indent". */ void type_item_print( Type_item type_item, Stdio out_file, int indent) { out(out_file, "%\t%s\n", indent, type_item->name); } /* * type_item_read(in_file, heap, zilch) * This routine will read in a type item from "in_file" allocated from * "heap". */ /* ARGSUSED */ LOCAL Type_item type_item_read( Stdio in_file, Heap heap, int zilch) { Type_item type_item; type_item = heap_allocate(heap, Type_item); type_item->name = strread(in_file, heap); type_item->value = getw(in_file); return type_item; } /* * type_item_write(type_item, out_file, zilch) * This routine will write "type_item" to "out_file". 0 is * always returned. */ /* ARGSUSED */ LOCAL int type_item_write( Type_item type_item, Stdio out_file, int zilch) { (void)strwrite(type_item->name, out_file); (void)putw(type_item->value, out_file); return 0; } /* * Type_items routines: */ /* * type_items_print(type_items, out_file, indent) * This routine will print out each type item in "type_items" to * "out_file" indented by "indent". */ LOCAL void type_items_print( Vec(Type_item) type_items, Stdio out_file, int indent) { Type_item type_item; VEC_LOOP(Type_item, type_items, type_item) { type_item_print(type_item, out_file, indent); } }