]> git.sur5r.net Git - cc65/blob - src/da65/infofile.c
Renamed the config file to info file and changed the handling when the
[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 "xmalloc.h"
48
49 /* da65 */
50 #include "attrtab.h"
51 #include "error.h"
52 #include "global.h"
53 #include "infofile.h"
54 #include "scanner.h"
55
56
57
58 /*****************************************************************************/
59 /*                                   Code                                    */
60 /*****************************************************************************/
61
62
63
64 static void GlobalSection (void)
65 /* Parse a global section */
66 {
67     static const IdentTok GlobalDefs[] = {
68         {   "INPUTNAME",        INFOTOK_INPUTNAME       },
69         {   "OUTPUTNAME",       INFOTOK_OUTPUTNAME      },
70         {   "PAGELENGTH",       INFOTOK_PAGELENGTH      },
71         {   "STARTADDR",        INFOTOK_STARTADDR       },
72     };
73
74     /* Skip the token */
75     InfoNextTok ();
76
77     /* Expect the opening curly brace */
78     InfoConsumeLCurly ();
79
80     /* Look for section tokens */
81     while (InfoTok != INFOTOK_RCURLY) {
82
83         /* Convert to special token */
84         InfoSpecialToken (GlobalDefs, ENTRY_COUNT (GlobalDefs), "Global directive");
85
86         /* Look at the token */
87         switch (InfoTok) {
88
89             case INFOTOK_INPUTNAME:
90                 InfoNextTok ();
91                 InfoAssureStr ();
92                 if (InFile) {
93                     InfoError ("Input file name already given");
94                 }
95                 InFile = xstrdup (InfoSVal);
96                 InfoNextTok ();
97                 break;
98
99             case INFOTOK_OUTPUTNAME:
100                 InfoNextTok ();
101                 InfoAssureStr ();
102                 if (OutFile) {
103                     InfoError ("Output file name already given");
104                 }
105                 OutFile = xstrdup (InfoSVal);
106                 InfoNextTok ();
107                 break;
108
109             case INFOTOK_PAGELENGTH:
110                 InfoNextTok ();
111                 InfoAssureInt ();
112                 if (InfoIVal != -1) {
113                     InfoRangeCheck (MIN_PAGE_LEN, MAX_PAGE_LEN);
114                 }
115                 PageLength = InfoIVal;
116                 InfoNextTok ();
117                 break;
118
119             case INFOTOK_STARTADDR:
120                 InfoNextTok ();
121                 InfoAssureInt ();
122                 InfoRangeCheck (0x0000, 0xFFFF);
123                 StartAddr = InfoIVal;
124                 InfoNextTok ();
125                 break;
126
127         }
128
129         /* Directive is followed by a semicolon */
130         InfoConsumeSemi ();
131
132     }
133
134     /* Consume the closing brace */
135     InfoConsumeRCurly ();
136 }
137
138
139
140 static void RangeSection (void)
141 /* Parse a range section */
142 {
143     static const IdentTok RangeDefs[] = {
144         {   "START",            INFOTOK_START   },
145         {   "END",              INFOTOK_END     },
146         {   "TYPE",             INFOTOK_TYPE    },
147     };
148
149     static const IdentTok TypeDefs[] = {
150         {   "CODE",             INFOTOK_CODE     },
151         {   "BYTETABLE",        INFOTOK_BYTETAB  },
152         {   "WORDTABLE",        INFOTOK_WORDTAB  },
153         {   "DWORDTABLE",       INFOTOK_DWORDTAB },
154         {   "ADDRTABLE",        INFOTOK_ADDRTAB  },
155         {   "RTSTABLE",         INFOTOK_RTSTAB   },
156         {   "TEXTTABLE",        INFOTOK_TEXTTAB  },
157     };
158
159
160     /* Which values did we get? */
161     enum {
162         tNone   = 0x00,
163         tStart  = 0x01,
164         tEnd    = 0x02,
165         tType   = 0x04,
166         tAll    = 0x07
167     } Needed = tNone;
168
169     /* Locals - initialize to avoid gcc warnings */
170     unsigned Start      = 0;
171     unsigned End        = 0;
172     unsigned char Type  = 0;
173
174     /* Skip the token */
175     InfoNextTok ();
176
177     /* Expect the opening curly brace */
178     InfoConsumeLCurly ();
179
180     /* Look for section tokens */
181     while (InfoTok != INFOTOK_RCURLY) {
182
183         /* Convert to special token */
184         InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range directive");
185
186         /* Look at the token */
187         switch (InfoTok) {
188
189             case INFOTOK_START:
190                 InfoNextTok ();
191                 InfoAssureInt ();
192                 InfoRangeCheck (0x0000, 0xFFFF);
193                 Start = InfoIVal;
194                 Needed |= tStart;
195                 InfoNextTok ();
196                 break;
197
198             case INFOTOK_END:
199                 InfoNextTok ();
200                 InfoAssureInt ();
201                 InfoRangeCheck (0x0000, 0xFFFF);
202                 End = InfoIVal;
203                 Needed |= tEnd;
204                 InfoNextTok ();
205                 break;
206
207             case INFOTOK_TYPE:
208                 InfoNextTok ();
209                 InfoSpecialToken (TypeDefs, ENTRY_COUNT (TypeDefs), "Type");
210                 switch (InfoTok) {
211                     case INFOTOK_CODE:          Type = atCode;          break;
212                     case INFOTOK_BYTETAB:       Type = atByteTab;       break;
213                     case INFOTOK_WORDTAB:       Type = atWordTab;       break;
214                     case INFOTOK_DWORDTAB:      Type = atDWordTab;      break;
215                     case INFOTOK_ADDRTAB:       Type = atAddrTab;       break;
216                     case INFOTOK_RTSTAB:        Type = atRtsTab;        break;
217                     case INFOTOK_TEXTTAB:       Type = atTextTab;       break;
218                 }
219                 Needed |= tType;
220                 InfoNextTok ();
221                 break;
222         }
223
224         /* Directive is followed by a semicolon */
225         InfoConsumeSemi ();
226
227     }
228
229     /* Did we get all required values? */
230     if (Needed != tAll) {
231         InfoError ("Required values missing from this section");
232     }
233
234     /* Start must be less than end */
235     if (Start > End) {
236         InfoError ("Start value must not be greater than end value");
237     }
238
239     /* Set the range */
240     MarkRange (Start, End, Type);
241
242     /* Consume the closing brace */
243     InfoConsumeRCurly ();
244 }
245
246
247
248 static void LabelSection (void)
249 /* Parse a label section */
250 {
251     static const IdentTok LabelDefs[] = {
252         {   "NAME",     INFOTOK_NAME    },
253         {   "ADDR",     INFOTOK_ADDR    },
254         {   "SIZE",     INFOTOK_SIZE    },
255     };
256
257     /* Locals - initialize to avoid gcc warnings */
258     char* Name = 0;
259     long Value = -1;
260     long Size  = -1;
261
262     /* Skip the token */
263     InfoNextTok ();
264
265     /* Expect the opening curly brace */
266     InfoConsumeLCurly ();
267
268     /* Look for section tokens */
269     while (InfoTok != INFOTOK_RCURLY) {
270
271         /* Convert to special token */
272         InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label directive");
273
274         /* Look at the token */
275         switch (InfoTok) {
276
277             case INFOTOK_NAME:
278                 InfoNextTok ();
279                 if (Name) {
280                     InfoError ("Name already given");
281                 }
282                 InfoAssureStr ();
283                 if (InfoSVal[0] == '\0') {
284                     InfoError ("Name may not be empty");
285                 }
286                 Name = xstrdup (InfoSVal);
287                 InfoNextTok ();
288                 break;
289
290             case INFOTOK_ADDR:
291                 InfoNextTok ();
292                 if (Value >= 0) {
293                     InfoError ("Value already given");
294                 }
295                 InfoAssureInt ();
296                 InfoRangeCheck (0, 0xFFFF);
297                 Value = InfoIVal;
298                 InfoNextTok ();
299                 break;
300
301             case INFOTOK_SIZE:
302                 InfoNextTok ();
303                 if (Size >= 0) {
304                     InfoError ("Size already given");
305                 }
306                 InfoAssureInt ();
307                 InfoRangeCheck (1, 0x10000);
308                 Size = InfoIVal;
309                 InfoNextTok ();
310                 break;
311
312         }
313
314         /* Directive is followed by a semicolon */
315         InfoConsumeSemi ();
316     }
317
318     /* Did we get the necessary data */
319     if (Name == 0) {
320         InfoError ("Label name is missing");
321     }
322     if (Value < 0) {
323         InfoError ("Label value is missing");
324     }
325     if (Size < 0) {
326         /* Use default */
327         Size = 1;
328     }
329     if (Value + Size > 0x10000) {
330         InfoError ("Invalid size (address out of range)");
331     }
332     if (HaveLabel ((unsigned) Value)) {
333         InfoError ("Label for address $%04lX already defined", Value);
334     }
335
336     /* Define the label */
337     AddLabel ((unsigned) Value, atExtLabel, Name);
338
339     /* Define dependent labels if necessary */
340     if (Size > 1) {
341         unsigned Offs;
342
343         /* Allocate memory for the dependent label names */
344         unsigned NameLen = strlen (Name);
345         char*    DepName = xmalloc (NameLen + 7);
346         char*    DepOffs = DepName + NameLen + 1;
347
348         /* Copy the original name into the buffer */
349         memcpy (DepName, Name, NameLen);
350         DepName[NameLen] = '+';
351
352         /* Define the labels */
353         for (Offs = 1; Offs < (unsigned) Size; ++Offs) {
354             sprintf (DepOffs, "%u", Offs);
355             AddLabel ((unsigned) Value+Offs, atDepLabel, DepName);
356         }
357
358         /* Free the name buffer */
359         xfree (DepName);
360     }
361
362     /* Delete the dynamically allocated memory for Name */
363     xfree (Name);
364
365     /* Consume the closing brace */
366     InfoConsumeRCurly ();
367 }
368
369
370
371 static void InfoParse (void)
372 /* Parse the config file */
373 {
374     static const IdentTok Globals[] = {
375         {   "GLOBAL",   INFOTOK_GLOBAL  },
376         {   "RANGE",    INFOTOK_RANGE   },
377         {   "LABEL",    INFOTOK_LABEL   },
378     };
379
380     while (InfoTok != INFOTOK_EOF) {
381
382         /* Convert an identifier into a token */
383         InfoSpecialToken (Globals, ENTRY_COUNT (Globals), "Config directive");
384
385         /* Check the token */
386         switch (InfoTok) {
387
388             case INFOTOK_GLOBAL:
389                 GlobalSection ();
390                 break;
391
392             case INFOTOK_RANGE:
393                 RangeSection ();
394                 break;
395
396             case INFOTOK_LABEL:
397                 LabelSection ();
398                 break;
399
400         }
401
402         /* Semicolon expected */
403         InfoConsumeSemi ();
404     }
405 }
406
407
408
409 void ReadInfoFile (void)
410 /* Read the info file */
411 {
412     /* Check if we have a info file given */
413     if (InfoAvail()) {
414         /* Open the config file */
415         InfoOpenInput ();
416
417         /* Parse the config file */
418         InfoParse ();
419
420         /* Close the file */
421         InfoCloseInput ();
422     }
423 }
424
425
426
427
428
429