} 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);
+ }
}
}
* 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.
*/
-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 */
{
+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 */
{
/* 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 ();
/* 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 ();
{ 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 */
{ ".RODATA", TOK_RODATA },
{ ".SCOPE", TOK_SCOPE },
{ ".SEGMENT", TOK_SEGMENT },
+ { ".SET", TOK_SET },
{ ".SETCPU", TOK_SETCPU },
{ ".SHL", TOK_SHL },
{ ".SHR", TOK_SHR },
TOK_RODATA,
TOK_SCOPE,
TOK_SEGMENT,
+ TOK_SET,
TOK_SETCPU,
TOK_SIZEOF,
TOK_SMART,
+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 */
{
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 */
/* 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.
*/
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.
* 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.
*/
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
#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 */
# 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.