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