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