/* */
/* */
/* */
-/* (C) 1998-2001 Ullrich von Bassewitz */
+/* (C) 1998-2003 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@cc65.org */
unsigned ExitLabel; /* Exit label */
unsigned CaseLabel; /* Label for case */
unsigned DefaultLabel; /* Label for the default branch */
- long Val; /* Case label value */
+ unsigned SwitchCodeLabel; /* Label for the switch code */
+ long Val; /* Case label value */
+ int HaveBreak = 0; /* True if the last statement had a break */
/* Eat the "switch" token */
intexpr (&SwitchExpr);
ConsumeRParen ();
+ /* Add a jump to the switch code. This jump is usually unnecessary,
+ * because the switch code will moved up just behind the switch
+ * expression. However, in rare cases, there's a label at the end of
+ * the switch expression. This label will not get moved, so the code
+ * jumps around the switch code, and after moving the switch code,
+ * things look really weird. If we add a jump here, we will never have
+ * a label attached to the current code position, and the jump itself
+ * will get removed by the optimizer if it is unnecessary.
+ */
+ SwitchCodeLabel = GetLocalLabel ();
+ g_jump (SwitchCodeLabel);
+
+ /* Remember the current code position. We will move the switch code
+ * to this position later.
+ */
+ CaseCodeStart = GetCodePos();
+
/* Opening curly brace */
ConsumeLCurly ();
- /* Remember the current code position */
- CaseCodeStart = GetCodePos();
-
/* Get the unqualified type of the switch expression */
SwitchExprType = UnqualifiedType (SwitchExpr.Type[0]);
ExitLabel = GetLocalLabel ();
/* Create a loop so we may use break. */
- AddLoop (oursp, 0, ExitLabel, 0, 0);
+ AddLoop (oursp, ExitLabel, 0);
/* Create the collection for the case node tree */
Nodes = NewCollection ();
NextToken ();
/* Read the selector expression */
- constexpr (&CaseExpr);
+ ConstExpr (&CaseExpr);
if (!IsClassInt (CaseExpr.Type)) {
- Error ("Switch quantity not an integer");
+ Error ("Switch quantity not an integer");
}
/* Check the range of the expression */
Error ("Range error");
}
break;
-
+
case T_SHORT:
case T_INT:
if (Val < -32768 || Val > 32767) {
Error ("Range error");
}
break;
-
+
case T_USHORT:
case T_UINT:
if (Val < 0 || Val > 65535) {
}
/* Insert the case selector into the selector table */
- CaseLabel = InsertCaseValue (Nodes, Val, Depth);
+ CaseLabel = InsertCaseValue (Nodes, Val, Depth);
/* Define this label */
g_defcodelabel (CaseLabel);
/* Parse statements */
if (CurTok.Tok != TOK_RCURLY) {
- Statement (0);
+ HaveBreak = Statement (0);
}
}
} else {
+ CodeMark SwitchCodeStart;
+
+ /* If the last statement did not have a break, we may have an open
+ * label (maybe from an if or similar). Emitting code and then moving
+ * this code to the top will also move the label to the top which is
+ * wrong. So if the last statement did not have a break (which would
+ * carry the label), add a jump to the exit. If it is useless, the
+ * optimizer will remove it later.
+ */
+ if (!HaveBreak) {
+ g_jump (ExitLabel);
+ }
+
/* Remember the current position */
- CodeMark SwitchCodeStart = GetCodePos();
+ SwitchCodeStart = GetCodePos();
+
+ /* Output the switch code label */
+ g_defcodelabel (SwitchCodeLabel);
/* Generate code */
g_switch (Nodes, DefaultLabel? DefaultLabel : ExitLabel, Depth);