]> git.sur5r.net Git - cc65/blobdiff - src/cc65/swstmt.c
Fixed a bug
[cc65] / src / cc65 / swstmt.c
index c1317449fedc55487cf660f0869a32c56844d846..5c50f5e6aae7bac66c540c685277db1ddc48b2cd 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2001 Ullrich von Bassewitz                                       */
+/* (C) 1998-2003 Ullrich von Bassewitz                                       */
 /*               Wacholderweg 14                                             */
 /*               D-70597 Stuttgart                                           */
 /* EMail:        uz@cc65.org                                                 */
@@ -73,7 +73,9 @@ void SwitchStatement (void)
     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 */
@@ -84,12 +86,26 @@ void SwitchStatement (void)
     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]);
 
@@ -101,7 +117,7 @@ void SwitchStatement (void)
     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 ();
@@ -121,9 +137,9 @@ void SwitchStatement (void)
                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 */
@@ -142,14 +158,14 @@ void SwitchStatement (void)
                            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) {
@@ -166,7 +182,7 @@ void SwitchStatement (void)
                }
 
                /* Insert the case selector into the selector table */
-               CaseLabel = InsertCaseValue (Nodes, Val, Depth);
+                       CaseLabel = InsertCaseValue (Nodes, Val, Depth);
 
                /* Define this label */
                g_defcodelabel (CaseLabel);
@@ -200,7 +216,7 @@ void SwitchStatement (void)
 
        /* Parse statements */
        if (CurTok.Tok != TOK_RCURLY) {
-                   Statement (0);
+                   HaveBreak = Statement (0);
        }
     }
 
@@ -211,8 +227,24 @@ void SwitchStatement (void)
 
     } 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);