]> git.sur5r.net Git - cc65/blobdiff - src/da65/infofile.c
Style and alignment fixes.
[cc65] / src / da65 / infofile.c
index 44a6f9e1f1ea11c75f24930ba79aa285b9a26d31..6db82cb362c1f8ac86ac02497aded79370896b2a 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2000-2005 Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 2000-2014, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
@@ -35,6 +35,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <limits.h>
 #if defined(_MSC_VER)
 /* Microsoft compiler */
 #  include <io.h>
 /* da65 */
 #include "asminc.h"
 #include "attrtab.h"
+#include "comments.h"
 #include "error.h"
 #include "global.h"
 #include "infofile.h"
+#include "labels.h"
 #include "opctable.h"
 #include "scanner.h"
+#include "segment.h"
+#include "handler.h"
 
 
 
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                                   Code                                    */
 /*****************************************************************************/
 
 
@@ -76,19 +81,123 @@ static void AddAttr (const char* Name, unsigned* Set, unsigned Attr)
 
 
 
+static void AsmIncSection (void)
+/* Parse a asminc section */
+{
+    static const IdentTok LabelDefs[] = {
+        {   "COMMENTSTART",     INFOTOK_COMMENTSTART    },
+        {   "FILE",             INFOTOK_FILE            },
+        {   "IGNOREUNKNOWN",    INFOTOK_IGNOREUNKNOWN   },
+    };
+
+    /* Locals - initialize to avoid gcc warnings */
+    char* Name = 0;
+    int CommentStart = EOF;
+    int IgnoreUnknown = -1;
+
+    /* Skip the token */
+    InfoNextTok ();
+
+    /* Expect the opening curly brace */
+    InfoConsumeLCurly ();
+
+    /* Look for section tokens */
+    while (InfoTok != INFOTOK_RCURLY) {
+
+        /* Convert to special token */
+        InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Asminc directive");
+
+        /* Look at the token */
+        switch (InfoTok) {
+
+            case INFOTOK_COMMENTSTART:
+                InfoNextTok ();
+                if (CommentStart != EOF) {
+                    InfoError ("Commentstart already given");
+                }
+                InfoAssureChar ();
+                CommentStart = (char) InfoIVal;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_FILE:
+                InfoNextTok ();
+                if (Name) {
+                    InfoError ("File name already given");
+                }
+                InfoAssureStr ();
+                if (InfoSVal[0] == '\0') {
+                    InfoError ("File name may not be empty");
+                }
+                Name = xstrdup (InfoSVal);
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_IGNOREUNKNOWN:
+                InfoNextTok ();
+                if (IgnoreUnknown != -1) {
+                    InfoError ("Ignoreunknown already specified");
+                }
+                InfoBoolToken ();
+                IgnoreUnknown = (InfoTok != INFOTOK_FALSE);
+                InfoNextTok ();
+                break;
+
+            default:
+                Internal ("Unexpected token: %u", InfoTok);
+        }
+
+        /* Directive is followed by a semicolon */
+        InfoConsumeSemi ();
+    }
+
+    /* Check for the necessary data and assume defaults */
+    if (Name == 0) {
+        InfoError ("File name is missing");
+    }
+    if (CommentStart == EOF) {
+        CommentStart = ';';
+    }
+    if (IgnoreUnknown == -1) {
+        IgnoreUnknown = 0;
+    }
+
+    /* Open the file and read the symbol definitions */
+    AsmInc (Name, CommentStart, IgnoreUnknown);
+
+    /* Delete the dynamically allocated memory for Name */
+    xfree (Name);
+
+    /* Consume the closing brace */
+    InfoConsumeRCurly ();
+}
+
+
+
 static void GlobalSection (void)
 /* Parse a global section */
 {
     static const IdentTok GlobalDefs[] = {
+        {   "ARGUMENTCOL",      INFOTOK_ARGUMENT_COLUMN },
+        {   "ARGUMENTCOLUMN",   INFOTOK_ARGUMENT_COLUMN },
+        {   "COMMENTCOL",       INFOTOK_COMMENT_COLUMN  },
+        {   "COMMENTCOLUMN",    INFOTOK_COMMENT_COLUMN  },
         {   "COMMENTS",         INFOTOK_COMMENTS        },
-               {   "CPU",              INFOTOK_CPU             },
+        {   "CPU",              INFOTOK_CPU             },
         {   "HEXOFFS",          INFOTOK_HEXOFFS         },
-               {   "INPUTNAME",        INFOTOK_INPUTNAME       },
+        {   "INPUTNAME",        INFOTOK_INPUTNAME       },
         {   "INPUTOFFS",        INFOTOK_INPUTOFFS       },
         {   "INPUTSIZE",        INFOTOK_INPUTSIZE       },
-       {   "OUTPUTNAME",       INFOTOK_OUTPUTNAME      },
-       {   "PAGELENGTH",       INFOTOK_PAGELENGTH      },
-       {   "STARTADDR",        INFOTOK_STARTADDR       },
+        {   "LABELBREAK",       INFOTOK_LABELBREAK      },
+        {   "MNEMONICCOL",      INFOTOK_MNEMONIC_COLUMN },
+        {   "MNEMONICCOLUMN",   INFOTOK_MNEMONIC_COLUMN },
+        {   "NEWLINEAFTERJMP",  INFOTOK_NL_AFTER_JMP    },
+        {   "NEWLINEAFTERRTS",  INFOTOK_NL_AFTER_RTS    },
+        {   "OUTPUTNAME",       INFOTOK_OUTPUTNAME      },
+        {   "PAGELENGTH",       INFOTOK_PAGELENGTH      },
+        {   "STARTADDR",        INFOTOK_STARTADDR       },
+        {   "TEXTCOL",          INFOTOK_TEXT_COLUMN     },
+        {   "TEXTCOLUMN",       INFOTOK_TEXT_COLUMN     },
     };
 
     /* Skip the token */
@@ -100,19 +209,35 @@ static void GlobalSection (void)
     /* Look for section tokens */
     while (InfoTok != INFOTOK_RCURLY) {
 
-       /* Convert to special token */
-               InfoSpecialToken (GlobalDefs, ENTRY_COUNT (GlobalDefs), "Global directive");
+        /* Convert to special token */
+        InfoSpecialToken (GlobalDefs, ENTRY_COUNT (GlobalDefs), "Global directive");
 
-       /* Look at the token */
-       switch (InfoTok) {
+        /* Look at the token */
+        switch (InfoTok) {
+
+            case INFOTOK_ARGUMENT_COLUMN:
+                InfoNextTok ();
+                InfoAssureInt ();
+                InfoRangeCheck (MIN_ACOL, MAX_ACOL);
+                ACol = InfoIVal;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_COMMENT_COLUMN:
+                InfoNextTok ();
+                InfoAssureInt ();
+                InfoRangeCheck (MIN_CCOL, MAX_CCOL);
+                CCol = InfoIVal;
+                InfoNextTok ();
+                break;
 
             case INFOTOK_COMMENTS:
-               InfoNextTok ();
-               InfoAssureInt ();
+                InfoNextTok ();
+                InfoAssureInt ();
                 InfoRangeCheck (MIN_COMMENTS, MAX_COMMENTS);
-               Comments = InfoIVal;
-               InfoNextTok ();
-               break;
+                Comments = InfoIVal;
+                InfoNextTok ();
+                break;
 
             case INFOTOK_CPU:
                 InfoNextTok ();
@@ -135,66 +260,257 @@ static void GlobalSection (void)
                 InfoNextTok ();
                 break;
 
-           case INFOTOK_INPUTNAME:
-               InfoNextTok ();
-               InfoAssureStr ();
-               if (InFile) {
-                   InfoError ("Input file name already given");
-               }
-               InFile = xstrdup (InfoSVal);
-               InfoNextTok ();
-               break;
+            case INFOTOK_INPUTNAME:
+                InfoNextTok ();
+                InfoAssureStr ();
+                if (InFile) {
+                    InfoError ("Input file name already given");
+                }
+                InFile = xstrdup (InfoSVal);
+                InfoNextTok ();
+                break;
 
             case INFOTOK_INPUTOFFS:
-               InfoNextTok ();
-               InfoAssureInt ();
-               InputOffs = InfoIVal;
-               InfoNextTok ();
-               break;
+                InfoNextTok ();
+                InfoAssureInt ();
+                InputOffs = InfoIVal;
+                InfoNextTok ();
+                break;
 
             case INFOTOK_INPUTSIZE:
-               InfoNextTok ();
-               InfoAssureInt ();
+                InfoNextTok ();
+                InfoAssureInt ();
+                InfoRangeCheck (1, 0x10000);
+                InputSize = InfoIVal;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_LABELBREAK:
+                InfoNextTok ();
+                InfoAssureInt ();
+                InfoRangeCheck (0, UCHAR_MAX);
+                LBreak = (unsigned char) InfoIVal;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_MNEMONIC_COLUMN:
+                InfoNextTok ();
+                InfoAssureInt ();
+                InfoRangeCheck (MIN_MCOL, MAX_MCOL);
+                MCol = InfoIVal;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_NL_AFTER_JMP:
+                InfoNextTok ();
+                if (NewlineAfterJMP != -1) {
+                    InfoError ("NLAfterJMP already specified");
+                }
+                InfoBoolToken ();
+                NewlineAfterJMP = (InfoTok != INFOTOK_FALSE);
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_NL_AFTER_RTS:
+                InfoNextTok ();
+                InfoBoolToken ();
+                if (NewlineAfterRTS != -1) {
+                    InfoError ("NLAfterRTS already specified");
+                }
+                NewlineAfterRTS = (InfoTok != INFOTOK_FALSE);
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_OUTPUTNAME:
+                InfoNextTok ();
+                InfoAssureStr ();
+                if (OutFile) {
+                    InfoError ("Output file name already given");
+                }
+                OutFile = xstrdup (InfoSVal);
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_PAGELENGTH:
+                InfoNextTok ();
+                InfoAssureInt ();
+                if (InfoIVal != 0) {
+                    InfoRangeCheck (MIN_PAGE_LEN, MAX_PAGE_LEN);
+                }
+                PageLength = InfoIVal;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_STARTADDR:
+                InfoNextTok ();
+                InfoAssureInt ();
+                InfoRangeCheck (0x0000, 0xFFFF);
+                StartAddr = InfoIVal;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_TEXT_COLUMN:
+                InfoNextTok ();
+                InfoAssureInt ();
+                InfoRangeCheck (MIN_TCOL, MAX_TCOL);
+                TCol = InfoIVal;
+                InfoNextTok ();
+                break;
+
+            default:
+                Internal ("Unexpected token: %u", InfoTok);
+
+        }
+
+        /* Directive is followed by a semicolon */
+        InfoConsumeSemi ();
+
+    }
+
+    /* Consume the closing brace */
+    InfoConsumeRCurly ();
+}
+
+
+
+static void LabelSection (void)
+/* Parse a label section */
+{
+    static const IdentTok LabelDefs[] = {
+        {   "COMMENT",      INFOTOK_COMMENT     },
+        {   "ADDR",         INFOTOK_ADDR        },
+        {   "NAME",         INFOTOK_NAME        },
+        {   "SIZE",         INFOTOK_SIZE        },
+        {   "PARAMSIZE",    INFOTOK_PARAMSIZE   },
+    };
+
+    /* Locals - initialize to avoid gcc warnings */
+    char* Name      = 0;
+    char* Comment   = 0;
+    long Value      = -1;
+    long Size       = -1;
+    long ParamSize  = -1;
+
+    /* Skip the token */
+    InfoNextTok ();
+
+    /* Expect the opening curly brace */
+    InfoConsumeLCurly ();
+
+    /* Look for section tokens */
+    while (InfoTok != INFOTOK_RCURLY) {
+
+        /* Convert to special token */
+        InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label attribute");
+
+        /* Look at the token */
+        switch (InfoTok) {
+
+            case INFOTOK_ADDR:
+                InfoNextTok ();
+                if (Value >= 0) {
+                    InfoError ("Value already given");
+                }
+                InfoAssureInt ();
+                InfoRangeCheck (0, 0xFFFF);
+                Value = InfoIVal;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_COMMENT:
+                InfoNextTok ();
+                if (Comment) {
+                    InfoError ("Comment already given");
+                }
+                InfoAssureStr ();
+                if (InfoSVal[0] == '\0') {
+                    InfoError ("Comment may not be empty");
+                }
+                Comment = xstrdup (InfoSVal);
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_NAME:
+                InfoNextTok ();
+                if (Name) {
+                    InfoError ("Name already given");
+                }
+                InfoAssureStr ();
+                Name = xstrdup (InfoSVal);
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_SIZE:
+                InfoNextTok ();
+                if (Size >= 0) {
+                    InfoError ("Size already given");
+                }
+                InfoAssureInt ();
                 InfoRangeCheck (1, 0x10000);
-               InputSize = InfoIVal;
-               InfoNextTok ();
-               break;
-
-           case INFOTOK_OUTPUTNAME:
-               InfoNextTok ();
-               InfoAssureStr ();
-               if (OutFile) {
-                   InfoError ("Output file name already given");
-               }
-               OutFile = xstrdup (InfoSVal);
-               InfoNextTok ();
-               break;
-
-           case INFOTOK_PAGELENGTH:
-               InfoNextTok ();
-               InfoAssureInt ();
-               if (InfoIVal != 0) {
-                   InfoRangeCheck (MIN_PAGE_LEN, MAX_PAGE_LEN);
-               }
-               PageLength = InfoIVal;
-               InfoNextTok ();
-               break;
-
-           case INFOTOK_STARTADDR:
-               InfoNextTok ();
-               InfoAssureInt ();
-               InfoRangeCheck (0x0000, 0xFFFF);
-               StartAddr = InfoIVal;
-               InfoNextTok ();
-               break;
-
-       }
-
-       /* Directive is followed by a semicolon */
-       InfoConsumeSemi ();
+                Size = InfoIVal;
+                InfoNextTok ();
+                break;
 
+            case INFOTOK_PARAMSIZE:
+                InfoNextTok ();
+                if (ParamSize >= 0) {
+                    InfoError ("ParamSize already given");
+                }
+                InfoAssureInt ();
+                InfoRangeCheck (1, 0x10000);
+                ParamSize = InfoIVal;
+                InfoNextTok ();
+                break;
+
+            default:
+                Internal ("Unexpected token: %u", InfoTok);
+        }
+
+        /* Directive is followed by a semicolon */
+        InfoConsumeSemi ();
     }
 
+    /* Did we get the necessary data */
+    if (Name == 0) {
+        InfoError ("Label name is missing");
+    }
+    if (Name[0] == '\0' && Size > 1) {
+        InfoError ("Unnamed labels must not have a size > 1");
+    }
+    if (Value < 0) {
+        InfoError ("Label value is missing");
+    }
+    if (Size < 0) {
+        /* Use default */
+        Size = 1;
+    }
+    if (Value + Size > 0x10000) {
+        InfoError ("Invalid size (address out of range)");
+    }
+    if (HaveLabel ((unsigned) Value)) {
+        InfoError ("Label for address $%04lX already defined", Value);
+    }
+
+    /* Define the label(s) */
+    if (Name[0] == '\0') {
+        /* Size has already beed checked */
+        AddUnnamedLabel (Value);
+    } else {
+        AddExtLabelRange ((unsigned) Value, Name, Size);
+    }
+    if (ParamSize >= 0) {
+        SetSubroutineParamSize ((unsigned) Value, (unsigned) ParamSize);
+    }
+
+    /* Define the comment */
+    if (Comment) {
+        SetComment (Value, Comment);
+    }
+
+    /* Delete the dynamically allocated memory for Name and Comment */
+    xfree (Name);
+    xfree (Comment);
+
     /* Consume the closing brace */
     InfoConsumeRCurly ();
 }
@@ -206,41 +522,41 @@ static void RangeSection (void)
 {
     static const IdentTok RangeDefs[] = {
         {   "COMMENT",          INFOTOK_COMMENT },
-       {   "END",              INFOTOK_END     },
+        {   "END",              INFOTOK_END     },
         {   "NAME",             INFOTOK_NAME    },
-               {   "START",            INFOTOK_START   },
-       {   "TYPE",             INFOTOK_TYPE    },
+        {   "START",            INFOTOK_START   },
+        {   "TYPE",             INFOTOK_TYPE    },
     };
 
     static const IdentTok TypeDefs[] = {
-       {   "ADDRTABLE",        INFOTOK_ADDRTAB  },
-       {   "BYTETABLE",        INFOTOK_BYTETAB  },
-       {   "CODE",             INFOTOK_CODE     },
+        {   "ADDRTABLE",        INFOTOK_ADDRTAB  },
+        {   "BYTETABLE",        INFOTOK_BYTETAB  },
+        {   "CODE",             INFOTOK_CODE     },
         {   "DBYTETABLE",       INFOTOK_DBYTETAB },
-       {   "DWORDTABLE",       INFOTOK_DWORDTAB },
-       {   "RTSTABLE",         INFOTOK_RTSTAB   },
+        {   "DWORDTABLE",       INFOTOK_DWORDTAB },
+        {   "RTSTABLE",         INFOTOK_RTSTAB   },
         {   "SKIP",             INFOTOK_SKIP     },
-       {   "TEXTTABLE",        INFOTOK_TEXTTAB  },
-       {   "WORDTABLE",        INFOTOK_WORDTAB  },
+        {   "TEXTTABLE",        INFOTOK_TEXTTAB  },
+        {   "WORDTABLE",        INFOTOK_WORDTAB  },
     };
 
 
     /* Which values did we get? */
     enum {
-       tNone   = 0x00,
-       tStart  = 0x01,
-       tEnd    = 0x02,
-       tType   = 0x04,
+        tNone   = 0x00,
+        tStart  = 0x01,
+        tEnd    = 0x02,
+        tType   = 0x04,
         tName   = 0x08,
         tComment= 0x10,
-               tNeeded = (tStart | tEnd | tType)
+        tNeeded = (tStart | tEnd | tType)
     };
     unsigned Attributes = tNone;
 
     /* Locals - initialize to avoid gcc warnings */
-    unsigned Start     = 0;
-    unsigned End       = 0;
-    unsigned char Type = 0;
+    unsigned Start      = 0;
+    unsigned End        = 0;
+    unsigned char Type  = 0;
     char* Name          = 0;
     char* Comment       = 0;
     unsigned MemberSize = 0;
@@ -255,91 +571,94 @@ static void RangeSection (void)
     /* Look for section tokens */
     while (InfoTok != INFOTOK_RCURLY) {
 
-       /* Convert to special token */
-               InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range directive");
+        /* Convert to special token */
+        InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range attribute");
 
-       /* Look at the token */
-       switch (InfoTok) {
+        /* Look at the token */
+        switch (InfoTok) {
 
-           case INFOTOK_COMMENT:
+            case INFOTOK_COMMENT:
                 AddAttr ("COMMENT", &Attributes, tComment);
-               InfoNextTok ();
-               InfoAssureStr ();
-               if (InfoSVal[0] == '\0') {
-                   InfoError ("Comment may not be empty");
-               }
-               Comment = xstrdup (InfoSVal);
+                InfoNextTok ();
+                InfoAssureStr ();
+                if (InfoSVal[0] == '\0') {
+                    InfoError ("Comment may not be empty");
+                }
+                Comment = xstrdup (InfoSVal);
                 Attributes |= tComment;
-               InfoNextTok ();
-               break;
+                InfoNextTok ();
+                break;
 
-           case INFOTOK_END:
+            case INFOTOK_END:
                 AddAttr ("END", &Attributes, tEnd);
-               InfoNextTok ();
-               InfoAssureInt ();
-               InfoRangeCheck (0x0000, 0xFFFF);
-               End = InfoIVal;
-               InfoNextTok ();
-               break;
-
-           case INFOTOK_NAME:
+                InfoNextTok ();
+                InfoAssureInt ();
+                InfoRangeCheck (0x0000, 0xFFFF);
+                End = InfoIVal;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_NAME:
                 AddAttr ("NAME", &Attributes, tName);
-               InfoNextTok ();
-               InfoAssureStr ();
-               if (InfoSVal[0] == '\0') {
-                   InfoError ("Name may not be empty");
-               }
-               Name = xstrdup (InfoSVal);
+                InfoNextTok ();
+                InfoAssureStr ();
+                if (InfoSVal[0] == '\0') {
+                    InfoError ("Name may not be empty");
+                }
+                Name = xstrdup (InfoSVal);
                 Attributes |= tName;
-               InfoNextTok ();
-               break;
+                InfoNextTok ();
+                break;
 
-           case INFOTOK_START:
+            case INFOTOK_START:
                 AddAttr ("START", &Attributes, tStart);
-               InfoNextTok ();
-               InfoAssureInt ();
-               InfoRangeCheck (0x0000, 0xFFFF);
-               Start = InfoIVal;
-               InfoNextTok ();
-               break;
-
-           case INFOTOK_TYPE:
+                InfoNextTok ();
+                InfoAssureInt ();
+                InfoRangeCheck (0x0000, 0xFFFF);
+                Start = InfoIVal;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_TYPE:
                 AddAttr ("TYPE", &Attributes, tType);
-               InfoNextTok ();
-               InfoSpecialToken (TypeDefs, ENTRY_COUNT (TypeDefs), "TYPE");
-               switch (InfoTok) {
-                   case INFOTOK_ADDRTAB:  Type = atAddrTab;  MemberSize = 2; break;
-                   case INFOTOK_BYTETAB:  Type = atByteTab;  MemberSize = 1; break;
-                   case INFOTOK_CODE:     Type = atCode;     MemberSize = 1; break;
+                InfoNextTok ();
+                InfoSpecialToken (TypeDefs, ENTRY_COUNT (TypeDefs), "TYPE");
+                switch (InfoTok) {
+                    case INFOTOK_ADDRTAB:  Type = atAddrTab;  MemberSize = 2; break;
+                    case INFOTOK_BYTETAB:  Type = atByteTab;  MemberSize = 1; break;
+                    case INFOTOK_CODE:     Type = atCode;     MemberSize = 1; break;
                     case INFOTOK_DBYTETAB: Type = atDByteTab; MemberSize = 2; break;
-                   case INFOTOK_DWORDTAB: Type = atDWordTab; MemberSize = 4; break;
-                           case INFOTOK_RTSTAB:   Type = atRtsTab;   MemberSize = 2; break;
+                    case INFOTOK_DWORDTAB: Type = atDWordTab; MemberSize = 4; break;
+                    case INFOTOK_RTSTAB:   Type = atRtsTab;   MemberSize = 2; break;
                     case INFOTOK_SKIP:     Type = atSkip;     MemberSize = 1; break;
-                   case INFOTOK_TEXTTAB:  Type = atTextTab;  MemberSize = 1; break;
-                   case INFOTOK_WORDTAB:  Type = atWordTab;  MemberSize = 2; break;
-               }
-               InfoNextTok ();
-               break;
-       }
+                    case INFOTOK_TEXTTAB:  Type = atTextTab;  MemberSize = 1; break;
+                    case INFOTOK_WORDTAB:  Type = atWordTab;  MemberSize = 2; break;
+                }
+                InfoNextTok ();
+                break;
 
-       /* Directive is followed by a semicolon */
-       InfoConsumeSemi ();
+            default:
+                Internal ("Unexpected token: %u", InfoTok);
+        }
+
+        /* Directive is followed by a semicolon */
+        InfoConsumeSemi ();
 
     }
 
     /* Did we get all required values? */
     if ((Attributes & tNeeded) != tNeeded) {
-       InfoError ("Required values missing from this section");
+        InfoError ("Required values missing from this section");
     }
 
     /* Start must be less than end */
     if (Start > End) {
-       InfoError ("Start value must not be greater than end value");
+        InfoError ("Start value must not be greater than end value");
     }
 
     /* Check the granularity */
     if (((End - Start + 1) % MemberSize) != 0) {
-       InfoError ("Type of range needs a granularity of %u", MemberSize);
+        InfoError ("Type of range needs a granularity of %u", MemberSize);
     }
 
     /* Set the range */
@@ -347,8 +666,15 @@ static void RangeSection (void)
 
     /* Do we have a label? */
     if (Attributes & tName) {
+
         /* Define a label for the table */
-        AddExtLabel (Start, Name, Comment);
+        AddExtLabel (Start, Name);
+
+        /* Set the comment if we have one */
+        if (Comment) {
+            SetComment (Start, Comment);
+        }
+
         /* Delete name and comment */
         xfree (Name);
         xfree (Comment);
@@ -360,135 +686,19 @@ static void RangeSection (void)
 
 
 
-static void LabelSection (void)
-/* Parse a label section */
-{
-    static const IdentTok LabelDefs[] = {
-               {   "COMMENT",  INFOTOK_COMMENT },
-       {   "ADDR",     INFOTOK_ADDR    },
-               {   "NAME",     INFOTOK_NAME    },
-               {   "SIZE",     INFOTOK_SIZE    },
-    };
-
-    /* Locals - initialize to avoid gcc warnings */
-    char* Name    = 0;
-    char* Comment = 0;
-    long Value    = -1;
-    long Size     = -1;
-
-    /* Skip the token */
-    InfoNextTok ();
-
-    /* Expect the opening curly brace */
-    InfoConsumeLCurly ();
-
-    /* Look for section tokens */
-    while (InfoTok != INFOTOK_RCURLY) {
-
-       /* Convert to special token */
-               InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label directive");
-
-       /* Look at the token */
-       switch (InfoTok) {
-
-           case INFOTOK_ADDR:
-               InfoNextTok ();
-               if (Value >= 0) {
-                   InfoError ("Value already given");
-               }
-               InfoAssureInt ();
-               InfoRangeCheck (0, 0xFFFF);
-               Value = InfoIVal;
-               InfoNextTok ();
-               break;
-
-           case INFOTOK_COMMENT:
-               InfoNextTok ();
-               if (Comment) {
-                   InfoError ("Comment already given");
-               }
-               InfoAssureStr ();
-               if (InfoSVal[0] == '\0') {
-                   InfoError ("Comment may not be empty");
-               }
-               Comment = xstrdup (InfoSVal);
-               InfoNextTok ();
-               break;
-
-           case INFOTOK_NAME:
-               InfoNextTok ();
-               if (Name) {
-                   InfoError ("Name already given");
-               }
-               InfoAssureStr ();
-               if (InfoSVal[0] == '\0') {
-                   InfoError ("Name may not be empty");
-               }
-               Name = xstrdup (InfoSVal);
-               InfoNextTok ();
-               break;
-
-           case INFOTOK_SIZE:
-               InfoNextTok ();
-               if (Size >= 0) {
-                   InfoError ("Size already given");
-               }
-               InfoAssureInt ();
-               InfoRangeCheck (1, 0x10000);
-               Size = InfoIVal;
-               InfoNextTok ();
-               break;
-
-       }
-
-       /* Directive is followed by a semicolon */
-       InfoConsumeSemi ();
-    }
-
-    /* Did we get the necessary data */
-    if (Name == 0) {
-       InfoError ("Label name is missing");
-    }
-    if (Value < 0) {
-       InfoError ("Label value is missing");
-    }
-    if (Size < 0) {
-       /* Use default */
-       Size = 1;
-    }
-    if (Value + Size > 0x10000) {
-       InfoError ("Invalid size (address out of range)");
-    }
-    if (HaveLabel ((unsigned) Value)) {
-       InfoError ("Label for address $%04lX already defined", Value);
-    }
-
-    /* Define the label(s) */
-    AddExtLabelRange ((unsigned) Value, Name, Comment, Size);
-
-    /* Delete the dynamically allocated memory for Name and Comment */
-    xfree (Name);
-    xfree (Comment);
-
-    /* Consume the closing brace */
-    InfoConsumeRCurly ();
-}
-
-
-
-static void AsmIncSection (void)
-/* Parse a asminc section */
+static void SegmentSection (void)
+/* Parse a segment section */
 {
     static const IdentTok LabelDefs[] = {
-        {   "COMMENTSTART",     INFOTOK_COMMENTSTART    },
-               {   "FILE",             INFOTOK_FILE            },
-        {   "IGNOREUNKNOWN",    INFOTOK_IGNOREUNKNOWN   },
+        {   "END",      INFOTOK_END     },
+        {   "NAME",     INFOTOK_NAME    },
+        {   "START",    INFOTOK_START   },
     };
 
     /* Locals - initialize to avoid gcc warnings */
-    char* Name = 0;
-    int CommentStart = EOF;
-    int IgnoreUnknown = -1;
+    long End    = -1;
+    long Start  = -1;
+    char* Name  = 0;
 
     /* Skip the token */
     InfoNextTok ();
@@ -499,63 +709,73 @@ static void AsmIncSection (void)
     /* Look for section tokens */
     while (InfoTok != INFOTOK_RCURLY) {
 
-       /* Convert to special token */
-               InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Asminc directive");
+        /* Convert to special token */
+        InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Segment attribute");
 
-       /* Look at the token */
-       switch (InfoTok) {
+        /* Look at the token */
+        switch (InfoTok) {
 
-            case INFOTOK_COMMENTSTART:
+            case INFOTOK_END:
                 InfoNextTok ();
-                if (CommentStart != EOF) {
-                    InfoError ("Commentstart already given");
+                if (End >= 0) {
+                    InfoError ("Value already given");
                 }
-                InfoAssureChar ();
-                CommentStart = (char) InfoIVal;
+                InfoAssureInt ();
+                InfoRangeCheck (0, 0xFFFF);
+                End = InfoIVal;
                 InfoNextTok ();
                 break;
 
-           case INFOTOK_FILE:
-               InfoNextTok ();
-               if (Name) {
-                   InfoError ("File name already given");
-               }
-               InfoAssureStr ();
-               if (InfoSVal[0] == '\0') {
-                   InfoError ("File name may not be empty");
-               }
-               Name = xstrdup (InfoSVal);
-               InfoNextTok ();
-               break;
+            case INFOTOK_NAME:
+                InfoNextTok ();
+                if (Name) {
+                    InfoError ("Name already given");
+                }
+                InfoAssureStr ();
+                Name = xstrdup (InfoSVal);
+                InfoNextTok ();
+                break;
 
-            case INFOTOK_IGNOREUNKNOWN:
+            case INFOTOK_START:
                 InfoNextTok ();
-                if (IgnoreUnknown != -1) {
-                    InfoError ("Ignoreunknown already specified");
+                if (Start >= 0) {
+                    InfoError ("Value already given");
                 }
-                InfoBoolToken ();
-                IgnoreUnknown = (InfoTok != INFOTOK_FALSE);
+                InfoAssureInt ();
+                InfoRangeCheck (0, 0xFFFF);
+                Start = InfoIVal;
                 InfoNextTok ();
                 break;
-       }
 
-       /* Directive is followed by a semicolon */
-       InfoConsumeSemi ();
+            default:
+                Internal ("Unexpected token: %u", InfoTok);
+        }
+
+        /* Directive is followed by a semicolon */
+        InfoConsumeSemi ();
     }
 
-    /* Check for the necessary data and assume defaults */
-    if (Name == 0) {
-       InfoError ("File name is missing");
+    /* Did we get the necessary data, and is it correct? */
+    if (Name == 0 || Name[0] == '\0') {
+        InfoError ("Segment name is missing");
     }
-    if (CommentStart == EOF) {
-       CommentStart = ';';
+    if (End < 0) {
+        InfoError ("End address is missing");
     }
-    if (IgnoreUnknown == -1) {
-        IgnoreUnknown = 0;
+    if (Start < 0) {
+        InfoError ("Start address is missing");
+    }
+    if (Start > End) {
+        InfoError ("Start address of segment is greater than end address");
     }
 
-    /* Open the file and read the symbol definitions */
-    AsmInc (Name, CommentStart, IgnoreUnknown);
+    /* Check that segments do not overlap */
+    if (SegmentDefined ((unsigned) Start, (unsigned) End)) {
+        InfoError ("Segments must not overlap");
+    }
+
+    /* Remember the segment data */
+    AddAbsSegment ((unsigned) Start, (unsigned) End, Name);
 
     /* Delete the dynamically allocated memory for Name */
     xfree (Name);
@@ -570,39 +790,47 @@ static void InfoParse (void)
 /* Parse the config file */
 {
     static const IdentTok Globals[] = {
-       {   "GLOBAL",   INFOTOK_GLOBAL  },
-       {   "RANGE",    INFOTOK_RANGE   },
-       {   "LABEL",    INFOTOK_LABEL   },
         {   "ASMINC",   INFOTOK_ASMINC  },
+        {   "GLOBAL",   INFOTOK_GLOBAL  },
+        {   "LABEL",    INFOTOK_LABEL   },
+        {   "RANGE",    INFOTOK_RANGE   },
+        {   "SEGMENT",  INFOTOK_SEGMENT },
     };
 
     while (InfoTok != INFOTOK_EOF) {
 
-       /* Convert an identifier into a token */
-       InfoSpecialToken (Globals, ENTRY_COUNT (Globals), "Config directive");
+        /* Convert an identifier into a token */
+        InfoSpecialToken (Globals, ENTRY_COUNT (Globals), "Config directive");
 
-       /* Check the token */
-       switch (InfoTok) {
+        /* Check the token */
+        switch (InfoTok) {
 
-           case INFOTOK_GLOBAL:
-               GlobalSection ();
-               break;
+            case INFOTOK_ASMINC:
+                AsmIncSection ();
+                break;
 
-           case INFOTOK_RANGE:
-               RangeSection ();
-               break;
+            case INFOTOK_GLOBAL:
+                GlobalSection ();
+                break;
 
-           case INFOTOK_LABEL:
-               LabelSection ();
-               break;
+            case INFOTOK_LABEL:
+                LabelSection ();
+                break;
 
-            case INFOTOK_ASMINC:
-                AsmIncSection ();
+            case INFOTOK_RANGE:
+                RangeSection ();
+                break;
+
+            case INFOTOK_SEGMENT:
+                SegmentSection ();
                 break;
-       }
 
-       /* Semicolon expected */
-       InfoConsumeSemi ();
+            default:
+                Internal ("Unexpected token: %u", InfoTok);
+        }
+
+        /* Semicolon expected */
+        InfoConsumeSemi ();
     }
 }
 
@@ -623,9 +851,3 @@ void ReadInfoFile (void)
         InfoCloseInput ();
     }
 }
-
-
-
-
-
-