/// <summary> /// Process the child nodes of a SwitchNode, and generate 'case's for them. /// </summary> private void ProcessSwitchChildren(int depth, SwitchNode node) { for (int i = 0; i < node.Expression.NumValues; i++) { // skip over child references in the outer loop. once we get to a real // child node, we'll scan for ChildReferenceNodes. if (!(node[i] is ChildReferenceNode)) { // search for child references and generate fall thru cases for (int j = i + 1; j < node.Expression.NumValues; j++) { if (node[j] is ChildReferenceNode && ((ChildReferenceNode)node[j]).Index == i) { EmitIndented(depth, $"case 0x{j:x}: "); EmitComment("fall thru"); } } // emit case label EmitIndented(depth, $"case 0x{i:x}:"); // emit children, followed by 'break' ProcessNode(node[i], depth + 1); if (!(node[i] is Rule) || !spec.Config.NoBreakAfterRule) { EmitIndented(depth + 1, "break;"); } } } }
/// <summary> /// Process a SwitchNode and generate equivalent C code. /// </summary> private void ProcessSwitch(SwitchNode node, int depth) { if (node.Expression is Bitfield) { var bf = (Bitfield)node.Expression; EmitIndented(depth, $"switch ({GenerateBitfield(bf)}) {{"); } else { Debug.Assert(node.Expression is BitfieldSet); var bfSet = (BitfieldSet)node.Expression; EmitIndented(depth, $"switch ({GenerateBitfieldSet(bfSet)}) {{"); } ProcessSwitchChildren(depth, node); EmitIndented(depth, "}"); }
/// <summary> /// Build a decoder subtree for the given switch case. /// </summary> /// <param name="node">The enclosing switch node.</param> /// <param name="value">Value of case (eg., case 0x0 has value 0).</param> /// <returns>Decoder subtree.</returns> private Node BuildSwitchCase(SwitchNode node, int value) { Debug.Assert(value >= 0 && value < node.Expression.NumValues); if (spec.Config.Verbose) { Console.WriteLine("Switch case {0}", value); } // generate a derived RuleSet for this switch case var cond = new Condition(spec, node.Expression.GetBitsForValue(value), new TristateBitArray(spec.NumFlags)); RuleSet derivedSet = ruleSet.Derive(cond); // generate a corresponding TreeBuilder and update its totals for // switch bits & nesting depth var builder = new TreeBuilder(spec, derivedSet, this); builder.totalSwitchBits += node.Expression.NumBits; builder.switchNestingDepth++; // use it to build tree for case label Node child = builder.Build(); // search previously-generated switch cases for functionally identical subtrees for (int previousValue = 0; previousValue < value; previousValue++) { if (node[previousValue].Equals(child)) { if (spec.Config.Verbose) { Console.WriteLine("Pruning child {0} => {1}", value, previousValue); } // replace generated subtree with a reference to the (identical) subtree child = new ChildReferenceNode(spec, previousValue); break; } } return(child); }
/// <summary> /// Actually build the switch node, given the supplied expression. /// </summary> /// <param name="expression">Either a bitfield or a bitfield set.</param> /// <returns>Bitfield node object.</returns> private SwitchNode BuildSwitch(SwitchableNode expression) { if (spec.Config.Verbose) { Console.WriteLine("Building switch node for {0}.", expression.ToString()); } var node = new SwitchNode(spec, expression); // iterate through every possible value of 'expression' for (int value = 0; value < expression.NumValues; value++) { // store child in switch node's table node[value] = BuildSwitchCase(node, value); } if (spec.Config.Verbose) { Console.WriteLine("Switch completed."); } return(node); }