1 /*****************************************************************************/
5 /* Disassembler info file handling */
9 /* (C) 2000-2005 Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
40 /* Microsoft compiler */
64 /*****************************************************************************/
66 /*****************************************************************************/
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 */
74 /* Attribute is already in the set */
75 InfoError ("%s given twice", Name);
82 static void GlobalSection (void)
83 /* Parse a global section */
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 },
101 /* Expect the opening curly brace */
102 InfoConsumeLCurly ();
104 /* Look for section tokens */
105 while (InfoTok != INFOTOK_RCURLY) {
107 /* Convert to special token */
108 InfoSpecialToken (GlobalDefs, ENTRY_COUNT (GlobalDefs), "Global directive");
110 /* Look at the token */
113 case INFOTOK_COMMENTS:
116 InfoRangeCheck (MIN_COMMENTS, MAX_COMMENTS);
124 if (CPU != CPU_UNKNOWN) {
125 InfoError ("CPU already specified");
127 CPU = FindCPU (InfoSVal);
132 case INFOTOK_HEXOFFS:
136 case INFOTOK_FALSE: UseHexOffs = 0; break;
137 case INFOTOK_TRUE: UseHexOffs = 1; break;
142 case INFOTOK_INPUTNAME:
146 InfoError ("Input file name already given");
148 InFile = xstrdup (InfoSVal);
152 case INFOTOK_INPUTOFFS:
155 InputOffs = InfoIVal;
159 case INFOTOK_INPUTSIZE:
162 InfoRangeCheck (1, 0x10000);
163 InputSize = InfoIVal;
167 case INFOTOK_LABELBREAK:
170 InfoRangeCheck (0, UCHAR_MAX);
171 LBreak = (unsigned char) InfoIVal;
175 case INFOTOK_OUTPUTNAME:
179 InfoError ("Output file name already given");
181 OutFile = xstrdup (InfoSVal);
185 case INFOTOK_PAGELENGTH:
189 InfoRangeCheck (MIN_PAGE_LEN, MAX_PAGE_LEN);
191 PageLength = InfoIVal;
195 case INFOTOK_STARTADDR:
198 InfoRangeCheck (0x0000, 0xFFFF);
199 StartAddr = InfoIVal;
205 /* Directive is followed by a semicolon */
210 /* Consume the closing brace */
211 InfoConsumeRCurly ();
216 static void RangeSection (void)
217 /* Parse a range section */
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 },
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 },
240 /* Which values did we get? */
248 tNeeded = (tStart | tEnd | tType)
250 unsigned Attributes = tNone;
252 /* Locals - initialize to avoid gcc warnings */
255 unsigned char Type = 0;
258 unsigned MemberSize = 0;
264 /* Expect the opening curly brace */
265 InfoConsumeLCurly ();
267 /* Look for section tokens */
268 while (InfoTok != INFOTOK_RCURLY) {
270 /* Convert to special token */
271 InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range directive");
273 /* Look at the token */
276 case INFOTOK_COMMENT:
277 AddAttr ("COMMENT", &Attributes, tComment);
280 if (InfoSVal[0] == '\0') {
281 InfoError ("Comment may not be empty");
283 Comment = xstrdup (InfoSVal);
284 Attributes |= tComment;
289 AddAttr ("END", &Attributes, tEnd);
292 InfoRangeCheck (0x0000, 0xFFFF);
298 AddAttr ("NAME", &Attributes, tName);
301 if (InfoSVal[0] == '\0') {
302 InfoError ("Name may not be empty");
304 Name = xstrdup (InfoSVal);
310 AddAttr ("START", &Attributes, tStart);
313 InfoRangeCheck (0x0000, 0xFFFF);
319 AddAttr ("TYPE", &Attributes, tType);
321 InfoSpecialToken (TypeDefs, ENTRY_COUNT (TypeDefs), "TYPE");
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;
337 /* Directive is followed by a semicolon */
342 /* Did we get all required values? */
343 if ((Attributes & tNeeded) != tNeeded) {
344 InfoError ("Required values missing from this section");
347 /* Start must be less than end */
349 InfoError ("Start value must not be greater than end value");
352 /* Check the granularity */
353 if (((End - Start + 1) % MemberSize) != 0) {
354 InfoError ("Type of range needs a granularity of %u", MemberSize);
358 MarkRange (Start, End, Type);
360 /* Do we have a label? */
361 if (Attributes & tName) {
363 /* Define a label for the table */
364 AddExtLabel (Start, Name);
366 /* Set the comment if we have one */
368 SetComment (Start, Comment);
371 /* Delete name and comment */
376 /* Consume the closing brace */
377 InfoConsumeRCurly ();
382 static void LabelSection (void)
383 /* Parse a label section */
385 static const IdentTok LabelDefs[] = {
386 { "COMMENT", INFOTOK_COMMENT },
387 { "ADDR", INFOTOK_ADDR },
388 { "NAME", INFOTOK_NAME },
389 { "SIZE", INFOTOK_SIZE },
392 /* Locals - initialize to avoid gcc warnings */
401 /* Expect the opening curly brace */
402 InfoConsumeLCurly ();
404 /* Look for section tokens */
405 while (InfoTok != INFOTOK_RCURLY) {
407 /* Convert to special token */
408 InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label directive");
410 /* Look at the token */
416 InfoError ("Value already given");
419 InfoRangeCheck (0, 0xFFFF);
424 case INFOTOK_COMMENT:
427 InfoError ("Comment already given");
430 if (InfoSVal[0] == '\0') {
431 InfoError ("Comment may not be empty");
433 Comment = xstrdup (InfoSVal);
440 InfoError ("Name already given");
443 Name = xstrdup (InfoSVal);
450 InfoError ("Size already given");
453 InfoRangeCheck (1, 0x10000);
460 /* Directive is followed by a semicolon */
464 /* Did we get the necessary data */
466 InfoError ("Label name is missing");
468 if (Name[0] == '\0' && Size > 1) {
469 InfoError ("Unnamed labels must not have a size > 1");
472 InfoError ("Label value is missing");
478 if (Value + Size > 0x10000) {
479 InfoError ("Invalid size (address out of range)");
481 if (HaveLabel ((unsigned) Value)) {
482 InfoError ("Label for address $%04lX already defined", Value);
485 /* Define the label(s) */
486 if (Name[0] == '\0') {
487 /* Size has already beed checked */
488 AddUnnamedLabel (Value);
490 AddExtLabelRange ((unsigned) Value, Name, Size);
493 /* Define the comment */
495 SetComment (Value, Comment);
498 /* Delete the dynamically allocated memory for Name and Comment */
502 /* Consume the closing brace */
503 InfoConsumeRCurly ();
508 static void AsmIncSection (void)
509 /* Parse a asminc section */
511 static const IdentTok LabelDefs[] = {
512 { "COMMENTSTART", INFOTOK_COMMENTSTART },
513 { "FILE", INFOTOK_FILE },
514 { "IGNOREUNKNOWN", INFOTOK_IGNOREUNKNOWN },
517 /* Locals - initialize to avoid gcc warnings */
519 int CommentStart = EOF;
520 int IgnoreUnknown = -1;
525 /* Expect the opening curly brace */
526 InfoConsumeLCurly ();
528 /* Look for section tokens */
529 while (InfoTok != INFOTOK_RCURLY) {
531 /* Convert to special token */
532 InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Asminc directive");
534 /* Look at the token */
537 case INFOTOK_COMMENTSTART:
539 if (CommentStart != EOF) {
540 InfoError ("Commentstart already given");
543 CommentStart = (char) InfoIVal;
550 InfoError ("File name already given");
553 if (InfoSVal[0] == '\0') {
554 InfoError ("File name may not be empty");
556 Name = xstrdup (InfoSVal);
560 case INFOTOK_IGNOREUNKNOWN:
562 if (IgnoreUnknown != -1) {
563 InfoError ("Ignoreunknown already specified");
566 IgnoreUnknown = (InfoTok != INFOTOK_FALSE);
571 /* Directive is followed by a semicolon */
575 /* Check for the necessary data and assume defaults */
577 InfoError ("File name is missing");
579 if (CommentStart == EOF) {
582 if (IgnoreUnknown == -1) {
586 /* Open the file and read the symbol definitions */
587 AsmInc (Name, CommentStart, IgnoreUnknown);
589 /* Delete the dynamically allocated memory for Name */
592 /* Consume the closing brace */
593 InfoConsumeRCurly ();
598 static void InfoParse (void)
599 /* Parse the config file */
601 static const IdentTok Globals[] = {
602 { "GLOBAL", INFOTOK_GLOBAL },
603 { "RANGE", INFOTOK_RANGE },
604 { "LABEL", INFOTOK_LABEL },
605 { "ASMINC", INFOTOK_ASMINC },
608 while (InfoTok != INFOTOK_EOF) {
610 /* Convert an identifier into a token */
611 InfoSpecialToken (Globals, ENTRY_COUNT (Globals), "Config directive");
613 /* Check the token */
633 /* Semicolon expected */
640 void ReadInfoFile (void)
641 /* Read the info file */
643 /* Check if we have a info file given */
645 /* Open the config file */
648 /* Parse the config file */