]> git.sur5r.net Git - cc65/blobdiff - src/ld65/config.c
Ignore module.inc
[cc65] / src / ld65 / config.c
index 314fc235c10c7370f2a981c81830b8292df205c8..6e310a8d52ef41090c1799914d5166d65cb40793 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/* (C) 1998-2002 Ullrich von Bassewitz                                       */
 /*               Wacholderweg 14                                             */
 /*               D-70597 Stuttgart                                           */
 /* EMail:        uz@musoftware.de                                            */
@@ -41,6 +41,7 @@
 /* common */
 #include "check.h"
 #include "bitops.h"
+#include "print.h"
 #include "xmalloc.h"
 
 /* ld65 */
@@ -103,17 +104,6 @@ unsigned           SegDescCount;   /* Number of entries in list */
 static BinDesc*        BinFmtDesc      = 0;
 static O65Desc* O65FmtDesc     = 0;
 
-/* Attributes for the o65 format */
-static unsigned O65Attr        = 0;
-#define OA_OS          0x0001
-#define OA_TYPE                0x0002
-#define OA_VERSION     0x0004
-#define OA_OSVERSION   0x0008
-#define OA_TEXT                0x0010
-#define OA_DATA                0x0020
-#define OA_BSS         0x0040
-#define OA_ZP          0x0080
-
 
 
 /*****************************************************************************/
@@ -618,20 +608,20 @@ static void ParseSegments (void)
 {
     static const IdentTok Attributes [] = {
                {   "LOAD",     CFGTOK_LOAD     },
-       {   "RUN",      CFGTOK_RUN      },
+       {   "RUN",      CFGTOK_RUN      },
         {   "TYPE",     CFGTOK_TYPE     },
         {   "ALIGN",    CFGTOK_ALIGN    },
         {   "DEFINE",   CFGTOK_DEFINE   },
-       {   "OFFSET",   CFGTOK_OFFSET   },
-       {   "START",    CFGTOK_START    },
+       {   "OFFSET",   CFGTOK_OFFSET   },
+       {   "START",    CFGTOK_START    },
     };
     static const IdentTok Types [] = {
-               {   "RO",       CFGTOK_RO       },
-               {   "RW",       CFGTOK_RW       },
-               {   "BSS",      CFGTOK_BSS      },
-       {   "ZP",       CFGTOK_ZP       },
-       {   "WP",       CFGTOK_WPROT    },
-       {   "WPROT",    CFGTOK_WPROT    },
+               {   "RO",       CFGTOK_RO       },
+               {   "RW",       CFGTOK_RW       },
+               {   "BSS",      CFGTOK_BSS      },
+       {   "ZP",       CFGTOK_ZP       },
+       {   "WP",       CFGTOK_WPROT    },
+       {   "WPROT",    CFGTOK_WPROT    },
     };
 
     unsigned Count;
@@ -801,20 +791,41 @@ static void ParseO65 (void)
 /* Parse the o65 format section */
 {
     static const IdentTok Attributes [] = {
-               {   "EXPORT",    CFGTOK_EXPORT          },
-       {   "IMPORT",    CFGTOK_IMPORT          },
-        {   "TYPE",      CFGTOK_TYPE           },
-               {   "OS",        CFGTOK_OS              },
+               {   "EXPORT",   CFGTOK_EXPORT           },
+       {   "IMPORT",   CFGTOK_IMPORT           },
+        {   "TYPE",     CFGTOK_TYPE            },
+               {   "OS",       CFGTOK_OS               },
+               {   "ID",       CFGTOK_ID               },
+               {   "VERSION",  CFGTOK_VERSION          },
     };
     static const IdentTok Types [] = {
-               {   "SMALL",     CFGTOK_SMALL           },
-               {   "LARGE",     CFGTOK_LARGE           },
+               {   "SMALL",    CFGTOK_SMALL            },
+               {   "LARGE",    CFGTOK_LARGE            },
     };
     static const IdentTok OperatingSystems [] = {
-               {   "LUNIX",     CFGTOK_LUNIX           },
-               {   "OSA65",     CFGTOK_OSA65           },
+               {   "LUNIX",    CFGTOK_LUNIX            },
+               {   "OSA65",    CFGTOK_OSA65            },
+        {   "CC65",     CFGTOK_CC65             },
     };
 
+    /* Bitmask to remember the attributes we got already */
+    enum {
+               atNone          = 0x0000,
+       atOS            = 0x0001,
+        atOSVersion     = 0x0002,
+       atType          = 0x0004,
+       atImport        = 0x0008,
+       atExport        = 0x0010,
+        atID            = 0x0020,
+        atVersion       = 0x0040
+    };
+    unsigned AttrFlags = atNone;
+
+    /* Remember the attributes read */
+    unsigned OS = 0;            /* Initialize to keep gcc happy */
+    unsigned Version = 0;
+
+    /* Read the attributes */
     while (CfgTok == CFGTOK_IDENT) {
 
        /* Map the identifier to a token */
@@ -830,46 +841,58 @@ static void ParseO65 (void)
        switch (AttrTok) {
 
            case CFGTOK_EXPORT:
+                /* Remember we had this token (maybe more than once) */
+                AttrFlags |= atExport;
                /* We expect an identifier */
                CfgAssureIdent ();
+               /* Check if the export symbol is also defined as an import. */
+               if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
+                   CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
+               }
                /* Check if we have this symbol defined already. The entry
                 * routine will check this also, but we get a more verbose
                 * error message when checking it here.
                 */
                if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
-                   CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
+                   CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
                }
                /* Insert the symbol into the table */
-               O65SetExport (O65FmtDesc, CfgSVal);
+               O65SetExport (O65FmtDesc, CfgSVal);
                break;
 
            case CFGTOK_IMPORT:
+                /* Remember we had this token (maybe more than once) */
+                AttrFlags |= atImport;
                /* We expect an identifier */
                CfgAssureIdent ();
-               /* Check if we have this symbol defined already. The entry
-                * routine will check this also, but we get a more verbose
-                * error message when checking it here.
-                */
-               if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
-                   CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
-               }
-               /* Insert the symbol into the table */
-               O65SetImport (O65FmtDesc, CfgSVal);
+               /* Check if the imported symbol is also defined as an export. */
+               if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
+                   CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
+               }
+               /* Check if we have this symbol defined already. The entry
+                * routine will check this also, but we get a more verbose
+                * error message when checking it here.
+                */
+               if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
+                   CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
+               }
+               /* Insert the symbol into the table */
+               O65SetImport (O65FmtDesc, CfgSVal);
                break;
 
            case CFGTOK_TYPE:
                /* Cannot have this attribute twice */
-               FlagAttr (&O65Attr, OA_TYPE, "TYPE");
+               FlagAttr (&AttrFlags, atType, "TYPE");
                /* Get the type of the executable */
                CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
                switch (CfgTok) {
 
                    case CFGTOK_SMALL:
-                       /* Default, nothing to do */
+                       O65SetSmallModel (O65FmtDesc);
                        break;
 
                    case CFGTOK_LARGE:
-                       O65SetLargeModel (O65FmtDesc);
+                       O65SetLargeModel (O65FmtDesc);
                        break;
 
                    default:
@@ -879,24 +902,35 @@ static void ParseO65 (void)
 
            case CFGTOK_OS:
                /* Cannot use this attribute twice */
-               FlagAttr (&O65Attr, OA_OS, "OS");
+               FlagAttr (&AttrFlags, atOS, "OS");
                /* Get the operating system */
                CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
                switch (CfgTok) {
-
-                   case CFGTOK_LUNIX:
-                       O65SetOS (O65FmtDesc, O65OS_LUNIX);
-                       break;
-
-                   case CFGTOK_OSA65:
-                       O65SetOS (O65FmtDesc, O65OS_OSA65);
-                       break;
-
-                   default:
-                       CfgError ("Unexpected OS token");
+                   case CFGTOK_LUNIX:  OS = O65OS_LUNIX;       break;
+                   case CFGTOK_OSA65:  OS = O65OS_OSA65;       break;
+                   case CFGTOK_CC65:   OS = O65OS_CC65;        break;
+                   default:            CfgError ("Unexpected OS token");
                }
                break;
 
+            case CFGTOK_ID:
+                /* Cannot have this attribute twice */
+                FlagAttr (&AttrFlags, atID, "ID");
+                /* We're expecting a number in the 0..$FFFF range*/
+                CfgAssureInt ();
+                CfgRangeCheck (0, 0xFFFF);
+                ModuleId = (unsigned) CfgIVal;
+                break;
+
+            case CFGTOK_VERSION:
+                /* Cannot have this attribute twice */
+                FlagAttr (&AttrFlags, atVersion, "VERSION");
+                /* We're expecting a number in byte range */
+                CfgAssureInt ();
+                CfgRangeCheck (0, 0xFF);
+                Version = (unsigned) CfgIVal;
+                break;
+
            default:
                FAIL ("Unexpected attribute token");
 
@@ -906,6 +940,23 @@ static void ParseO65 (void)
        CfgNextTok ();
        CfgOptionalComma ();
     }
+
+    /* Check if we have all mandatory attributes */
+    AttrCheck (AttrFlags, atOS, "OS");
+
+    /* Check for attributes that may not be combined */
+    if (OS == O65OS_CC65) {
+        if ((AttrFlags & (atImport | atExport)) != 0) {
+            CfgError ("OS type CC65 may not have imports or exports");
+        }
+    } else {
+        if (AttrFlags & atID) {
+            CfgError ("Operating system does not support the ID attribute");
+        }
+    }
+
+    /* Set the O65 operating system to use */
+    O65SetOS (O65FmtDesc, OS, Version, ModuleId);
 }
 
 
@@ -956,9 +1007,11 @@ static void ParseConDes (void)
 /* Parse the CONDES feature */
 {
     static const IdentTok Attributes [] = {
-               {   "SEGMENT",          CFGTOK_SEGMENT          },
-       {   "LABEL",            CFGTOK_LABEL            },
-       {   "TYPE",             CFGTOK_TYPE             },
+               {   "SEGMENT",          CFGTOK_SEGMENT          },
+       {   "LABEL",            CFGTOK_LABEL            },
+       {   "COUNT",            CFGTOK_COUNT            },
+       {   "TYPE",             CFGTOK_TYPE             },
+       {   "ORDER",            CFGTOK_ORDER            },
     };
 
     static const IdentTok Types [] = {
@@ -966,17 +1019,27 @@ static void ParseConDes (void)
        {   "DESTRUCTOR",       CFGTOK_DESTRUCTOR       },
     };
 
+    static const IdentTok Orders [] = {
+       {   "DECREASING",       CFGTOK_DECREASING       },
+               {   "INCREASING",       CFGTOK_INCREASING       },
+    };
+
     /* Attribute values. */
     char SegName[sizeof (CfgSVal)];
     char Label[sizeof (CfgSVal)];
-    int Type = -1;     /* Initialize to avoid gcc warnings */
+    char Count[sizeof (CfgSVal)];
+    /* Initialize to avoid gcc warnings: */
+    int Type = -1;
+    ConDesOrder Order = cdIncreasing;
 
     /* Bitmask to remember the attributes we got already */
     enum {
        atNone          = 0x0000,
        atSegName       = 0x0001,
        atLabel         = 0x0002,
-       atType          = 0x0004
+       atCount         = 0x0004,
+       atType          = 0x0008,
+       atOrder         = 0x0010
     };
     unsigned AttrFlags = atNone;
 
@@ -1013,6 +1076,14 @@ static void ParseConDes (void)
                strcpy (Label, CfgSVal);
                break;
 
+           case CFGTOK_COUNT:
+               /* Don't allow this twice */
+               FlagAttr (&AttrFlags, atCount, "COUNT");
+               /* We expect an identifier */
+               CfgAssureIdent ();
+               /* Remember the value for later */
+               strcpy (Count, CfgSVal);
+               break;
 
            case CFGTOK_TYPE:
                /* Don't allow this twice */
@@ -1031,6 +1102,17 @@ static void ParseConDes (void)
                }
                break;
 
+           case CFGTOK_ORDER:
+               /* Don't allow this twice */
+               FlagAttr (&AttrFlags, atOrder, "ORDER");
+               CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
+               switch (CfgTok) {
+                   case CFGTOK_DECREASING: Order = cdDecreasing;       break;
+                   case CFGTOK_INCREASING: Order = cdIncreasing;       break;
+                   default: FAIL ("Unexpected order token");
+               }
+               break;
+
            default:
                FAIL ("Unexpected attribute token");
 
@@ -1060,6 +1142,12 @@ static void ParseConDes (void)
     /* Define the attributes */
     ConDesSetSegName (Type, SegName);
     ConDesSetLabel (Type, Label);
+    if (AttrFlags & atCount) {
+       ConDesSetCountSym (Type, Count);
+    }
+    if (AttrFlags & atOrder) {
+       ConDesSetOrder (Type, Order);
+    }
 }
 
 
@@ -1100,6 +1188,36 @@ static void ParseFeatures (void)
 
 
 
+static void ParseSymbols (void)
+/* Parse a symbols section */
+{
+    while (CfgTok == CFGTOK_IDENT) {
+
+       long Val;
+
+       /* Remember the name */
+       char Name [sizeof (CfgSVal)];
+       strcpy (Name, CfgSVal);
+       CfgNextTok ();
+
+       /* Allow an optional assignment */
+       CfgOptionalAssign ();
+
+       /* Make sure the next token is an integer, read and skip it */
+       CfgAssureInt ();
+       Val = CfgIVal;
+       CfgNextTok ();
+
+       /* Generate an export with the given value */
+       CreateConstExport (Name, Val);
+
+       /* Skip the semicolon */
+       CfgConsumeSemi ();
+    }
+}
+
+
+
 static void ParseConfig (void)
 /* Parse the config file */
 {
@@ -1109,6 +1227,7 @@ static void ParseConfig (void)
         {   "SEGMENTS", CFGTOK_SEGMENTS },
        {   "FORMATS",  CFGTOK_FORMATS  },
        {   "FEATURES", CFGTOK_FEATURES },
+       {   "SYMBOLS",  CFGTOK_SYMBOLS  },
     };
     cfgtok_t BlockTok;
 
@@ -1145,6 +1264,10 @@ static void ParseConfig (void)
                ParseFeatures ();
                break;
 
+           case CFGTOK_SYMBOLS:
+               ParseSymbols ();
+               break;
+
            default:
                FAIL ("Unexpected block token");
 
@@ -1330,48 +1453,56 @@ void CfgWriteTarget (void)
     /* Walk through the files list */
     File* F = FileList;
     while (F) {
-       /* We don't need to look at files with no memory areas */
-       if (F->MemList) {
+       /* We don't need to look at files with no memory areas */
+       if (F->MemList) {
 
-           /* Is there an output file? */
-           if (strlen (F->Name) > 0) {
+           /* Is there an output file? */
+           if (strlen (F->Name) > 0) {
 
-               /* Assign a proper binary format */
-               if (F->Format == BINFMT_DEFAULT) {
-                   F->Format = DefaultBinFmt;
+               /* Assign a proper binary format */
+               if (F->Format == BINFMT_DEFAULT) {
+                   F->Format = DefaultBinFmt;
                }
 
                /* Call the apropriate routine for the binary format */
-               switch (F->Format) {
+               switch (F->Format) {
 
-                   case BINFMT_BINARY:
-                       BinWriteTarget (BinFmtDesc, F);
-                       break;
+                   case BINFMT_BINARY:
+                       BinWriteTarget (BinFmtDesc, F);
+                       break;
 
-                   case BINFMT_O65:
-                       O65WriteTarget (O65FmtDesc, F);
-                       break;
+                   case BINFMT_O65:
+                       O65WriteTarget (O65FmtDesc, F);
+                       break;
 
-                   default:
-                       Internal ("Invalid binary format: %u", F->Format);
+                   default:
+                       Internal ("Invalid binary format: %u", F->Format);
 
-               }
+               }
+
+           } else {
+
+               /* No output file. Walk through the list and mark all segments
+                        * loading into these memory areas in this file as dumped.
+                */
+               M = F->MemList;
+               while (M) {
+
+                   MemListNode* N;
+
+                   /* Debugging */
+                           Print (stdout, 2, "Skipping `%s'...\n", M->Name);
+
+                   /* Walk throught the segments */
+                   N = M->SegList;
+                   while (N) {
+                       if (N->Seg->Load == M) {
+                           /* Load area - mark the segment as dumped */
+                           N->Seg->Seg->Dumped = 1;
+                       }
 
-           } else {
-
-               /* No output file. Walk through the list and mark all segments
-                * assigned to the memory areas in this file as dumped.
-                */
-               M = F->MemList;
-               while (M) {
-                   /* Walk throught the segments */
-                   MemListNode* N = M->SegList;
-                   while (N) {
-                       /* Mark the segment as dumped */
-                               N->Seg->Seg->Dumped = 1;
-
-                       /* Next segment node */
-                       N = N->Next;
+                       /* Next segment node */
+                       N = N->Next;
                    }
                    /* Next memory area */
                    M = M->FNext;