static void CheckSymTable (SymTable* Tab) /* Check a symbol table for open references, unused symbols ... */ { SymEntry* Entry = Tab->SymHead; while (Entry) { /* Get the storage flags for tne entry */ unsigned Flags = Entry->Flags; /* Ignore typedef entries */ if (!SymIsTypeDef (Entry)) { /* Check if the symbol is one with storage, and it if it was ** defined but not used. */ if (((Flags & SC_AUTO) || (Flags & SC_STATIC)) && (Flags & SC_EXTERN) == 0) { if (SymIsDef (Entry) && !SymIsRef (Entry) && !SymHasAttr (Entry, atUnused)) { if (Flags & SC_PARAM) { if (IS_Get (&WarnUnusedParam)) { Warning ("Parameter `%s' is never used", Entry->Name); } } else { if (IS_Get (&WarnUnusedVar)) { Warning ("`%s' is defined but never used", Entry->Name); } } } } /* If the entry is a label, check if it was defined in the function */ if (Flags & SC_LABEL) { if (!SymIsDef (Entry)) { /* Undefined label */ Error ("Undefined label: `%s'", Entry->Name); } else if (!SymIsRef (Entry)) { /* Defined but not used */ if (IS_Get (&WarnUnusedLabel)) { Warning ("`%s' is defined but never used", Entry->Name); } } } } /* Next entry */ Entry = Entry->NextSym; } }
static void NewSymbol (const char* SymName, long Val) /* Define a symbol with a fixed numeric value in the current scope */ { ExprNode* Expr; SymEntry* Sym; /* Convert the name to a string buffer */ StrBuf SymBuf = STATIC_STRBUF_INITIALIZER; SB_CopyStr (&SymBuf, SymName); /* Search for the symbol, allocate a new one if it doesn't exist */ Sym = SymFind (CurrentScope, &SymBuf, SYM_ALLOC_NEW); /* Check if have already a symbol with this name */ if (SymIsDef (Sym)) { AbEnd ("`%s' is already defined", SymName); } /* Generate an expression for the symbol */ Expr = GenLiteralExpr (Val); /* Mark the symbol as defined */ SymDef (Sym, Expr, ADDR_SIZE_DEFAULT, SF_NONE); /* Free string buffer memory */ SB_Done (&SymBuf); }
SymEntry* AddLabelSym (const char* Name, unsigned Flags) /* Add a goto label to the label table */ { /* Do we have an entry with this name already? */ SymEntry* Entry = FindSymInTable (LabelTab, Name, HashStr (Name)); if (Entry) { if (SymIsDef (Entry) && (Flags & SC_DEF) != 0) { /* Trying to define the label more than once */ Error ("Label `%s' is defined more than once", Name); } Entry->Flags |= Flags; } else { /* Create a new entry */ Entry = NewSymEntry (Name, SC_LABEL | Flags); /* Set a new label number */ Entry->V.Label = GetLocalLabel (); /* Generate the assembler name of the label */ Entry->AsmName = xstrdup (LocalLabelName (Entry->V.Label)); /* Add the entry to the label table */ AddSymEntry (LabelTab, Entry); } /* Return the entry */ return Entry; }
void EmitExternals (void) /* Write import/export statements for external symbols */ { SymEntry* Entry; Entry = SymTab->SymHead; while (Entry) { unsigned Flags = Entry->Flags; if (Flags & SC_EXTERN) { /* Only defined or referenced externs */ if (SymIsRef (Entry) && !SymIsDef (Entry)) { /* An import */ g_defimport (Entry->Name, Flags & SC_ZEROPAGE); } else if (SymIsDef (Entry)) { /* An export */ g_defexport (Entry->Name, Flags & SC_ZEROPAGE); } } Entry = Entry->NextSym; } }
void EmitDebugInfo (void) /* Emit debug infos for the locals of the current scope */ { const char* Head; const SymEntry* Sym; /* Output info for locals if enabled */ if (DebugInfo) { /* For cosmetic reasons in the output file, we will insert two tabs ** on global level and just one on local level. */ if (LexicalLevel == LEX_LEVEL_GLOBAL) { Head = "\t.dbg\t\tsym"; } else { Head = "\t.dbg\tsym"; } Sym = SymTab->SymHead; while (Sym) { if ((Sym->Flags & (SC_CONST|SC_TYPE)) == 0) { if (Sym->Flags & SC_AUTO) { AddTextLine ("%s, \"%s\", \"00\", auto, %d", Head, Sym->Name, Sym->V.Offs); } else if (Sym->Flags & SC_REGISTER) { AddTextLine ("%s, \"%s\", \"00\", register, \"regbank\", %d", Head, Sym->Name, Sym->V.R.RegOffs); } else if (SymIsRef (Sym) && !SymIsDef (Sym)) { AddTextLine ("%s, \"%s\", \"00\", %s, \"%s\"", Head, Sym->Name, (Sym->Flags & SC_EXTERN)? "extern" : "static", Sym->AsmName); } } Sym = Sym->NextSym; } } }
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); }
static long DoStructInternal (long Offs, unsigned Type) /* Handle the .STRUCT command */ { long Size = 0; /* Outside of other structs, we need a name. Inside another struct or ** union, the struct may be anonymous, in which case no new lexical level ** is started. */ int Anon = (CurTok.Tok != TOK_IDENT); if (!Anon) { /* Enter a new scope, then skip the name */ SymEnterLevel (&CurTok.SVal, SCOPE_STRUCT, ADDR_SIZE_ABS, 0); NextTok (); /* Start at zero offset in the new scope */ Offs = 0; } /* Test for end of line */ ConsumeSep (); /* Read until end of struct */ while (CurTok.Tok != TOK_ENDSTRUCT && CurTok.Tok != TOK_ENDUNION && CurTok.Tok != TOK_EOF) { long MemberSize; SymTable* Struct; SymEntry* Sym; /* Allow empty and comment lines */ if (CurTok.Tok == TOK_SEP) { NextTok (); continue; } /* The format is "[identifier] storage-allocator [, multiplicator]" */ Sym = 0; if (CurTok.Tok == TOK_IDENT) { /* Beware: An identifier may also be a macro, in which case we have ** to start over. */ Macro* M = FindMacro (&CurTok.SVal); if (M) { MacExpandStart (M); continue; } /* We have an identifier, generate a symbol */ Sym = SymFind (CurrentScope, &CurTok.SVal, SYM_ALLOC_NEW); /* Assign the symbol the offset of the current member */ SymDef (Sym, GenLiteralExpr (Offs), ADDR_SIZE_DEFAULT, SF_NONE); /* Skip the member name */ NextTok (); } /* Read storage allocators */ MemberSize = 0; /* In case of errors, use zero */ switch (CurTok.Tok) { case TOK_BYTE: NextTok (); MemberSize = Member (1); break; case TOK_DBYT: case TOK_WORD: case TOK_ADDR: NextTok (); MemberSize = Member (2); break; case TOK_FARADDR: NextTok (); MemberSize = Member (3); break; case TOK_DWORD: NextTok (); MemberSize = Member (4); break; case TOK_RES: NextTok (); if (CurTok.Tok == TOK_SEP) { ErrorSkip ("Size is missing"); } else { MemberSize = Member (1); } break; case TOK_TAG: NextTok (); Struct = ParseScopedSymTable (); if (Struct == 0) { ErrorSkip ("Unknown struct/union"); } else if (GetSymTabType (Struct) != SCOPE_STRUCT) { ErrorSkip ("Not a struct/union"); } else { SymEntry* SizeSym = GetSizeOfScope (Struct); if (!SymIsDef (SizeSym) || !SymIsConst (SizeSym, &MemberSize)) { ErrorSkip ("Size of struct/union is unknown"); } } MemberSize = Member (MemberSize); break; case TOK_STRUCT: NextTok (); MemberSize = DoStructInternal (Offs, STRUCT); break; case TOK_UNION: NextTok (); MemberSize = DoStructInternal (Offs, UNION); break; default: if (!CheckConditionals ()) { /* Not a conditional directive */ ErrorSkip ("Invalid storage allocator in struct/union"); } } /* Assign the size to the member if it has a name */ if (Sym) { DefSizeOfSymbol (Sym, MemberSize); } /* Next member */ if (Type == STRUCT) { /* Struct */ Offs += MemberSize; Size += MemberSize; } else { /* Union */ if (MemberSize > Size) { Size = MemberSize; } } /* Expect end of line */ ConsumeSep (); } /* If this is not a anon struct, enter a special symbol named ".size" ** into the symbol table of the struct that holds the size of the ** struct. Since the symbol starts with a dot, it cannot be accessed ** by user code. ** Leave the struct scope level. */ if (!Anon) { /* Add a symbol */ SymEntry* SizeSym = GetSizeOfScope (CurrentScope); SymDef (SizeSym, GenLiteralExpr (Size), ADDR_SIZE_DEFAULT, SF_NONE); /* Close the struct scope */ SymLeaveLevel (); } /* End of struct/union definition */ if (Type == STRUCT) { Consume (TOK_ENDSTRUCT, "'.ENDSTRUCT' expected"); } else { Consume (TOK_ENDUNION, "'.ENDUNION' expected"); } /* Return the size of the struct */ return Size; }