]> git.sur5r.net Git - cc65/blobdiff - src/da65/infofile.c
Style and alignment fixes.
[cc65] / src / da65 / infofile.c
index 8cf95fcaf83d916f2a815013044327d797e6c65e..6db82cb362c1f8ac86ac02497aded79370896b2a 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2000-2003 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>
 #include "xmalloc.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                                    */
 /*****************************************************************************/
 
 
 
+static void AddAttr (const char* Name, unsigned* Set, unsigned Attr)
+/* Add an attribute to the set and check that it is not given twice */
+{
+    if (*Set & Attr) {
+        /* Attribute is already in the set */
+        InfoError ("%s given twice", Name);
+    }
+    *Set |= 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[] = {
-               {   "CPU",              INFOTOK_CPU             },
-               {   "INPUTNAME",        INFOTOK_INPUTNAME       },
-       {   "OUTPUTNAME",       INFOTOK_OUTPUTNAME      },
-       {   "PAGELENGTH",       INFOTOK_PAGELENGTH      },
-       {   "STARTADDR",        INFOTOK_STARTADDR       },
+        {   "ARGUMENTCOL",      INFOTOK_ARGUMENT_COLUMN },
+        {   "ARGUMENTCOLUMN",   INFOTOK_ARGUMENT_COLUMN },
+        {   "COMMENTCOL",       INFOTOK_COMMENT_COLUMN  },
+        {   "COMMENTCOLUMN",    INFOTOK_COMMENT_COLUMN  },
+        {   "COMMENTS",         INFOTOK_COMMENTS        },
+        {   "CPU",              INFOTOK_CPU             },
+        {   "HEXOFFS",          INFOTOK_HEXOFFS         },
+        {   "INPUTNAME",        INFOTOK_INPUTNAME       },
+        {   "INPUTOFFS",        INFOTOK_INPUTOFFS       },
+        {   "INPUTSIZE",        INFOTOK_INPUTSIZE       },
+        {   "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 */
@@ -83,11 +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) {
+
+            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;
 
-       /* Look at the token */
-       switch (InfoTok) {
+            case INFOTOK_COMMENTS:
+                InfoNextTok ();
+                InfoAssureInt ();
+                InfoRangeCheck (MIN_COMMENTS, MAX_COMMENTS);
+                Comments = InfoIVal;
+                InfoNextTok ();
+                break;
 
             case INFOTOK_CPU:
                 InfoNextTok ();
@@ -100,48 +250,120 @@ 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_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 ();
+            case INFOTOK_HEXOFFS:
+                InfoNextTok ();
+                InfoBoolToken ();
+                switch (InfoTok) {
+                    case INFOTOK_FALSE: UseHexOffs = 0; break;
+                    case INFOTOK_TRUE:  UseHexOffs = 1; break;
+                }
+                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;
+
+            case INFOTOK_INPUTSIZE:
+                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 ();
 
     }
 
@@ -151,39 +373,194 @@ static void GlobalSection (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        },
+        {   "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);
+                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 ();
+}
+
+
+
 static void RangeSection (void)
 /* Parse a range section */
 {
     static const IdentTok RangeDefs[] = {
-               {   "START",            INFOTOK_START   },
-       {   "END",              INFOTOK_END     },
-       {   "TYPE",             INFOTOK_TYPE    },
+        {   "COMMENT",          INFOTOK_COMMENT },
+        {   "END",              INFOTOK_END     },
+        {   "NAME",             INFOTOK_NAME    },
+        {   "START",            INFOTOK_START   },
+        {   "TYPE",             INFOTOK_TYPE    },
     };
 
     static const IdentTok TypeDefs[] = {
-       {   "CODE",             INFOTOK_CODE     },
-       {   "BYTETABLE",        INFOTOK_BYTETAB  },
-       {   "WORDTABLE",        INFOTOK_WORDTAB  },
-       {   "DWORDTABLE",       INFOTOK_DWORDTAB },
-       {   "ADDRTABLE",        INFOTOK_ADDRTAB  },
-       {   "RTSTABLE",         INFOTOK_RTSTAB   },
-       {   "TEXTTABLE",        INFOTOK_TEXTTAB  },
+        {   "ADDRTABLE",        INFOTOK_ADDRTAB  },
+        {   "BYTETABLE",        INFOTOK_BYTETAB  },
+        {   "CODE",             INFOTOK_CODE     },
+        {   "DBYTETABLE",       INFOTOK_DBYTETAB },
+        {   "DWORDTABLE",       INFOTOK_DWORDTAB },
+        {   "RTSTABLE",         INFOTOK_RTSTAB   },
+        {   "SKIP",             INFOTOK_SKIP     },
+        {   "TEXTTABLE",        INFOTOK_TEXTTAB  },
+        {   "WORDTABLE",        INFOTOK_WORDTAB  },
     };
 
 
     /* Which values did we get? */
     enum {
-       tNone   = 0x00,
-       tStart  = 0x01,
-       tEnd    = 0x02,
-       tType   = 0x04,
-       tAll    = 0x07
-    } Needed = tNone;
+        tNone   = 0x00,
+        tStart  = 0x01,
+        tEnd    = 0x02,
+        tType   = 0x04,
+        tName   = 0x08,
+        tComment= 0x10,
+        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;
+
 
     /* Skip the token */
     InfoNextTok ();
@@ -194,84 +571,134 @@ static void RangeSection (void)
     /* Look for section tokens */
     while (InfoTok != INFOTOK_RCURLY) {
 
-       /* Convert to special token */
-               InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range directive");
-
-       /* Look at the token */
-       switch (InfoTok) {
-
-           case INFOTOK_START:
-               InfoNextTok ();
-               InfoAssureInt ();
-               InfoRangeCheck (0x0000, 0xFFFF);
-               Start = InfoIVal;
-               Needed |= tStart;
-               InfoNextTok ();
-               break;
-
-           case INFOTOK_END:
-               InfoNextTok ();
-               InfoAssureInt ();
-               InfoRangeCheck (0x0000, 0xFFFF);
-               End = InfoIVal;
-               Needed |= tEnd;
-               InfoNextTok ();
-               break;
-
-           case INFOTOK_TYPE:
-               InfoNextTok ();
-               InfoSpecialToken (TypeDefs, ENTRY_COUNT (TypeDefs), "Type");
-               switch (InfoTok) {
-                   case INFOTOK_CODE:          Type = atCode;          break;
-                   case INFOTOK_BYTETAB:       Type = atByteTab;       break;
-                   case INFOTOK_WORDTAB:       Type = atWordTab;       break;
-                   case INFOTOK_DWORDTAB:      Type = atDWordTab;      break;
-                   case INFOTOK_ADDRTAB:       Type = atAddrTab;       break;
-                           case INFOTOK_RTSTAB:        Type = atRtsTab;        break;
-                   case INFOTOK_TEXTTAB:       Type = atTextTab;       break;
-               }
-               Needed |= tType;
-               InfoNextTok ();
-               break;
-       }
-
-       /* Directive is followed by a semicolon */
-       InfoConsumeSemi ();
+        /* Convert to special token */
+        InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range attribute");
+
+        /* Look at the token */
+        switch (InfoTok) {
+
+            case INFOTOK_COMMENT:
+                AddAttr ("COMMENT", &Attributes, tComment);
+                InfoNextTok ();
+                InfoAssureStr ();
+                if (InfoSVal[0] == '\0') {
+                    InfoError ("Comment may not be empty");
+                }
+                Comment = xstrdup (InfoSVal);
+                Attributes |= tComment;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_END:
+                AddAttr ("END", &Attributes, tEnd);
+                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);
+                Attributes |= tName;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_START:
+                AddAttr ("START", &Attributes, tStart);
+                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;
+                    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_SKIP:     Type = atSkip;     MemberSize = 1; break;
+                    case INFOTOK_TEXTTAB:  Type = atTextTab;  MemberSize = 1; break;
+                    case INFOTOK_WORDTAB:  Type = atWordTab;  MemberSize = 2; break;
+                }
+                InfoNextTok ();
+                break;
+
+            default:
+                Internal ("Unexpected token: %u", InfoTok);
+        }
+
+        /* Directive is followed by a semicolon */
+        InfoConsumeSemi ();
 
     }
 
     /* Did we get all required values? */
-    if (Needed != tAll) {
-       InfoError ("Required values missing from this section");
+    if ((Attributes & tNeeded) != tNeeded) {
+        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);
     }
 
     /* Set the range */
     MarkRange (Start, End, Type);
 
+    /* Do we have a label? */
+    if (Attributes & tName) {
+
+        /* Define a label for the table */
+        AddExtLabel (Start, Name);
+
+        /* Set the comment if we have one */
+        if (Comment) {
+            SetComment (Start, Comment);
+        }
+
+        /* Delete name and comment */
+        xfree (Name);
+        xfree (Comment);
+    }
+
     /* Consume the closing brace */
     InfoConsumeRCurly ();
 }
 
 
 
-static void LabelSection (void)
-/* Parse a label section */
+static void SegmentSection (void)
+/* Parse a segment section */
 {
     static const IdentTok LabelDefs[] = {
-               {   "NAME",     INFOTOK_NAME    },
-       {   "ADDR",     INFOTOK_ADDR    },
-               {   "SIZE",     INFOTOK_SIZE    },
+        {   "END",      INFOTOK_END     },
+        {   "NAME",     INFOTOK_NAME    },
+        {   "START",    INFOTOK_START   },
     };
 
     /* Locals - initialize to avoid gcc warnings */
-    char* Name = 0;
-    long Value = -1;
-    long Size  = -1;
+    long End    = -1;
+    long Start  = -1;
+    char* Name  = 0;
 
     /* Skip the token */
     InfoNextTok ();
@@ -282,97 +709,74 @@ static void LabelSection (void)
     /* 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_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_ADDR:
-               InfoNextTok ();
-               if (Value >= 0) {
-                   InfoError ("Value already given");
-               }
-               InfoAssureInt ();
-               InfoRangeCheck (0, 0xFFFF);
-               Value = InfoIVal;
-               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 ();
-    }
+        /* Convert to special token */
+        InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Segment attribute");
 
-    /* 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);
-    }
+        /* Look at the token */
+        switch (InfoTok) {
 
-    /* Define the label */
-    AddLabel ((unsigned) Value, atExtLabel, Name);
+            case INFOTOK_END:
+                InfoNextTok ();
+                if (End >= 0) {
+                    InfoError ("Value already given");
+                }
+                InfoAssureInt ();
+                InfoRangeCheck (0, 0xFFFF);
+                End = InfoIVal;
+                InfoNextTok ();
+                break;
+
+            case INFOTOK_NAME:
+                InfoNextTok ();
+                if (Name) {
+                    InfoError ("Name already given");
+                }
+                InfoAssureStr ();
+                Name = xstrdup (InfoSVal);
+                InfoNextTok ();
+                break;
 
-    /* Define dependent labels if necessary */
-    if (Size > 1) {
-       unsigned Offs;
+            case INFOTOK_START:
+                InfoNextTok ();
+                if (Start >= 0) {
+                    InfoError ("Value already given");
+                }
+                InfoAssureInt ();
+                InfoRangeCheck (0, 0xFFFF);
+                Start = InfoIVal;
+                InfoNextTok ();
+                break;
 
-       /* Allocate memory for the dependent label names */
-       unsigned NameLen = strlen (Name);
-       char*    DepName = xmalloc (NameLen + 7);
-       char*    DepOffs = DepName + NameLen + 1;
+            default:
+                Internal ("Unexpected token: %u", InfoTok);
+        }
 
-       /* Copy the original name into the buffer */
-       memcpy (DepName, Name, NameLen);
-       DepName[NameLen] = '+';
+        /* Directive is followed by a semicolon */
+        InfoConsumeSemi ();
+    }
 
-       /* Define the labels */
-       for (Offs = 1; Offs < (unsigned) Size; ++Offs) {
-           sprintf (DepOffs, "%u", Offs);
-           AddLabel ((unsigned) Value+Offs, atDepLabel, DepName);
-       }
+    /* Did we get the necessary data, and is it correct? */
+    if (Name == 0 || Name[0] == '\0') {
+        InfoError ("Segment name is missing");
+    }
+    if (End < 0) {
+        InfoError ("End address is missing");
+    }
+    if (Start < 0) {
+        InfoError ("Start address is missing");
+    }
+    if (Start > End) {
+        InfoError ("Start address of segment is greater than end address");
+    }
 
-       /* Free the name buffer */
-       xfree (DepName);
+    /* 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);
 
@@ -386,35 +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_ASMINC:
+                AsmIncSection ();
+                break;
+
+            case INFOTOK_GLOBAL:
+                GlobalSection ();
+                break;
 
-           case INFOTOK_GLOBAL:
-               GlobalSection ();
-               break;
+            case INFOTOK_LABEL:
+                LabelSection ();
+                break;
 
-           case INFOTOK_RANGE:
-               RangeSection ();
-               break;
+            case INFOTOK_RANGE:
+                RangeSection ();
+                break;
 
-           case INFOTOK_LABEL:
-               LabelSection ();
-               break;
+            case INFOTOK_SEGMENT:
+                SegmentSection ();
+                break;
 
-       }
+            default:
+                Internal ("Unexpected token: %u", InfoTok);
+        }
 
-       /* Semicolon expected */
-       InfoConsumeSemi ();
+        /* Semicolon expected */
+        InfoConsumeSemi ();
     }
 }
 
@@ -435,9 +851,3 @@ void ReadInfoFile (void)
         InfoCloseInput ();
     }
 }
-
-
-
-
-
-