static void VPrintMsg (const FilePos* Pos, const char* Desc, const char* Format, va_list ap) /* Format and output an error/warning message. */ { StrBuf S = STATIC_STRBUF_INITIALIZER; /* Format the actual message */ StrBuf Msg = STATIC_STRBUF_INITIALIZER; SB_VPrintf (&Msg, Format, ap); SB_Terminate (&Msg); /* Format the message header */ SB_Printf (&S, "%s(%u): %s: ", SB_GetConstBuf (GetFileName (Pos->Name)), Pos->Line, Desc); /* Append the message to the message header */ SB_Append (&S, &Msg); /* Delete the formatted message */ SB_Done (&Msg); /* Add a new line and terminate the generated full message */ SB_AppendChar (&S, '\n'); SB_Terminate (&S); /* Output the full message */ fputs (SB_GetConstBuf (&S), stderr); /* Delete the buffer for the full message */ SB_Done (&S); }
void CreateDependencies (void) /* Create dependency files requested by the user */ { if (SB_NotEmpty (&DepName)) { CreateDepFile (SB_GetConstBuf (&DepName), IT_MAIN | IT_USRINC); } if (SB_NotEmpty (&FullDepName)) { CreateDepFile (SB_GetConstBuf (&FullDepName), IT_MAIN | IT_SYSINC | IT_USRINC); } }
void CreateDependencies (void) /* Create dependency files requested by the user */ { if (SB_NotEmpty (&DepName)) { CreateDepFile (SB_GetConstBuf (&DepName), FT_MAIN | FT_INCLUDE | FT_BINARY); } if (SB_NotEmpty (&FullDepName)) { CreateDepFile (SB_GetConstBuf (&FullDepName), FT_MAIN | FT_INCLUDE | FT_BINARY | FT_DBGINFO); } }
static IntStack* GetWarning (StrBuf* B) /* Get a warning name from the string buffer. Returns a pointer to the intstack * that holds the state of the warning, and NULL in case of errors. The * function will output error messages in case of problems. */ { IntStack* S = 0; StrBuf W = AUTO_STRBUF_INITIALIZER; /* The warning name is a symbol but the '-' char is allowed within */ if (SB_GetSym (B, &W, "-")) { /* Map the warning name to an IntStack that contains its state */ S = FindWarning (SB_GetConstBuf (&W)); /* Handle errors */ if (S == 0) { Error ("Pragma expects a warning name as first argument"); } } /* Deallocate the string */ SB_Done (&W); /* Done */ return S; }
static void WriteDep (FILE* F, FileType Types) /* Helper function. Writes all file names that match Types to the output */ { unsigned I; /* Loop over all files */ for (I = 0; I < CollCount (&FileTab); ++I) { const StrBuf* Filename; /* Get the next input file */ const FileEntry* E = (const FileEntry*) CollAt (&FileTab, I); /* Ignore it if it is not of the correct type */ if ((E->Type & Types) == 0) { continue; } /* If this is not the first file, add a space */ if (I > 0) { fputc (' ', F); } /* Print the dependency */ Filename = GetStrBuf (E->Name); fprintf (F, "%*s", SB_GetLen (Filename), SB_GetConstBuf (Filename)); } }
static token_t FindDotKeyword (void) /* Find the dot keyword in SVal. Return the corresponding token if found, ** return TOK_NONE if not found. */ { struct DotKeyword K; struct DotKeyword* R; /* Initialize K */ K.Key = SB_GetConstBuf (&CurTok.SVal); K.Tok = 0; /* If we aren't in ignore case mode, we have to uppercase the keyword */ if (!IgnoreCase) { UpcaseSVal (); } /* Search for the keyword */ R = bsearch (&K, DotKeywords, sizeof (DotKeywords) / sizeof (DotKeywords [0]), sizeof (DotKeywords [0]), CmpDotKeyword); if (R != 0) { return R->Tok; } else { return TOK_NONE; } }
static int Sweet16Reg (const StrBuf* Id) /* Check if the given identifier is a sweet16 register. Return -1 if this is ** not the case, return the register number otherwise. */ { unsigned RegNum; char Check; if (SB_GetLen (Id) < 2) { return -1; } if (toupper (SB_AtUnchecked (Id, 0)) != 'R') { return -1; } if (!IsDigit (SB_AtUnchecked (Id, 1))) { return -1; } if (sscanf (SB_GetConstBuf (Id)+1, "%u%c", &RegNum, &Check) != 1 || RegNum > 15) { /* Invalid register */ return -1; } /* The register number is valid */ return (int) RegNum; }
static void DoInclude (void) /* Open an include file. */ { char RTerm; InputType IT; StrBuf Filename = STATIC_STRBUF_INITIALIZER; /* Preprocess the remainder of the line */ PreprocessLine (); /* Skip blanks */ SkipWhitespace (0); /* Get the next char and check for a valid file name terminator. Setup * the include directory spec (SYS/USR) by looking at the terminator. */ switch (CurC) { case '\"': RTerm = '\"'; IT = IT_USRINC; break; case '<': RTerm = '>'; IT = IT_SYSINC; break; default: PPError ("`\"' or `<' expected"); goto Done; } NextChar (); /* Get a copy of the filename */ while (CurC != '\0' && CurC != RTerm) { SB_AppendChar (&Filename, CurC); NextChar (); } SB_Terminate (&Filename); /* Check if we got a terminator */ if (CurC == RTerm) { /* Open the include file */ OpenIncludeFile (SB_GetConstBuf (&Filename), IT); } else if (CurC == '\0') { /* No terminator found */ PPError ("#include expects \"FILENAME\" or <FILENAME>"); } Done: /* Free the allocated filename data */ SB_Done (&Filename); /* Clear the remaining line so the next input will come from the new * file (if open) */ ClearLine (); }
void AddSubSearchPathFromEnv (SearchPaths* P, const char* EnvVar, const char* SubDir) /* Add a search path from an environment variable, adding a subdirectory to ** the environment variable value. */ { StrBuf Dir = AUTO_STRBUF_INITIALIZER; const char* EnvVal = getenv (EnvVar); if (EnvVal == 0) { /* Not found */ return; } /* Copy the environment variable to the buffer */ SB_CopyStr (&Dir, EnvVal); /* Add a path separator if necessary */ if (SB_NotEmpty (&Dir)) { if (SB_LookAtLast (&Dir) != '\\' && SB_LookAtLast (&Dir) != '/') { SB_AppendChar (&Dir, '/'); } } /* Add the subdirectory and terminate the string */ SB_AppendStr (&Dir, SubDir); SB_Terminate (&Dir); /* Add the search path */ AddSearchPath (P, SB_GetConstBuf (&Dir)); /* Free the temp buffer */ SB_Done (&Dir); }
void SplitAddAttr (Collection* C, const char* Combined, const char* Name) /* Split a combined name/value pair and add it as an attribute to C. Some * attributes may not need a name. If the name is missing, use Name. If * Name is NULL, terminate with an error. */ { /* Name and value are separated by an equal sign */ const char* Pos = strchr (Combined, '='); if (Pos == 0) { /* Combined is actually a value */ if (Name == 0) { Error ("Command line attribute `%s' doesn't contain a name", Combined); } AddAttr (C, Name, Combined); } else { /* Must split name and value */ StrBuf N = AUTO_STRBUF_INITIALIZER; SB_CopyBuf (&N, Combined, Pos - Combined); SB_Terminate (&N); /* Add the attribute */ AddAttr (C, SB_GetConstBuf (&N), Pos+1); /* Release memory */ SB_Done (&N); } }
void Internal (const char* Format, ...) /* Print a message about an internal compiler error and die. */ { va_list ap; const char* FileName; unsigned LineNum; if (CurTok.LI) { FileName = GetInputName (CurTok.LI); LineNum = GetInputLine (CurTok.LI); } else { FileName = GetCurrentFile (); LineNum = GetCurrentLine (); } fprintf (stderr, "%s(%u): Internal compiler error:\n", FileName, LineNum); va_start (ap, Format); vfprintf (stderr, Format, ap); va_end (ap); fprintf (stderr, "\n"); if (Line) { fprintf (stderr, "\nInput: %.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line)); } /* Use abort to create a core dump */ abort (); }
void Fatal (const char* Format, ...) /* Print a message about a fatal error and die */ { va_list ap; const char* FileName; unsigned LineNum; if (CurTok.LI) { FileName = GetInputName (CurTok.LI); LineNum = GetInputLine (CurTok.LI); } else { FileName = GetCurrentFile (); LineNum = GetCurrentLine (); } fprintf (stderr, "%s(%u): Fatal: ", FileName, LineNum); va_start (ap, Format); vfprintf (stderr, Format, ap); va_end (ap); fprintf (stderr, "\n"); if (Line) { Print (stderr, 1, "Input: %.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line)); } exit (EXIT_FAILURE); }
static void CreateDepFile (const char* Name, InputType Types) /* Create a dependency file with the given name and place dependencies for * all files with the given types there. */ { /* Open the file */ FILE* F = fopen (Name, "w"); if (F == 0) { Fatal ("Cannot open dependency file `%s': %s", Name, strerror (errno)); } /* If a dependency target was given, use it, otherwise use the output * file name as target, followed by a tab character. */ if (SB_IsEmpty (&DepTarget)) { WriteEscaped (F, OutputFilename); } else { WriteEscaped (F, SB_GetConstBuf (&DepTarget)); } fputs (":\t", F); /* Write out the dependencies for the output file */ WriteDep (F, Types); fputs ("\n\n", F); /* Write out a phony dependency for the included files */ WriteDep (F, Types); fputs (":\n\n", F); /* Close the file, check for errors */ if (fclose (F) != 0) { remove (Name); Fatal ("Cannot write to dependeny file (disk full?)"); } }
void ParseRepeat (void) /* Parse and handle the .REPEAT statement */ { char* Name; TokList* List; /* Repeat count follows */ long RepCount = ConstExpression (); if (RepCount < 0) { Error ("Range error"); RepCount = 0; } /* Optional there is a comma and a counter variable */ Name = 0; if (Tok == TOK_COMMA) { /* Skip the comma */ NextTok (); /* Check for an identifier */ if (Tok != TOK_IDENT) { ErrorSkip ("Identifier expected"); } else { /* Remember the name and skip it */ SB_Terminate (&SVal); Name = xstrdup (SB_GetConstBuf (&SVal)); NextTok (); } } /* Separator */ ConsumeSep (); /* Read the token list */ List = CollectRepeatTokens (); /* If we had an error, bail out */ if (List == 0) { xfree (Name); return; } /* Update the token list for replay */ List->RepMax = (unsigned) RepCount; List->Data = Name; List->Check = RepeatTokenCheck; /* If the list is empty, or repeat count zero, there is nothing * to repeat. */ if (List->Count == 0 || RepCount == 0) { FreeTokList (List); return; } /* Read input from the repeat descriptor */ PushTokList (List, ".REPEAT"); }
static pragma_t FindPragma (const StrBuf* Key) /* Find a pragma and return the token. Return PRAGMA_ILLEGAL if the keyword is * not a valid pragma. */ { struct Pragma* P; P = bsearch (SB_GetConstBuf (Key), Pragmas, PRAGMA_COUNT, sizeof (Pragmas[0]), CmpKey); return P? P->Tok : PRAGMA_ILLEGAL; }
int IsAnonName (const StrBuf* Name) /* Check if the given symbol name is that of an anonymous symbol */ { if (SB_GetLen (Name) < sizeof (AnonTag) - 1) { /* Too short */ return 0; } return (strncmp (SB_GetConstBuf (Name), AnonTag, sizeof (AnonTag) - 1) == 0); }
static AFile* NewAFile (IFile* IF, FILE* F) /* Create a new AFile, push it onto the stack, add the path of the file to * the path search list, and finally return a pointer to the new AFile struct. */ { StrBuf Path = AUTO_STRBUF_INITIALIZER; /* Allocate a AFile structure */ AFile* AF = (AFile*) xmalloc (sizeof (AFile)); /* Initialize the fields */ AF->Line = 0; AF->F = F; AF->Input = IF; /* Increment the usage counter of the corresponding IFile. If this * is the first use, set the file data and output debug info if * requested. */ if (IF->Usage++ == 0) { /* Get file size and modification time. There a race condition here, * since we cannot use fileno() (non standard identifier in standard * header file), and therefore not fstat. When using stat with the * file name, there's a risk that the file was deleted and recreated * while it was open. Since mtime and size are only used to check * if a file has changed in the debugger, we will ignore this problem * here. */ struct stat Buf; if (FileStat (IF->Name, &Buf) != 0) { /* Error */ Fatal ("Cannot stat `%s': %s", IF->Name, strerror (errno)); } IF->Size = (unsigned long) Buf.st_size; IF->MTime = (unsigned long) Buf.st_mtime; /* Set the debug data */ g_fileinfo (IF->Name, IF->Size, IF->MTime); } /* Insert the new structure into the AFile collection */ CollAppend (&AFiles, AF); /* Get the path of this file and add it as an extra search path. * To avoid file search overhead, we will add one path only once. * This is checked by the PushSearchPath function. */ SB_CopyBuf (&Path, IF->Name, FindName (IF->Name) - IF->Name); SB_Terminate (&Path); AF->SearchPath = PushSearchPath (UsrIncSearchPath, SB_GetConstBuf (&Path)); SB_Done (&Path); /* Return the new struct */ return AF; }
static void DoError (void) /* Print an error */ { SkipWhitespace (0); if (CurC == '\0') { PPError ("Invalid #error directive"); } else { PPError ("#error: %s", SB_GetConstBuf (Line) + SB_GetIndex (Line)); } /* Clear the rest of line */ ClearLine (); }
static int HasStr (StrBuf* B, const char* E) /* Checks if E follows in B. If so, skips it and returns true */ { unsigned Len = strlen (E); if (SB_GetLen (B) - SB_GetIndex (B) >= Len) { if (strncmp (SB_GetConstBuf (B) + SB_GetIndex (B), E, Len) == 0) { /* Found */ SB_SkipMultiple (B, Len); return 1; } } return 0; }
static void DoWarning (void) /* Print a warning */ { SkipWhitespace (0); if (CurC == '\0') { PPError ("Invalid #warning directive"); } else { PPWarning ("#warning: %s", SB_GetConstBuf (Line) + SB_GetIndex (Line)); } /* Clear the rest of line */ ClearLine (); }
static int ValidateType (StrBuf* Type) /* Check if the given type is valid and if so, return a string id for it. If ** the type isn't valid, return -1. Type is overwritten when checking. */ { unsigned I; const char* A; char* B; /* The length must not be zero and divideable by two */ unsigned Length = SB_GetLen (Type); if (Length < 2 || (Length & 0x01) != 0) { ErrorSkip ("Type value has invalid length"); return -1; } /* The string must consist completely of hex digit chars */ A = SB_GetConstBuf (Type); for (I = 0; I < Length; ++I) { if (!IsXDigit (A[I])) { ErrorSkip ("Type value contains invalid characters"); return -1; } } /* Convert the type to binary */ B = SB_GetBuf (Type); while (A < SB_GetConstBuf (Type) + Length) { /* Since we know, there are only hex digits, there can't be any errors */ *B++ = (HexValue (A[0]) << 4) | HexValue (A[1]); A += 2; } Type->Len = (Length /= 2); /* Allocate the type and return it */ return GetStrBufId (Type); }
static void IntWarning (const char* Filename, unsigned LineNo, const char* Msg, va_list ap) /* Print warning message - internal function. */ { if (!IS_Get (&WarnDisable)) { fprintf (stderr, "%s(%u): Warning: ", Filename, LineNo); vfprintf (stderr, Msg, ap); fprintf (stderr, "\n"); if (Line) { Print (stderr, 1, "Input: %.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line)); } ++WarningCount; } }
static void StringPragma (StrBuf* B, void (*Func) (const char*)) /* Handle a pragma that expects a string parameter */ { StrBuf S = AUTO_STRBUF_INITIALIZER; /* We expect a string here */ if (GetString (B, &S)) { /* Call the given function with the string argument */ Func (SB_GetConstBuf (&S)); } /* Call the string buf destructor */ SB_Done (&S); }
void CfgWarning (const FilePos* Pos, const char* Format, ...) /* Print a warning message adding file name and line number of a given file */ { StrBuf Buf = STATIC_STRBUF_INITIALIZER; va_list ap; va_start (ap, Format); SB_VPrintf (&Buf, Format, ap); va_end (ap); Warning ("%s(%u): %s", GetString (Pos->Name), Pos->Line, SB_GetConstBuf (&Buf)); SB_Done (&Buf); }
const char* ED_GetLabelName (const ExprDesc* Expr, long Offs) /* Return the assembler label name of the given expression. Beware: This * function may use a static buffer, so the name may get "lost" on the second * call to the function. */ { static StrBuf Buf = STATIC_STRBUF_INITIALIZER; /* Expr may have it's own offset, adjust Offs accordingly */ Offs += Expr->IVal; /* Generate a label depending on the location */ switch (ED_GetLoc (Expr)) { case E_LOC_ABS: /* Absolute: numeric address or const */ SB_Printf (&Buf, "$%04X", (int)(Offs & 0xFFFF)); break; case E_LOC_GLOBAL: case E_LOC_STATIC: /* Global or static variable */ if (Offs) { SB_Printf (&Buf, "%s%+ld", SymGetAsmName (Expr->Sym), Offs); } else { SB_Printf (&Buf, "%s", SymGetAsmName (Expr->Sym)); } break; case E_LOC_REGISTER: /* Register variable */ SB_Printf (&Buf, "regbank+%u", (unsigned)((Offs + Expr->Name) & 0xFFFFU)); break; case E_LOC_LITERAL: /* Literal in the literal pool */ if (Offs) { SB_Printf (&Buf, "%s%+ld", LocalLabelName (Expr->Name), Offs); } else { SB_Printf (&Buf, "%s", LocalLabelName (Expr->Name)); } break; default: Internal ("Invalid location in ED_GetLabelName: 0x%04X", ED_GetLoc (Expr)); } /* Return a pointer to the static buffer */ return SB_GetConstBuf (&Buf); }
static void OutputLiteral (Literal* L) /* Output one literal to the currently active data segment */ { /* Translate the literal into the target charset */ TranslateLiteral (L); /* Define the label for the literal */ g_defdatalabel (L->Label); /* Output the literal data */ g_defbytes (SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data)); /* Mark the literal as output */ L->Output = 1; }
static void IntError (const char* Filename, unsigned LineNo, const char* Msg, va_list ap) /* Print an error message - internal function*/ { fprintf (stderr, "%s(%u): Error: ", Filename, LineNo); vfprintf (stderr, Msg, ap); fprintf (stderr, "\n"); if (Line) { Print (stderr, 1, "Input: %.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line)); } ++ErrorCount; if (ErrorCount > 10) { Fatal ("Too many errors"); } }
Collection* ParseAttrList (const char* List, const char** NameList, unsigned NameCount) /* Parse a list containing name/value pairs into a sorted collection. Some * attributes may not need a name, so NameList contains these names. If there * were no errors, the function returns a alphabetically sorted collection * containing Attr entries. */ { const char* Name; /* Create a new collection */ Collection* C = NewCollection (); /* Name/value pairs are separated by commas */ const char* L = List; StrBuf B = AUTO_STRBUF_INITIALIZER; while (1) { if (*L == ',' || *L == ':' || *L == '\0') { /* Terminate the string */ SB_Terminate (&B); /* Determine the default name */ if (CollCount (C) >= NameCount) { Name = 0; } else { Name = NameList[CollCount (C)]; } /* Split and add this attribute/value pair */ SplitAddAttr (C, SB_GetConstBuf (&B), Name); /* Done, clear the buffer. */ SB_Clear (&B); if (*L == '\0') { break; } } else { SB_AppendChar (&B, *L); } ++L; } /* Free memory */ SB_Done (&B); /* Return the collection with the attributes */ return C; }
static void OpenDebugFile (const CodeSeg* S) /* Open the debug file for the given segment if the flag is on */ { if (DebugOptOutput) { StrBuf Name = AUTO_STRBUF_INITIALIZER; if (S->Func) { SB_CopyStr (&Name, S->Func->Name); } else { SB_CopyStr (&Name, "global"); } SB_AppendStr (&Name, ".opt"); SB_Terminate (&Name); OpenDebugOutputFile (SB_GetConstBuf (&Name)); SB_Done (&Name); } }
static void DefineSymbol (const char* Def) /* Define a symbol from the command line */ { const char* P; long Val; StrBuf SymName = AUTO_STRBUF_INITIALIZER; /* The symbol must start with a character or underline */ if (!IsIdStart (Def [0])) { InvDef (Def); } P = Def; /* Copy the symbol, checking the rest */ while (IsIdChar (*P)) { SB_AppendChar (&SymName, *P++); } SB_Terminate (&SymName); /* Do we have a value given? */ if (*P != '=') { if (*P != '\0') { InvDef (Def); } Val = 0; } else { /* We have a value */ ++P; if (*P == '$') { ++P; if (sscanf (P, "%lx", &Val) != 1) { InvDef (Def); } } else { if (sscanf (P, "%li", &Val) != 1) { InvDef (Def); } } } /* Define the new symbol */ NewSymbol (SB_GetConstBuf (&SymName), Val); /* Release string memory */ SB_Done (&SymName); }