More work on expressions and address sizes
git-svn-id: svn://svn.cc65.org/cc65/trunk@2658 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* (C) 1998-2003 Ullrich von Bassewitz */
|
/* (C) 1998-2003 Ullrich von Bassewitz */
|
||||||
/* R<>merstrasse 52 */
|
/* R<>merstra<EFBFBD>e 52 */
|
||||||
/* D-70794 Filderstadt */
|
/* D-70794 Filderstadt */
|
||||||
/* EMail: uz@cc65.org */
|
/* EMail: uz@cc65.org */
|
||||||
/* */
|
/* */
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/* Warning levels */
|
/* Warning levels */
|
||||||
extern unsigned WarnLevel;
|
extern unsigned WarnLevel;
|
||||||
|
|
||||||
/* Statistics */
|
/* Statistics */
|
||||||
extern unsigned ErrorCount;
|
extern unsigned ErrorCount;
|
||||||
@@ -73,7 +73,7 @@ void PWarning (const FilePos* Pos, unsigned Level, const char* Format, ...) attr
|
|||||||
|
|
||||||
void Error (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
void Error (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||||
/* Print an error message */
|
/* Print an error message */
|
||||||
|
|
||||||
void PError (const FilePos* Pos, const char* Format, ...) attribute ((format (printf, 2, 3)));
|
void PError (const FilePos* Pos, const char* Format, ...) attribute ((format (printf, 2, 3)));
|
||||||
/* Print an error message giving an explicit file and position. */
|
/* Print an error message giving an explicit file and position. */
|
||||||
|
|
||||||
|
|||||||
311
src/ca65/expr.c
311
src/ca65/expr.c
@@ -92,6 +92,17 @@ struct ExprDesc {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Forwards */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void StudyExpr (ExprNode* Expr, ExprDesc* D, int Sign);
|
||||||
|
/* Study an expression tree and place the contents into D */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Helpers */
|
/* Helpers */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -559,8 +570,13 @@ static ExprNode* Factor (void)
|
|||||||
} else {
|
} else {
|
||||||
/* Mark the symbol as referenced */
|
/* Mark the symbol as referenced */
|
||||||
SymRef (S);
|
SymRef (S);
|
||||||
/* Create symbol node */
|
/* Remove the symbol if possible */
|
||||||
N = GenSymExpr (S);
|
if (SymHasExpr (S)) {
|
||||||
|
N = CloneExpr (GetSymExpr (S));
|
||||||
|
} else {
|
||||||
|
/* Create symbol node */
|
||||||
|
N = GenSymExpr (S);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -787,7 +803,7 @@ static ExprNode* Term (void)
|
|||||||
|
|
||||||
/* Generate an expression tree */
|
/* Generate an expression tree */
|
||||||
unsigned char Op;
|
unsigned char Op;
|
||||||
switch (T) {
|
switch (T) {
|
||||||
case TOK_MUL: Op = EXPR_MUL; break;
|
case TOK_MUL: Op = EXPR_MUL; break;
|
||||||
case TOK_DIV: Op = EXPR_DIV; break;
|
case TOK_DIV: Op = EXPR_DIV; break;
|
||||||
case TOK_MOD: Op = EXPR_MOD; break;
|
case TOK_MOD: Op = EXPR_MOD; break;
|
||||||
@@ -819,22 +835,50 @@ static ExprNode* SimpleExpr (void)
|
|||||||
/* Handle additive operations */
|
/* Handle additive operations */
|
||||||
while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) {
|
while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) {
|
||||||
|
|
||||||
/* Create the new node */
|
long LVal, RVal, Val;
|
||||||
ExprNode* Left = Root;
|
ExprNode* Left;
|
||||||
switch (Tok) {
|
ExprNode* Right;
|
||||||
case TOK_PLUS: Root = NewExprNode (EXPR_PLUS); break;
|
|
||||||
case TOK_MINUS: Root = NewExprNode (EXPR_MINUS); break;
|
|
||||||
case TOK_OR: Root = NewExprNode (EXPR_OR); break;
|
|
||||||
default: Internal ("Invalid token");
|
|
||||||
}
|
|
||||||
Root->Left = Left;
|
|
||||||
|
|
||||||
/* Skip the operator token */
|
/* Remember the token and skip it */
|
||||||
NextTok ();
|
enum Token T = Tok;
|
||||||
|
NextTok ();
|
||||||
|
|
||||||
/* Parse the right hand side */
|
/* Move root to left side and read the right side */
|
||||||
Root->Right = Term ();
|
Left = Root;
|
||||||
|
Right = Term ();
|
||||||
|
|
||||||
|
/* If both expressions are constant, we can evaluate the term */
|
||||||
|
if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
|
||||||
|
|
||||||
|
switch (T) {
|
||||||
|
case TOK_PLUS: Val = LVal + RVal; break;
|
||||||
|
case TOK_MINUS: Val = LVal - RVal; break;
|
||||||
|
case TOK_OR: Val = LVal | RVal; break;
|
||||||
|
default: Internal ("Invalid token");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate a literal expression and delete the old left and
|
||||||
|
* right sides.
|
||||||
|
*/
|
||||||
|
FreeExpr (Left);
|
||||||
|
FreeExpr (Right);
|
||||||
|
Root = GenLiteralExpr (Val);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Generate an expression tree */
|
||||||
|
unsigned char Op;
|
||||||
|
switch (T) {
|
||||||
|
case TOK_PLUS: Op = EXPR_PLUS; break;
|
||||||
|
case TOK_MINUS: Op = EXPR_MINUS; break;
|
||||||
|
case TOK_OR: Op = EXPR_OR; break;
|
||||||
|
default: Internal ("Invalid token");
|
||||||
|
}
|
||||||
|
Root = NewExprNode (Op);
|
||||||
|
Root->Left = Left;
|
||||||
|
Root->Right = Right;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the expression tree we've created */
|
/* Return the expression tree we've created */
|
||||||
@@ -853,25 +897,56 @@ static ExprNode* BoolExpr (void)
|
|||||||
while (Tok == TOK_EQ || Tok == TOK_NE || Tok == TOK_LT ||
|
while (Tok == TOK_EQ || Tok == TOK_NE || Tok == TOK_LT ||
|
||||||
Tok == TOK_GT || Tok == TOK_LE || Tok == TOK_GE) {
|
Tok == TOK_GT || Tok == TOK_LE || Tok == TOK_GE) {
|
||||||
|
|
||||||
/* Create the new node */
|
long LVal, RVal, Val;
|
||||||
ExprNode* Left = Root;
|
ExprNode* Left;
|
||||||
switch (Tok) {
|
ExprNode* Right;
|
||||||
case TOK_EQ: Root = NewExprNode (EXPR_EQ); break;
|
|
||||||
case TOK_NE: Root = NewExprNode (EXPR_NE); break;
|
|
||||||
case TOK_LT: Root = NewExprNode (EXPR_LT); break;
|
|
||||||
case TOK_GT: Root = NewExprNode (EXPR_GT); break;
|
|
||||||
case TOK_LE: Root = NewExprNode (EXPR_LE); break;
|
|
||||||
case TOK_GE: Root = NewExprNode (EXPR_GE); break;
|
|
||||||
default: Internal ("Invalid token");
|
|
||||||
}
|
|
||||||
Root->Left = Left;
|
|
||||||
|
|
||||||
/* Skip the operator token */
|
/* Remember the token and skip it */
|
||||||
NextTok ();
|
enum Token T = Tok;
|
||||||
|
NextTok ();
|
||||||
|
|
||||||
/* Parse the right hand side */
|
/* Move root to left side and read the right side */
|
||||||
Root->Right = SimpleExpr ();
|
Left = Root;
|
||||||
|
Right = SimpleExpr ();
|
||||||
|
|
||||||
|
/* If both expressions are constant, we can evaluate the term */
|
||||||
|
if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
|
||||||
|
|
||||||
|
switch (T) {
|
||||||
|
case TOK_EQ: Val = (LVal == RVal); break;
|
||||||
|
case TOK_NE: Val = (LVal != RVal); break;
|
||||||
|
case TOK_LT: Val = (LVal < RVal); break;
|
||||||
|
case TOK_GT: Val = (LVal > RVal); break;
|
||||||
|
case TOK_LE: Val = (LVal <= RVal); break;
|
||||||
|
case TOK_GE: Val = (LVal >= RVal); break;
|
||||||
|
default: Internal ("Invalid token");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate a literal expression and delete the old left and
|
||||||
|
* right sides.
|
||||||
|
*/
|
||||||
|
FreeExpr (Left);
|
||||||
|
FreeExpr (Right);
|
||||||
|
Root = GenLiteralExpr (Val);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Generate an expression tree */
|
||||||
|
unsigned char Op;
|
||||||
|
switch (T) {
|
||||||
|
case TOK_EQ: Op = EXPR_EQ; break;
|
||||||
|
case TOK_NE: Op = EXPR_NE; break;
|
||||||
|
case TOK_LT: Op = EXPR_LT; break;
|
||||||
|
case TOK_GT: Op = EXPR_GT; break;
|
||||||
|
case TOK_LE: Op = EXPR_LE; break;
|
||||||
|
case TOK_GE: Op = EXPR_GE; break;
|
||||||
|
default: Internal ("Invalid token");
|
||||||
|
}
|
||||||
|
Root = NewExprNode (Op);
|
||||||
|
Root->Left = Left;
|
||||||
|
Root->Right = Right;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the expression tree we've created */
|
/* Return the expression tree we've created */
|
||||||
@@ -889,21 +964,48 @@ static ExprNode* Expr2 (void)
|
|||||||
/* Handle booleans */
|
/* Handle booleans */
|
||||||
while (Tok == TOK_BOOLAND || Tok == TOK_BOOLXOR) {
|
while (Tok == TOK_BOOLAND || Tok == TOK_BOOLXOR) {
|
||||||
|
|
||||||
/* Create the new node */
|
long LVal, RVal, Val;
|
||||||
ExprNode* Left = Root;
|
ExprNode* Left;
|
||||||
switch (Tok) {
|
ExprNode* Right;
|
||||||
case TOK_BOOLAND: Root = NewExprNode (EXPR_BOOLAND); break;
|
|
||||||
case TOK_BOOLXOR: Root = NewExprNode (EXPR_BOOLXOR); break;
|
|
||||||
default: Internal ("Invalid token");
|
|
||||||
}
|
|
||||||
Root->Left = Left;
|
|
||||||
|
|
||||||
/* Skip the operator token */
|
/* Remember the token and skip it */
|
||||||
NextTok ();
|
enum Token T = Tok;
|
||||||
|
NextTok ();
|
||||||
|
|
||||||
/* Parse the right hand side */
|
/* Move root to left side and read the right side */
|
||||||
Root->Right = BoolExpr ();
|
Left = Root;
|
||||||
|
Right = BoolExpr ();
|
||||||
|
|
||||||
|
/* If both expressions are constant, we can evaluate the term */
|
||||||
|
if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
|
||||||
|
|
||||||
|
switch (T) {
|
||||||
|
case TOK_BOOLAND: Val = ((LVal != 0) && (RVal != 0)); break;
|
||||||
|
case TOK_BOOLXOR: Val = ((LVal != 0) ^ (RVal != 0)); break;
|
||||||
|
default: Internal ("Invalid token");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate a literal expression and delete the old left and
|
||||||
|
* right sides.
|
||||||
|
*/
|
||||||
|
FreeExpr (Left);
|
||||||
|
FreeExpr (Right);
|
||||||
|
Root = GenLiteralExpr (Val);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Generate an expression tree */
|
||||||
|
unsigned char Op;
|
||||||
|
switch (T) {
|
||||||
|
case TOK_BOOLAND: Op = EXPR_BOOLAND; break;
|
||||||
|
case TOK_BOOLXOR: Op = EXPR_BOOLXOR; break;
|
||||||
|
default: Internal ("Invalid token");
|
||||||
|
}
|
||||||
|
Root = NewExprNode (Op);
|
||||||
|
Root->Left = Left;
|
||||||
|
Root->Right = Right;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the expression tree we've created */
|
/* Return the expression tree we've created */
|
||||||
@@ -921,20 +1023,46 @@ static ExprNode* Expr1 (void)
|
|||||||
/* Handle booleans */
|
/* Handle booleans */
|
||||||
while (Tok == TOK_BOOLOR) {
|
while (Tok == TOK_BOOLOR) {
|
||||||
|
|
||||||
/* Create the new node */
|
long LVal, RVal, Val;
|
||||||
ExprNode* Left = Root;
|
ExprNode* Left;
|
||||||
switch (Tok) {
|
ExprNode* Right;
|
||||||
case TOK_BOOLOR: Root = NewExprNode (EXPR_BOOLOR); break;
|
|
||||||
default: Internal ("Invalid token");
|
|
||||||
}
|
|
||||||
Root->Left = Left;
|
|
||||||
|
|
||||||
/* Skip the operator token */
|
/* Remember the token and skip it */
|
||||||
NextTok ();
|
enum Token T = Tok;
|
||||||
|
NextTok ();
|
||||||
|
|
||||||
/* Parse the right hand side */
|
/* Move root to left side and read the right side */
|
||||||
Root->Right = Expr2 ();
|
Left = Root;
|
||||||
|
Right = Expr2 ();
|
||||||
|
|
||||||
|
/* If both expressions are constant, we can evaluate the term */
|
||||||
|
if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
|
||||||
|
|
||||||
|
switch (T) {
|
||||||
|
case TOK_BOOLOR: Val = ((LVal != 0) || (RVal != 0)); break;
|
||||||
|
default: Internal ("Invalid token");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate a literal expression and delete the old left and
|
||||||
|
* right sides.
|
||||||
|
*/
|
||||||
|
FreeExpr (Left);
|
||||||
|
FreeExpr (Right);
|
||||||
|
Root = GenLiteralExpr (Val);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Generate an expression tree */
|
||||||
|
unsigned char Op;
|
||||||
|
switch (T) {
|
||||||
|
case TOK_BOOLOR: Op = EXPR_BOOLOR; break;
|
||||||
|
default: Internal ("Invalid token");
|
||||||
|
}
|
||||||
|
Root = NewExprNode (Op);
|
||||||
|
Root->Left = Left;
|
||||||
|
Root->Right = Right;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the expression tree we've created */
|
/* Return the expression tree we've created */
|
||||||
@@ -951,14 +1079,23 @@ static ExprNode* Expr0 (void)
|
|||||||
/* Handle booleans */
|
/* Handle booleans */
|
||||||
if (Tok == TOK_BOOLNOT) {
|
if (Tok == TOK_BOOLNOT) {
|
||||||
|
|
||||||
/* Create the new node */
|
long Val;
|
||||||
Root = NewExprNode (EXPR_BOOLNOT);
|
ExprNode* Left;
|
||||||
|
|
||||||
/* Skip the operator token */
|
/* Skip the operator token */
|
||||||
NextTok ();
|
NextTok ();
|
||||||
|
|
||||||
/* Parse the left hand side, allow more BNOTs */
|
/* Read the argument */
|
||||||
Root->Left = Expr0 ();
|
Left = Expr0 ();
|
||||||
|
|
||||||
|
/* If the argument is const, evaluate it directly */
|
||||||
|
if (IsEasyConst (Left, &Val)) {
|
||||||
|
FreeExpr (Left);
|
||||||
|
Root = GenLiteralExpr (!Val);
|
||||||
|
} else {
|
||||||
|
Root = NewExprNode (EXPR_BOOLNOT);
|
||||||
|
Root->Left = Left;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -973,9 +1110,8 @@ static ExprNode* Expr0 (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void StudyExpr (ExprNode* Expr, ExprDesc* D, int Sign);
|
|
||||||
static void StudyBinaryExpr (ExprNode* Expr, ExprDesc* D)
|
static void StudyBinaryExpr (ExprNode* Expr, ExprDesc* D)
|
||||||
/* Study a binary expression subtree */
|
/* Study a binary expression subtree. Helper function for StudyExpr. */
|
||||||
{
|
{
|
||||||
StudyExpr (Expr->Left, D, 1);
|
StudyExpr (Expr->Left, D, 1);
|
||||||
if (ExprDescIsConst (D)) {
|
if (ExprDescIsConst (D)) {
|
||||||
@@ -1542,23 +1678,52 @@ ExprNode* GenBranchExpr (unsigned Offs)
|
|||||||
{
|
{
|
||||||
ExprNode* N;
|
ExprNode* N;
|
||||||
ExprNode* Root;
|
ExprNode* Root;
|
||||||
|
long Val;
|
||||||
|
|
||||||
|
/* Read Expression() */
|
||||||
|
N = Expression ();
|
||||||
|
|
||||||
|
/* If the expression is a cheap constant, generate a simpler tree */
|
||||||
|
if (IsEasyConst (N, &Val)) {
|
||||||
|
|
||||||
|
/* Free the constant expression tree */
|
||||||
|
FreeExpr (N);
|
||||||
|
|
||||||
|
/* Generate the final expression:
|
||||||
|
* Val - (* + Offs)
|
||||||
|
* Val - ((Seg + PC) + Offs)
|
||||||
|
* Val - Seg - PC - Offs
|
||||||
|
* (Val - PC - Offs) - Seg
|
||||||
|
*/
|
||||||
|
Root = GenLiteralExpr (Val - GetPC () - Offs);
|
||||||
|
if (RelocMode) {
|
||||||
|
N = Root;
|
||||||
|
Root = NewExprNode (EXPR_MINUS);
|
||||||
|
Root->Left = N;
|
||||||
|
Root->Right = GenSectionExpr (GetCurrentSegNum ());
|
||||||
|
}
|
||||||
|
|
||||||
/* Create *+Offs */
|
|
||||||
if (RelocMode) {
|
|
||||||
N = NewExprNode (EXPR_PLUS);
|
|
||||||
N->Left = GenSectionExpr (GetCurrentSegNum ());
|
|
||||||
N->Right = GenLiteralExpr (GetPC () + Offs);
|
|
||||||
} else {
|
} else {
|
||||||
N = GenLiteralExpr (GetPC () + Offs);
|
|
||||||
|
/* Generate the expression:
|
||||||
|
* N - (* + Offs)
|
||||||
|
* N - ((Seg + PC) + Offs)
|
||||||
|
* N - Seg - PC - Offs
|
||||||
|
* N - (PC + Offs) - Seg
|
||||||
|
*/
|
||||||
|
Root = NewExprNode (EXPR_MINUS);
|
||||||
|
Root->Left = N;
|
||||||
|
Root->Right = GenLiteralExpr (GetPC () + Offs);
|
||||||
|
if (RelocMode) {
|
||||||
|
N = Root;
|
||||||
|
Root = NewExprNode (EXPR_MINUS);
|
||||||
|
Root->Left = N;
|
||||||
|
Root->Right = GenSectionExpr (GetCurrentSegNum ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the root node */
|
|
||||||
Root = NewExprNode (EXPR_MINUS);
|
|
||||||
Root->Left = Expression ();
|
|
||||||
Root->Right = N;
|
|
||||||
|
|
||||||
/* Return the result */
|
/* Return the result */
|
||||||
return SimplifyExpr (Root);
|
return Root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ int main (int argc, char* argv [])
|
|||||||
/* Enter the base lexical level. We must do that here, since we may
|
/* Enter the base lexical level. We must do that here, since we may
|
||||||
* define symbols using -D.
|
* define symbols using -D.
|
||||||
*/
|
*/
|
||||||
SymEnterLevel ("", ADDR_SIZE_DEFAULT);
|
SymEnterLevel ("", ST_GLOBAL, ADDR_SIZE_DEFAULT);
|
||||||
|
|
||||||
/* Check the parameters */
|
/* Check the parameters */
|
||||||
I = 1;
|
I = 1;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* (C) 1998-2003 Ullrich von Bassewitz */
|
/* (C) 1998-2003 Ullrich von Bassewitz */
|
||||||
/* R<>merstrasse 52 */
|
/* R<>merstra<EFBFBD>e 52 */
|
||||||
/* D-70794 Filderstadt */
|
/* D-70794 Filderstadt */
|
||||||
/* EMail: uz@cc65.org */
|
/* EMail: uz@cc65.org */
|
||||||
/* */
|
/* */
|
||||||
@@ -114,7 +114,7 @@ static void DoInvalid (void);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned OptionalAddrSize (void)
|
static unsigned char OptionalAddrSize (void)
|
||||||
/* If a colon follows, parse an optional address size spec and return it.
|
/* If a colon follows, parse an optional address size spec and return it.
|
||||||
* Otherwise return ADDR_SIZE_DEFAULT.
|
* Otherwise return ADDR_SIZE_DEFAULT.
|
||||||
*/
|
*/
|
||||||
@@ -161,12 +161,12 @@ static void SetBoolOption (unsigned char* Flag)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ExportImport (void (*Func) (SymEntry*, unsigned, unsigned),
|
static void ExportImport (void (*Func) (SymEntry*, unsigned char, unsigned),
|
||||||
unsigned DefAddrSize, unsigned Flags)
|
unsigned char DefAddrSize, unsigned Flags)
|
||||||
/* Export or import symbols */
|
/* Export or import symbols */
|
||||||
{
|
{
|
||||||
SymEntry* Sym;
|
SymEntry* Sym;
|
||||||
unsigned AddrSize;
|
unsigned char AddrSize;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
@@ -227,6 +227,10 @@ static void ConDes (const char* Name, unsigned Type)
|
|||||||
{
|
{
|
||||||
long Prio;
|
long Prio;
|
||||||
|
|
||||||
|
|
||||||
|
/* Find the symbol table entry, allocate a new one if necessary */
|
||||||
|
SymEntry* Sym = SymFind (CurrentScope, Name, SYM_ALLOC_NEW);
|
||||||
|
|
||||||
/* Optional constructor priority */
|
/* Optional constructor priority */
|
||||||
if (Tok == TOK_COMMA) {
|
if (Tok == TOK_COMMA) {
|
||||||
/* Priority value follows */
|
/* Priority value follows */
|
||||||
@@ -243,7 +247,7 @@ static void ConDes (const char* Name, unsigned Type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Define the symbol */
|
/* Define the symbol */
|
||||||
SymConDes (Name, Type, (unsigned) Prio);
|
SymConDes (Sym, ADDR_SIZE_DEFAULT, Type, (unsigned) Prio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -700,11 +704,11 @@ static void DoEnd (void)
|
|||||||
static void DoEndProc (void)
|
static void DoEndProc (void)
|
||||||
/* Leave a lexical level */
|
/* Leave a lexical level */
|
||||||
{
|
{
|
||||||
if (CurrentScope != RootScope) {
|
if (CurrentScope == RootScope || GetCurrentSymTabType () != ST_PROC) {
|
||||||
SymLeaveLevel ();
|
|
||||||
} else {
|
|
||||||
/* No local scope */
|
/* No local scope */
|
||||||
ErrorSkip ("No open lexical level");
|
ErrorSkip ("No open .PROC");
|
||||||
|
} else {
|
||||||
|
SymLeaveLevel ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -713,11 +717,11 @@ static void DoEndProc (void)
|
|||||||
static void DoEndScope (void)
|
static void DoEndScope (void)
|
||||||
/* Leave a lexical level */
|
/* Leave a lexical level */
|
||||||
{
|
{
|
||||||
if (CurrentScope != RootScope) {
|
if (CurrentScope == RootScope || GetCurrentSymTabType () != ST_SCOPE) {
|
||||||
SymLeaveLevel ();
|
|
||||||
} else {
|
|
||||||
/* No local scope */
|
/* No local scope */
|
||||||
ErrorSkip ("No open lexical level");
|
ErrorSkip ("No open .SCOPE");
|
||||||
|
} else {
|
||||||
|
SymLeaveLevel ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1294,12 +1298,12 @@ static void DoPopSeg (void)
|
|||||||
static void DoProc (void)
|
static void DoProc (void)
|
||||||
/* Start a new lexical scope */
|
/* Start a new lexical scope */
|
||||||
{
|
{
|
||||||
|
char Name[sizeof(SVal)];
|
||||||
|
unsigned char AddrSize;
|
||||||
|
|
||||||
if (Tok == TOK_IDENT) {
|
if (Tok == TOK_IDENT) {
|
||||||
|
|
||||||
unsigned AddrSize;
|
|
||||||
|
|
||||||
/* The new scope has a name. Remember it. */
|
/* The new scope has a name. Remember it. */
|
||||||
char Name[sizeof(SVal)];
|
|
||||||
strcpy (Name, SVal);
|
strcpy (Name, SVal);
|
||||||
|
|
||||||
/* Search for the symbol, generate a new one if needed */
|
/* Search for the symbol, generate a new one if needed */
|
||||||
@@ -1314,17 +1318,17 @@ static void DoProc (void)
|
|||||||
/* Mark the symbol as defined */
|
/* Mark the symbol as defined */
|
||||||
SymDef (Sym, GenCurrentPC (), AddrSize, SF_LABEL);
|
SymDef (Sym, GenCurrentPC (), AddrSize, SF_LABEL);
|
||||||
|
|
||||||
/* Enter a new scope with the given name */
|
|
||||||
SymEnterLevel (Name, AddrSize);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* A .PROC statement without a name */
|
/* A .PROC statement without a name */
|
||||||
char Buf[sizeof (SVal)];
|
|
||||||
SymEnterLevel (AnonName (Buf, sizeof (Buf), "Scope"), ADDR_SIZE_DEFAULT);
|
|
||||||
Warning (1, "Unnamed .PROCs are deprecated, please use .SCOPE");
|
Warning (1, "Unnamed .PROCs are deprecated, please use .SCOPE");
|
||||||
|
AnonName (Name, sizeof (Name), "PROC");
|
||||||
|
AddrSize = ADDR_SIZE_DEFAULT;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enter a new scope */
|
||||||
|
SymEnterLevel (Name, ST_PROC, AddrSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1413,27 +1417,28 @@ static void DoScope (void)
|
|||||||
/* Start a local scope */
|
/* Start a local scope */
|
||||||
{
|
{
|
||||||
char Name[sizeof (SVal)];
|
char Name[sizeof (SVal)];
|
||||||
|
unsigned char AddrSize;
|
||||||
|
|
||||||
|
|
||||||
if (Tok == TOK_IDENT) {
|
if (Tok == TOK_IDENT) {
|
||||||
|
|
||||||
unsigned AddrSize;
|
/* The new scope has a name. Remember and skip it. */
|
||||||
|
|
||||||
/* The new scope has a name. Remember and skip it. */
|
|
||||||
strcpy (Name, SVal);
|
strcpy (Name, SVal);
|
||||||
NextTok ();
|
NextTok ();
|
||||||
|
|
||||||
/* Read an optional address size specifier */
|
|
||||||
AddrSize = OptionalAddrSize ();
|
|
||||||
|
|
||||||
/* Enter a new scope with the given name */
|
|
||||||
SymEnterLevel (Name, AddrSize);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* An unnamed scope */
|
/* An unnamed scope */
|
||||||
SymEnterLevel (AnonName (Name, sizeof (Name), "Scope"), ADDR_SIZE_DEFAULT);
|
AnonName (Name, sizeof (Name), "SCOPE");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read an optional address size specifier */
|
||||||
|
AddrSize = OptionalAddrSize ();
|
||||||
|
|
||||||
|
/* Enter the new scope */
|
||||||
|
SymEnterLevel (Name, ST_SCOPE, AddrSize);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1671,7 +1676,7 @@ static CtrlDesc CtrlCmdTab [] = {
|
|||||||
{ ccNone, DoRepeat },
|
{ ccNone, DoRepeat },
|
||||||
{ ccNone, DoRes },
|
{ ccNone, DoRes },
|
||||||
{ ccNone, DoInvalid }, /* .RIGHT */
|
{ ccNone, DoInvalid }, /* .RIGHT */
|
||||||
{ ccNone, DoROData },
|
{ ccNone, DoROData },
|
||||||
{ ccNone, DoScope },
|
{ ccNone, DoScope },
|
||||||
{ ccNone, DoSegment },
|
{ ccNone, DoSegment },
|
||||||
{ ccNone, DoSetCPU },
|
{ ccNone, DoSetCPU },
|
||||||
|
|||||||
@@ -1138,7 +1138,7 @@ int GetSubKey (const char** Keys, unsigned Count)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned ParseAddrSize (void)
|
unsigned char ParseAddrSize (void)
|
||||||
/* Check if the next token is a keyword that denotes an address size specifier.
|
/* Check if the next token is a keyword that denotes an address size specifier.
|
||||||
* If so, return the corresponding address size constant, otherwise output an
|
* If so, return the corresponding address size constant, otherwise output an
|
||||||
* error message and return ADDR_SIZE_DEFAULT.
|
* error message and return ADDR_SIZE_DEFAULT.
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* (C) 1998-2003 Ullrich von Bassewitz */
|
/* (C) 1998-2003 Ullrich von Bassewitz */
|
||||||
/* R<>merstrasse 52 */
|
/* R<>merstra<EFBFBD>e 52 */
|
||||||
/* D-70794 Filderstadt */
|
/* D-70794 Filderstadt */
|
||||||
/* EMail: uz@cc65.org */
|
/* EMail: uz@cc65.org */
|
||||||
/* */
|
/* */
|
||||||
@@ -294,7 +294,7 @@ int GetSubKey (const char** Keys, unsigned Count);
|
|||||||
* or -1 if the keyword was not found.
|
* or -1 if the keyword was not found.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned ParseAddrSize (void);
|
unsigned char ParseAddrSize (void);
|
||||||
/* Check if the next token is a keyword that denotes an address size specifier.
|
/* Check if the next token is a keyword that denotes an address size specifier.
|
||||||
* If so, return the corresponding address size constant, otherwise output an
|
* If so, return the corresponding address size constant, otherwise output an
|
||||||
* error message and return ADDR_SIZE_DEFAULT.
|
* error message and return ADDR_SIZE_DEFAULT.
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
|
#include "segment.h"
|
||||||
#include "spool.h"
|
#include "spool.h"
|
||||||
#include "symentry.h"
|
#include "symentry.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
@@ -94,8 +95,8 @@ static unsigned SymAddrSize (const SymEntry* S)
|
|||||||
return ADDR_SIZE_ABS;
|
return ADDR_SIZE_ABS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the address size of the enclosing scope */
|
/* Return the address size of the segment */
|
||||||
return S->SymTab->AddrSize;
|
return GetCurrentSegAddrSize ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -139,7 +140,7 @@ void SymRef (SymEntry* S)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags)
|
void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
|
||||||
/* Define a new symbol */
|
/* Define a new symbol */
|
||||||
{
|
{
|
||||||
if (S->Flags & SF_IMPORT) {
|
if (S->Flags & SF_IMPORT) {
|
||||||
@@ -160,7 +161,7 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set the symbol value */
|
/* Set the symbol value */
|
||||||
S->V.Expr = Expr;
|
S->V.Expr = Expr;
|
||||||
|
|
||||||
/* If the symbol is marked as global, export it */
|
/* If the symbol is marked as global, export it */
|
||||||
if (S->Flags & SF_GLOBAL) {
|
if (S->Flags & SF_GLOBAL) {
|
||||||
@@ -178,7 +179,9 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags)
|
|||||||
/* Use the real size of the symbol */
|
/* Use the real size of the symbol */
|
||||||
S->ExportSize = S->AddrSize;
|
S->ExportSize = S->AddrSize;
|
||||||
} else if (S->AddrSize > S->ExportSize) {
|
} else if (S->AddrSize > S->ExportSize) {
|
||||||
Warning (1, "Address size mismatch for symbol `%s'", GetSymName (S));
|
PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported as %s",
|
||||||
|
GetSymName (S), AddrSizeToStr (S->AddrSize),
|
||||||
|
AddrSizeToStr (S->ExportSize));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +201,7 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SymImport (SymEntry* S, unsigned AddrSize, unsigned Flags)
|
void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||||
/* Mark the given symbol as an imported symbol */
|
/* Mark the given symbol as an imported symbol */
|
||||||
{
|
{
|
||||||
/* Don't accept local symbols */
|
/* Don't accept local symbols */
|
||||||
@@ -226,11 +229,18 @@ void SymImport (SymEntry* S, unsigned AddrSize, unsigned Flags)
|
|||||||
/* If the symbol is marked as import or global, check the symbol flags,
|
/* If the symbol is marked as import or global, check the symbol flags,
|
||||||
* then do silently remove the global flag
|
* then do silently remove the global flag
|
||||||
*/
|
*/
|
||||||
if (S->Flags & (SF_IMPORT | SF_GLOBAL)) {
|
if (S->Flags & SF_IMPORT) {
|
||||||
if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED) ||
|
if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
|
||||||
AddrSize != S->AddrSize) {
|
|
||||||
Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
|
Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
|
||||||
}
|
}
|
||||||
|
if (AddrSize != S->AddrSize) {
|
||||||
|
Error ("Address size mismatch for symbol `%s'", GetSymName (S));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (S->Flags & SF_GLOBAL) {
|
||||||
|
if (S->AddrSize != ADDR_SIZE_DEFAULT && S->AddrSize != AddrSize) {
|
||||||
|
Error ("Address size mismatch for symbol `%s'", GetSymName (S));
|
||||||
|
}
|
||||||
S->Flags &= ~SF_GLOBAL;
|
S->Flags &= ~SF_GLOBAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +251,7 @@ void SymImport (SymEntry* S, unsigned AddrSize, unsigned Flags)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags)
|
void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||||
/* Mark the given symbol as an exported symbol */
|
/* Mark the given symbol as an exported symbol */
|
||||||
{
|
{
|
||||||
/* Don't accept local symbols */
|
/* Don't accept local symbols */
|
||||||
@@ -257,6 +267,131 @@ void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the symbol was marked as global before, make it an export */
|
||||||
|
if (S->Flags & SF_GLOBAL) {
|
||||||
|
S->ExportSize = S->AddrSize;
|
||||||
|
S->Flags &= ~SF_GLOBAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the symbol was already marked as an export, check if this was done
|
||||||
|
* specifiying the same address size. If the old spec had no explicit
|
||||||
|
* address size, use the new one.
|
||||||
|
*/
|
||||||
|
if (S->Flags & SF_EXPORT) {
|
||||||
|
if (S->ExportSize == ADDR_SIZE_DEFAULT) {
|
||||||
|
S->ExportSize = AddrSize;
|
||||||
|
} else if (AddrSize == ADDR_SIZE_DEFAULT) {
|
||||||
|
AddrSize = S->ExportSize;
|
||||||
|
}
|
||||||
|
if (S->ExportSize != ADDR_SIZE_DEFAULT && S->ExportSize != AddrSize) {
|
||||||
|
Error ("Address size mismatch for symbol `%s'", GetSymName (S));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
S->ExportSize = AddrSize;
|
||||||
|
|
||||||
|
/* If the symbol is already defined, check symbol size against the
|
||||||
|
* exported size.
|
||||||
|
*/
|
||||||
|
if (S->Flags & SF_DEFINED) {
|
||||||
|
if (S->ExportSize == ADDR_SIZE_DEFAULT) {
|
||||||
|
/* No export size given, use the real size of the symbol */
|
||||||
|
S->ExportSize = S->AddrSize;
|
||||||
|
} else if (S->AddrSize > S->ExportSize) {
|
||||||
|
Warning (1, "Symbol `%s' is %s but exported as %s",
|
||||||
|
GetSymName (S), AddrSizeToStr (S->AddrSize),
|
||||||
|
AddrSizeToStr (S->ExportSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the symbol data */
|
||||||
|
S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||||
|
/* Mark the given symbol as a global symbol, that is, as a symbol that is
|
||||||
|
* either imported or exported.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Don't accept local symbols */
|
||||||
|
if (IsLocalNameId (S->Name)) {
|
||||||
|
Error ("Illegal use of a local symbol");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the symbol is already marked as import or export, check the
|
||||||
|
* size of the definition, then bail out.
|
||||||
|
*/
|
||||||
|
if (S->Flags & SF_IMPORT) {
|
||||||
|
if (AddrSize != ADDR_SIZE_DEFAULT && AddrSize != S->AddrSize) {
|
||||||
|
Error ("Address size mismatch for symbol `%s'", GetSymName (S));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (S->Flags & SF_EXPORT) {
|
||||||
|
/* If the old symbol had no explicit address size spec, use the
|
||||||
|
* new one.
|
||||||
|
*/
|
||||||
|
if (S->ExportSize == ADDR_SIZE_DEFAULT) {
|
||||||
|
S->ExportSize = AddrSize;
|
||||||
|
}
|
||||||
|
if (AddrSize != S->ExportSize) {
|
||||||
|
Error ("Address size mismatch for symbol `%s'", GetSymName (S));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the symbol is already defined, export it. Otherwise mark it as
|
||||||
|
* global.
|
||||||
|
*/
|
||||||
|
if (S->Flags & SF_DEFINED) {
|
||||||
|
/* The symbol is defined, export it */
|
||||||
|
S->ExportSize = AddrSize;
|
||||||
|
if (S->ExportSize == ADDR_SIZE_DEFAULT) {
|
||||||
|
/* No export size given, use the real size of the symbol */
|
||||||
|
S->ExportSize = S->AddrSize;
|
||||||
|
} else if (S->AddrSize > S->ExportSize) {
|
||||||
|
Warning (1, "Symbol `%s' is %s but exported as %s",
|
||||||
|
GetSymName (S), AddrSizeToStr (S->AddrSize),
|
||||||
|
AddrSizeToStr (S->ExportSize));
|
||||||
|
}
|
||||||
|
S->Flags |= (SF_EXPORT | Flags);
|
||||||
|
S->ExportSize = AddrSize;
|
||||||
|
} else {
|
||||||
|
S->Flags |= (SF_GLOBAL | Flags);
|
||||||
|
S->AddrSize = AddrSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
|
||||||
|
/* Mark the given symbol as a module constructor/destructor. This will also
|
||||||
|
* mark the symbol as an export. Initializers may never be zero page symbols.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Check the parameters */
|
||||||
|
#if (CD_TYPE_MIN != 0)
|
||||||
|
CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
|
||||||
|
#else
|
||||||
|
CHECK (Type <= CD_TYPE_MAX);
|
||||||
|
#endif
|
||||||
|
CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
|
||||||
|
|
||||||
|
/* Don't accept local symbols */
|
||||||
|
if (IsLocalNameId (S->Name)) {
|
||||||
|
Error ("Illegal use of a local symbol");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for errors */
|
||||||
|
if (S->Flags & SF_IMPORT) {
|
||||||
|
/* The symbol is already marked as imported external symbol */
|
||||||
|
Error ("Symbol `%s' is already an import", 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
|
||||||
* declaration, silently remove the global flag.
|
* declaration, silently remove the global flag.
|
||||||
@@ -276,63 +411,23 @@ void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags)
|
|||||||
if (S->ExportSize == ADDR_SIZE_DEFAULT) {
|
if (S->ExportSize == ADDR_SIZE_DEFAULT) {
|
||||||
/* Use the real size of the symbol */
|
/* Use the real size of the symbol */
|
||||||
S->ExportSize = S->AddrSize;
|
S->ExportSize = S->AddrSize;
|
||||||
} else if (S->AddrSize > S->ExportSize) {
|
} else if (S->AddrSize != S->ExportSize) {
|
||||||
Warning (1, "Address size mismatch for symbol `%s'", GetSymName (S));
|
Error ("Address size mismatch for symbol `%s'", GetSymName (S));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the symbol was already declared as a condes, check if the new
|
||||||
|
* priority value is the same as the old one.
|
||||||
|
*/
|
||||||
|
if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
|
||||||
|
if (S->ConDesPrio[Type] != Prio) {
|
||||||
|
Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
S->ConDesPrio[Type] = Prio;
|
||||||
|
|
||||||
/* Set the symbol data */
|
/* Set the symbol data */
|
||||||
S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
|
S->Flags |= (SF_EXPORT | SF_REFERENCED);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SymGlobal (SymEntry* S, unsigned AddrSize, unsigned Flags)
|
|
||||||
/* Mark the given symbol as a global symbol, that is, as a symbol that is
|
|
||||||
* either imported or exported.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
/* Don't accept local symbols */
|
|
||||||
if (IsLocalNameId (S->Name)) {
|
|
||||||
Error ("Illegal use of a local symbol");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map a default address size to a real value */
|
|
||||||
if (AddrSize == ADDR_SIZE_DEFAULT) {
|
|
||||||
AddrSize = SymAddrSize (S);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the symbol is already marked as import or export, check the
|
|
||||||
* size of the definition, then bail out.
|
|
||||||
*/
|
|
||||||
if (S->Flags & SF_IMPORT) {
|
|
||||||
if (AddrSize != S->AddrSize) {
|
|
||||||
Error ("Address size mismatch for symbol `%s'", GetSymName (S));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (S->Flags & SF_EXPORT) {
|
|
||||||
if (AddrSize != S->ExportSize) {
|
|
||||||
Error ("Address size mismatch for symbol `%s'", GetSymName (S));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the symbol is already defined, export it. Otherwise mark it as
|
|
||||||
* global.
|
|
||||||
*/
|
|
||||||
if (S->Flags & SF_DEFINED) {
|
|
||||||
/* The symbol is defined, export it */
|
|
||||||
if (S->ExportSize != AddrSize) {
|
|
||||||
Error ("Address size mismatch for symbol `%s'", GetSymName (S));
|
|
||||||
}
|
|
||||||
S->Flags |= (SF_EXPORT | Flags);
|
|
||||||
S->ExportSize = AddrSize;
|
|
||||||
} else {
|
|
||||||
S->Flags |= (SF_GLOBAL | Flags);
|
|
||||||
S->AddrSize = AddrSize;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -136,23 +136,28 @@ INLINE void SymDelExprRef (SymEntry* Sym, struct ExprNode* Expr)
|
|||||||
#define SymDelExprRef(Sym,Expr) CollDeleteItem (&(Sym)->ExprRefs, Expr)
|
#define SymDelExprRef(Sym,Expr) CollDeleteItem (&(Sym)->ExprRefs, Expr)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void SymDef (SymEntry* Sym, ExprNode* Expr, unsigned AddrSize, unsigned Flags);
|
void SymDef (SymEntry* Sym, ExprNode* Expr, unsigned char AddrSize, unsigned Flags);
|
||||||
/* Mark a symbol as defined */
|
/* Mark a symbol as defined */
|
||||||
|
|
||||||
void SymRef (SymEntry* Sym);
|
void SymRef (SymEntry* Sym);
|
||||||
/* Mark the given symbol as referenced */
|
/* Mark the given symbol as referenced */
|
||||||
|
|
||||||
void SymImport (SymEntry* Sym, unsigned AddrSize, unsigned Flags);
|
void SymImport (SymEntry* Sym, unsigned char AddrSize, unsigned Flags);
|
||||||
/* Mark the given symbol as an imported symbol */
|
/* Mark the given symbol as an imported symbol */
|
||||||
|
|
||||||
void SymExport (SymEntry* Sym, unsigned AddrSize, unsigned Flags);
|
void SymExport (SymEntry* Sym, unsigned char AddrSize, unsigned Flags);
|
||||||
/* Mark the given symbol as an exported symbol */
|
/* Mark the given symbol as an exported symbol */
|
||||||
|
|
||||||
void SymGlobal (SymEntry* S, unsigned AddrSize, unsigned Flags);
|
void SymGlobal (SymEntry* Sym, unsigned char AddrSize, unsigned Flags);
|
||||||
/* Mark the given symbol as a global symbol, that is, as a symbol that is
|
/* Mark the given symbol as a global symbol, that is, as a symbol that is
|
||||||
* either imported or exported.
|
* either imported or exported.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void SymConDes (SymEntry* Sym, unsigned char AddrSize, unsigned Type, unsigned Prio);
|
||||||
|
/* Mark the given symbol as a module constructor/destructor. This will also
|
||||||
|
* mark the symbol as an export. Initializers may never be zero page symbols.
|
||||||
|
*/
|
||||||
|
|
||||||
int SymIsDef (const SymEntry* Sym);
|
int SymIsDef (const SymEntry* Sym);
|
||||||
/* Return true if the given symbol is already defined */
|
/* Return true if the given symbol is already defined */
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name)
|
|||||||
S->Childs = 0;
|
S->Childs = 0;
|
||||||
S->Flags = ST_NONE;
|
S->Flags = ST_NONE;
|
||||||
S->AddrSize = ADDR_SIZE_DEFAULT;
|
S->AddrSize = ADDR_SIZE_DEFAULT;
|
||||||
S->Type = 0;
|
S->Type = ST_UNDEF;
|
||||||
S->Level = Level;
|
S->Level = Level;
|
||||||
S->TableSlots = Slots;
|
S->TableSlots = Slots;
|
||||||
S->TableEntries = 0;
|
S->TableEntries = 0;
|
||||||
@@ -203,7 +203,7 @@ static int SearchSymTree (SymEntry* T, const char* Name, SymEntry** E)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SymEnterLevel (const char* ScopeName, unsigned AddrSize)
|
void SymEnterLevel (const char* ScopeName, unsigned char Type, unsigned char AddrSize)
|
||||||
/* Enter a new lexical level */
|
/* Enter a new lexical level */
|
||||||
{
|
{
|
||||||
/* Map a default address size to something real */
|
/* Map a default address size to something real */
|
||||||
@@ -216,18 +216,23 @@ void SymEnterLevel (const char* ScopeName, unsigned AddrSize)
|
|||||||
* new one if it doesn't exist. If this is the root scope, just create it.
|
* new one if it doesn't exist. If this is the root scope, just create it.
|
||||||
*/
|
*/
|
||||||
if (CurrentScope) {
|
if (CurrentScope) {
|
||||||
|
|
||||||
|
/* Search for the scope, create a new one */
|
||||||
CurrentScope = SymFindScope (CurrentScope, ScopeName, SYM_ALLOC_NEW);
|
CurrentScope = SymFindScope (CurrentScope, ScopeName, SYM_ALLOC_NEW);
|
||||||
|
|
||||||
/* Check if the scope has been defined before */
|
/* Check if the scope has been defined before */
|
||||||
if (CurrentScope->Flags & ST_DEFINED) {
|
if (CurrentScope->Flags & ST_DEFINED) {
|
||||||
Error ("Duplicate scope `%s'", ScopeName);
|
Error ("Duplicate scope `%s'", ScopeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
CurrentScope = RootScope = NewSymTable (0, ScopeName);
|
CurrentScope = RootScope = NewSymTable (0, ScopeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark the scope as defined */
|
/* Mark the scope as defined and set type and address size */
|
||||||
CurrentScope->Flags |= ST_DEFINED;
|
CurrentScope->Flags |= ST_DEFINED;
|
||||||
|
CurrentScope->AddrSize = AddrSize;
|
||||||
|
CurrentScope->Type = Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -364,7 +369,7 @@ static SymEntry* SymFindAny (SymTable* Scope, const char* Name)
|
|||||||
do {
|
do {
|
||||||
/* Search in the current table */
|
/* Search in the current table */
|
||||||
Sym = SymFind (Scope, Name, SYM_FIND_EXISTING);
|
Sym = SymFind (Scope, Name, SYM_FIND_EXISTING);
|
||||||
if (Sym) {
|
if (Sym) {
|
||||||
/* Found, return it */
|
/* Found, return it */
|
||||||
return Sym;
|
return Sym;
|
||||||
} else {
|
} else {
|
||||||
@@ -379,61 +384,6 @@ static SymEntry* SymFindAny (SymTable* Scope, const char* Name)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SymConDes (const char* Name, unsigned Type, unsigned Prio)
|
|
||||||
/* Mark the given symbol as a module constructor/destructor. This will also
|
|
||||||
* mark the symbol as an export. Initializers may never be zero page symbols.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
SymEntry* S;
|
|
||||||
|
|
||||||
/* Check the parameters */
|
|
||||||
#if (CD_TYPE_MIN != 0)
|
|
||||||
CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
|
|
||||||
#else
|
|
||||||
CHECK (Type <= CD_TYPE_MAX);
|
|
||||||
#endif
|
|
||||||
CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
|
|
||||||
|
|
||||||
/* Don't accept local symbols */
|
|
||||||
if (IsLocalName (Name)) {
|
|
||||||
Error ("Illegal use of a local symbol");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do we have such a symbol? */
|
|
||||||
S = SymFind (CurrentScope, Name, SYM_ALLOC_NEW);
|
|
||||||
if (S->Flags & SF_IMPORT) {
|
|
||||||
/* The symbol is already marked as imported external symbol */
|
|
||||||
Error ("Symbol `%s' is already an import", Name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the symbol is marked as global, silently remove the global flag */
|
|
||||||
if (S->Flags & SF_GLOBAL) {
|
|
||||||
S->Flags &= ~SF_GLOBAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the symbol was not already defined as ZP symbol */
|
|
||||||
if (S->AddrSize == ADDR_SIZE_ZP) {
|
|
||||||
Error ("Redeclaration mismatch for symbol `%s'", Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the symbol was already declared as a condes, check if the new
|
|
||||||
* priority value is the same as the old one.
|
|
||||||
*/
|
|
||||||
if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
|
|
||||||
if (S->ConDesPrio[Type] != Prio) {
|
|
||||||
Error ("Redeclaration mismatch for symbol `%s'", Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
S->ConDesPrio[Type] = Prio;
|
|
||||||
|
|
||||||
/* Set the symbol data */
|
|
||||||
S->Flags |= SF_EXPORT | SF_REFERENCED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int SymIsZP (SymEntry* S)
|
int SymIsZP (SymEntry* S)
|
||||||
/* Return true if the symbol is explicitly marked as zeropage symbol */
|
/* Return true if the symbol is explicitly marked as zeropage symbol */
|
||||||
{
|
{
|
||||||
@@ -464,6 +414,15 @@ int SymIsZP (SymEntry* S)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned char GetCurrentSymTabType ()
|
||||||
|
/* Return the type of the current symbol table */
|
||||||
|
{
|
||||||
|
CHECK (CurrentScope != 0);
|
||||||
|
return CurrentScope->Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void SymCheckUndefined (SymEntry* S)
|
static void SymCheckUndefined (SymEntry* S)
|
||||||
/* Handle an undefined symbol */
|
/* Handle an undefined symbol */
|
||||||
{
|
{
|
||||||
@@ -821,4 +780,4 @@ void WriteDbgSyms (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,13 @@
|
|||||||
#define ST_NONE 0x00 /* No flags */
|
#define ST_NONE 0x00 /* No flags */
|
||||||
#define ST_DEFINED 0x01 /* Scope has been defined */
|
#define ST_DEFINED 0x01 /* Scope has been defined */
|
||||||
|
|
||||||
|
/* Symbol table types */
|
||||||
|
#define ST_GLOBAL 0x00 /* Root level */
|
||||||
|
#define ST_PROC 0x01 /* .PROC */
|
||||||
|
#define ST_SCOPE 0x02 /* .SCOPE */
|
||||||
|
#define ST_STUCT 0x03 /* .STRUCT */
|
||||||
|
#define ST_UNDEF 0xFF
|
||||||
|
|
||||||
/* A symbol table */
|
/* A symbol table */
|
||||||
typedef struct SymTable SymTable;
|
typedef struct SymTable SymTable;
|
||||||
struct SymTable {
|
struct SymTable {
|
||||||
@@ -87,7 +94,7 @@ SymTable* RootScope; /* Root symbol table */
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SymEnterLevel (const char* ScopeName, unsigned AddrSize);
|
void SymEnterLevel (const char* ScopeName, unsigned char Type, unsigned char AddrSize);
|
||||||
/* Enter a new lexical level */
|
/* Enter a new lexical level */
|
||||||
|
|
||||||
void SymLeaveLevel (void);
|
void SymLeaveLevel (void);
|
||||||
@@ -102,14 +109,12 @@ SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew);
|
|||||||
* new entry created, or - in case AllocNew is zero - return 0.
|
* new entry created, or - in case AllocNew is zero - return 0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void SymConDes (const char* Name, unsigned Type, unsigned Prio);
|
|
||||||
/* Mark the given symbol as a module constructor/destructor. This will also
|
|
||||||
* mark the symbol as an export. Initializers may never be zero page symbols.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int SymIsZP (SymEntry* Sym);
|
int SymIsZP (SymEntry* Sym);
|
||||||
/* Return true if the symbol is explicitly marked as zeropage symbol */
|
/* Return true if the symbol is explicitly marked as zeropage symbol */
|
||||||
|
|
||||||
|
unsigned char GetCurrentSymTabType ();
|
||||||
|
/* Return the type of the current symbol table */
|
||||||
|
|
||||||
void SymCheck (void);
|
void SymCheck (void);
|
||||||
/* Run through all symbols and check for anomalies and errors */
|
/* Run through all symbols and check for anomalies and errors */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user