]> git.sur5r.net Git - cc65/blobdiff - src/cc65/loadexpr.c
Replace hard returns with an "else", add an error for non-IDENT tokens, and test...
[cc65] / src / cc65 / loadexpr.c
index b39506a004efb1c513fa0821bbaeee52365220e7..fa37c6bbd64281251b58e560df2f7b15cc086593 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2004      Ullrich von Bassewitz                                       */
-/*               Römerstraße 52                                              */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 2004-2009, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
@@ -43,7 +43,7 @@
 
 
 /*****************************************************************************/
-/*                                  Code                                    */
+/*                                   Code                                    */
 /*****************************************************************************/
 
 
@@ -53,38 +53,38 @@ static void LoadConstant (unsigned Flags, ExprDesc* Expr)
 {
     switch (ED_GetLoc (Expr)) {
 
-               case E_LOC_ABS:
-           /* Number constant */
-                   g_getimmed (Flags | TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0);
-                   break;
+        case E_LOC_ABS:
+            /* Number constant */
+            g_getimmed (Flags | TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0);
+            break;
 
         case E_LOC_GLOBAL:
-                   /* Global symbol, load address */
-           g_getimmed ((Flags | CF_EXTERNAL) & ~CF_CONST, Expr->Name, Expr->IVal);
-                   break;
-
-               case E_LOC_STATIC:
-               case E_LOC_LITERAL:
-                   /* Static symbol or literal, load address */
-                   g_getimmed ((Flags | CF_STATIC) & ~CF_CONST, Expr->Name, Expr->IVal);
-                   break;
-
-               case E_LOC_REGISTER:
-           /* Register variable. Taking the address is usually not
-            * allowed.
-            */
-           if (IS_Get (&AllowRegVarAddr) == 0) {
-               Error ("Cannot take the address of a register variable");
-           }
-                   g_getimmed ((Flags | CF_REGVAR) & ~CF_CONST, Expr->Name, Expr->IVal);
-           break;
-
-       case E_LOC_STACK:
-                   g_leasp (Expr->IVal);
-           break;
-
-               default:
-           Internal ("Unknown constant type: %04X", Expr->Flags);
+            /* Global symbol, load address */
+            g_getimmed ((Flags | CF_EXTERNAL) & ~CF_CONST, Expr->Name, Expr->IVal);
+            break;
+
+        case E_LOC_STATIC:
+        case E_LOC_LITERAL:
+            /* Static symbol or literal, load address */
+            g_getimmed ((Flags | CF_STATIC) & ~CF_CONST, Expr->Name, Expr->IVal);
+            break;
+
+        case E_LOC_REGISTER:
+            /* Register variable. Taking the address is usually not
+            ** allowed.
+            */
+            if (IS_Get (&AllowRegVarAddr) == 0) {
+                Error ("Cannot take the address of a register variable");
+            }
+            g_getimmed ((Flags | CF_REGVAR) & ~CF_CONST, Expr->Name, Expr->IVal);
+            break;
+
+        case E_LOC_STACK:
+            g_leasp (Expr->IVal);
+            break;
+
+        default:
+            Internal ("Unknown constant type: %04X", Expr->Flags);
     }
 }
 
@@ -95,11 +95,20 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr)
 {
     if (ED_IsLVal (Expr)) {
 
-               /* Dereferenced lvalue */
-               Flags |= TypeOf (Expr->Type);
-       if (ED_NeedsTest (Expr)) {
-           Flags |= CF_TEST;
-       }
+        /* Dereferenced lvalue. If this is a bit field its type is unsigned.
+        ** But if the field is completely contained in the lower byte, we will
+        ** throw away the high byte anyway and may therefore load just the
+        ** low byte.
+        */
+        if (ED_IsBitField (Expr)) {
+            Flags |= (Expr->BitOffs + Expr->BitWidth <= CHAR_BITS)? CF_CHAR : CF_INT;
+            Flags |= CF_UNSIGNED;
+        } else {
+            Flags |= TypeOf (Expr->Type);
+        }
+        if (ED_NeedsTest (Expr)) {
+            Flags |= CF_TEST;
+        }
 
         switch (ED_GetLoc (Expr)) {
 
@@ -145,23 +154,38 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr)
                 Internal ("Invalid location in LoadExpr: 0x%04X", ED_GetLoc (Expr));
         }
 
+        /* Handle bit fields. The actual type may have been casted or
+        ** converted, so be sure to always use unsigned ints for the
+        ** operations.
+        */
+        if (ED_IsBitField (Expr)) {
+            unsigned F = CF_INT | CF_UNSIGNED | CF_CONST | (Flags & CF_TEST);
+            /* Shift right by the bit offset */
+            g_asr (F, Expr->BitOffs);
+            /* And by the width if the field doesn't end on an int boundary */
+            if (Expr->BitOffs + Expr->BitWidth != CHAR_BITS &&
+                Expr->BitOffs + Expr->BitWidth != INT_BITS) {
+                g_and (F, (0x0001U << Expr->BitWidth) - 1U);
+            }
+        }
+
         /* Expression was tested */
         ED_TestDone (Expr);
 
     } else {
-       /* An rvalue */
-               if (ED_IsLocExpr (Expr)) {
+        /* An rvalue */
+        if (ED_IsLocExpr (Expr)) {
             if (Expr->IVal != 0) {
                 /* We have an expression in the primary plus a constant
-                 * offset. Adjust the value in the primary accordingly.
-                 */
+                ** offset. Adjust the value in the primary accordingly.
+                */
                 Flags |= TypeOf (Expr->Type);
                 g_inc (Flags | CF_CONST, Expr->IVal);
             }
-       } else {
-           /* Constant of some sort, load it into the primary */
-           LoadConstant (Flags, Expr);
-       }
+        } else {
+            /* Constant of some sort, load it into the primary */
+            LoadConstant (Flags, Expr);
+        }
 
         /* Are we testing this value? */
         if (ED_NeedsTest (Expr)) {
@@ -171,7 +195,5 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr)
             ED_TestDone (Expr);
         }
     }
-}
-
-
 
+}