]> git.sur5r.net Git - cc65/blob - src/ca65/pseudo.c
Removed the strexpr module and placed the implementation of the .STRING
[cc65] / src / ca65 / pseudo.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 pseudo.c                                  */
4 /*                                                                           */
5 /*              Pseudo instructions for the ca65 macroassembler              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2000 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
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 #include "../common/bitops.h"
43
44 #include "condasm.h"
45 #include "error.h"
46 #include "expr.h"
47 #include "global.h"
48 #include "instr.h"
49 #include "listing.h"
50 #include "macpack.h"
51 #include "macro.h"
52 #include "nexttok.h"
53 #include "objcode.h"
54 #include "options.h"
55 #include "symtab.h"
56 #include "pseudo.h"
57
58
59
60 /*****************************************************************************/
61 /*                                   Data                                    */
62 /*****************************************************************************/
63
64
65
66 /* Keyword we're about to handle */
67 static char Keyword [sizeof (SVal)+1] = ".";
68
69
70
71 /*****************************************************************************/
72 /*                               Forwards                                    */
73 /*****************************************************************************/
74
75
76
77 static void DoUnexpected (void);
78
79
80
81 /*****************************************************************************/
82 /*                              Helper functions                             */
83 /*****************************************************************************/
84
85
86
87 static void SetBoolOption (unsigned char* Flag)
88 /* Read a on/off/+/- option and set flag accordingly */
89 {
90     static const char* Keys[] = {
91         "OFF",
92         "ON",
93     };
94
95     if (Tok == TOK_PLUS) {
96         *Flag = 1;
97         NextTok ();
98     } else if (Tok == TOK_MINUS) {
99         *Flag = 0;
100         NextTok ();
101     } else if (Tok == TOK_IDENT) {
102         /* Map the keyword to a number */
103         switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
104             case 0:     *Flag = 0; NextTok ();          break;
105             case 1:     *Flag = 1; NextTok ();          break;
106             default:    ErrorSkip (ERR_ONOFF_EXPECTED); break;
107         }
108     } else if (Tok == TOK_SEP || Tok == TOK_EOF) {
109         /* Without anything assume switch on */
110         *Flag = 1;
111     } else {
112         ErrorSkip (ERR_ONOFF_EXPECTED);
113     }
114 }
115
116
117
118 static void ExportImport (void (*SymFunc) (const char*, int), int ZP)
119 /* Export or import symbols */
120 {
121     while (1) {
122         if (Tok != TOK_IDENT) {
123             ErrorSkip (ERR_IDENT_EXPECTED);
124             break;
125         }
126         SymFunc (SVal, ZP);
127         NextTok ();
128         if (Tok == TOK_COMMA) {
129             NextTok ();
130         } else {
131             break;
132         }
133     }
134 }
135
136
137
138 static long IntArg (long Min, long Max)
139 /* Read an integer argument and check a range. Accept the token "unlimited"
140  * and return -1 in this case.
141  */
142 {
143     if (Tok == TOK_IDENT && strcmp (SVal, "unlimited") == 0) {
144         NextTok ();
145         return -1;
146     } else {
147         long Val = ConstExpression ();
148         if (Val < Min || Val > Max) {
149             Error (ERR_RANGE);
150             Val = Min;
151         }
152         return Val;
153     }
154 }
155
156
157
158 /*****************************************************************************/
159 /*                             Handler functions                             */
160 /*****************************************************************************/
161
162
163
164 static void DoA16 (void)
165 /* Switch the accu to 16 bit mode (assembler only) */
166 {
167     if (GetCPU() != CPU_65816) {
168         Error (ERR_816_MODE_ONLY);
169     } else {
170         /* Immidiate mode has two extension bytes */
171         ExtBytes [AMI_IMM_ACCU] = 2;
172     }
173 }
174
175
176
177 static void DoA8 (void)
178 /* Switch the accu to 8 bit mode (assembler only) */
179 {
180     if (GetCPU() != CPU_65816) {
181         Error (ERR_816_MODE_ONLY);
182     } else {
183         /* Immidiate mode has one extension byte */
184         ExtBytes [AMI_IMM_ACCU] = 1;
185     }
186 }
187
188
189
190 static void DoAddr (void)
191 /* Define addresses */
192 {
193     while (1) {
194         if (GetCPU() == CPU_65816) {
195             EmitWord (ForceWordExpr (Expression ()));
196         } else {
197             /* Do a range check */
198             EmitWord (Expression ());
199         }
200         if (Tok != TOK_COMMA) {
201             break;
202         } else {
203             NextTok ();
204         }
205     }
206 }
207
208
209
210 static void DoAlign (void)
211 /* Align the PC to some boundary */
212 {
213     long Val;
214     long Align;
215     unsigned Bit;
216
217     /* Read the alignment value */
218     Align = ConstExpression ();
219     if (Align <= 0 || Align > 0x10000) {
220         ErrorSkip (ERR_RANGE);
221         return;
222     }
223
224     /* Optional value follows */
225     if (Tok == TOK_COMMA) {
226         NextTok ();
227         Val = ConstExpression ();
228         /* We need a byte value here */
229         if (!IsByteRange (Val)) {
230             ErrorSkip (ERR_RANGE);
231             return;
232         }
233     } else {
234         Val = -1;
235     }
236
237     /* Check if the alignment is a power of two */
238     Bit = BitFind (Align);
239     if (Align != (0x01L << Bit)) {
240         Error (ERR_ALIGN);
241     } else {
242         SegAlign (Bit, (int) Val);
243     }
244 }
245
246
247
248 static void DoASCIIZ (void)
249 /* Define text with a zero terminator */
250 {
251     while (1) {
252         if (Tok != TOK_STRCON) {
253             ErrorSkip (ERR_STRCON_EXPECTED);
254             return;
255         }
256         EmitData (SVal, strlen (SVal));
257         NextTok ();
258         if (Tok == TOK_COMMA) {
259             NextTok ();
260         } else {
261             break;
262         }
263     }
264     Emit0 (0);
265 }
266
267
268
269 static void DoAutoImport (void)
270 /* Mark unresolved symbols as imported */
271 {
272     SetBoolOption (&AutoImport);
273 }
274
275
276
277 static void DoBss (void)
278 /* Switch to the BSS segment */
279 {
280     UseBssSeg ();
281 }
282
283
284
285 static void DoByte (void)
286 /* Define bytes */
287 {
288     while (1) {
289         if (Tok == TOK_STRCON) {
290             /* A string */
291             EmitData (SVal, strlen (SVal));
292             NextTok ();
293         } else {
294             EmitByte (Expression ());
295         }
296         if (Tok != TOK_COMMA) {
297             break;
298         } else {
299             NextTok ();
300             /* Do smart handling of dangling comma */
301             if (Tok == TOK_SEP) {
302                 Error (ERR_UNEXPECTED_EOL);
303                 break;
304             }
305         }
306     }
307 }
308
309
310
311 static void DoCase (void)
312 /* Switch the IgnoreCase option */
313 {
314     SetBoolOption (&IgnoreCase);
315     IgnoreCase = !IgnoreCase;
316 }
317
318
319
320 static void DoCode (void)
321 /* Switch to the code segment */
322 {
323     UseCodeSeg ();
324 }
325
326
327
328 static void DoData (void)
329 /* Switch to the data segment */
330 {
331     UseDataSeg ();
332 }
333
334
335
336 static void DoDByt (void)
337 /* Output double bytes */
338 {
339     while (1) {
340         EmitWord (SwapExpr (Expression ()));
341         if (Tok != TOK_COMMA) {
342             break;
343         } else {
344             NextTok ();
345         }
346     }
347 }
348
349
350
351 static void DoDebugInfo (void)
352 /* Switch debug info on or off */
353 {
354     SetBoolOption (&DbgSyms);
355 }
356
357
358
359 static void DoDefine (void)
360 /* Define a one line macro */
361 {
362     MacDef (MAC_STYLE_DEFINE);
363 }
364
365
366
367 static void DoDWord (void)
368 /* Define dwords */
369 {
370     while (1) {
371         EmitDWord (Expression ());
372         if (Tok != TOK_COMMA) {
373             break;
374         } else {
375             NextTok ();
376         }
377     }
378 }
379
380
381
382 static void DoEnd (void)
383 /* End of assembly */
384 {
385     ForcedEnd = 1;
386 }
387
388
389
390 static void DoEndProc (void)
391 /* Leave a lexical level */
392 {
393     SymLeaveLevel ();
394 }
395
396
397
398 static void DoError (void)
399 /* Use error */
400 {
401     if (Tok == TOK_STRCON) {
402         ErrorSkip (ERR_STRCON_EXPECTED);
403     } else {
404         Error (ERR_USER, SVal);
405         SkipUntilSep ();
406     }
407 }
408
409
410
411 static void DoExitMacro (void)
412 /* Exit a macro expansion */
413 {
414     if (!InMacExpansion ()) {
415         /* We aren't expanding a macro currently */
416         DoUnexpected ();
417     } else {
418         MacAbort ();
419     }
420 }
421
422
423
424 static void DoExport (void)
425 /* Export a symbol */
426 {
427     ExportImport (SymExport, 0);
428 }
429
430
431
432 static void DoExportZP (void)
433 /* Export a zeropage symbol */
434 {
435     ExportImport (SymExport, 1);
436 }
437
438
439
440 static void DoFarAddr (void)
441 /* Define far addresses (24 bit) */
442 {
443     while (1) {
444         EmitFarAddr (Expression ());
445         if (Tok != TOK_COMMA) {
446             break;
447         } else {
448             NextTok ();
449         }
450     }
451 }
452
453
454
455 static void DoFeature (void)
456 /* Switch the Feature option */
457 {
458     int Feature;
459
460     static const char* Keys[] = {
461         "DOLLAR_IS_PC",
462         "LABELS_WITHOUT_COLONS",
463         "LOOSE_STRING_TERM",
464         "AT_IN_IDENTIFIERS",
465         "DOLLAR_IN_IDENTIFIERS",
466     };
467
468     /* Allow a list of comma separated keywords */
469     while (1) {
470
471         /* We expect an identifier */
472         if (Tok != TOK_IDENT) {
473             ErrorSkip (ERR_IDENT_EXPECTED);
474             return;
475         }
476
477         /* Map the keyword to a number */
478         Feature = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
479         if (Feature < 0) {
480             /* Not found */
481             ErrorSkip (ERR_ILLEGAL_FEATURE);
482             return;
483         }
484
485         /* Skip the keyword */
486         NextTok ();
487
488         /* Switch the feature on */
489         switch (Feature) {
490             case 0:     DollarIsPC      = 1;    break;
491             case 1:     NoColonLabels   = 1;    break;
492             case 2:     LooseStringTerm = 1;    break;
493             case 3:     AtInIdents      = 1;    break;
494             case 4:     DollarInIdents  = 1;    break;
495             default:    Internal ("Invalid feature: %d", Feature);
496         }
497
498         /* Allow more than one keyword */
499         if (Tok == TOK_COMMA) {
500             NextTok ();
501         } else {
502             break;
503         }
504     }
505 }
506
507
508
509 static void DoFileOpt (void)
510 /* Insert a file option */
511 {
512     long OptNum;
513
514     /* The option type may be given as a keyword or as a number. */
515     if (Tok == TOK_IDENT) {
516
517         /* Option given as keyword */
518         static const char* Keys [] = {
519             "AUTHOR", "COMMENT", "COMPILER"
520         };
521
522         /* Map the option to a number */
523         OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
524         if (OptNum < 0) {
525             /* Not found */
526             ErrorSkip (ERR_OPTION_KEY_EXPECTED);
527             return;
528         }
529
530         /* Skip the keyword */
531         NextTok ();
532
533         /* Must be followed by a comma */
534         ConsumeComma ();
535
536         /* We accept only string options for now */
537         if (Tok != TOK_STRCON) {
538             ErrorSkip (ERR_STRCON_EXPECTED);
539             return;
540         }
541
542         /* Insert the option */
543         switch (OptNum) {
544
545             case 0:
546                 /* Author */
547                 OptAuthor (SVal);
548                 break;
549
550             case 1:
551                 /* Comment */
552                 OptComment (SVal);
553                 break;
554
555             case 2:
556                 /* Compiler */
557                 OptCompiler (SVal);
558                 break;
559
560             default:
561                 Internal ("Invalid OptNum: %l", OptNum);
562
563         }
564
565         /* Done */
566         NextTok ();
567
568     } else {
569
570         /* Option given as number */
571         OptNum = ConstExpression ();
572         if (!IsByteRange (OptNum)) {
573             ErrorSkip (ERR_RANGE);
574             return;
575         }
576
577         /* Must be followed by a comma */
578         ConsumeComma ();
579
580         /* We accept only string options for now */
581         if (Tok != TOK_STRCON) {
582             ErrorSkip (ERR_STRCON_EXPECTED);
583             return;
584         }
585
586         /* Insert the option */
587         OptStr ((unsigned char) OptNum, SVal);
588
589         /* Done */
590         NextTok ();
591     }
592 }
593
594
595
596 static void DoGlobal (void)
597 /* Declare a global symbol */
598 {
599     ExportImport (SymGlobal, 0);
600 }
601
602
603
604 static void DoGlobalZP (void)
605 /* Declare a global zeropage symbol */
606 {
607     ExportImport (SymGlobal, 1);
608 }
609
610
611
612 static void DoI16 (void)
613 /* Switch the index registers to 16 bit mode (assembler only) */
614 {
615     if (GetCPU() != CPU_65816) {
616         Error (ERR_816_MODE_ONLY);
617     } else {
618         /* Immidiate mode has two extension bytes */
619         ExtBytes [AMI_IMM_INDEX] = 2;
620     }
621 }
622
623
624
625 static void DoI8 (void)
626 /* Switch the index registers to 16 bit mode (assembler only) */
627 {
628     if (GetCPU() != CPU_65816) {
629         Error (ERR_816_MODE_ONLY);
630     } else {
631         /* Immidiate mode has one extension byte */
632         ExtBytes [AMI_IMM_INDEX] = 1;
633     }
634 }
635
636
637
638 static void DoImport (void)
639 /* Import a symbol */
640 {
641     ExportImport (SymImport, 0);
642 }
643
644
645
646 static void DoImportZP (void)
647 /* Import a zero page symbol */
648 {
649     ExportImport (SymImport, 1);
650 }
651
652
653
654 static void DoIncBin (void)
655 /* Include a binary file */
656 {
657     /* Name must follow */
658     if (Tok != TOK_STRCON) {
659         ErrorSkip (ERR_STRCON_EXPECTED);
660     } else {
661         /* Try to open the file */
662         FILE* F = fopen (SVal, "rb");
663         if (F == 0) {
664             Error (ERR_CANNOT_OPEN_INCLUDE, SVal, strerror (errno));
665         } else {
666             unsigned char Buf [1024];
667             size_t Count;
668             /* Read chunks and insert them into the output */
669             while ((Count = fread (Buf, 1, sizeof (Buf), F)) > 0) {
670                 EmitData (Buf, Count);
671             }
672             /* Close the file, ignore errors since it's r/o */
673             (void) fclose (F);
674         }
675         /* Skip the name */
676         NextTok ();
677     }
678 }
679
680
681
682 static void DoInclude (void)
683 /* Include another file */
684 {
685     char Name [MAX_STR_LEN+1];
686
687     /* Name must follow */
688     if (Tok != TOK_STRCON) {
689         ErrorSkip (ERR_STRCON_EXPECTED);
690     } else {
691         strcpy (Name, SVal);
692         NextTok ();
693         NewInputFile (Name);
694     }
695 }
696
697
698
699 static void DoLineCont (void)
700 /* Switch the use of line continuations */
701 {
702     SetBoolOption (&LineCont);
703 }
704
705
706
707 static void DoList (void)
708 /* Enable/disable the listing */
709 {
710     /* Get the setting */
711     unsigned char List;
712     SetBoolOption (&List);
713
714     /* Manage the counter */
715     if (List) {
716         EnableListing ();
717     } else {
718         DisableListing ();
719     }
720 }
721
722
723
724 static void DoListBytes (void)
725 /* Set maximum number of bytes to list for one line */
726 {
727     SetListBytes (IntArg (MIN_LIST_BYTES, MAX_LIST_BYTES));
728 }
729
730
731
732 static void DoLocalChar (void)
733 /* Define the character that starts local labels */
734 {
735     if (Tok != TOK_CHARCON) {
736         ErrorSkip (ERR_CHARCON_EXPECTED);
737     } else {
738         if (IVal != '@' && IVal != '?') {
739             Error (ERR_ILLEGAL_LOCALSTART);
740         } else {
741             LocalStart = (char) IVal;
742         }
743         NextTok ();
744     }
745 }
746
747
748
749 static void DoMacPack (void)
750 /* Insert a macro package */
751 {
752     /* Macro package names */
753     static const char* Keys [] = {
754         "GENERIC",
755         "LONGBRANCH",
756     };
757
758     int Package;
759
760     /* We expect an identifier */
761     if (Tok != TOK_IDENT) {
762         ErrorSkip (ERR_IDENT_EXPECTED);
763         return;
764     }
765
766     /* Map the keyword to a number */
767     Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
768     if (Package < 0) {
769         /* Not found */
770         ErrorSkip (ERR_ILLEGAL_MACPACK);
771         return;
772     }
773
774     /* Skip the package name */
775     NextTok ();
776
777     /* Insert the package */
778     InsertMacPack (Package);
779 }
780
781
782
783 static void DoMacro (void)
784 /* Start a macro definition */
785 {
786     MacDef (MAC_STYLE_CLASSIC);
787 }
788
789
790
791 static void DoMid (void)
792 /* Handle .MID - this should never happen, since the keyword is actually
793  * handled on a much lower level of the expression hierarchy.
794  */
795 {
796     Internal ("Unexpected token: .MID");
797 }
798
799
800
801 static void DoNull (void)
802 /* Switch to the NULL segment */
803 {
804     UseNullSeg ();
805 }
806
807
808
809 static void DoOrg (void)
810 /* Start absolute code */
811 {
812     long PC = ConstExpression ();
813     if (PC < 0 || PC > 0xFFFF) {
814         Error (ERR_RANGE);
815         return;
816     }
817     SetAbsPC (PC);
818 }
819
820
821
822 static void DoOut (void)
823 /* Output a string */
824 {
825     if (Tok != TOK_STRCON) {
826         ErrorSkip (ERR_STRCON_EXPECTED);
827     } else {
828         /* Output the string and be sure to flush the output to keep it in
829          * sync with any error messages if the output is redirected to a file.
830          */
831         printf ("%s\n", SVal);
832         fflush (stdout);
833         NextTok ();
834     }
835 }
836
837
838
839 static void DoP02 (void)
840 /* Switch to 6502 CPU */
841 {
842     SetCPU (CPU_6502);
843 }
844
845
846
847 static void DoPC02 (void)
848 /* Switch to 65C02 CPU */
849 {
850     SetCPU (CPU_65C02);
851 }
852
853
854
855 static void DoP816 (void)
856 /* Switch to 65816 CPU */
857 {
858     SetCPU (CPU_65816);
859 }
860
861
862
863 static void DoPageLength (void)
864 /* Set the page length for the listing */
865 {
866     PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
867 }
868
869
870
871 static void DoProc (void)
872 /* Start a new lexical scope */
873 {
874     if (Tok == TOK_IDENT) {
875         /* The new scope has a name */
876         SymDef (SVal, CurrentPC (), IsZPSeg ());
877         NextTok ();
878     }
879     SymEnterLevel ();
880 }
881
882
883
884 static void DoReloc (void)
885 /* Enter relocatable mode */
886 {
887     RelocMode = 1;
888 }
889
890
891
892 static void DoRepeat (void)
893 /* Repeat some instruction block */
894 {
895     ErrorSkip (ERR_NOT_IMPLEMENTED);
896 }
897
898
899
900 static void DoRes (void)
901 /* Reserve some number of storage bytes */
902 {
903     long Count;
904     long Val;
905
906     Count = ConstExpression ();
907     if (Count > 0xFFFF || Count < 0) {
908         ErrorSkip (ERR_RANGE);
909         return;
910     }
911     if (Tok == TOK_COMMA) {
912         NextTok ();
913         Val = ConstExpression ();
914         /* We need a byte value here */
915         if (!IsByteRange (Val)) {
916             ErrorSkip (ERR_RANGE);
917             return;
918         }
919
920         /* Emit constant values */
921         while (Count--) {
922             Emit0 ((unsigned char) Val);
923         }
924
925     } else {
926         /* Emit fill fragments */
927         EmitFill (Count);
928     }
929 }
930
931
932
933 static void DoROData (void)
934 /* Switch to the r/o data segment */
935 {
936     UseRODataSeg ();
937 }
938
939
940
941 static void DoSegment (void)
942 /* Switch to another segment */
943 {
944     static const char* AttrTab [] = {
945         "ZEROPAGE", "DIRECT",
946         "ABSOLUTE",
947         "FAR", "LONG"
948     };
949     char Name [sizeof (SVal)];
950     int SegType;
951
952     if (Tok != TOK_STRCON) {
953         ErrorSkip (ERR_STRCON_EXPECTED);
954     } else {
955
956         /* Save the name of the segment and skip it */
957         strcpy (Name, SVal);
958         NextTok ();
959
960         /* Check for an optional segment attribute */
961         SegType = SEGTYPE_DEFAULT;
962         if (Tok == TOK_COMMA) {
963             NextTok ();
964             if (Tok != TOK_IDENT) {
965                 ErrorSkip (ERR_IDENT_EXPECTED);
966             } else {
967                 int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0]));
968                 switch (Attr) {
969
970                     case 0:
971                     case 1:
972                         /* Zeropage */
973                         SegType = SEGTYPE_ZP;
974                         break;
975
976                     case 2:
977                         /* Absolute */
978                         SegType = SEGTYPE_ABS;
979                         break;
980
981                     case 3:
982                     case 4:
983                         /* Far */
984                         SegType = SEGTYPE_FAR;
985                         break;
986
987                     default:
988                         Error (ERR_ILLEGAL_SEG_ATTR);
989                 }
990                 NextTok ();
991             }
992         }
993
994         /* Set the segment */
995         UseSeg (Name, SegType);
996     }
997 }
998
999
1000
1001 static void DoSmart (void)
1002 /* Smart mode on/off */
1003 {
1004     SetBoolOption (&SmartMode);
1005 }
1006
1007
1008
1009 static void DoSunPlus (void)
1010 /* Switch to the SUNPLUS CPU */
1011 {
1012     SetCPU (CPU_SUNPLUS);
1013 }
1014
1015
1016
1017 static void DoUnexpected (void)
1018 /* Got an unexpected keyword */
1019 {
1020     Error (ERR_UNEXPECTED, Keyword);
1021     SkipUntilSep ();
1022 }
1023
1024
1025
1026 static void DoWord (void)
1027 /* Define words */
1028 {
1029     while (1) {
1030         EmitWord (Expression ());
1031         if (Tok != TOK_COMMA) {
1032             break;
1033         } else {
1034             NextTok ();
1035         }
1036     }
1037 }
1038
1039
1040
1041 static void DoZeropage (void)
1042 /* Switch to the zeropage segment */
1043 {
1044     UseZeropageSeg ();
1045 }
1046
1047
1048
1049 /*****************************************************************************/
1050 /*                                Table data                                 */
1051 /*****************************************************************************/
1052
1053
1054
1055 /* Control commands flags */
1056 enum {
1057     ccNone      = 0x0000,               /* No special flags */
1058     ccKeepToken = 0x0001                /* Do not skip the current token */
1059 };
1060
1061 /* Control command table */
1062 struct CtrlDesc_ {
1063     unsigned    Flags;                  /* Flags for this directive */
1064     void        (*Handler) (void);      /* Command handler */
1065 };
1066 typedef struct CtrlDesc_ CtrlDesc;
1067
1068 #define PSEUDO_COUNT    (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
1069 static CtrlDesc CtrlCmdTab [] = {
1070     { ccNone,           DoA16           },
1071     { ccNone,           DoA8            },
1072     { ccNone,           DoAddr          },      /* .ADDR */
1073     { ccNone,           DoAlign         },
1074     { ccNone,           DoASCIIZ        },
1075     { ccNone,           DoAutoImport    },
1076     { ccNone,           DoUnexpected    },      /* .BLANK */
1077     { ccNone,           DoBss           },
1078     { ccNone,           DoByte          },
1079     { ccNone,           DoCase          },
1080     { ccNone,           DoCode          },
1081     { ccNone,           DoUnexpected,   },      /* .CONCAT */
1082     { ccNone,           DoUnexpected    },      /* .CONST */
1083     { ccNone,           DoUnexpected    },      /* .CPU */
1084     { ccNone,           DoData          },
1085     { ccNone,           DoDByt          },
1086     { ccNone,           DoDebugInfo     },
1087     { ccNone,           DoDefine        },
1088     { ccNone,           DoUnexpected    },      /* .DEFINED */
1089     { ccNone,           DoDWord         },
1090     { ccKeepToken,      DoConditionals  },      /* .ELSE */
1091     { ccKeepToken,      DoConditionals  },      /* .ELSEIF */
1092     { ccNone,           DoEnd           },
1093     { ccKeepToken,      DoConditionals  },      /* .ENDIF */
1094     { ccNone,           DoUnexpected    },      /* .ENDMACRO */
1095     { ccNone,           DoEndProc       },
1096     { ccNone,           DoUnexpected    },      /* .ENDREPEAT */
1097     { ccNone,           DoError         },
1098     { ccNone,           DoExitMacro     },
1099     { ccNone,           DoExport        },
1100     { ccNone,           DoExportZP      },
1101     { ccNone,           DoFarAddr       },
1102     { ccNone,           DoFeature       },
1103     { ccNone,           DoFileOpt       },
1104     { ccNone,           DoGlobal        },
1105     { ccNone,           DoGlobalZP      },
1106     { ccNone,           DoI16           },
1107     { ccNone,           DoI8            },
1108     { ccKeepToken,      DoConditionals  },      /* .IF */
1109     { ccKeepToken,      DoConditionals  },      /* .IFBLANK */
1110     { ccKeepToken,      DoConditionals  },      /* .IFCONST */
1111     { ccKeepToken,      DoConditionals  },      /* .IFDEF */
1112     { ccKeepToken,      DoConditionals  },      /* .IFNBLANK */
1113     { ccKeepToken,      DoConditionals  },      /* .IFNCONST */
1114     { ccKeepToken,      DoConditionals  },      /* .IFNDEF */
1115     { ccKeepToken,      DoConditionals  },      /* .IFNREF */
1116     { ccKeepToken,      DoConditionals  },      /* .IFP02 */
1117     { ccKeepToken,      DoConditionals  },      /* .IFP816 */
1118     { ccKeepToken,      DoConditionals  },      /* .IFPC02 */
1119     { ccKeepToken,      DoConditionals  },      /* .IFREF */
1120     { ccNone,           DoImport        },
1121     { ccNone,           DoImportZP      },
1122     { ccNone,           DoIncBin        },
1123     { ccNone,           DoInclude       },
1124     { ccNone,           DoLineCont      },
1125     { ccNone,           DoList          },
1126     { ccNone,           DoListBytes     },
1127     { ccNone,           DoUnexpected    },      /* .LOCAL */
1128     { ccNone,           DoLocalChar     },
1129     { ccNone,           DoMacPack       },
1130     { ccNone,           DoMacro         },
1131     { ccNone,           DoUnexpected    },      /* .MATCH */
1132     { ccNone,           DoMid           },
1133     { ccNone,           DoNull          },
1134     { ccNone,           DoOrg           },
1135     { ccNone,           DoOut           },
1136     { ccNone,           DoP02           },
1137     { ccNone,           DoP816          },
1138     { ccNone,           DoPageLength    },
1139     { ccNone,           DoUnexpected    },      /* .PARAMCOUNT */
1140     { ccNone,           DoPC02          },
1141     { ccNone,           DoProc          },
1142     { ccNone,           DoUnexpected    },      /* .REFERENCED */
1143     { ccNone,           DoReloc         },
1144     { ccNone,           DoRepeat        },
1145     { ccNone,           DoRes           },
1146     { ccNone,           DoROData        },
1147     { ccNone,           DoSegment       },
1148     { ccNone,           DoSmart         },
1149     { ccNone,           DoUnexpected    },      /* .STRING */
1150     { ccNone,           DoSunPlus       },
1151     { ccNone,           DoWord          },
1152     { ccNone,           DoUnexpected    },      /* .XMATCH */
1153     { ccNone,           DoZeropage      },
1154 };
1155
1156
1157
1158 /*****************************************************************************/
1159 /*                                   Code                                    */
1160 /*****************************************************************************/
1161
1162
1163
1164 int TokIsPseudo (unsigned Tok)
1165 /* Return true if the given token is a pseudo instruction token */
1166 {
1167     return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO);
1168 }
1169
1170
1171
1172 void HandlePseudo (void)
1173 /* Handle a pseudo instruction */
1174 {
1175     CtrlDesc* D;
1176
1177     /* Calculate the index into the table */
1178     unsigned Index = Tok - TOK_FIRSTPSEUDO;
1179
1180     /* Safety check */
1181     if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
1182         Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
1183                   PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
1184     }
1185     CHECK (Index < PSEUDO_COUNT);
1186
1187     /* Get the pseudo intruction descriptor */
1188     D = &CtrlCmdTab [Index];
1189
1190     /* Remember the instruction, then skip it if needed */
1191     if ((D->Flags & ccKeepToken) == 0) {
1192         strcpy (Keyword+1, SVal);
1193         NextTok ();
1194     }
1195
1196     /* Call the handler */
1197     D->Handler ();
1198 }
1199
1200
1201