Branching rules
Last time I talked about synthesis and IL generation. Currently, half of the statements already write valid byte code. I have now completed the branching infrastructure that I mentioned in my previous blog post, and most conditional structures and loops are now prepared – including the If, While, and Until structures. The For-Next loop and the Select-Case structure are next. But before going there I decided to wrap up a quick summary about branching rules and what they mean in terms of code compilation.
First of all, there’s a mechanic in place that eliminates unreachable code. For example, if you had an If condition that has a constant expression that always evaluates to false, the compiler knows this during compile time and will not write the byte code for that block. Similarly, if you had a While loop that is known to be always true the compiler doesn’t write the byte code for the expression at all. Code elimination also applies to nested code blocks, meaning that everything inside an unreachable code block is ignored when the byte code output is written. Next, let’s look at the specs:
The If structure
- The
IfandElseIfstatements must know the nextElseIf/Elsestatement in order to branch when the expression is false - The
If,ElseIfandElsestatements must know theEndIfstatement that is associated with the condition chain; TheIfstatement needs it in order to branch when the expression is false, and theElseIfandElsestatements need it in order to issue an unconditional jump to indicate the end of the previous block - The
ElseIfandElsestatements must add an unconditional jump to the correspondingEndIfstatement before any other byte code unless the statement in question is andElseIfwith a constant value expression of false - If the
If/ElseIfexpression is a constant value, don’t write expression byte code - If any of the
IforElseIfblocks evaluated to a constant expression of true, don’t write byte code for any of the subsequent blocks in the same chain - If an
Ifblock or anElseIfblock has a constant expression of false, don’t write its byte code. This includes nested code blocks
In addition to the rules listed above there are some minor tweaks that accomplish cleaner byte code output; I’ve eliminated some branching instructions that are not needed, for example.
The Repeat-Until structure
- The
UntilandForeverstatements must know the correspondingRepeatstatement in order to branch to the correct location - If the
Untilstatement’s expression is a constant value of true, do nothing - If the
Untilstatement’s expression is a constant value of false, add an unconditional jump - The
Foreverstatement just adds an unconditional jump
The While-EndWhile structure
- The
Whilestatement needs to know the correspondingEndWhilestatement in order to branch when the expression is false - The
EndWhilestatement needs to know the correspondingWhilestatement in order to issue an unconditional jump - If the
Whilestatement’s expression is a constant value of false, don’t write byte code for the expression or code block - If the
Whilestatement’s expression is a constant value of true, don’t write the expression’s byte code - The
EndWhilestatement only adds an unconditional jump to theWhilestatement
Controlling loops
The old “Exit” statement is now renamed as “Break”. It exits the Repeat, While, For, and Foreach loops, and continues execution from after the loop.
Similarly, a new loop control statement has been added. The “Continue” statement continues the encapsulating loop from its next iteration pass, but doesn’t exit the loop unless the associated condition dictates so.
The implementation of these is quite straight-forward; The Break statement needs to know the loop’s ending statement, and the Continue statement needs to know the loop’s starting statement. Both issue an unconditional jump.
I haven’t yet implemented these, and will retain doing so until I get the For-Next structure done. I might write a similar blog post about the For-Next structure and Select-Case structure next time…