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