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