### Control Flow In `c` (`structs`, `if`, `goto` ) are all we need. Control flow constructs can all disapear: `?:`, `switch`-`case`, `do while`, `else if`, `for`, `while`, `switch`, and even `functions` can disapear. C is a syntactic sugar on assembly provide programmers with various ways to control the flow of execution in C programs without goto #### Conditional Operator `?:` ```c z = (a > b) ? a : b; // compact if-else if (a > b) // equivalent to the above Conditional Operator `?:` z = a; else z = b; ``` #### `else if` and "nested-`if`" Guard Clauses The Guard Clauses method to convert from nested if statements to non-nested, is to test for the negation of the test condition and upon the negation return or exit immediately, and if that fails an the program didn't exit the current code section then go ahead and do what would have normally been inside the if statement. ```c if (n > 0) { //nested if if (a > b) z = a; } else z = b; if !(n > 0) { // guard clause version of nested if z = b; } else if (a > b) { z = a; } ``` Also known as assert or precondition; the use of negation or guard clauses isn't just a practice to avoid unnecessary branching, it is how compiled code executes nested if statements. but eventually after nested if's are converted to `else if` they are turned into gotos. ```c if !(n > 0) goto alternate; // else if translated into gotos if !(a > b) goto alternate; z = a; goto end; alternate: z = b; end: ``` #### `do while` ```c do [loop body statement] while ([condition]); begin: //equivalent to the above do-while-loop loop body statement; if (condition) goto begin; ``` #### `for` ```c for (variable-declaration; condition; variable-update) statement1 continue; statement2; variable-declaration; // equivalent to the above for-loop begin: if (!condition) goto end; statement1; goto continuefor; statement2; continuefor: variable-update; goto begin; end: // end loop ``` #### `while` ```c while (condition) statement begin: // equivalent to the above while-loop if !(condition) goto end; statements; goto begin; end: ``` #### `switch`-`case` ```c switch (expression) { case const-expr1: statement1 case const-expr2: statement2 case const-expr3: statement3 default: statements } **Function calls**: While not strictly a control flow statement, calling a function transfers control to that function until it returns. type value = expression // equivalent to the above switch if (value == const-expr1) statement1 else if (value == const-expr2) statement2 else if (value == const-expr3) statement3 else statement0 //Which is also equivalent to: type value = expression if !(value == const-expr1) goto alternate2; statement1; goto end; alternate2: if !(value == const-expr2) goto alternate3; statement2; goto end; alternate3: if !(value == const-expr3) goto alternate0; statement3; goto end; alternate0: statement0 end: ``` #### `default` Label ```c switch (x) { case 1: statement1; break; case 2: statement2; break; default: statement0; } // equivalent to the above `default` Labeled `switch` if (x == 1) { statement1; goto endswitch; } if (x == 2) { statement2; goto endswitch; } statement0; endswitch: ``` ______________________________________________________________________ **7 translations** for `break` and `continue` --- #### `break` in a **while** loop ```c while (condition) { if (something) break; statement; } begin: // equivalent to the above break in a while-loop if (!(condition)) goto end; if (something) goto end; statement; goto begin; end: ``` --- #### `break` in a **for** loop ```c for (i = 0; i < n; i++) { if (something) break; statement; } i = 0; // equivalent to the above break in a for-loop begin: if (!(i < n)) goto end; if (something) goto end; statement; i++; goto begin; end: ``` --- #### `break` in a **do-while** loop ```c do { if (something) break; statement; } while (condition); begin: // equivalent to the above break in a do-while-loop if (something) goto end; statement; if (condition) goto begin; end: ``` --- #### `break` in a **switch** statement ```c switch (x) { case 1: statement1; break; case 2: statement2; break; default: statement0; } if (x == 1) { statement1; goto endswitch; } if (x == 2) { statement2; goto endswitch; } statement0; endswitch: ``` --- #### `continue` in a **while** loop ```c while (condition) { if (skip) continue; statement; } begin: // equivalent to the above continue in a while-loop if (!(condition)) goto end; if (skip) goto begin; statement; goto begin; end: ``` --- #### `continue` in a **for** loop ```c for (i = 0; i < n; i++) { if (skip) continue; statement; } i = 0; // equivalent to the above continue in a for-loop begin: if (!(i < n)) goto end; if (skip) goto continuefor; statement; continuefor: i++; goto begin; end: ``` --- #### `continue` in a **do-while** loop ```c do { if (skip) continue; statement; } while (condition); begin: // equivalent to the above continue in a do-while-loop if (skip) goto checkcond; statement; checkcond: if (condition) goto begin; end: ``` ______________________________________________________________________ #### nested break continue ?? We may also need **nested-loop `break` and `continue` translations** — those require labeled `goto` targets to simulate breaking or continuing *outer* loops, which makes them more complex and interesting. That would complete the mapping for every case. #### other Structures In addition to the control flow structures mentioned, C language has other important control flow constructs: **Comma operator (`,`)**: Can be used in control flow contexts, particularly in for loops, to evaluate multiple expressions where only one is typically expected. **Null statements**: A standalone semicolon (`;`) that does nothing, sometimes used in loops where all the work is done in the loop condition. ______________________________________________________________________ #### `functions` can be turned into goto Statements too ```c int func() { if (error) return -1; return 0; } func: // equivalent to the above using goto if (error) { result = -1; goto endfunc; } result = 0; endfunc: return result; ``` HOWEVER, special care must be taken to expose functions to other programs, this brings functions slightly outside the realm of control flow. **Function calls**: While not strictly a control flow statement, calling a function transfers control to that function until it returns. even though we can replace function calls with gotos, they need to be left in to represent where we will leave symbol references for the "`.o`" files (even executables are formatted this way the `main()` function is called). // CA_size decides how big a grocery list we want to have before we go // to to he store // // Developers should only need the type they are working with and the // pointer to the COA_##type and we will provide: // size pushstart popstart pushend popend functions from the // underlying structures above. // // /* ________________________________________________________________ */ // might need these: // typedef struct COA_##type { size Head } // typedef struct Deck_##type { size Start End // typedef struct LLNode_##type { data next prev // typedef struct CA_##type { data[CA_size] size start_offset end_offset // // struct CA_##type get allocated in llnode // free() with pop() on 1 element remaining. // malloc() with push() to a full deck. // /* ________________________________________________________________ */ // #define DEFINE_COA(base_type, ca_type, deck_type, CA_size) \ // typedef struct COA_##base_type { \ // uint64_t size; \ // deck_type* deque; \ // } COA_##base_type; \ // \ // COA_##base_type* New_COA_##base_type(); \ // void COA_pushStart_##base_type(base_type *xref, COA_##base_type* c); \ // void COA_pushEnd_##base_type(base_type *xref, COA_##base_type* c); \ // void COA_popStart_##base_type(base_type *xref, COA_##base_type* c); \ // void COA_popEnd_##base_type(base_type *xref, COA_##base_type* c); \ // \ // COA_##base_type* New_COA_##base_type() { \ // COA_##base_type* c = zalloc(sizeof(COA_##base_type)); \ // c->size = 0; \ // c->deque = zalloc(sizeof(deck_type)); \ // ca_type* first = zalloc(sizeof(ca_type)); \ // first->size = 0; \ // first->start_offset = 0; \ // first->end_offset = 0; \ // pushStart_Deck_##ca_type(NULL, c->deque); \ // c->deque->Start->data = first; \ // return c; \ // } \ // \ // void COA_pushStart_##base_type(base_type *xref, COA_##base_type* c) { \ // ca_type* current = c->deque->Start->data; \ // if (current->size >= CA_size) { \ // ca_type* newArray = zalloc(sizeof(ca_type)); \ // newArray->size = 0; \ // newArray->start_offset = CA_size - 1; \ // newArray->end_offset = (CA_size - 1 + 1) % CA_size; \ // newArray->data[newArray->start_offset] = *xref; \ // newArray->size++; \ // pushStart_Deck_##ca_type(NULL, c->deque); \ // c->deque->Start->data = newArray; \ // } else { \ // pushStart_CA_##base_type(xref, current); \ // } \ // c->size++; \ // } \ // \ // void COA_pushEnd_##base_type(base_type *xref, COA_##base_type* c) { \ // ca_type* current = c->deque->End->data; \ // if (current->size >= CA_size) { \ // ca_type* newArray = zalloc(sizeof(ca_type)); \ // newArray->size = 0; \ // newArray->start_offset = 0; \ // newArray->end_offset = 0; \ // newArray->data[newArray->end_offset] = *xref; \ // newArray->size++; \ // pushEnd_Deck_##ca_type(NULL, c->deque); \ // c->deque->End->data = newArray; \ // } else { \ // pushEnd_CA_##base_type(xref, current); \ // } \ // c->size++; \ // } \ // \ // void COA_popStart_##base_type(base_type *xref, COA_##base_type* c) { \ // assert(c->size > 0); \ // ca_type* current = c->deque->Start->data; \ // popStart_CA_##base_type(xref, current); \ // c->size--; \ // if (current->size == 0) { \ // if (c->deque->Start == c->deque->End) { \ // current->size = 0; \ // current->start_offset = 0; \ // current->end_offset = 0; \ // } else { \ // LLNode_##ca_type* temp = c->deque->Start; \ // c->deque->Start = c->deque->Start->next; \ // c->deque->Start->prev = NULL; \ // free(temp); \ // free(current); \ // } \ // } \ // } \ // \ // void COA_popEnd_##base_type(base_type *xref, COA_##base_type* c) { \ // assert(c->size > 0); \ // ca_type* current = c->deque->End->data; \ // popEnd_CA_##base_type(xref, current); \ // c->size--; \ // if (current->size == 0) { \ // if (c->deque->Start == c->deque->End) { \ // current->size = 0; \ // current->start_offset = 0; \ // current->end_offset = 0; \ // } else { \ // LLNode_##ca_type* temp = c->deque->End; \ // c->deque->End = c->deque->End->prev; \ // c->deque->End->next = NULL; \ // free(temp); \ // free(current); \ // } \ // } \ // } // typedef Deck_CA_float64_t CA_float64_t_deck; // #define CA_float64_t_deck_type Deck_CA_float64_t // // DEFINE_COA(float64_t, CA_float64_t, CA_float64_t_deck_type, 256) // typedef Deck_CA_float64_t CA_float64_t_deck; // #define CA_float64_t_deck_type Deck_CA_float64_t // // DEFINE_COA(float64_t, CA_float64_t, CA_float64_t_deck, 256) // DEFINE_COA(float64_t, CA_float64_t, CA_float64_t_deck_type, 256) // DEFINE_COA(float64_t, CA_float64_t, Deck_CA_float64_t, 256) // DEFINE_COA(float64_t, CA_float64_t, Deck_CA_float64_t*, 256) // DEFINE_COA(float64_t, CA_float64_t, CA_float64_t_ptr, 256)