static IfDesc* AllocIf (const char* Directive, int NeedTerm) /* Alloc a new element from the .IF stack */ { IfDesc* ID; /* Check for stack overflow */ if (IfCount >= MAX_IFS) { Fatal ("Too many nested .IFs"); } /* Get the next element */ ID = &IfStack[IfCount]; /* Initialize elements */ ID->Flags = NeedTerm? ifNeedTerm : ifNone; if (GetOverallIfCond ()) { /* The parents .IF condition is true */ ID->Flags |= ifParentCond; } ID->LineInfos = EmptyCollection; GetFullLineInfo (&ID->LineInfos); ID->Name = Directive; /* One more slot allocated */ ++IfCount; /* Return the result */ return ID; }
void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags) /* Mark the given symbol as an imported symbol */ { if (S->Flags & SF_DEFINED) { Error ("Symbol `%m%p' is already defined", GetSymName (S)); S->Flags |= SF_MULTDEF; return; } if (S->Flags & SF_EXPORT) { /* The symbol is already marked as exported symbol */ Error ("Cannot import exported symbol `%m%p'", GetSymName (S)); return; } /* If no address size is given, use the address size of the enclosing ** segment. */ if (AddrSize == ADDR_SIZE_DEFAULT) { AddrSize = GetCurrentSegAddrSize (); } /* If the symbol is marked as import or global, check the address size, ** then do silently remove the global flag. */ if (S->Flags & SF_IMPORT) { if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) { Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S)); } if (AddrSize != S->AddrSize) { Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); } } if (S->Flags & SF_GLOBAL) { S->Flags &= ~SF_GLOBAL; if (AddrSize != S->AddrSize) { Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); } } /* Set the symbol data */ S->Flags |= (SF_IMPORT | Flags); S->AddrSize = AddrSize; /* Mark the position of the import as the position of the definition. ** Please note: In case of multiple .global or .import statements, the line ** infos add up. */ GetFullLineInfo (&S->DefLines); }
static Assertion* NewAssertion (ExprNode* Expr, AssertAction Action, unsigned Msg) /* Create a new Assertion struct and return it */ { /* Allocate memory */ Assertion* A = xmalloc (sizeof (Assertion)); /* Initialize the fields */ A->Expr = Expr; A->Action = Action; A->Msg = Msg; A->LI = EmptyCollection; GetFullLineInfo (&A->LI); /* Return the new struct */ return A; }
void Error (const char* Format, ...) /* Print an error message */ { 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); }
Fragment* NewFragment (unsigned char Type, unsigned short Len) /* Create, initialize and return a new fragment. The fragment will be inserted * into the current segment. */ { /* Create a new fragment */ Fragment* F = xmalloc (sizeof (*F)); /* Initialize it */ F->Next = 0; F->LineList = 0; F->LI = EmptyCollection; GetFullLineInfo (&F->LI); F->Len = Len; F->Type = Type; /* And return it */ return F; }
static ULabel* NewULabel (ExprNode* Val) /* Create a new ULabel and insert it into the collection. The created label * structure is returned. */ { /* Allocate memory for the ULabel structure */ ULabel* L = xmalloc (sizeof (ULabel)); /* Initialize the fields */ L->LineInfos = EmptyCollection; GetFullLineInfo (&L->LineInfos); L->Val = Val; L->Ref = 0; /* Insert the label into the collection */ CollAppend (&ULabList, L); /* Return the created label */ return L; }
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 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 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 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; }
static void SymCheckUndefined (SymEntry* S) /* Handle an undefined symbol */ { /* Undefined symbol. It may be... ** ** - An undefined symbol in a nested lexical level. If the symbol is not ** fixed to this level, search for the symbol in the higher levels and ** make the entry a trampoline entry if we find one. ** ** - If the symbol is not found, it is a real undefined symbol. If the ** AutoImport flag is set, make it an import. If the AutoImport flag is ** not set, it's an error. */ SymEntry* Sym = 0; if ((S->Flags & SF_FIXED) == 0) { SymTable* Tab = GetSymParentScope (S); while (Tab) { Sym = SymFind (Tab, GetStrBuf (S->Name), SYM_FIND_EXISTING | SYM_CHECK_ONLY); if (Sym && (Sym->Flags & (SF_DEFINED | SF_IMPORT)) != 0) { /* We've found a symbol in a higher level that is ** either defined in the source, or an import. */ break; } /* No matching symbol found in this level. Look further */ Tab = Tab->Parent; } } if (Sym) { /* We found the symbol in a higher level. Transfer the flags and ** address size from the local symbol to that in the higher level ** and check for problems. */ if (S->Flags & SF_EXPORT) { if (Sym->Flags & SF_IMPORT) { /* The symbol is already marked as import */ LIError (&S->RefLines, "Symbol `%s' is already an import", GetString (Sym->Name)); } if ((Sym->Flags & SF_EXPORT) == 0) { /* Mark the symbol as an export */ Sym->Flags |= SF_EXPORT; Sym->ExportSize = S->ExportSize; if (Sym->ExportSize == ADDR_SIZE_DEFAULT) { /* Use the actual size of the symbol */ Sym->ExportSize = Sym->AddrSize; } if (Sym->AddrSize > Sym->ExportSize) { /* We're exporting a symbol smaller than it actually is */ LIWarning (&Sym->DefLines, 1, "Symbol `%m%p' is %s but exported %s", GetSymName (Sym), AddrSizeToStr (Sym->AddrSize), AddrSizeToStr (Sym->ExportSize)); } } } if (S->Flags & SF_REFERENCED) { /* Mark as referenced and move the line info */ Sym->Flags |= SF_REFERENCED; CollTransfer (&Sym->RefLines, &S->RefLines); CollDeleteAll (&S->RefLines); } /* Transfer all expression references */ SymTransferExprRefs (S, Sym); /* Mark the symbol as unused removing all other flags */ S->Flags = SF_UNUSED; } else { /* The symbol is definitely undefined */ if (S->Flags & SF_EXPORT) { /* We will not auto-import an export */ LIError (&S->RefLines, "Exported symbol `%m%p' was never defined", GetSymName (S)); } else { if (AutoImport) { /* Mark as import, will be indexed later */ S->Flags |= SF_IMPORT; /* Use the address size for code */ S->AddrSize = CodeAddrSize; /* Mark point of import */ GetFullLineInfo (&S->DefLines); } else { /* Error */ LIError (&S->RefLines, "Symbol `%m%p' is undefined", GetSymName (S)); } } } }
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. */ { if (S->Flags & SF_VAR) { /* Variable symbols cannot be exported or imported */ Error ("Var symbol `%m%p' cannot be made global", GetSymName (S)); return; } /* If the symbol is already marked as import, the address size must match. ** Apart from that, ignore the global declaration. */ if (S->Flags & SF_IMPORT) { if (AddrSize == ADDR_SIZE_DEFAULT) { /* Use the size of the current segment */ AddrSize = GetCurrentSegAddrSize (); } if (AddrSize != S->AddrSize) { Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); } return; } /* If the symbol is already an export: If it is not defined, the address ** sizes must match. */ if (S->Flags & SF_EXPORT) { if ((S->Flags & SF_DEFINED) == 0) { /* Symbol is undefined */ if (AddrSize != S->ExportSize) { Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); } } else if (AddrSize != ADDR_SIZE_DEFAULT) { /* Symbol is defined and address size given */ if (AddrSize != S->ExportSize) { Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); } } return; } /* If the symbol is already marked as global, the address size must match. ** Use the ExportSize here, since it contains the actual address size ** passed to this function. */ if (S->Flags & SF_GLOBAL) { if (AddrSize != S->ExportSize) { Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); } return; } /* If we come here, the symbol was neither declared as export, import or ** global before. Check if it is already defined, in which case it will ** become an export. If it is not defined, mark it as global and remember ** the given address sizes. */ 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) { /* 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)); } S->Flags |= (SF_EXPORT | Flags); } else { /* Since we don't know if the symbol will get exported or imported, ** remember two different address sizes: One for an import in AddrSize, ** and the other one for an export in ExportSize. */ S->AddrSize = AddrSize; if (S->AddrSize == ADDR_SIZE_DEFAULT) { /* Use the size of the current segment */ S->AddrSize = GetCurrentSegAddrSize (); } S->ExportSize = AddrSize; S->Flags |= (SF_GLOBAL | Flags); /* Remember the current location as location of definition in case ** an .IMPORT follows later. */ GetFullLineInfo (&S->DefLines); } }
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; } }
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); /* Check for errors */ 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 or imported */ Error ("Var symbol `%m%p' cannot be exported", GetSymName (S)); return; } /* If the symbol was already marked as an export or global, check if * this was done specifiying the same address size. In case of a global * declaration, silently remove the global flag. */ if (S->Flags & (SF_EXPORT | SF_GLOBAL)) { if (S->ExportSize != AddrSize) { Error ("Address size mismatch for symbol `%m%p'", 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 `%m%p'", 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 `%m%p'", GetSymName (S)); } } S->ConDesPrio[Type] = Prio; /* Set the symbol data */ S->Flags |= (SF_EXPORT | SF_REFERENCED); /* In case we have no line info for the definition, record it now */ if (CollCount (&S->DefLines) == 0) { GetFullLineInfo (&S->DefLines); } }