1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* infofile.h */ |
4 | /* */ |
5 | /* Disassembler info file handling */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2000-2014, Ullrich von Bassewitz */ |
10 | /* Roemerstrasse 52 */ |
11 | /* D-70794 Filderstadt */ |
12 | /* EMail: uz@cc65.org */ |
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 | #include <string.h> |
38 | #include <limits.h> |
39 | #if defined(_MSC_VER) |
40 | /* Microsoft compiler */ |
41 | # include <io.h> |
42 | #else |
43 | /* Anyone else */ |
44 | # include <unistd.h> |
45 | #endif |
46 | |
47 | /* common */ |
48 | #include "cpu.h" |
49 | #include "xmalloc.h" |
50 | |
51 | /* da65 */ |
52 | #include "asminc.h" |
53 | #include "attrtab.h" |
54 | #include "comments.h" |
55 | #include "error.h" |
56 | #include "global.h" |
57 | #include "infofile.h" |
58 | #include "labels.h" |
59 | #include "opctable.h" |
60 | #include "scanner.h" |
61 | #include "segment.h" |
62 | #include "handler.h" |
63 | |
64 | |
65 | |
66 | /*****************************************************************************/ |
67 | /* Code */ |
68 | /*****************************************************************************/ |
69 | |
70 | |
71 | |
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 */ |
74 | { |
75 | if (*Set & Attr) { |
76 | /* Attribute is already in the set */ |
77 | InfoError ("%s given twice" , Name); |
78 | } |
79 | *Set |= Attr; |
80 | } |
81 | |
82 | |
83 | |
84 | static void AsmIncSection (void) |
85 | /* Parse a asminc section */ |
86 | { |
87 | static const IdentTok LabelDefs[] = { |
88 | { "COMMENTSTART" , INFOTOK_COMMENTSTART }, |
89 | { "FILE" , INFOTOK_FILE }, |
90 | { "IGNOREUNKNOWN" , INFOTOK_IGNOREUNKNOWN }, |
91 | }; |
92 | |
93 | /* Locals - initialize to avoid gcc warnings */ |
94 | char* Name = 0; |
95 | int = EOF; |
96 | int IgnoreUnknown = -1; |
97 | |
98 | /* Skip the token */ |
99 | InfoNextTok (); |
100 | |
101 | /* Expect the opening curly brace */ |
102 | InfoConsumeLCurly (); |
103 | |
104 | /* Look for section tokens */ |
105 | while (InfoTok != INFOTOK_RCURLY) { |
106 | |
107 | /* Convert to special token */ |
108 | InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Asminc directive" ); |
109 | |
110 | /* Look at the token */ |
111 | switch (InfoTok) { |
112 | |
113 | case INFOTOK_COMMENTSTART: |
114 | InfoNextTok (); |
115 | if (CommentStart != EOF) { |
116 | InfoError ("Commentstart already given" ); |
117 | } |
118 | InfoAssureChar (); |
119 | CommentStart = (char) InfoIVal; |
120 | InfoNextTok (); |
121 | break; |
122 | |
123 | case INFOTOK_FILE: |
124 | InfoNextTok (); |
125 | if (Name) { |
126 | InfoError ("File name already given" ); |
127 | } |
128 | InfoAssureStr (); |
129 | if (InfoSVal[0] == '\0') { |
130 | InfoError ("File name may not be empty" ); |
131 | } |
132 | Name = xstrdup (InfoSVal); |
133 | InfoNextTok (); |
134 | break; |
135 | |
136 | case INFOTOK_IGNOREUNKNOWN: |
137 | InfoNextTok (); |
138 | if (IgnoreUnknown != -1) { |
139 | InfoError ("Ignoreunknown already specified" ); |
140 | } |
141 | InfoBoolToken (); |
142 | IgnoreUnknown = (InfoTok != INFOTOK_FALSE); |
143 | InfoNextTok (); |
144 | break; |
145 | |
146 | default: |
147 | Internal ("Unexpected token: %u" , InfoTok); |
148 | } |
149 | |
150 | /* Directive is followed by a semicolon */ |
151 | InfoConsumeSemi (); |
152 | } |
153 | |
154 | /* Check for the necessary data and assume defaults */ |
155 | if (Name == 0) { |
156 | InfoError ("File name is missing" ); |
157 | } |
158 | if (CommentStart == EOF) { |
159 | CommentStart = ';'; |
160 | } |
161 | if (IgnoreUnknown == -1) { |
162 | IgnoreUnknown = 0; |
163 | } |
164 | |
165 | /* Open the file and read the symbol definitions */ |
166 | AsmInc (Name, CommentStart, IgnoreUnknown); |
167 | |
168 | /* Delete the dynamically allocated memory for Name */ |
169 | xfree (Name); |
170 | |
171 | /* Consume the closing brace */ |
172 | InfoConsumeRCurly (); |
173 | } |
174 | |
175 | |
176 | |
177 | static void GlobalSection (void) |
178 | /* Parse a global section */ |
179 | { |
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 }, |
201 | }; |
202 | |
203 | /* Skip the token */ |
204 | InfoNextTok (); |
205 | |
206 | /* Expect the opening curly brace */ |
207 | InfoConsumeLCurly (); |
208 | |
209 | /* Look for section tokens */ |
210 | while (InfoTok != INFOTOK_RCURLY) { |
211 | |
212 | /* Convert to special token */ |
213 | InfoSpecialToken (GlobalDefs, ENTRY_COUNT (GlobalDefs), "Global directive" ); |
214 | |
215 | /* Look at the token */ |
216 | switch (InfoTok) { |
217 | |
218 | case INFOTOK_ARGUMENT_COLUMN: |
219 | InfoNextTok (); |
220 | InfoAssureInt (); |
221 | InfoRangeCheck (MIN_ACOL, MAX_ACOL); |
222 | ACol = InfoIVal; |
223 | InfoNextTok (); |
224 | break; |
225 | |
226 | case INFOTOK_COMMENT_COLUMN: |
227 | InfoNextTok (); |
228 | InfoAssureInt (); |
229 | InfoRangeCheck (MIN_CCOL, MAX_CCOL); |
230 | CCol = InfoIVal; |
231 | InfoNextTok (); |
232 | break; |
233 | |
234 | case INFOTOK_COMMENTS: |
235 | InfoNextTok (); |
236 | InfoAssureInt (); |
237 | InfoRangeCheck (MIN_COMMENTS, MAX_COMMENTS); |
238 | Comments = InfoIVal; |
239 | InfoNextTok (); |
240 | break; |
241 | |
242 | case INFOTOK_CPU: |
243 | InfoNextTok (); |
244 | InfoAssureStr (); |
245 | if (CPU != CPU_UNKNOWN) { |
246 | InfoError ("CPU already specified" ); |
247 | } |
248 | CPU = FindCPU (InfoSVal); |
249 | SetOpcTable (CPU); |
250 | InfoNextTok (); |
251 | break; |
252 | |
253 | case INFOTOK_HEXOFFS: |
254 | InfoNextTok (); |
255 | InfoBoolToken (); |
256 | switch (InfoTok) { |
257 | case INFOTOK_FALSE: UseHexOffs = 0; break; |
258 | case INFOTOK_TRUE: UseHexOffs = 1; break; |
259 | } |
260 | InfoNextTok (); |
261 | break; |
262 | |
263 | case INFOTOK_INPUTNAME: |
264 | InfoNextTok (); |
265 | InfoAssureStr (); |
266 | if (InFile) { |
267 | InfoError ("Input file name already given" ); |
268 | } |
269 | InFile = xstrdup (InfoSVal); |
270 | InfoNextTok (); |
271 | break; |
272 | |
273 | case INFOTOK_INPUTOFFS: |
274 | InfoNextTok (); |
275 | InfoAssureInt (); |
276 | InputOffs = InfoIVal; |
277 | InfoNextTok (); |
278 | break; |
279 | |
280 | case INFOTOK_INPUTSIZE: |
281 | InfoNextTok (); |
282 | InfoAssureInt (); |
283 | InfoRangeCheck (1, 0x10000); |
284 | InputSize = InfoIVal; |
285 | InfoNextTok (); |
286 | break; |
287 | |
288 | case INFOTOK_LABELBREAK: |
289 | InfoNextTok (); |
290 | InfoAssureInt (); |
291 | InfoRangeCheck (0, UCHAR_MAX); |
292 | LBreak = (unsigned char) InfoIVal; |
293 | InfoNextTok (); |
294 | break; |
295 | |
296 | case INFOTOK_MNEMONIC_COLUMN: |
297 | InfoNextTok (); |
298 | InfoAssureInt (); |
299 | InfoRangeCheck (MIN_MCOL, MAX_MCOL); |
300 | MCol = InfoIVal; |
301 | InfoNextTok (); |
302 | break; |
303 | |
304 | case INFOTOK_NL_AFTER_JMP: |
305 | InfoNextTok (); |
306 | if (NewlineAfterJMP != -1) { |
307 | InfoError ("NLAfterJMP already specified" ); |
308 | } |
309 | InfoBoolToken (); |
310 | NewlineAfterJMP = (InfoTok != INFOTOK_FALSE); |
311 | InfoNextTok (); |
312 | break; |
313 | |
314 | case INFOTOK_NL_AFTER_RTS: |
315 | InfoNextTok (); |
316 | InfoBoolToken (); |
317 | if (NewlineAfterRTS != -1) { |
318 | InfoError ("NLAfterRTS already specified" ); |
319 | } |
320 | NewlineAfterRTS = (InfoTok != INFOTOK_FALSE); |
321 | InfoNextTok (); |
322 | break; |
323 | |
324 | case INFOTOK_OUTPUTNAME: |
325 | InfoNextTok (); |
326 | InfoAssureStr (); |
327 | if (OutFile) { |
328 | InfoError ("Output file name already given" ); |
329 | } |
330 | OutFile = xstrdup (InfoSVal); |
331 | InfoNextTok (); |
332 | break; |
333 | |
334 | case INFOTOK_PAGELENGTH: |
335 | InfoNextTok (); |
336 | InfoAssureInt (); |
337 | if (InfoIVal != 0) { |
338 | InfoRangeCheck (MIN_PAGE_LEN, MAX_PAGE_LEN); |
339 | } |
340 | PageLength = InfoIVal; |
341 | InfoNextTok (); |
342 | break; |
343 | |
344 | case INFOTOK_STARTADDR: |
345 | InfoNextTok (); |
346 | InfoAssureInt (); |
347 | InfoRangeCheck (0x0000, 0xFFFF); |
348 | StartAddr = InfoIVal; |
349 | InfoNextTok (); |
350 | break; |
351 | |
352 | case INFOTOK_TEXT_COLUMN: |
353 | InfoNextTok (); |
354 | InfoAssureInt (); |
355 | InfoRangeCheck (MIN_TCOL, MAX_TCOL); |
356 | TCol = InfoIVal; |
357 | InfoNextTok (); |
358 | break; |
359 | |
360 | default: |
361 | Internal ("Unexpected token: %u" , InfoTok); |
362 | |
363 | } |
364 | |
365 | /* Directive is followed by a semicolon */ |
366 | InfoConsumeSemi (); |
367 | |
368 | } |
369 | |
370 | /* Consume the closing brace */ |
371 | InfoConsumeRCurly (); |
372 | } |
373 | |
374 | |
375 | |
376 | static void LabelSection (void) |
377 | /* Parse a label section */ |
378 | { |
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 }, |
385 | }; |
386 | |
387 | /* Locals - initialize to avoid gcc warnings */ |
388 | char* Name = 0; |
389 | char* = 0; |
390 | long Value = -1; |
391 | long Size = -1; |
392 | long ParamSize = -1; |
393 | |
394 | /* Skip the token */ |
395 | InfoNextTok (); |
396 | |
397 | /* Expect the opening curly brace */ |
398 | InfoConsumeLCurly (); |
399 | |
400 | /* Look for section tokens */ |
401 | while (InfoTok != INFOTOK_RCURLY) { |
402 | |
403 | /* Convert to special token */ |
404 | InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label attribute" ); |
405 | |
406 | /* Look at the token */ |
407 | switch (InfoTok) { |
408 | |
409 | case INFOTOK_ADDR: |
410 | InfoNextTok (); |
411 | if (Value >= 0) { |
412 | InfoError ("Value already given" ); |
413 | } |
414 | InfoAssureInt (); |
415 | InfoRangeCheck (0, 0xFFFF); |
416 | Value = InfoIVal; |
417 | InfoNextTok (); |
418 | break; |
419 | |
420 | case INFOTOK_COMMENT: |
421 | InfoNextTok (); |
422 | if (Comment) { |
423 | InfoError ("Comment already given" ); |
424 | } |
425 | InfoAssureStr (); |
426 | if (InfoSVal[0] == '\0') { |
427 | InfoError ("Comment may not be empty" ); |
428 | } |
429 | Comment = xstrdup (InfoSVal); |
430 | InfoNextTok (); |
431 | break; |
432 | |
433 | case INFOTOK_NAME: |
434 | InfoNextTok (); |
435 | if (Name) { |
436 | InfoError ("Name already given" ); |
437 | } |
438 | InfoAssureStr (); |
439 | Name = xstrdup (InfoSVal); |
440 | InfoNextTok (); |
441 | break; |
442 | |
443 | case INFOTOK_SIZE: |
444 | InfoNextTok (); |
445 | if (Size >= 0) { |
446 | InfoError ("Size already given" ); |
447 | } |
448 | InfoAssureInt (); |
449 | InfoRangeCheck (1, 0x10000); |
450 | Size = InfoIVal; |
451 | InfoNextTok (); |
452 | break; |
453 | |
454 | case INFOTOK_PARAMSIZE: |
455 | InfoNextTok (); |
456 | if (ParamSize >= 0) { |
457 | InfoError ("ParamSize already given" ); |
458 | } |
459 | InfoAssureInt (); |
460 | InfoRangeCheck (1, 0x10000); |
461 | ParamSize = InfoIVal; |
462 | InfoNextTok (); |
463 | break; |
464 | |
465 | default: |
466 | Internal ("Unexpected token: %u" , InfoTok); |
467 | } |
468 | |
469 | /* Directive is followed by a semicolon */ |
470 | InfoConsumeSemi (); |
471 | } |
472 | |
473 | /* Did we get the necessary data */ |
474 | if (Name == 0) { |
475 | InfoError ("Label name is missing" ); |
476 | } |
477 | if (Name[0] == '\0' && Size > 1) { |
478 | InfoError ("Unnamed labels must not have a size > 1" ); |
479 | } |
480 | if (Value < 0) { |
481 | InfoError ("Label value is missing" ); |
482 | } |
483 | if (Size < 0) { |
484 | /* Use default */ |
485 | Size = 1; |
486 | } |
487 | if (Value + Size > 0x10000) { |
488 | InfoError ("Invalid size (address out of range)" ); |
489 | } |
490 | if (HaveLabel ((unsigned) Value)) { |
491 | InfoError ("Label for address $%04lX already defined" , Value); |
492 | } |
493 | |
494 | /* Define the label(s) */ |
495 | if (Name[0] == '\0') { |
496 | /* Size has already beed checked */ |
497 | AddUnnamedLabel (Value); |
498 | } else { |
499 | AddExtLabelRange ((unsigned) Value, Name, Size); |
500 | } |
501 | if (ParamSize >= 0) { |
502 | SetSubroutineParamSize ((unsigned) Value, (unsigned) ParamSize); |
503 | } |
504 | |
505 | /* Define the comment */ |
506 | if (Comment) { |
507 | SetComment (Value, Comment); |
508 | } |
509 | |
510 | /* Delete the dynamically allocated memory for Name and Comment */ |
511 | xfree (Name); |
512 | xfree (Comment); |
513 | |
514 | /* Consume the closing brace */ |
515 | InfoConsumeRCurly (); |
516 | } |
517 | |
518 | |
519 | |
520 | static void RangeSection (void) |
521 | /* Parse a range section */ |
522 | { |
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 }, |
529 | }; |
530 | |
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 }, |
541 | }; |
542 | |
543 | |
544 | /* Which values did we get? */ |
545 | enum { |
546 | tNone = 0x00, |
547 | tStart = 0x01, |
548 | tEnd = 0x02, |
549 | tType = 0x04, |
550 | tName = 0x08, |
551 | = 0x10, |
552 | tNeeded = (tStart | tEnd | tType) |
553 | }; |
554 | unsigned Attributes = tNone; |
555 | |
556 | /* Locals - initialize to avoid gcc warnings */ |
557 | unsigned Start = 0; |
558 | unsigned End = 0; |
559 | unsigned char Type = 0; |
560 | char* Name = 0; |
561 | char* = 0; |
562 | unsigned MemberSize = 0; |
563 | |
564 | |
565 | /* Skip the token */ |
566 | InfoNextTok (); |
567 | |
568 | /* Expect the opening curly brace */ |
569 | InfoConsumeLCurly (); |
570 | |
571 | /* Look for section tokens */ |
572 | while (InfoTok != INFOTOK_RCURLY) { |
573 | |
574 | /* Convert to special token */ |
575 | InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range attribute" ); |
576 | |
577 | /* Look at the token */ |
578 | switch (InfoTok) { |
579 | |
580 | case INFOTOK_COMMENT: |
581 | AddAttr ("COMMENT" , &Attributes, tComment); |
582 | InfoNextTok (); |
583 | InfoAssureStr (); |
584 | if (InfoSVal[0] == '\0') { |
585 | InfoError ("Comment may not be empty" ); |
586 | } |
587 | Comment = xstrdup (InfoSVal); |
588 | Attributes |= tComment; |
589 | InfoNextTok (); |
590 | break; |
591 | |
592 | case INFOTOK_END: |
593 | AddAttr ("END" , &Attributes, tEnd); |
594 | InfoNextTok (); |
595 | InfoAssureInt (); |
596 | InfoRangeCheck (0x0000, 0xFFFF); |
597 | End = InfoIVal; |
598 | InfoNextTok (); |
599 | break; |
600 | |
601 | case INFOTOK_NAME: |
602 | AddAttr ("NAME" , &Attributes, tName); |
603 | InfoNextTok (); |
604 | InfoAssureStr (); |
605 | if (InfoSVal[0] == '\0') { |
606 | InfoError ("Name may not be empty" ); |
607 | } |
608 | Name = xstrdup (InfoSVal); |
609 | Attributes |= tName; |
610 | InfoNextTok (); |
611 | break; |
612 | |
613 | case INFOTOK_START: |
614 | AddAttr ("START" , &Attributes, tStart); |
615 | InfoNextTok (); |
616 | InfoAssureInt (); |
617 | InfoRangeCheck (0x0000, 0xFFFF); |
618 | Start = InfoIVal; |
619 | InfoNextTok (); |
620 | break; |
621 | |
622 | case INFOTOK_TYPE: |
623 | AddAttr ("TYPE" , &Attributes, tType); |
624 | InfoNextTok (); |
625 | InfoSpecialToken (TypeDefs, ENTRY_COUNT (TypeDefs), "TYPE" ); |
626 | switch (InfoTok) { |
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; |
636 | } |
637 | InfoNextTok (); |
638 | break; |
639 | |
640 | default: |
641 | Internal ("Unexpected token: %u" , InfoTok); |
642 | } |
643 | |
644 | /* Directive is followed by a semicolon */ |
645 | InfoConsumeSemi (); |
646 | |
647 | } |
648 | |
649 | /* Did we get all required values? */ |
650 | if ((Attributes & tNeeded) != tNeeded) { |
651 | InfoError ("Required values missing from this section" ); |
652 | } |
653 | |
654 | /* Start must be less than end */ |
655 | if (Start > End) { |
656 | InfoError ("Start value must not be greater than end value" ); |
657 | } |
658 | |
659 | /* Check the granularity */ |
660 | if (((End - Start + 1) % MemberSize) != 0) { |
661 | InfoError ("Type of range needs a granularity of %u" , MemberSize); |
662 | } |
663 | |
664 | /* Set the range */ |
665 | MarkRange (Start, End, Type); |
666 | |
667 | /* Do we have a label? */ |
668 | if (Attributes & tName) { |
669 | |
670 | /* Define a label for the table */ |
671 | AddExtLabel (Start, Name); |
672 | |
673 | /* Set the comment if we have one */ |
674 | if (Comment) { |
675 | SetComment (Start, Comment); |
676 | } |
677 | |
678 | /* Delete name and comment */ |
679 | xfree (Name); |
680 | xfree (Comment); |
681 | } |
682 | |
683 | /* Consume the closing brace */ |
684 | InfoConsumeRCurly (); |
685 | } |
686 | |
687 | |
688 | |
689 | static void SegmentSection (void) |
690 | /* Parse a segment section */ |
691 | { |
692 | static const IdentTok LabelDefs[] = { |
693 | { "END" , INFOTOK_END }, |
694 | { "NAME" , INFOTOK_NAME }, |
695 | { "START" , INFOTOK_START }, |
696 | }; |
697 | |
698 | /* Locals - initialize to avoid gcc warnings */ |
699 | long End = -1; |
700 | long Start = -1; |
701 | char* Name = 0; |
702 | |
703 | /* Skip the token */ |
704 | InfoNextTok (); |
705 | |
706 | /* Expect the opening curly brace */ |
707 | InfoConsumeLCurly (); |
708 | |
709 | /* Look for section tokens */ |
710 | while (InfoTok != INFOTOK_RCURLY) { |
711 | |
712 | /* Convert to special token */ |
713 | InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Segment attribute" ); |
714 | |
715 | /* Look at the token */ |
716 | switch (InfoTok) { |
717 | |
718 | case INFOTOK_END: |
719 | InfoNextTok (); |
720 | if (End >= 0) { |
721 | InfoError ("Value already given" ); |
722 | } |
723 | InfoAssureInt (); |
724 | InfoRangeCheck (0, 0xFFFF); |
725 | End = InfoIVal; |
726 | InfoNextTok (); |
727 | break; |
728 | |
729 | case INFOTOK_NAME: |
730 | InfoNextTok (); |
731 | if (Name) { |
732 | InfoError ("Name already given" ); |
733 | } |
734 | InfoAssureStr (); |
735 | Name = xstrdup (InfoSVal); |
736 | InfoNextTok (); |
737 | break; |
738 | |
739 | case INFOTOK_START: |
740 | InfoNextTok (); |
741 | if (Start >= 0) { |
742 | InfoError ("Value already given" ); |
743 | } |
744 | InfoAssureInt (); |
745 | InfoRangeCheck (0, 0xFFFF); |
746 | Start = InfoIVal; |
747 | InfoNextTok (); |
748 | break; |
749 | |
750 | default: |
751 | Internal ("Unexpected token: %u" , InfoTok); |
752 | } |
753 | |
754 | /* Directive is followed by a semicolon */ |
755 | InfoConsumeSemi (); |
756 | } |
757 | |
758 | /* Did we get the necessary data, and is it correct? */ |
759 | if (Name == 0 || Name[0] == '\0') { |
760 | InfoError ("Segment name is missing" ); |
761 | } |
762 | if (End < 0) { |
763 | InfoError ("End address is missing" ); |
764 | } |
765 | if (Start < 0) { |
766 | InfoError ("Start address is missing" ); |
767 | } |
768 | if (Start > End) { |
769 | InfoError ("Start address of segment is greater than end address" ); |
770 | } |
771 | |
772 | /* Check that segments do not overlap */ |
773 | if (SegmentDefined ((unsigned) Start, (unsigned) End)) { |
774 | InfoError ("Segments must not overlap" ); |
775 | } |
776 | |
777 | /* Remember the segment data */ |
778 | AddAbsSegment ((unsigned) Start, (unsigned) End, Name); |
779 | |
780 | /* Delete the dynamically allocated memory for Name */ |
781 | xfree (Name); |
782 | |
783 | /* Consume the closing brace */ |
784 | InfoConsumeRCurly (); |
785 | } |
786 | |
787 | |
788 | |
789 | static void InfoParse (void) |
790 | /* Parse the config file */ |
791 | { |
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 }, |
798 | }; |
799 | |
800 | while (InfoTok != INFOTOK_EOF) { |
801 | |
802 | /* Convert an identifier into a token */ |
803 | InfoSpecialToken (Globals, ENTRY_COUNT (Globals), "Config directive" ); |
804 | |
805 | /* Check the token */ |
806 | switch (InfoTok) { |
807 | |
808 | case INFOTOK_ASMINC: |
809 | AsmIncSection (); |
810 | break; |
811 | |
812 | case INFOTOK_GLOBAL: |
813 | GlobalSection (); |
814 | break; |
815 | |
816 | case INFOTOK_LABEL: |
817 | LabelSection (); |
818 | break; |
819 | |
820 | case INFOTOK_RANGE: |
821 | RangeSection (); |
822 | break; |
823 | |
824 | case INFOTOK_SEGMENT: |
825 | SegmentSection (); |
826 | break; |
827 | |
828 | default: |
829 | Internal ("Unexpected token: %u" , InfoTok); |
830 | } |
831 | |
832 | /* Semicolon expected */ |
833 | InfoConsumeSemi (); |
834 | } |
835 | } |
836 | |
837 | |
838 | |
839 | void ReadInfoFile (void) |
840 | /* Read the info file */ |
841 | { |
842 | /* Check if we have a info file given */ |
843 | if (InfoAvail()) { |
844 | /* Open the config file */ |
845 | InfoOpenInput (); |
846 | |
847 | /* Parse the config file */ |
848 | InfoParse (); |
849 | |
850 | /* Close the file */ |
851 | InfoCloseInput (); |
852 | } |
853 | } |
854 | |