+static void write_type_array(write_env_t *env, ir_type *tp)
+{
+ size_t n_dimensions = get_array_n_dimensions(tp);
+ ir_type *element_type = get_array_element_type(tp);
+ ir_entity *element_entity = get_array_element_entity(tp);
+ size_t i;
+
+ write_type(env, element_type);
+
+ write_type_common(env, tp);
+ write_size_t(env, n_dimensions);
+ write_type_ref(env, get_array_element_type(tp));
+ for (i = 0; i < n_dimensions; i++) {
+ ir_node *lower = get_array_lower_bound(tp, i);
+ ir_node *upper = get_array_upper_bound(tp, i);
+
+ if (is_Const(lower))
+ write_long(env, get_tarval_long(get_Const_tarval(lower)));
+ else
+ panic("Lower array bound is not constant");
+
+ if (is_Const(upper))
+ write_long(env, get_tarval_long(get_Const_tarval(upper)));
+ else if (is_Unknown(upper))
+ write_symbol(env, "unknown");
+ else
+ panic("Upper array bound is not constant");
+ }
+ /* note that we just write a reference to the element entity
+ * but never the entity itself */
+ write_entity_ref(env, element_entity);
+ fputc('\n', env->file);
+}
+
+static void write_type_method(write_env_t *env, ir_type *tp)
+{
+ size_t nparams = get_method_n_params(tp);
+ size_t nresults = get_method_n_ress(tp);
+ size_t i;
+
+ for (i = 0; i < nparams; i++)
+ write_type(env, get_method_param_type(tp, i));
+ for (i = 0; i < nresults; i++)
+ write_type(env, get_method_res_type(tp, i));
+
+ write_type_common(env, tp);
+ write_unsigned(env, get_method_calling_convention(tp));
+ write_unsigned(env, get_method_additional_properties(tp));
+ write_size_t(env, nparams);
+ write_size_t(env, nresults);
+ for (i = 0; i < nparams; i++)
+ write_type_ref(env, get_method_param_type(tp, i));
+ for (i = 0; i < nresults; i++)
+ write_type_ref(env, get_method_res_type(tp, i));
+ write_unsigned(env, get_method_variadicity(tp));
+ fputc('\n', env->file);
+}
+
+static void write_type_pointer(write_env_t *env, ir_type *tp)
+{
+ ir_type *points_to = get_pointer_points_to_type(tp);
+
+ write_type(env, points_to);
+
+ write_type_common(env, tp);
+ write_mode_ref(env, get_type_mode(tp));
+ write_type_ref(env, points_to);
+ fputc('\n', env->file);
+}
+
+static void write_type_enumeration(write_env_t *env, ir_type *tp)
+{
+ write_type_common(env, tp);
+ write_ident_null(env, get_enumeration_ident(tp));
+ fputc('\n', env->file);
+}
+
+static void write_type(write_env_t *env, ir_type *tp)
+{
+ if (type_visited(tp))
+ return;
+ mark_type_visited(tp);
+
+ switch ((tp_opcode)get_type_tpop_code(tp)) {
+ case tpo_none:
+ case tpo_unknown:
+ case tpo_code:
+ case tpo_uninitialized:
+ /* no need to write special builtin types */
+ return;
+
+ case tpo_union:
+ case tpo_struct:
+ case tpo_class:
+ write_type_compound(env, tp);
+ return;
+
+ case tpo_primitive: write_type_primitive(env, tp); return;
+ case tpo_enumeration: write_type_enumeration(env, tp); return;
+ case tpo_method: write_type_method(env, tp); return;
+ case tpo_pointer: write_type_pointer(env, tp); return;
+ case tpo_array: write_type_array(env, tp); return;
+ }
+ panic("can't write invalid type %+F\n", tp);
+}
+
+static void write_entity(write_env_t *env, ir_entity *ent)
+{
+ ir_type *type = get_entity_type(ent);
+ ir_type *owner = get_entity_owner(ent);
+ ir_visibility visibility = get_entity_visibility(ent);
+ ir_linkage linkage = get_entity_linkage(ent);
+
+ if (entity_visited(ent))
+ return;
+ mark_entity_visited(ent);
+
+ write_type(env, type);
+ write_type(env, owner);
+
+ fputc('\t', env->file);
+ switch ((ir_entity_kind)ent->entity_kind) {
+ case IR_ENTITY_NORMAL: write_symbol(env, "entity"); break;
+ case IR_ENTITY_METHOD: write_symbol(env, "method"); break;
+ case IR_ENTITY_LABEL: write_symbol(env, "label"); break;
+ case IR_ENTITY_COMPOUND_MEMBER: write_symbol(env, "compound_member"); break;
+ case IR_ENTITY_PARAMETER: write_symbol(env, "parameter"); break;
+ case IR_ENTITY_UNKNOWN:
+ write_symbol(env, "unknown");
+ write_long(env, get_entity_nr(ent));
+ return;
+ }
+ write_long(env, get_entity_nr(ent));
+
+ if (ent->entity_kind != IR_ENTITY_LABEL
+ && ent->entity_kind != IR_ENTITY_PARAMETER) {
+ write_ident_null(env, get_entity_ident(ent));
+ if (!entity_has_ld_ident(ent)) {
+ write_ident_null(env, NULL);
+ } else {
+ write_ident_null(env, get_entity_ld_ident(ent));
+ }
+ }
+
+ write_visibility(env, visibility);
+ write_list_begin(env);
+ if (linkage & IR_LINKAGE_CONSTANT)
+ write_symbol(env, "constant");
+ if (linkage & IR_LINKAGE_WEAK)
+ write_symbol(env, "weak");
+ if (linkage & IR_LINKAGE_GARBAGE_COLLECT)
+ write_symbol(env, "garbage_collect");
+ if (linkage & IR_LINKAGE_MERGE)
+ write_symbol(env, "merge");
+ if (linkage & IR_LINKAGE_HIDDEN_USER)
+ write_symbol(env, "hidden_user");
+ write_list_end(env);
+
+ write_type_ref(env, type);
+ if (ent->entity_kind != IR_ENTITY_LABEL)
+ write_type_ref(env, owner);
+ write_long(env, is_entity_compiler_generated(ent));
+ write_volatility(env, get_entity_volatility(ent));
+
+ switch ((ir_entity_kind)ent->entity_kind) {
+ case IR_ENTITY_NORMAL:
+ if (ent->initializer != NULL) {
+ write_symbol(env, "initializer");
+ write_initializer(env, get_entity_initializer(ent));
+ } else if (entity_has_compound_ent_values(ent)) {
+ /* compound graph API is deprecated */
+ panic("exporting compound_graph initializers not supported");
+ } else {
+ write_symbol(env, "none");
+ }
+ break;
+ case IR_ENTITY_COMPOUND_MEMBER:
+ write_long(env, get_entity_offset(ent));
+ write_unsigned(env, get_entity_offset_bits_remainder(ent));
+ break;
+ case IR_ENTITY_PARAMETER: {
+ size_t num = get_entity_parameter_number(ent);
+ if (num == IR_VA_START_PARAMETER_NUMBER) {
+ write_symbol(env, "va_start");
+ } else {
+ write_size_t(env, num);
+ }
+ break;
+ }
+ case IR_ENTITY_UNKNOWN:
+ case IR_ENTITY_LABEL:
+ case IR_ENTITY_METHOD:
+ break;
+ }
+
+ fputc('\n', env->file);
+}
+
+static void write_switch_table(write_env_t *env, const ir_switch_table *table)
+{
+ size_t n_entries = ir_switch_table_get_n_entries(table);
+ size_t i;
+
+ write_size_t(env, n_entries);
+ for (i = 0; i < n_entries; ++i) {
+ long pn = ir_switch_table_get_pn(table, i);
+ ir_tarval *min = ir_switch_table_get_min(table, i);
+ ir_tarval *max = ir_switch_table_get_max(table, i);
+ write_long(env, pn);
+ write_tarval(env, min);
+ write_tarval(env, max);
+ }
+}
+
+static void write_pred_refs(write_env_t *env, const ir_node *node, int from)
+{
+ int arity = get_irn_arity(node);
+ int i;
+ write_list_begin(env);
+ assert(from <= arity);
+ for (i = from; i < arity; ++i) {
+ ir_node *pred = get_irn_n(node, i);
+ write_node_ref(env, pred);
+ }
+ write_list_end(env);
+}
+
+static void write_node_nr(write_env_t *env, const ir_node *node)
+{
+ write_long(env, get_irn_node_nr(node));
+}
+
+static void write_ASM(write_env_t *env, const ir_node *node)
+{
+ ir_asm_constraint *input_constraints = get_ASM_input_constraints(node);
+ ir_asm_constraint *output_constraints = get_ASM_output_constraints(node);
+ ident **clobbers = get_ASM_clobbers(node);
+ size_t n_input_constraints = get_ASM_n_input_constraints(node);
+ size_t n_output_constraints = get_ASM_n_output_constraints(node);
+ size_t n_clobbers = get_ASM_n_clobbers(node);
+ size_t i;
+
+ write_symbol(env, "ASM");
+ write_node_nr(env, node);
+ write_node_nr(env, get_nodes_block(node));
+
+ write_ident(env, get_ASM_text(node));
+ write_list_begin(env);
+ for (i = 0; i < n_input_constraints; ++i) {
+ const ir_asm_constraint *constraint = &input_constraints[i];
+ write_unsigned(env, constraint->pos);
+ write_ident(env, constraint->constraint);
+ write_mode_ref(env, constraint->mode);
+ }
+ write_list_end(env);
+
+ write_list_begin(env);
+ for (i = 0; i < n_output_constraints; ++i) {
+ const ir_asm_constraint *constraint = &output_constraints[i];
+ write_unsigned(env, constraint->pos);
+ write_ident(env, constraint->constraint);
+ write_mode_ref(env, constraint->mode);
+ }
+ write_list_end(env);
+
+ write_list_begin(env);
+ for (i = 0; i < n_clobbers; ++i) {
+ ident *clobber = clobbers[i];
+ write_ident(env, clobber);
+ }
+ write_list_end(env);
+
+ write_pin_state(env, get_irn_pinned(node));
+ write_pred_refs(env, node, 0);
+}
+
+static void write_Phi(write_env_t *env, const ir_node *node)
+{
+ write_symbol(env, "Phi");
+ write_node_nr(env, node);
+ write_node_ref(env, get_nodes_block(node));
+ write_mode_ref(env, get_irn_mode(node));
+ write_pred_refs(env, node, 0);
+}
+
+static void write_Block(write_env_t *env, const ir_node *node)
+{
+ ir_entity *entity = get_Block_entity(node);
+
+ if (entity != NULL) {
+ write_symbol(env, "BlockL");
+ write_node_nr(env, node);
+ write_entity_ref(env, entity);
+ } else {
+ write_symbol(env, "Block");
+ write_node_nr(env, node);
+ }
+ write_pred_refs(env, node, 0);
+}
+
+static void write_Anchor(write_env_t *env, const ir_node *node)
+{
+ write_symbol(env, "Anchor");
+ write_node_nr(env, node);
+ write_pred_refs(env, node, 0);
+}
+
+static void write_SymConst(write_env_t *env, const ir_node *node)
+{
+ /* TODO: only symconst_addr_ent implemented yet */
+ if (get_SymConst_kind(node) != symconst_addr_ent)
+ panic("Can't export %+F (only symconst_addr_ent supported)", node);
+
+ write_symbol(env, "SymConst");
+ write_node_nr(env, node);
+ write_mode_ref(env, get_irn_mode(node));
+ write_entity_ref(env, get_SymConst_entity(node));
+}
+
+typedef void (*write_node_func)(write_env_t *env, const ir_node *node);
+
+static void register_node_writer(ir_op *op, write_node_func func)
+{
+ set_generic_function_ptr(op, (op_func)func);
+}
+
+static void writers_init(void)
+{
+ ir_clear_opcodes_generic_func();
+ register_node_writer(op_Anchor, write_Anchor);
+ register_node_writer(op_ASM, write_ASM);
+ register_node_writer(op_Block, write_Block);
+ register_node_writer(op_Phi, write_Phi);
+ register_node_writer(op_SymConst, write_SymConst);
+ register_generated_node_writers();
+}
+
+static void write_node(const ir_node *node, write_env_t *env)
+{
+ ir_op *op = get_irn_op(node);
+ write_node_func func = (write_node_func) get_generic_function_ptr(op);
+
+ fputc('\t', env->file);
+ if (func == NULL)
+ panic("No write_node_func for %+F", node);
+ func(env, node);
+ fputc('\n', env->file);
+}
+
+static void write_node_recursive(ir_node *node, write_env_t *env);
+
+static void write_preds(ir_node *node, write_env_t *env)
+{
+ int arity = get_irn_arity(node);
+ int i;
+ for (i = 0; i < arity; ++i) {
+ ir_node *pred = get_irn_n(node, i);
+ write_node_recursive(pred, env);
+ }
+}
+
+/**
+ * Recursively write nodes.
+ * The reader expects nodes in a way that except for block/phi/anchor nodes
+ * all predecessors are already defined when we reach them. So usually we
+ * recurse to all our predecessors except for block/phi/anchor nodes where
+ * we put the predecessors into a queue for later processing.
+ */
+static void write_node_recursive(ir_node *node, write_env_t *env)
+{
+ if (irn_visited_else_mark(node))
+ return;
+
+ if (!is_Block(node)) {
+ write_node_recursive(get_nodes_block(node), env);
+ }
+ /* write predecessors */
+ if (!is_Phi(node) && !is_Block(node) && !is_Anchor(node)) {
+ write_preds(node, env);
+ } else {
+ int arity = get_irn_arity(node);
+ int i;
+ for (i = 0; i < arity; ++i) {
+ ir_node *pred = get_irn_n(node, i);
+ pdeq_putr(env->write_queue, pred);
+ }
+ }
+ write_node(node, env);
+}
+
+static void write_mode(write_env_t *env, ir_mode *mode)
+{
+ if (mode_is_int(mode)) {
+ write_symbol(env, "int_mode");
+ write_string(env, get_mode_name(mode));
+ write_mode_arithmetic(env, get_mode_arithmetic(mode));
+ write_unsigned(env, get_mode_size_bits(mode));
+ write_int(env, get_mode_sign(mode));
+ write_unsigned(env, get_mode_modulo_shift(mode));
+ } else if (mode_is_reference(mode)) {
+ write_symbol(env, "reference_mode");
+ write_string(env, get_mode_name(mode));
+ write_mode_arithmetic(env, get_mode_arithmetic(mode));
+ write_unsigned(env, get_mode_size_bits(mode));
+ write_unsigned(env, get_mode_modulo_shift(mode));
+
+ write_mode_ref(env, get_reference_mode_signed_eq(mode));
+ write_mode_ref(env, get_reference_mode_unsigned_eq(mode));
+ write_int(env, (mode == mode_P ? 1 : 0));
+ } else if (mode_is_float(mode)) {
+ write_symbol(env, "float_mode");
+ write_string(env, get_mode_name(mode));
+ write_mode_arithmetic(env, get_mode_arithmetic(mode));
+ write_unsigned(env, get_mode_exponent_size(mode));
+ write_unsigned(env, get_mode_mantissa_size(mode));
+ } else {
+ panic("Can't write internal modes");
+ }
+}
+
+static void write_modes(write_env_t *env)
+{
+ size_t n_modes = ir_get_n_modes();
+ size_t i;
+
+ write_symbol(env, "modes");
+ fputs("{\n", env->file);
+
+ for (i = 0; i < n_modes; i++) {
+ ir_mode *mode = ir_get_mode(i);
+ if (!mode_is_int(mode) && !mode_is_reference(mode)
+ && !mode_is_float(mode)) {
+ /* skip internal modes */
+ continue;
+ }
+ fputc('\t', env->file);
+ write_mode(env, mode);
+ fputc('\n', env->file);
+ }
+
+ fputs("}\n\n", env->file);
+}
+
+static void write_program(write_env_t *env)
+{
+ ir_segment_t s;
+ size_t n_asms = get_irp_n_asms();
+ size_t i;
+
+ write_symbol(env, "program");
+ write_scope_begin(env);
+ if (irp_prog_name_is_set()) {
+ fputc('\t', env->file);
+ write_symbol(env, "name");
+ write_string(env, get_irp_name());
+ fputc('\n', env->file);
+ }
+
+ for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
+ ir_type *segment_type = get_segment_type(s);
+ fputc('\t', env->file);
+ write_symbol(env, "segment_type");
+ write_symbol(env, get_segment_name(s));
+ if (segment_type == NULL) {
+ write_symbol(env, "NULL");
+ } else {
+ write_type_ref(env, segment_type);
+ }
+ fputc('\n', env->file);
+ }
+
+ for (i = 0; i < n_asms; ++i) {
+ ident *asm_text = get_irp_asm(i);
+ fputc('\t', env->file);
+ write_symbol(env, "asm");
+ write_ident(env, asm_text);
+ fputc('\n', env->file);
+ }
+ write_scope_end(env);
+}
+
+int ir_export(const char *filename)
+{
+ FILE *file = fopen(filename, "wt");
+ int res = 0;
+ if (file == NULL) {
+ perror(filename);
+ return 1;
+ }
+
+ ir_export_file(file);
+ res = ferror(file);
+ fclose(file);
+ return res;
+}
+
+static void write_node_cb(ir_node *node, void *ctx)
+{
+ write_env_t *env = (write_env_t*)ctx;
+ write_node(node, env);
+}
+
+static void write_typegraph(write_env_t *env)
+{
+ size_t n_types = get_irp_n_types();
+ size_t i;
+
+ write_symbol(env, "typegraph");
+ write_scope_begin(env);
+ irp_reserve_resources(irp, IRP_RESOURCE_TYPE_VISITED);
+ inc_master_type_visited();
+ for (i = 0; i < n_types; ++i) {
+ ir_type *type = get_irp_type(i);
+ write_type(env, type);
+ }
+ irp_free_resources(irp, IRP_RESOURCE_TYPE_VISITED);
+ write_scope_end(env);
+}
+
+static void write_irg(write_env_t *env, ir_graph *irg)
+{
+ write_symbol(env, "irg");
+ write_entity_ref(env, get_irg_entity(irg));
+ write_type_ref(env, get_irg_frame_type(irg));
+ write_inline_property(env, get_irg_inline_property(irg));
+ write_unsigned(env, get_irg_additional_properties(irg));
+ write_scope_begin(env);
+ ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
+ inc_irg_visited(irg);
+ assert(pdeq_empty(env->write_queue));
+ pdeq_putr(env->write_queue, irg->anchor);
+ do {
+ ir_node *node = (ir_node*) pdeq_getl(env->write_queue);
+ write_node_recursive(node, env);
+ } while (!pdeq_empty(env->write_queue));
+ ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
+ write_scope_end(env);
+}
+
+/* Exports the whole irp to the given file in a textual form. */
+void ir_export_file(FILE *file)
+{
+ write_env_t my_env;
+ write_env_t *env = &my_env;
+ size_t i, n_irgs = get_irp_n_irgs();
+
+ memset(env, 0, sizeof(*env));
+ env->file = file;
+ env->write_queue = new_pdeq();
+
+ writers_init();
+ write_modes(env);
+
+ write_typegraph(env);
+
+ for (i = 0; i < n_irgs; i++) {
+ ir_graph *irg = get_irp_irg(i);
+ write_irg(env, irg);
+ }
+
+ write_symbol(env, "constirg");
+ write_node_ref(env, get_const_code_irg()->current_block);
+ write_scope_begin(env);
+ walk_const_code(NULL, write_node_cb, env);
+ write_scope_end(env);
+
+ write_program(env);
+
+ del_pdeq(env->write_queue);
+}
+
+
+
+static void read_c(read_env_t *env)
+{
+ int c = fgetc(env->file);
+ env->c = c;
+ if (c == '\n')
+ env->line++;
+}
+
+/** Returns the first non-whitespace character or EOF. **/
+static void skip_ws(read_env_t *env)
+{
+ while (true) {
+ switch (env->c) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ read_c(env);
+ continue;
+
+ default:
+ return;
+ }
+ }
+}
+
+static void skip_to(read_env_t *env, char to_ch)
+{
+ while (env->c != to_ch && env->c != EOF) {
+ read_c(env);
+ }
+}
+
+static bool expect_char(read_env_t *env, char ch)
+{
+ skip_ws(env);
+ if (env->c != ch) {
+ parse_error(env, "Unexpected char '%c', expected '%c'\n",
+ env->c, ch);
+ return false;
+ }
+ read_c(env);
+ return true;
+}
+
+#define EXPECT(c) if (expect_char(env, (c))) {} else return
+
+static char *read_word(read_env_t *env)
+{
+ skip_ws(env);
+
+ assert(obstack_object_size(&env->obst) == 0);
+ while (true) {
+ int c = env->c;
+ switch (c) {
+ case EOF:
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ goto endofword;
+
+ default:
+ obstack_1grow(&env->obst, c);
+ break;
+ }
+ read_c(env);
+ }
+
+endofword:
+ obstack_1grow(&env->obst, '\0');
+ return (char*)obstack_finish(&env->obst);
+}
+
+static char *read_string(read_env_t *env)
+{
+ skip_ws(env);
+ if (env->c != '"') {
+ parse_error(env, "Expected string, got '%c'\n", env->c);
+ exit(1);
+ }
+ read_c(env);
+
+ assert(obstack_object_size(&env->obst) == 0);
+ while (env->c != '"') {
+ if (env->c == EOF) {
+ parse_error(env, "Unexpected EOF while parsing string\n");
+ exit(1);
+ }
+
+ if (env->c == '\\') {
+ read_c(env);
+ switch (env->c) {
+ case 'n':
+ obstack_1grow(&env->obst, '\n');
+ break;
+ case '"':
+ case '\\':
+ obstack_1grow(&env->obst, env->c);
+ break;
+ default:
+ parse_error(env, "Unknown escape sequence '\\%c'\n", env->c);
+ exit(1);
+ }
+ } else {
+ obstack_1grow(&env->obst, env->c);
+ }
+ read_c(env);
+ }
+ read_c(env);
+ obstack_1grow(&env->obst, 0);
+
+ return (char*)obstack_finish(&env->obst);
+}
+
+static ident *read_ident(read_env_t *env)
+{
+ char *str = read_string(env);
+ ident *res = new_id_from_str(str);
+ obstack_free(&env->obst, str);
+ return res;
+}
+
+static ident *read_symbol(read_env_t *env)
+{
+ char *str = read_word(env);
+ ident *res = new_id_from_str(str);
+ obstack_free(&env->obst, str);
+ return res;
+}
+
+/*
+ * reads a "quoted string" or alternatively the token NULL
+ */
+static char *read_string_null(read_env_t *env)
+{
+ skip_ws(env);
+ if (env->c == 'N') {
+ char *str = read_word(env);
+ if (strcmp(str, "NULL") == 0) {
+ obstack_free(&env->obst, str);
+ return NULL;
+ }
+ } else if (env->c == '"') {
+ return read_string(env);
+ }
+
+ parse_error(env, "Expected \"string\" or NULL\n");
+ exit(1);
+}
+
+static ident *read_ident_null(read_env_t *env)
+{
+ ident *res;
+ char *str = read_string_null(env);
+ if (str == NULL)
+ return NULL;
+
+ res = new_id_from_str(str);
+ obstack_free(&env->obst, str);
+ return res;
+}
+
+static long read_long(read_env_t *env)
+{
+ long result;
+ char *str;
+
+ skip_ws(env);
+ if (!isdigit(env->c) && env->c != '-') {
+ parse_error(env, "Expected number, got '%c'\n", env->c);
+ exit(1);
+ }
+
+ assert(obstack_object_size(&env->obst) == 0);
+ do {
+ obstack_1grow(&env->obst, env->c);
+ read_c(env);
+ } while (isdigit(env->c));
+ obstack_1grow(&env->obst, 0);
+
+ str = (char*)obstack_finish(&env->obst);
+ result = atol(str);
+ obstack_free(&env->obst, str);
+
+ return result;
+}
+
+static int read_int(read_env_t *env)
+{
+ return (int) read_long(env);
+}
+
+static unsigned read_unsigned(read_env_t *env)
+{
+ return (unsigned) read_long(env);
+}
+
+static size_t read_size_t(read_env_t *env)
+{
+ /* FIXME */
+ return (size_t) read_unsigned(env);
+}
+
+static void expect_list_begin(read_env_t *env)
+{
+ skip_ws(env);
+ if (env->c != '[') {
+ parse_error(env, "Expected list, got '%c'\n", env->c);
+ exit(1);
+ }
+ read_c(env);
+}
+
+static bool list_has_next(read_env_t *env)
+{
+ if (feof(env->file)) {
+ parse_error(env, "Unexpected EOF while reading list");
+ exit(1);
+ }
+ skip_ws(env);
+ if (env->c == ']') {
+ read_c(env);
+ return false;
+ }
+
+ return true;
+}
+
+static void *get_id(read_env_t *env, long id)
+{
+ id_entry key, *entry;
+ key.id = id;
+
+ entry = (id_entry*)set_find(env->idset, &key, sizeof(key), (unsigned) id);
+ return entry ? entry->elem : NULL;
+}
+
+static void set_id(read_env_t *env, long id, void *elem)
+{
+ id_entry key;
+ key.id = id;
+ key.elem = elem;
+ set_insert(env->idset, &key, sizeof(key), (unsigned) id);
+}
+
+static ir_node *get_node_or_null(read_env_t *env, long nodenr)
+{
+ ir_node *node = (ir_node *) get_id(env, nodenr);
+ if (node && node->kind != k_ir_node) {
+ parse_error(env, "Irn ID %ld collides with something else\n",
+ nodenr);
+ return NULL;
+ }
+ return node;
+}
+
+static ir_type *get_type(read_env_t *env, long typenr)
+{
+ ir_type *type = (ir_type *) get_id(env, typenr);
+ if (type == NULL) {
+ parse_error(env, "Type %ld not defined (yet?)\n", typenr);
+ return get_unknown_type();
+ }
+ if (type->kind != k_type) {
+ parse_error(env, "Object %ld is not a type (but should be)\n", typenr);
+ return get_unknown_type();
+ }
+ return type;
+}
+
+static ir_type *read_type_ref(read_env_t *env)
+{
+ char *str = read_word(env);
+ if (strcmp(str, "none") == 0) {
+ obstack_free(&env->obst, str);
+ return get_none_type();
+ }
+ if (strcmp(str, "unknown") == 0) {
+ obstack_free(&env->obst, str);
+ return get_unknown_type();
+ }
+ if (strcmp(str, "code") == 0) {
+ obstack_free(&env->obst, str);
+ return get_code_type();
+ }
+ long nr = atol(str);
+ obstack_free(&env->obst, str);
+
+ return get_type(env, nr);
+}
+
+static ir_entity *create_error_entity(void)
+{
+ ir_entity *res = new_entity(get_glob_type(), new_id_from_str("error"),
+ get_unknown_type());
+ return res;
+}
+
+static ir_entity *get_entity(read_env_t *env, long entnr)
+{
+ ir_entity *entity = (ir_entity *) get_id(env, entnr);
+ if (entity == NULL) {
+ parse_error(env, "unknown entity: %ld\n", entnr);
+ return create_error_entity();
+ }
+ if (entity->kind != k_entity) {
+ parse_error(env, "Object %ld is not an entity (but should be)\n",
+ entnr);
+ return create_error_entity();
+ }
+
+ return entity;
+}
+
+static ir_entity *read_entity_ref(read_env_t *env)
+{
+ long nr = read_long(env);
+ return get_entity(env, nr);
+}
+
+static ir_mode *read_mode_ref(read_env_t *env)
+{
+ char *str = read_string(env);
+ size_t n = ir_get_n_modes();
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ ir_mode *mode = ir_get_mode(i);
+ if (strcmp(str, get_mode_name(mode)) == 0) {
+ obstack_free(&env->obst, str);
+ return mode;
+ }
+ }
+
+ parse_error(env, "unknown mode \"%s\"\n", str);
+ return mode_ANY;
+}
+
+static const char *get_typetag_name(typetag_t typetag)
+{
+ switch (typetag) {
+ case tt_align: return "align";
+ case tt_builtin_kind: return "builtin kind";
+ case tt_cond_jmp_predicate: return "cond_jmp_predicate";
+ case tt_initializer: return "initializer kind";
+ case tt_irg_inline_property: return "irg_inline_property";
+ case tt_keyword: return "keyword";
+ case tt_linkage: return "linkage";
+ case tt_mode_arithmetic: return "mode_arithmetic";
+ case tt_pin_state: return "pin state";
+ case tt_segment: return "segment";
+ case tt_throws: return "throws";
+ case tt_tpo: return "type";
+ case tt_type_state: return "type state";
+ case tt_visibility: return "visibility";
+ case tt_volatility: return "volatility";
+ case tt_where_alloc: return "where alloc";
+ }
+ return "<UNKNOWN>";
+}
+
+/**
+ * Read and decode an enum constant.
+ */
+static unsigned read_enum(read_env_t *env, typetag_t typetag)
+{
+ char *str = read_word(env);
+ unsigned code = symbol(str, typetag);
+
+ if (code != SYMERROR) {
+ obstack_free(&env->obst, str);
+ return code;
+ }
+
+ parse_error(env, "invalid %s: \"%s\"\n", get_typetag_name(typetag), str);
+ return 0;
+}
+
+static ir_align read_align(read_env_t *env)
+{
+ return (ir_align)read_enum(env, tt_align);
+}
+
+static ir_builtin_kind read_builtin_kind(read_env_t *env)
+{
+ return (ir_builtin_kind)read_enum(env, tt_builtin_kind);
+}
+
+static cond_jmp_predicate read_cond_jmp_predicate(read_env_t *env)
+{
+ return (cond_jmp_predicate)read_enum(env, tt_cond_jmp_predicate);
+}
+
+static ir_initializer_kind_t read_initializer_kind(read_env_t *env)
+{
+ return (ir_initializer_kind_t)read_enum(env, tt_initializer);
+}
+
+static ir_mode_arithmetic read_mode_arithmetic(read_env_t *env)
+{
+ return (ir_mode_arithmetic)read_enum(env, tt_mode_arithmetic);
+}
+
+static op_pin_state read_pin_state(read_env_t *env)
+{
+ return (op_pin_state)read_enum(env, tt_pin_state);
+}
+
+static ir_type_state read_type_state(read_env_t *env)
+{
+ return (ir_type_state)read_enum(env, tt_type_state);
+}
+
+static ir_visibility read_visibility(read_env_t *env)
+{
+ return (ir_visibility)read_enum(env, tt_visibility);
+}
+
+static ir_linkage read_linkage(read_env_t *env)
+{
+ return (ir_linkage)read_enum(env, tt_linkage);
+}
+
+static ir_volatility read_volatility(read_env_t *env)
+{
+ return (ir_volatility)read_enum(env, tt_volatility);
+}
+
+static ir_where_alloc read_where_alloc(read_env_t *env)
+{
+ return (ir_where_alloc)read_enum(env, tt_where_alloc);
+}
+
+static bool read_throws(read_env_t *env)
+{
+ return (bool)read_enum(env, tt_throws);
+}
+
+static keyword_t read_keyword(read_env_t *env)
+{
+ return (keyword_t)read_enum(env, tt_keyword);
+}
+
+static irg_inline_property read_inline_property(read_env_t *env)
+{
+ return (irg_inline_property)read_enum(env, tt_irg_inline_property);
+}
+
+static ir_relation read_relation(read_env_t *env)
+{
+ return (ir_relation)read_long(env);
+}
+
+static ir_tarval *read_tarval(read_env_t *env)
+{
+ ir_mode *tvmode = read_mode_ref(env);
+ char *str = read_word(env);
+ ir_tarval *tv;
+ if (strcmp(str, "bad") == 0)
+ return tarval_bad;
+ tv = new_tarval_from_str(str, strlen(str), tvmode);
+ if (tv == tarval_bad)
+ parse_error(env, "problem while parsing tarval '%s'\n", str);
+ obstack_free(&env->obst, str);
+
+ return tv;
+}
+
+static ir_switch_table *read_switch_table(read_env_t *env)
+{
+ size_t n_entries = read_size_t(env);
+ ir_switch_table *table = ir_new_switch_table(env->irg, n_entries);
+ size_t i;
+
+ for (i = 0; i < n_entries; ++i) {
+ long pn = read_long(env);
+ ir_tarval *min = read_tarval(env);
+ ir_tarval *max = read_tarval(env);
+ ir_switch_table_set(table, i, min, max, pn);
+ }
+ return table;
+}
+
+static ir_initializer_t *read_initializer(read_env_t *env)