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 */
66 /*****************************************************************************/
68 /*****************************************************************************/
72 static void AddAttr (const char* Name, unsigned* Set, unsigned Attr)
73 /* Add an attribute to the set and check that it is not given twice */
76 /* Attribute is already in the set */
77 InfoError ("%s given twice", Name);
84 static void AsmIncSection (void)
85 /* Parse a asminc section */
87 static const IdentTok LabelDefs[] = {
88 { "COMMENTSTART", INFOTOK_COMMENTSTART },
89 { "FILE", INFOTOK_FILE },
90 { "IGNOREUNKNOWN", INFOTOK_IGNOREUNKNOWN },
93 /* Locals - initialize to avoid gcc warnings */
95 int CommentStart = EOF;
96 int IgnoreUnknown = -1;
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 (LabelDefs, ENTRY_COUNT (LabelDefs), "Asminc directive");
110 /* Look at the token */
113 case INFOTOK_COMMENTSTART:
115 if (CommentStart != EOF) {
116 InfoError ("Commentstart already given");
119 CommentStart = (char) InfoIVal;
126 InfoError ("File name already given");
129 if (InfoSVal[0] == '\0') {
130 InfoError ("File name may not be empty");
132 Name = xstrdup (InfoSVal);
136 case INFOTOK_IGNOREUNKNOWN:
138 if (IgnoreUnknown != -1) {
139 InfoError ("Ignoreunknown already specified");
142 IgnoreUnknown = (InfoTok != INFOTOK_FALSE);
147 Internal ("Unexpected token: %u", InfoTok);
150 /* Directive is followed by a semicolon */
154 /* Check for the necessary data and assume defaults */
156 InfoError ("File name is missing");
158 if (CommentStart == EOF) {
161 if (IgnoreUnknown == -1) {
165 /* Open the file and read the symbol definitions */
166 AsmInc (Name, CommentStart, IgnoreUnknown);
168 /* Delete the dynamically allocated memory for Name */
171 /* Consume the closing brace */
172 InfoConsumeRCurly ();
177 static void GlobalSection (void)
178 /* Parse a global section */
180 static const IdentTok GlobalDefs[] = {
181 { "ARGUMENTCOL", INFOTOK_ARGUMENT_COLUMN },
182 { "ARGUMENTCOLUMN", INFOTOK_ARGUMENT_COLUMN },
183 { "COMMENTCOL", INFOTOK_COMMENT_COLUMN },
184 { "COMMENTCOLUMN", INFOTOK_COMMENT_COLUMN },
185 { "COMMENTS", INFOTOK_COMMENTS },
186 { "CPU", INFOTOK_CPU },
187 { "HEXOFFS", INFOTOK_HEXOFFS },
188 { "INPUTNAME", INFOTOK_INPUTNAME },
189 { "INPUTOFFS", INFOTOK_INPUTOFFS },
190 { "INPUTSIZE", INFOTOK_INPUTSIZE },
191 { "LABELBREAK", INFOTOK_LABELBREAK },
192 { "MNEMONICCOL", INFOTOK_MNEMONIC_COLUMN },
193 { "MNEMONICCOLUMN", INFOTOK_MNEMONIC_COLUMN },
194 { "NEWLINEAFTERJMP", INFOTOK_NL_AFTER_JMP },
195 { "NEWLINEAFTERRTS", INFOTOK_NL_AFTER_RTS },
196 { "OUTPUTNAME", INFOTOK_OUTPUTNAME },
197 { "PAGELENGTH", INFOTOK_PAGELENGTH },
198 { "STARTADDR", INFOTOK_STARTADDR },
199 { "TEXTCOL", INFOTOK_TEXT_COLUMN },
200 { "TEXTCOLUMN", INFOTOK_TEXT_COLUMN },
206 /* Expect the opening curly brace */
207 InfoConsumeLCurly ();
209 /* Look for section tokens */
210 while (InfoTok != INFOTOK_RCURLY) {
212 /* Convert to special token */
213 InfoSpecialToken (GlobalDefs, ENTRY_COUNT (GlobalDefs), "Global directive");
215 /* Look at the token */
218 case INFOTOK_ARGUMENT_COLUMN:
221 InfoRangeCheck (MIN_ACOL, MAX_ACOL);
226 case INFOTOK_COMMENT_COLUMN:
229 InfoRangeCheck (MIN_CCOL, MAX_CCOL);
234 case INFOTOK_COMMENTS:
237 InfoRangeCheck (MIN_COMMENTS, MAX_COMMENTS);
245 if (CPU != CPU_UNKNOWN) {
246 InfoError ("CPU already specified");
248 CPU = FindCPU (InfoSVal);
253 case INFOTOK_HEXOFFS:
257 case INFOTOK_FALSE: UseHexOffs = 0; break;
258 case INFOTOK_TRUE: UseHexOffs = 1; break;
263 case INFOTOK_INPUTNAME:
267 InfoError ("Input file name already given");
269 InFile = xstrdup (InfoSVal);
273 case INFOTOK_INPUTOFFS:
276 InputOffs = InfoIVal;
280 case INFOTOK_INPUTSIZE:
283 InfoRangeCheck (1, 0x10000);
284 InputSize = InfoIVal;
288 case INFOTOK_LABELBREAK:
291 InfoRangeCheck (0, UCHAR_MAX);
292 LBreak = (unsigned char) InfoIVal;
296 case INFOTOK_MNEMONIC_COLUMN:
299 InfoRangeCheck (MIN_MCOL, MAX_MCOL);
304 case INFOTOK_NL_AFTER_JMP:
306 if (NewlineAfterJMP != -1) {
307 InfoError ("NLAfterJMP already specified");
310 NewlineAfterJMP = (InfoTok != INFOTOK_FALSE);
314 case INFOTOK_NL_AFTER_RTS:
317 if (NewlineAfterRTS != -1) {
318 InfoError ("NLAfterRTS already specified");
320 NewlineAfterRTS = (InfoTok != INFOTOK_FALSE);
324 case INFOTOK_OUTPUTNAME:
328 InfoError ("Output file name already given");
330 OutFile = xstrdup (InfoSVal);
334 case INFOTOK_PAGELENGTH:
338 InfoRangeCheck (MIN_PAGE_LEN, MAX_PAGE_LEN);
340 PageLength = InfoIVal;
344 case INFOTOK_STARTADDR:
347 InfoRangeCheck (0x0000, 0xFFFF);
348 StartAddr = InfoIVal;
352 case INFOTOK_TEXT_COLUMN:
355 InfoRangeCheck (MIN_TCOL, MAX_TCOL);
361 Internal ("Unexpected token: %u", InfoTok);
365 /* Directive is followed by a semicolon */
370 /* Consume the closing brace */
371 InfoConsumeRCurly ();
376 static void LabelSection (void)
377 /* Parse a label section */
379 static const IdentTok LabelDefs[] = {
380 { "COMMENT", INFOTOK_COMMENT },
381 { "ADDR", INFOTOK_ADDR },
382 { "NAME", INFOTOK_NAME },
383 { "SIZE", INFOTOK_SIZE },
384 { "PARAMSIZE", INFOTOK_PARAMSIZE },
387 /* Locals - initialize to avoid gcc warnings */
397 /* Expect the opening curly brace */
398 InfoConsumeLCurly ();
400 /* Look for section tokens */
401 while (InfoTok != INFOTOK_RCURLY) {
403 /* Convert to special token */
404 InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label attribute");
406 /* Look at the token */
412 InfoError ("Value already given");
415 InfoRangeCheck (0, 0xFFFF);
420 case INFOTOK_COMMENT:
423 InfoError ("Comment already given");
426 if (InfoSVal[0] == '\0') {
427 InfoError ("Comment may not be empty");
429 Comment = xstrdup (InfoSVal);
436 InfoError ("Name already given");
439 Name = xstrdup (InfoSVal);
446 InfoError ("Size already given");
449 InfoRangeCheck (1, 0x10000);
454 case INFOTOK_PARAMSIZE:
456 if (ParamSize >= 0) {
457 InfoError ("ParamSize already given");
460 InfoRangeCheck (1, 0x10000);
461 ParamSize = InfoIVal;
466 Internal ("Unexpected token: %u", InfoTok);
469 /* Directive is followed by a semicolon */
473 /* Did we get the necessary data */
475 InfoError ("Label name is missing");
477 if (Name[0] == '\0' && Size > 1) {
478 InfoError ("Unnamed labels must not have a size > 1");
481 InfoError ("Label value is missing");
487 if (Value + Size > 0x10000) {
488 InfoError ("Invalid size (address out of range)");
490 if (HaveLabel ((unsigned) Value)) {
491 InfoError ("Label for address $%04lX already defined", Value);
494 /* Define the label(s) */
495 if (Name[0] == '\0') {
496 /* Size has already beed checked */
497 AddUnnamedLabel (Value);
499 AddExtLabelRange ((unsigned) Value, Name, Size);
501 if (ParamSize >= 0) {
502 SetSubroutineParamSize ((unsigned) Value, (unsigned) ParamSize);
505 /* Define the comment */
507 SetComment (Value, Comment);
510 /* Delete the dynamically allocated memory for Name and Comment */
514 /* Consume the closing brace */
515 InfoConsumeRCurly ();
520 static void RangeSection (void)
521 /* Parse a range section */
523 static const IdentTok RangeDefs[] = {
524 { "COMMENT", INFOTOK_COMMENT },
525 { "END", INFOTOK_END },
526 { "NAME", INFOTOK_NAME },
527 { "START", INFOTOK_START },
528 { "TYPE", INFOTOK_TYPE },
531 static const IdentTok TypeDefs[] = {
532 { "ADDRTABLE", INFOTOK_ADDRTAB },
533 { "BYTETABLE", INFOTOK_BYTETAB },
534 { "CODE", INFOTOK_CODE },
535 { "DBYTETABLE", INFOTOK_DBYTETAB },
536 { "DWORDTABLE", INFOTOK_DWORDTAB },
537 { "RTSTABLE", INFOTOK_RTSTAB },
538 { "SKIP", INFOTOK_SKIP },
539 { "TEXTTABLE", INFOTOK_TEXTTAB },
540 { "WORDTABLE", INFOTOK_WORDTAB },
544 /* Which values did we get? */
552 tNeeded = (tStart | tEnd | tType)
554 unsigned Attributes = tNone;
556 /* Locals - initialize to avoid gcc warnings */
559 unsigned char Type = 0;
562 unsigned MemberSize = 0;
568 /* Expect the opening curly brace */
569 InfoConsumeLCurly ();
571 /* Look for section tokens */
572 while (InfoTok != INFOTOK_RCURLY) {
574 /* Convert to special token */
575 InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range attribute");
577 /* Look at the token */
580 case INFOTOK_COMMENT:
581 AddAttr ("COMMENT", &Attributes, tComment);
584 if (InfoSVal[0] == '\0') {
585 InfoError ("Comment may not be empty");
587 Comment = xstrdup (InfoSVal);
588 Attributes |= tComment;
593 AddAttr ("END", &Attributes, tEnd);
596 InfoRangeCheck (0x0000, 0xFFFF);
602 AddAttr ("NAME", &Attributes, tName);
605 if (InfoSVal[0] == '\0') {
606 InfoError ("Name may not be empty");
608 Name = xstrdup (InfoSVal);
614 AddAttr ("START", &Attributes, tStart);
617 InfoRangeCheck (0x0000, 0xFFFF);
623 AddAttr ("TYPE", &Attributes, tType);
625 InfoSpecialToken (TypeDefs, ENTRY_COUNT (TypeDefs), "TYPE");
627 case INFOTOK_ADDRTAB: Type = atAddrTab; MemberSize = 2; break;
628 case INFOTOK_BYTETAB: Type = atByteTab; MemberSize = 1; break;
629 case INFOTOK_CODE: Type = atCode; MemberSize = 1; break;
630 case INFOTOK_DBYTETAB: Type = atDByteTab; MemberSize = 2; break;
631 case INFOTOK_DWORDTAB: Type = atDWordTab; MemberSize = 4; break;
632 case INFOTOK_RTSTAB: Type = atRtsTab; MemberSize = 2; break;
633 case INFOTOK_SKIP: Type = atSkip; MemberSize = 1; break;
634 case INFOTOK_TEXTTAB: Type = atTextTab; MemberSize = 1; break;
635 case INFOTOK_WORDTAB: Type = atWordTab; MemberSize = 2; break;
641 Internal ("Unexpected token: %u", InfoTok);
644 /* Directive is followed by a semicolon */
649 /* Did we get all required values? */
650 if ((Attributes & tNeeded) != tNeeded) {
651 InfoError ("Required values missing from this section");
654 /* Start must be less than end */
656 InfoError ("Start value must not be greater than end value");
659 /* Check the granularity */
660 if (((End - Start + 1) % MemberSize) != 0) {
661 InfoError ("Type of range needs a granularity of %u", MemberSize);
665 MarkRange (Start, End, Type);
667 /* Do we have a label? */
668 if (Attributes & tName) {
670 /* Define a label for the table */
671 AddExtLabel (Start, Name);
673 /* Set the comment if we have one */
675 SetComment (Start, Comment);
678 /* Delete name and comment */
683 /* Consume the closing brace */
684 InfoConsumeRCurly ();
689 static void SegmentSection (void)
690 /* Parse a segment section */
692 static const IdentTok LabelDefs[] = {
693 { "END", INFOTOK_END },
694 { "NAME", INFOTOK_NAME },
695 { "START", INFOTOK_START },
698 /* Locals - initialize to avoid gcc warnings */
706 /* Expect the opening curly brace */
707 InfoConsumeLCurly ();
709 /* Look for section tokens */
710 while (InfoTok != INFOTOK_RCURLY) {
712 /* Convert to special token */
713 InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Segment attribute");
715 /* Look at the token */
721 InfoError ("Value already given");
724 InfoRangeCheck (0, 0xFFFF);
732 InfoError ("Name already given");
735 Name = xstrdup (InfoSVal);
742 InfoError ("Value already given");
745 InfoRangeCheck (0, 0xFFFF);
751 Internal ("Unexpected token: %u", InfoTok);
754 /* Directive is followed by a semicolon */
758 /* Did we get the necessary data, and is it correct? */
759 if (Name == 0 || Name[0] == '\0') {
760 InfoError ("Segment name is missing");
763 InfoError ("End address is missing");
766 InfoError ("Start address is missing");
769 InfoError ("Start address of segment is greater than end address");
772 /* Check that segments do not overlap */
773 if (SegmentDefined ((unsigned) Start, (unsigned) End)) {
774 InfoError ("Segments must not overlap");
777 /* Remember the segment data */
778 AddAbsSegment ((unsigned) Start, (unsigned) End, Name);
780 /* Delete the dynamically allocated memory for Name */
783 /* Consume the closing brace */
784 InfoConsumeRCurly ();
789 static void InfoParse (void)
790 /* Parse the config file */
792 static const IdentTok Globals[] = {
793 { "ASMINC", INFOTOK_ASMINC },
794 { "GLOBAL", INFOTOK_GLOBAL },
795 { "LABEL", INFOTOK_LABEL },
796 { "RANGE", INFOTOK_RANGE },
797 { "SEGMENT", INFOTOK_SEGMENT },
800 while (InfoTok != INFOTOK_EOF) {
802 /* Convert an identifier into a token */
803 InfoSpecialToken (Globals, ENTRY_COUNT (Globals), "Config directive");
805 /* Check the token */
824 case INFOTOK_SEGMENT:
829 Internal ("Unexpected token: %u", InfoTok);
832 /* Semicolon expected */
839 void ReadInfoFile (void)
840 /* Read the info file */
842 /* Check if we have a info file given */
844 /* Open the config file */
847 /* Parse the config file */