1 /*****************************************************************************/
5 /* Disassembler info file handling */
9 /* (C) 2000-2007 Ullrich von Bassewitz */
10 /* Roemerstrasse 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 */
65 /*****************************************************************************/
67 /*****************************************************************************/
71 static void AddAttr (const char* Name, unsigned* Set, unsigned Attr)
72 /* Add an attribute to the set and check that it is not given twice */
75 /* Attribute is already in the set */
76 InfoError ("%s given twice", Name);
83 static void AsmIncSection (void)
84 /* Parse a asminc section */
86 static const IdentTok LabelDefs[] = {
87 { "COMMENTSTART", INFOTOK_COMMENTSTART },
88 { "FILE", INFOTOK_FILE },
89 { "IGNOREUNKNOWN", INFOTOK_IGNOREUNKNOWN },
92 /* Locals - initialize to avoid gcc warnings */
94 int CommentStart = EOF;
95 int IgnoreUnknown = -1;
100 /* Expect the opening curly brace */
101 InfoConsumeLCurly ();
103 /* Look for section tokens */
104 while (InfoTok != INFOTOK_RCURLY) {
106 /* Convert to special token */
107 InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Asminc directive");
109 /* Look at the token */
112 case INFOTOK_COMMENTSTART:
114 if (CommentStart != EOF) {
115 InfoError ("Commentstart already given");
118 CommentStart = (char) InfoIVal;
125 InfoError ("File name already given");
128 if (InfoSVal[0] == '\0') {
129 InfoError ("File name may not be empty");
131 Name = xstrdup (InfoSVal);
135 case INFOTOK_IGNOREUNKNOWN:
137 if (IgnoreUnknown != -1) {
138 InfoError ("Ignoreunknown already specified");
141 IgnoreUnknown = (InfoTok != INFOTOK_FALSE);
146 Internal ("Unexpected token: %u", InfoTok);
149 /* Directive is followed by a semicolon */
153 /* Check for the necessary data and assume defaults */
155 InfoError ("File name is missing");
157 if (CommentStart == EOF) {
160 if (IgnoreUnknown == -1) {
164 /* Open the file and read the symbol definitions */
165 AsmInc (Name, CommentStart, IgnoreUnknown);
167 /* Delete the dynamically allocated memory for Name */
170 /* Consume the closing brace */
171 InfoConsumeRCurly ();
176 static void GlobalSection (void)
177 /* Parse a global section */
179 static const IdentTok GlobalDefs[] = {
180 { "ARGUMENTCOL", INFOTOK_ARGUMENT_COLUMN },
181 { "ARGUMENTCOLUMN", INFOTOK_ARGUMENT_COLUMN },
182 { "COMMENTCOL", INFOTOK_COMMENT_COLUMN },
183 { "COMMENTCOLUMN", INFOTOK_COMMENT_COLUMN },
184 { "COMMENTS", INFOTOK_COMMENTS },
185 { "CPU", INFOTOK_CPU },
186 { "HEXOFFS", INFOTOK_HEXOFFS },
187 { "INPUTNAME", INFOTOK_INPUTNAME },
188 { "INPUTOFFS", INFOTOK_INPUTOFFS },
189 { "INPUTSIZE", INFOTOK_INPUTSIZE },
190 { "LABELBREAK", INFOTOK_LABELBREAK },
191 { "MNEMONICCOL", INFOTOK_MNEMONIC_COLUMN },
192 { "MNEMONICCOLUMN", INFOTOK_MNEMONIC_COLUMN },
193 { "OUTPUTNAME", INFOTOK_OUTPUTNAME },
194 { "PAGELENGTH", INFOTOK_PAGELENGTH },
195 { "STARTADDR", INFOTOK_STARTADDR },
196 { "TEXTCOL", INFOTOK_TEXT_COLUMN },
197 { "TEXTCOLUMN", INFOTOK_TEXT_COLUMN },
203 /* Expect the opening curly brace */
204 InfoConsumeLCurly ();
206 /* Look for section tokens */
207 while (InfoTok != INFOTOK_RCURLY) {
209 /* Convert to special token */
210 InfoSpecialToken (GlobalDefs, ENTRY_COUNT (GlobalDefs), "Global directive");
212 /* Look at the token */
215 case INFOTOK_ARGUMENT_COLUMN:
218 InfoRangeCheck (MIN_ACOL, MAX_ACOL);
223 case INFOTOK_COMMENT_COLUMN:
226 InfoRangeCheck (MIN_CCOL, MAX_CCOL);
231 case INFOTOK_COMMENTS:
234 InfoRangeCheck (MIN_COMMENTS, MAX_COMMENTS);
242 if (CPU != CPU_UNKNOWN) {
243 InfoError ("CPU already specified");
245 CPU = FindCPU (InfoSVal);
250 case INFOTOK_HEXOFFS:
254 case INFOTOK_FALSE: UseHexOffs = 0; break;
255 case INFOTOK_TRUE: UseHexOffs = 1; break;
260 case INFOTOK_INPUTNAME:
264 InfoError ("Input file name already given");
266 InFile = xstrdup (InfoSVal);
270 case INFOTOK_INPUTOFFS:
273 InputOffs = InfoIVal;
277 case INFOTOK_INPUTSIZE:
280 InfoRangeCheck (1, 0x10000);
281 InputSize = InfoIVal;
285 case INFOTOK_LABELBREAK:
288 InfoRangeCheck (0, UCHAR_MAX);
289 LBreak = (unsigned char) InfoIVal;
293 case INFOTOK_MNEMONIC_COLUMN:
296 InfoRangeCheck (MIN_MCOL, MAX_MCOL);
301 case INFOTOK_OUTPUTNAME:
305 InfoError ("Output file name already given");
307 OutFile = xstrdup (InfoSVal);
311 case INFOTOK_PAGELENGTH:
315 InfoRangeCheck (MIN_PAGE_LEN, MAX_PAGE_LEN);
317 PageLength = InfoIVal;
321 case INFOTOK_STARTADDR:
324 InfoRangeCheck (0x0000, 0xFFFF);
325 StartAddr = InfoIVal;
329 case INFOTOK_TEXT_COLUMN:
332 InfoRangeCheck (MIN_TCOL, MAX_TCOL);
338 Internal ("Unexpected token: %u", InfoTok);
342 /* Directive is followed by a semicolon */
347 /* Consume the closing brace */
348 InfoConsumeRCurly ();
353 static void LabelSection (void)
354 /* Parse a label section */
356 static const IdentTok LabelDefs[] = {
357 { "COMMENT", INFOTOK_COMMENT },
358 { "ADDR", INFOTOK_ADDR },
359 { "NAME", INFOTOK_NAME },
360 { "SIZE", INFOTOK_SIZE },
363 /* Locals - initialize to avoid gcc warnings */
372 /* Expect the opening curly brace */
373 InfoConsumeLCurly ();
375 /* Look for section tokens */
376 while (InfoTok != INFOTOK_RCURLY) {
378 /* Convert to special token */
379 InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label attribute");
381 /* Look at the token */
387 InfoError ("Value already given");
390 InfoRangeCheck (0, 0xFFFF);
395 case INFOTOK_COMMENT:
398 InfoError ("Comment already given");
401 if (InfoSVal[0] == '\0') {
402 InfoError ("Comment may not be empty");
404 Comment = xstrdup (InfoSVal);
411 InfoError ("Name already given");
414 Name = xstrdup (InfoSVal);
421 InfoError ("Size already given");
424 InfoRangeCheck (1, 0x10000);
430 Internal ("Unexpected token: %u", InfoTok);
433 /* Directive is followed by a semicolon */
437 /* Did we get the necessary data */
439 InfoError ("Label name is missing");
441 if (Name[0] == '\0' && Size > 1) {
442 InfoError ("Unnamed labels must not have a size > 1");
445 InfoError ("Label value is missing");
451 if (Value + Size > 0x10000) {
452 InfoError ("Invalid size (address out of range)");
454 if (HaveLabel ((unsigned) Value)) {
455 InfoError ("Label for address $%04lX already defined", Value);
458 /* Define the label(s) */
459 if (Name[0] == '\0') {
460 /* Size has already beed checked */
461 AddUnnamedLabel (Value);
463 AddExtLabelRange ((unsigned) Value, Name, Size);
466 /* Define the comment */
468 SetComment (Value, Comment);
471 /* Delete the dynamically allocated memory for Name and Comment */
475 /* Consume the closing brace */
476 InfoConsumeRCurly ();
481 static void RangeSection (void)
482 /* Parse a range section */
484 static const IdentTok RangeDefs[] = {
485 { "COMMENT", INFOTOK_COMMENT },
486 { "END", INFOTOK_END },
487 { "NAME", INFOTOK_NAME },
488 { "START", INFOTOK_START },
489 { "TYPE", INFOTOK_TYPE },
492 static const IdentTok TypeDefs[] = {
493 { "ADDRTABLE", INFOTOK_ADDRTAB },
494 { "BYTETABLE", INFOTOK_BYTETAB },
495 { "CODE", INFOTOK_CODE },
496 { "DBYTETABLE", INFOTOK_DBYTETAB },
497 { "DWORDTABLE", INFOTOK_DWORDTAB },
498 { "RTSTABLE", INFOTOK_RTSTAB },
499 { "SKIP", INFOTOK_SKIP },
500 { "TEXTTABLE", INFOTOK_TEXTTAB },
501 { "WORDTABLE", INFOTOK_WORDTAB },
505 /* Which values did we get? */
513 tNeeded = (tStart | tEnd | tType)
515 unsigned Attributes = tNone;
517 /* Locals - initialize to avoid gcc warnings */
520 unsigned char Type = 0;
523 unsigned MemberSize = 0;
529 /* Expect the opening curly brace */
530 InfoConsumeLCurly ();
532 /* Look for section tokens */
533 while (InfoTok != INFOTOK_RCURLY) {
535 /* Convert to special token */
536 InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range attribute");
538 /* Look at the token */
541 case INFOTOK_COMMENT:
542 AddAttr ("COMMENT", &Attributes, tComment);
545 if (InfoSVal[0] == '\0') {
546 InfoError ("Comment may not be empty");
548 Comment = xstrdup (InfoSVal);
549 Attributes |= tComment;
554 AddAttr ("END", &Attributes, tEnd);
557 InfoRangeCheck (0x0000, 0xFFFF);
563 AddAttr ("NAME", &Attributes, tName);
566 if (InfoSVal[0] == '\0') {
567 InfoError ("Name may not be empty");
569 Name = xstrdup (InfoSVal);
575 AddAttr ("START", &Attributes, tStart);
578 InfoRangeCheck (0x0000, 0xFFFF);
584 AddAttr ("TYPE", &Attributes, tType);
586 InfoSpecialToken (TypeDefs, ENTRY_COUNT (TypeDefs), "TYPE");
588 case INFOTOK_ADDRTAB: Type = atAddrTab; MemberSize = 2; break;
589 case INFOTOK_BYTETAB: Type = atByteTab; MemberSize = 1; break;
590 case INFOTOK_CODE: Type = atCode; MemberSize = 1; break;
591 case INFOTOK_DBYTETAB: Type = atDByteTab; MemberSize = 2; break;
592 case INFOTOK_DWORDTAB: Type = atDWordTab; MemberSize = 4; break;
593 case INFOTOK_RTSTAB: Type = atRtsTab; MemberSize = 2; break;
594 case INFOTOK_SKIP: Type = atSkip; MemberSize = 1; break;
595 case INFOTOK_TEXTTAB: Type = atTextTab; MemberSize = 1; break;
596 case INFOTOK_WORDTAB: Type = atWordTab; MemberSize = 2; break;
602 Internal ("Unexpected token: %u", InfoTok);
605 /* Directive is followed by a semicolon */
610 /* Did we get all required values? */
611 if ((Attributes & tNeeded) != tNeeded) {
612 InfoError ("Required values missing from this section");
615 /* Start must be less than end */
617 InfoError ("Start value must not be greater than end value");
620 /* Check the granularity */
621 if (((End - Start + 1) % MemberSize) != 0) {
622 InfoError ("Type of range needs a granularity of %u", MemberSize);
626 MarkRange (Start, End, Type);
628 /* Do we have a label? */
629 if (Attributes & tName) {
631 /* Define a label for the table */
632 AddExtLabel (Start, Name);
634 /* Set the comment if we have one */
636 SetComment (Start, Comment);
639 /* Delete name and comment */
644 /* Consume the closing brace */
645 InfoConsumeRCurly ();
650 static void SegmentSection (void)
651 /* Parse a segment section */
653 static const IdentTok LabelDefs[] = {
654 { "END", INFOTOK_END },
655 { "NAME", INFOTOK_NAME },
656 { "START", INFOTOK_START },
659 /* Locals - initialize to avoid gcc warnings */
667 /* Expect the opening curly brace */
668 InfoConsumeLCurly ();
670 /* Look for section tokens */
671 while (InfoTok != INFOTOK_RCURLY) {
673 /* Convert to special token */
674 InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Segment attribute");
676 /* Look at the token */
682 InfoError ("Value already given");
685 InfoRangeCheck (0, 0xFFFF);
693 InfoError ("Name already given");
696 Name = xstrdup (InfoSVal);
703 InfoError ("Value already given");
706 InfoRangeCheck (0, 0xFFFF);
712 Internal ("Unexpected token: %u", InfoTok);
715 /* Directive is followed by a semicolon */
719 /* Did we get the necessary data, and is it correct? */
720 if (Name == 0 || Name[0] == '\0') {
721 InfoError ("Segment name is missing");
724 InfoError ("End address is missing");
727 InfoError ("Start address is missing");
730 InfoError ("Segment is empty");
733 InfoError ("Start address of segment is greater than end address");
736 /* Check that segments do not overlap */
737 if (SegmentDefined ((unsigned) Start, (unsigned) End)) {
738 InfoError ("Segments cannot overlap");
741 /* Remember the segment data */
742 AddAbsSegment ((unsigned) Start, (unsigned) End, Name);
744 /* Delete the dynamically allocated memory for Name */
747 /* Consume the closing brace */
748 InfoConsumeRCurly ();
753 static void InfoParse (void)
754 /* Parse the config file */
756 static const IdentTok Globals[] = {
757 { "ASMINC", INFOTOK_ASMINC },
758 { "GLOBAL", INFOTOK_GLOBAL },
759 { "LABEL", INFOTOK_LABEL },
760 { "RANGE", INFOTOK_RANGE },
761 { "SEGMENT", INFOTOK_SEGMENT },
764 while (InfoTok != INFOTOK_EOF) {
766 /* Convert an identifier into a token */
767 InfoSpecialToken (Globals, ENTRY_COUNT (Globals), "Config directive");
769 /* Check the token */
788 case INFOTOK_SEGMENT:
793 Internal ("Unexpected token: %u", InfoTok);
796 /* Semicolon expected */
803 void ReadInfoFile (void)
804 /* Read the info file */
806 /* Check if we have a info file given */
808 /* Open the config file */
811 /* Parse the config file */