]> git.sur5r.net Git - cc65/blob - src/ca65/pseudo.c
Fixed open mode for second try in DoIncBin (Greg King).
[cc65] / src / ca65 / pseudo.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 pseudo.c                                  */
4 /*                                                                           */
5 /*              Pseudo instructions for the ca65 macroassembler              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2010, 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 <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <errno.h>
41
42 /* common */
43 #include "assertion.h"
44 #include "bitops.h"
45 #include "cddefs.h"
46 #include "coll.h"
47 #include "symdefs.h"
48 #include "tgttrans.h"
49 #include "xmalloc.h"
50
51 /* ca65 */
52 #include "anonname.h"
53 #include "asserts.h"
54 #include "condasm.h"
55 #include "dbginfo.h"
56 #include "enum.h"
57 #include "error.h"
58 #include "expr.h"
59 #include "feature.h"
60 #include "global.h"
61 #include "incpath.h"
62 #include "instr.h"
63 #include "listing.h"
64 #include "macpack.h"
65 #include "macro.h"
66 #include "nexttok.h"
67 #include "objcode.h"
68 #include "options.h"
69 #include "pseudo.h"
70 #include "repeat.h"
71 #include "segment.h"
72 #include "sizeof.h"
73 #include "spool.h"
74 #include "struct.h"
75 #include "symbol.h"
76 #include "symtab.h"
77
78
79
80 /*****************************************************************************/
81 /*                                   Data                                    */
82 /*****************************************************************************/
83
84
85
86 /* Keyword we're about to handle */
87 static StrBuf Keyword = STATIC_STRBUF_INITIALIZER;
88
89 /* Segment stack */
90 #define MAX_PUSHED_SEGMENTS     16
91 static Collection SegStack = STATIC_COLLECTION_INITIALIZER;
92
93
94
95 /*****************************************************************************/
96 /*                               Forwards                                    */
97 /*****************************************************************************/
98
99
100
101 static void DoUnexpected (void);
102 /* Got an unexpected keyword */
103
104 static void DoInvalid (void);
105 /* Handle a token that is invalid here, since it should have been handled on
106  * a much lower level of the expression hierarchy. Getting this sort of token
107  * means that the lower level code has bugs.
108  * This function differs to DoUnexpected in that the latter may be triggered
109  * by the user by using keywords in the wrong location. DoUnexpected is not
110  * an error in the assembler itself, while DoInvalid is.
111  */
112
113
114
115 /*****************************************************************************/
116 /*                              Helper functions                             */
117 /*****************************************************************************/
118
119
120
121 static unsigned char OptionalAddrSize (void)
122 /* If a colon follows, parse an optional address size spec and return it.
123  * Otherwise return ADDR_SIZE_DEFAULT.
124  */
125 {
126     unsigned AddrSize = ADDR_SIZE_DEFAULT;
127     if (Tok == TOK_COLON) {
128         NextTok ();
129         AddrSize = ParseAddrSize ();
130         if (!ValidAddrSizeForCPU (AddrSize)) {
131             /* Print an error and reset to default */
132             Error ("Invalid address size specification for current CPU");
133             AddrSize = ADDR_SIZE_DEFAULT;
134         }
135         NextTok ();
136     }
137     return AddrSize;
138 }
139
140
141
142 static void SetBoolOption (unsigned char* Flag)
143 /* Read a on/off/+/- option and set flag accordingly */
144 {
145     static const char* Keys[] = {
146         "OFF",
147         "ON",
148     };
149
150     if (Tok == TOK_PLUS) {
151         *Flag = 1;
152         NextTok ();
153     } else if (Tok == TOK_MINUS) {
154         *Flag = 0;
155         NextTok ();
156     } else if (Tok == TOK_IDENT) {
157         /* Map the keyword to a number */
158         switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
159             case 0:     *Flag = 0; NextTok ();                  break;
160             case 1:     *Flag = 1; NextTok ();                  break;
161             default:    ErrorSkip ("`on' or `off' expected");   break;
162         }
163     } else if (TokIsSep (Tok)) {
164         /* Without anything assume switch on */
165         *Flag = 1;
166     } else {
167         ErrorSkip ("`on' or `off' expected");
168     }
169 }
170
171
172
173 static void ExportWithAssign (SymEntry* Sym, unsigned char AddrSize, unsigned Flags)
174 /* Allow to assign the value of an export in an .export statement */
175 {
176     /* The name and optional address size spec may be followed by an assignment
177      * or equal token.
178      */
179     if (Tok == TOK_ASSIGN || Tok == TOK_EQ) {
180
181         /* Assignment means the symbol is a label */
182         if (Tok == TOK_ASSIGN) {
183             Flags |= SF_LABEL;
184         }
185
186         /* Skip the assignment token */
187         NextTok ();
188
189         /* Define the symbol with the expression following the '=' */
190         SymDef (Sym, Expression(), ADDR_SIZE_DEFAULT, Flags);
191
192     }
193
194     /* Now export the symbol */
195     SymExport (Sym, AddrSize, Flags);
196 }
197
198
199
200 static void ExportImport (void (*Func) (SymEntry*, unsigned char, unsigned),
201                           unsigned char DefAddrSize, unsigned Flags)
202 /* Export or import symbols */
203 {
204     SymEntry* Sym;
205     unsigned char AddrSize;
206
207     while (1) {
208
209         /* We need an identifier here */
210         if (Tok != TOK_IDENT) {
211             ErrorSkip ("Identifier expected");
212             return;
213         }
214
215         /* Find the symbol table entry, allocate a new one if necessary */
216         Sym = SymFind (CurrentScope, &SVal, SYM_ALLOC_NEW);
217
218         /* Skip the name */
219         NextTok ();
220
221         /* Get an optional address size */
222         AddrSize = OptionalAddrSize ();
223         if (AddrSize == ADDR_SIZE_DEFAULT) {
224             AddrSize = DefAddrSize;
225         }
226
227         /* Call the actual import/export function */
228         Func (Sym, AddrSize, Flags);
229
230         /* More symbols? */
231         if (Tok == TOK_COMMA) {
232             NextTok ();
233         } else {
234             break;
235         }
236     }
237 }
238
239
240
241 static long IntArg (long Min, long Max)
242 /* Read an integer argument and check a range. Accept the token "unlimited"
243  * and return -1 in this case.
244  */
245 {
246     if (Tok == TOK_IDENT && SB_CompareStr (&SVal, "unlimited") == 0) {
247         NextTok ();
248         return -1;
249     } else {
250         long Val = ConstExpression ();
251         if (Val < Min || Val > Max) {
252             Error ("Range error");
253             Val = Min;
254         }
255         return Val;
256     }
257 }
258
259
260
261 static void ConDes (const StrBuf* Name, unsigned Type)
262 /* Parse remaining line for constructor/destructor of the remaining type */
263 {
264     long Prio;
265
266
267     /* Find the symbol table entry, allocate a new one if necessary */
268     SymEntry* Sym = SymFind (CurrentScope, Name, SYM_ALLOC_NEW);
269
270     /* Optional constructor priority */
271     if (Tok == TOK_COMMA) {
272         /* Priority value follows */
273         NextTok ();
274         Prio = ConstExpression ();
275         if (Prio < CD_PRIO_MIN || Prio > CD_PRIO_MAX) {
276             /* Value out of range */
277             Error ("Range error");
278             return;
279         }
280     } else {
281         /* Use the default priority value */
282         Prio = CD_PRIO_DEF;
283     }
284
285     /* Define the symbol */
286     SymConDes (Sym, ADDR_SIZE_DEFAULT, Type, (unsigned) Prio);
287 }
288
289
290
291 /*****************************************************************************/
292 /*                             Handler functions                             */
293 /*****************************************************************************/
294
295
296
297 static void DoA16 (void)
298 /* Switch the accu to 16 bit mode (assembler only) */
299 {
300     if (GetCPU() != CPU_65816) {
301         Error ("Command is only valid in 65816 mode");
302     } else {
303         /* Immidiate mode has two extension bytes */
304         ExtBytes [AM65I_IMM_ACCU] = 2;
305     }
306 }
307
308
309
310 static void DoA8 (void)
311 /* Switch the accu to 8 bit mode (assembler only) */
312 {
313     if (GetCPU() != CPU_65816) {
314         Error ("Command is only valid in 65816 mode");
315     } else {
316         /* Immidiate mode has one extension byte */
317         ExtBytes [AM65I_IMM_ACCU] = 1;
318     }
319 }
320
321
322
323 static void DoAddr (void)
324 /* Define addresses */
325 {
326     while (1) {
327         if (GetCPU() == CPU_65816) {
328             EmitWord (GenWordExpr (Expression ()));
329         } else {
330             /* Do a range check */
331             EmitWord (Expression ());
332         }
333         if (Tok != TOK_COMMA) {
334             break;
335         } else {
336             NextTok ();
337         }
338     }
339 }
340
341
342
343 static void DoAlign (void)
344 /* Align the PC to some boundary */
345 {
346     long Val;
347     long Align;
348     unsigned Bit;
349
350     /* Read the alignment value */
351     Align = ConstExpression ();
352     if (Align <= 0 || Align > 0x10000) {
353         ErrorSkip ("Range error");
354         return;
355     }
356
357     /* Optional value follows */
358     if (Tok == TOK_COMMA) {
359         NextTok ();
360         Val = ConstExpression ();
361         /* We need a byte value here */
362         if (!IsByteRange (Val)) {
363             ErrorSkip ("Range error");
364             return;
365         }
366     } else {
367         Val = -1;
368     }
369
370     /* Check if the alignment is a power of two */
371     Bit = BitFind (Align);
372     if (Align != (0x01L << Bit)) {
373         Error ("Alignment value must be a power of 2");
374     } else {
375         SegAlign (Bit, (int) Val);
376     }
377 }
378
379
380
381 static void DoASCIIZ (void)
382 /* Define text with a zero terminator */
383 {
384     while (1) {
385         /* Must have a string constant */
386         if (Tok != TOK_STRCON) {
387             ErrorSkip ("String constant expected");
388             return;
389         }
390
391         /* Translate into target charset and emit */
392         TgtTranslateStrBuf (&SVal);
393         EmitStrBuf (&SVal);
394         NextTok ();
395         if (Tok == TOK_COMMA) {
396             NextTok ();
397         } else {
398             break;
399         }
400     }
401     Emit0 (0);
402 }
403
404
405
406 static void DoAssert (void)
407 /* Add an assertion */
408 {
409     static const char* ActionTab [] = {
410         "WARN", "WARNING",
411         "ERROR",
412         "LDWARN", "LDWARNING",
413         "LDERROR",
414     };
415
416     AssertAction Action;
417     unsigned     Msg;
418
419     /* First we have the expression that has to evaluated */
420     ExprNode* Expr = Expression ();
421     ConsumeComma ();
422
423     /* Action follows */
424     if (Tok != TOK_IDENT) {
425         ErrorSkip ("Identifier expected");
426         return;
427     }
428     switch (GetSubKey (ActionTab, sizeof (ActionTab) / sizeof (ActionTab[0]))) {
429
430         case 0:
431         case 1:
432             /* Warning */
433             Action = ASSERT_ACT_WARN;
434             break;
435
436         case 2:
437             /* Error */
438             Action = ASSERT_ACT_ERROR;
439             break;
440
441         case 3:
442         case 4:
443             /* Linker warning */
444             Action = ASSERT_ACT_LDWARN;
445             break;
446
447         case 5:
448             /* Linker error */
449             Action = ASSERT_ACT_LDERROR;
450             break;
451
452         default:
453             Error ("Illegal assert action specifier");
454             /* Use lderror - there won't be an .o file anyway */
455             Action = ASSERT_ACT_LDERROR;
456             break;
457
458     }
459     NextTok ();
460
461     /* We can have an optional message. If no message is present, use
462      * "Assertion failed".
463      */
464     if (Tok == TOK_COMMA) {
465
466         /* Skip the comma */
467         NextTok ();
468
469         /* Read the message */
470         if (Tok != TOK_STRCON) {
471             ErrorSkip ("String constant expected");
472             return;
473         }
474
475         /* Translate the message into a string id. We can then skip the input
476          * string.
477          */
478         Msg = GetStrBufId (&SVal);
479         NextTok ();
480
481     } else {
482
483         /* Use "Assertion failed" */
484         Msg = GetStringId ("Assertion failed");
485
486     }
487
488     /* Remember the assertion */
489     AddAssertion (Expr, (AssertAction) Action, Msg);
490 }
491
492
493
494 static void DoAutoImport (void)
495 /* Mark unresolved symbols as imported */
496 {
497     SetBoolOption (&AutoImport);
498 }
499
500
501 static void DoBankBytes (void)
502 /* Define bytes, extracting the bank byte from each expression in the list */
503 {
504     while (1) {
505         EmitByte (FuncBankByte ());
506         if (Tok != TOK_COMMA) {
507             break;
508         } else {
509             NextTok ();
510         }
511     }
512 }
513
514
515
516 static void DoBss (void)
517 /* Switch to the BSS segment */
518 {
519     UseSeg (&BssSegDef);
520 }
521
522
523
524 static void DoByte (void)
525 /* Define bytes */
526 {
527     while (1) {
528         if (Tok == TOK_STRCON) {
529             /* A string, translate into target charset and emit */
530             TgtTranslateStrBuf (&SVal);
531             EmitStrBuf (&SVal);
532             NextTok ();
533         } else {
534             EmitByte (Expression ());
535         }
536         if (Tok != TOK_COMMA) {
537             break;
538         } else {
539             NextTok ();
540             /* Do smart handling of dangling comma */
541             if (Tok == TOK_SEP) {
542                 Error ("Unexpected end of line");
543                 break;
544             }
545         }
546     }
547 }
548
549
550
551 static void DoCase (void)
552 /* Switch the IgnoreCase option */
553 {
554     SetBoolOption (&IgnoreCase);
555     IgnoreCase = !IgnoreCase;
556 }
557
558
559
560 static void DoCharMap (void)
561 /* Allow custome character mappings */
562 {
563     long Index;
564     long Code;
565
566     /* Read the index as numerical value */
567     Index = ConstExpression ();
568     if (Index < 0 || Index > 255) {
569         /* Value out of range */
570         ErrorSkip ("Range error");
571         return;
572     }
573
574     /* Comma follows */
575     ConsumeComma ();
576
577     /* Read the character code */
578     Code = ConstExpression ();
579     if (Code < 0 || Code > 255) {
580         /* Value out of range */
581         ErrorSkip ("Range error");
582         return;
583     }
584
585     /* Set the character translation */
586     TgtTranslateSet ((unsigned) Index, (unsigned char) Code);
587 }
588
589
590
591 static void DoCode (void)
592 /* Switch to the code segment */
593 {
594     UseSeg (&CodeSegDef);
595 }
596
597
598
599 static void DoConDes (void)
600 /* Export a symbol as constructor/destructor */
601 {
602     static const char* Keys[] = {
603         "CONSTRUCTOR",
604         "DESTRUCTOR",
605         "INTERRUPTOR",
606     };
607     StrBuf Name = STATIC_STRBUF_INITIALIZER;
608     long Type;
609
610     /* Symbol name follows */
611     if (Tok != TOK_IDENT) {
612         ErrorSkip ("Identifier expected");
613         return;
614     }
615     SB_Copy (&Name, &SVal);
616     NextTok ();
617
618     /* Type follows. May be encoded as identifier or numerical */
619     ConsumeComma ();
620     if (Tok == TOK_IDENT) {
621
622         /* Map the following keyword to a number, then skip it */
623         Type = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
624         NextTok ();
625
626         /* Check if we got a valid keyword */
627         if (Type < 0) {
628             ErrorSkip ("Syntax error");
629             goto ExitPoint;
630         }
631
632     } else {
633
634         /* Read the type as numerical value */
635         Type = ConstExpression ();
636         if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) {
637             /* Value out of range */
638             ErrorSkip ("Range error");
639             goto ExitPoint;
640         }
641
642     }
643
644     /* Parse the remainder of the line and export the symbol */
645     ConDes (&Name, (unsigned) Type);
646
647 ExitPoint:
648     /* Free string memory */
649     SB_Done (&Name);
650 }
651
652
653
654 static void DoConstructor (void)
655 /* Export a symbol as constructor */
656 {
657     StrBuf Name = STATIC_STRBUF_INITIALIZER;
658
659     /* Symbol name follows */
660     if (Tok != TOK_IDENT) {
661         ErrorSkip ("Identifier expected");
662         return;
663     }
664     SB_Copy (&Name, &SVal);
665     NextTok ();
666
667     /* Parse the remainder of the line and export the symbol */
668     ConDes (&Name, CD_TYPE_CON);
669
670     /* Free string memory */
671     SB_Done (&Name);
672 }
673
674
675
676 static void DoData (void)
677 /* Switch to the data segment */
678 {
679     UseSeg (&DataSegDef);
680 }
681
682
683
684 static void DoDbg (void)
685 /* Add debug information from high level code */
686 {
687     static const char* Keys[] = {
688         "FILE",
689         "LINE",
690         "SYM",
691     };
692     int Key;
693
694
695     /* We expect a subkey */
696     if (Tok != TOK_IDENT) {
697         ErrorSkip ("Identifier expected");
698         return;
699     }
700
701     /* Map the following keyword to a number */
702     Key = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
703
704     /* Skip the subkey */
705     NextTok ();
706
707     /* Check the key and dispatch to a handler */
708     switch (Key) {
709         case 0:     DbgInfoFile ();             break;
710         case 1:     DbgInfoLine ();             break;
711         case 2:     DbgInfoSym ();              break;
712         default:    ErrorSkip ("Syntax error"); break;
713     }
714 }
715
716
717
718 static void DoDByt (void)
719 /* Output double bytes */
720 {
721     while (1) {
722         EmitWord (GenSwapExpr (Expression ()));
723         if (Tok != TOK_COMMA) {
724             break;
725         } else {
726             NextTok ();
727         }
728     }
729 }
730
731
732
733 static void DoDebugInfo (void)
734 /* Switch debug info on or off */
735 {
736     SetBoolOption (&DbgSyms);
737 }
738
739
740
741 static void DoDefine (void)
742 /* Define a one line macro */
743 {
744     MacDef (MAC_STYLE_DEFINE);
745 }
746
747
748
749 static void DoDestructor (void)
750 /* Export a symbol as destructor */
751 {
752     StrBuf Name = STATIC_STRBUF_INITIALIZER;
753
754     /* Symbol name follows */
755     if (Tok != TOK_IDENT) {
756         ErrorSkip ("Identifier expected");
757         return;
758     }
759     SB_Copy (&Name, &SVal);
760     NextTok ();
761
762     /* Parse the remainder of the line and export the symbol */
763     ConDes (&Name, CD_TYPE_DES);
764
765     /* Free string memory */
766     SB_Done (&Name);
767 }
768
769
770
771 static void DoDWord (void)
772 /* Define dwords */
773 {
774     while (1) {
775         EmitDWord (Expression ());
776         if (Tok != TOK_COMMA) {
777             break;
778         } else {
779             NextTok ();
780         }
781     }
782 }
783
784
785
786 static void DoEnd (void)
787 /* End of assembly */
788 {
789     ForcedEnd = 1;
790     NextTok ();
791 }
792
793
794
795 static void DoEndProc (void)
796 /* Leave a lexical level */
797 {
798     if (GetCurrentSymTabType () != ST_PROC) {
799         /* No local scope */
800         ErrorSkip ("No open .PROC");
801     } else {
802         SymLeaveLevel ();
803     }
804 }
805
806
807
808 static void DoEndScope (void)
809 /* Leave a lexical level */
810 {
811     if ( GetCurrentSymTabType () != ST_SCOPE) {
812         /* No local scope */
813         ErrorSkip ("No open .SCOPE");
814     } else {
815         SymLeaveLevel ();
816     }
817 }
818
819
820
821 static void DoError (void)
822 /* User error */
823 {
824     if (Tok != TOK_STRCON) {
825         ErrorSkip ("String constant expected");
826     } else {
827         Error ("User error: %m%p", &SVal);
828         SkipUntilSep ();
829     }
830 }
831
832
833
834 static void DoExitMacro (void)
835 /* Exit a macro expansion */
836 {
837     if (!InMacExpansion ()) {
838         /* We aren't expanding a macro currently */
839         DoUnexpected ();
840     } else {
841         MacAbort ();
842     }
843 }
844
845
846
847 static void DoExport (void)
848 /* Export a symbol */
849 {
850     ExportImport (ExportWithAssign, ADDR_SIZE_DEFAULT, SF_NONE);
851 }
852
853
854
855 static void DoExportZP (void)
856 /* Export a zeropage symbol */
857 {
858     ExportImport (ExportWithAssign, ADDR_SIZE_ZP, SF_NONE);
859 }
860
861
862
863 static void DoFarAddr (void)
864 /* Define far addresses (24 bit) */
865 {
866     while (1) {
867         EmitFarAddr (Expression ());
868         if (Tok != TOK_COMMA) {
869             break;
870         } else {
871             NextTok ();
872         }
873     }
874 }
875
876
877
878 static void DoFeature (void)
879 /* Switch the Feature option */
880 {
881     /* Allow a list of comma separated keywords */
882     while (1) {
883
884         /* We expect an identifier */
885         if (Tok != TOK_IDENT) {
886             ErrorSkip ("Identifier expected");
887             return;
888         }
889
890         /* Make the string attribute lower case */
891         LocaseSVal ();
892
893         /* Set the feature and check for errors */
894         if (SetFeature (&SVal) == FEAT_UNKNOWN) {
895             /* Not found */
896             ErrorSkip ("Invalid feature: `%m%p'", &SVal);
897             return;
898         } else {
899             /* Skip the keyword */
900             NextTok ();
901         }
902
903         /* Allow more than one keyword */
904         if (Tok == TOK_COMMA) {
905             NextTok ();
906         } else {
907             break;
908         }
909     }
910 }
911
912
913
914 static void DoFileOpt (void)
915 /* Insert a file option */
916 {
917     long OptNum;
918
919     /* The option type may be given as a keyword or as a number. */
920     if (Tok == TOK_IDENT) {
921
922         /* Option given as keyword */
923         static const char* Keys [] = {
924             "AUTHOR", "COMMENT", "COMPILER"
925         };
926
927         /* Map the option to a number */
928         OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
929         if (OptNum < 0) {
930             /* Not found */
931             ErrorSkip ("File option keyword expected");
932             return;
933         }
934
935         /* Skip the keyword */
936         NextTok ();
937
938         /* Must be followed by a comma */
939         ConsumeComma ();
940
941         /* We accept only string options for now */
942         if (Tok != TOK_STRCON) {
943             ErrorSkip ("String constant expected");
944             return;
945         }
946
947         /* Insert the option */
948         switch (OptNum) {
949
950             case 0:
951                 /* Author */
952                 OptAuthor (&SVal);
953                 break;
954
955             case 1:
956                 /* Comment */
957                 OptComment (&SVal);
958                 break;
959
960             case 2:
961                 /* Compiler */
962                 OptCompiler (&SVal);
963                 break;
964
965             default:
966                 Internal ("Invalid OptNum: %ld", OptNum);
967
968         }
969
970         /* Done */
971         NextTok ();
972
973     } else {
974
975         /* Option given as number */
976         OptNum = ConstExpression ();
977         if (!IsByteRange (OptNum)) {
978             ErrorSkip ("Range error");
979             return;
980         }
981
982         /* Must be followed by a comma */
983         ConsumeComma ();
984
985         /* We accept only string options for now */
986         if (Tok != TOK_STRCON) {
987             ErrorSkip ("String constant expected");
988             return;
989         }
990
991         /* Insert the option */
992         OptStr ((unsigned char) OptNum, &SVal);
993
994         /* Done */
995         NextTok ();
996     }
997 }
998
999
1000
1001 static void DoForceImport (void)
1002 /* Do a forced import on a symbol */
1003 {
1004     ExportImport (SymImport, ADDR_SIZE_DEFAULT, SF_FORCED);
1005 }
1006
1007
1008
1009 static void DoGlobal (void)
1010 /* Declare a global symbol */
1011 {
1012     ExportImport (SymGlobal, ADDR_SIZE_DEFAULT, SF_NONE);
1013 }
1014
1015
1016
1017 static void DoGlobalZP (void)
1018 /* Declare a global zeropage symbol */
1019 {
1020     ExportImport (SymGlobal, ADDR_SIZE_ZP, SF_NONE);
1021 }
1022
1023
1024 static void DoHiBytes (void)
1025 /* Define bytes, extracting the hi byte from each expression in the list */
1026 {
1027     while (1) {
1028         EmitByte (FuncHiByte ());
1029         if (Tok != TOK_COMMA) {
1030             break;
1031         } else {
1032             NextTok ();
1033         }
1034     }
1035 }
1036
1037
1038
1039 static void DoI16 (void)
1040 /* Switch the index registers to 16 bit mode (assembler only) */
1041 {
1042     if (GetCPU() != CPU_65816) {
1043         Error ("Command is only valid in 65816 mode");
1044     } else {
1045         /* Immidiate mode has two extension bytes */
1046         ExtBytes [AM65I_IMM_INDEX] = 2;
1047     }
1048 }
1049
1050
1051
1052 static void DoI8 (void)
1053 /* Switch the index registers to 16 bit mode (assembler only) */
1054 {
1055     if (GetCPU() != CPU_65816) {
1056         Error ("Command is only valid in 65816 mode");
1057     } else {
1058         /* Immidiate mode has one extension byte */
1059         ExtBytes [AM65I_IMM_INDEX] = 1;
1060     }
1061 }
1062
1063
1064
1065 static void DoImport (void)
1066 /* Import a symbol */
1067 {
1068     ExportImport (SymImport, ADDR_SIZE_DEFAULT, SF_NONE);
1069 }
1070
1071
1072
1073 static void DoImportZP (void)
1074 /* Import a zero page symbol */
1075 {
1076     ExportImport (SymImport, ADDR_SIZE_ZP, SF_NONE);
1077 }
1078
1079
1080
1081 static void DoIncBin (void)
1082 /* Include a binary file */
1083 {
1084     StrBuf Name = STATIC_STRBUF_INITIALIZER;
1085     long Start = 0L;
1086     long Count = -1L;
1087     long Size;
1088     FILE* F;
1089
1090     /* Name must follow */
1091     if (Tok != TOK_STRCON) {
1092         ErrorSkip ("String constant expected");
1093         return;
1094     }
1095     SB_Copy (&Name, &SVal);
1096     SB_Terminate (&Name);
1097     NextTok ();
1098
1099     /* A starting offset may follow */
1100     if (Tok == TOK_COMMA) {
1101         NextTok ();
1102         Start = ConstExpression ();
1103
1104         /* And a length may follow */
1105         if (Tok == TOK_COMMA) {
1106             NextTok ();
1107             Count = ConstExpression ();
1108         }
1109
1110     }
1111
1112     /* Try to open the file */
1113     F = fopen (SB_GetConstBuf (&Name), "rb");
1114     if (F == 0) {
1115
1116         /* Search for the file in the binary include directory */
1117         char* PathName = FindInclude (SB_GetConstBuf (&Name), INC_BIN);
1118         if (PathName == 0 || (F = fopen (PathName, "rb")) == 0) {
1119             /* Not found or cannot open, print an error and bail out */
1120             ErrorSkip ("Cannot open include file `%m%p': %s", &Name, strerror (errno));
1121         }
1122
1123         /* Free the allocated memory */
1124         xfree (PathName);
1125
1126         /* If we had an error before, bail out now */
1127         if (F == 0) {
1128             goto ExitPoint;
1129         }
1130     }
1131
1132     /* Get the size of the file */
1133     fseek (F, 0, SEEK_END);
1134     Size = ftell (F);
1135
1136     /* If a count was not given, calculate it now */
1137     if (Count < 0) {
1138         Count = Size - Start;
1139         if (Count < 0) {
1140             /* Nothing to read - flag this as a range error */
1141             ErrorSkip ("Range error");
1142             goto Done;
1143         }
1144     } else {
1145         /* Count was given, check if it is valid */
1146         if (Start + Count > Size) {
1147             ErrorSkip ("Range error");
1148             goto Done;
1149         }
1150     }
1151
1152     /* Seek to the start position */
1153     fseek (F, Start, SEEK_SET);
1154
1155     /* Read chunks and insert them into the output */
1156     while (Count > 0) {
1157
1158         unsigned char Buf [1024];
1159
1160         /* Calculate the number of bytes to read */
1161         size_t BytesToRead = (Count > (long)sizeof(Buf))? sizeof(Buf) : (size_t) Count;
1162
1163         /* Read chunk */
1164         size_t BytesRead = fread (Buf, 1, BytesToRead, F);
1165         if (BytesToRead != BytesRead) {
1166             /* Some sort of error */
1167             ErrorSkip ("Cannot read from include file `%m%p': %s",
1168                        &Name, strerror (errno));
1169             break;
1170         }
1171
1172         /* Insert it into the output */
1173         EmitData (Buf, BytesRead);
1174
1175         /* Keep the counters current */
1176         Count -= BytesRead;
1177     }
1178
1179 Done:
1180     /* Close the file, ignore errors since it's r/o */
1181     (void) fclose (F);
1182
1183 ExitPoint:
1184     /* Free string memory */
1185     SB_Done (&Name);
1186 }
1187
1188
1189
1190 static void DoInclude (void)
1191 /* Include another file */
1192 {
1193     /* Name must follow */
1194     if (Tok != TOK_STRCON) {
1195         ErrorSkip ("String constant expected");
1196     } else {
1197         SB_Terminate (&SVal);
1198         if (NewInputFile (SB_GetConstBuf (&SVal)) == 0) {
1199             /* Error opening the file, skip remainder of line */
1200             SkipUntilSep ();
1201         }
1202     }
1203 }
1204
1205
1206
1207 static void DoInterruptor (void)
1208 /* Export a symbol as interruptor */
1209 {
1210     StrBuf Name = STATIC_STRBUF_INITIALIZER;
1211
1212     /* Symbol name follows */
1213     if (Tok != TOK_IDENT) {
1214         ErrorSkip ("Identifier expected");
1215         return;
1216     }
1217     SB_Copy (&Name, &SVal);
1218     NextTok ();
1219
1220     /* Parse the remainder of the line and export the symbol */
1221     ConDes (&Name, CD_TYPE_INT);
1222
1223     /* Free string memory */
1224     SB_Done (&Name);
1225 }
1226
1227
1228
1229 static void DoInvalid (void)
1230 /* Handle a token that is invalid here, since it should have been handled on
1231  * a much lower level of the expression hierarchy. Getting this sort of token
1232  * means that the lower level code has bugs.
1233  * This function differs to DoUnexpected in that the latter may be triggered
1234  * by the user by using keywords in the wrong location. DoUnexpected is not
1235  * an error in the assembler itself, while DoInvalid is.
1236  */
1237 {
1238     Internal ("Unexpected token: %m%p", &Keyword);
1239 }
1240
1241
1242
1243 static void DoLineCont (void)
1244 /* Switch the use of line continuations */
1245 {
1246     SetBoolOption (&LineCont);
1247 }
1248
1249
1250
1251 static void DoList (void)
1252 /* Enable/disable the listing */
1253 {
1254     /* Get the setting */
1255     unsigned char List;
1256     SetBoolOption (&List);
1257
1258     /* Manage the counter */
1259     if (List) {
1260         EnableListing ();
1261     } else {
1262         DisableListing ();
1263     }
1264 }
1265
1266
1267
1268 static void DoLoBytes (void)
1269 /* Define bytes, extracting the lo byte from each expression in the list */
1270 {
1271     while (1) {
1272         EmitByte (FuncLoByte ());
1273         if (Tok != TOK_COMMA) {
1274             break;
1275         } else {
1276             NextTok ();
1277         }
1278     }
1279 }
1280
1281
1282 static void DoListBytes (void)
1283 /* Set maximum number of bytes to list for one line */
1284 {
1285     SetListBytes (IntArg (MIN_LIST_BYTES, MAX_LIST_BYTES));
1286 }
1287
1288
1289
1290 static void DoLocalChar (void)
1291 /* Define the character that starts local labels */
1292 {
1293     if (Tok != TOK_CHARCON) {
1294         ErrorSkip ("Character constant expected");
1295     } else {
1296         if (IVal != '@' && IVal != '?') {
1297             Error ("Invalid start character for locals");
1298         } else {
1299             LocalStart = (char) IVal;
1300         }
1301         NextTok ();
1302     }
1303 }
1304
1305
1306
1307 static void DoMacPack (void)
1308 /* Insert a macro package */
1309 {
1310     int Package;
1311
1312     /* We expect an identifier */
1313     if (Tok != TOK_IDENT) {
1314         ErrorSkip ("Identifier expected");
1315         return;
1316     }
1317
1318     /* Search for the macro package name */
1319     LocaseSVal ();
1320     Package = MacPackFind (&SVal);
1321     if (Package < 0) {
1322         /* Not found */
1323         ErrorSkip ("Invalid macro package");
1324         return;
1325     }
1326
1327     /* Insert the package. If this fails, skip the remainder of the line to
1328      * avoid additional error messages.
1329      */
1330     if (MacPackInsert (Package) == 0) {
1331         SkipUntilSep ();
1332     }
1333 }
1334
1335
1336
1337 static void DoMacro (void)
1338 /* Start a macro definition */
1339 {
1340     MacDef (MAC_STYLE_CLASSIC);
1341 }
1342
1343
1344
1345 static void DoNull (void)
1346 /* Switch to the NULL segment */
1347 {
1348     UseSeg (&NullSegDef);
1349 }
1350
1351
1352
1353 static void DoOrg (void)
1354 /* Start absolute code */
1355 {
1356     long PC = ConstExpression ();
1357     if (PC < 0 || PC > 0xFFFFFF) {
1358         Error ("Range error");
1359         return;
1360     }
1361     EnterAbsoluteMode (PC);
1362 }
1363
1364
1365
1366 static void DoOut (void)
1367 /* Output a string */
1368 {
1369     if (Tok != TOK_STRCON) {
1370         ErrorSkip ("String constant expected");
1371     } else {
1372         /* Output the string and be sure to flush the output to keep it in
1373          * sync with any error messages if the output is redirected to a file.
1374          */
1375         printf ("%.*s\n", (int) SB_GetLen (&SVal), SB_GetConstBuf (&SVal));
1376         fflush (stdout);
1377         NextTok ();
1378     }
1379 }
1380
1381
1382
1383 static void DoP02 (void)
1384 /* Switch to 6502 CPU */
1385 {
1386     SetCPU (CPU_6502);
1387 }
1388
1389
1390
1391 static void DoPC02 (void)
1392 /* Switch to 65C02 CPU */
1393 {
1394     SetCPU (CPU_65C02);
1395 }
1396
1397
1398
1399 static void DoP816 (void)
1400 /* Switch to 65816 CPU */
1401 {
1402     SetCPU (CPU_65816);
1403 }
1404
1405
1406
1407 static void DoPageLength (void)
1408 /* Set the page length for the listing */
1409 {
1410     PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
1411 }
1412
1413
1414
1415 static void DoPopSeg (void)
1416 /* Pop an old segment from the segment stack */
1417 {
1418     SegDef* Def;
1419
1420     /* Must have a segment on the stack */
1421     if (CollCount (&SegStack) == 0) {
1422         ErrorSkip ("Segment stack is empty");
1423         return;
1424     }
1425
1426     /* Pop the last element */
1427     Def = CollPop (&SegStack);
1428
1429     /* Restore this segment */
1430     UseSeg (Def);
1431
1432     /* Delete the segment definition */
1433     FreeSegDef (Def);
1434 }
1435
1436
1437
1438 static void DoProc (void)
1439 /* Start a new lexical scope */
1440 {
1441     StrBuf Name = STATIC_STRBUF_INITIALIZER;
1442     unsigned char AddrSize;
1443
1444     if (Tok == TOK_IDENT) {
1445
1446         SymEntry* Sym;
1447
1448         /* The new scope has a name. Remember it. */
1449         SB_Copy (&Name, &SVal);
1450
1451         /* Search for the symbol, generate a new one if needed */
1452         Sym = SymFind (CurrentScope, &Name, SYM_ALLOC_NEW);
1453
1454         /* Skip the scope name */
1455         NextTok ();
1456
1457         /* Read an optional address size specifier */
1458         AddrSize = OptionalAddrSize ();
1459
1460         /* Mark the symbol as defined */
1461         SymDef (Sym, GenCurrentPC (), AddrSize, SF_LABEL);
1462
1463     } else {
1464
1465         /* A .PROC statement without a name */
1466         Warning (1, "Unnamed .PROCs are deprecated, please use .SCOPE");
1467         AnonName (&Name, "PROC");
1468         AddrSize = ADDR_SIZE_DEFAULT;
1469
1470     }
1471
1472     /* Enter a new scope */
1473     SymEnterLevel (&Name, ST_PROC, AddrSize);
1474
1475     /* Free memory for Name */
1476     SB_Done (&Name);
1477 }
1478
1479
1480
1481 static void DoPSC02 (void)
1482 /* Switch to 65SC02 CPU */
1483 {
1484     SetCPU (CPU_65SC02);
1485 }
1486
1487
1488
1489 static void DoPushSeg (void)
1490 /* Push the current segment onto the segment stack */
1491 {
1492     /* Can only push a limited size of segments */
1493     if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) {
1494         ErrorSkip ("Segment stack overflow");
1495         return;
1496     }
1497
1498     /* Get the current segment and push it */
1499     CollAppend (&SegStack, DupSegDef (GetCurrentSegDef ()));
1500 }
1501
1502
1503
1504 static void DoReloc (void)
1505 /* Enter relocatable mode */
1506 {
1507     EnterRelocMode ();
1508 }
1509
1510
1511
1512 static void DoRepeat (void)
1513 /* Repeat some instruction block */
1514 {
1515     ParseRepeat ();
1516 }
1517
1518
1519
1520 static void DoRes (void)
1521 /* Reserve some number of storage bytes */
1522 {
1523     long Count;
1524     long Val;
1525
1526     Count = ConstExpression ();
1527     if (Count > 0xFFFF || Count < 0) {
1528         ErrorSkip ("Range error");
1529         return;
1530     }
1531     if (Tok == TOK_COMMA) {
1532         NextTok ();
1533         Val = ConstExpression ();
1534         /* We need a byte value here */
1535         if (!IsByteRange (Val)) {
1536             ErrorSkip ("Range error");
1537             return;
1538         }
1539
1540         /* Emit constant values */
1541         while (Count--) {
1542             Emit0 ((unsigned char) Val);
1543         }
1544
1545     } else {
1546         /* Emit fill fragments */
1547         EmitFill (Count);
1548     }
1549 }
1550
1551
1552
1553 static void DoROData (void)
1554 /* Switch to the r/o data segment */
1555 {
1556     UseSeg (&RODataSegDef);
1557 }
1558
1559
1560
1561 static void DoScope (void)
1562 /* Start a local scope */
1563 {
1564     StrBuf Name = STATIC_STRBUF_INITIALIZER;
1565     unsigned char AddrSize;
1566
1567
1568     if (Tok == TOK_IDENT) {
1569
1570         /* The new scope has a name. Remember and skip it. */
1571         SB_Copy (&Name, &SVal);
1572         NextTok ();
1573
1574     } else {
1575
1576         /* An unnamed scope */
1577         AnonName (&Name, "SCOPE");
1578
1579     }
1580
1581     /* Read an optional address size specifier */
1582     AddrSize = OptionalAddrSize ();
1583
1584     /* Enter the new scope */
1585     SymEnterLevel (&Name, ST_SCOPE, AddrSize);
1586
1587     /* Free memory for Name */
1588     SB_Done (&Name);
1589 }
1590
1591
1592
1593 static void DoSegment (void)
1594 /* Switch to another segment */
1595 {
1596     StrBuf Name = STATIC_STRBUF_INITIALIZER;
1597     SegDef Def;
1598
1599     if (Tok != TOK_STRCON) {
1600         ErrorSkip ("String constant expected");
1601     } else {
1602
1603         /* Save the name of the segment and skip it */
1604         SB_Copy (&Name, &SVal);
1605         NextTok ();
1606
1607         /* Use the name for the segment definition */
1608         SB_Terminate (&Name);
1609         Def.Name = SB_GetBuf (&Name);
1610
1611         /* Check for an optional address size modifier */
1612         Def.AddrSize = OptionalAddrSize ();
1613
1614         /* Set the segment */
1615         UseSeg (&Def);
1616     }
1617
1618     /* Free memory for Name */
1619     SB_Done (&Name);
1620 }
1621
1622
1623
1624 static void DoSetCPU (void)
1625 /* Switch the CPU instruction set */
1626 {
1627     /* We expect an identifier */
1628     if (Tok != TOK_STRCON) {
1629         ErrorSkip ("String constant expected");
1630     } else {
1631         cpu_t CPU;
1632
1633         /* Try to find the CPU */
1634         SB_Terminate (&SVal);
1635         CPU = FindCPU (SB_GetConstBuf (&SVal));
1636
1637         /* Switch to the new CPU */
1638         SetCPU (CPU);
1639
1640         /* Skip the identifier. If the CPU switch was successful, the scanner
1641          * will treat the input now correctly for the new CPU.
1642          */
1643         NextTok ();
1644     }
1645 }
1646
1647
1648
1649 static void DoSmart (void)
1650 /* Smart mode on/off */
1651 {
1652     SetBoolOption (&SmartMode);
1653 }
1654
1655
1656
1657 static void DoSunPlus (void)
1658 /* Switch to the SUNPLUS CPU */
1659 {
1660     SetCPU (CPU_SUNPLUS);
1661 }
1662
1663
1664
1665 static void DoTag (void)
1666 /* Allocate space for a struct */
1667 {
1668     SymEntry* SizeSym;
1669     long Size;
1670
1671     /* Read the struct name */
1672     SymTable* Struct = ParseScopedSymTable ();
1673
1674     /* Check the supposed struct */
1675     if (Struct == 0) {
1676         ErrorSkip ("Unknown struct");
1677         return;
1678     }
1679     if (GetSymTabType (Struct) != ST_STRUCT) {
1680         ErrorSkip ("Not a struct");
1681         return;
1682     }
1683
1684     /* Get the symbol that defines the size of the struct */
1685     SizeSym = GetSizeOfScope (Struct);
1686
1687     /* Check if it does exist and if its value is known */
1688     if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
1689         ErrorSkip ("Size of struct/union is unknown");
1690         return;
1691     }
1692
1693     /* Optional multiplicator may follow */
1694     if (Tok == TOK_COMMA) {
1695         long Multiplicator;
1696         NextTok ();
1697         Multiplicator = ConstExpression ();
1698         /* Multiplicator must make sense */
1699         if (Multiplicator <= 0) {
1700             ErrorSkip ("Range error");
1701             return;
1702         }
1703         Size *= Multiplicator;
1704     }
1705
1706     /* Emit fill fragments */
1707     EmitFill (Size);
1708 }
1709
1710
1711
1712 static void DoUnexpected (void)
1713 /* Got an unexpected keyword */
1714 {
1715     Error ("Unexpected `%m%p'", &Keyword);
1716     SkipUntilSep ();
1717 }
1718
1719
1720
1721 static void DoWarning (void)
1722 /* User warning */
1723 {
1724     if (Tok != TOK_STRCON) {
1725         ErrorSkip ("String constant expected");
1726     } else {
1727         Warning (0, "User warning: %m%p", &SVal);
1728         SkipUntilSep ();
1729     }
1730 }
1731
1732
1733
1734 static void DoWord (void)
1735 /* Define words */
1736 {
1737     while (1) {
1738         EmitWord (Expression ());
1739         if (Tok != TOK_COMMA) {
1740             break;
1741         } else {
1742             NextTok ();
1743         }
1744     }
1745 }
1746
1747
1748
1749 static void DoZeropage (void)
1750 /* Switch to the zeropage segment */
1751 {
1752     UseSeg (&ZeropageSegDef);
1753 }
1754
1755
1756
1757 /*****************************************************************************/
1758 /*                                Table data                                 */
1759 /*****************************************************************************/
1760
1761
1762
1763 /* Control commands flags */
1764 enum {
1765     ccNone      = 0x0000,               /* No special flags */
1766     ccKeepToken = 0x0001                /* Do not skip the current token */
1767 };
1768
1769 /* Control command table */
1770 typedef struct CtrlDesc CtrlDesc;
1771 struct CtrlDesc {
1772     unsigned    Flags;                  /* Flags for this directive */
1773     void        (*Handler) (void);      /* Command handler */
1774 };
1775
1776 #define PSEUDO_COUNT    (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
1777 static CtrlDesc CtrlCmdTab [] = {
1778     { ccNone,           DoA16           },
1779     { ccNone,           DoA8            },
1780     { ccNone,           DoAddr          },      /* .ADDR */
1781     { ccNone,           DoAlign         },
1782     { ccNone,           DoASCIIZ        },
1783     { ccNone,           DoAssert        },
1784     { ccNone,           DoAutoImport    },
1785     { ccNone,           DoUnexpected    },      /* .BANKBYTE */
1786     { ccNone,           DoBankBytes     },
1787     { ccNone,           DoUnexpected    },      /* .BLANK */
1788     { ccNone,           DoBss           },
1789     { ccNone,           DoByte          },
1790     { ccNone,           DoCase          },
1791     { ccNone,           DoCharMap       },
1792     { ccNone,           DoCode          },
1793     { ccNone,           DoUnexpected,   },      /* .CONCAT */
1794     { ccNone,           DoConDes        },
1795     { ccNone,           DoUnexpected    },      /* .CONST */
1796     { ccNone,           DoConstructor   },
1797     { ccNone,           DoUnexpected    },      /* .CPU */
1798     { ccNone,           DoData          },
1799     { ccNone,           DoDbg,          },
1800     { ccNone,           DoDByt          },
1801     { ccNone,           DoDebugInfo     },
1802     { ccNone,           DoDefine        },
1803     { ccNone,           DoUnexpected    },      /* .DEFINED */
1804     { ccNone,           DoDestructor    },
1805     { ccNone,           DoDWord         },
1806     { ccKeepToken,      DoConditionals  },      /* .ELSE */
1807     { ccKeepToken,      DoConditionals  },      /* .ELSEIF */
1808     { ccKeepToken,      DoEnd           },
1809     { ccNone,           DoUnexpected    },      /* .ENDENUM */
1810     { ccKeepToken,      DoConditionals  },      /* .ENDIF */
1811     { ccNone,           DoUnexpected    },      /* .ENDMACRO */
1812     { ccNone,           DoEndProc       },
1813     { ccNone,           DoUnexpected    },      /* .ENDREPEAT */
1814     { ccNone,           DoEndScope      },
1815     { ccNone,           DoUnexpected    },      /* .ENDSTRUCT */
1816     { ccNone,           DoUnexpected    },      /* .ENDUNION */
1817     { ccNone,           DoEnum          },
1818     { ccNone,           DoError         },
1819     { ccNone,           DoExitMacro     },
1820     { ccNone,           DoExport        },
1821     { ccNone,           DoExportZP      },
1822     { ccNone,           DoFarAddr       },
1823     { ccNone,           DoFeature       },
1824     { ccNone,           DoFileOpt       },
1825     { ccNone,           DoForceImport   },
1826     { ccNone,           DoUnexpected    },      /* .FORCEWORD */
1827     { ccNone,           DoGlobal        },
1828     { ccNone,           DoGlobalZP      },
1829     { ccNone,           DoUnexpected    },      /* .HIBYTE */
1830     { ccNone,           DoHiBytes       },
1831     { ccNone,           DoUnexpected    },      /* .HIWORD */
1832     { ccNone,           DoI16           },
1833     { ccNone,           DoI8            },
1834     { ccNone,           DoUnexpected    },      /* .IDENT */
1835     { ccKeepToken,      DoConditionals  },      /* .IF */
1836     { ccKeepToken,      DoConditionals  },      /* .IFBLANK */
1837     { ccKeepToken,      DoConditionals  },      /* .IFCONST */
1838     { ccKeepToken,      DoConditionals  },      /* .IFDEF */
1839     { ccKeepToken,      DoConditionals  },      /* .IFNBLANK */
1840     { ccKeepToken,      DoConditionals  },      /* .IFNCONST */
1841     { ccKeepToken,      DoConditionals  },      /* .IFNDEF */
1842     { ccKeepToken,      DoConditionals  },      /* .IFNREF */
1843     { ccKeepToken,      DoConditionals  },      /* .IFP02 */
1844     { ccKeepToken,      DoConditionals  },      /* .IFP816 */
1845     { ccKeepToken,      DoConditionals  },      /* .IFPC02 */
1846     { ccKeepToken,      DoConditionals  },      /* .IFPSC02 */
1847     { ccKeepToken,      DoConditionals  },      /* .IFREF */
1848     { ccNone,           DoImport        },
1849     { ccNone,           DoImportZP      },
1850     { ccNone,           DoIncBin        },
1851     { ccNone,           DoInclude       },
1852     { ccNone,           DoInterruptor   },
1853     { ccNone,           DoInvalid       },      /* .LEFT */
1854     { ccNone,           DoLineCont      },
1855     { ccNone,           DoList          },
1856     { ccNone,           DoListBytes     },
1857     { ccNone,           DoUnexpected    },      /* .LOBYTE */
1858     { ccNone,           DoLoBytes       },
1859     { ccNone,           DoUnexpected    },      /* .LOCAL */
1860     { ccNone,           DoLocalChar     },
1861     { ccNone,           DoUnexpected    },      /* .LOWORD */
1862     { ccNone,           DoMacPack       },
1863     { ccNone,           DoMacro         },
1864     { ccNone,           DoUnexpected    },      /* .MATCH */
1865     { ccNone,           DoInvalid       },      /* .MID */
1866     { ccNone,           DoNull          },
1867     { ccNone,           DoOrg           },
1868     { ccNone,           DoOut           },
1869     { ccNone,           DoP02           },
1870     { ccNone,           DoP816          },
1871     { ccNone,           DoPageLength    },
1872     { ccNone,           DoUnexpected    },      /* .PARAMCOUNT */
1873     { ccNone,           DoPC02          },
1874     { ccNone,           DoPopSeg        },
1875     { ccNone,           DoProc          },
1876     { ccNone,           DoPSC02         },
1877     { ccNone,           DoPushSeg       },
1878     { ccNone,           DoUnexpected    },      /* .REFERENCED */
1879     { ccNone,           DoReloc         },
1880     { ccNone,           DoRepeat        },
1881     { ccNone,           DoRes           },
1882     { ccNone,           DoInvalid       },      /* .RIGHT */
1883     { ccNone,           DoROData        },
1884     { ccNone,           DoScope         },
1885     { ccNone,           DoSegment       },
1886     { ccNone,           DoUnexpected    },      /* .SET */
1887     { ccNone,           DoSetCPU        },
1888     { ccNone,           DoUnexpected    },      /* .SIZEOF */
1889     { ccNone,           DoSmart         },
1890     { ccNone,           DoUnexpected    },      /* .SPRINTF */
1891     { ccNone,           DoUnexpected    },      /* .STRAT */
1892     { ccNone,           DoUnexpected    },      /* .STRING */
1893     { ccNone,           DoUnexpected    },      /* .STRLEN */
1894     { ccNone,           DoStruct        },
1895     { ccNone,           DoSunPlus       },
1896     { ccNone,           DoTag           },
1897     { ccNone,           DoUnexpected    },      /* .TCOUNT */
1898     { ccNone,           DoUnexpected    },      /* .TIME */
1899     { ccNone,           DoUnion         },
1900     { ccNone,           DoUnexpected    },      /* .VERSION */
1901     { ccNone,           DoWarning       },
1902     { ccNone,           DoWord          },
1903     { ccNone,           DoUnexpected    },      /* .XMATCH */
1904     { ccNone,           DoZeropage      },
1905 };
1906
1907
1908
1909 /*****************************************************************************/
1910 /*                                   Code                                    */
1911 /*****************************************************************************/
1912
1913
1914
1915 void HandlePseudo (void)
1916 /* Handle a pseudo instruction */
1917 {
1918     CtrlDesc* D;
1919
1920     /* Calculate the index into the table */
1921     unsigned Index = Tok - TOK_FIRSTPSEUDO;
1922
1923     /* Safety check */
1924     if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
1925         Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
1926                   (unsigned) PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
1927     }
1928     CHECK (Index < PSEUDO_COUNT);
1929
1930     /* Get the pseudo intruction descriptor */
1931     D = &CtrlCmdTab [Index];
1932
1933     /* Remember the instruction, then skip it if needed */
1934     if ((D->Flags & ccKeepToken) == 0) {
1935         SB_Copy (&Keyword, &SVal);
1936         NextTok ();
1937     }
1938
1939     /* Call the handler */
1940     D->Handler ();
1941 }
1942
1943
1944
1945 void SegStackCheck (void)
1946 /* Check if the segment stack is empty at end of assembly */
1947 {
1948     if (CollCount (&SegStack) != 0) {
1949         Error ("Segment stack is not empty");
1950     }
1951 }
1952
1953
1954