public static IReadOnlyList <Int32> GrabLabels(SwitchStmt stmt) { CaseLabelsGrabber grabber = new CaseLabelsGrabber(); stmt.Stmt.Accept(grabber); return(grabber.Labels); }
public override void CGenStmt(Env env, CGenState state) { // Inside a switch statement, the initializations are ignored, // but the stack size should be changed. List <Tuple <Env, Decln> > declns; List <Tuple <Env, Stmt> > stmts; var compoundStmt = this.Stmt as CompoundStmt; if (compoundStmt == null) { throw new NotImplementedException(); } declns = compoundStmt.Declns; stmts = compoundStmt.Stmts; // Track all case values. IReadOnlyList <Int32> values = CaseLabelsGrabber.GrabLabels(this); // Make sure there are no duplicates. if (values.Distinct().Count() != values.Count) { throw new InvalidOperationException("case labels not unique."); } // Request labels for these values. Dictionary <Int32, Int32> value_to_label = values.ToDictionary(value => value, value => state.RequestLabel()); Int32 label_finish = state.RequestLabel(); Int32 num_default_stmts = stmts.Count(_ => _.Item2 is DefaultStmt); if (num_default_stmts > 1) { throw new InvalidOperationException("duplicate defaults."); } Int32 label_default = num_default_stmts == 1 ? state.RequestLabel() : label_finish; Int32 saved_stack_size = state.StackSize; Int32 stack_size = declns.Any() ? declns.Last().Item1.StackSize : saved_stack_size; // 1. Evaluate Expr. CGenExprStmt(env, this.Expr, state); // 2. Expand stack. state.CGenForceStackSizeTo(stack_size); // 3. Make the Jump list. foreach (KeyValuePair <Int32, Int32> value_label_pair in value_to_label) { state.CMPL(value_label_pair.Key, Reg.EAX); state.JZ(value_label_pair.Value); } state.JMP(label_default); // 4. List all the statements. state.InSwitch(label_finish, label_default, value_to_label); foreach (Tuple <Env, Stmt> env_stmt_pair in stmts) { env_stmt_pair.Item2.CGenStmt(env_stmt_pair.Item1, state); } state.OutLabels(); // 5. finish: state.CGenLabel(label_finish); // 6. Restore stack size. state.CGenForceStackSizeTo(saved_stack_size); }
public static IReadOnlyList<Int32> GrabLabels(SwitchStmt stmt) { CaseLabelsGrabber grabber = new CaseLabelsGrabber(); stmt.Stmt.Accept(grabber); return grabber.Labels; }