]> git.sur5r.net Git - cc65/blob - src/da65/infofile.c
Merge remote-tracking branch 'upstream/master' into a5200
[cc65] / src / da65 / infofile.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                infofile.h                                 */
4 /*                                                                           */
5 /*                      Disassembler info file handling                      */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2011, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <limits.h>
39 #if defined(_MSC_VER)
40 /* Microsoft compiler */
41 #  include <io.h>
42 #else
43 /* Anyone else */
44 #  include <unistd.h>
45 #endif
46
47 /* common */
48 #include "cpu.h"
49 #include "xmalloc.h"
50
51 /* da65 */
52 #include "asminc.h"
53 #include "attrtab.h"
54 #include "comments.h"
55 #include "error.h"
56 #include "global.h"
57 #include "infofile.h"
58 #include "labels.h"
59 #include "opctable.h"
60 #include "scanner.h"
61 #include "segment.h"
62
63
64
65 /*****************************************************************************/
66 /*                                   Code                                    */
67 /*****************************************************************************/
68
69
70
71 static void AddAttr (const char* Name, unsigned* Set, unsigned Attr)
72 /* Add an attribute to the set and check that it is not given twice */
73 {
74     if (*Set & Attr) {
75         /* Attribute is already in the set */
76         InfoError ("%s given twice", Name);
77     }
78     *Set |= Attr;
79 }
80
81
82
83 static void AsmIncSection (void)
84 /* Parse a asminc section */
85 {
86     static const IdentTok LabelDefs[] = {
87         {   "COMMENTSTART",     INFOTOK_COMMENTSTART    },
88         {   "FILE",             INFOTOK_FILE            },
89         {   "IGNOREUNKNOWN",    INFOTOK_IGNOREUNKNOWN   },
90     };
91
92     /* Locals - initialize to avoid gcc warnings */
93     char* Name = 0;
94     int CommentStart = EOF;
95     int IgnoreUnknown = -1;
96
97     /* Skip the token */
98     InfoNextTok ();
99
100     /* Expect the opening curly brace */
101     InfoConsumeLCurly ();
102
103     /* Look for section tokens */
104     while (InfoTok != INFOTOK_RCURLY) {
105
106         /* Convert to special token */
107         InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Asminc directive");
108
109         /* Look at the token */
110         switch (InfoTok) {
111
112             case INFOTOK_COMMENTSTART:
113                 InfoNextTok ();
114                 if (CommentStart != EOF) {
115                     InfoError ("Commentstart already given");
116                 }
117                 InfoAssureChar ();
118                 CommentStart = (char) InfoIVal;
119                 InfoNextTok ();
120                 break;
121
122             case INFOTOK_FILE:
123                 InfoNextTok ();
124                 if (Name) {
125                     InfoError ("File name already given");
126                 }
127                 InfoAssureStr ();
128                 if (InfoSVal[0] == '\0') {
129                     InfoError ("File name may not be empty");
130                 }
131                 Name = xstrdup (InfoSVal);
132                 InfoNextTok ();
133                 break;
134
135             case INFOTOK_IGNOREUNKNOWN:
136                 InfoNextTok ();
137                 if (IgnoreUnknown != -1) {
138                     InfoError ("Ignoreunknown already specified");
139                 }
140                 InfoBoolToken ();
141                 IgnoreUnknown = (InfoTok != INFOTOK_FALSE);
142                 InfoNextTok ();
143                 break;
144
145             default:
146                 Internal ("Unexpected token: %u", InfoTok);
147         }
148
149         /* Directive is followed by a semicolon */
150         InfoConsumeSemi ();
151     }
152
153     /* Check for the necessary data and assume defaults */
154     if (Name == 0) {
155         InfoError ("File name is missing");
156     }
157     if (CommentStart == EOF) {
158         CommentStart = ';';
159     }
160     if (IgnoreUnknown == -1) {
161         IgnoreUnknown = 0;
162     }
163
164     /* Open the file and read the symbol definitions */
165     AsmInc (Name, CommentStart, IgnoreUnknown);
166
167     /* Delete the dynamically allocated memory for Name */
168     xfree (Name);
169
170     /* Consume the closing brace */
171     InfoConsumeRCurly ();
172 }
173
174
175
176 static void GlobalSection (void)
177 /* Parse a global section */
178 {
179     static const IdentTok GlobalDefs[] = {
180         {   "ARGUMENTCOL",      INFOTOK_ARGUMENT_COLUMN },
181         {   "ARGUMENTCOLUMN",   INFOTOK_ARGUMENT_COLUMN },
182         {   "COMMENTCOL",       INFOTOK_COMMENT_COLUMN  },
183         {   "COMMENTCOLUMN",    INFOTOK_COMMENT_COLUMN  },
184         {   "COMMENTS",         INFOTOK_COMMENTS        },
185         {   "CPU",              INFOTOK_CPU             },
186         {   "HEXOFFS",          INFOTOK_HEXOFFS         },
187         {   "INPUTNAME",        INFOTOK_INPUTNAME       },
188         {   "INPUTOFFS",        INFOTOK_INPUTOFFS       },
189         {   "INPUTSIZE",        INFOTOK_INPUTSIZE       },
190         {   "LABELBREAK",       INFOTOK_LABELBREAK      },
191         {   "MNEMONICCOL",      INFOTOK_MNEMONIC_COLUMN },
192         {   "MNEMONICCOLUMN",   INFOTOK_MNEMONIC_COLUMN },
193         {   "NEWLINEAFTERJMP",  INFOTOK_NL_AFTER_JMP    },
194         {   "NEWLINEAFTERRTS",  INFOTOK_NL_AFTER_RTS    },
195         {   "OUTPUTNAME",       INFOTOK_OUTPUTNAME      },
196         {   "PAGELENGTH",       INFOTOK_PAGELENGTH      },
197         {   "STARTADDR",        INFOTOK_STARTADDR       },
198         {   "TEXTCOL",          INFOTOK_TEXT_COLUMN     },
199         {   "TEXTCOLUMN",       INFOTOK_TEXT_COLUMN     },
200     };
201
202     /* Skip the token */
203     InfoNextTok ();
204
205     /* Expect the opening curly brace */
206     InfoConsumeLCurly ();
207
208     /* Look for section tokens */
209     while (InfoTok != INFOTOK_RCURLY) {
210
211         /* Convert to special token */
212         InfoSpecialToken (GlobalDefs, ENTRY_COUNT (GlobalDefs), "Global directive");
213
214         /* Look at the token */
215         switch (InfoTok) {
216
217             case INFOTOK_ARGUMENT_COLUMN:
218                 InfoNextTok ();
219                 InfoAssureInt ();
220                 InfoRangeCheck (MIN_ACOL, MAX_ACOL);
221                 ACol = InfoIVal;
222                 InfoNextTok ();
223                 break;
224
225             case INFOTOK_COMMENT_COLUMN:
226                 InfoNextTok ();
227                 InfoAssureInt ();
228                 InfoRangeCheck (MIN_CCOL, MAX_CCOL);
229                 CCol = InfoIVal;
230                 InfoNextTok ();
231                 break;
232
233             case INFOTOK_COMMENTS:
234                 InfoNextTok ();
235                 InfoAssureInt ();
236                 InfoRangeCheck (MIN_COMMENTS, MAX_COMMENTS);
237                 Comments = InfoIVal;
238                 InfoNextTok ();
239                 break;
240
241             case INFOTOK_CPU:
242                 InfoNextTok ();
243                 InfoAssureStr ();
244                 if (CPU != CPU_UNKNOWN) {
245                     InfoError ("CPU already specified");
246                 }
247                 CPU = FindCPU (InfoSVal);
248                 SetOpcTable (CPU);
249                 InfoNextTok ();
250                 break;
251
252             case INFOTOK_HEXOFFS:
253                 InfoNextTok ();
254                 InfoBoolToken ();
255                 switch (InfoTok) {
256                     case INFOTOK_FALSE: UseHexOffs = 0; break;
257                     case INFOTOK_TRUE:  UseHexOffs = 1; break;
258                 }
259                 InfoNextTok ();
260                 break;
261
262             case INFOTOK_INPUTNAME:
263                 InfoNextTok ();
264                 InfoAssureStr ();
265                 if (InFile) {
266                     InfoError ("Input file name already given");
267                 }
268                 InFile = xstrdup (InfoSVal);
269                 InfoNextTok ();
270                 break;
271
272             case INFOTOK_INPUTOFFS:
273                 InfoNextTok ();
274                 InfoAssureInt ();
275                 InputOffs = InfoIVal;
276                 InfoNextTok ();
277                 break;
278
279             case INFOTOK_INPUTSIZE:
280                 InfoNextTok ();
281                 InfoAssureInt ();
282                 InfoRangeCheck (1, 0x10000);
283                 InputSize = InfoIVal;
284                 InfoNextTok ();
285                 break;
286
287             case INFOTOK_LABELBREAK:
288                 InfoNextTok ();
289                 InfoAssureInt ();
290                 InfoRangeCheck (0, UCHAR_MAX);
291                 LBreak = (unsigned char) InfoIVal;
292                 InfoNextTok ();
293                 break;
294
295             case INFOTOK_MNEMONIC_COLUMN:
296                 InfoNextTok ();
297                 InfoAssureInt ();
298                 InfoRangeCheck (MIN_MCOL, MAX_MCOL);
299                 MCol = InfoIVal;
300                 InfoNextTok ();
301                 break;
302
303             case INFOTOK_NL_AFTER_JMP:
304                 InfoNextTok ();
305                 if (NewlineAfterJMP != -1) {
306                     InfoError ("NLAfterJMP already specified");
307                 }
308                 InfoBoolToken ();
309                 NewlineAfterJMP = (InfoTok != INFOTOK_FALSE);
310                 InfoNextTok ();
311                 break;
312
313             case INFOTOK_NL_AFTER_RTS:
314                 InfoNextTok ();
315                 InfoBoolToken ();
316                 if (NewlineAfterRTS != -1) {
317                     InfoError ("NLAfterRTS already specified");
318                 }
319                 NewlineAfterRTS = (InfoTok != INFOTOK_FALSE);
320                 InfoNextTok ();
321                 break;
322
323             case INFOTOK_OUTPUTNAME:
324                 InfoNextTok ();
325                 InfoAssureStr ();
326                 if (OutFile) {
327                     InfoError ("Output file name already given");
328                 }
329                 OutFile = xstrdup (InfoSVal);
330                 InfoNextTok ();
331                 break;
332
333             case INFOTOK_PAGELENGTH:
334                 InfoNextTok ();
335                 InfoAssureInt ();
336                 if (InfoIVal != 0) {
337                     InfoRangeCheck (MIN_PAGE_LEN, MAX_PAGE_LEN);
338                 }
339                 PageLength = InfoIVal;
340                 InfoNextTok ();
341                 break;
342
343             case INFOTOK_STARTADDR:
344                 InfoNextTok ();
345                 InfoAssureInt ();
346                 InfoRangeCheck (0x0000, 0xFFFF);
347                 StartAddr = InfoIVal;
348                 InfoNextTok ();
349                 break;
350
351             case INFOTOK_TEXT_COLUMN:
352                 InfoNextTok ();
353                 InfoAssureInt ();
354                 InfoRangeCheck (MIN_TCOL, MAX_TCOL);
355                 TCol = InfoIVal;
356                 InfoNextTok ();
357                 break;
358
359             default:
360                 Internal ("Unexpected token: %u", InfoTok);
361
362         }
363
364         /* Directive is followed by a semicolon */
365         InfoConsumeSemi ();
366
367     }
368
369     /* Consume the closing brace */
370     InfoConsumeRCurly ();
371 }
372
373
374
375 static void LabelSection (void)
376 /* Parse a label section */
377 {
378     static const IdentTok LabelDefs[] = {
379         {   "COMMENT",  INFOTOK_COMMENT },
380         {   "ADDR",     INFOTOK_ADDR    },
381         {   "NAME",     INFOTOK_NAME    },
382         {   "SIZE",     INFOTOK_SIZE    },
383     };
384
385     /* Locals - initialize to avoid gcc warnings */
386     char* Name    = 0;
387     char* Comment = 0;
388     long Value    = -1;
389     long Size     = -1;
390
391     /* Skip the token */
392     InfoNextTok ();
393
394     /* Expect the opening curly brace */
395     InfoConsumeLCurly ();
396
397     /* Look for section tokens */
398     while (InfoTok != INFOTOK_RCURLY) {
399
400         /* Convert to special token */
401         InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label attribute");
402
403         /* Look at the token */
404         switch (InfoTok) {
405
406             case INFOTOK_ADDR:
407                 InfoNextTok ();
408                 if (Value >= 0) {
409                     InfoError ("Value already given");
410                 }
411                 InfoAssureInt ();
412                 InfoRangeCheck (0, 0xFFFF);
413                 Value = InfoIVal;
414                 InfoNextTok ();
415                 break;
416
417             case INFOTOK_COMMENT:
418                 InfoNextTok ();
419                 if (Comment) {
420                     InfoError ("Comment already given");
421                 }
422                 InfoAssureStr ();
423                 if (InfoSVal[0] == '\0') {
424                     InfoError ("Comment may not be empty");
425                 }
426                 Comment = xstrdup (InfoSVal);
427                 InfoNextTok ();
428                 break;
429
430             case INFOTOK_NAME:
431                 InfoNextTok ();
432                 if (Name) {
433                     InfoError ("Name already given");
434                 }
435                 InfoAssureStr ();
436                 Name = xstrdup (InfoSVal);
437                 InfoNextTok ();
438                 break;
439
440             case INFOTOK_SIZE:
441                 InfoNextTok ();
442                 if (Size >= 0) {
443                     InfoError ("Size already given");
444                 }
445                 InfoAssureInt ();
446                 InfoRangeCheck (1, 0x10000);
447                 Size = InfoIVal;
448                 InfoNextTok ();
449                 break;
450
451             default:
452                 Internal ("Unexpected token: %u", InfoTok);
453         }
454
455         /* Directive is followed by a semicolon */
456         InfoConsumeSemi ();
457     }
458
459     /* Did we get the necessary data */
460     if (Name == 0) {
461         InfoError ("Label name is missing");
462     }
463     if (Name[0] == '\0' && Size > 1) {
464         InfoError ("Unnamed labels must not have a size > 1");
465     }
466     if (Value < 0) {
467         InfoError ("Label value is missing");
468     }
469     if (Size < 0) {
470         /* Use default */
471         Size = 1;
472     }
473     if (Value + Size > 0x10000) {
474         InfoError ("Invalid size (address out of range)");
475     }
476     if (HaveLabel ((unsigned) Value)) {
477         InfoError ("Label for address $%04lX already defined", Value);
478     }
479
480     /* Define the label(s) */
481     if (Name[0] == '\0') {
482         /* Size has already beed checked */
483         AddUnnamedLabel (Value);
484     } else {
485         AddExtLabelRange ((unsigned) Value, Name, Size);
486     }
487
488     /* Define the comment */
489     if (Comment) {
490         SetComment (Value, Comment);
491     }
492
493     /* Delete the dynamically allocated memory for Name and Comment */
494     xfree (Name);
495     xfree (Comment);
496
497     /* Consume the closing brace */
498     InfoConsumeRCurly ();
499 }
500
501
502
503 static void RangeSection (void)
504 /* Parse a range section */
505 {
506     static const IdentTok RangeDefs[] = {
507         {   "COMMENT",          INFOTOK_COMMENT },
508         {   "END",              INFOTOK_END     },
509         {   "NAME",             INFOTOK_NAME    },
510         {   "START",            INFOTOK_START   },
511         {   "TYPE",             INFOTOK_TYPE    },
512     };
513
514     static const IdentTok TypeDefs[] = {
515         {   "ADDRTABLE",        INFOTOK_ADDRTAB  },
516         {   "BYTETABLE",        INFOTOK_BYTETAB  },
517         {   "CODE",             INFOTOK_CODE     },
518         {   "DBYTETABLE",       INFOTOK_DBYTETAB },
519         {   "DWORDTABLE",       INFOTOK_DWORDTAB },
520         {   "RTSTABLE",         INFOTOK_RTSTAB   },
521         {   "SKIP",             INFOTOK_SKIP     },
522         {   "TEXTTABLE",        INFOTOK_TEXTTAB  },
523         {   "WORDTABLE",        INFOTOK_WORDTAB  },
524     };
525
526
527     /* Which values did we get? */
528     enum {
529         tNone   = 0x00,
530         tStart  = 0x01,
531         tEnd    = 0x02,
532         tType   = 0x04,
533         tName   = 0x08,
534         tComment= 0x10,
535         tNeeded = (tStart | tEnd | tType)
536     };
537     unsigned Attributes = tNone;
538
539     /* Locals - initialize to avoid gcc warnings */
540     unsigned Start      = 0;
541     unsigned End        = 0;
542     unsigned char Type  = 0;
543     char* Name          = 0;
544     char* Comment       = 0;
545     unsigned MemberSize = 0;
546
547
548     /* Skip the token */
549     InfoNextTok ();
550
551     /* Expect the opening curly brace */
552     InfoConsumeLCurly ();
553
554     /* Look for section tokens */
555     while (InfoTok != INFOTOK_RCURLY) {
556
557         /* Convert to special token */
558         InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range attribute");
559
560         /* Look at the token */
561         switch (InfoTok) {
562
563             case INFOTOK_COMMENT:
564                 AddAttr ("COMMENT", &Attributes, tComment);
565                 InfoNextTok ();
566                 InfoAssureStr ();
567                 if (InfoSVal[0] == '\0') {
568                     InfoError ("Comment may not be empty");
569                 }
570                 Comment = xstrdup (InfoSVal);
571                 Attributes |= tComment;
572                 InfoNextTok ();
573                 break;
574
575             case INFOTOK_END:
576                 AddAttr ("END", &Attributes, tEnd);
577                 InfoNextTok ();
578                 InfoAssureInt ();
579                 InfoRangeCheck (0x0000, 0xFFFF);
580                 End = InfoIVal;
581                 InfoNextTok ();
582                 break;
583
584             case INFOTOK_NAME:
585                 AddAttr ("NAME", &Attributes, tName);
586                 InfoNextTok ();
587                 InfoAssureStr ();
588                 if (InfoSVal[0] == '\0') {
589                     InfoError ("Name may not be empty");
590                 }
591                 Name = xstrdup (InfoSVal);
592                 Attributes |= tName;
593                 InfoNextTok ();
594                 break;
595
596             case INFOTOK_START:
597                 AddAttr ("START", &Attributes, tStart);
598                 InfoNextTok ();
599                 InfoAssureInt ();
600                 InfoRangeCheck (0x0000, 0xFFFF);
601                 Start = InfoIVal;
602                 InfoNextTok ();
603                 break;
604
605             case INFOTOK_TYPE:
606                 AddAttr ("TYPE", &Attributes, tType);
607                 InfoNextTok ();
608                 InfoSpecialToken (TypeDefs, ENTRY_COUNT (TypeDefs), "TYPE");
609                 switch (InfoTok) {
610                     case INFOTOK_ADDRTAB:  Type = atAddrTab;  MemberSize = 2; break;
611                     case INFOTOK_BYTETAB:  Type = atByteTab;  MemberSize = 1; break;
612                     case INFOTOK_CODE:     Type = atCode;     MemberSize = 1; break;
613                     case INFOTOK_DBYTETAB: Type = atDByteTab; MemberSize = 2; break;
614                     case INFOTOK_DWORDTAB: Type = atDWordTab; MemberSize = 4; break;
615                     case INFOTOK_RTSTAB:   Type = atRtsTab;   MemberSize = 2; break;
616                     case INFOTOK_SKIP:     Type = atSkip;     MemberSize = 1; break;
617                     case INFOTOK_TEXTTAB:  Type = atTextTab;  MemberSize = 1; break;
618                     case INFOTOK_WORDTAB:  Type = atWordTab;  MemberSize = 2; break;
619                 }
620                 InfoNextTok ();
621                 break;
622
623             default:
624                 Internal ("Unexpected token: %u", InfoTok);
625         }
626
627         /* Directive is followed by a semicolon */
628         InfoConsumeSemi ();
629
630     }
631
632     /* Did we get all required values? */
633     if ((Attributes & tNeeded) != tNeeded) {
634         InfoError ("Required values missing from this section");
635     }
636
637     /* Start must be less than end */
638     if (Start > End) {
639         InfoError ("Start value must not be greater than end value");
640     }
641
642     /* Check the granularity */
643     if (((End - Start + 1) % MemberSize) != 0) {
644         InfoError ("Type of range needs a granularity of %u", MemberSize);
645     }
646
647     /* Set the range */
648     MarkRange (Start, End, Type);
649
650     /* Do we have a label? */
651     if (Attributes & tName) {
652
653         /* Define a label for the table */
654         AddExtLabel (Start, Name);
655
656         /* Set the comment if we have one */
657         if (Comment) {
658             SetComment (Start, Comment);
659         }
660
661         /* Delete name and comment */
662         xfree (Name);
663         xfree (Comment);
664     }
665
666     /* Consume the closing brace */
667     InfoConsumeRCurly ();
668 }
669
670
671
672 static void SegmentSection (void)
673 /* Parse a segment section */
674 {
675     static const IdentTok LabelDefs[] = {
676         {   "END",      INFOTOK_END     },
677         {   "NAME",     INFOTOK_NAME    },
678         {   "START",    INFOTOK_START   },
679     };
680
681     /* Locals - initialize to avoid gcc warnings */
682     long End    = -1;
683     long Start  = -1;
684     char* Name  = 0;
685
686     /* Skip the token */
687     InfoNextTok ();
688
689     /* Expect the opening curly brace */
690     InfoConsumeLCurly ();
691
692     /* Look for section tokens */
693     while (InfoTok != INFOTOK_RCURLY) {
694
695         /* Convert to special token */
696         InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Segment attribute");
697
698         /* Look at the token */
699         switch (InfoTok) {
700
701             case INFOTOK_END:
702                 InfoNextTok ();
703                 if (End >= 0) {
704                     InfoError ("Value already given");
705                 }
706                 InfoAssureInt ();
707                 InfoRangeCheck (0, 0xFFFF);
708                 End = InfoIVal;
709                 InfoNextTok ();
710                 break;
711
712             case INFOTOK_NAME:
713                 InfoNextTok ();
714                 if (Name) {
715                     InfoError ("Name already given");
716                 }
717                 InfoAssureStr ();
718                 Name = xstrdup (InfoSVal);
719                 InfoNextTok ();
720                 break;
721
722             case INFOTOK_START:
723                 InfoNextTok ();
724                 if (Start >= 0) {
725                     InfoError ("Value already given");
726                 }
727                 InfoAssureInt ();
728                 InfoRangeCheck (0, 0xFFFF);
729                 Start = InfoIVal;
730                 InfoNextTok ();
731                 break;
732
733             default:
734                 Internal ("Unexpected token: %u", InfoTok);
735         }
736
737         /* Directive is followed by a semicolon */
738         InfoConsumeSemi ();
739     }
740
741     /* Did we get the necessary data, and is it correct? */
742     if (Name == 0 || Name[0] == '\0') {
743         InfoError ("Segment name is missing");
744     }
745     if (End < 0) {
746         InfoError ("End address is missing");
747     }
748     if (Start < 0) {
749         InfoError ("Start address is missing");
750     }
751     if (Start == End) {
752         InfoError ("Segment is empty");
753     }
754     if (Start > End) {
755         InfoError ("Start address of segment is greater than end address");
756     }
757
758     /* Check that segments do not overlap */
759     if (SegmentDefined ((unsigned) Start, (unsigned) End)) {
760         InfoError ("Segments cannot overlap");
761     }
762
763     /* Remember the segment data */
764     AddAbsSegment ((unsigned) Start, (unsigned) End, Name);
765
766     /* Delete the dynamically allocated memory for Name */
767     xfree (Name);
768
769     /* Consume the closing brace */
770     InfoConsumeRCurly ();
771 }
772
773
774
775 static void InfoParse (void)
776 /* Parse the config file */
777 {
778     static const IdentTok Globals[] = {
779         {   "ASMINC",   INFOTOK_ASMINC  },
780         {   "GLOBAL",   INFOTOK_GLOBAL  },
781         {   "LABEL",    INFOTOK_LABEL   },
782         {   "RANGE",    INFOTOK_RANGE   },
783         {   "SEGMENT",  INFOTOK_SEGMENT },
784     };
785
786     while (InfoTok != INFOTOK_EOF) {
787
788         /* Convert an identifier into a token */
789         InfoSpecialToken (Globals, ENTRY_COUNT (Globals), "Config directive");
790
791         /* Check the token */
792         switch (InfoTok) {
793
794             case INFOTOK_ASMINC:
795                 AsmIncSection ();
796                 break;
797
798             case INFOTOK_GLOBAL:
799                 GlobalSection ();
800                 break;
801
802             case INFOTOK_LABEL:
803                 LabelSection ();
804                 break;
805
806             case INFOTOK_RANGE:
807                 RangeSection ();
808                 break;
809
810             case INFOTOK_SEGMENT:
811                 SegmentSection ();
812                 break;
813
814             default:
815                 Internal ("Unexpected token: %u", InfoTok);
816         }
817
818         /* Semicolon expected */
819         InfoConsumeSemi ();
820     }
821 }
822
823
824
825 void ReadInfoFile (void)
826 /* Read the info file */
827 {
828     /* Check if we have a info file given */
829     if (InfoAvail()) {
830         /* Open the config file */
831         InfoOpenInput ();
832
833         /* Parse the config file */
834         InfoParse ();
835
836         /* Close the file */
837         InfoCloseInput ();
838     }
839 }