]> git.sur5r.net Git - cc65/blobdiff - src/cc65/swstmt.c
Removed (pretty inconsistently used) tab chars from source code base.
[cc65] / src / cc65 / swstmt.c
index cba0b06ad0ea586391ea66672ffe66daf56e9a9a..7e48b58d2cf0daf5677f3f3283a3407c3e479b38 100644 (file)
@@ -1,13 +1,13 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                swstmt.c                                  */
+/*                                 swstmt.c                                  */
 /*                                                                           */
-/*                       Parse the switch statement                         */
+/*                        Parse the switch statement                         */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2006 Ullrich von Bassewitz                                       */
-/*               Römerstraße 52                                              */
+/* (C) 1998-2008 Ullrich von Bassewitz                                       */
+/*               Roemerstrasse 52                                            */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
 
 
 /*****************************************************************************/
-/*                                  Code                                    */
+/*                                   Data                                    */
+/*****************************************************************************/
+
+
+
+typedef struct SwitchCtrl SwitchCtrl;
+struct SwitchCtrl {
+    Collection* Nodes;          /* CaseNode tree */
+    TypeCode    ExprType;       /* Basic switch expression type */
+    unsigned    Depth;          /* Number of bytes the selector type has */
+    unsigned    DefaultLabel;   /* Label for the default branch */
+
+
+
+};
+
+/* Pointer to current switch control struct */
+static SwitchCtrl* Switch = 0;
+
+
+
+/*****************************************************************************/
+/*                                   Code                                    */
 /*****************************************************************************/
 
 
 void SwitchStatement (void)
 /* Handle a switch statement for chars with a cmp cascade for the selector */
 {
-    Collection* Nodes;          /* CaseNode tree */
-    ExprDesc SwitchExpr;               /* Switch statement expression */
-    ExprDesc CaseExpr;          /* Case label expression */
-    TypeCode SwitchExprType;    /* Basic switch expression type */
-    CodeMark CaseCodeStart;     /* Start of code marker */
-    CodeMark SwitchCodeStart;   /* Start of switch code */
-    CodeMark SwitchCodeEnd;     /* End of switch code */
-    unsigned Depth;             /* Number of bytes the selector type has */
-    unsigned ExitLabel;                /* Exit label */
-    unsigned CaseLabel;         /* Label for case */
-    unsigned DefaultLabel;      /* Label for the default branch */
-    unsigned SwitchCodeLabel;   /* Label for the switch code */
-    long     Val;               /* Case label value */
-    int      HaveBreak = 0;     /* True if the last statement had a break */
+    ExprDesc    SwitchExpr;     /* Switch statement expression */
+    CodeMark    CaseCodeStart;  /* Start of code marker */
+    CodeMark    SwitchCodeStart;/* Start of switch code */
+    CodeMark    SwitchCodeEnd;  /* End of switch code */
+    unsigned    ExitLabel;      /* Exit label */
+    unsigned    SwitchCodeLabel;/* Label for the switch code */
+    int         HaveBreak = 0;  /* True if the last statement had a break */
+    int         RCurlyBrace;    /* True if last token is right curly brace */
+    SwitchCtrl* OldSwitch;      /* Pointer to old switch control data */
+    SwitchCtrl  SwitchData;     /* New switch data */
 
 
     /* Eat the "switch" token */
@@ -90,8 +108,8 @@ void SwitchStatement (void)
     Expression0 (&SwitchExpr);
     if (!IsClassInt (SwitchExpr.Type))  {
         Error ("Switch quantity is not an integer");
-       /* To avoid any compiler errors, make the expression a valid int */
-       ED_MakeConstAbsInt (&SwitchExpr, 1);
+        /* To avoid any compiler errors, make the expression a valid int */
+        ED_MakeConstAbsInt (&SwitchExpr, 1);
     }
     ConsumeRParen ();
 
@@ -112,15 +130,13 @@ void SwitchStatement (void)
      */
     GetCodePos (&CaseCodeStart);
 
-    /* Opening curly brace */
-    ConsumeLCurly ();
-
-    /* Get the unqualified type of the switch expression */
-    SwitchExprType = UnqualifiedType (SwitchExpr.Type[0].C);
-
-    /* Get the number of bytes the selector type has */
-    Depth = SizeOf (SwitchExpr.Type);
-    CHECK (Depth == SIZEOF_CHAR || Depth == SIZEOF_INT || Depth == SIZEOF_LONG);
+    /* Setup the control structure, save the old and activate the new one */
+    SwitchData.Nodes        = NewCollection ();
+    SwitchData.ExprType     = UnqualifiedType (SwitchExpr.Type[0].C);
+    SwitchData.Depth        = SizeOf (SwitchExpr.Type);
+    SwitchData.DefaultLabel = 0;
+    OldSwitch = Switch;
+    Switch = &SwitchData;
 
     /* Get the exit label for the switch statement */
     ExitLabel = GetLocalLabel ();
@@ -128,146 +144,176 @@ void SwitchStatement (void)
     /* Create a loop so we may use break. */
     AddLoop (ExitLabel, 0);
 
-    /* Create the collection for the case node tree */
-    Nodes = NewCollection ();
+    /* Make sure a curly brace follows */
+    if (CurTok.Tok != TOK_LCURLY) {
+        Error ("`{' expected");
+    }
 
-    /* Clear the label for the default branch */
-    DefaultLabel = 0;
+    /* Parse the following statement, which will actually be a compound
+     * statement because of the curly brace at the current input position
+     */
+    HaveBreak = Statement (&RCurlyBrace);
 
-    /* Parse the labels */
-    while (CurTok.Tok != TOK_RCURLY) {
+    /* Check if we had any labels */
+    if (CollCount (SwitchData.Nodes) == 0 && SwitchData.DefaultLabel == 0) {
+        Warning ("No case labels");
+    }
 
-       while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
+    /* 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);
+    }
 
-           /* Parse the selector */
-           if (CurTok.Tok == TOK_CASE) {
+    /* Remember the current position */
+    GetCodePos (&SwitchCodeStart);
 
-               /* Skip the "case" token */
-               NextToken ();
+    /* Output the switch code label */
+    g_defcodelabel (SwitchCodeLabel);
 
-               /* Read the selector expression */
-               ConstAbsIntExpr (hie1, &CaseExpr);
+    /* Generate code */
+    if (SwitchData.DefaultLabel == 0) {
+        /* No default label, use switch exit */
+        SwitchData.DefaultLabel = ExitLabel;
+    }
+    g_switch (SwitchData.Nodes, SwitchData.DefaultLabel, SwitchData.Depth);
 
-               /* Check the range of the expression */
-               Val = CaseExpr.IVal;
-               switch (SwitchExprType) {
+    /* Move the code to the front */
+    GetCodePos (&SwitchCodeEnd);
+    MoveCode (&SwitchCodeStart, &SwitchCodeEnd, &CaseCodeStart);
 
-                   case T_SCHAR:
-                       /* Signed char */
-                       if (Val < -128 || Val > 127) {
-                           Error ("Range error");
-                       }
-                       break;
+    /* Define the exit label */
+    g_defcodelabel (ExitLabel);
 
-                   case T_UCHAR:
-                       if (Val < 0 || Val > 255) {
-                           Error ("Range error");
-                       }
-                       break;
+    /* Exit the loop */
+    DelLoop ();
 
-                   case T_SHORT:
-                   case T_INT:
-                       if (Val < -32768 || Val > 32767) {
-                           Error ("Range error");
-                       }
-                       break;
+    /* Switch back to the enclosing switch statement if any */
+    Switch = OldSwitch;
 
-                   case T_USHORT:
-                   case T_UINT:
-                       if (Val < 0 || Val > 65535) {
-                           Error ("Range error");
-                       }
-                       break;
+    /* Free the case value tree */
+    FreeCaseNodeColl (SwitchData.Nodes);
 
-                   case T_LONG:
-                   case T_ULONG:
-                       break;
+    /* If the case statement was (correctly) terminated by a closing curly
+     * brace, skip it now.
+     */
+    if (RCurlyBrace) {
+        NextToken ();
+    }
+}
 
-                   default:
-                       Internal ("Invalid type: %06lX", SwitchExprType);
-               }
 
-               /* Insert the case selector into the selector table */
-                       CaseLabel = InsertCaseValue (Nodes, Val, Depth);
 
-               /* Define this label */
-               g_defcodelabel (CaseLabel);
+void CaseLabel (void)
+/* Handle a case sabel */
+{
+    ExprDesc CaseExpr;          /* Case label expression */
+    long     Val;               /* Case label value */
+    unsigned CodeLabel;         /* Code label for this case */
 
-               /* Skip the colon */
-               ConsumeColon ();
 
-           } else {
+    /* Skip the "case" token */
+    NextToken ();
 
-               /* Default case */
-               NextToken ();
+    /* Read the selector expression */
+    ConstAbsIntExpr (hie1, &CaseExpr);
+    Val = CaseExpr.IVal;
 
-               /* Check if we do already have a default branch */
-               if (DefaultLabel == 0) {
+    /* Now check if we're inside a switch statement */
+    if (Switch != 0) {
 
-                   /* Generate and emit the default label */
-                   DefaultLabel = GetLocalLabel ();
-                   g_defcodelabel (DefaultLabel);
+        /* Check the range of the expression */
+        switch (Switch->ExprType) {
 
-               } else {
-                   /* We had the default label already */
-                   Error ("Duplicate `default' case");
-               }
+            case T_SCHAR:
+                /* Signed char */
+                if (Val < -128 || Val > 127) {
+                    Error ("Range error");
+                }
+                break;
 
-               /* Skip the colon */
-               ConsumeColon ();
+            case T_UCHAR:
+                if (Val < 0 || Val > 255) {
+                    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) {
+                    Error ("Range error");
+                }
+                break;
 
-       /* Parse statements */
-       if (CurTok.Tok != TOK_RCURLY) {
-                   HaveBreak = Statement (0);
-       }
-    }
+            case T_LONG:
+            case T_ULONG:
+                break;
 
-    /* Check if we had any labels */
-    if (CollCount (Nodes) == 0 && DefaultLabel == 0) {
+            default:
+                Internal ("Invalid type: %06lX", Switch->ExprType);
+        }
 
-       Warning ("No case labels");
+        /* Insert the case selector into the selector table */
+        CodeLabel = InsertCaseValue (Switch->Nodes, Val, Switch->Depth);
 
-    }
+        /* Define this label */
+        g_defcodelabel (CodeLabel);
 
-    /* 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);
-    }
+    } else {
 
-    /* Remember the current position */
-    GetCodePos (&SwitchCodeStart);
+        /* case keyword outside a switch statement */
+        Error ("Case label not within a switch statement");
 
-    /* Output the switch code label */
-    g_defcodelabel (SwitchCodeLabel);
+    }
 
-    /* Generate code */
-    g_switch (Nodes, DefaultLabel? DefaultLabel : ExitLabel, Depth);
+    /* Skip the colon */
+    ConsumeColon ();
+}
 
-    /* Move the code to the front */
-    GetCodePos (&SwitchCodeEnd);
-    MoveCode (&SwitchCodeStart, &SwitchCodeEnd, &CaseCodeStart);
 
-    /* Define the exit label */
-    g_defcodelabel (ExitLabel);
 
-    /* Eat the closing curly brace */
+void DefaultLabel (void)
+/* Handle a default label */
+{
+    /* Default case */
     NextToken ();
 
-    /* Free the case value tree */
-    FreeCaseNodeColl (Nodes);
+    /* Now check if we're inside a switch statement */
+    if (Switch != 0) {
 
-    /* End the loop */
-    DelLoop ();
+        /* Check if we do already have a default branch */
+        if (Switch->DefaultLabel == 0) {
+
+            /* Generate and emit the default label */
+            Switch->DefaultLabel = GetLocalLabel ();
+            g_defcodelabel (Switch->DefaultLabel);
+
+        } else {
+            /* We had the default label already */
+            Error ("Multiple default labels in one switch");
+        }
+
+    } else {
+
+        /* case keyword outside a switch statement */
+        Error ("`default' label not within a switch statement");
+
+    }
+
+    /* Skip the colon */
+    ConsumeColon ();
 }