text: /*
   * %CopyrightBegin%
   *
   * Copyright Ericsson AB and Kjell Winblad 2019-2021. All Rights Reserved.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   * %CopyrightEnd%
   */
  
  /*
   * Author: Kjell Winblad
   */
  
  #include <stdlib.h>
  #include <stdio.h>
  #include <string.h>
  
  
  #include "ycf_utils.h"
  #include "ycf_yield_fun.h"
  #include "ycf_node.h"
  #include "ycf_symbol.h"
  #include "ycf_string.h"
  #include "ycf_printers.h"
  #include "ycf_parser.h"
  
  static int ycf_yield_location_id_counter = 0;
  
  static
  ycf_node* mk_typedef_struct_node(ycf_node_list definitions, char* name){
    ycf_node* res = ycf_malloc(sizeof(ycf_node));
    res->next = NULL;
    res->type = ycf_node_type_gen_typedef_struct;
    res->u.gen_typedef_struct.definition_nodes = definitions;
    res->u.gen_typedef_struct.name = name;
    return res;
  }
  
  static
  ycf_node_list mk_ycf_trap_state_params(){
    return ycf_node_definition_list_from_string(ycf_string_new(
            "long* ycf_nr_of_reductions_param;\n"
            "void** ycf_trap_state;\n"
            "void* ycf_extra_context;\n"));
  }
  
  static
  ycf_node_list mk_saved_ycf_trap_state_params(){
    return ycf_node_definition_list_from_string(
            "ycf_yield_alloc_type ycf_yield_alloc;\n"
            "ycf_yield_free_type ycf_yield_free;\n"
            "void* ycf_yield_alloc_free_context;\n"
            "size_t ycf_stack_alloc_size_or_max_size;\n"
            "void* ycf_stack_alloc_data;\n");
  }
  
  static
  ycf_node_list mk_trap_extra_state(){
    return ycf_node_definition_list_from_string(
              "int ycf_trap_location;\n"
              "long ycf_nr_of_reductions;\n"
              "struct ycf_alloc_data ycf_frame_alloc_data;\n");;
  }
  
  static
  char* get_ycf_trap_state_assignments(ycf_node_list ycf_trap_state_defines){
    ycf_node* current = ycf_trap_state_defines.head;
    char* str = "";
    while(current != NULL){
      char* ident = ycf_symbol_get_text(current->u.definition.identifier);
      if(current->u.definition.array_brackets.head != NULL && !current->u.definition.array_brackets.head->u.array_bracket.empty){
        ycf_string_printable_buffer* array_size_exp = ycf_string_printable_buffer_new();
        ycf_node* bracket = current->u.definition.array_brackets.head;
        while(bracket != NULL){
          print_node_code_expression(bracket->u.array_bracket.content,array_size_exp);
            ycf_string_printable_buffer_printf(array_size_exp, " * ");
          bracket = bracket->next;
        }
          ycf_string_printable_buffer_printf(array_size_exp, " sizeof(");
        print_symbol_list(&current->u.definition.type_specifiers, array_size_exp);
          ycf_string_printable_buffer_printf(array_size_exp, ")");
        str = ycf_string_new("%s"
                             "    memcpy(ycf_my_trap_state->%s, %s, %s);\n",
                             str,
                             ident,
                             ident,
                             array_size_exp->buffer);
      }else{
        str = ycf_string_new("%s"
                             "    ycf_my_trap_state->%s = %s;\n",
                             str,
                             ident,
                             ident);
      }
      current = current->next;
    }
    return str;
  }
  
  static
  char* mk_code_from_special_code_list(ycf_node_list special_code_list){
    ycf_string_printable_buffer* b = ycf_string_printable_buffer_new();
    ycf_node* current = special_code_list.head;
    ycf_string_printable_buffer_printf(b, "\n/* YCF SPECIAL CUSTOM CODE START */\n");
    while(current != NULL) {
      ycf_node_print(current->u.special_code_block.code.if_statement, b);
      ycf_string_printable_buffer_printf(b, "\n");
      current = current->next;
    }
    ycf_string_printable_buffer_printf(b, "\n/* YCF SPECIAL CUSTOM CODE END */\n");
    return b->buffer;
  }
  
  static
  ycf_node* mk_print_offsets_for_struct_fields(char* ycf_trap_state_name,
                                               ycf_node_list ycf_trap_state_defines) {
  
      ycf_string_printable_buffer* buffer =  ycf_string_printable_buffer_new();
      ycf_node* iterator = ycf_trap_state_defines.head;
      while (iterator != NULL) {
          char * fieldName = ycf_symbol_get_text(iterator->u.definition.identifier);
          ycf_string_printable_buffer_printf(buffer,
                                             "fprintf(stderr, \"    %s: %%zu\\n\","
                                             " (size_t)&((struct %s*)0)->%s  );\n",
                                             fieldName,
                                             ycf_trap_state_name,
                                             fieldName);
          iterator = iterator->next;
      }
      char* ret =
          ycf_string_new(("static void %s_print_offsets_for_struct_fields(void);\n"
                          "static void %s_print_offsets_for_struct_fields() {\n"
                          "fprintf(stderr, \"Field offsets for struct %s:\\n\");\n"
                          "%s\n"
                          "}\n"),
                         ycf_trap_state_name,
                         ycf_trap_state_name,
                         ycf_trap_state_name,
                         buffer->buffer);
      return ycf_node_new_text_node(ret);
  }
  
  static
  ycf_node* mk_yield_code(ycf_node* f_node,
                          char* ycf_trap_state_name,
                          ycf_node_list ycf_trap_state_defines,
                          ycf_node_list on_save_yield_state_code_list,
                          bool debug){
    char* ret_code;
    if(ycf_node_is_void_ret_fun(f_node)) {
      ret_code = "return;\n";
    } else {
      ycf_symbol_list ret_type = ycf_node_get_return_type(f_node);
      ret_code =
        ycf_string_new("  {\n"
                       "    static %s const ycf_unused_ret_value;\n"
                       "    return ycf_unused_ret_value;\n"
                       "  }\n",
                       ycf_symbol_list_to_str(&ret_type));
    }
    char *debug_check_for_stack_ptrs = "";
    char *debug_zero_my_trap_state = "";
    if(debug){
      debug_check_for_stack_ptrs =
        ycf_string_new("ycf_debug_check_block(\"%s\",\n"
                       "                      ycf_find_stack_bottom_conservative(),\n"
                       "                      ycf_trap_state,\n"
                       "                      ycf_my_trap_state,\n"
                       "                      sizeof(struct %s),\n"
                       "                      %s_print_offsets_for_struct_fields);\n",
                       ycf_trap_state_name,
                       ycf_trap_state_name,
                       ycf_trap_state_name);
      debug_zero_my_trap_state =
          ycf_string_new("  for (int i = 0; i < sizeof(struct %s); i++) {\n"
                         "    ((char*)ycf_my_trap_state)[i] = 0;\n"
                         "  }\n", ycf_trap_state_name);
    }
    char* code = ycf_string_new("\n"
                                "{\n"
                                "  struct %s* ycf_my_trap_state;\n"
                                "  ycf_do_yield_label_%s:;\n"
                                "  %s"
                                "  if (*ycf_trap_state == NULL) {\n"
                                "    ycf_my_trap_state = ycf_yield_alloc(sizeof(struct %s), ycf_yield_alloc_free_context);\n"
                                "    %s"
                                "  } else {\n"
                                "    ycf_my_trap_state = *ycf_trap_state;\n"
                                "  }\n"
                                "  %s\n"
                                "  *ycf_nr_of_reductions_param = ycf_nr_of_reductions;\n"
                                "  *ycf_trap_state = ycf_my_trap_state;\n"
                                "  %s"
                                "  %s\n"
                                "}\n"
                                "\n",
                                ycf_trap_state_name,
                                ycf_symbol_get_text(f_node->u.function.definition.definition.identifier),
                                mk_code_from_special_code_list(on_save_yield_state_code_list),
                                ycf_trap_state_name,
                                debug_zero_my_trap_state,
                                get_ycf_trap_state_assignments(ycf_trap_state_defines),
                                debug_check_for_stack_ptrs,
                                ret_code
    );
    return ycf_node_get_from_code_scope_text(code);
  }
  
  ycf_node* mk_goto_yield_code(ycf_node* f_node,
                               char* ycf_trap_state_name,
                               ycf_node_list ycf_trap_state_defines){
    ycf_yield_location_id_counter++;
    char* code = ycf_string_new("\n"
                                "{\n"
                                "  ycf_nr_of_reductions = 0;\n"
                                "  ycf_trap_location = %d;\n"
                                "  goto ycf_do_yield_label_%s;\n"
                                "  ycf_yield_location_label_%d:;\n"
                                "}\n",
                                ycf_yield_location_id_counter,
                                ycf_symbol_get_text(f_node->u.function.definition.definition.identifier),
                                ycf_yield_location_id_counter
    );
    return ycf_node_get_from_code_scope_text(code);
  }
  
  static
  ycf_node* mk_goto_yield_no_reds_code(ycf_node* f_node,
                                       char* ycf_trap_state_name,
                                       ycf_node_list ycf_trap_state_defines){
    ycf_yield_location_id_counter++;
    char* code = ycf_string_new("\n"
                                "{\n"
                                "  ycf_trap_location = %d;\n"
                                "  goto ycf_do_yield_label_%s;\n"
                                "  ycf_yield_location_label_%d:;\n"
                                "}\n",
                                ycf_yield_location_id_counter,
                                ycf_symbol_get_text(f_node->u.function.definition.definition.identifier),
                                ycf_yield_location_id_counter
    );
    return ycf_node_get_from_code_scope_text(code);
  }
  
  
  static
  ycf_node* mk_yield_fun_call_state_var(ycf_node* f){
    ycf_node_list code = ycf_node_list_empty();
    char* fun_name = NULL;
    if(f->u.statement.expression->type == ycf_node_type_function_call){
      fun_name = ycf_symbol_get_text(f->u.statement.expression->u.function_call.identifier);
    }else{
      fun_name = ycf_symbol_get_text(f->u.statement.expression->u.function_call_assignment.fun_call.identifier);
    }
    ycf_node * scope_with_dec =
            ycf_node_get_from_code_scope_text(ycf_string_new("void* ycf_sub_fun_trap_state_wb = NULL;\n"
                                                             "/*special_code_start:ON_DESTROY_STATE*/\n"
                                                             "if(0){\n"
                                                             "  if(ycf_sub_fun_trap_state_wb != NULL)\n{"
                                                             "     %s_ycf_gen_destroy(ycf_sub_fun_trap_state_wb);\n"
                                                             "  }\n"
                                                             "}\n"
                                                             "/*special_code_end*/\n", fun_name));
    ycf_node_list_append(&code, ycf_node_shallow_copy(f));
    ycf_node_list_append(&code, scope_with_dec->u.code_scope.other_nodes.head);
    ycf_node* ret = ycf_node_scope_new(ycf_symbol_new_open_curly_brace(),
                                       scope_with_dec->u.code_scope.definition_nodes,
                                       code,
                                       ycf_symbol_new_end_curly_brace());
    return ret;
  }
  
  static
  ycf_node* mk_yield_fun_call(ycf_node* c_file_node,
                              ycf_node* f,
                              char* ycf_trap_state_var_name,
                              char* calling_fun_name,
                              bool auto_yield){
    ycf_yield_location_id_counter++;
    ycf_node_function_call f_node;
    char* assignment_code = "";
    char* tmp_assignment_var_name = "ycf_tmp_fun_call_tmp_var";
    char* tmp_assignment_var_declaration = "";
    char* parameters = "";
    char* finalize_call_code = "";
    if(f->u.statement.expression->type == ycf_node_type_function_call){
      f_node = f->u.statement.expression->u.function_call;
    }else{
      ycf_symbol_list called_fun_ret_type;
      ycf_string_printable_buffer* assign_to_b = ycf_string_printable_buffer_new();
      f_node = f->u.statement.expression->u.function_call_assignment.fun_call;
      called_fun_ret_type =
        ycf_node_find_function_return_type(c_file_node,
                                           ycf_symbol_get_text(f_node.identifier));
      tmp_assignment_var_declaration =
        ycf_string_new("%s %s;\n",
                       ycf_symbol_list_to_str(&called_fun_ret_type),
                       tmp_assignment_var_name);
      print_node_code_expression(f->u.statement.expression->u.function_call_assignment.left_side, assign_to_b);
      assignment_code = ycf_string_new("%s = ", tmp_assignment_var_name);
      finalize_call_code = ycf_string_new("%s = %s;\n",
                                          assign_to_b->buffer,
                                          tmp_assignment_var_name);
    }
    if (f_node.parameter_expressions.head != NULL){
      ycf_string_printable_buffer* b = ycf_string_printable_buffer_new();
      print_node_list_code(f_node.parameter_expressions.head, b);
      parameters = ycf_string_new(",%s", b->buffer);
    }
  
    char* code = ycf_string_new("%s"
                                "%s"
                                "%s %s%s_ycf_gen_yielding(&ycf_nr_of_reductions,\n"
                                "                         &%s,ycf_extra_context,\n"
                                "                         ycf_yield_alloc,ycf_yield_free,\n"
                                "                         ycf_yield_alloc_free_context,\n"
                                "                         YCF_ALLOC_NEXT_MAX_SIZE(),\n"
                                "                         YCF_ALLOC_NEXT_BLOCK()\n"
                                "                         %s);\n"
                                "while(YCF_IS_YIELDED(%s)){\n"
                                "   ycf_trap_location = %d;\n"
                                "   goto ycf_do_yield_label_%s;\n"
                                "  ycf_yield_location_label_%d:;\n"
                                "   %s %s%s_ycf_gen_continue(&ycf_nr_of_reductions,\n"
                                "                            &%s,\n"
                                "                            ycf_extra_context);\n"
                                "}\n"
                                "%s\n",
                                tmp_assignment_var_declaration,
                                auto_yield ? "YCF_CONSUME_REDS(1);" : "",
                                assignment_code,
                                ycf_symbol_list_to_str(&f_node.neg_symbols),
                                ycf_symbol_get_text(f_node.identifier),
                                ycf_trap_state_var_name,
                                parameters,
                                ycf_trap_state_var_name,
                                ycf_yield_location_id_counter,
                                calling_fun_name,
                                ycf_yield_location_id_counter,
                                assignment_code,
                                ycf_symbol_list_to_str(&f_node.neg_symbols),
                                ycf_symbol_get_text(f_node.identifier),
                                ycf_trap_state_var_name,
                                finalize_call_code
    );
  
    return ycf_node_get_from_code_scope_text(code);
  }
  
  
  static
  char* get_trap_restore_assignments(ycf_node_list ycf_trap_state_defines){
    ycf_node* current = ycf_trap_state_defines.head;
    char* str = "\n";
    while(current != NULL){
      char* ident = ycf_symbol_get_text(current->u.definition.identifier);
      if(current->u.definition.array_brackets.head != NULL && !current->u.definition.array_brackets.head->u.array_bracket.empty){
        ycf_string_printable_buffer* array_size_exp = ycf_string_printable_buffer_new();
        ycf_node* bracket = current->u.definition.array_brackets.head;
        while(bracket != NULL){
          print_node_code_expression(bracket->u.array_bracket.content,array_size_exp);
            ycf_string_printable_buffer_printf(array_size_exp, " * ");
          bracket = bracket->next;
        }
          ycf_string_printable_buffer_printf(array_size_exp, " sizeof(");
        print_symbol_list(&current->u.definition.type_specifiers, array_size_exp);
          ycf_string_printable_buffer_printf(array_size_exp, ")");
        str = ycf_string_new("%s"
                             "    memcpy(%s, ycf_my_trap_state->%s, %s);\n",
                             str,
                             ident,
                             ident,
                             array_size_exp->buffer);
      }else{
        str = ycf_string_new("%s"
                             "    %s = ycf_my_trap_state->%s;\n",
                             str,
                             ident,
                             ident);
      }
      current = current->next;
    }
    return str;
  }
  
  static
  char* get_debug_trap_zero_assignments(ycf_node_list ycf_trap_state_defines){
      ycf_node* current = ycf_trap_state_defines.head;
      char* str = "\n";
      while(current != NULL){
          char* ident = ycf_symbol_get_text(current->u.definition.identifier);
          if(current->u.definition.array_brackets.head != NULL &&
             !current->u.definition.array_brackets.head->u.array_bracket.empty){
              ycf_string_printable_buffer* array_size_exp = ycf_string_printable_buffer_new();
              ycf_node* bracket = current->u.definition.array_brackets.head;
              while(bracket != NULL){
                  print_node_code_expression(bracket->u.array_bracket.content,array_size_exp);
                  ycf_string_printable_buffer_printf(array_size_exp, " * ");
                  bracket = bracket->next;
              }
              ycf_string_printable_buffer_printf(array_size_exp, " sizeof(");
              print_symbol_list(&current->u.definition.type_specifiers, array_size_exp);
              ycf_string_printable_buffer_printf(array_size_exp, ")");
              str = ycf_string_new("%s"
                                   "    memset((char*)(void*)%s, 0, %s);\n",
                                   str,
                                   ident,
                                   array_size_exp->buffer);
          }else{
              ycf_string_printable_buffer* type = ycf_string_printable_buffer_new();
              print_symbol_list(&current->u.definition.type_specifiers, type);
              str = ycf_string_new("%s"
                                   "    memset((char*)(void*)&%s, 0, sizeof(%s));\n",
                                   str,
                                   ident,
                                   type->buffer);
          }
          current = current->next;
      }
      return str;
  }
  
  static
  char* get_goto_ycf_trap_location_switch(int nr_of_ycf_trap_locations){
    int i;
    char* str = "switch(ycf_trap_location){\n";
    for(i = 1; i <= nr_of_ycf_trap_locations; i++){
      str = ycf_string_new("%s"
                           "case %d: goto ycf_yield_location_label_%d;\n", str, i, i);
    }
    str = ycf_string_new("%s\n}", str, i, i);
    return str;
  }
  
  typedef struct {
    ycf_node* f_node;
    char* ycf_trap_state_name;
    ycf_node_list ycf_trap_state_defines;
  } yield_code_replacer_context;
  
  ycf_node* yield_code_replacer(ycf_node* candidate, ycf_node_code_scope* s,void* context){
    yield_code_replacer_context* c = context;
    (void)s;
    if(candidate->type == ycf_node_type_statement &&
       candidate->u.statement.expression != NULL &&
       candidate->u.statement.expression->type == ycf_node_type_function_call &&
       ycf_symbol_is_text_eq(candidate->u.statement.expression->u.function_call.identifier,
                             "YCF_YIELD") &&
       candidate->u.statement.expression->u.function_call.parameter_expressions.head == NULL){
      ycf_node* yield_code = mk_goto_yield_code(c->f_node, c->ycf_trap_state_name, c->ycf_trap_state_defines);
      return yield_code;
    } else {
      return candidate;
    }
  }
  
  static
  void insert_yield_code(ycf_node* f_node, char* ycf_trap_state_name, ycf_node_list ycf_trap_state_defines, ycf_node_code_scope* s){
      ycf_node_search_and_replace_statements_in_scope(s,
                                                      yield_code_replacer,
                                                      &(yield_code_replacer_context) {f_node, ycf_trap_state_name,
                                                                                      ycf_trap_state_defines});
  }
  
  static
  ycf_node* special_code_section_replacer(ycf_node* candidate, ycf_node_code_scope* s,void* context){
    (void)context;
    (void)s;
    if(candidate->type == ycf_node_type_statement &&
       candidate->u.statement.expression != NULL &&
       candidate->u.statement.expression->type == ycf_node_type_function_call) {
      ycf_node_function_call fun_call = candidate->u.statement.expression->u.function_call;
      ycf_symbol* fun_name = fun_call.identifier;
      if(ycf_symbol_is_text_eq(fun_name, "YCF_SPECIAL_CODE_START") &&
         ycf_node_list_length(fun_call.parameter_expressions) == 1) {
        char* parameter = ycf_node_to_string(fun_call.parameter_expressions.head);
        ycf_node* special_code_start =
          ycf_node_new_text_node(ycf_string_new("/*special_code_start:%s*/\n"
                                                "if(0){\n",
                                                parameter));
        return special_code_start;
      } else if (ycf_symbol_is_text_eq(candidate->u.statement.expression->u.function_call.identifier,
                                       "YCF_SPECIAL_CODE_END") &&
                 ycf_node_list_length(fun_call.parameter_expressions) == 0) {
        return ycf_node_new_text_node("}/*special_code_end*/\n");
      }
    }
    return candidate;
  }
  
  static
  ycf_node* replace_alt_syntax_special_code_section_code(ycf_node* f_node){
      ycf_node_search_and_replace_statements_in_scope(&f_node->u.function.body,
                                                      special_code_section_replacer,
                                                      NULL);
      return ycf_node_get_function_from_text(ycf_node_to_string(f_node));
  }
  
  
  static
  ycf_node* yield_no_reds_code_replacer(ycf_node* candidate, ycf_node_code_scope* s,void* context){
    yield_code_replacer_context* c = context;
    (void)s;
    if(candidate->type == ycf_node_type_statement &&
       candidate->u.statement.expression != NULL &&
       candidate->u.statement.expression->type == ycf_node_type_function_call &&
       ycf_symbol_is_text_eq(candidate->u.statement.expression->u.function_call.identifier,
                             "YCF_YIELD_NO_REDS") &&
       candidate->u.statement.expression->u.function_call.parameter_expressions.head == NULL){
      ycf_node* yield_code = mk_goto_yield_no_reds_code(c->f_node, c->ycf_trap_state_name, c->ycf_trap_state_defines);
      return yield_code;
    } else {
      return candidate;
    }
  }
  
  static
  void insert_yield_no_reds_code(ycf_node* f_node, char* ycf_trap_state_name, ycf_node_list ycf_trap_state_defines, ycf_node_code_scope* s){
      ycf_node_search_and_replace_statements_in_scope(s,
                                                      yield_no_reds_code_replacer,
                                                      &(yield_code_replacer_context){f_node, ycf_trap_state_name,
                                                                                    ycf_trap_state_defines});
  }
  
  typedef struct {
    ycf_node_list on_return_code_list;
    ycf_node_list on_return_or_destroy_code_list;
    bool auto_yield;
  } replace_return_ctx;
  
  static
  ycf_node* save_nr_of_reductions_before_return_replacer(ycf_node* candidate,
                                                         ycf_node_code_scope* s,
                                                         void* context){
    replace_return_ctx* ctx = context;
    (void)s;
    char* consume_reds_code = ctx->auto_yield ? "YCF_CONSUME_REDS(1);\n" : "";
    if(candidate->type == ycf_node_type_return_statement){
      char* code =
        ycf_string_new("\n"
                       "%s"
                       "if (*ycf_trap_state != NULL) {\n"
                       "   ycf_yield_free(*ycf_trap_state, ycf_yield_alloc_free_context);\n"
                       "   *ycf_trap_state = NULL;\n"
                       "}\n"
                       "ycf_destroy_stack_allocator(&ycf_frame_alloc_data,\n"
                       "                            ycf_yield_free,\n"
                       "                            ycf_yield_alloc_free_context);\n"
                       "*ycf_nr_of_reductions_param = ycf_nr_of_reductions;"
                       "%s"
                       "%s"
                       "%s",
                       consume_reds_code,
                       mk_code_from_special_code_list(
                                                      ctx->on_return_or_destroy_code_list),
                       mk_code_from_special_code_list(ctx->on_return_code_list),
                       ycf_node_to_string(candidate));
      return ycf_node_get_from_code_scope_text(code);
    } else {
      return candidate;
    }
  }
  
  static
  void save_nr_of_reductions_before_return(ycf_node_code_scope* s,
                                           ycf_node_list on_return_code_list,
                                           ycf_node_list on_return_or_destroy_code_list,
                                           bool auto_yield){
    replace_return_ctx ctx;
    ctx.on_return_code_list = on_return_code_list;
    ctx.on_return_or_destroy_code_list = on_return_or_destroy_code_list;
    ctx.auto_yield = auto_yield;
    ycf_node_search_and_replace_statements_in_scope(s,
                                                    save_nr_of_reductions_before_return_replacer,
                                                    &ctx);
  }
  
  ycf_node* mk_consume_reds_code(char* function_name, ycf_node* consume_reds_node){
      ycf_node_list parameters = consume_reds_node->u.statement.expression->u.function_call.parameter_expressions;
      ycf_string_printable_buffer* b = ycf_string_printable_buffer_new();
      ycf_yield_location_id_counter++;
      ycf_string_printable_buffer_printf(b, "(");
      ycf_node* exp = ycf_node_list_get_item_at_position(&parameters, 0);
      print_node_code_expression(exp->u.expression, b);
      ycf_string_printable_buffer_printf(b, ")");
      return ycf_node_get_from_code_scope_text(ycf_string_new("ycf_nr_of_reductions = ycf_nr_of_reductions - %s;\n"
                                                              "if (ycf_nr_of_reductions <= 0) {\n"
                                                              "  ycf_trap_location = %d;\n"
                                                              "  goto ycf_do_yield_label_%s;\n"
                                                              "  ycf_yield_location_label_%d:;\n"
                                                              "}\n",
                                                              b->buffer,
                                                              ycf_yield_location_id_counter,
                                                              function_name,
                                                              ycf_yield_location_id_counter));
  }
  
  static
  ycf_node* consume_reds_replacer(ycf_node* candidate, ycf_node_code_scope* s, void* context){
    char* function_name = context;
    (void)s;
    if(candidate->type == ycf_node_type_statement &&
       candidate->u.statement.expression != NULL &&
       candidate->u.statement.expression->type == ycf_node_type_function_call &&
       ycf_symbol_is_text_eq(candidate->u.statement.expression->u.function_call.identifier,
                             "YCF_CONSUME_REDS")){
        ycf_node_list parameters = candidate->u.statement.expression->u.function_call.parameter_expressions;
        if (ycf_node_list_length(parameters) != 1){
            fprintf(stderr, "Error: YCF_CONSUME_REDS call needs exactly one parameter\n");
            exit(1);
        }
        return mk_consume_reds_code(function_name, candidate);
    } else {
      return candidate;
    }
  }
  
  static
  void insert_consume_reds_code(char* function_name, ycf_node_code_scope* s){
      ycf_node_search_and_replace_statements_in_scope(s,
                                                      consume_reds_replacer,
                                                      function_name);
  }
  
  static
  ycf_node* mk_consume_reds_wrapped_statement(ycf_node* statement){
    return ycf_node_get_from_code_scope_text(ycf_string_new("YCF_CONSUME_REDS(1);\n"
                                                            "%s\n", ycf_node_to_string(statement)));
  }
  
  static
  void insert_consume_reds_calls(ycf_node_code_scope* s);
  
  static
  ycf_node* consume_reds_calls_inserter(ycf_node* candidate, ycf_node_code_scope* s, void* context){
    if(candidate->type == ycf_node_type_goto){
      return mk_consume_reds_wrapped_statement(candidate);
    } else if (candidate->type == ycf_node_type_while){
      if(candidate->u.while_n.statement->type == ycf_node_type_code_scope){
        insert_consume_reds_calls(&candidate->u.while_n.statement->u.code_scope);
      }
      candidate->u.while_n.statement = mk_consume_reds_wrapped_statement(candidate->u.while_n.statement);
      return candidate;
    } else if (candidate->type == ycf_node_type_do_while){
      if(candidate->u.do_while.statement->type == ycf_node_type_code_scope){
        insert_consume_reds_calls(&candidate->u.do_while.statement->u.code_scope);
      }
      candidate->u.do_while.statement = mk_consume_reds_wrapped_statement(candidate->u.do_while.statement);
      return candidate;
    } else if (candidate->type == ycf_node_type_for){
      if(candidate->u.for_n.statement->type == ycf_node_type_code_scope){
        insert_consume_reds_calls(&candidate->u.for_n.statement->u.code_scope);
      }
      candidate->u.for_n.statement = mk_consume_reds_wrapped_statement(candidate->u.for_n.statement);
      return candidate;
    } else {
      return candidate;
    }
  }
  
  static void insert_consume_reds_calls(ycf_node_code_scope* s){
      ycf_node_search_and_replace_statements_in_scope(s,
                                                      consume_reds_calls_inserter,
                                                      NULL);
  }
  
  typedef struct {
    ycf_node_list code;
    ycf_node_type code_type;
  } special_code_context;
  
  ycf_node* do_special_code_replace(ycf_node* candidate, ycf_node_code_scope* s, void* context){
    special_code_context* c = context;
    (void)s;
    if(candidate->type == c->code_type){
      ycf_node_list_append(&c->code, ycf_node_shallow_copy(candidate));
      return ycf_node_new_text_node("\n/* YCF Replaced special code */\n");
    } else {
      return candidate;
    }
  }
  
  static
  ycf_node_list save_and_replace_special_code(ycf_node_code_scope* s, ycf_node_type code_type){
    special_code_context context;
    context.code = ycf_node_list_empty();
    context.code_type = code_type;
      ycf_node_search_and_replace_statements_in_scope(s,
                                                      do_special_code_replace,
                                                      &context);
    return context.code;
  }
  
  static
  ycf_node* insert_fun_call_state_var_replacer(ycf_node* candidate, ycf_node_code_scope* s, void* context){
    ycf_string_item_list* yielding_funs = context;
    (void)s;
    if(candidate->type == ycf_node_type_statement &&
       (candidate->u.statement.expression->type == ycf_node_type_function_call ||
        candidate->u.statement.expression->type == ycf_node_type_assignment_function_call)){
      ycf_string_item* current = yielding_funs->head;
      while(current != NULL){
        char* fun_name = NULL;
        if(candidate->u.statement.expression->type == ycf_node_type_function_call){
          fun_name = ycf_symbol_get_text(candidate->u.statement.expression->u.function_call.identifier);
        } else if(candidate->u.statement.expression->type == ycf_node_type_assignment_function_call){
          fun_name = ycf_symbol_get_text(
                  candidate->u.statement.expression->u.function_call_assignment.fun_call.identifier);
        } else {
          current = current->next;
          continue;
        }
        if(ycf_string_is_equal(current->str, fun_name)){
          return mk_yield_fun_call_state_var(candidate);
        }
        current = current->next;
      }
    }
    return candidate;
  }
  
  static
  void insert_fun_call_state_var(ycf_node_code_scope* s, ycf_string_item_list* yielding_funs){
      ycf_node_search_and_replace_statements_in_scope(s,
                                                      insert_fun_call_state_var_replacer,
                                                      yielding_funs);
  }
  
  typedef struct {
    ycf_node* c_file_node;
    char* calling_fun_name;
    ycf_string_item_list* yielding_funs;
    ycf_string_item_list* starte_vars_wb;
    bool auto_yield;
  } yielding_fun_call_code_context;
  
  static
  ycf_node* insert_yielding_fun_call_code_replacer(ycf_node* candidate,
                                                   ycf_node_code_scope* s,
                                                   void* context){
    yielding_fun_call_code_context* c = context;
    ycf_node* c_file_node = c->c_file_node;
    ycf_string_item_list* yielding_funs = c->yielding_funs;
    (void)s;
    if (candidate->type == ycf_node_type_code_scope &&
        candidate->u.code_scope.other_nodes.head != candidate->u.code_scope.other_nodes.last){
      ycf_node* call_candidate = candidate->u.code_scope.other_nodes.head->next;
      if (call_candidate->type == ycf_node_type_statement &&
          (call_candidate->u.statement.expression->type == ycf_node_type_function_call ||
           call_candidate->u.statement.expression->type == ycf_node_type_assignment_function_call)) {
        ycf_string_item* current = yielding_funs->head;
        while(current != NULL){
          char* fun_name = NULL;
          if (call_candidate->u.statement.expression->type == ycf_node_type_function_call) {
            fun_name = ycf_symbol_get_text(call_candidate->u.statement.expression->u.function_call.identifier);
          } else if (call_candidate->u.statement.expression->type == ycf_node_type_assignment_function_call) {
            fun_name = ycf_symbol_get_text(
                    call_candidate->u.statement.expression->u.function_call_assignment.fun_call.identifier);
          } else {
            current = current->next;
            continue;
          }
          if(ycf_string_is_equal(current->str, fun_name)){
            char* ycf_trap_state_var_name =
              ycf_symbol_get_text(ycf_node_get_assignment(candidate->u.code_scope.other_nodes.head)->left_side.content.head->u.other.what);
              ycf_string_item_list_append(c->starte_vars_wb, ycf_string_item_new(ycf_trap_state_var_name));
              ycf_node* new_call_code = mk_yield_fun_call(c_file_node,
                                                          call_candidate,
                                                          ycf_trap_state_var_name,
                                                          c->calling_fun_name,
                                                          c->auto_yield);
            ycf_node_list_replace(&candidate->u.code_scope.other_nodes, call_candidate, new_call_code);
            return ycf_node_scope_new(ycf_symbol_new_open_curly_brace(),
                                      candidate->u.code_scope.definition_nodes,
                                      candidate->u.code_scope.other_nodes,
                                      ycf_symbol_new_end_curly_brace());;
          }
          current = current->next;
        }
      }
    }
    return candidate;
  }
  
  ycf_string_item_list insert_yielding_fun_call_code(ycf_node* c_file_node,
                                                     ycf_node_code_scope* s,
                                                     ycf_string_item_list* yielding_funs,
                                                     char* calling_fun_name,
                                                     bool auto_yield){
    yielding_fun_call_code_context context;
    ycf_string_item_list state_vars = ycf_string_item_list_empty();
    context.c_file_node = c_file_node;
    context.calling_fun_name = calling_fun_name;
    context.yielding_funs = yielding_funs;
    context.starte_vars_wb = &state_vars;
    context.auto_yield = auto_yield;
    ycf_node_search_and_replace_statements_in_scope(s,
                                                    insert_yielding_fun_call_code_replacer,
                                                    &context);
    return state_vars;
  }
  
  static
  ycf_node* mk_yield_init_code(char* ycf_trap_state_name,
                               ycf_node_list ycf_trap_state_defines,
                               ycf_node_list on_restore_yield_state_code_list,
                               bool auto_yield,
                               char *function_name,
                               ycf_node_list declarations_in_function_body,
                               bool is_debug_mode){
    char* code = ycf_string_new("\n"
                                "{\n"
                                "  %s\n"
                                "  ycf_nr_of_reductions = *ycf_nr_of_reductions_param;\n"
                                "  ycf_frame_alloc_data.size = 0;\n"
                                "  ycf_frame_alloc_data.max_size = ycf_stack_alloc_size_or_max_size;\n"
                                "  ycf_frame_alloc_data.data = ycf_stack_alloc_data;\n"
                                "  ycf_frame_alloc_data.needs_freeing = 0;\n"
                                "  if(*ycf_trap_state != NULL){\n"
                                "     struct %s* ycf_my_trap_state = *ycf_trap_state;\n"
                                "     %s\n"
                                "     %s\n"
                                "     ycf_nr_of_reductions = *ycf_nr_of_reductions_param;\n"
                                "     %s\n"
                                "  }\n"
                                "}\n",
                                (is_debug_mode ? get_debug_trap_zero_assignments(declarations_in_function_body): ""),
                                ycf_trap_state_name,
                                get_trap_restore_assignments(ycf_trap_state_defines),
                                mk_code_from_special_code_list(on_restore_yield_state_code_list),
                                get_goto_ycf_trap_location_switch(ycf_yield_location_id_counter));
    return ycf_node_get_from_code_scope_text(code);
  }
  
  static
  ycf_node* mk_destroy_state_function_node(char* yielding_function_name,
                                           ycf_node_list defs,
                                           char* ycf_trap_state_struct_name,
                                           ycf_node_list destroy_code,
                                           ycf_node_list on_destroy_state_or_return_code_list,
                                           bool static_aux_funs){
    ycf_node_list my_defs = ycf_node_list_shallow_copy(defs);
    ycf_node* current = my_defs.head;
    while(current != NULL){
      current->u.definition.end = ycf_symbol_new_semicolon();
      int empty_array_brackets = 0;
      {
        current->u.definition.array_brackets = ycf_node_list_shallow_copy(current->u.definition.array_brackets);
        ycf_node* b = current->u.definition.array_brackets.head;
        while(b != NULL && b->u.array_bracket.empty){
          empty_array_brackets++;
          ycf_node_list_remove(&current->u.definition.array_brackets, b);
          b = b->next;
        }
      }
      current->u.definition.type_specifiers = ycf_symbol_list_shallow_copy(current->u.definition.type_specifiers);
      if(empty_array_brackets > 0){
        for(int i = 0; i < empty_array_brackets; i++){
          ycf_symbol_list_append(&current->u.definition.type_specifiers, ycf_symbol_new_star());
        }
      }
      current = current->next;
    }
    char* code =
      ycf_string_new("\n"
                     "%s void %s_ycf_gen_destroy(void* ycf_my_trap_state_param){\n"
                     "     {\n"
                     "     struct %s* ycf_my_trap_state = ycf_my_trap_state_param;\n"
                     "     %s\n"
                     "     %s\n"
                     "     %s\n"
                     "     %s\n"
                     "     ycf_destroy_stack_allocator(&ycf_frame_alloc_data, ycf_yield_free, ycf_yield_alloc_free_context);\n"
                     "     ycf_yield_free(ycf_my_trap_state, ycf_yield_alloc_free_context);\n"
                     "     }\n"
                     "}\n",
                     static_aux_funs ? "static" : "",
                     yielding_function_name,
                     ycf_trap_state_struct_name,
                     ycf_node_list_to_string(&my_defs),
                     get_trap_restore_assignments(my_defs),
                     mk_code_from_special_code_list(on_destroy_state_or_return_code_list),
                     mk_code_from_special_code_list(destroy_code));
    return ycf_node_get_function_from_text(code);
  }
  
  void ast_add_yield_code_generated_define(ycf_node* source_out_tree/*Will be changed*/, bool debug_mode)
  {
    char *debug_mode_code =
      (debug_mode ?
       "\n"
       "#include <setjmp.h>\n"
       "#include <stdint.h>\n"
       "#include <string.h>\n"
       "#include <inttypes.h>\n"
       "static void* ycf_find_stack_bottom_conservative_helper(void);\n"
       "static void* ycf_find_stack_bottom_conservative(void);\n"
       "static void* ycf_find_stack_bottom_conservative_helper() {\n"
       "  void* p = NULL;\n"
       "  volatile intptr_t tmp = (intptr_t)&p;\n"
       "  /* codechecker_intentional [StackAddrEscapeBase] */\n"
       "  return (void*)tmp;\n"
       "}\n"
       "static void* ycf_find_stack_bottom_conservative() {\n"
       "  jmp_buf env;\n"
       "  setjmp(env);\n"
       "\n"
       "  {\n"
       "  volatile int noinline = 1;\n"
       "  void* (*bottom)(void) = noinline\n"
       "    ? ycf_find_stack_bottom_conservative_helper\n"
       "    : (void*(*)(void))(NULL);\n"
       "\n"
       "  return bottom();\n"
       "  }\n"
       "}\n"
       "void* ycf_debug_get_stack_start(void);\n"
       "#include <signal.h>\n"
       "static void ycf_debug_check_block(char*, void*, void*, void*, size_t, void (*)(void));\n"
       "static void ycf_debug_check_block(char* struct_name, void* stack_start, void* stack_end, void* block, size_t block_size, void (*print_offsets_function)(void)) {\n"
       "  char* p;\n"
       "  if (ycf_debug_get_stack_start() != NULL) {\n"
       "    stack_end = ycf_debug_get_stack_start();\n"
       "  }\n"
       "  for (p = block; p < (((char*)block) + block_size); p += sizeof(void*)) {\n"
       "    if(*((char**)p) > (char*)stack_start && *((char**)p) <= (char*)stack_end){\n"
       "      fprintf(stderr, \"\\n\\nPointer to stack in yielded functions state!!!!! (pointer_address=%p, pointer_value=%p, struct %s, offset=%zu, struct size=%zu)\\n\\n\", (void*)p, *((void**)p), struct_name, (size_t)((uintptr_t)p-(uintptr_t)block), block_size);\n"
       "      print_offsets_function();\n"
       "      raise(SIGABRT);\n"
       "    }\n"
       "  }\n"
       "}\n"
       "\n"
       :
       "");
    char *ycf_stack_alloc_code = (
                     "YCF_GCC_ATTRIBUTE_UNUSED\n"
                     "static void* ycf_stack_alloc(size_t size,\n"
                     "                             struct ycf_alloc_data* data,\n"
                     "                             ycf_yield_alloc_type allocator,\n"
                     "                             void* ycf_yield_alloc_free_context,\n"
                     "                             size_t default_stack_size){\n"
                     "  void * ret = NULL;\n"
                     "  if (data->data == NULL) {\n"
                     "    if (default_stack_size == 0) {\n"
                     "      fprintf(stderr, \"ycf_alloc: not enough stack!! (max size = 0)\\n\");\n"
                     "      exit(1);\n"
                     "    }\n"
                     "    data->data = allocator(default_stack_size, ycf_yield_alloc_free_context);\n"
                     "    data->needs_freeing = 1;\n"
                     "    data->max_size = default_stack_size;\n"
                     "    data->size = 0;\n"
                     "  }\n"
                     "  if (data->size + size > data->max_size) {\n"
                     "    fprintf(stderr, \"ycf_alloc: not enough stack! (max size = %zu)\\n\", default_stack_size);\n"
                     "    exit(1);\n"
                     "  }\n"
                     "  ret = &data->data[data->size];\n"
                     "  data->size = data->size + size + (sizeof(void * ) - (size % sizeof(void * ))) % sizeof(void * );\n"
                     "  return ret;\n"
                     "}\n"
                     "YCF_GCC_ATTRIBUTE_UNUSED\n"
                     "static void ycf_destroy_stack_allocator(struct ycf_alloc_data* data,\n"
                     "                                        ycf_yield_free_type freer,\n"
                     "                                        void* ycf_yield_alloc_free_context){\n"
                     "  if(data->needs_freeing){\n"
                     "    freer(data->data, ycf_yield_alloc_free_context);\n"
                     "  }\n"
                     "}\n");
    char* ycf_yielding_c_fun_helpers_code =
      ycf_string_new("#ifndef YCF_YIELDING_C_FUN_HELPERS\n"
                     "#define YCF_YIELDING_C_FUN_HELPERS 1\n"
                     "#include <string.h>\n"
                     "#include <stdio.h>\n"
                     "#include <stdlib.h>\n"
                     "\n"
                     "/*\n"
                     " * YCF_GCC_DIAG_ON and YCF_GCC_DIAG_OFF can be used to temporarly\n"
                     " * disable a gcc or clang warning in a file.\n"
                     " *\n"
                     " * Example:\n"
                     " * YCF_GCC_DIAG_OFF(unused-function)\n"
                     " * static int test(){ return 0;}\n"
                     " * YCF_GCC_DIAG_ON(unused-function)\n"
                     " *\n"
                     " * These macros were originally authored by Jonathan Wakely and has\n"
                     " * been modified by Patrick Horgan.\n"
                     " *\n"
                     " * Source: http://dbp-consulting.com/tutorials/SuppressingGCCWarnings.html\n"
                     " *\n"
                     " */\n"
                     "#if defined(_MSC_VER)\n"
                     "#  define YCF_GCC_DIAG_OFF(x) __pragma(warning(push, 0))\n"
                     "#  define YCF_GCC_DIAG_ON(x)  __pragma(warning(pop))\n"
                     "#elif ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402\n"
                     "#define YCF_GCC_DIAG_STR(s) #s\n"
                     "#define YCF_GCC_DIAG_JOINSTR(x,y) YCF_GCC_DIAG_STR(x ## y)\n"
                     "# define YCF_GCC_DIAG_DO_PRAGMA(x) _Pragma (#x)\n"
                     "# define YCF_GCC_DIAG_PRAGMA(x) YCF_GCC_DIAG_DO_PRAGMA(GCC diagnostic x)\n"
                     "# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406\n"
                     "#  define YCF_GCC_DIAG_OFF(x) YCF_GCC_DIAG_PRAGMA(push) \\\n"
                     "      YCF_GCC_DIAG_PRAGMA(ignored YCF_GCC_DIAG_JOINSTR(-W,x))\n"
                     "#  define YCF_GCC_DIAG_ON(x) YCF_GCC_DIAG_PRAGMA(pop)\n"
                     "# else\n"
                     "#  define YCF_GCC_DIAG_OFF(x) YCF_GCC_DIAG_PRAGMA(ignored YCF_GCC_DIAG_JOINSTR(-W,x))\n"
                     "#  define YCF_GCC_DIAG_ON(x)  YCF_GCC_DIAG_PRAGMA(warning YCF_GCC_DIAG_JOINSTR(-W,x))\n"
                     "# endif\n"
                     "#else\n"
                     "# define YCF_GCC_DIAG_OFF(x)\n"
                     "# define YCF_GCC_DIAG_ON(x)\n"
                     "#endif\n"
                     "#ifdef __GNUC__\n"
                     "#  if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5) || defined(__clang__)\n"
                     "#    define YCF_GCC_ATTRIBUTE_UNUSED __attribute__ ((unused))\n"
                     "#  else\n"
                     "#    define YCF_GCC_ATTRIBUTE_UNUSED\n"
                     "#  endif\n"
                     "#else\n"
                     "#  define YCF_GCC_ATTRIBUTE_UNUSED\n"
                     "#endif\n"
                     "\n"
                     "typedef void* (*ycf_yield_alloc_type) (size_t,void*);\n"
                     "typedef void (*ycf_yield_free_type) (void*,void*);\n"
                     "\n"
                     "struct ycf_alloc_data {\n"
                     "  size_t size;\n"
                     "  size_t max_size;\n"
                     "  int needs_freeing;\n"
                     "  char* data;\n"
                     "};\n"
                     "\n"
                     "#define YCF_ALLOC_NEXT_BLOCK() (\\\n"
                     " ycf_frame_alloc_data.data == NULL \\\n"
                     "   ? NULL \\\n"
                     "   : ((void*)(&ycf_frame_alloc_data.data[ycf_frame_alloc_data.size]))\\\n"
                     ")\n"
                     "#define YCF_ALLOC_NEXT_MAX_SIZE() (\\\n"
                     " ycf_frame_alloc_data.data == NULL \\\n"
                     "   ? ycf_frame_alloc_data.max_size \\\n"
                     "   : (ycf_frame_alloc_data.max_size - ycf_frame_alloc_data.size)\\\n"
                     ")\n"
                     "\n"
                     "/* Macros for special code sections */\n"
                     "#define ON_SAVE_YIELD_STATE ON_SAVE_YIELD_STATE\n"
                     "#define ON_RESTORE_YIELD_STATE ON_RESTORE_YIELD_STATE\n"
                     "#define ON_DESTROY_STATE ON_DESTROY_STATE\n"
                     "#define ON_RETURN ON_RETURN\n"
                     "#define ON_DESTROY_STATE_OR_RETURN ON_DESTROY_STATE_OR_RETURN\n"
                     "#define YCF_SPECIAL_CODE_START(PARAM) \\\n"
                     "   /*special_code_start:PARAM*/       \\\n"
                     "   if(0){\n"
                     "#define YCF_SPECIAL_CODE_END() \\\n"
                     "   }\\\n"
                     "   /*special_code_end*/\n"
                     "\n"
                     "%s\n"
                     "\n"
                     "#include <limits.h>\n"
                     "#define YCF_MAX_NR_OF_REDS LONG_MAX\n"
                     "#define YCF_NR_OF_REDS_LEFT() ycf_nr_of_reductions\n"
                     "#define YCF_SET_NR_OF_REDS_LEFT(NEW_NR_OF_REDS_LEFT) \\\n"
                     "  do{ycf_nr_of_reductions = (NEW_NR_OF_REDS_LEFT);}while(0)\n"
                     "\n"
                     "#define YCF_GET_EXTRA_CONTEXT() ycf_extra_context\n"
                     "\n"
                     "#define YCF_IS_YIELDED(CTX) (CTX != NULL)\n"
                     "\n"
                     "#define YCF_YIELD_CODE_GENERATED 1\n"
                     "\n"
                     "%s"
                     "\n"
                     "/* end of YCF_YIELDING_C_FUN_HELPERS guard */\n"
                     "#endif\n", ycf_stack_alloc_code, debug_mode_code);
    ycf_node_list_prepend(&source_out_tree->u.c_file.content,
                          ycf_node_new_text_node(ycf_yielding_c_fun_helpers_code));
  }
  
  static
  ycf_node* mk_fun_def(ycf_node* fun_node){
    ycf_node* fun_def = ycf_malloc(sizeof(ycf_node));
    fun_def->next = NULL;
    fun_def->type = ycf_node_type_function_declaration;
    fun_def->u.function_definition = fun_node->u.function.definition;
    ycf_symbol_list fun_node_def_end = ycf_symbol_list_empty();
    ycf_symbol_list_append(&fun_node_def_end, ycf_symbol_new_semicolon());
    fun_def->u.function_definition.end = fun_node_def_end;
    return fun_def;
  }
  
  
  static
  ycf_node* mk_null_vars_code(ycf_string_item_list fun_call_state_vars){
    ycf_string_item* current = fun_call_state_vars.head;
    char* assignments = "";
    while(current != NULL){
      assignments = ycf_string_new("%s\n"
                                   "%s = NULL;\n",
                                   assignments,
                                   current->str);
      current = current->next;
    }
    ycf_node* code = ycf_node_get_from_code_scope_text(assignments);
    return code;
  }
  
  static
  ycf_node* mk_continue_function_node(char* yielding_function_name,
                                      char* ycf_trap_state_struct_name,
                                      ycf_node* yielding_fun,
                                      ycf_node_list uniqified_parameters){
    char* parameters = "";
    ycf_node* current = uniqified_parameters.head;
    while(current != NULL){
      parameters = ycf_string_new("%s,ycf_my_trap_state->%s", parameters, ycf_symbol_get_text(current->u.definition.identifier));
      current = current->next;
    }
    char* fun_call_str =
      ycf_string_new("%s_ycf_gen_yielding(ycf_number_of_reduction_param,\n"
                     "                    ycf_trap_state,\n"
                     "                    ycf_extra_context,\n"
                     "                    ycf_my_trap_state->ycf_yield_alloc,\n"
                     "                    ycf_my_trap_state->ycf_yield_free,\n"
                     "                    ycf_my_trap_state->ycf_yield_alloc_free_context,\n"
                     "                    ycf_my_trap_state->ycf_stack_alloc_size_or_max_size,\n"
                     "                    ycf_my_trap_state->ycf_stack_alloc_data\n"
                     "                    %s)\n",
                     yielding_function_name,
                     parameters);
    char* code = ycf_string_new("\n"
                                "%s %s_ycf_gen_continue(long* ycf_number_of_reduction_param,\n"
                                "                       void** ycf_trap_state,\n"
                                "                       void* ycf_extra_context){\n"
                                "     struct %s* ycf_my_trap_state = *ycf_trap_state;\n"
                                "%s"
                                "}\n",
                                ycf_symbol_list_to_str(&yielding_fun->u.function.definition.definition.type_specifiers),
                                yielding_function_name,
                                ycf_trap_state_struct_name,
                                (ycf_node_is_void_ret_fun(yielding_fun) ?
                                 ycf_string_new("%s;\n"
                                               "return;\n",
                                               fun_call_str):
                                 ycf_string_new("return %s;\n",
                                                fun_call_str)));
    ycf_symbol_list symbols = ycf_symbol_list_from_text(code);
    ycf_node* tree = get_abstract_syntax_tree_root(&symbols);
    if(tree->u.c_file.content.head->type != ycf_node_type_function_definition){
      printf("NOT A FUNCTION\n");
      exit(1);
    }
    return tree->u.c_file.content.head;
  }
  
  static
  ycf_node* mk_debug_yielding_fun_call_wrapper(char* yielding_function_name,
                                               char* ycf_trap_state_struct_name,
                                               ycf_node* yielding_fun){
    char* parameters_2 = "";
    {
      ycf_node* current = yielding_fun->u.function.definition.parameters.head;
      bool first = true;
      char* identifier;
      while(current != NULL){
        identifier = ycf_symbol_get_text(current->u.definition.identifier);
        if(strcmp(identifier, "ycf_trap_state") == 0){
          identifier = ycf_string_new("(void**)(&ycf_my_trap_state)");
        }
        parameters_2 = ycf_string_new(first ? "%s%s" :"%s,%s",
                                    parameters_2,
                                    identifier);
        current = current->next;
        first = false;
      }
    }
    char* parameters = "";
    {
      ycf_node* current = yielding_fun->u.function.definition.parameters.head;
      bool first = true;
      while(current != NULL){
        parameters = ycf_string_new(first ? "%s%s" :"%s,%s",
                                    parameters,
                                    ycf_symbol_get_text(current->u.definition.identifier));
        current = current->next;
        first = false;
      }
    }
    ycf_string_printable_buffer* header_2 = ycf_string_printable_buffer_new();
    ycf_node_function_definition def_2 = yielding_fun->u.function.definition;
    def_2.definition.identifier =
      ycf_symbol_copy_change_text(def_2.definition.identifier,
                                  ycf_string_new("%s_2",
                                                 ycf_symbol_get_text(def_2.definition.identifier)));
    print_node_code_function_def(def_2, header_2);
    ycf_string_printable_buffer* header = ycf_string_printable_buffer_new();
    print_node_code_function_def(yielding_fun->u.function.definition, header);
    ycf_string_printable_buffer* parameter_types = ycf_string_printable_buffer_new();
    print_node_code_function_def_parameters(yielding_fun->u.function.definition, parameter_types);
    ycf_symbol_list ret_type = ycf_node_get_return_type(yielding_fun);
    char* wrapper_assignment = NULL;
    char* wrapper_return = NULL;
    if(ycf_node_is_void_ret_fun(yielding_fun)){
      wrapper_assignment = ycf_string_new("");
      wrapper_return = ycf_string_new("return;");
    }else{
      wrapper_assignment = ycf_string_new("%s ycf_to_return = ", ycf_symbol_list_to_str(&ret_type));
      wrapper_return = ycf_string_new("return ycf_to_return;");
    }
    char* code = ycf_string_new("\n"
                                "%s{\n"
                                "  volatile int noinline = 1;\n"
                                "  volatile void* ycf_my_trap_state = *ycf_trap_state;\n"
                                "  %s (*next)(%s = noinline\n"
                                "    ? %s_ycf_gen_yielding_3\n"
                                "    : (%s(*)(%s)(NULL);\n"
                                "  {\n"
                                "    %s next(%s);\n"
                                "    *ycf_trap_state = (struct %s*)ycf_my_trap_state;\n"
                                "    %s\n"
                                "  }\n"
                                "}\n"
                                "\n"
                                "\n"
                                "%s{\n"
                                "  volatile int noinline = 1;\n"
                                "  %s (*next)(%s = noinline\n"
                                "    ? %s_ycf_gen_yielding_2\n"
                                "    : (%s(*)(%s)(NULL);\n"
                                "\n"
                                "  {\n"
                                "    %s next(%s);\n"
                                "    %s;\n"
                                "  }\n"
                                "}\n",
                                header_2->buffer,
                                ycf_symbol_list_to_str(&ret_type),
                                parameter_types->buffer,
                                yielding_function_name,
                                ycf_symbol_list_to_str(&ret_type),
                                parameter_types->buffer,
                                wrapper_assignment,
                                parameters_2,
                                ycf_trap_state_struct_name,
                                wrapper_return,
                                /* Second function*/
                                header->buffer,
                                ycf_symbol_list_to_str(&ret_type),
                                parameter_types->buffer,
                                yielding_function_name,
                                ycf_symbol_list_to_str(&ret_type),
                                parameter_types->buffer,
                                wrapper_assignment,
                                parameters,
                                wrapper_return);
  
    return ycf_node_new_text_node(code);
  }
  
  
  static
  void break_up_control_expressions(ycf_node_code_scope* s,
                                    ycf_string_item_list* yielding_function_names);
  
  
  static ycf_node* break_up_control_expressions_helper(ycf_node* candidate,
                                                       ycf_node_code_scope* candidates_scope,
                                                       void* context){
      ycf_string_item_list* list = (ycf_string_item_list*)context;
      if(candidate->type == ycf_node_type_if &&
         ycf_node_list_length(candidate->u.if_n.expression.content.content) == 1 &&
         candidate->u.if_n.expression.content.content.head->type == ycf_node_type_function_call &&
         ycf_string_item_list_contains(list,
                                       ycf_symbol_get_text(candidate->u.if_n.expression.content.content.head->u.function_call.identifier))){
        break_up_control_expressions(&candidate->u.if_n.if_statement->u.code_scope, list);
        ycf_node * wrapper =
          ycf_node_get_from_code_scope_text(ycf_string_new("int ycf_gen_control_tmp;\n"
                                                           "ycf_gen_control_tmp = !!%s;\n"
                                                           "if(ycf_gen_control_tmp)\n"
                                                           "%s",
                                                           ycf_node_to_string(candidate->u.if_n.expression.content.content.head),
                                                           ycf_node_to_string(candidate->u.if_n.if_statement)));
        return wrapper;
      } else if(candidate->type == ycf_node_type_if_else &&
         ycf_node_list_length(candidate->u.if_else.if_part.expression.content.content) == 1 &&
         candidate->u.if_else.if_part.expression.content.content.head->type == ycf_node_type_function_call &&
         ycf_string_item_list_contains(list,
                                       ycf_symbol_get_text(candidate->u.if_else.if_part.expression.content.content.head->u.function_call.identifier))){
        break_up_control_expressions(&candidate->u.if_else.if_part.if_statement->u.code_scope, list);
        ycf_node * wrapper =
          ycf_node_get_from_code_scope_text(ycf_string_new("int ycf_gen_control_tmp;\n"
                                                           "ycf_gen_control_tmp = !!%s;\n"
                                                           "if(ycf_gen_control_tmp)\n"
                                                           "%s\n"
                                                           "%s\n"
                                                           "%s\n",
                                                           ycf_node_to_string(candidate->u.if_else.if_part.expression.content.content.head),
                                                           ycf_node_to_string(candidate->u.if_else.if_part.if_statement),
                                                           ycf_symbol_get_text(candidate->u.if_else.else_word),
                                                           ycf_node_to_string(candidate->u.if_else.else_statement)));
        return wrapper;
      } else if(candidate->type == ycf_node_type_do_while &&
         ycf_node_list_length(candidate->u.do_while.expression.content.content) == 1 &&
         candidate->u.do_while.expression.content.content.head->type == ycf_node_type_function_call &&
         ycf_string_item_list_contains(list,
                                       ycf_symbol_get_text(candidate->u.do_while.expression.content.content.head->u.function_call.identifier))){
        break_up_control_expressions(&candidate->u.do_while.statement->u.code_scope, list);
        ycf_node * wrapper =
          ycf_node_get_from_code_scope_text(ycf_string_new("int ycf_gen_control_tmp;\n"
                                                           "do {\n"
                                                           "  %s\n"
                                                           "  ycf_gen_control_tmp = !!%s;\n"
                                                           "}while(ycf_gen_control_tmp);\n",
                                                           ycf_node_to_string(candidate->u.do_while.statement),
                                                           ycf_node_to_string(candidate->u.do_while.expression.content.content.head)));
        return wrapper;
      } else if(candidate->type == ycf_node_type_while &&
         ycf_node_list_length(candidate->u.while_n.expression.content.content) == 1 &&
         candidate->u.while_n.expression.content.content.head->type == ycf_node_type_function_call &&
         ycf_string_item_list_contains(list,
                                       ycf_symbol_get_text(candidate->u.while_n.expression.content.content.head->u.function_call.identifier))){
        break_up_control_expressions(&candidate->u.while_n.statement->u.code_scope, list);
        ycf_node * wrapper =
          ycf_node_get_from_code_scope_text(ycf_string_new("int ycf_gen_control_tmp;\n"
                                                           "ycf_gen_control_tmp = !!%s;\n"
                                                           "while(ycf_gen_control_tmp){\n"
                                                           "  %s\n"
                                                           "  ycf_gen_control_tmp = !!%s;\n"
                                                           "}\n",
                                                           ycf_node_to_string(candidate->u.while_n.expression.content.content.head),
                                                           ycf_node_to_string(candidate->u.while_n.statement),
                                                           ycf_node_to_string(candidate->u.while_n.expression.content.content.head)));
        return wrapper;
      }
      return candidate;
  }
  
  static
  void break_up_control_expressions(ycf_node_code_scope* s,
                                    ycf_string_item_list* yielding_function_names){
    ycf_node_insert_scopes_in_complex_statements(s);
    ycf_node_search_and_replace_statements_in_scope(s,
                                                    break_up_control_expressions_helper,
                                                    yielding_function_names);
  }
  
  static
  ycf_node* mk_wrap_in_surpress_warn(char* warning, ycf_node* to_wrap) {
    ycf_string_printable_buffer* buf = ycf_string_printable_buffer_new();
    ycf_string_printable_buffer_printf(buf,
                                       "\n"
                                       "/* clang-format off */\n"
                                       "YCF_GCC_DIAG_OFF(%s)\n"
                                       "/* clang-format on */\n", warning);
    ycf_node_print(to_wrap, buf);
    ycf_string_printable_buffer_printf(buf,
                                       "\n"
                                       "/* clang-format off */\n"
                                       "YCF_GCC_DIAG_ON(%s)\n"
                                       "/* clang-format on */\n", warning);
    return ycf_node_new_text_node(buf->buffer);
  
  }
  
  static
  ycf_node* supress_warnings_wrap_yielding_fun(ycf_node* yielding_fun){
    ycf_node* ret = yielding_fun;
    ret = mk_wrap_in_surpress_warn("uninitialized", ret);
    ret = mk_wrap_in_surpress_warn("maybe-uninitialized", ret);
    ret = mk_wrap_in_surpress_warn("sometimes-uninitialized", ret);
    ret = mk_wrap_in_surpress_warn("unknown-warning-option", ret);
    ret = mk_wrap_in_surpress_warn("pragmas", ret);
    return ret;
  }
  
  static
  ycf_node* supress_warnings_wrap_destroy_fun(ycf_node* fun){
    ycf_node* ret = fun;
    ret = mk_wrap_in_surpress_warn("unused-function", ret);
    ret = mk_wrap_in_surpress_warn("unused-but-set-variable", ret);
    ret = mk_wrap_in_surpress_warn("unknown-warning-option", ret);
    ret = mk_wrap_in_surpress_warn("pragmas", ret);
    return ret;
  }
  
  ycf_node* insert_yielding_function_with_prefix_suffix(ycf_node* tree_to_insert_to,
                                                        ycf_node* insert_before,
                                                        ycf_node* yielding_fun,
                                                        bool debug_mode,
                                                        char* yielding_function_name,
                                                        char* ycf_trap_state_struct_name){
    ycf_node* prefix = ycf_node_new_text_node("\n"
                                              "#define YCF_IN_YIELDING_FUN 1\n"
                                              "#undef YCF_STACK_ALLOC\n"
                                              "#define YCF_STACK_ALLOC(SIZE) \\\n"
                                              "    ycf_stack_alloc(SIZE,\\\n"
                                              "                    &ycf_frame_alloc_data,\\\n"
                                              "                    ycf_yield_alloc, ycf_yield_alloc_free_context,\\\n"
                                              "                     ycf_stack_alloc_size_or_max_size)\n");
    if(insert_before == NULL){
      ycf_node_list_append(&tree_to_insert_to->u.c_file.content, prefix);
    }else{
      ycf_node_list_insert_before(&tree_to_insert_to->u.c_file.content,
                                  insert_before,
                                  prefix);
    }
    if(debug_mode){
      ycf_node* wrapper_funs =
        mk_debug_yielding_fun_call_wrapper(yielding_function_name,
                                           ycf_trap_state_struct_name,
                                           yielding_fun);
      ycf_node_rename_function(&yielding_fun->u.function,
                               ycf_string_new("%s_ycf_gen_yielding_3",
                                              yielding_function_name));
  
      if(insert_before == NULL){
        yielding_fun = supress_warnings_wrap_yielding_fun(yielding_fun);
        ycf_node_list_append(&tree_to_insert_to->u.c_file.content,
                             yielding_fun);
        ycf_node_list_append(&tree_to_insert_to->u.c_file.content, wrapper_funs);
      } else {
        yielding_fun = supress_warnings_wrap_yielding_fun(yielding_fun);
        ycf_node_list_insert_before(&tree_to_insert_to->u.c_file.content,
                                    insert_before,
                                    yielding_fun);
        ycf_node_list_insert_before(&tree_to_insert_to->u.c_file.content,
                                    insert_before,
                                    wrapper_funs);
      }
    }else {
      if(insert_before == NULL){
        yielding_fun = supress_warnings_wrap_yielding_fun(yielding_fun);
        ycf_node_list_append(&tree_to_insert_to->u.c_file.content,
                             yielding_fun);
      }else{
        yielding_fun = supress_warnings_wrap_yielding_fun(yielding_fun);
        ycf_node_list_insert_before(&tree_to_insert_to->u.c_file.content,
                                    insert_before,
                                    yielding_fun);
      }
    }
    if(insert_before == NULL){
      ycf_node_list_append(&tree_to_insert_to->u.c_file.content,
                           ycf_node_new_text_node("\n"
                                                  "#undef YCF_STACK_ALLOC\n"
                                                  "#undef YCF_IN_YIELDING_FUN\n"));
    }else{
      ycf_node_list_insert_after(&tree_to_insert_to->u.c_file.content,
                                 yielding_fun,
                                 ycf_node_new_text_node("\n"
                                                        "#undef YCF_STACK_ALLOC\n"
                                                        "#undef YCF_IN_YIELDING_FUN\n"
                                                        "#define YCF_STACK_ALLOC(SIZE) malloc(SIZE)\n"));
      ycf_node_list_insert_after(&tree_to_insert_to->u.c_file.content,
                                 insert_before,
                                 ycf_node_new_text_node("\n#undef YCF_STACK_ALLOC\n"));
    }
    return yielding_fun;
  }
  
  typedef struct {
      char *orginal_function_name;
      ycf_string_item_list* all_yielding_function_names;
  } error_exit_info;
  
  static void error_exit_if_not_fun_call_not_transformed_scanner(ycf_node* node, void* context) {
      error_exit_info* info = context;
      ycf_string_item_list* all_yielding_function_names = info->all_yielding_function_names;
      char *orginal_function_name = info->orginal_function_name;
      ycf_symbol* ident = NULL;
      if (node->type == ycf_node_type_function_call) {
          ident = node->u.function_call.identifier;
      } else if (node->type == ycf_node_type_assignment_function_call) {
          ident = node->u.function_call_assignment.fun_call.identifier;
      } else if(node->type == ycf_node_type_other &&
         node->u.other.what->type == ycf_symbol_type_identifier) {
          ident = node->u.other.what;
      }
      if (ident != NULL) {
          ycf_string_item* curr = all_yielding_function_names->head;
          while(curr != NULL) {
              if (ycf_symbol_is_text_eq(ident, curr->str)) {
                  fprintf(stderr,
                          "\n"
                          "\n"
                          "ERROR: The function identifier %s (probably a function call)\n"
                          "in the function %s is not transformed but %s is among\n"
                          "the functions that shall be transformed. This probably means\n"
                          "that you have to rewrite the code so the call to %s\n"
                          "is not nested inside another expression.\n"
                          "See the documentation of Yielding C Fun for more information.\n"
                          "\n"
                          "\n",
                          curr->str,
                          orginal_function_name,
                          curr->str,
                          curr->str);
                  exit(1);
              }
              curr = curr->next;
          }
      }
  }
  
  static void error_exit_if_fun_call_not_transformed(ycf_node* fun_change,
                                                     char *orginal_function_name,
                                                     ycf_string_item_list* all_yielding_function_names) {
      error_exit_info info;
      info.orginal_function_name = orginal_function_name;
      info.all_yielding_function_names = all_yielding_function_names;
      ycf_scan_scope(&fun_change->u.function.body,
                     error_exit_if_not_fun_call_not_transformed_scanner,
                     &info);
  }
  
  ycf_node* ast_get_ast_with_yieldified_function(ycf_node* source_tree,
                                                 ycf_node* header_tree,
                                                 char* yielding_function_name,
                                                 ycf_string_item_list* all_yielding_function_names,
                                                 bool auto_yield,
                                                 bool recusive_auto_yield,
                                                 bool debug_mode,
                                                 bool only_yielding_funs,
                                                 ycf_node** only_yielding_funs_tree,
                                                 bool static_aux_funs)
  {
    ycf_yield_location_id_counter = 0;
    ycf_node* tree_ret = ycf_node_deep_copy(source_tree);
    if (*only_yielding_funs_tree == NULL){
      *only_yielding_funs_tree = ycf_node_c_file_new(ycf_node_list_empty());
    }
    /* Find function */
    ycf_node* fun = ycf_node_find_function(tree_ret, yielding_function_name);
    if(fun == NULL){
      fprintf(stderr, "Could not find function %s\n", yielding_function_name);
      exit(1);
    }
    ycf_node* fun_change = ycf_node_deep_copy(fun);
    /* Replace alternative syntax for special code sections */
    fun_change = replace_alt_syntax_special_code_section_code(fun_change);
    ycf_node_normalize_function(fun_change);
    /* Brake up control expressions with simple calls to yielding functions */
    break_up_control_expressions(&fun_change->u.function.body, all_yielding_function_names);
    /* Insert trap state var for calls to yielding functions */
    insert_fun_call_state_var(&fun_change->u.function.body, all_yielding_function_names);
    /* Normalize the function to make transformation easier (move all declarations to the top etc) */
    ycf_node_normalize_function(fun_change);
    /* Insert YCF_CONSUME_REDS(1) code if auto yielding is on */
    if(auto_yield){
      insert_consume_reds_calls(&fun_change->u.function.body);
    }
    /* Save variable declarations */
    ycf_node_list uniqified_parameters =
      ycf_node_list_shallow_copy(fun_change->u.function.definition.parameters);
    ycf_node_list scope_defs =
      ycf_node_list_shallow_copy(ycf_node_get_declarations_in_scope(&fun_change->u.function.body));;
    ycf_node_list defs =
      ycf_node_list_shallow_copy(ycf_node_get_all_definitions_in_function(&fun_change->u.function));
    /* Add extra variables that are needed for yielding */
    ycf_node_list extra_ycf_trap_state = mk_trap_extra_state();
    ycf_node_list_concat(&scope_defs, &extra_ycf_trap_state);
    fun_change->u.function.body.definition_nodes = scope_defs;
    /* Generate trap state struct */
    ycf_node_list trap_state_struct_var_declarations =
      ycf_node_list_shallow_copy(extra_ycf_trap_state);
    ycf_node_list_concat(&trap_state_struct_var_declarations, &defs);
    char* ycf_trap_state_struct_name =
            ycf_string_new("gen_ycf_trap_state_for_%s",
                           yielding_function_name);
    trap_state_struct_var_declarations =
      ycf_node_list_copy_concat(mk_saved_ycf_trap_state_params(),
                                trap_state_struct_var_declarations);
    ycf_node* ycf_trap_state_struct =
      mk_typedef_struct_node(trap_state_struct_var_declarations,
                             ycf_trap_state_struct_name);
    /* Add extra parameters for trapping */
    {
      ycf_node_list trap_params = mk_ycf_trap_state_params();
      ycf_node_list saved_params = mk_saved_ycf_trap_state_params();
      ycf_node_list_concat(&trap_params, &saved_params);
      ycf_node_list_concat(&trap_params, &fun_change->u.function.definition.parameters);
      fun_change->u.function.definition.parameters = trap_params;
      fun_change->u.function.definition.ignore_param_ending = 1;
    }
    /* Collect and replace special code */
    ycf_node_list on_save_yield_state_code_list =
      save_and_replace_special_code(&fun_change->u.function.body,
                                    ycf_node_type_on_save_yield_state_code);
    ycf_node_list on_restore_yield_state_code_list =
      save_and_replace_special_code(&fun_change->u.function.body,
                                    ycf_node_type_on_restore_yield_state_code);
    ycf_node_list on_destroy_state_code_list =
      save_and_replace_special_code(&fun_change->u.function.body,
                                    ycf_node_type_on_destroy_state_code);
    ycf_node_list on_destroy_state_or_return_code_list =
      save_and_replace_special_code(&fun_change->u.function.body,
                                    ycf_node_type_on_destroy_state_or_return_code);
    ycf_node_list on_return_code_list =
      save_and_replace_special_code(&fun_change->u.function.body, ycf_node_type_on_return_code);
    save_nr_of_reductions_before_return(&fun_change->u.function.body,
                                            on_destroy_state_or_return_code_list,
                                            on_return_code_list,
                                            recusive_auto_yield);
    /* Insert goto yield code in function */
    insert_yield_code(fun_change,
                      ycf_trap_state_struct_name,
                      trap_state_struct_var_declarations,
                      &fun_change->u.function.body);
    insert_yield_no_reds_code(fun_change,
                              ycf_trap_state_struct_name,
                              trap_state_struct_var_declarations,
                              &fun_change->u.function.body);
    {
      ycf_string_item_list fun_call_state_vars =
        insert_yielding_fun_call_code(source_tree,
                                      &fun_change->u.function.body,
                                      all_yielding_function_names,
                                      yielding_function_name,
                                      recusive_auto_yield);
      /* Null all fun_call_state_vars */
      ycf_node_list_prepend(&fun_change->u.function.body.other_nodes, mk_null_vars_code(fun_call_state_vars));
    }
    /* Replace YCF_CONSUME_REDS calls */
    insert_consume_reds_code(yielding_function_name, &fun_change->u.function.body);
    /* Insert yield initialization in the beginning of the function */
    {
      ycf_node* trap_init = mk_yield_init_code(ycf_trap_state_struct_name,
                                               trap_state_struct_var_declarations,
                                               on_restore_yield_state_code_list,
                                               auto_yield,
                                               yielding_function_name,
                                               scope_defs,
                                               debug_mode);
      ycf_node_list_prepend(&fun_change->u.function.body.other_nodes, trap_init);
    }
    /* Add code that saves the state and yields to the end of the function */
    ycf_node_list_append(&fun_change->u.function.body.other_nodes,
                           mk_yield_code(fun_change,
                                         ycf_trap_state_struct_name,
                                         trap_state_struct_var_declarations,
                                         on_save_yield_state_code_list,
                                         debug_mode));
    /* Change name of function */
    ycf_node_rename_function(&fun_change->u.function,
                             ycf_string_new("%s_ycf_gen_yielding",
                                            yielding_function_name));
    /* Remove unnecessary scopes */
    ycf_node_remove_unecessary_scopes(&fun_change->u.function.body);
    /* Exit with error message if a function call to a yielding function
       is not transformed */
    error_exit_if_fun_call_not_transformed(fun_change,
                                           yielding_function_name,
                                           all_yielding_function_names);
    /* Make continue function */
    ycf_node* continue_function =
      mk_continue_function_node(yielding_function_name,
                                ycf_trap_state_struct_name,
                                fun,
                                uniqified_parameters);
    /* Make destroy state function */
    ycf_node* destroy_state_function =
      mk_destroy_state_function_node(yielding_function_name,
                                     trap_state_struct_var_declarations,
                                     ycf_trap_state_struct_name,
                                     on_destroy_state_code_list,
                                     on_destroy_state_or_return_code_list,
                                     static_aux_funs);
    ycf_node* fun_change_dec = mk_fun_def(fun_change);
    /****************************************************************
     *
     * The following code inserts the changed function and its helper
     * function into the output AST(s)
     *
     ****************************************************************/
    /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
    /* Insert changed function into tree that will be printed */
    /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
    ycf_node* fun_ret = ycf_node_find_function(tree_ret, yielding_function_name);
    ycf_node* fun_change_wrapper =
      insert_yielding_function_with_prefix_suffix(tree_ret,
                                                  fun_ret,
                                                  fun_change,
                                                  debug_mode,
                                                  yielding_function_name,
                                                  ycf_trap_state_struct_name);
    /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
    /* END: Insert changed function into tree that will be printed */
    /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
    /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
    /* Insert declarations in the top */
    /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
    ycf_node* fun_dec_node = ycf_node_find_function_declaration(tree_ret, yielding_function_name);
    ycf_node_list_prepend(&tree_ret->u.c_file.content, ycf_node_new_text_node("\n"));
    if(fun_dec_node == NULL){
      ycf_node_list_prepend(&tree_ret->u.c_file.content,
                            mk_wrap_in_surpress_warn("unused-function",
                                                     mk_fun_def(destroy_state_function)));
      ycf_node_list_prepend(&tree_ret->u.c_file.content,
                            mk_wrap_in_surpress_warn("unused-function",
                                                     mk_fun_def(continue_function)));
    } else {
      ycf_node_list_insert_before(&tree_ret->u.c_file.content,
                                  fun_dec_node,
                                  mk_wrap_in_surpress_warn("unused-function",
                                                           mk_fun_def(destroy_state_function)));
      ycf_node_list_insert_before(&tree_ret->u.c_file.content,
                                  fun_dec_node,
                                  mk_wrap_in_surpress_warn("unused-function",
                                                           mk_fun_def(continue_function)));
  
    }
    ycf_node_list_prepend(&header_tree->u.c_file.content, ycf_node_shallow_copy(fun_change_dec));
    ycf_node_list_prepend(&header_tree->u.c_file.content, ycf_node_new_text_node("\n"));
    ycf_node_list_prepend(&header_tree->u.c_file.content,
                          mk_wrap_in_surpress_warn("unused-function",
                                                   mk_fun_def(destroy_state_function)));
    ycf_node_list_prepend(&header_tree->u.c_file.content,
                          mk_wrap_in_surpress_warn("unused-function",
                                                   mk_fun_def(continue_function)));
    ycf_node* ycf_trap_state_struct_dec =
            ycf_node_new_text_node(ycf_string_new("\n\nstruct %s;",
                                                  ycf_trap_state_struct->u.gen_typedef_struct.name));
  
    ycf_node_list_prepend(&tree_ret->u.c_file.content,
                          ycf_trap_state_struct_dec);
    ycf_node_list_prepend(&header_tree->u.c_file.content,
                          ycf_node_shallow_copy(ycf_trap_state_struct_dec));
    ycf_node_list_append(&header_tree->u.c_file.content,
                         ycf_node_new_text_node("\n"));
    /* Insert definition of changed function */
    if(fun_dec_node != NULL){
      ycf_node_list_insert_before(&tree_ret->u.c_file.content,
                                  fun_dec_node,
                                  ycf_node_shallow_copy(ycf_node_shallow_copy(fun_change_dec)));
    }else{
      ycf_node_list_insert_before(&tree_ret->u.c_file.content,
                                  fun_change_wrapper,
                                  ycf_node_shallow_copy(ycf_node_shallow_copy(fun_change_dec)));
    }
    ycf_node_list_insert_before(&tree_ret->u.c_file.content,
                                fun_change_wrapper,
                                ycf_trap_state_struct);
    if (debug_mode) {
        ycf_node_list_insert_before(&tree_ret->u.c_file.content,
                                    fun_change_wrapper,
                                    mk_print_offsets_for_struct_fields(ycf_trap_state_struct_name,
                                                                       trap_state_struct_var_declarations));
    }
    ycf_node_list_insert_after(&tree_ret->u.c_file.content,
                               ycf_trap_state_struct,
                               supress_warnings_wrap_destroy_fun(destroy_state_function));
    ycf_node_list_insert_after(&tree_ret->u.c_file.content,
                               ycf_trap_state_struct,
                               mk_wrap_in_surpress_warn("unused-function",
                                                        continue_function));
    /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
    /* END: Insert declarations in the top */
    /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
    if(only_yielding_funs){
      ycf_node_list_prepend(&(*only_yielding_funs_tree)->u.c_file.content,
                            ycf_node_new_text_node("\n"));
      ycf_node_list_prepend(&(*only_yielding_funs_tree)->u.c_file.content,
                            ycf_node_shallow_copy(fun_change_dec));
      if (debug_mode) {
          ycf_node* debug_dec_2 =
              ycf_node_function_definition_copy_change_name(fun_change_dec,
                                                            ycf_string_new("%s_ycf_gen_yielding_2",
                                                                           yielding_function_name));
          ycf_node* debug_dec_3 =
              ycf_node_function_definition_copy_change_name(fun_change_dec,
                                                            ycf_string_new("%s_ycf_gen_yielding_3",
                                                                           yielding_function_name));
          ycf_node_list_prepend(&(*only_yielding_funs_tree)->u.c_file.content,
                                debug_dec_2);
          ycf_node_list_prepend(&(*only_yielding_funs_tree)->u.c_file.content,
                                debug_dec_3);
      }
      ycf_node_list_prepend(&(*only_yielding_funs_tree)->u.c_file.content,
                            ycf_node_new_text_node("\n"));
      ycf_node_list_prepend(&(*only_yielding_funs_tree)->u.c_file.content,
                            mk_wrap_in_surpress_warn("unused-function",mk_fun_def(destroy_state_function)));
      ycf_node_list_prepend(&(*only_yielding_funs_tree)->u.c_file.content,
                            ycf_node_new_text_node("\n"));
      ycf_node_list_prepend(&(*only_yielding_funs_tree)->u.c_file.content,
                            mk_wrap_in_surpress_warn("unused-function",
                                                     mk_fun_def(continue_function)));
      ycf_node_list_prepend(&(*only_yielding_funs_tree)->u.c_file.content,
                            ycf_node_new_text_node("\n"));
      ycf_node_list_prepend(&(*only_yielding_funs_tree)->u.c_file.content,
                            ycf_node_shallow_copy(ycf_trap_state_struct_dec));
      ycf_node_list_prepend(&(*only_yielding_funs_tree)->u.c_file.content,
                            ycf_node_new_text_node("\n"));
  
      ycf_node_list_append(&(*only_yielding_funs_tree)->u.c_file.content,
                           ycf_node_shallow_copy(ycf_trap_state_struct));
      if (debug_mode) {
          ycf_node_list_append(&(*only_yielding_funs_tree)->u.c_file.content,
                               mk_print_offsets_for_struct_fields(ycf_trap_state_struct_name,
                                                                  trap_state_struct_var_declarations));
      }
      ycf_node_list_append(&(*only_yielding_funs_tree)->u.c_file.content,
                            ycf_node_new_text_node("\n"));
      ycf_node_list_append(&(*only_yielding_funs_tree)->u.c_file.content,
                           supress_warnings_wrap_destroy_fun(destroy_state_function));
      ycf_node_list_append(&(*only_yielding_funs_tree)->u.c_file.content,
                            ycf_node_new_text_node("\n"));
      ycf_node_list_append(&(*only_yielding_funs_tree)->u.c_file.content,
                           mk_wrap_in_surpress_warn("unused-function",continue_function));
      if (debug_mode) {
        /* The name got changed above so we need to change it back before doing the next step */
        ycf_node_rename_function(&fun_change->u.function,
                               ycf_string_new("%s_ycf_gen_yielding",
                                              yielding_function_name));
  
      }
      insert_yielding_function_with_prefix_suffix((*only_yielding_funs_tree),
                                                  NULL,
                                                  fun_change,
                                                  debug_mode,
                                                  yielding_function_name,
                                                  ycf_trap_state_struct_name);
    }
    return tree_ret;
  }
  