1 /*****************************************************************************/
5 /* Disassembler info file handling */
9 /* (C) 2000-2014, 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 { "NEWLINEAFTERJMP", INFOTOK_NL_AFTER_JMP },
194 { "NEWLINEAFTERRTS", INFOTOK_NL_AFTER_RTS },
195 { "OUTPUTNAME", INFOTOK_OUTPUTNAME },
196 { "PAGELENGTH", INFOTOK_PAGELENGTH },
197 { "STARTADDR", INFOTOK_STARTADDR },
198 { "TEXTCOL", INFOTOK_TEXT_COLUMN },
199 { "TEXTCOLUMN", INFOTOK_TEXT_COLUMN },
205 /* Expect the opening curly brace */
206 InfoConsumeLCurly ();
208 /* Look for section tokens */
209 while (InfoTok != INFOTOK_RCURLY) {
211 /* Convert to special token */
212 InfoSpecialToken (GlobalDefs, ENTRY_COUNT (GlobalDefs), "Global directive");
214 /* Look at the token */
217 case INFOTOK_ARGUMENT_COLUMN:
220 InfoRangeCheck (MIN_ACOL, MAX_ACOL);
225 case INFOTOK_COMMENT_COLUMN:
228 InfoRangeCheck (MIN_CCOL, MAX_CCOL);
233 case INFOTOK_COMMENTS:
236 InfoRangeCheck (MIN_COMMENTS, MAX_COMMENTS);
244 if (CPU != CPU_UNKNOWN) {
245 InfoError ("CPU already specified");
247 CPU = FindCPU (InfoSVal);
252 case INFOTOK_HEXOFFS:
256 case INFOTOK_FALSE: UseHexOffs = 0; break;
257 case INFOTOK_TRUE: UseHexOffs = 1; break;
262 case INFOTOK_INPUTNAME:
266 InfoError ("Input file name already given");
268 InFile = xstrdup (InfoSVal);
272 case INFOTOK_INPUTOFFS:
275 InputOffs = InfoIVal;
279 case INFOTOK_INPUTSIZE:
282 InfoRangeCheck (1, 0x10000);
283 InputSize = InfoIVal;
287 case INFOTOK_LABELBREAK:
290 InfoRangeCheck (0, UCHAR_MAX);
291 LBreak = (unsigned char) InfoIVal;
295 case INFOTOK_MNEMONIC_COLUMN:
298 InfoRangeCheck (MIN_MCOL, MAX_MCOL);
303 case INFOTOK_NL_AFTER_JMP:
305 if (NewlineAfterJMP != -1) {
306 InfoError ("NLAfterJMP already specified");
309 NewlineAfterJMP = (InfoTok != INFOTOK_FALSE);
313 case INFOTOK_NL_AFTER_RTS:
316 if (NewlineAfterRTS != -1) {
317 InfoError ("NLAfterRTS already specified");
319 NewlineAfterRTS = (InfoTok != INFOTOK_FALSE);
323 case INFOTOK_OUTPUTNAME:
327 InfoError ("Output file name already given");
329 OutFile = xstrdup (InfoSVal);
333 case INFOTOK_PAGELENGTH:
337 InfoRangeCheck (MIN_PAGE_LEN, MAX_PAGE_LEN);
339 PageLength = InfoIVal;
343 case INFOTOK_STARTADDR:
346 InfoRangeCheck (0x0000, 0xFFFF);
347 StartAddr = InfoIVal;
351 case INFOTOK_TEXT_COLUMN:
354 InfoRangeCheck (MIN_TCOL, MAX_TCOL);
360 Internal ("Unexpected token: %u", InfoTok);
364 /* Directive is followed by a semicolon */
369 /* Consume the closing brace */
370 InfoConsumeRCurly ();
375 static void LabelSection (void)
376 /* Parse a label section */
378 static const IdentTok LabelDefs[] = {
379 { "COMMENT", INFOTOK_COMMENT },
380 { "ADDR", INFOTOK_ADDR },
381 { "NAME", INFOTOK_NAME },
382 { "SIZE", INFOTOK_SIZE },
385 /* Locals - initialize to avoid gcc warnings */
394 /* Expect the opening curly brace */
395 InfoConsumeLCurly ();
397 /* Look for section tokens */
398 while (InfoTok != INFOTOK_RCURLY) {
400 /* Convert to special token */
401 InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label attribute");
403 /* Look at the token */
409 InfoError ("Value already given");
412 InfoRangeCheck (0, 0xFFFF);
417 case INFOTOK_COMMENT:
420 InfoError ("Comment already given");
423 if (InfoSVal[0] == '\0') {
424 InfoError ("Comment may not be empty");
426 Comment = xstrdup (InfoSVal);
433 InfoError ("Name already given");
436 Name = xstrdup (InfoSVal);
443 InfoError ("Size already given");
446 InfoRangeCheck (1, 0x10000);
452 Internal ("Unexpected token: %u", InfoTok);
455 /* Directive is followed by a semicolon */
459 /* Did we get the necessary data */
461 InfoError ("Label name is missing");
463 if (Name[0] == '\0' && Size > 1) {
464 InfoError ("Unnamed labels must not have a size > 1");
467 InfoError ("Label value is missing");
473 if (Value + Size > 0x10000) {
474 InfoError ("Invalid size (address out of range)");
476 if (HaveLabel ((unsigned) Value)) {
477 InfoError ("Label for address $%04lX already defined", Value);
480 /* Define the label(s) */
481 if (Name[0] == '\0') {
482 /* Size has already beed checked */
483 AddUnnamedLabel (Value);
485 AddExtLabelRange ((unsigned) Value, Name, Size);
488 /* Define the comment */
490 SetComment (Value, Comment);
493 /* Delete the dynamically allocated memory for Name and Comment */
497 /* Consume the closing brace */
498 InfoConsumeRCurly ();
503 static void RangeSection (void)
504 /* Parse a range section */
506 static const IdentTok RangeDefs[] = {
507 { "COMMENT", INFOTOK_COMMENT },
508 { "END", INFOTOK_END },
509 { "NAME", INFOTOK_NAME },
510 { "START", INFOTOK_START },
511 { "TYPE", INFOTOK_TYPE },
514 static const IdentTok TypeDefs[] = {
515 { "ADDRTABLE", INFOTOK_ADDRTAB },
516 { "BYTETABLE", INFOTOK_BYTETAB },
517 { "CODE", INFOTOK_CODE },
518 { "DBYTETABLE", INFOTOK_DBYTETAB },
519 { "DWORDTABLE", INFOTOK_DWORDTAB },
520 { "RTSTABLE", INFOTOK_RTSTAB },
521 { "SKIP", INFOTOK_SKIP },
522 { "TEXTTABLE", INFOTOK_TEXTTAB },
523 { "WORDTABLE", INFOTOK_WORDTAB },
527 /* Which values did we get? */
535 tNeeded = (tStart | tEnd | tType)
537 unsigned Attributes = tNone;
539 /* Locals - initialize to avoid gcc warnings */
542 unsigned char Type = 0;
545 unsigned MemberSize = 0;
551 /* Expect the opening curly brace */
552 InfoConsumeLCurly ();
554 /* Look for section tokens */
555 while (InfoTok != INFOTOK_RCURLY) {
557 /* Convert to special token */
558 InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range attribute");
560 /* Look at the token */
563 case INFOTOK_COMMENT:
564 AddAttr ("COMMENT", &Attributes, tComment);
567 if (InfoSVal[0] == '\0') {
568 InfoError ("Comment may not be empty");
570 Comment = xstrdup (InfoSVal);
571 Attributes |= tComment;
576 AddAttr ("END", &Attributes, tEnd);
579 InfoRangeCheck (0x0000, 0xFFFF);
585 AddAttr ("NAME", &Attributes, tName);
588 if (InfoSVal[0] == '\0') {
589 InfoError ("Name may not be empty");
591 Name = xstrdup (InfoSVal);
597 AddAttr ("START", &Attributes, tStart);
600 InfoRangeCheck (0x0000, 0xFFFF);
606 AddAttr ("TYPE", &Attributes, tType);
608 InfoSpecialToken (TypeDefs, ENTRY_COUNT (TypeDefs), "TYPE");
610 case INFOTOK_ADDRTAB: Type = atAddrTab; MemberSize = 2; break;
611 case INFOTOK_BYTETAB: Type = atByteTab; MemberSize = 1; break;
612 case INFOTOK_CODE: Type = atCode; MemberSize = 1; break;
613 case INFOTOK_DBYTETAB: Type = atDByteTab; MemberSize = 2; break;
614 case INFOTOK_DWORDTAB: Type = atDWordTab; MemberSize = 4; break;
615 case INFOTOK_RTSTAB: Type = atRtsTab; MemberSize = 2; break;
616 case INFOTOK_SKIP: Type = atSkip; MemberSize = 1; break;
617 case INFOTOK_TEXTTAB: Type = atTextTab; MemberSize = 1; break;
618 case INFOTOK_WORDTAB: Type = atWordTab; MemberSize = 2; break;
624 Internal ("Unexpected token: %u", InfoTok);
627 /* Directive is followed by a semicolon */
632 /* Did we get all required values? */
633 if ((Attributes & tNeeded) != tNeeded) {
634 InfoError ("Required values missing from this section");
637 /* Start must be less than end */
639 InfoError ("Start value must not be greater than end value");
642 /* Check the granularity */
643 if (((End - Start + 1) % MemberSize) != 0) {
644 InfoError ("Type of range needs a granularity of %u", MemberSize);
648 MarkRange (Start, End, Type);
650 /* Do we have a label? */
651 if (Attributes & tName) {
653 /* Define a label for the table */
654 AddExtLabel (Start, Name);
656 /* Set the comment if we have one */
658 SetComment (Start, Comment);
661 /* Delete name and comment */
666 /* Consume the closing brace */
667 InfoConsumeRCurly ();
672 static void SegmentSection (void)
673 /* Parse a segment section */
675 static const IdentTok LabelDefs[] = {
676 { "END", INFOTOK_END },
677 { "NAME", INFOTOK_NAME },
678 { "START", INFOTOK_START },
681 /* Locals - initialize to avoid gcc warnings */
689 /* Expect the opening curly brace */
690 InfoConsumeLCurly ();
692 /* Look for section tokens */
693 while (InfoTok != INFOTOK_RCURLY) {
695 /* Convert to special token */
696 InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Segment attribute");
698 /* Look at the token */
704 InfoError ("Value already given");
707 InfoRangeCheck (0, 0xFFFF);
715 InfoError ("Name already given");
718 Name = xstrdup (InfoSVal);
725 InfoError ("Value already given");
728 InfoRangeCheck (0, 0xFFFF);
734 Internal ("Unexpected token: %u", InfoTok);
737 /* Directive is followed by a semicolon */
741 /* Did we get the necessary data, and is it correct? */
742 if (Name == 0 || Name[0] == '\0') {
743 InfoError ("Segment name is missing");
746 InfoError ("End address is missing");
749 InfoError ("Start address is missing");
752 InfoError ("Start address of segment is greater than end address");
755 /* Check that segments do not overlap */
756 if (SegmentDefined ((unsigned) Start, (unsigned) End)) {
757 InfoError ("Segments must not overlap");
760 /* Remember the segment data */
761 AddAbsSegment ((unsigned) Start, (unsigned) End, Name);
763 /* Delete the dynamically allocated memory for Name */
766 /* Consume the closing brace */
767 InfoConsumeRCurly ();
772 static void InfoParse (void)
773 /* Parse the config file */
775 static const IdentTok Globals[] = {
776 { "ASMINC", INFOTOK_ASMINC },
777 { "GLOBAL", INFOTOK_GLOBAL },
778 { "LABEL", INFOTOK_LABEL },
779 { "RANGE", INFOTOK_RANGE },
780 { "SEGMENT", INFOTOK_SEGMENT },
783 while (InfoTok != INFOTOK_EOF) {
785 /* Convert an identifier into a token */
786 InfoSpecialToken (Globals, ENTRY_COUNT (Globals), "Config directive");
788 /* Check the token */
807 case INFOTOK_SEGMENT:
812 Internal ("Unexpected token: %u", InfoTok);
815 /* Semicolon expected */
822 void ReadInfoFile (void)
823 /* Read the info file */
825 /* Check if we have a info file given */
827 /* Open the config file */
830 /* Parse the config file */