]> git.sur5r.net Git - cc65/blob - src/da65/infofile.c
Restructured some of the code. Attribute handling is still a mess and needs
[cc65] / src / da65 / infofile.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                infofile.h                                 */
4 /*                                                                           */
5 /*                      Disassembler info file handling                      */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2005 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 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
62
63
64 /*****************************************************************************/
65 /*                                   Code                                    */
66 /*****************************************************************************/
67
68
69
70 static void AddAttr (const char* Name, unsigned* Set, unsigned Attr)
71 /* Add an attribute to the set and check that it is not given twice */
72 {
73     if (*Set & Attr) {
74         /* Attribute is already in the set */
75         InfoError ("%s given twice", Name);
76     }
77     *Set |= Attr;
78 }
79
80
81
82 static void GlobalSection (void)
83 /* Parse a global section */
84 {
85     static const IdentTok GlobalDefs[] = {
86         {   "COMMENTS",         INFOTOK_COMMENTS        },
87         {   "CPU",              INFOTOK_CPU             },
88         {   "HEXOFFS",          INFOTOK_HEXOFFS         },
89         {   "INPUTNAME",        INFOTOK_INPUTNAME       },
90         {   "INPUTOFFS",        INFOTOK_INPUTOFFS       },
91         {   "INPUTSIZE",        INFOTOK_INPUTSIZE       },
92         {   "LABELBREAK",       INFOTOK_LABELBREAK      },
93         {   "OUTPUTNAME",       INFOTOK_OUTPUTNAME      },
94         {   "PAGELENGTH",       INFOTOK_PAGELENGTH      },
95         {   "STARTADDR",        INFOTOK_STARTADDR       },
96     };
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 (GlobalDefs, ENTRY_COUNT (GlobalDefs), "Global directive");
109
110         /* Look at the token */
111         switch (InfoTok) {
112
113             case INFOTOK_COMMENTS:
114                 InfoNextTok ();
115                 InfoAssureInt ();
116                 InfoRangeCheck (MIN_COMMENTS, MAX_COMMENTS);
117                 Comments = InfoIVal;
118                 InfoNextTok ();
119                 break;
120
121             case INFOTOK_CPU:
122                 InfoNextTok ();
123                 InfoAssureStr ();
124                 if (CPU != CPU_UNKNOWN) {
125                     InfoError ("CPU already specified");
126                 }
127                 CPU = FindCPU (InfoSVal);
128                 SetOpcTable (CPU);
129                 InfoNextTok ();
130                 break;
131
132             case INFOTOK_HEXOFFS:
133                 InfoNextTok ();
134                 InfoBoolToken ();
135                 switch (InfoTok) {
136                     case INFOTOK_FALSE: UseHexOffs = 0; break;
137                     case INFOTOK_TRUE:  UseHexOffs = 1; break;
138                 }
139                 InfoNextTok ();
140                 break;
141
142             case INFOTOK_INPUTNAME:
143                 InfoNextTok ();
144                 InfoAssureStr ();
145                 if (InFile) {
146                     InfoError ("Input file name already given");
147                 }
148                 InFile = xstrdup (InfoSVal);
149                 InfoNextTok ();
150                 break;
151
152             case INFOTOK_INPUTOFFS:
153                 InfoNextTok ();
154                 InfoAssureInt ();
155                 InputOffs = InfoIVal;
156                 InfoNextTok ();
157                 break;
158
159             case INFOTOK_INPUTSIZE:
160                 InfoNextTok ();
161                 InfoAssureInt ();
162                 InfoRangeCheck (1, 0x10000);
163                 InputSize = InfoIVal;
164                 InfoNextTok ();
165                 break;
166
167             case INFOTOK_LABELBREAK:
168                 InfoNextTok ();
169                 InfoAssureInt ();
170                 InfoRangeCheck (0, UCHAR_MAX);
171                 LBreak = (unsigned char) InfoIVal;
172                 InfoNextTok ();
173                 break;
174
175             case INFOTOK_OUTPUTNAME:
176                 InfoNextTok ();
177                 InfoAssureStr ();
178                 if (OutFile) {
179                     InfoError ("Output file name already given");
180                 }
181                 OutFile = xstrdup (InfoSVal);
182                 InfoNextTok ();
183                 break;
184
185             case INFOTOK_PAGELENGTH:
186                 InfoNextTok ();
187                 InfoAssureInt ();
188                 if (InfoIVal != 0) {
189                     InfoRangeCheck (MIN_PAGE_LEN, MAX_PAGE_LEN);
190                 }
191                 PageLength = InfoIVal;
192                 InfoNextTok ();
193                 break;
194
195             case INFOTOK_STARTADDR:
196                 InfoNextTok ();
197                 InfoAssureInt ();
198                 InfoRangeCheck (0x0000, 0xFFFF);
199                 StartAddr = InfoIVal;
200                 InfoNextTok ();
201                 break;
202
203         }
204
205         /* Directive is followed by a semicolon */
206         InfoConsumeSemi ();
207
208     }
209
210     /* Consume the closing brace */
211     InfoConsumeRCurly ();
212 }
213
214
215
216 static void RangeSection (void)
217 /* Parse a range section */
218 {
219     static const IdentTok RangeDefs[] = {
220         {   "COMMENT",          INFOTOK_COMMENT },
221         {   "END",              INFOTOK_END     },
222         {   "NAME",             INFOTOK_NAME    },
223         {   "START",            INFOTOK_START   },
224         {   "TYPE",             INFOTOK_TYPE    },
225     };
226
227     static const IdentTok TypeDefs[] = {
228         {   "ADDRTABLE",        INFOTOK_ADDRTAB  },
229         {   "BYTETABLE",        INFOTOK_BYTETAB  },
230         {   "CODE",             INFOTOK_CODE     },
231         {   "DBYTETABLE",       INFOTOK_DBYTETAB },
232         {   "DWORDTABLE",       INFOTOK_DWORDTAB },
233         {   "RTSTABLE",         INFOTOK_RTSTAB   },
234         {   "SKIP",             INFOTOK_SKIP     },
235         {   "TEXTTABLE",        INFOTOK_TEXTTAB  },
236         {   "WORDTABLE",        INFOTOK_WORDTAB  },
237     };
238
239
240     /* Which values did we get? */
241     enum {
242         tNone   = 0x00,
243         tStart  = 0x01,
244         tEnd    = 0x02,
245         tType   = 0x04,
246         tName   = 0x08,
247         tComment= 0x10,
248         tNeeded = (tStart | tEnd | tType)
249     };
250     unsigned Attributes = tNone;
251
252     /* Locals - initialize to avoid gcc warnings */
253     unsigned Start      = 0;
254     unsigned End        = 0;
255     unsigned char Type  = 0;
256     char* Name          = 0;
257     char* Comment       = 0;
258     unsigned MemberSize = 0;
259
260
261     /* Skip the token */
262     InfoNextTok ();
263
264     /* Expect the opening curly brace */
265     InfoConsumeLCurly ();
266
267     /* Look for section tokens */
268     while (InfoTok != INFOTOK_RCURLY) {
269
270         /* Convert to special token */
271         InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range directive");
272
273         /* Look at the token */
274         switch (InfoTok) {
275
276             case INFOTOK_COMMENT:
277                 AddAttr ("COMMENT", &Attributes, tComment);
278                 InfoNextTok ();
279                 InfoAssureStr ();
280                 if (InfoSVal[0] == '\0') {
281                     InfoError ("Comment may not be empty");
282                 }
283                 Comment = xstrdup (InfoSVal);
284                 Attributes |= tComment;
285                 InfoNextTok ();
286                 break;
287
288             case INFOTOK_END:
289                 AddAttr ("END", &Attributes, tEnd);
290                 InfoNextTok ();
291                 InfoAssureInt ();
292                 InfoRangeCheck (0x0000, 0xFFFF);
293                 End = InfoIVal;
294                 InfoNextTok ();
295                 break;
296
297             case INFOTOK_NAME:
298                 AddAttr ("NAME", &Attributes, tName);
299                 InfoNextTok ();
300                 InfoAssureStr ();
301                 if (InfoSVal[0] == '\0') {
302                     InfoError ("Name may not be empty");
303                 }
304                 Name = xstrdup (InfoSVal);
305                 Attributes |= tName;
306                 InfoNextTok ();
307                 break;
308
309             case INFOTOK_START:
310                 AddAttr ("START", &Attributes, tStart);
311                 InfoNextTok ();
312                 InfoAssureInt ();
313                 InfoRangeCheck (0x0000, 0xFFFF);
314                 Start = InfoIVal;
315                 InfoNextTok ();
316                 break;
317
318             case INFOTOK_TYPE:
319                 AddAttr ("TYPE", &Attributes, tType);
320                 InfoNextTok ();
321                 InfoSpecialToken (TypeDefs, ENTRY_COUNT (TypeDefs), "TYPE");
322                 switch (InfoTok) {
323                     case INFOTOK_ADDRTAB:  Type = atAddrTab;  MemberSize = 2; break;
324                     case INFOTOK_BYTETAB:  Type = atByteTab;  MemberSize = 1; break;
325                     case INFOTOK_CODE:     Type = atCode;     MemberSize = 1; break;
326                     case INFOTOK_DBYTETAB: Type = atDByteTab; MemberSize = 2; break;
327                     case INFOTOK_DWORDTAB: Type = atDWordTab; MemberSize = 4; break;
328                     case INFOTOK_RTSTAB:   Type = atRtsTab;   MemberSize = 2; break;
329                     case INFOTOK_SKIP:     Type = atSkip;     MemberSize = 1; break;
330                     case INFOTOK_TEXTTAB:  Type = atTextTab;  MemberSize = 1; break;
331                     case INFOTOK_WORDTAB:  Type = atWordTab;  MemberSize = 2; break;
332                 }
333                 InfoNextTok ();
334                 break;
335         }
336
337         /* Directive is followed by a semicolon */
338         InfoConsumeSemi ();
339
340     }
341
342     /* Did we get all required values? */
343     if ((Attributes & tNeeded) != tNeeded) {
344         InfoError ("Required values missing from this section");
345     }
346
347     /* Start must be less than end */
348     if (Start > End) {
349         InfoError ("Start value must not be greater than end value");
350     }
351
352     /* Check the granularity */
353     if (((End - Start + 1) % MemberSize) != 0) {
354         InfoError ("Type of range needs a granularity of %u", MemberSize);
355     }
356
357     /* Set the range */
358     MarkRange (Start, End, Type);
359
360     /* Do we have a label? */
361     if (Attributes & tName) {
362
363         /* Define a label for the table */
364         AddExtLabel (Start, Name);
365
366         /* Set the comment if we have one */
367         if (Comment) {
368             SetComment (Start, Comment);
369         }
370
371         /* Delete name and comment */
372         xfree (Name);
373         xfree (Comment);
374     }
375
376     /* Consume the closing brace */
377     InfoConsumeRCurly ();
378 }
379
380
381
382 static void LabelSection (void)
383 /* Parse a label section */
384 {
385     static const IdentTok LabelDefs[] = {
386         {   "COMMENT",  INFOTOK_COMMENT },
387         {   "ADDR",     INFOTOK_ADDR    },
388         {   "NAME",     INFOTOK_NAME    },
389         {   "SIZE",     INFOTOK_SIZE    },
390     };
391
392     /* Locals - initialize to avoid gcc warnings */
393     char* Name    = 0;
394     char* Comment = 0;
395     long Value    = -1;
396     long Size     = -1;
397
398     /* Skip the token */
399     InfoNextTok ();
400
401     /* Expect the opening curly brace */
402     InfoConsumeLCurly ();
403
404     /* Look for section tokens */
405     while (InfoTok != INFOTOK_RCURLY) {
406
407         /* Convert to special token */
408         InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label directive");
409
410         /* Look at the token */
411         switch (InfoTok) {
412
413             case INFOTOK_ADDR:
414                 InfoNextTok ();
415                 if (Value >= 0) {
416                     InfoError ("Value already given");
417                 }
418                 InfoAssureInt ();
419                 InfoRangeCheck (0, 0xFFFF);
420                 Value = InfoIVal;
421                 InfoNextTok ();
422                 break;
423
424             case INFOTOK_COMMENT:
425                 InfoNextTok ();
426                 if (Comment) {
427                     InfoError ("Comment already given");
428                 }
429                 InfoAssureStr ();
430                 if (InfoSVal[0] == '\0') {
431                     InfoError ("Comment may not be empty");
432                 }
433                 Comment = xstrdup (InfoSVal);
434                 InfoNextTok ();
435                 break;
436
437             case INFOTOK_NAME:
438                 InfoNextTok ();
439                 if (Name) {
440                     InfoError ("Name already given");
441                 }
442                 InfoAssureStr ();
443                 Name = xstrdup (InfoSVal);
444                 InfoNextTok ();
445                 break;
446
447             case INFOTOK_SIZE:
448                 InfoNextTok ();
449                 if (Size >= 0) {
450                     InfoError ("Size already given");
451                 }
452                 InfoAssureInt ();
453                 InfoRangeCheck (1, 0x10000);
454                 Size = InfoIVal;
455                 InfoNextTok ();
456                 break;
457
458         }
459
460         /* Directive is followed by a semicolon */
461         InfoConsumeSemi ();
462     }
463
464     /* Did we get the necessary data */
465     if (Name == 0) {
466         InfoError ("Label name is missing");
467     }
468     if (Name[0] == '\0' && Size > 1) {
469         InfoError ("Unnamed labels must not have a size > 1");
470     }
471     if (Value < 0) {
472         InfoError ("Label value is missing");
473     }
474     if (Size < 0) {
475         /* Use default */
476         Size = 1;
477     }
478     if (Value + Size > 0x10000) {
479         InfoError ("Invalid size (address out of range)");
480     }
481     if (HaveLabel ((unsigned) Value)) {
482         InfoError ("Label for address $%04lX already defined", Value);
483     }
484
485     /* Define the label(s) */
486     if (Name[0] == '\0') {
487         /* Size has already beed checked */
488         AddUnnamedLabel (Value);
489     } else {
490         AddExtLabelRange ((unsigned) Value, Name, Size);
491     }
492
493     /* Define the comment */
494     if (Comment) {
495         SetComment (Value, Comment);
496     }
497
498     /* Delete the dynamically allocated memory for Name and Comment */
499     xfree (Name);
500     xfree (Comment);
501
502     /* Consume the closing brace */
503     InfoConsumeRCurly ();
504 }
505
506
507
508 static void AsmIncSection (void)
509 /* Parse a asminc section */
510 {
511     static const IdentTok LabelDefs[] = {
512         {   "COMMENTSTART",     INFOTOK_COMMENTSTART    },
513         {   "FILE",             INFOTOK_FILE            },
514         {   "IGNOREUNKNOWN",    INFOTOK_IGNOREUNKNOWN   },
515     };
516
517     /* Locals - initialize to avoid gcc warnings */
518     char* Name = 0;
519     int CommentStart = EOF;
520     int IgnoreUnknown = -1;
521
522     /* Skip the token */
523     InfoNextTok ();
524
525     /* Expect the opening curly brace */
526     InfoConsumeLCurly ();
527
528     /* Look for section tokens */
529     while (InfoTok != INFOTOK_RCURLY) {
530
531         /* Convert to special token */
532         InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Asminc directive");
533
534         /* Look at the token */
535         switch (InfoTok) {
536
537             case INFOTOK_COMMENTSTART:
538                 InfoNextTok ();
539                 if (CommentStart != EOF) {
540                     InfoError ("Commentstart already given");
541                 }
542                 InfoAssureChar ();
543                 CommentStart = (char) InfoIVal;
544                 InfoNextTok ();
545                 break;
546
547             case INFOTOK_FILE:
548                 InfoNextTok ();
549                 if (Name) {
550                     InfoError ("File name already given");
551                 }
552                 InfoAssureStr ();
553                 if (InfoSVal[0] == '\0') {
554                     InfoError ("File name may not be empty");
555                 }
556                 Name = xstrdup (InfoSVal);
557                 InfoNextTok ();
558                 break;
559
560             case INFOTOK_IGNOREUNKNOWN:
561                 InfoNextTok ();
562                 if (IgnoreUnknown != -1) {
563                     InfoError ("Ignoreunknown already specified");
564                 }
565                 InfoBoolToken ();
566                 IgnoreUnknown = (InfoTok != INFOTOK_FALSE);
567                 InfoNextTok ();
568                 break;
569         }
570
571         /* Directive is followed by a semicolon */
572         InfoConsumeSemi ();
573     }
574
575     /* Check for the necessary data and assume defaults */
576     if (Name == 0) {
577         InfoError ("File name is missing");
578     }
579     if (CommentStart == EOF) {
580         CommentStart = ';';
581     }
582     if (IgnoreUnknown == -1) {
583         IgnoreUnknown = 0;
584     }
585
586     /* Open the file and read the symbol definitions */
587     AsmInc (Name, CommentStart, IgnoreUnknown);
588
589     /* Delete the dynamically allocated memory for Name */
590     xfree (Name);
591
592     /* Consume the closing brace */
593     InfoConsumeRCurly ();
594 }
595
596
597
598 static void InfoParse (void)
599 /* Parse the config file */
600 {
601     static const IdentTok Globals[] = {
602         {   "GLOBAL",   INFOTOK_GLOBAL  },
603         {   "RANGE",    INFOTOK_RANGE   },
604         {   "LABEL",    INFOTOK_LABEL   },
605         {   "ASMINC",   INFOTOK_ASMINC  },
606     };
607
608     while (InfoTok != INFOTOK_EOF) {
609
610         /* Convert an identifier into a token */
611         InfoSpecialToken (Globals, ENTRY_COUNT (Globals), "Config directive");
612
613         /* Check the token */
614         switch (InfoTok) {
615
616             case INFOTOK_GLOBAL:
617                 GlobalSection ();
618                 break;
619
620             case INFOTOK_RANGE:
621                 RangeSection ();
622                 break;
623
624             case INFOTOK_LABEL:
625                 LabelSection ();
626                 break;
627
628             case INFOTOK_ASMINC:
629                 AsmIncSection ();
630                 break;
631         }
632
633         /* Semicolon expected */
634         InfoConsumeSemi ();
635     }
636 }
637
638
639
640 void ReadInfoFile (void)
641 /* Read the info file */
642 {
643     /* Check if we have a info file given */
644     if (InfoAvail()) {
645         /* Open the config file */
646         InfoOpenInput ();
647
648         /* Parse the config file */
649         InfoParse ();
650
651         /* Close the file */
652         InfoCloseInput ();
653     }
654 }
655
656
657
658
659
660