]> git.sur5r.net Git - cc65/commitdiff
Switch statement may now contain arbitrary code as the standard requires. The
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Fri, 1 Aug 2008 19:44:01 +0000 (19:44 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Fri, 1 Aug 2008 19:44:01 +0000 (19:44 +0000)
compiler will now accept stuff like Duffs device.

git-svn-id: svn://svn.cc65.org/cc65/trunk@3859 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/cc65/stmt.c
src/cc65/stmt.h
src/cc65/swstmt.c
src/cc65/swstmt.h

index 67742113cdda5532c7e9540d6d3a48042118702f..3e4787ecf2a64ce8bdedcfa8655878598fdac3c0 100644 (file)
@@ -6,8 +6,8 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2004 Ullrich von Bassewitz                                       */
-/*               Römerstraße 52                                              */
+/* (C) 1998-2008 Ullrich von Bassewitz                                       */
+/*               Roemerstrasse 52                                            */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
@@ -57,9 +57,9 @@
 #include "pragma.h"
 #include "scanner.h"
 #include "stackptr.h"
+#include "stmt.h"
 #include "swstmt.h"
 #include "symtab.h"
-#include "stmt.h"
 #include "testexpr.h"
 #include "typeconv.h"
 
@@ -542,7 +542,7 @@ int Statement (int* PendingToken)
            case TOK_LCURLY:
                NextToken ();
                GotBreak = CompoundStatement ();
-               CheckTok (TOK_RCURLY, "`{' expected", PendingToken);
+                       CheckTok (TOK_RCURLY, "`{' expected", PendingToken);
                return GotBreak;
 
            case TOK_IF:
@@ -567,7 +567,7 @@ int Statement (int* PendingToken)
 
            case TOK_BREAK:
                BreakStatement ();
-               CheckSemi (PendingToken);
+                       CheckSemi (PendingToken);
                return 1;
 
            case TOK_CONTINUE:
@@ -593,6 +593,14 @@ int Statement (int* PendingToken)
                DoPragma ();
                break;
 
+            case TOK_CASE:
+                CaseLabel ();
+                break;
+
+            case TOK_DEFAULT:
+                DefaultLabel ();
+                break;
+
            default:
                 /* Remember the current code position */
                 GetCodePos (&Start);
@@ -606,7 +614,7 @@ int Statement (int* PendingToken)
                 }
                 /* If the statement didn't generate code, and is not of type
                  * void, emit a warning.
-                 */     
+                 */
                 GetCodePos (&End);
                 if (CodeRangeIsEmpty (&Start, &End) && !IsTypeVoid (Expr.Type)) {
                     Warning ("Statement has no effect");
index 0a504a0ba27a49a8819f176181ac7ce90f2eacbf..8a1d2a94107a67341a810ba9be3c6c0bf955b743 100644 (file)
@@ -6,9 +6,9 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2001 Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
+/* (C) 1998-2008 Ullrich von Bassewitz                                       */
+/*               Roemerstrasse 52                                            */
+/*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
 /*                                                                           */
index cba0b06ad0ea586391ea66672ffe66daf56e9a9a..b5c4b2b8f06948d66993a27cc2b997b59580aebf 100644 (file)
@@ -6,8 +6,8 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (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 */
+    SwitchCtrl* OldSwitch;      /* Pointer to old switch control data */
+    SwitchCtrl  SwitchData;     /* New switch data */
 
 
     /* Eat the "switch" token */
@@ -112,15 +129,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 +143,169 @@ 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 (0);
 
-    /* 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);
+                                                                    
+    /* Exit the loop */
+    DelLoop ();
 
-                   case T_UCHAR:
-                       if (Val < 0 || Val > 255) {
-                           Error ("Range error");
-                       }
-                       break;
+    /* Switch back to the enclosing switch statement if any */
+    Switch = OldSwitch;
 
-                   case T_SHORT:
-                   case T_INT:
-                       if (Val < -32768 || Val > 32767) {
-                           Error ("Range error");
-                       }
-                       break;
+    /* Free the case value tree */
+    FreeCaseNodeColl (SwitchData.Nodes);
+}
 
-                   case T_USHORT:
-                   case T_UINT:
-                       if (Val < 0 || Val > 65535) {
-                           Error ("Range error");
-                       }
-                       break;
 
-                   case T_LONG:
-                   case T_ULONG:
-                       break;
 
-                   default:
-                       Internal ("Invalid type: %06lX", SwitchExprType);
-               }
+void CaseLabel (void)
+/* Handle a case sabel */
+{
+    ExprDesc CaseExpr;          /* Case label expression */
+    long     Val;               /* Case label value */
+    unsigned CodeLabel;         /* Code label for this case */
 
-               /* Insert the case selector into the selector table */
-                       CaseLabel = InsertCaseValue (Nodes, Val, Depth);
 
-               /* Define this label */
-               g_defcodelabel (CaseLabel);
+    /* Skip the "case" token */
+    NextToken ();
 
-               /* Skip the colon */
-               ConsumeColon ();
+    /* Read the selector expression */
+    ConstAbsIntExpr (hie1, &CaseExpr);
+    Val = CaseExpr.IVal;
 
-           } else {
+    /* Now check if we're inside a switch statement */
+    if (Switch != 0) {
 
-               /* Default case */
-               NextToken ();
+        /* Check the range of the expression */
+        switch (Switch->ExprType) {
 
-               /* Check if we do already have a default branch */
-               if (DefaultLabel == 0) {
+            case T_SCHAR:
+                /* Signed char */
+                if (Val < -128 || Val > 127) {
+                    Error ("Range error");
+                }
+                break;
 
-                   /* Generate and emit the default label */
-                   DefaultLabel = GetLocalLabel ();
-                   g_defcodelabel (DefaultLabel);
+            case T_UCHAR:
+                if (Val < 0 || Val > 255) {
+                    Error ("Range error");
+                }
+                break;
 
-               } else {
-                   /* We had the default label already */
-                   Error ("Duplicate `default' case");
-               }
+            case T_SHORT:
+            case T_INT:
+                if (Val < -32768 || Val > 32767) {
+                    Error ("Range error");
+                }
+                break;
 
-               /* Skip the colon */
-               ConsumeColon ();
+            case T_USHORT:
+            case T_UINT:
+                if (Val < 0 || Val > 65535) {
+                    Error ("Range error");
+                }
+                break;
 
-           }
+            case T_LONG:
+            case T_ULONG:
+                break;
 
-       }
+            default:
+                Internal ("Invalid type: %06lX", Switch->ExprType);
+        }
 
-       /* Parse statements */
-       if (CurTok.Tok != TOK_RCURLY) {
-                   HaveBreak = Statement (0);
-       }
-    }
+        /* Insert the case selector into the selector table */
+        CodeLabel = InsertCaseValue (Switch->Nodes, Val, Switch->Depth);
 
-    /* Check if we had any labels */
-    if (CollCount (Nodes) == 0 && DefaultLabel == 0) {
+        /* Define this label */
+        g_defcodelabel (CodeLabel);
 
-       Warning ("No case labels");
+    } else {
 
-    }
+        /* case keyword outside a switch statement */
+        Error ("Case label not within a switch statement");
 
-    /* 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 */
-    GetCodePos (&SwitchCodeStart);
+    /* Skip the colon */
+    ConsumeColon ();
+}
 
-    /* Output the switch code label */
-    g_defcodelabel (SwitchCodeLabel);
 
-    /* Generate code */
-    g_switch (Nodes, DefaultLabel? DefaultLabel : ExitLabel, Depth);
 
-    /* Move the code to the front */
-    GetCodePos (&SwitchCodeEnd);
-    MoveCode (&SwitchCodeStart, &SwitchCodeEnd, &CaseCodeStart);
+void DefaultLabel (void)
+/* Handle a default label */
+{
+    /* Default case */
+    NextToken ();
 
-    /* Define the exit label */
-    g_defcodelabel (ExitLabel);
+    /* Now check if we're inside a switch statement */
+    if (Switch != 0) {
 
-    /* Eat the closing curly brace */
-    NextToken ();
+        /* Check if we do already have a default branch */
+        if (Switch->DefaultLabel == 0) {
 
-    /* Free the case value tree */
-    FreeCaseNodeColl (Nodes);
+            /* Generate and emit the default label */
+            Switch->DefaultLabel = GetLocalLabel ();
+            g_defcodelabel (Switch->DefaultLabel);
 
-    /* End the loop */
-    DelLoop ();
+        } 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 ();
 }
 
 
index 3077d224b7116cec183edb7e98fc8b4b3283832a..7af232f85509a9bb32e6078a32355b83f739d217 100644 (file)
@@ -6,9 +6,9 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2001 Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
+/* (C) 1998-2008 Ullrich von Bassewitz                                       */
+/*               Roemerstrasse 52                                            */
+/*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
 /*                                                                           */
 void SwitchStatement (void);
 /* Handle a 'switch' statement */
 
+void CaseLabel (void);
+/* Handle a case label */
+
+void DefaultLabel (void);
+/* Handle a default label */
+
 
 
 /* End of swstmt.h */