Esempio n. 1
0
static void AddNotifications (const Collection* LineInfos)
/* Output additional notifications for an error or warning */
{
    unsigned I;
    unsigned Output;
    unsigned Skipped;

    /* The basic line info is always in slot zero. It has been used to
    ** output the actual error or warning. The following slots may contain
    ** more information. Check them and print additional notifications if
    ** they're present, but limit the number to a reasonable value.
    */
    for (I = 1, Output = 0, Skipped = 0; I < CollCount (LineInfos); ++I) {
        /* Get next line info */
        const LineInfo* LI = CollConstAt (LineInfos, I);
        /* Check the type and output an appropriate note */
        const char* Msg;
        switch (GetLineInfoType (LI)) {

        case LI_TYPE_ASM:
            Msg = "Expanded from here";
            break;

        case LI_TYPE_EXT:
            Msg = "Assembler code generated from this line";
            break;

        case LI_TYPE_MACRO:
            Msg = "Macro was defined here";
            break;

        case LI_TYPE_MACPARAM:
            Msg = "Macro parameter came from here";
            break;

        default:
            /* No output */
            Msg = 0;
            break;

        }

        /* Output until an upper limit of messages is reached */
        if (Msg) {
            if (Output < MAX_NOTES) {
                PrintMsg (GetSourcePos (LI), "Note", "%s", Msg);
                ++Output;
            } else {
                ++Skipped;
            }
        }
    }

    /* Add a note if we have more stuff that we won't output */
    if (Skipped > 0) {
        const LineInfo* LI = CollConstAt (LineInfos, 0);
        PrintMsg (GetSourcePos (LI), "Note",
                  "Dropping %u additional line infos", Skipped);
    }
}
Esempio n. 2
0
void PrintDbgModules (FILE* F)
/* Output the modules to a debug info file */
{
    unsigned I;

    /* Output modules */
    for (I = 0; I < CollCount (&ObjDataList); ++I) {

        /* Get this object file */
        const ObjData* O = CollConstAt (&ObjDataList, I);

        /* The main source file is the one at index zero */
        const FileInfo* Source = CollConstAt (&O->Files, 0);

        /* Output the module line */
        fprintf (F,
                 "mod\tid=%u,name=\"%s\",file=%u",
                 I,
                 GetObjFileName (O),
                 Source->Id);

        /* Add library if any */
        if (O->Lib != 0) {
            fprintf (F, ",lib=%u", GetLibId (O->Lib));
        }

        /* Terminate the output line */
        fputc ('\n', F);
    }

}
Esempio n. 3
0
void CheckOpenIfs (void)
/* Called from the scanner before closing an input file. Will check for any
** open .ifs in this file.
*/
{
    const LineInfo* LI;

    while (1) {
        /* Get the current file number and check if the topmost entry on the
        ** .IF stack was inserted with this file number
        */
        IfDesc* D = GetCurrentIf ();
        if (D == 0) {
            /* There are no open .IFs */
            break;
        }

        LI = CollConstAt (&D->LineInfos, 0);
        if (GetSourcePos (LI)->Name != CurTok.Pos.Name) {
            /* The .if is from another file, bail out */
            break;
        }

        /* Start of .if is in the file we're about to leave */
        LIError (&D->LineInfos, "Conditional assembly branch was never closed");
        FreeIf ();
    }

    /* Calculate the new overall .IF condition */
    CalcOverallIfCond ();
}
Esempio n. 4
0
static void PrintUnresolved (ExpCheckFunc F, void* Data)
/* Print a list of unresolved symbols. On unresolved symbols, F is
** called (see the comments on ExpCheckFunc in the data section).
*/
{
    unsigned I;

    /* Print all open imports */
    for (I = 0; I < ExpCount; ++I) {
        Export* E = ExpPool [I];
        if (E->Expr == 0 && E->ImpCount > 0 && F (E->Name, Data) == 0) {
            /* Unresolved external */
            Import* Imp = E->ImpList;
            fprintf (stderr,
                     "Unresolved external `%s' referenced in:\n",
                     GetString (E->Name));
            while (Imp) {
                unsigned J;
                for (J = 0; J < CollCount (&Imp->RefLines); ++J) {
                    const LineInfo* LI = CollConstAt (&Imp->RefLines, J);
                    fprintf (stderr,
                         "  %s(%u)\n",
                         GetSourceName (LI),
                         GetSourceLine (LI));
                }
                Imp = Imp->Next;
            }
        }
    }
}
Esempio n. 5
0
char* SearchFile (const SearchPaths* P, const char* File)
/* Search for a file in a list of directories. Return a pointer to a malloced
** area that contains the complete path, if found, return 0 otherwise.
*/
{
    char* Name = 0;
    StrBuf PathName = AUTO_STRBUF_INITIALIZER;

    /* Start the search */
    unsigned I;
    for (I = 0; I < CollCount (P); ++I) {

        /* Copy the next path element into the buffer */
        SB_CopyStr (&PathName, CollConstAt (P, I));

        /* Add a path separator and the filename */
        if (SB_NotEmpty (&PathName)) {
            SB_AppendChar (&PathName, '/');
        }
        SB_AppendStr (&PathName, File);
        SB_Terminate (&PathName);

        /* Check if this file exists */
        if (access (SB_GetBuf (&PathName), 0) == 0) {
            /* The file exists, we're done */
            Name = xstrdup (SB_GetBuf (&PathName));
            break;
        }
    }

    /* Cleanup and return the result of the search */
    SB_Done (&PathName);
    return Name;
}
Esempio n. 6
0
void DumpAttrColl (const Collection* C)
/* Dump a collection of attribute/value pairs for debugging */
{
    unsigned I;
    for (I = 0; I < CollCount (C); ++I) {
        const Attr* A = CollConstAt (C, I);
        printf ("%s=%s\n", A->Name, A->Value);
    }
}
Esempio n. 7
0
void CheckAssertions (void)
/* Check all assertions */
{
    unsigned I;

    /* Walk over all assertions */
    for (I = 0; I < CollCount (&Assertions); ++I) {

        const LineInfo* LI;
        const char* Module;
        unsigned Line;

        /* Get the assertion */
        Assertion* A = CollAtUnchecked (&Assertions, I);

        /* Ignore assertions that shouldn't be handled at link time */
        if (!AssertAtLinkTime (A->Action)) {
            continue;
        }

        /* Retrieve the relevant line info for this assertion */
        LI = CollConstAt (&A->LineInfos, 0);

        /* Get file name and line number from the source */
        Module = GetSourceName (LI);
        Line   = GetSourceLine (LI);

        /* If the expression is not constant, we're not able to handle it */
        if (!IsConstExpr (A->Expr)) {
            Warning ("Cannot evaluate assertion in module `%s', line %u",
                     Module, Line);
        } else if (GetExprVal (A->Expr) == 0) {

            /* Assertion failed */
            const char* Message = GetString (A->Msg);

            switch (A->Action) {

                case ASSERT_ACT_WARN:
                case ASSERT_ACT_LDWARN:
                    Warning ("%s(%u): %s", Module, Line, Message);
                    break;

                case ASSERT_ACT_ERROR:
                case ASSERT_ACT_LDERROR:
                    Error ("%s(%u): %s", Module, Line, Message);
                    break;

                default:
                    Internal ("Invalid assertion action (%u) in module `%s', "
                              "line %u (file corrupt?)",
                              A->Action, Module, Line);
                    break;
            }
        }
    }
}
Esempio n. 8
0
static const char* GetString (const Collection* C, unsigned Index)
/* Get a string from a collection. In fact, this function calls CollConstAt,
 * but will print a somewhat more readable error message if the index is out
 * of bounds.
 */
{
    if (Index >= CollCount (C)) {
        Error ("Invalid string index (%u) - file corrupt!", Index);
    }
    return CollConstAt (C, Index);
}
Esempio n. 9
0
const Attr* NeedAttr (const Collection* C, const char* Name, const char* Op)
/* Search for an attribute with the given name and return it. If the attribute
 * is not found, the function terminates with an error using Op as additional
 * context in the error message.
 */
{
    /* Search for the attribute and return it */
    unsigned Index;
    if (!FindAttr (C, Name, &Index)) {
        Error ("Found no attribute named `%s' for operation %s", Name, Op);
    }
    return CollConstAt (C, Index);
}
Esempio n. 10
0
const StrBuf* GetFileName (unsigned Name)
/* Get the name of a file where the name index is known */
{
    static const StrBuf ErrorMsg = LIT_STRBUF_INITIALIZER ("(outside file scope)");

    const FileEntry* F;

    if (Name == 0) {
        /* Name was defined outside any file scope, use the name of the first
         * file instead. Errors are then reported with a file position of
         * line zero in the first file.
         */
        if (CollCount (&FileTab) == 0) {
            /* No files defined until now */
            return &ErrorMsg;
        } else {
            F = CollConstAt (&FileTab, 0);
        }
    } else {
        F = CollConstAt (&FileTab, Name-1);
    }
    return GetStrBuf (F->Name);
}
Esempio n. 11
0
const Attr* GetAttr (const Collection* C, const char* Name)
/* Search for an attribute with the given name and return it. The function
 * returns NULL if the attribute wasn't found.
 */
{
    /* Search for the attribute and return it */
    unsigned Index;
    if (FindAttr (C, Name, &Index)) {
        return CollConstAt (C, Index);
    } else {
        /* Not found */
        return 0;
    }
}
Esempio n. 12
0
void ErrorMsg (const Collection* LineInfos, const char* Format, va_list ap)
/* Print an error message */
{
    /* The first entry in the collection is that of the actual source pos */
    const LineInfo* LI = CollConstAt (LineInfos, 0);

    /* Output an error for this position */
    VPrintMsg (GetSourcePos (LI), "Error", Format, ap);

    /* Add additional notifications if necessary */
    AddNotifications (LineInfos);

    /* Count errors */
    ++ErrorCount;
}
Esempio n. 13
0
static void WarningMsg (const Collection* LineInfos, const char* Format, va_list ap)
/* Print warning message. */
{
    /* The first entry in the collection is that of the actual source pos */
    const LineInfo* LI = CollConstAt (LineInfos, 0);

    /* Output a warning for this position */
    VPrintMsg (GetSourcePos (LI), "Warning", Format, ap);

    /* Add additional notifications if necessary */
    AddNotifications (LineInfos);

    /* Count warnings */
    ++WarningCount;
}
Esempio n. 14
0
static void ConvertImports (FILE* F, const O65Data* D)
/* Convert the imports */
{
    unsigned I;

    if (CollCount (&D->Imports) > 0) {
        for (I = 0; I < CollCount (&D->Imports); ++I) {

            /* Get the next import */
            const O65Import* Import = CollConstAt (&D->Imports, I);

            /* Import it by name */
            fprintf (F, ".import\t%s\n", Import->Name);
        }
        fprintf (F, "\n");
    }
}
Esempio n. 15
0
static const char* RelocExpr (const O65Data* D, unsigned char SegID,
                              unsigned long Val, const O65Reloc* R)
/* Generate the segment relative relocation expression. R is only used if the
 * expression contains am import, and may be NULL if this is an error (which
 * is then flagged).
 */
{
    const O65Import* Import;

    switch (SegID) {

        case O65_SEGID_UNDEF:
            if (R) {
                if (R->SymIdx >= CollCount (&D->Imports)) {
                    Error ("Import index out of range (input file corrupt)");
                }
                Import = CollConstAt (&D->Imports, R->SymIdx);
                return LabelPlusOffs (Import->Name, Val);
            } else {
                Error ("Relocation references an import which is not allowed here");
                return 0;
            }
            break;

        case O65_SEGID_TEXT:
            return LabelPlusOffs (CodeLabel, Val - D->Header.tbase);

        case O65_SEGID_DATA:
            return LabelPlusOffs (DataLabel, Val - D->Header.dbase);

        case O65_SEGID_BSS:
            return LabelPlusOffs (BssLabel, Val - D->Header.bbase);

        case O65_SEGID_ZP:
            return LabelPlusOffs (ZeropageLabel, Val - D->Header.zbase);

        case O65_SEGID_ABS:
            return LabelPlusOffs ("", Val);

        default:
            Internal ("Cannot handle this segment reference in reloc entry");
    }

    /* NOTREACHED */
    return 0;
}
Esempio n. 16
0
static void WriteIndex (void)
/* Write the index of a library file */
{
    unsigned I;

    /* Sync I/O in case the last operation was a read */
    fseek (NewLib, 0, SEEK_CUR);

    /* Remember the current offset in the header */
    Header.IndexOffs = ftell (NewLib);

    /* Write the object file count */
    WriteVar (NewLib, CollCount (&ObjPool));

    /* Write the object files */
    for (I = 0; I < CollCount (&ObjPool); ++I) {
        WriteIndexEntry (CollConstAt (&ObjPool, I));
    }
}
Esempio n. 17
0
int PushSearchPath (SearchPaths* P, const char* NewPath)
/* Add a new search path to the head of an existing search path list, provided
** that it's not already there. If the path is already at the first position,
** return zero, otherwise return a non zero value.
*/
{                                      
    /* Generate a clean copy of NewPath */
    char* Path = CleanupPath (NewPath);   

    /* If we have paths, check if Path is already at position zero */
    if (CollCount (P) > 0 && strcmp (CollConstAt (P, 0), Path) == 0) {
        /* Match. Delete the copy and return to the caller */
        xfree (Path);
        return 0;
    }

    /* Insert a clean copy of the path at position 0, return success */
    CollInsert (P, Path, 0);
    return 1;
}
Esempio n. 18
0
static void LibCheckExports (ObjData* O)
/* Insert all exports from the given object file into the global list
 * checking for duplicates.
 */
{
    unsigned I;

    /* Let the user know what we do */
    Print (stdout, 1, "Module `%s' (%u exports):\n", O->Name, CollCount (&O->Exports));

    /* Insert the exports into the global table */
    for (I = 0; I < CollCount (&O->Exports); ++I) {

        /* Get the name of the export */
        const char* Name = CollConstAt (&O->Exports, I);

        /* Insert the name into the hash table */
        Print (stdout, 1, "  %s\n", Name);
        ExpInsert (Name, O);
    }
}
Esempio n. 19
0
static void ConvertExports (FILE* F, const O65Data* D)
/* Convert the exports */
{
    unsigned I;

    if (CollCount (&D->Exports) > 0) {
        for (I = 0; I < CollCount (&D->Exports); ++I) {

            /* Get the next import */
            const O65Export* Export = CollConstAt (&D->Exports, I);

            /* First define it */
            fprintf (F, "%s = %s\n",
                     Export->Name,
                     RelocExpr (D, Export->SegID, Export->Val, 0));

            /* Then export it by name */
            fprintf (F, ".export\t%s\n", Export->Name);
        }
        fprintf (F, "\n");
    }
}
Esempio n. 20
0
void WriteFiles (void)
/* Write the list of input files to the object file */
{
    unsigned I;

    /* Tell the obj file module that we're about to start the file list */
    ObjStartFiles ();

    /* Write the file count */
    ObjWriteVar (CollCount (&FileTab));

    /* Write the file data */
    for (I = 0; I < CollCount (&FileTab); ++I) {
        /* Get a pointer to the entry */
        const FileEntry* F = CollConstAt (&FileTab, I);
        /* Write the fields */
        ObjWriteVar (F->Name);
        ObjWrite32 (F->MTime);
        ObjWriteVar (F->Size);
    }

    /* Done writing files */
    ObjEndFiles ();
}
Esempio n. 21
0
static void ConvertSeg (FILE* F, const O65Data* D, const Collection* Relocs,
                        const unsigned char* Data, unsigned long Size)
/* Convert one segment */
{
    const O65Reloc* R;
    unsigned        RIdx;
    unsigned long   Byte;

    /* Get the pointer to the first relocation entry if there are any */
    R = (CollCount (Relocs) > 0)? CollConstAt (Relocs, 0) : 0;

    /* Initialize for the loop */
    RIdx = 0;
    Byte = 0;

    /* Walk over the segment data */
    while (Byte < Size) {

        if (R && R->Offs == Byte) {
            /* We've reached an entry that must be relocated */
            unsigned long Val;
            switch (R->Type) {

                case O65_RTYPE_WORD:
                    if (Byte >= Size - 1) {
                        Error ("Found WORD relocation, but not enough bytes left");
                    } else {
                        Val = (Data[Byte+1] << 8) + Data[Byte];
                        Byte += 2;
                        fprintf (F, "\t.word\t%s\n", RelocExpr (D, R->SegID, Val, R));
                    }
                    break;

                case O65_RTYPE_HIGH:
                    Val = (Data[Byte++] << 8) + R->Val;
                    fprintf (F, "\t.byte\t>(%s)\n", RelocExpr (D, R->SegID, Val, R));
                    break;

                case O65_RTYPE_LOW:
                    Val = Data[Byte++];
                    fprintf (F, "\t.byte\t<(%s)\n", RelocExpr (D, R->SegID, Val, R));
                    break;

                case O65_RTYPE_SEGADDR:
                    if (Byte >= Size - 2) {
                        Error ("Found SEGADDR relocation, but not enough bytes left");
                    } else {
                        Val = (((unsigned long) Data[Byte+2]) << 16) +
                              (((unsigned long) Data[Byte+1]) <<  8) +
                              (((unsigned long) Data[Byte+0]) <<  0) +
                              R->Val;
                        Byte += 3;
                        fprintf (F, "\t.faraddr\t%s\n", RelocExpr (D, R->SegID, Val, R));
                    }
                    break;

                case O65_RTYPE_SEG:
                    /* FALLTHROUGH for now */
                default:
                    Internal ("Cannot handle relocation type %d at %lu",
                              R->Type, Byte);
            }

            /* Get the next relocation entry */
            if (++RIdx < CollCount (Relocs)) {
                R = CollConstAt (Relocs, RIdx);
            } else {
                R = 0;
            }

        } else {
            /* Just a constant value */
            fprintf (F, "\t.byte\t$%02X\n", Data[Byte++]);
        }
    }

    fprintf (F, "\n");
}
Esempio n. 22
0
void Convert (const O65Data* D)
/* Convert the o65 file in D using the given output file. */
{
    FILE*       F;
    unsigned    I;
    char*       Author = 0;

    /* For now, we do only accept o65 files generated by the ld65 linker which
     * have a specific format.
     */
    if (!Debug && D->Header.mode != O65_MODE_CC65) {
        Error ("Cannot convert o65 files of this type");
    }

    /* Output statistics */
    PrintO65Stats (D);

    /* Walk through the options and print them if verbose mode is enabled.
     * Check for a os=cc65 option and bail out if we didn't find one (for
     * now - later we switch to special handling).
     */
    for (I = 0; I < CollCount (&D->Options); ++I) {

        /* Get the next option */
        const O65Option* O = CollConstAt (&D->Options, I);

        /* Check the type of the option */
        switch (O->Type) {

            case O65_OPT_FILENAME:
                Print (stdout, 1, "O65 filename option:         `%s'\n",
                       GetO65OptionText (O));
                break;

            case O65_OPT_OS:
                if (O->Len == 2) {
                    Warning ("Operating system option without data found");
                } else {
                    Print (stdout, 1, "O65 operating system option: `%s'\n",
                           GetO65OSName (O->Data[0]));
                    switch (O->Data[0]) {
                        case O65_OS_CC65_MODULE:
                            if (Model != O65_MODEL_NONE &&
                                Model != O65_MODEL_CC65_MODULE) {
                                Warning ("Wrong o65 model for input file specified");
                            } else {
                                Model = O65_MODEL_CC65_MODULE;
                            }
                            break;
                    }
                }
                break;

            case O65_OPT_ASM:
                Print (stdout, 1, "O65 assembler option:        `%s'\n",
                       GetO65OptionText (O));
                break;

            case O65_OPT_AUTHOR:
                if (Author) {
                    xfree (Author);
                }
                Author = xstrdup (GetO65OptionText (O));
                Print (stdout, 1, "O65 author option:           `%s'\n", Author);
                break;

            case O65_OPT_TIMESTAMP:
                Print (stdout, 1, "O65 timestamp option:        `%s'\n",
                       GetO65OptionText (O));
                break;

            default:
                Warning ("Found unknown option, type %d, length %d",
                         O->Type, O->Len);
                break;
        }
    }

    /* If we shouldn't generate output, we're done here */
    if (NoOutput) {
        return;
    }

    /* Open the output file */
    F = fopen (OutputName, "w");
    if (F == 0) {
        Error ("Cannot open `%s': %s", OutputName, strerror (errno));
    }

    /* Create a header */
    fprintf (F, ";\n; File generated by co65 v %s using model `%s'\n;\n",
             GetVersionAsString (), GetModelName (Model));

    /* Select the CPU */
    if ((D->Header.mode & O65_CPU_MASK) == O65_CPU_65816) {
    	fprintf (F, ".p816\n");
    }

    /* Object file options */
    fprintf (F, ".fopt\t\tcompiler,\"co65 v %s\"\n", GetVersionAsString ());
    if (Author) {
        fprintf (F, ".fopt\t\tauthor, \"%s\"\n", Author);
        xfree (Author);
        Author = 0;
    }

    /* Several other assembler options */
    fprintf (F, ".case\t\ton\n");
    fprintf (F, ".debuginfo\t%s\n", (DebugInfo != 0)? "on" : "off");

    /* Setup/export the segment labels */
    SetupSegLabels (F);

    /* End of header */
    fprintf (F, "\n");

    /* Imported identifiers */
    ConvertImports (F, D);

    /* Exported identifiers */
    ConvertExports (F, D);

    /* Code segment */
    ConvertCodeSeg (F, D);

    /* Data segment */
    ConvertDataSeg (F, D);

    /* BSS segment */
    ConvertBssSeg (F, D);

    /* Zero page segment */
    ConvertZeropageSeg (F, D);

    /* End of data */
    fprintf (F, ".end\n");
    fclose (F);
}
Esempio n. 23
0
void CS_Output (CodeSeg* S)
/* Output the code segment data to the output file */
{
    unsigned I;
    const LineInfo* LI;

    /* Get the number of entries in this segment */
    unsigned Count = CS_GetEntryCount (S);

    /* If the code segment is empty, bail out here */
    if (Count == 0) {
	return;
    }

    /* Generate register info */
    CS_GenRegInfo (S);

    /* Output the segment directive */
    WriteOutput (".segment\t\"%s\"\n\n", S->SegName);

    /* Output all entries, prepended by the line information if it has changed */
    LI = 0;
    for (I = 0; I < Count; ++I) {
    	/* Get the next entry */
    	const CodeEntry* E = CollConstAt (&S->Entries, I);
    	/* Check if the line info has changed. If so, output the source line
    	 * if the option is enabled and output debug line info if the debug
    	 * option is enabled.
    	 */
    	if (E->LI != LI) {
    	    /* Line info has changed, remember the new line info */
    	    LI = E->LI;

    	    /* Add the source line as a comment. Beware: When line continuation
             * was used, the line may contain newlines.
             */
    	    if (AddSource) {
                const char* L = LI->Line;
                WriteOutput (";\n; ");
                while (*L) {
                    const char* N = strchr (L, '\n');
                    if (N) {
                        /* We have a newline, just write the first part */
                        WriteOutput ("%.*s\n; ", (int) (N - L), L);
                        L = N+1;
                    } else {
                        /* No Newline, write as is */
                        WriteOutput ("%s\n", L);
                        break;
                    }
                }
                WriteOutput (";\n");
    	    }

    	    /* Add line debug info */
	    if (DebugInfo) {
	       	WriteOutput ("\t.dbg\tline, \"%s\", %u\n",
	       	      	     GetInputName (LI), GetInputLine (LI));
	    }
	}
	/* Output the code */
	CE_Output (E);
    }

    /* If debug info is enabled, terminate the last line number information */
    if (DebugInfo) {
       	WriteOutput ("\t.dbg\tline\n");
    }

    /* Free register info */
    CS_FreeRegInfo (S);
}