/* Explanation of how we handle conditions and booleans: of course, C has no booleans, and all conditionals are expected to be lazy evaluated, ie if we have "a || b", then if a is true, b is never evaluated. Which is important if b is a function call with side effects, such as getchar(). However C does convert the results of boolean operations and arithmetic comparisons to the canonical values 0 for false and 1 for true, even akthough "if (x) ..." considers x to be true for any non-0 value. In this file, we identify those boolean expressions which are being used in a context that automatically assures that you can evaluate them as short-circuit conditionals, and jump to one of two destinations (corresponding to true or false for the whole condition) at any point in the evaluation of the condition. These conditions are the ones in "if (...) " statements etc; once they have been processed, and remaining boolean conditions are to be treated as evaluating to truth values 0 and 1, and stored somewhere or used appropriately - in other words, a statement like a = (x && y) is to be treated as a = (x && y ? TRUE : FALSE). Sometimes this equivalency is not necessary (eg if a and b are known to have already been canonicalised to 0 or 1), but when a and b are unknown, wrapping them in (... ? ... : ...) serves the dual purpose of both canonicaalisation _and_ wrapping the lazy evaluation conditional in a framework that causes the jumps to work. When we *are* able to treat conditions are pure booleans, we use BAND, BOR and BNOT to evaluate the expressions. (BNOT == Eor #1) Also, in expressions like "a && b", a and b are implicitly to be treated as being compared against 0, ie (a != 0) && (b != 0) if using short-circuit evaluation, otherwise if treated as regular booleans, conditions can be evaluated with bitwise Ands and Ors. Coercion to 0/1 booleans should start at the leaves, and propogate up the tree so that parent nodes do not need to be coerced again. Finally, we take advantage of the jumps on true/false to implement negation by swapping those jumps, which is free. We don't yet simplify conditions using DeMorgan's law, which is also sometimes useful to save a negation when we don't have both true and false brtanches to follow. One final tweak - possible more sensible to implement in the general tree-rewrite optimiser module than here - is to catch all sequences of "||" where the operands are not canonical booleans, and handle them arithmetically, eg (a || b || c) -> ( a!=0 || b!=0 || c!=0) -> (a|b|c) != 0 */