]> git.sur5r.net Git - cc65/blob - src/da65/infofile.c
Allow conditional directives within .STRUCT7:UNION and .ENUM
[cc65] / src / da65 / infofile.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                infofile.h                                 */
4 /*                                                                           */
5 /*                      Disassembler info file handling                      */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2003 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 #if defined(_MSC_VER)
39 /* Microsoft compiler */
40 #  include <io.h>
41 #else
42 /* Anyone else */
43 #  include <unistd.h>
44 #endif
45
46 /* common */
47 #include "cpu.h"
48 #include "xmalloc.h"
49
50 /* da65 */
51 #include "attrtab.h"
52 #include "error.h"
53 #include "global.h"
54 #include "infofile.h"
55 #include "opctable.h"
56 #include "scanner.h"
57
58
59
60 /*****************************************************************************/
61 /*                                   Code                                    */
62 /*****************************************************************************/
63
64
65
66 static void AddAttr (const char* Name, unsigned* Set, unsigned Attr)
67 /* Add an attribute to the set and check that it is not given twice */
68 {
69     if (*Set & Attr) {
70         /* Attribute is already in the set */
71         InfoError ("%s given twice", Name);
72     }
73     *Set |= Attr;
74 }
75
76
77
78 static void GlobalSection (void)
79 /* Parse a global section */
80 {
81     static const IdentTok GlobalDefs[] = {
82         {   "COMMENTS",         INFOTOK_COMMENTS        },
83         {   "CPU",              INFOTOK_CPU             },
84         {   "HEXOFFS",          INFOTOK_HEXOFFS         },
85         {   "INPUTNAME",        INFOTOK_INPUTNAME       },
86         {   "INPUTOFFS",        INFOTOK_INPUTOFFS       },
87         {   "INPUTSIZE",        INFOTOK_INPUTSIZE       },
88         {   "OUTPUTNAME",       INFOTOK_OUTPUTNAME      },
89         {   "PAGELENGTH",       INFOTOK_PAGELENGTH      },
90         {   "STARTADDR",        INFOTOK_STARTADDR       },
91     };
92
93     /* Skip the token */
94     InfoNextTok ();
95
96     /* Expect the opening curly brace */
97     InfoConsumeLCurly ();
98
99     /* Look for section tokens */
100     while (InfoTok != INFOTOK_RCURLY) {
101
102         /* Convert to special token */
103         InfoSpecialToken (GlobalDefs, ENTRY_COUNT (GlobalDefs), "Global directive");
104
105         /* Look at the token */
106         switch (InfoTok) {
107
108             case INFOTOK_COMMENTS:
109                 InfoNextTok ();
110                 InfoAssureInt ();
111                 InfoRangeCheck (MIN_COMMENTS, MAX_COMMENTS);
112                 Comments = InfoIVal;
113                 InfoNextTok ();
114                 break;
115
116             case INFOTOK_CPU:
117                 InfoNextTok ();
118                 InfoAssureStr ();
119                 if (CPU != CPU_UNKNOWN) {
120                     InfoError ("CPU already specified");
121                 }
122                 CPU = FindCPU (InfoSVal);
123                 SetOpcTable (CPU);
124                 InfoNextTok ();
125                 break;
126
127             case INFOTOK_HEXOFFS:
128                 InfoNextTok ();
129                 InfoBoolToken ();
130                 switch (InfoTok) {
131                     case INFOTOK_FALSE: UseHexOffs = 0; break;
132                     case INFOTOK_TRUE:  UseHexOffs = 1; break;
133                 }
134                 InfoNextTok ();
135                 break;
136
137             case INFOTOK_INPUTNAME:
138                 InfoNextTok ();
139                 InfoAssureStr ();
140                 if (InFile) {
141                     InfoError ("Input file name already given");
142                 }
143                 InFile = xstrdup (InfoSVal);
144                 InfoNextTok ();
145                 break;
146
147             case INFOTOK_INPUTOFFS:
148                 InfoNextTok ();
149                 InfoAssureInt ();
150                 InputOffs = InfoIVal;
151                 InfoNextTok ();
152                 break;
153
154             case INFOTOK_INPUTSIZE:
155                 InfoNextTok ();
156                 InfoAssureInt ();
157                 InfoRangeCheck (1, 0x10000);
158                 InputSize = InfoIVal;
159                 InfoNextTok ();
160                 break;
161
162             case INFOTOK_OUTPUTNAME:
163                 InfoNextTok ();
164                 InfoAssureStr ();
165                 if (OutFile) {
166                     InfoError ("Output file name already given");
167                 }
168                 OutFile = xstrdup (InfoSVal);
169                 InfoNextTok ();
170                 break;
171
172             case INFOTOK_PAGELENGTH:
173                 InfoNextTok ();
174                 InfoAssureInt ();
175                 if (InfoIVal != 0) {
176                     InfoRangeCheck (MIN_PAGE_LEN, MAX_PAGE_LEN);
177                 }
178                 PageLength = InfoIVal;
179                 InfoNextTok ();
180                 break;
181
182             case INFOTOK_STARTADDR:
183                 InfoNextTok ();
184                 InfoAssureInt ();
185                 InfoRangeCheck (0x0000, 0xFFFF);
186                 StartAddr = InfoIVal;
187                 InfoNextTok ();
188                 break;
189
190         }
191
192         /* Directive is followed by a semicolon */
193         InfoConsumeSemi ();
194
195     }
196
197     /* Consume the closing brace */
198     InfoConsumeRCurly ();
199 }
200
201
202
203 static void RangeSection (void)
204 /* Parse a range section */
205 {
206     static const IdentTok RangeDefs[] = {
207         {   "END",              INFOTOK_END     },
208         {   "NAME",             INFOTOK_NAME    },
209         {   "START",            INFOTOK_START   },
210         {   "TYPE",             INFOTOK_TYPE    },
211     };
212
213     static const IdentTok TypeDefs[] = {
214         {   "ADDRTABLE",        INFOTOK_ADDRTAB  },
215         {   "BYTETABLE",        INFOTOK_BYTETAB  },
216         {   "CODE",             INFOTOK_CODE     },
217         {   "DBYTETABLE",       INFOTOK_DBYTETAB },
218         {   "DWORDTABLE",       INFOTOK_DWORDTAB },
219         {   "RTSTABLE",         INFOTOK_RTSTAB   },
220         {   "SKIP",             INFOTOK_SKIP     },
221         {   "TEXTTABLE",        INFOTOK_TEXTTAB  },
222         {   "WORDTABLE",        INFOTOK_WORDTAB  },
223     };
224
225
226     /* Which values did we get? */
227     enum {
228         tNone   = 0x00,
229         tStart  = 0x01,
230         tEnd    = 0x02,
231         tType   = 0x04,
232         tName   = 0x08,
233         tNeeded = (tStart | tEnd | tType)
234     };
235     unsigned Attributes = tNone;
236
237     /* Locals - initialize to avoid gcc warnings */
238     unsigned Start      = 0;
239     unsigned End        = 0;
240     unsigned char Type  = 0;
241     char* Name          = 0;
242
243     /* Skip the token */
244     InfoNextTok ();
245
246     /* Expect the opening curly brace */
247     InfoConsumeLCurly ();
248
249     /* Look for section tokens */
250     while (InfoTok != INFOTOK_RCURLY) {
251
252         /* Convert to special token */
253         InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range directive");
254
255         /* Look at the token */
256         switch (InfoTok) {
257
258             case INFOTOK_END:
259                 AddAttr ("END", &Attributes, tEnd);
260                 InfoNextTok ();
261                 InfoAssureInt ();
262                 InfoRangeCheck (0x0000, 0xFFFF);
263                 End = InfoIVal;
264                 InfoNextTok ();
265                 break;
266
267             case INFOTOK_NAME:
268                 AddAttr ("NAME", &Attributes, tName);
269                 InfoNextTok ();
270                 InfoAssureStr ();
271                 if (InfoSVal[0] == '\0') {
272                     InfoError ("Name may not be empty");
273                 }
274                 Name = xstrdup (InfoSVal);
275                 Attributes |= tName;
276                 InfoNextTok ();
277                 break;
278
279             case INFOTOK_START:
280                 AddAttr ("START", &Attributes, tStart);
281                 InfoNextTok ();
282                 InfoAssureInt ();
283                 InfoRangeCheck (0x0000, 0xFFFF);
284                 Start = InfoIVal;
285                 InfoNextTok ();
286                 break;
287
288             case INFOTOK_TYPE:
289                 AddAttr ("TYPE", &Attributes, tType);
290                 InfoNextTok ();
291                 InfoSpecialToken (TypeDefs, ENTRY_COUNT (TypeDefs), "TYPE");
292                 switch (InfoTok) {
293                     case INFOTOK_ADDRTAB:       Type = atAddrTab;       break;
294                     case INFOTOK_BYTETAB:       Type = atByteTab;       break;
295                     case INFOTOK_CODE:          Type = atCode;          break;
296                     case INFOTOK_DBYTETAB:      Type = atDByteTab;      break;
297                     case INFOTOK_DWORDTAB:      Type = atDWordTab;      break;
298                     case INFOTOK_RTSTAB:        Type = atRtsTab;        break;
299                     case INFOTOK_SKIP:          Type = atSkip;          break;
300                     case INFOTOK_TEXTTAB:       Type = atTextTab;       break;
301                     case INFOTOK_WORDTAB:       Type = atWordTab;       break;
302                 }
303                 InfoNextTok ();
304                 break;
305         }
306
307         /* Directive is followed by a semicolon */
308         InfoConsumeSemi ();
309
310     }
311
312     /* Did we get all required values? */
313     if ((Attributes & tNeeded) != tNeeded) {
314         InfoError ("Required values missing from this section");
315     }
316
317     /* Start must be less than end */
318     if (Start > End) {
319         InfoError ("Start value must not be greater than end value");
320     }
321
322     /* Set the range */
323     MarkRange (Start, End, Type);
324
325     /* Do we have a label? */
326     if (Attributes & tName) {
327         /* Define a label for the table */
328         AddLabel (Start, atExtLabel, Name);
329         /* Delete the name */
330         xfree (Name);
331     }
332
333     /* Consume the closing brace */
334     InfoConsumeRCurly ();
335 }
336
337
338
339 static void LabelSection (void)
340 /* Parse a label section */
341 {
342     static const IdentTok LabelDefs[] = {
343         {   "NAME",     INFOTOK_NAME    },
344         {   "ADDR",     INFOTOK_ADDR    },
345         {   "SIZE",     INFOTOK_SIZE    },
346     };
347
348     /* Locals - initialize to avoid gcc warnings */
349     char* Name = 0;
350     long Value = -1;
351     long Size  = -1;
352
353     /* Skip the token */
354     InfoNextTok ();
355
356     /* Expect the opening curly brace */
357     InfoConsumeLCurly ();
358
359     /* Look for section tokens */
360     while (InfoTok != INFOTOK_RCURLY) {
361
362         /* Convert to special token */
363         InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label directive");
364
365         /* Look at the token */
366         switch (InfoTok) {
367
368             case INFOTOK_NAME:
369                 InfoNextTok ();
370                 if (Name) {
371                     InfoError ("Name already given");
372                 }
373                 InfoAssureStr ();
374                 if (InfoSVal[0] == '\0') {
375                     InfoError ("Name may not be empty");
376                 }
377                 Name = xstrdup (InfoSVal);
378                 InfoNextTok ();
379                 break;
380
381             case INFOTOK_ADDR:
382                 InfoNextTok ();
383                 if (Value >= 0) {
384                     InfoError ("Value already given");
385                 }
386                 InfoAssureInt ();
387                 InfoRangeCheck (0, 0xFFFF);
388                 Value = InfoIVal;
389                 InfoNextTok ();
390                 break;
391
392             case INFOTOK_SIZE:
393                 InfoNextTok ();
394                 if (Size >= 0) {
395                     InfoError ("Size already given");
396                 }
397                 InfoAssureInt ();
398                 InfoRangeCheck (1, 0x10000);
399                 Size = InfoIVal;
400                 InfoNextTok ();
401                 break;
402
403         }
404
405         /* Directive is followed by a semicolon */
406         InfoConsumeSemi ();
407     }
408
409     /* Did we get the necessary data */
410     if (Name == 0) {
411         InfoError ("Label name is missing");
412     }
413     if (Value < 0) {
414         InfoError ("Label value is missing");
415     }
416     if (Size < 0) {
417         /* Use default */
418         Size = 1;
419     }
420     if (Value + Size > 0x10000) {
421         InfoError ("Invalid size (address out of range)");
422     }
423     if (HaveLabel ((unsigned) Value)) {
424         InfoError ("Label for address $%04lX already defined", Value);
425     }
426
427     /* Define the label(s) */
428     AddExtLabelRange ((unsigned) Value, Name, Size);
429
430     /* Delete the dynamically allocated memory for Name */
431     xfree (Name);
432
433     /* Consume the closing brace */
434     InfoConsumeRCurly ();
435 }
436
437
438
439 static void InfoParse (void)
440 /* Parse the config file */
441 {
442     static const IdentTok Globals[] = {
443         {   "GLOBAL",   INFOTOK_GLOBAL  },
444         {   "RANGE",    INFOTOK_RANGE   },
445         {   "LABEL",    INFOTOK_LABEL   },
446     };
447
448     while (InfoTok != INFOTOK_EOF) {
449
450         /* Convert an identifier into a token */
451         InfoSpecialToken (Globals, ENTRY_COUNT (Globals), "Config directive");
452
453         /* Check the token */
454         switch (InfoTok) {
455
456             case INFOTOK_GLOBAL:
457                 GlobalSection ();
458                 break;
459
460             case INFOTOK_RANGE:
461                 RangeSection ();
462                 break;
463
464             case INFOTOK_LABEL:
465                 LabelSection ();
466                 break;
467
468         }
469
470         /* Semicolon expected */
471         InfoConsumeSemi ();
472     }
473 }
474
475
476
477 void ReadInfoFile (void)
478 /* Read the info file */
479 {
480     /* Check if we have a info file given */
481     if (InfoAvail()) {
482         /* Open the config file */
483         InfoOpenInput ();
484
485         /* Parse the config file */
486         InfoParse ();
487
488         /* Close the file */
489         InfoCloseInput ();
490     }
491 }
492
493
494
495
496
497