+ 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_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);