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