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