From: cuz Date: Thu, 13 Nov 2003 00:21:31 +0000 (+0000) Subject: More work on expressions and address sizes X-Git-Tag: V2.12.0~1142 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=ba68b5f87af2e2fea641462f7c4d0308a4140e97;p=cc65 More work on expressions and address sizes git-svn-id: svn://svn.cc65.org/cc65/trunk@2658 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- diff --git a/src/ca65/error.h b/src/ca65/error.h index 5eddd8949..2d7e2048b 100644 --- a/src/ca65/error.h +++ b/src/ca65/error.h @@ -7,7 +7,7 @@ /* */ /* */ /* (C) 1998-2003 Ullrich von Bassewitz */ -/* Römerstrasse 52 */ +/* Römerstraße 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ @@ -51,7 +51,7 @@ /* Warning levels */ -extern unsigned WarnLevel; +extern unsigned WarnLevel; /* Statistics */ 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))); /* Print an error message */ - + void PError (const FilePos* Pos, const char* Format, ...) attribute ((format (printf, 2, 3))); /* Print an error message giving an explicit file and position. */ diff --git a/src/ca65/expr.c b/src/ca65/expr.c index 68baabb3f..9d4426191 100644 --- a/src/ca65/expr.c +++ b/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 */ /*****************************************************************************/ @@ -559,8 +570,13 @@ static ExprNode* Factor (void) } else { /* Mark the symbol as referenced */ SymRef (S); - /* Create symbol node */ - N = GenSymExpr (S); + /* Remove the symbol if possible */ + if (SymHasExpr (S)) { + N = CloneExpr (GetSymExpr (S)); + } else { + /* Create symbol node */ + N = GenSymExpr (S); + } } break; @@ -787,7 +803,7 @@ static ExprNode* Term (void) /* Generate an expression tree */ unsigned char Op; - switch (T) { + switch (T) { case TOK_MUL: Op = EXPR_MUL; break; case TOK_DIV: Op = EXPR_DIV; break; case TOK_MOD: Op = EXPR_MOD; break; @@ -819,22 +835,50 @@ static ExprNode* SimpleExpr (void) /* Handle additive operations */ while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) { - /* Create the new node */ - ExprNode* Left = Root; - switch (Tok) { - 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; + long LVal, RVal, Val; + ExprNode* Left; + ExprNode* Right; - /* Skip the operator token */ - NextTok (); + /* Remember the token and skip it */ + enum Token T = Tok; + NextTok (); - /* Parse the right hand side */ - Root->Right = Term (); + /* Move root to left side and read the right side */ + 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 */ @@ -853,25 +897,56 @@ static ExprNode* BoolExpr (void) while (Tok == TOK_EQ || Tok == TOK_NE || Tok == TOK_LT || Tok == TOK_GT || Tok == TOK_LE || Tok == TOK_GE) { - /* Create the new node */ - ExprNode* Left = Root; - switch (Tok) { - 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; + long LVal, RVal, Val; + ExprNode* Left; + ExprNode* Right; - /* Skip the operator token */ - NextTok (); + /* Remember the token and skip it */ + enum Token T = Tok; + NextTok (); + + /* Move root to left side and read the right side */ + Left = Root; + Right = SimpleExpr (); + + /* If both expressions are constant, we can evaluate the term */ + if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) { - /* Parse the right hand side */ - Root->Right = SimpleExpr (); + 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 */ @@ -889,21 +964,48 @@ static ExprNode* Expr2 (void) /* Handle booleans */ while (Tok == TOK_BOOLAND || Tok == TOK_BOOLXOR) { - /* Create the new node */ - ExprNode* Left = Root; - switch (Tok) { - case TOK_BOOLAND: Root = NewExprNode (EXPR_BOOLAND); break; - case TOK_BOOLXOR: Root = NewExprNode (EXPR_BOOLXOR); break; - default: Internal ("Invalid token"); - } - Root->Left = Left; + long LVal, RVal, Val; + ExprNode* Left; + ExprNode* Right; - /* Skip the operator token */ - NextTok (); + /* Remember the token and skip it */ + enum Token T = Tok; + NextTok (); + + /* Move root to left side and read the right side */ + 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); - /* Parse the right hand side */ - Root->Right = BoolExpr (); + } 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 */ @@ -921,20 +1023,46 @@ static ExprNode* Expr1 (void) /* Handle booleans */ while (Tok == TOK_BOOLOR) { - /* Create the new node */ - ExprNode* Left = Root; - switch (Tok) { - case TOK_BOOLOR: Root = NewExprNode (EXPR_BOOLOR); break; - default: Internal ("Invalid token"); - } - Root->Left = Left; + long LVal, RVal, Val; + ExprNode* Left; + ExprNode* Right; - /* Skip the operator token */ - NextTok (); + /* Remember the token and skip it */ + enum Token T = Tok; + NextTok (); + + /* Move root to left side and read the right side */ + 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"); + } - /* Parse the right hand side */ - Root->Right = Expr2 (); + /* 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 */ @@ -951,14 +1079,23 @@ static ExprNode* Expr0 (void) /* Handle booleans */ if (Tok == TOK_BOOLNOT) { - /* Create the new node */ - Root = NewExprNode (EXPR_BOOLNOT); + long Val; + ExprNode* Left; /* Skip the operator token */ NextTok (); - /* Parse the left hand side, allow more BNOTs */ - Root->Left = Expr0 (); + /* Read the argument */ + 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 { @@ -973,9 +1110,8 @@ static ExprNode* Expr0 (void) -static void StudyExpr (ExprNode* Expr, ExprDesc* D, int Sign); 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); if (ExprDescIsConst (D)) { @@ -1542,23 +1678,52 @@ ExprNode* GenBranchExpr (unsigned Offs) { ExprNode* N; 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 { - N = GenLiteralExpr (GetPC () + Offs); - } - /* Create the root node */ - Root = NewExprNode (EXPR_MINUS); - Root->Left = Expression (); - Root->Right = N; + /* 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 ()); + } + } /* Return the result */ - return SimplifyExpr (Root); + return Root; } diff --git a/src/ca65/main.c b/src/ca65/main.c index 413492e32..6223bfe92 100644 --- a/src/ca65/main.c +++ b/src/ca65/main.c @@ -524,7 +524,7 @@ int main (int argc, char* argv []) /* Enter the base lexical level. We must do that here, since we may * define symbols using -D. */ - SymEnterLevel ("", ADDR_SIZE_DEFAULT); + SymEnterLevel ("", ST_GLOBAL, ADDR_SIZE_DEFAULT); /* Check the parameters */ I = 1; diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c index 42674285a..4d6d945cb 100644 --- a/src/ca65/pseudo.c +++ b/src/ca65/pseudo.c @@ -7,7 +7,7 @@ /* */ /* */ /* (C) 1998-2003 Ullrich von Bassewitz */ -/* Römerstrasse 52 */ +/* Römerstraße 52 */ /* D-70794 Filderstadt */ /* 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. * Otherwise return ADDR_SIZE_DEFAULT. */ @@ -161,12 +161,12 @@ static void SetBoolOption (unsigned char* Flag) -static void ExportImport (void (*Func) (SymEntry*, unsigned, unsigned), - unsigned DefAddrSize, unsigned Flags) +static void ExportImport (void (*Func) (SymEntry*, unsigned char, unsigned), + unsigned char DefAddrSize, unsigned Flags) /* Export or import symbols */ { SymEntry* Sym; - unsigned AddrSize; + unsigned char AddrSize; while (1) { @@ -227,6 +227,10 @@ static void ConDes (const char* Name, unsigned Type) { long Prio; + + /* Find the symbol table entry, allocate a new one if necessary */ + SymEntry* Sym = SymFind (CurrentScope, Name, SYM_ALLOC_NEW); + /* Optional constructor priority */ if (Tok == TOK_COMMA) { /* Priority value follows */ @@ -243,7 +247,7 @@ static void ConDes (const char* Name, unsigned Type) } /* 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) /* Leave a lexical level */ { - if (CurrentScope != RootScope) { - SymLeaveLevel (); - } else { + if (CurrentScope == RootScope || GetCurrentSymTabType () != ST_PROC) { /* 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) /* Leave a lexical level */ { - if (CurrentScope != RootScope) { - SymLeaveLevel (); - } else { + if (CurrentScope == RootScope || GetCurrentSymTabType () != ST_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) /* Start a new lexical scope */ { - if (Tok == TOK_IDENT) { + char Name[sizeof(SVal)]; + unsigned char AddrSize; - unsigned AddrSize; + if (Tok == TOK_IDENT) { /* The new scope has a name. Remember it. */ - char Name[sizeof(SVal)]; strcpy (Name, SVal); /* Search for the symbol, generate a new one if needed */ @@ -1314,17 +1318,17 @@ static void DoProc (void) /* Mark the symbol as defined */ SymDef (Sym, GenCurrentPC (), AddrSize, SF_LABEL); - /* Enter a new scope with the given name */ - SymEnterLevel (Name, AddrSize); - } else { /* 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"); + 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 */ { char Name[sizeof (SVal)]; + unsigned char AddrSize; - if (Tok == TOK_IDENT) { - unsigned AddrSize; + if (Tok == TOK_IDENT) { - /* The new scope has a name. Remember and skip it. */ + /* The new scope has a name. Remember and skip it. */ strcpy (Name, SVal); NextTok (); - /* Read an optional address size specifier */ - AddrSize = OptionalAddrSize (); - - /* Enter a new scope with the given name */ - SymEnterLevel (Name, AddrSize); - } else { /* 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, DoRes }, { ccNone, DoInvalid }, /* .RIGHT */ - { ccNone, DoROData }, + { ccNone, DoROData }, { ccNone, DoScope }, { ccNone, DoSegment }, { ccNone, DoSetCPU }, diff --git a/src/ca65/scanner.c b/src/ca65/scanner.c index b1a3b522d..594584da5 100644 --- a/src/ca65/scanner.c +++ b/src/ca65/scanner.c @@ -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. * If so, return the corresponding address size constant, otherwise output an * error message and return ADDR_SIZE_DEFAULT. diff --git a/src/ca65/scanner.h b/src/ca65/scanner.h index 38a2b2d95..ed5d2614d 100644 --- a/src/ca65/scanner.h +++ b/src/ca65/scanner.h @@ -7,7 +7,7 @@ /* */ /* */ /* (C) 1998-2003 Ullrich von Bassewitz */ -/* Römerstrasse 52 */ +/* Römerstraße 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ @@ -294,7 +294,7 @@ int GetSubKey (const char** Keys, unsigned Count); * 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. * If so, return the corresponding address size constant, otherwise output an * error message and return ADDR_SIZE_DEFAULT. diff --git a/src/ca65/symentry.c b/src/ca65/symentry.c index 35e60b5ef..f716e3288 100644 --- a/src/ca65/symentry.c +++ b/src/ca65/symentry.c @@ -44,6 +44,7 @@ #include "expr.h" #include "global.h" #include "scanner.h" +#include "segment.h" #include "spool.h" #include "symentry.h" #include "symtab.h" @@ -94,8 +95,8 @@ static unsigned SymAddrSize (const SymEntry* S) return ADDR_SIZE_ABS; } - /* Return the address size of the enclosing scope */ - return S->SymTab->AddrSize; + /* Return the address size of the segment */ + 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 */ { if (S->Flags & SF_IMPORT) { @@ -160,7 +161,7 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags) } /* Set the symbol value */ - S->V.Expr = Expr; + S->V.Expr = Expr; /* If the symbol is marked as global, export it */ 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 */ S->ExportSize = S->AddrSize; } 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 */ { /* 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, * then do silently remove the global flag */ - if (S->Flags & (SF_IMPORT | SF_GLOBAL)) { - if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED) || - AddrSize != S->AddrSize) { + if (S->Flags & SF_IMPORT) { + if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) { 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; } @@ -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 */ { /* Don't accept local symbols */ @@ -257,15 +267,25 @@ void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags) 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 - * declaration, silently remove the global flag. + /* 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 | SF_GLOBAL)) { - if (S->ExportSize != AddrSize) { + 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->Flags &= ~SF_GLOBAL; } S->ExportSize = AddrSize; @@ -274,10 +294,12 @@ void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags) */ if (S->Flags & SF_DEFINED) { if (S->ExportSize == ADDR_SIZE_DEFAULT) { - /* Use the real size of the symbol */ + /* No export size given, use the real size of the symbol */ S->ExportSize = S->AddrSize; } else if (S->AddrSize > S->ExportSize) { - Warning (1, "Address size mismatch for symbol `%s'", GetSymName (S)); + Warning (1, "Symbol `%s' is %s but exported as %s", + GetSymName (S), AddrSizeToStr (S->AddrSize), + AddrSizeToStr (S->ExportSize)); } } @@ -287,7 +309,7 @@ void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags) -void SymGlobal (SymEntry* S, unsigned AddrSize, unsigned 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. */ @@ -298,21 +320,22 @@ void SymGlobal (SymEntry* S, unsigned AddrSize, unsigned Flags) 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) { + 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)); } @@ -324,8 +347,14 @@ void SymGlobal (SymEntry* S, unsigned AddrSize, unsigned Flags) */ 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->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; @@ -337,6 +366,72 @@ void SymGlobal (SymEntry* S, unsigned AddrSize, unsigned Flags) +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 + * this was done specifiying the same address size. In case of a global + * declaration, silently remove the global flag. + */ + if (S->Flags & (SF_EXPORT | SF_GLOBAL)) { + if (S->ExportSize != AddrSize) { + Error ("Address size mismatch for symbol `%s'", GetSymName (S)); + } + S->Flags &= ~SF_GLOBAL; + } + 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) { + /* Use the real size of the symbol */ + S->ExportSize = S->AddrSize; + } else if (S->AddrSize != S->ExportSize) { + 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 */ + S->Flags |= (SF_EXPORT | SF_REFERENCED); +} + + + int SymIsDef (const SymEntry* S) /* Return true if the given symbol is already defined */ { diff --git a/src/ca65/symentry.h b/src/ca65/symentry.h index 940278bab..46dba46fa 100644 --- a/src/ca65/symentry.h +++ b/src/ca65/symentry.h @@ -136,23 +136,28 @@ INLINE void SymDelExprRef (SymEntry* Sym, struct ExprNode* Expr) #define SymDelExprRef(Sym,Expr) CollDeleteItem (&(Sym)->ExprRefs, Expr) #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 */ void SymRef (SymEntry* Sym); /* 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 */ -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 */ -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 * 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); /* Return true if the given symbol is already defined */ diff --git a/src/ca65/symtab.c b/src/ca65/symtab.c index 6af89a97e..d21d0e1eb 100644 --- a/src/ca65/symtab.c +++ b/src/ca65/symtab.c @@ -112,7 +112,7 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name) S->Childs = 0; S->Flags = ST_NONE; S->AddrSize = ADDR_SIZE_DEFAULT; - S->Type = 0; + S->Type = ST_UNDEF; S->Level = Level; S->TableSlots = Slots; 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 */ { /* 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. */ if (CurrentScope) { + + /* Search for the scope, create a new one */ CurrentScope = SymFindScope (CurrentScope, ScopeName, SYM_ALLOC_NEW); /* Check if the scope has been defined before */ if (CurrentScope->Flags & ST_DEFINED) { Error ("Duplicate scope `%s'", ScopeName); } + } else { CurrentScope = RootScope = NewSymTable (0, ScopeName); } - /* Mark the scope as defined */ - CurrentScope->Flags |= ST_DEFINED; + /* Mark the scope as defined and set type and address size */ + CurrentScope->Flags |= ST_DEFINED; + CurrentScope->AddrSize = AddrSize; + CurrentScope->Type = Type; } @@ -364,7 +369,7 @@ static SymEntry* SymFindAny (SymTable* Scope, const char* Name) do { /* Search in the current table */ Sym = SymFind (Scope, Name, SYM_FIND_EXISTING); - if (Sym) { + if (Sym) { /* Found, return it */ return Sym; } 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) /* 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) /* Handle an undefined symbol */ { @@ -821,4 +780,4 @@ void WriteDbgSyms (void) - + diff --git a/src/ca65/symtab.h b/src/ca65/symtab.h index fc28def44..86d0aa4ca 100644 --- a/src/ca65/symtab.h +++ b/src/ca65/symtab.h @@ -58,6 +58,13 @@ #define ST_NONE 0x00 /* No flags */ #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 */ typedef struct SymTable 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 */ 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. */ -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); /* 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); /* Run through all symbols and check for anomalies and errors */