Added variable symbols using .set
git-svn-id: svn://svn.cc65.org/cc65/trunk@3510 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
f06dc5dfa3
commit
945bbe2b50
8 changed files with 182 additions and 60 deletions
|
@ -305,10 +305,17 @@ static ExprNode* Symbol (SymEntry* S)
|
||||||
} else {
|
} else {
|
||||||
/* Mark the symbol as referenced */
|
/* Mark the symbol as referenced */
|
||||||
SymRef (S);
|
SymRef (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 */
|
/* Create symbol node */
|
||||||
return GenSymExpr (S);
|
return GenSymExpr (S);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -562,16 +562,41 @@ static void OneLine (void)
|
||||||
* is no colon, it's an assignment.
|
* is no colon, it's an assignment.
|
||||||
*/
|
*/
|
||||||
if (Tok == TOK_EQ || Tok == TOK_ASSIGN) {
|
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;
|
unsigned Flags = (Tok == TOK_ASSIGN)? SF_LABEL : SF_NONE;
|
||||||
|
|
||||||
/* Skip the '=' */
|
/* Skip the '=' */
|
||||||
NextTok ();
|
NextTok ();
|
||||||
|
|
||||||
/* Define the symbol with the expression following the '=' */
|
/* Define the symbol with the expression following the '=' */
|
||||||
SymDef (Sym, Expression(), ADDR_SIZE_DEFAULT, Flags);
|
SymDef (Sym, Expression(), ADDR_SIZE_DEFAULT, Flags);
|
||||||
|
|
||||||
/* Don't allow anything after a symbol definition */
|
/* Don't allow anything after a symbol definition */
|
||||||
ConsumeSep ();
|
ConsumeSep ();
|
||||||
return;
|
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 {
|
} else {
|
||||||
|
|
||||||
/* A label. Remember the current segment, so we can later
|
/* A label. Remember the current segment, so we can later
|
||||||
* determine the size of the data stored under the label.
|
* determine the size of the data stored under the label.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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)
|
static void NoIdent (void)
|
||||||
/* Print an error message and skip the remainder of the line */
|
/* 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)
|
static void FuncMid (void)
|
||||||
/* Handle the .MID function */
|
/* Handle the .MID function */
|
||||||
{
|
{
|
||||||
|
@ -338,19 +337,21 @@ static void FuncMid (void)
|
||||||
/* Left paren expected */
|
/* Left paren expected */
|
||||||
ConsumeLParen ();
|
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 ();
|
Start = ConstExpression ();
|
||||||
if (Start < 0 || Start > 100) {
|
if (Start < 0 || Start > 100) {
|
||||||
Error ("Range error");
|
|
||||||
Start = 0;
|
Start = 0;
|
||||||
}
|
}
|
||||||
ConsumeComma ();
|
ConsumeComma ();
|
||||||
|
|
||||||
/* Count argument */
|
/* Count argument. Similar as above, we will accept negative counts and
|
||||||
|
* correct them to zero silently.
|
||||||
|
*/
|
||||||
Count = ConstExpression ();
|
Count = ConstExpression ();
|
||||||
if (Count < 0 || Count > 100) {
|
if (Count < 0) {
|
||||||
Error ("Range error");
|
Count = 0;
|
||||||
Count = 1;
|
|
||||||
}
|
}
|
||||||
ConsumeComma ();
|
ConsumeComma ();
|
||||||
|
|
||||||
|
@ -387,11 +388,10 @@ static void FuncRight (void)
|
||||||
/* Left paren expected */
|
/* Left paren expected */
|
||||||
ConsumeLParen ();
|
ConsumeLParen ();
|
||||||
|
|
||||||
/* Count argument */
|
/* Count argument. Correct negative counts to zero. */
|
||||||
Count = ConstExpression ();
|
Count = ConstExpression ();
|
||||||
if (Count < 0 || Count > 100) {
|
if (Count < 0) {
|
||||||
Error ("Range error");
|
Count = 0;
|
||||||
Count = 1;
|
|
||||||
}
|
}
|
||||||
ConsumeComma ();
|
ConsumeComma ();
|
||||||
|
|
||||||
|
|
|
@ -1771,6 +1771,7 @@ static CtrlDesc CtrlCmdTab [] = {
|
||||||
{ ccNone, DoROData },
|
{ ccNone, DoROData },
|
||||||
{ ccNone, DoScope },
|
{ ccNone, DoScope },
|
||||||
{ ccNone, DoSegment },
|
{ ccNone, DoSegment },
|
||||||
|
{ ccNone, DoUnexpected }, /* .SET */
|
||||||
{ ccNone, DoSetCPU },
|
{ ccNone, DoSetCPU },
|
||||||
{ ccNone, DoUnexpected }, /* .SIZEOF */
|
{ ccNone, DoUnexpected }, /* .SIZEOF */
|
||||||
{ ccNone, DoSmart },
|
{ ccNone, DoSmart },
|
||||||
|
|
|
@ -236,6 +236,7 @@ struct DotKeyword {
|
||||||
{ ".RODATA", TOK_RODATA },
|
{ ".RODATA", TOK_RODATA },
|
||||||
{ ".SCOPE", TOK_SCOPE },
|
{ ".SCOPE", TOK_SCOPE },
|
||||||
{ ".SEGMENT", TOK_SEGMENT },
|
{ ".SEGMENT", TOK_SEGMENT },
|
||||||
|
{ ".SET", TOK_SET },
|
||||||
{ ".SETCPU", TOK_SETCPU },
|
{ ".SETCPU", TOK_SETCPU },
|
||||||
{ ".SHL", TOK_SHL },
|
{ ".SHL", TOK_SHL },
|
||||||
{ ".SHR", TOK_SHR },
|
{ ".SHR", TOK_SHR },
|
||||||
|
|
|
@ -225,6 +225,7 @@ enum Token {
|
||||||
TOK_RODATA,
|
TOK_RODATA,
|
||||||
TOK_SCOPE,
|
TOK_SCOPE,
|
||||||
TOK_SEGMENT,
|
TOK_SEGMENT,
|
||||||
|
TOK_SET,
|
||||||
TOK_SETCPU,
|
TOK_SETCPU,
|
||||||
TOK_SIZEOF,
|
TOK_SIZEOF,
|
||||||
TOK_SMART,
|
TOK_SMART,
|
||||||
|
|
|
@ -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)
|
void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
|
||||||
/* Define a new symbol */
|
/* 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));
|
Error ("Symbol `%s' is already an import", GetSymName (S));
|
||||||
return;
|
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) {
|
if (S->Flags & SF_DEFINED) {
|
||||||
/* Multiple definition */
|
/* Multiple definition. In case of a variable, this is legal. */
|
||||||
|
if ((S->Flags & SF_VAR) == 0) {
|
||||||
Error ("Symbol `%s' is already defined", GetSymName (S));
|
Error ("Symbol `%s' is already defined", GetSymName (S));
|
||||||
S->Flags |= SF_MULTDEF;
|
S->Flags |= SF_MULTDEF;
|
||||||
return;
|
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 */
|
/* 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 */
|
/* Set the symbol value */
|
||||||
S->Expr = Expr;
|
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
|
/* If the symbol is marked as global, export it. Address size is checked
|
||||||
* below.
|
* below.
|
||||||
*/
|
*/
|
||||||
|
@ -289,6 +348,11 @@ void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||||
Error ("Symbol `%s' is already an import", GetSymName (S));
|
Error ("Symbol `%s' is already an import", GetSymName (S));
|
||||||
return;
|
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
|
/* If the symbol was marked as global before, remove the global flag and
|
||||||
* proceed, but check the address size.
|
* proceed, but check the address size.
|
||||||
|
@ -336,6 +400,12 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||||
* either imported or exported.
|
* 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.
|
/* If the symbol is already marked as import, the address size must match.
|
||||||
* Apart from that, ignore the global declaration.
|
* 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));
|
Error ("Symbol `%s' is already an import", GetSymName (S));
|
||||||
return;
|
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
|
/* 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
|
* this was done specifiying the same address size. In case of a global
|
||||||
|
|
|
@ -64,7 +64,8 @@
|
||||||
#define SF_GLOBAL 0x0010 /* Global symbol */
|
#define SF_GLOBAL 0x0010 /* Global symbol */
|
||||||
#define SF_LOCAL 0x0020 /* Cheap local symbol */
|
#define SF_LOCAL 0x0020 /* Cheap local symbol */
|
||||||
#define SF_LABEL 0x0080 /* Used as a label */
|
#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_INDEXED 0x0800 /* Index is valid */
|
||||||
#define SF_MULTDEF 0x2000 /* Multiply defined symbol */
|
#define SF_MULTDEF 0x2000 /* Multiply defined symbol */
|
||||||
#define SF_DEFINED 0x4000 /* Defined */
|
#define SF_DEFINED 0x4000 /* Defined */
|
||||||
|
@ -217,6 +218,17 @@ INLINE int SymIsExport (const SymEntry* S)
|
||||||
# define SymIsExport(S) (((S)->Flags & SF_EXPORT) != 0)
|
# define SymIsExport(S) (((S)->Flags & SF_EXPORT) != 0)
|
||||||
#endif
|
#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);
|
int SymIsConst (SymEntry* Sym, long* Val);
|
||||||
/* Return true if the given symbol has a constant value. If Val is not NULL
|
/* 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.
|
* and the symbol has a constant value, store it's value there.
|
||||||
|
|
Loading…
Add table
Reference in a new issue