void Warning (unsigned Level, const char* Format, ...) /* Print warning message. */ { if (Level <= WarnLevel) { va_list ap; Collection LineInfos = STATIC_COLLECTION_INITIALIZER; /* Get line infos for the current position */ GetFullLineInfo (&LineInfos); /* Output the message */ va_start (ap, Format); WarningMsg (&LineInfos, Format, ap); va_end (ap); /* Free the line info list */ ReleaseFullLineInfo (&LineInfos); DoneCollection (&LineInfos); } }
void ErrorSkip (const char* Format, ...) /* Print an error message and skip the rest of the line */ { va_list ap; Collection LineInfos = STATIC_COLLECTION_INITIALIZER; /* Get line infos for the current position */ GetFullLineInfo (&LineInfos); /* Output the message */ va_start (ap, Format); ErrorMsg (&LineInfos, Format, ap); va_end (ap); /* Free the line info list */ ReleaseFullLineInfo (&LineInfos); DoneCollection (&LineInfos); /* Skip tokens until we reach the end of the line */ SkipUntilSep (); }
void ULabDef (void) /* Define an unnamed label at the current PC */ { if (ULabDefCount < CollCount (&ULabList)) { /* We did already have a forward reference to this label, so has * already been generated, but doesn't have a value. Use the current * PC for the label value. */ ULabel* L = CollAtUnchecked (&ULabList, ULabDefCount); CHECK (L->Val == 0); L->Val = GenCurrentPC (); ReleaseFullLineInfo (&L->LineInfos); GetFullLineInfo (&L->LineInfos); } else { /* There is no such label, create it */ NewULabel (GenCurrentPC ()); } /* We have one more defined label */ ++ULabDefCount; }
void ULabDone (void) /* Run through all unnamed labels, check for anomalies and errors and do * necessary cleanups. */ { /* Check if there are undefined labels */ unsigned I = ULabDefCount; while (I < CollCount (&ULabList)) { ULabel* L = CollAtUnchecked (&ULabList, I); LIError (&L->LineInfos, "Undefined label"); ++I; } /* Walk over all labels and emit a warning if any unreferenced ones * are found. Remove line infos because they're no longer needed. */ for (I = 0; I < CollCount (&ULabList); ++I) { ULabel* L = CollAtUnchecked (&ULabList, I); if (L->Ref == 0) { LIWarning (&L->LineInfos, 1, "No reference to unnamed label"); } ReleaseFullLineInfo (&L->LineInfos); } }
void DoConditionals (void) /* Catch all for conditional directives */ { IfDesc* D; do { switch (CurTok.Tok) { case TOK_ELSE: D = GetCurrentIf (); /* Allow an .ELSE */ ElseClause (D, ".ELSE"); /* Remember the data for the .ELSE */ if (D) { ReleaseFullLineInfo (&D->LineInfos); GetFullLineInfo (&D->LineInfos); D->Name = ".ELSE"; } /* Calculate the new overall condition */ CalcOverallIfCond (); /* Skip .ELSE */ NextTok (); ExpectSep (); break; case TOK_ELSEIF: D = GetCurrentIf (); /* Handle as if there was an .ELSE first */ ElseClause (D, ".ELSEIF"); /* Calculate the new overall if condition */ CalcOverallIfCond (); /* Allocate and prepare a new descriptor */ D = AllocIf (".ELSEIF", 0); NextTok (); /* Ignore the new condition if we are inside a false .ELSE ** branch. This way we won't get any errors about undefined ** symbols or similar... */ if (IfCond) { SetIfCond (D, ConstExpression ()); ExpectSep (); } /* Get the new overall condition */ CalcOverallIfCond (); break; case TOK_ENDIF: /* We're done with this .IF.. - remove the descriptor(s) */ FreeIf (); /* Be sure not to read the next token until the .IF stack ** has been cleanup up, since we may be at end of file. */ NextTok (); ExpectSep (); /* Get the new overall condition */ CalcOverallIfCond (); break; case TOK_IF: D = AllocIf (".IF", 1); NextTok (); if (IfCond) { SetIfCond (D, ConstExpression ()); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFBLANK: D = AllocIf (".IFBLANK", 1); NextTok (); if (IfCond) { if (TokIsSep (CurTok.Tok)) { SetIfCond (D, 1); } else { SetIfCond (D, 0); SkipUntilSep (); } } CalcOverallIfCond (); break; case TOK_IFCONST: D = AllocIf (".IFCONST", 1); NextTok (); if (IfCond) { ExprNode* Expr = Expression(); SetIfCond (D, IsConstExpr (Expr, 0)); FreeExpr (Expr); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFDEF: D = AllocIf (".IFDEF", 1); NextTok (); if (IfCond) { SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING); SetIfCond (D, Sym != 0 && SymIsDef (Sym)); } CalcOverallIfCond (); break; case TOK_IFNBLANK: D = AllocIf (".IFNBLANK", 1); NextTok (); if (IfCond) { if (TokIsSep (CurTok.Tok)) { SetIfCond (D, 0); } else { SetIfCond (D, 1); SkipUntilSep (); } } CalcOverallIfCond (); break; case TOK_IFNCONST: D = AllocIf (".IFNCONST", 1); NextTok (); if (IfCond) { ExprNode* Expr = Expression(); SetIfCond (D, !IsConstExpr (Expr, 0)); FreeExpr (Expr); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFNDEF: D = AllocIf (".IFNDEF", 1); NextTok (); if (IfCond) { SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING); SetIfCond (D, Sym == 0 || !SymIsDef (Sym)); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFNREF: D = AllocIf (".IFNREF", 1); NextTok (); if (IfCond) { SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING); SetIfCond (D, Sym == 0 || !SymIsRef (Sym)); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFP02: D = AllocIf (".IFP02", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_6502); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFP4510: D = AllocIf (".IFP4510", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_4510); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFP816: D = AllocIf (".IFP816", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_65816); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFPC02: D = AllocIf (".IFPC02", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_65C02); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFPSC02: D = AllocIf (".IFPSC02", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_65SC02); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFREF: D = AllocIf (".IFREF", 1); NextTok (); if (IfCond) { SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING); SetIfCond (D, Sym != 0 && SymIsRef (Sym)); ExpectSep (); } CalcOverallIfCond (); break; default: /* Skip tokens */ NextTok (); } } while (IfCond == 0 && CurTok.Tok != TOK_EOF); }
void NextRawTok (void) /* Read the next raw token from the input stream */ { Macro* M; /* If we've a forced end of assembly, don't read further */ if (ForcedEnd) { CurTok.Tok = TOK_EOF; return; } Restart: /* Check if we have tokens from another input source */ if (InputFromStack ()) { if (CurTok.Tok == TOK_IDENT && (M = FindDefine (&CurTok.SVal)) != 0) { /* This is a define style macro - expand it */ MacExpandStart (M); goto Restart; } return; } Again: /* Skip whitespace, remember if we had some */ if ((CurTok.WS = IsBlank (C)) != 0) { do { NextChar (); } while (IsBlank (C)); } /* Mark the file position of the next token */ Source->Func->MarkStart (Source); /* Clear the string attribute */ SB_Clear (&CurTok.SVal); /* Generate line info for the current token */ NewAsmLine (); /* Hex number or PC symbol? */ if (C == '$') { NextChar (); /* Hex digit must follow or DollarIsPC must be enabled */ if (!IsXDigit (C)) { if (DollarIsPC) { CurTok.Tok = TOK_PC; return; } else { Error ("Hexadecimal digit expected"); } } /* Read the number */ CurTok.IVal = 0; while (1) { if (UnderlineInNumbers && C == '_') { while (C == '_') { NextChar (); } if (!IsXDigit (C)) { Error ("Number may not end with underline"); } } if (IsXDigit (C)) { if (CurTok.IVal & 0xF0000000) { Error ("Overflow in hexadecimal number"); CurTok.IVal = 0; } CurTok.IVal = (CurTok.IVal << 4) + DigitVal (C); NextChar (); } else { break; } } /* This is an integer constant */ CurTok.Tok = TOK_INTCON; return; } /* Binary number? */ if (C == '%') { NextChar (); /* 0 or 1 must follow */ if (!IsBDigit (C)) { Error ("Binary digit expected"); } /* Read the number */ CurTok.IVal = 0; while (1) { if (UnderlineInNumbers && C == '_') { while (C == '_') { NextChar (); } if (!IsBDigit (C)) { Error ("Number may not end with underline"); } } if (IsBDigit (C)) { if (CurTok.IVal & 0x80000000) { Error ("Overflow in binary number"); CurTok.IVal = 0; } CurTok.IVal = (CurTok.IVal << 1) + DigitVal (C); NextChar (); } else { break; } } /* This is an integer constant */ CurTok.Tok = TOK_INTCON; return; } /* Number? */ if (IsDigit (C)) { char Buf[16]; unsigned Digits; unsigned Base; unsigned I; long Max; unsigned DVal; /* Ignore leading zeros */ while (C == '0') { NextChar (); } /* Read the number into Buf counting the digits */ Digits = 0; while (1) { if (UnderlineInNumbers && C == '_') { while (C == '_') { NextChar (); } if (!IsXDigit (C)) { Error ("Number may not end with underline"); } } if (IsXDigit (C)) { /* Buf is big enough to allow any decimal and hex number to ** overflow, so ignore excess digits here, they will be detected ** when we convert the value. */ if (Digits < sizeof (Buf)) { Buf[Digits++] = C; } NextChar (); } else { break; } } /* Allow zilog/intel style hex numbers with a 'h' suffix */ if (C == 'h' || C == 'H') { NextChar (); Base = 16; Max = 0xFFFFFFFFUL / 16; } else { Base = 10; Max = 0xFFFFFFFFUL / 10; } /* Convert the number using the given base */ CurTok.IVal = 0; for (I = 0; I < Digits; ++I) { if (CurTok.IVal > Max) { Error ("Number out of range"); CurTok.IVal = 0; break; } DVal = DigitVal (Buf[I]); if (DVal >= Base) { Error ("Invalid digits in number"); CurTok.IVal = 0; break; } CurTok.IVal = (CurTok.IVal * Base) + DVal; } /* This is an integer constant */ CurTok.Tok = TOK_INTCON; return; } /* Control command? */ if (C == '.') { /* Remember and skip the dot */ NextChar (); /* Check if it's just a dot */ if (!IsIdStart (C)) { /* Just a dot */ CurTok.Tok = TOK_DOT; } else { /* Read the remainder of the identifier */ SB_AppendChar (&CurTok.SVal, '.'); ReadIdent (); /* Dot keyword, search for it */ CurTok.Tok = FindDotKeyword (); if (CurTok.Tok == TOK_NONE) { /* Not found */ if (!LeadingDotInIdents) { /* Invalid pseudo instruction */ Error ("'%m%p' is not a recognized control command", &CurTok.SVal); goto Again; } /* An identifier with a dot. Check if it's a define style ** macro. */ if ((M = FindDefine (&CurTok.SVal)) != 0) { /* This is a define style macro - expand it */ MacExpandStart (M); goto Restart; } /* Just an identifier with a dot */ CurTok.Tok = TOK_IDENT; } } return; } /* Indirect op for sweet16 cpu. Must check this before checking for local ** symbols, because these may also use the '@' symbol. */ if (CPU == CPU_SWEET16 && C == '@') { NextChar (); CurTok.Tok = TOK_AT; return; } /* Local symbol? */ if (C == LocalStart) { /* Read the identifier. */ ReadIdent (); /* Start character alone is not enough */ if (SB_GetLen (&CurTok.SVal) == 1) { Error ("Invalid cheap local symbol"); goto Again; } /* A local identifier */ CurTok.Tok = TOK_LOCAL_IDENT; return; } /* Identifier or keyword? */ if (IsIdStart (C)) { /* Read the identifier */ ReadIdent (); /* Check for special names. Bail out if we have identified the type of ** the token. Go on if the token is an identifier. */ switch (SB_GetLen (&CurTok.SVal)) { case 1: switch (toupper (SB_AtUnchecked (&CurTok.SVal, 0))) { case 'A': if (C == ':') { NextChar (); CurTok.Tok = TOK_OVERRIDE_ABS; } else { CurTok.Tok = TOK_A; } return; case 'F': if (C == ':') { NextChar (); CurTok.Tok = TOK_OVERRIDE_FAR; return; } break; case 'S': if ((CPU == CPU_4510) || (CPU == CPU_65816)) { CurTok.Tok = TOK_S; return; } break; case 'X': CurTok.Tok = TOK_X; return; case 'Y': CurTok.Tok = TOK_Y; return; case 'Z': if (C == ':') { NextChar (); CurTok.Tok = TOK_OVERRIDE_ZP; return; } else { if (CPU == CPU_4510) { CurTok.Tok = TOK_Z; return; } } break; default: break; } break; case 2: if ((CPU == CPU_4510) && (toupper (SB_AtUnchecked (&CurTok.SVal, 0)) == 'S') && (toupper (SB_AtUnchecked (&CurTok.SVal, 1)) == 'P')) { CurTok.Tok = TOK_S; return; } /* FALL THROUGH */ default: if (CPU == CPU_SWEET16 && (CurTok.IVal = Sweet16Reg (&CurTok.SVal)) >= 0) { /* A sweet16 register number in sweet16 mode */ CurTok.Tok = TOK_REG; return; } } /* Check for define style macro */ if ((M = FindDefine (&CurTok.SVal)) != 0) { /* Macro - expand it */ MacExpandStart (M); goto Restart; } else { /* An identifier */ CurTok.Tok = TOK_IDENT; } return; } /* Ok, let's do the switch */ CharAgain: switch (C) { case '+': NextChar (); CurTok.Tok = TOK_PLUS; return; case '-': NextChar (); CurTok.Tok = TOK_MINUS; return; case '/': NextChar (); if (C != '*') { CurTok.Tok = TOK_DIV; } else if (CComments) { /* Remember the position, then skip the '*' */ Collection LineInfos = STATIC_COLLECTION_INITIALIZER; GetFullLineInfo (&LineInfos); NextChar (); do { while (C != '*') { if (C == EOF) { LIError (&LineInfos, "Unterminated comment"); ReleaseFullLineInfo (&LineInfos); DoneCollection (&LineInfos); goto CharAgain; } NextChar (); } NextChar (); } while (C != '/'); NextChar (); ReleaseFullLineInfo (&LineInfos); DoneCollection (&LineInfos); goto Again; } return; case '*': NextChar (); CurTok.Tok = TOK_MUL; return; case '^': NextChar (); CurTok.Tok = TOK_XOR; return; case '&': NextChar (); if (C == '&') { NextChar (); CurTok.Tok = TOK_BOOLAND; } else { CurTok.Tok = TOK_AND; } return; case '|': NextChar (); if (C == '|') { NextChar (); CurTok.Tok = TOK_BOOLOR; } else { CurTok.Tok = TOK_OR; } return; case ':': NextChar (); switch (C) { case ':': NextChar (); CurTok.Tok = TOK_NAMESPACE; break; case '-': CurTok.IVal = 0; do { --CurTok.IVal; NextChar (); } while (C == '-'); CurTok.Tok = TOK_ULABEL; break; case '+': CurTok.IVal = 0; do { ++CurTok.IVal; NextChar (); } while (C == '+'); CurTok.Tok = TOK_ULABEL; break; case '=': NextChar (); CurTok.Tok = TOK_ASSIGN; break; default: CurTok.Tok = TOK_COLON; break; } return; case ',': NextChar (); CurTok.Tok = TOK_COMMA; return; case ';': NextChar (); while (C != '\n' && C != EOF) { NextChar (); } goto CharAgain; case '#': NextChar (); CurTok.Tok = TOK_HASH; return; case '(': NextChar (); CurTok.Tok = TOK_LPAREN; return; case ')': NextChar (); CurTok.Tok = TOK_RPAREN; return; case '[': NextChar (); CurTok.Tok = TOK_LBRACK; return; case ']': NextChar (); CurTok.Tok = TOK_RBRACK; return; case '{': NextChar (); CurTok.Tok = TOK_LCURLY; return; case '}': NextChar (); CurTok.Tok = TOK_RCURLY; return; case '<': NextChar (); if (C == '=') { NextChar (); CurTok.Tok = TOK_LE; } else if (C == '<') { NextChar (); CurTok.Tok = TOK_SHL; } else if (C == '>') { NextChar (); CurTok.Tok = TOK_NE; } else { CurTok.Tok = TOK_LT; } return; case '=': NextChar (); CurTok.Tok = TOK_EQ; return; case '!': NextChar (); CurTok.Tok = TOK_BOOLNOT; return; case '>': NextChar (); if (C == '=') { NextChar (); CurTok.Tok = TOK_GE; } else if (C == '>') { NextChar (); CurTok.Tok = TOK_SHR; } else { CurTok.Tok = TOK_GT; } return; case '~': NextChar (); CurTok.Tok = TOK_NOT; return; case '\'': /* Hack: If we allow ' as terminating character for strings, read ** the following stuff as a string, and check for a one character ** string later. */ if (LooseStringTerm) { ReadStringConst ('\''); if (SB_GetLen (&CurTok.SVal) == 1) { CurTok.IVal = SB_AtUnchecked (&CurTok.SVal, 0); CurTok.Tok = TOK_CHARCON; } else { CurTok.Tok = TOK_STRCON; } } else { /* Always a character constant */ NextChar (); if (C == EOF || IsControl (C)) { Error ("Illegal character constant"); goto CharAgain; } CurTok.IVal = C; CurTok.Tok = TOK_CHARCON; NextChar (); if (C != '\'') { if (!MissingCharTerm) { Error ("Illegal character constant"); } } else { NextChar (); } } return; case '\"': ReadStringConst ('\"'); CurTok.Tok = TOK_STRCON; return; case '\\': /* Line continuation? */ if (LineCont) { NextChar (); /* Next char should be a LF, if not, will result in an error later */ if (C == '\n') { /* Ignore the '\n' */ NextChar (); goto Again; } else { /* Make it clear what the problem is: */ Error ("EOL expected."); } } break; case '\n': NextChar (); CurTok.Tok = TOK_SEP; return; case EOF: CheckInputStack (); /* In case of the main file, do not close it, but return EOF. */ if (Source && Source->Next) { DoneCharSource (); goto Again; } else { CurTok.Tok = TOK_EOF; } return; } /* If we go here, we could not identify the current character. Skip it ** and try again. */ Error ("Invalid input character: 0x%02X", C & 0xFF); NextChar (); goto Again; }
void SymCheck (void) /* Run through all symbols and check for anomalies and errors */ { SymEntry* S; /* Check for open scopes */ if (CurrentScope->Parent != 0) { Error ("Local scope was not closed"); } /* First pass: Walk through all symbols, checking for undefined's and ** changing them to trampoline symbols or make them imports. */ S = SymList; while (S) { /* If the symbol is marked as global, mark it as export, if it is ** already defined, otherwise mark it as import. */ if (S->Flags & SF_GLOBAL) { if (S->Flags & SF_DEFINED) { SymExportFromGlobal (S); } else { SymImportFromGlobal (S); } } /* Handle undefined symbols */ if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) { /* This is an undefined symbol. Handle it. */ SymCheckUndefined (S); } /* Next symbol */ S = S->List; } /* Second pass: Walk again through the symbols. Count exports and imports ** and set address sizes where this has not happened before. Ignore ** undefined's, since we handled them in the last pass, and ignore unused ** symbols, since we handled them in the last pass, too. */ S = SymList; while (S) { if ((S->Flags & SF_UNUSED) == 0 && (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) { /* Check for defined symbols that were never referenced */ if (IsSizeOfSymbol (S)) { /* Remove line infos, we don't need them any longer */ ReleaseFullLineInfo (&S->DefLines); ReleaseFullLineInfo (&S->RefLines); } else if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) { LIWarning (&S->DefLines, 2, "Symbol `%m%p' is defined but never used", GetSymName (S)); } /* Assign an index to all imports */ if (S->Flags & SF_IMPORT) { if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) { /* Imported symbol is not referenced */ LIWarning (&S->DefLines, 2, "Symbol `%m%p' is imported but never used", GetSymName (S)); } else { /* Give the import an id, count imports */ S->ImportId = ImportCount++; } } /* Count exports, assign the export ID */ if (S->Flags & SF_EXPORT) { S->ExportId = ExportCount++; } /* If the symbol is defined but has an unknown address size, ** recalculate it. */ if (SymHasExpr (S) && S->AddrSize == ADDR_SIZE_DEFAULT) { ExprDesc ED; ED_Init (&ED); StudyExpr (S->Expr, &ED); S->AddrSize = ED.AddrSize; if (SymIsExport (S)) { if (S->ExportSize == ADDR_SIZE_DEFAULT) { /* Use the real export size */ S->ExportSize = S->AddrSize; } else if (S->AddrSize > S->ExportSize) { /* We're exporting a symbol smaller than it actually is */ LIWarning (&S->DefLines, 1, "Symbol `%m%p' is %s but exported %s", GetSymName (S), AddrSizeToStr (S->AddrSize), AddrSizeToStr (S->ExportSize)); } } ED_Done (&ED); } /* If the address size of the symbol was guessed, check the guess ** against the actual address size and print a warning if the two ** differ. */ if (S->AddrSize != ADDR_SIZE_DEFAULT) { /* Do we have data for this address size? */ if (S->AddrSize <= sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0])) { /* Get the file position where the symbol was used */ const FilePos* P = S->GuessedUse[S->AddrSize - 1]; if (P) { PWarning (P, 0, "Didn't use %s addressing for `%m%p'", AddrSizeToStr (S->AddrSize), GetSymName (S)); } } } } /* Next symbol */ S = S->List; } }
void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags) /* Mark the given symbol as an exported symbol */ { /* Check if it's ok to export the symbol */ if (S->Flags & SF_IMPORT) { /* The symbol is already marked as imported external symbol */ Error ("Symbol `%m%p' is already an import", GetSymName (S)); return; } if (S->Flags & SF_VAR) { /* Variable symbols cannot be exported */ Error ("Var symbol `%m%p' cannot be exported", GetSymName (S)); return; } /* If the symbol was marked as global before, remove the global flag and ** proceed, but check the address size. */ if (S->Flags & SF_GLOBAL) { if (AddrSize != S->ExportSize) { Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); } S->Flags &= ~SF_GLOBAL; /* .GLOBAL remembers line infos in case an .IMPORT follows. We have ** to remove these here. */ ReleaseFullLineInfo (&S->DefLines); } /* If the symbol was already marked as an export, but wasn't defined ** before, the address sizes in both definitions must match. */ if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) { if (S->ExportSize != AddrSize) { Error ("Address size mismatch for symbol `%m%p'", 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) { /* We're exporting a symbol smaller than it actually is */ Warning (1, "Symbol `%m%p' is %s but exported %s", GetSymName (S), AddrSizeToStr (S->AddrSize), AddrSizeToStr (S->ExportSize)); } } /* Set the symbol data */ S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags); /* Remember line info for this reference */ CollAppend (&S->RefLines, GetAsmLineInfo ()); }
void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags) /* Define a new symbol */ { if (S->Flags & SF_IMPORT) { /* Defined symbol is marked as imported external symbol */ Error ("Symbol `%m%p' is already an import", GetSymName (S)); return; } if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) { /* Variable symbols cannot be exports or globals */ Error ("Var symbol `%m%p' cannot be an export or global symbol", GetSymName (S)); return; } if (S->Flags & SF_DEFINED) { /* Multiple definition. In case of a variable, this is legal. */ if ((S->Flags & SF_VAR) == 0) { Error ("Symbol `%m%p' is already defined", GetSymName (S)); S->Flags |= SF_MULTDEF; return; } else { /* Redefinition must also be a variable symbol */ if ((Flags & SF_VAR) == 0) { Error ("Symbol `%m%p' 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 */ if (AddrSize == ADDR_SIZE_DEFAULT) { /* ### Must go! Delay address size calculation until end of assembly! */ ExprDesc ED; ED_Init (&ED); StudyExpr (Expr, &ED); AddrSize = ED.AddrSize; ED_Done (&ED); } /* Set the symbol value */ S->Expr = Expr; /* In case of a variable symbol, walk over all expressions containing ** this symbol and replace the (sub-)expression by the literal value of ** the tree. Be sure to replace the expression node in place, since there ** may be pointers to it. */ if (Flags & SF_VAR) { SymReplaceExprRefs (S); } /* If the symbol is marked as global, export it. Address size is checked ** below. */ if (S->Flags & SF_GLOBAL) { S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT; ReleaseFullLineInfo (&S->DefLines); } /* Mark the symbol as defined and use the given address size */ S->Flags |= (SF_DEFINED | Flags); S->AddrSize = AddrSize; /* Remember the line info of the symbol definition */ GetFullLineInfo (&S->DefLines); /* If the symbol is exported, check the address sizes */ if (S->Flags & SF_EXPORT) { if (S->ExportSize == ADDR_SIZE_DEFAULT) { /* Use the real size of the symbol */ S->ExportSize = S->AddrSize; } else if (S->AddrSize > S->ExportSize) { /* We're exporting a symbol smaller than it actually is */ Warning (1, "Symbol `%m%p' is %s but exported %s", GetSymName (S), AddrSizeToStr (S->AddrSize), AddrSizeToStr (S->ExportSize)); } } /* If this is not a local symbol, remember it as the last global one */ if ((S->Flags & SF_LOCAL) == 0) { SymLast = S; } }