/* ** Returns `block` on success or NULL on failure ** ** If the given block is used, returns NULL and does nothing. */ t_block *egc_defrag_block(t_heap *heap, t_block *block, int clr_left) { t_block *last_free_block; last_free_block = egc_get_last_free_block(heap, block); if (!last_free_block || block == last_free_block) return (NULL); join_blocks(block, last_free_block, clr_left); LOG("egc_defrag_block()"); LOG_POINTER(block); LOG(""); return (block); }
static void generate_control(code_block *parent, control_statement *control) { loop_statement *target = control->target; if (target->type == S_DO_WHILE) { block_node **root = control->type == S_BREAK ? &target->break_node : &target->continue_node; block_node *node = xmalloc(sizeof(*node)); node->block = parent; node->next = *root; *root = node; } else { join_blocks(parent, control->type == S_BREAK ? target->post_block : target->condition_block); } }
static code_block *generate_do_while(code_block *parent, loop_statement *loop) { size_t body_block = parent->system->block_count; code_block *body = fork_block(parent), *context = body; if (loop->body) { struct generate_loop_trigger_data data = { .loop = loop, .done = false, .prev_block = body, .context_block = &context }; body = generate_block(body, loop->body, loop_trigger, &data); } // if the body ends, it implicitly continues if (body) { block_node *node = xmalloc(sizeof(*node)); node->block = body; node->next = loop->continue_node; loop->continue_node = node; } // if we ever continue the loop, we'll want to include the available variables // these variables: // - need to be in the outermost scope in the loop // - need to be available from all continue statements (including the final // implicit continue) if (loop->continue_node) { code_block *condition = tangle_blocks(context, loop->continue_node); condition = generate_expression(condition, loop->condition); code_block *body_replay, *post; weave_blocks(parent, loop->break_node, condition, &body_replay, &post); join_blocks(body_replay, body_block); return post; } // loop only breaks, never continues (effectively not a loop) if (loop->break_node) { fprintf(stderr, "do-while condition not reachable\n"); return tangle_blocks(parent, loop->break_node); } fprintf(stderr, "infinite loop, do-while condition not reachable\n"); return NULL; } static code_block *generate_while(code_block *parent, loop_statement *loop) { if (loop->condition->operation.type == O_LITERAL && loop->condition->type->type == T_BOOL && loop->condition->value_bool) { loop->type = S_DO_WHILE; return generate_do_while(parent, loop); } size_t condition_block = parent->system->block_count; code_block *condition = fork_block(parent); condition = generate_expression(condition, loop->condition); code_block *body, *post; branch_into(condition, &body, &post); // TODO: this is using undocumented behavior size_t /*body_block = parent->system->block_count - 2, */post_block = parent->system->block_count - 1; loop->condition_block = condition_block; loop->post_block = post_block; if (loop->body) { body = generate_block(body, loop->body, NULL, NULL); } if (body) { join_blocks(body, condition_block); } return post; } static code_block *generate_loop(code_block *parent, loop_statement *loop) { return loop->type == S_DO_WHILE ? generate_do_while(parent, loop) : generate_while(parent, loop); } static code_block *generate_if(code_block *parent, if_statement *branch) { parent = generate_expression(parent, branch->condition); code_block *first, *second; branch_into(parent, &first, &second); first = branch->first ? generate_block(first, branch->first, NULL, NULL) : first; second = branch->second ? generate_block(second, branch->second, NULL, NULL) : second; switch (((!first) << 1) | (!second)) { case 0: // both exist return merge_blocks(parent, first, second); case 1: // the first block exists return rejoin_block(parent, first); case 2: // the second block exists return rejoin_block(parent, second); case 3: return NULL; } fprintf(stderr, "if statement generation logical failure\n"); abort(); }