]> git.sur5r.net Git - cc65/commitdiff
Added variable symbols using .set
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Wed, 11 May 2005 08:31:42 +0000 (08:31 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Wed, 11 May 2005 08:31:42 +0000 (08:31 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@3510 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/ca65/expr.c
src/ca65/main.c
src/ca65/nexttok.c
src/ca65/pseudo.c
src/ca65/scanner.c
src/ca65/scanner.h
src/ca65/symentry.c
src/ca65/symentry.h

index b39f0655ffa1b6202129004c19bfd885946a8134..daed0e69b1f5ed0dd4ceb12e7e9aa385c66df6ff 100644 (file)
@@ -305,8 +305,15 @@ static ExprNode* Symbol (SymEntry* S)
     } else {
         /* Mark the symbol as referenced */
         SymRef (S);
-        /* Create symbol node */
-        return GenSymExpr (S);
+        /* If the symbol is a variable, return just its value, otherwise
+         * return a reference to the symbol.
+         */
+        if (SymIsVar (S)) {
+            return CloneExpr (GetSymExpr (S));
+        } else {
+            /* Create symbol node */
+            return GenSymExpr (S);
+        }
     }
 }
 
index 157470314b2799fd6cd7eb19894761cf59b03f71..42b2891b0486b5b900a2faa1328c2722d923e711 100644 (file)
@@ -562,16 +562,41 @@ static void OneLine (void)
          * is no colon, it's an assignment.
          */
         if (Tok == TOK_EQ || Tok == TOK_ASSIGN) {
-            /* If it's an assign token, we have a label */
+
+            /* Determine the symbol flags from the assignment token */
             unsigned Flags = (Tok == TOK_ASSIGN)? SF_LABEL : SF_NONE;
+
             /* Skip the '=' */
             NextTok ();
+
             /* Define the symbol with the expression following the '=' */
             SymDef (Sym, Expression(), ADDR_SIZE_DEFAULT, Flags);
+
             /* Don't allow anything after a symbol definition */
             ConsumeSep ();
             return;
+
+        } else if (Tok == TOK_SET) {
+
+            ExprNode* Expr;
+
+            /* .SET defines variables (= redefinable symbols) */
+            NextTok ();
+
+            /* Read the assignment expression, which must be constant */
+            Expr = GenLiteralExpr (ConstExpression ());
+
+            /* Define the symbol with the constant expression following
+             * the '='
+             */
+            SymDef (Sym, Expr, ADDR_SIZE_DEFAULT, SF_VAR);
+
+            /* Don't allow anything after a symbol definition */
+            ConsumeSep ();
+            return;
+
         } else {
+
             /* A label. Remember the current segment, so we can later
              * determine the size of the data stored under the label.
              */
index 139017494b792f6524d3278fcc8b18e924bf86c3..350aaf38df69f6502328206387ef0ee5144a74dc 100644 (file)
@@ -206,47 +206,6 @@ static void FuncConcat (void)
 
 
 
-static void FuncLeft (void)
-/* Handle the .LEFT function */
-{
-    long               Count;
-    TokList*   List;
-
-    /* Skip it */
-    NextTok ();
-
-    /* Left paren expected */
-    ConsumeLParen ();
-
-    /* Count argument */
-    Count = ConstExpression ();
-    if (Count < 0 || Count > 100) {
-       Error ("Range error");
-       Count = 1;
-    }
-    ConsumeComma ();
-
-    /* Read the token list */
-    List = CollectTokens (0, (unsigned) Count);
-
-    /* Since we want to insert the list before the now current token, we have
-     * to save the current token in some way and then skip it. To do this, we
-     * will add the current token at the end of the token list (so the list
-     * will never be empty), push the token list, and then skip the current
-     * token. This will replace the current token by the first token from the
-     * list (which will be the old current token in case the list was empty).
-     */
-    AddCurTok (List);
-
-    /* Insert it into the scanner feed */
-    PushTokList (List, ".LEFT");
-
-    /* Skip the current token */
-    NextTok ();
-}
-
-
-
 static void NoIdent (void)
 /* Print an error message and skip the remainder of the line */
 {
@@ -325,6 +284,46 @@ static void FuncIdent (void)
 
 
 
+static void FuncLeft (void)
+/* Handle the .LEFT function */
+{
+    long               Count;
+    TokList*   List;
+
+    /* Skip it */
+    NextTok ();
+
+    /* Left paren expected */
+    ConsumeLParen ();
+
+    /* Count argument. Correct negative counts to zero. */
+    Count = ConstExpression ();
+    if (Count < 0) {
+       Count = 1;
+    }
+    ConsumeComma ();
+
+    /* Read the token list */
+    List = CollectTokens (0, (unsigned) Count);
+
+    /* Since we want to insert the list before the now current token, we have
+     * to save the current token in some way and then skip it. To do this, we
+     * will add the current token at the end of the token list (so the list
+     * will never be empty), push the token list, and then skip the current
+     * token. This will replace the current token by the first token from the
+     * list (which will be the old current token in case the list was empty).
+     */
+    AddCurTok (List);
+
+    /* Insert it into the scanner feed */
+    PushTokList (List, ".LEFT");
+
+    /* Skip the current token */
+    NextTok ();
+}
+
+
+
 static void FuncMid (void)
 /* Handle the .MID function */
 {
@@ -338,19 +337,21 @@ static void FuncMid (void)
     /* Left paren expected */
     ConsumeLParen ();
 
-    /* Start argument */
+    /* Start argument. Since the start argument can get negative with 
+     * expressions like ".tcount(arg)-2", we correct it to zero silently.
+     */
     Start = ConstExpression ();
     if (Start < 0 || Start > 100) {
-       Error ("Range error");
        Start = 0;
     }
     ConsumeComma ();
 
-    /* Count argument */
+    /* Count argument. Similar as above, we will accept negative counts and
+     * correct them to zero silently.
+     */
     Count = ConstExpression ();
-    if (Count < 0 || Count > 100) {
-       Error ("Range error");
-       Count = 1;
+    if (Count < 0) {
+       Count = 0;
     }
     ConsumeComma ();
 
@@ -387,11 +388,10 @@ static void FuncRight (void)
     /* Left paren expected */
     ConsumeLParen ();
 
-    /* Count argument */
+    /* Count argument. Correct negative counts to zero. */
     Count = ConstExpression ();
-    if (Count < 0 || Count > 100) {
-       Error ("Range error");
-       Count = 1;
+    if (Count < 0) {
+       Count = 0;
     }
     ConsumeComma ();
 
index 85aef7d8b43ff8cecee579ad9f1954f9e364770a..1eed86f94a30076ed713cee33f42a069009a902e 100644 (file)
@@ -1771,9 +1771,10 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccNone,          DoROData        },
     { ccNone,           DoScope         },
     { ccNone,          DoSegment       },
+    { ccNone,           DoUnexpected    },      /* .SET */
     { ccNone,                  DoSetCPU        },
     { ccNone,           DoUnexpected    },      /* .SIZEOF */
-    { ccNone,          DoSmart         },                  
+    { ccNone,          DoSmart         },
     { ccNone,           DoUnexpected    },      /* .SPRINTF */
     { ccNone,          DoUnexpected    },      /* .STRAT */
     { ccNone,                  DoUnexpected    },      /* .STRING */
index 69846d9c5eb5e8c4934515e99200656f9dbe22d8..5f64c2adee1566c579001b20b4c817b66dea5e07 100644 (file)
@@ -236,6 +236,7 @@ struct DotKeyword {
     { ".RODATA",       TOK_RODATA      },
     { ".SCOPE",         TOK_SCOPE       },
     { ".SEGMENT",      TOK_SEGMENT     },
+    { ".SET",           TOK_SET         },
     { ".SETCPU",       TOK_SETCPU      },
     { ".SHL",          TOK_SHL         },
     { ".SHR",          TOK_SHR         },
index dedbeb047362abdb7426f5ff1256745774456c33..d347e7a200bf658254c037c564c913c9edee11b4 100644 (file)
@@ -225,6 +225,7 @@ enum Token {
     TOK_RODATA,
     TOK_SCOPE,
     TOK_SEGMENT,
+    TOK_SET,
     TOK_SETCPU,
     TOK_SIZEOF,
     TOK_SMART,
index a1c86d80286ce51acccc75acc256b84a946c7a6c..8fcd5c0a505dbd7e4238ea106bfc73d543527166 100644 (file)
@@ -174,6 +174,38 @@ void SymTransferExprRefs (SymEntry* From, SymEntry* To)
 
 
 
+static void SymReplaceExprRefs (SymEntry* S)
+/* Replace the references to this symbol by a copy of the symbol expression */
+{
+    unsigned I;
+    long     Val;
+
+    /* Check if the expression is const and get its value */
+    int IsConst = IsConstExpr (S->Expr, &Val);
+    CHECK (IsConst);
+
+    /* Loop over all references */
+    for (I = 0; I < CollCount (&S->ExprRefs); ++I) {
+
+        /* Get the expression node */
+        ExprNode* E = CollAtUnchecked (&S->ExprRefs, I);
+
+        /* Safety */
+        CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S);
+
+        /* We cannot touch the root node, since there are pointers to it. 
+         * Replace it by a literal node.
+         */
+        E->Op = EXPR_LITERAL;
+        E->V.Val = Val;
+    }
+
+    /* Remove all symbol references from the symbol */
+    CollDeleteAll (&S->ExprRefs);
+}
+
+
+
 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
 /* Define a new symbol */
 {
@@ -182,11 +214,29 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags
                Error ("Symbol `%s' is already an import", GetSymName (S));
                return;
     }
+    if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
+        /* Variable symbols cannot be exports or globals */
+        Error ("Var symbol `%s' cannot be an export or global symbol", GetSymName (S));
+        return;
+    }
     if (S->Flags & SF_DEFINED) {
-               /* Multiple definition */
-               Error ("Symbol `%s' is already defined", GetSymName (S));
-               S->Flags |= SF_MULTDEF;
-               return;
+               /* Multiple definition. In case of a variable, this is legal. */
+        if ((S->Flags & SF_VAR) == 0) {
+            Error ("Symbol `%s' is already defined", GetSymName (S));
+            S->Flags |= SF_MULTDEF;
+            return;
+        } else {
+            /* Redefinition must also be a variable symbol */
+            if ((Flags & SF_VAR) == 0) {
+                Error ("Symbol `%s' is already different kind", GetSymName (S));
+                return;
+            }
+            /* Delete the current symbol expression, since it will get
+             * replaced
+             */
+            FreeExpr (S->Expr);
+            S->Expr = 0;
+        }
     }
 
     /* Map a default address size to a real value */
@@ -202,6 +252,15 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags
     /* Set the symbol value */
     S->Expr = Expr;
 
+    /* In case of a variable symbol, walk over all expressions containing 
+     * this symbol and replace the (sub-)expression by the literal value of
+     * the tree. Be sure to replace the expression node in place, since there
+     * may be pointers to it.
+     */
+    if (Flags & SF_VAR) {
+        SymReplaceExprRefs (S);
+    }
+
     /* If the symbol is marked as global, export it. Address size is checked
      * below.
      */
@@ -289,6 +348,11 @@ void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
        Error ("Symbol `%s' is already an import", GetSymName (S));
        return;
     }
+    if (S->Flags & SF_VAR) {
+        /* Variable symbols cannot be exported */
+        Error ("Var symbol `%s' cannot be exported", GetSymName (S));
+        return;
+    }
 
     /* If the symbol was marked as global before, remove the global flag and
      * proceed, but check the address size.
@@ -336,6 +400,12 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
  * either imported or exported.
  */
 {
+    if (S->Flags & SF_VAR) {
+        /* Variable symbols cannot be exported or imported */
+        Error ("Var symbol `%s' cannot be made global", GetSymName (S));
+        return;
+    }
+
     /* If the symbol is already marked as import, the address size must match.
      * Apart from that, ignore the global declaration.
      */
@@ -433,6 +503,11 @@ void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Pri
                Error ("Symbol `%s' is already an import", GetSymName (S));
                return;
     }
+    if (S->Flags & SF_VAR) {
+        /* Variable symbols cannot be exported or imported */
+        Error ("Var symbol `%s' cannot be exported", GetSymName (S));
+        return;
+    }
 
     /* If the symbol was already marked as an export or global, check if
      * this was done specifiying the same address size. In case of a global
index c9772a99edf09e43ef33c312118753384af21310..a5d745dd8a73fc8bc0752521f86d0517e84da2eb 100644 (file)
@@ -64,7 +64,8 @@
 #define SF_GLOBAL      0x0010          /* Global symbol */
 #define SF_LOCAL        0x0020          /* Cheap local symbol */
 #define SF_LABEL        0x0080          /* Used as a label */
-#define SF_FORCED       0x0100          /* Forced import, SF_IMPORT also set */
+#define SF_VAR          0x0100          /* Variable symbol */
+#define SF_FORCED       0x0400          /* Forced import, SF_IMPORT also set */
 #define SF_INDEXED     0x0800          /* Index is valid */
 #define SF_MULTDEF             0x2000          /* Multiply defined symbol */
 #define        SF_DEFINED      0x4000          /* Defined */
@@ -217,6 +218,17 @@ INLINE int SymIsExport (const SymEntry* S)
 #  define SymIsExport(S)  (((S)->Flags & SF_EXPORT) != 0)
 #endif
 
+#if defined(HAVE_INLINE)
+INLINE int SymIsVar (const SymEntry* S)
+/* Return true if the given symbol is marked as variable */
+{
+    /* Check the variable flag */
+    return (S->Flags & SF_VAR) != 0;
+}
+#else
+#  define SymIsVar(S)   (((S)->Flags & SF_VAR) != 0)
+#endif
+
 int SymIsConst (SymEntry* Sym, long* Val);
 /* Return true if the given symbol has a constant value. If Val is not NULL
  * and the symbol has a constant value, store it's value there.