1 /*****************************************************************************/
5 /* Pseudo instructions for the ca65 macroassembler */
9 /* (C) 1998-2003 Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
71 /*****************************************************************************/
73 /*****************************************************************************/
77 /* Keyword we're about to handle */
78 static char Keyword [sizeof (SVal)+1] = ".";
81 #define MAX_PUSHED_SEGMENTS 16
82 static Collection SegStack = STATIC_COLLECTION_INITIALIZER;
86 /*****************************************************************************/
88 /*****************************************************************************/
92 static void DoUnexpected (void);
93 /* Got an unexpected keyword */
95 static void DoInvalid (void);
96 /* Handle a token that is invalid here, since it should have been handled on
97 * a much lower level of the expression hierarchy. Getting this sort of token
98 * means that the lower level code has bugs.
99 * This function differs to DoUnexpected in that the latter may be triggered
100 * by the user by using keywords in the wrong location. DoUnexpected is not
101 * an error in the assembler itself, while DoInvalid is.
106 /*****************************************************************************/
107 /* Helper functions */
108 /*****************************************************************************/
112 static void SetBoolOption (unsigned char* Flag)
113 /* Read a on/off/+/- option and set flag accordingly */
115 static const char* Keys[] = {
120 if (Tok == TOK_PLUS) {
123 } else if (Tok == TOK_MINUS) {
126 } else if (Tok == TOK_IDENT) {
127 /* Map the keyword to a number */
128 switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
129 case 0: *Flag = 0; NextTok (); break;
130 case 1: *Flag = 1; NextTok (); break;
131 default: ErrorSkip (ERR_ONOFF_EXPECTED); break;
133 } else if (TokIsSep (Tok)) {
134 /* Without anything assume switch on */
137 ErrorSkip (ERR_ONOFF_EXPECTED);
143 static void ExportImport (void (*SymFunc) (const char*))
144 /* Export or import symbols */
147 if (Tok != TOK_IDENT) {
148 ErrorSkip (ERR_IDENT_EXPECTED);
153 if (Tok == TOK_COMMA) {
163 static long IntArg (long Min, long Max)
164 /* Read an integer argument and check a range. Accept the token "unlimited"
165 * and return -1 in this case.
168 if (Tok == TOK_IDENT && strcmp (SVal, "unlimited") == 0) {
172 long Val = ConstExpression ();
173 if (Val < Min || Val > Max) {
183 static void ConDes (const char* Name, unsigned Type)
184 /* Parse remaining line for constructor/destructor of the remaining type */
188 /* Optional constructor priority */
189 if (Tok == TOK_COMMA) {
190 /* Priority value follows */
192 Prio = ConstExpression ();
193 if (Prio < CD_PRIO_MIN || Prio > CD_PRIO_MAX) {
194 /* Value out of range */
199 /* Use the default priority value */
203 /* Define the symbol */
204 SymConDes (Name, Type, (unsigned) Prio);
209 /*****************************************************************************/
210 /* Handler functions */
211 /*****************************************************************************/
215 static void DoA16 (void)
216 /* Switch the accu to 16 bit mode (assembler only) */
218 if (GetCPU() != CPU_65816) {
219 Error (ERR_816_MODE_ONLY);
221 /* Immidiate mode has two extension bytes */
222 ExtBytes [AMI_IMM_ACCU] = 2;
228 static void DoA8 (void)
229 /* Switch the accu to 8 bit mode (assembler only) */
231 if (GetCPU() != CPU_65816) {
232 Error (ERR_816_MODE_ONLY);
234 /* Immidiate mode has one extension byte */
235 ExtBytes [AMI_IMM_ACCU] = 1;
241 static void DoAddr (void)
242 /* Define addresses */
245 if (GetCPU() == CPU_65816) {
246 EmitWord (ForceWordExpr (Expression ()));
248 /* Do a range check */
249 EmitWord (Expression ());
251 if (Tok != TOK_COMMA) {
261 static void DoAlign (void)
262 /* Align the PC to some boundary */
268 /* Read the alignment value */
269 Align = ConstExpression ();
270 if (Align <= 0 || Align > 0x10000) {
271 ErrorSkip (ERR_RANGE);
275 /* Optional value follows */
276 if (Tok == TOK_COMMA) {
278 Val = ConstExpression ();
279 /* We need a byte value here */
280 if (!IsByteRange (Val)) {
281 ErrorSkip (ERR_RANGE);
288 /* Check if the alignment is a power of two */
289 Bit = BitFind (Align);
290 if (Align != (0x01L << Bit)) {
293 SegAlign (Bit, (int) Val);
299 static void DoASCIIZ (void)
300 /* Define text with a zero terminator */
305 /* Must have a string constant */
306 if (Tok != TOK_STRCON) {
307 ErrorSkip (ERR_STRCON_EXPECTED);
311 /* Get the length of the string constant */
314 /* Translate into target charset and emit */
315 TgtTranslateBuf (SVal, Len);
316 EmitData ((unsigned char*) SVal, Len);
318 if (Tok == TOK_COMMA) {
329 static void DoAutoImport (void)
330 /* Mark unresolved symbols as imported */
332 SetBoolOption (&AutoImport);
337 static void DoBss (void)
338 /* Switch to the BSS segment */
345 static void DoByte (void)
349 if (Tok == TOK_STRCON) {
350 /* A string, translate into target charset and emit */
351 unsigned Len = strlen (SVal);
352 TgtTranslateBuf (SVal, Len);
353 EmitData ((unsigned char*) SVal, Len);
356 EmitByte (Expression ());
358 if (Tok != TOK_COMMA) {
362 /* Do smart handling of dangling comma */
363 if (Tok == TOK_SEP) {
364 Error (ERR_UNEXPECTED_EOL);
373 static void DoCase (void)
374 /* Switch the IgnoreCase option */
376 SetBoolOption (&IgnoreCase);
377 IgnoreCase = !IgnoreCase;
382 static void DoCharMap (void)
383 /* Allow custome character mappings */
388 /* Read the index as numerical value */
389 Index = ConstExpression ();
390 if (Index < 1 || Index > 255) {
391 /* Value out of range */
392 ErrorSkip (ERR_RANGE);
399 /* Read the character code */
400 Code = ConstExpression ();
401 if (Code < 1 || Code > 255) {
402 /* Value out of range */
403 ErrorSkip (ERR_RANGE);
407 /* Set the character translation */
408 TgtTranslateSet ((unsigned) Index, (unsigned char) Code);
413 static void DoCode (void)
414 /* Switch to the code segment */
416 UseSeg (&CodeSegDef);
421 static void DoConDes (void)
422 /* Export a symbol as constructor/destructor */
424 static const char* Keys[] = {
428 char Name [sizeof (SVal)];
431 /* Symbol name follows */
432 if (Tok != TOK_IDENT) {
433 ErrorSkip (ERR_IDENT_EXPECTED);
439 /* Type follows. May be encoded as identifier or numerical */
441 if (Tok == TOK_IDENT) {
443 /* Map the following keyword to a number, then skip it */
444 Type = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
447 /* Check if we got a valid keyword */
456 /* Read the type as numerical value */
457 Type = ConstExpression ();
458 if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) {
459 /* Value out of range */
466 /* Parse the remainder of the line and export the symbol */
467 ConDes (Name, (unsigned) Type);
472 static void DoConstructor (void)
473 /* Export a symbol as constructor */
475 char Name [sizeof (SVal)];
477 /* Symbol name follows */
478 if (Tok != TOK_IDENT) {
479 ErrorSkip (ERR_IDENT_EXPECTED);
485 /* Parse the remainder of the line and export the symbol */
486 ConDes (Name, CD_TYPE_CON);
491 static void DoData (void)
492 /* Switch to the data segment */
494 UseSeg (&DataSegDef);
499 static void DoDbg (void)
500 /* Add debug information from high level code */
502 static const char* Keys[] = {
510 /* We expect a subkey */
511 if (Tok != TOK_IDENT) {
512 ErrorSkip (ERR_IDENT_EXPECTED);
516 /* Map the following keyword to a number */
517 Key = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
519 /* Skip the subkey */
522 /* Check the key and dispatch to a handler */
524 case 0: DbgInfoFile (); break;
525 case 1: DbgInfoLine (); break;
526 case 2: DbgInfoSym (); break;
527 default: ErrorSkip (ERR_SYNTAX); break;
533 static void DoDByt (void)
534 /* Output double bytes */
537 EmitWord (SwapExpr (Expression ()));
538 if (Tok != TOK_COMMA) {
548 static void DoDebugInfo (void)
549 /* Switch debug info on or off */
551 SetBoolOption (&DbgSyms);
556 static void DoDefine (void)
557 /* Define a one line macro */
559 MacDef (MAC_STYLE_DEFINE);
564 static void DoDestructor (void)
565 /* Export a symbol as destructor */
567 char Name [sizeof (SVal)];
569 /* Symbol name follows */
570 if (Tok != TOK_IDENT) {
571 ErrorSkip (ERR_IDENT_EXPECTED);
577 /* Parse the remainder of the line and export the symbol */
578 ConDes (Name, CD_TYPE_DES);
583 static void DoDWord (void)
587 EmitDWord (Expression ());
588 if (Tok != TOK_COMMA) {
598 static void DoEnd (void)
599 /* End of assembly */
607 static void DoEndProc (void)
608 /* Leave a lexical level */
610 if (!SymIsLocalLevel ()) {
612 ErrorSkip (ERR_NO_OPEN_PROC);
620 static void DoError (void)
623 if (Tok != TOK_STRCON) {
624 ErrorSkip (ERR_STRCON_EXPECTED);
626 Error (ERR_USER, SVal);
633 static void DoExitMacro (void)
634 /* Exit a macro expansion */
636 if (!InMacExpansion ()) {
637 /* We aren't expanding a macro currently */
646 static void DoExport (void)
647 /* Export a symbol */
649 ExportImport (SymExport);
654 static void DoExportZP (void)
655 /* Export a zeropage symbol */
657 ExportImport (SymExportZP);
662 static void DoFarAddr (void)
663 /* Define far addresses (24 bit) */
666 EmitFarAddr (Expression ());
667 if (Tok != TOK_COMMA) {
677 static void DoFeature (void)
678 /* Switch the Feature option */
680 /* Allow a list of comma separated keywords */
683 /* We expect an identifier */
684 if (Tok != TOK_IDENT) {
685 ErrorSkip (ERR_IDENT_EXPECTED);
689 /* Make the string attribute lower case */
692 /* Set the feature and check for errors */
693 if (SetFeature (SVal) == FEAT_UNKNOWN) {
695 ErrorSkip (ERR_ILLEGAL_FEATURE);
698 /* Skip the keyword */
702 /* Allow more than one keyword */
703 if (Tok == TOK_COMMA) {
713 static void DoFileOpt (void)
714 /* Insert a file option */
718 /* The option type may be given as a keyword or as a number. */
719 if (Tok == TOK_IDENT) {
721 /* Option given as keyword */
722 static const char* Keys [] = {
723 "AUTHOR", "COMMENT", "COMPILER"
726 /* Map the option to a number */
727 OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
730 ErrorSkip (ERR_OPTION_KEY_EXPECTED);
734 /* Skip the keyword */
737 /* Must be followed by a comma */
740 /* We accept only string options for now */
741 if (Tok != TOK_STRCON) {
742 ErrorSkip (ERR_STRCON_EXPECTED);
746 /* Insert the option */
765 Internal ("Invalid OptNum: %l", OptNum);
774 /* Option given as number */
775 OptNum = ConstExpression ();
776 if (!IsByteRange (OptNum)) {
777 ErrorSkip (ERR_RANGE);
781 /* Must be followed by a comma */
784 /* We accept only string options for now */
785 if (Tok != TOK_STRCON) {
786 ErrorSkip (ERR_STRCON_EXPECTED);
790 /* Insert the option */
791 OptStr ((unsigned char) OptNum, SVal);
800 static void DoForceImport (void)
801 /* Do a forced import on a symbol */
803 ExportImport (SymImportForced);
808 static void DoGlobal (void)
809 /* Declare a global symbol */
811 ExportImport (SymGlobal);
816 static void DoGlobalZP (void)
817 /* Declare a global zeropage symbol */
819 ExportImport (SymGlobalZP);
824 static void DoI16 (void)
825 /* Switch the index registers to 16 bit mode (assembler only) */
827 if (GetCPU() != CPU_65816) {
828 Error (ERR_816_MODE_ONLY);
830 /* Immidiate mode has two extension bytes */
831 ExtBytes [AMI_IMM_INDEX] = 2;
837 static void DoI8 (void)
838 /* Switch the index registers to 16 bit mode (assembler only) */
840 if (GetCPU() != CPU_65816) {
841 Error (ERR_816_MODE_ONLY);
843 /* Immidiate mode has one extension byte */
844 ExtBytes [AMI_IMM_INDEX] = 1;
850 static void DoImport (void)
851 /* Import a symbol */
853 ExportImport (SymImport);
858 static void DoImportZP (void)
859 /* Import a zero page symbol */
861 ExportImport (SymImportZP);
866 static void DoIncBin (void)
867 /* Include a binary file */
869 char Name [sizeof (SVal)];
875 /* Name must follow */
876 if (Tok != TOK_STRCON) {
877 ErrorSkip (ERR_STRCON_EXPECTED);
883 /* A starting offset may follow */
884 if (Tok == TOK_COMMA) {
886 Start = ConstExpression ();
888 /* And a length may follow */
889 if (Tok == TOK_COMMA) {
891 Count = ConstExpression ();
896 /* Try to open the file */
897 F = fopen (Name, "rb");
900 /* Search for the file in the include directories. */
901 char* PathName = FindInclude (Name);
902 if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
903 /* Not found or cannot open, print an error and bail out */
904 ErrorSkip (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno));
907 /* Free the allocated memory */
910 /* If we had an error before, bail out now */
916 /* Get the size of the file */
917 fseek (F, 0, SEEK_END);
920 /* If a count was not given, calculate it now */
922 Count = Size - Start;
924 /* Nothing to read - flag this as a range error */
925 ErrorSkip (ERR_RANGE);
929 /* Count was given, check if it is valid */
930 if (Start + Count > Size) {
931 ErrorSkip (ERR_RANGE);
936 /* Seek to the start position */
937 fseek (F, Start, SEEK_SET);
939 /* Read chunks and insert them into the output */
942 unsigned char Buf [1024];
944 /* Calculate the number of bytes to read */
945 size_t BytesToRead = (Count > (long)sizeof(Buf))? sizeof(Buf) : (size_t) Count;
948 size_t BytesRead = fread (Buf, 1, BytesToRead, F);
949 if (BytesToRead != BytesRead) {
950 /* Some sort of error */
951 ErrorSkip (ERR_CANNOT_READ_INCLUDE, Name, strerror (errno));
955 /* Insert it into the output */
956 EmitData (Buf, BytesRead);
958 /* Keep the counters current */
963 /* Close the file, ignore errors since it's r/o */
969 static void DoInclude (void)
970 /* Include another file */
972 char Name [MAX_STR_LEN+1];
974 /* Name must follow */
975 if (Tok != TOK_STRCON) {
976 ErrorSkip (ERR_STRCON_EXPECTED);
986 static void DoInvalid (void)
987 /* Handle a token that is invalid here, since it should have been handled on
988 * a much lower level of the expression hierarchy. Getting this sort of token
989 * means that the lower level code has bugs.
990 * This function differs to DoUnexpected in that the latter may be triggered
991 * by the user by using keywords in the wrong location. DoUnexpected is not
992 * an error in the assembler itself, while DoInvalid is.
995 Internal ("Unexpected token: %s", Keyword);
1000 static void DoLineCont (void)
1001 /* Switch the use of line continuations */
1003 SetBoolOption (&LineCont);
1008 static void DoList (void)
1009 /* Enable/disable the listing */
1011 /* Get the setting */
1013 SetBoolOption (&List);
1015 /* Manage the counter */
1025 static void DoListBytes (void)
1026 /* Set maximum number of bytes to list for one line */
1028 SetListBytes (IntArg (MIN_LIST_BYTES, MAX_LIST_BYTES));
1033 static void DoLocalChar (void)
1034 /* Define the character that starts local labels */
1036 if (Tok != TOK_CHARCON) {
1037 ErrorSkip (ERR_CHARCON_EXPECTED);
1039 if (IVal != '@' && IVal != '?') {
1040 Error (ERR_ILLEGAL_LOCALSTART);
1042 LocalStart = (char) IVal;
1050 static void DoMacPack (void)
1051 /* Insert a macro package */
1053 /* Macro package names */
1054 static const char* Keys [] = {
1061 /* We expect an identifier */
1062 if (Tok != TOK_IDENT) {
1063 ErrorSkip (ERR_IDENT_EXPECTED);
1067 /* Map the keyword to a number */
1068 Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
1071 ErrorSkip (ERR_ILLEGAL_MACPACK);
1075 /* Skip the package name */
1078 /* Insert the package */
1079 InsertMacPack (Package);
1084 static void DoMacro (void)
1085 /* Start a macro definition */
1087 MacDef (MAC_STYLE_CLASSIC);
1092 static void DoNull (void)
1093 /* Switch to the NULL segment */
1095 UseSeg (&NullSegDef);
1100 static void DoOrg (void)
1101 /* Start absolute code */
1103 long PC = ConstExpression ();
1104 if (PC < 0 || PC > 0xFFFFFF) {
1113 static void DoOut (void)
1114 /* Output a string */
1116 if (Tok != TOK_STRCON) {
1117 ErrorSkip (ERR_STRCON_EXPECTED);
1119 /* Output the string and be sure to flush the output to keep it in
1120 * sync with any error messages if the output is redirected to a file.
1122 printf ("%s\n", SVal);
1130 static void DoP02 (void)
1131 /* Switch to 6502 CPU */
1138 static void DoPC02 (void)
1139 /* Switch to 65C02 CPU */
1146 static void DoP816 (void)
1147 /* Switch to 65816 CPU */
1154 static void DoPageLength (void)
1155 /* Set the page length for the listing */
1157 PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
1162 static void DoPopSeg (void)
1163 /* Pop an old segment from the segment stack */
1167 /* Must have a segment on the stack */
1168 if (CollCount (&SegStack) == 0) {
1169 ErrorSkip (ERR_SEGSTACK_EMPTY);
1173 /* Pop the last element */
1174 Def = CollPop (&SegStack);
1176 /* Restore this segment */
1179 /* Delete the segment definition */
1185 static void DoProc (void)
1186 /* Start a new lexical scope */
1188 if (Tok == TOK_IDENT) {
1189 /* The new scope has a name */
1190 SymDef (SVal, CurrentPC (), IsZPSeg (), 1);
1198 static void DoPushSeg (void)
1199 /* Push the current segment onto the segment stack */
1201 /* Can only push a limited size of segments */
1202 if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) {
1203 ErrorSkip (ERR_SEGSTACK_OVERFLOW);
1207 /* Get the current segment and push it */
1208 CollAppend (&SegStack, DupSegDef (GetCurrentSeg ()));
1213 static void DoReloc (void)
1214 /* Enter relocatable mode */
1221 static void DoRepeat (void)
1222 /* Repeat some instruction block */
1229 static void DoRes (void)
1230 /* Reserve some number of storage bytes */
1235 Count = ConstExpression ();
1236 if (Count > 0xFFFF || Count < 0) {
1237 ErrorSkip (ERR_RANGE);
1240 if (Tok == TOK_COMMA) {
1242 Val = ConstExpression ();
1243 /* We need a byte value here */
1244 if (!IsByteRange (Val)) {
1245 ErrorSkip (ERR_RANGE);
1249 /* Emit constant values */
1251 Emit0 ((unsigned char) Val);
1255 /* Emit fill fragments */
1262 static void DoROData (void)
1263 /* Switch to the r/o data segment */
1265 UseSeg (&RODataSegDef);
1270 static void DoSegment (void)
1271 /* Switch to another segment */
1273 static const char* AttrTab [] = {
1274 "ZEROPAGE", "DIRECT",
1278 char Name [sizeof (SVal)];
1281 Def.Type = SEGTYPE_DEFAULT;
1283 if (Tok != TOK_STRCON) {
1284 ErrorSkip (ERR_STRCON_EXPECTED);
1287 /* Save the name of the segment and skip it */
1288 strcpy (Name, SVal);
1291 /* Check for an optional segment attribute */
1292 if (Tok == TOK_COMMA) {
1294 if (Tok != TOK_IDENT) {
1295 ErrorSkip (ERR_IDENT_EXPECTED);
1297 int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0]));
1303 Def.Type = SEGTYPE_ZP;
1308 Def.Type = SEGTYPE_ABS;
1314 Def.Type = SEGTYPE_FAR;
1318 Error (ERR_ILLEGAL_SEG_ATTR);
1324 /* Set the segment */
1331 static void DoSmart (void)
1332 /* Smart mode on/off */
1334 SetBoolOption (&SmartMode);
1339 static void DoSunPlus (void)
1340 /* Switch to the SUNPLUS CPU */
1342 SetCPU (CPU_SUNPLUS);
1347 static void DoUnexpected (void)
1348 /* Got an unexpected keyword */
1350 Error (ERR_UNEXPECTED, Keyword);
1356 static void DoWarning (void)
1359 if (Tok != TOK_STRCON) {
1360 ErrorSkip (ERR_STRCON_EXPECTED);
1362 Warning (WARN_USER, SVal);
1369 static void DoWord (void)
1373 EmitWord (Expression ());
1374 if (Tok != TOK_COMMA) {
1384 static void DoZeropage (void)
1385 /* Switch to the zeropage segment */
1387 UseSeg (&ZeropageSegDef);
1392 /*****************************************************************************/
1394 /*****************************************************************************/
1398 /* Control commands flags */
1400 ccNone = 0x0000, /* No special flags */
1401 ccKeepToken = 0x0001 /* Do not skip the current token */
1404 /* Control command table */
1406 unsigned Flags; /* Flags for this directive */
1407 void (*Handler) (void); /* Command handler */
1409 typedef struct CtrlDesc_ CtrlDesc;
1411 #define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
1412 static CtrlDesc CtrlCmdTab [] = {
1415 { ccNone, DoAddr }, /* .ADDR */
1416 { ccNone, DoAlign },
1417 { ccNone, DoASCIIZ },
1418 { ccNone, DoAutoImport },
1419 { ccNone, DoUnexpected }, /* .BLANK */
1423 { ccNone, DoCharMap },
1425 { ccNone, DoUnexpected, }, /* .CONCAT */
1426 { ccNone, DoConDes },
1427 { ccNone, DoUnexpected }, /* .CONST */
1428 { ccNone, DoConstructor },
1429 { ccNone, DoUnexpected }, /* .CPU */
1433 { ccNone, DoDebugInfo },
1434 { ccNone, DoDefine },
1435 { ccNone, DoUnexpected }, /* .DEFINED */
1436 { ccNone, DoDestructor },
1437 { ccNone, DoDWord },
1438 { ccKeepToken, DoConditionals }, /* .ELSE */
1439 { ccKeepToken, DoConditionals }, /* .ELSEIF */
1440 { ccKeepToken, DoEnd },
1441 { ccKeepToken, DoConditionals }, /* .ENDIF */
1442 { ccNone, DoUnexpected }, /* .ENDMACRO */
1443 { ccNone, DoEndProc },
1444 { ccNone, DoUnexpected }, /* .ENDREPEAT */
1445 { ccNone, DoError },
1446 { ccNone, DoExitMacro },
1447 { ccNone, DoExport },
1448 { ccNone, DoExportZP },
1449 { ccNone, DoFarAddr },
1450 { ccNone, DoFeature },
1451 { ccNone, DoFileOpt },
1452 { ccNone, DoForceImport },
1453 { ccNone, DoUnexpected }, /* .FORCEWORD */
1454 { ccNone, DoGlobal },
1455 { ccNone, DoGlobalZP },
1458 { ccKeepToken, DoConditionals }, /* .IF */
1459 { ccKeepToken, DoConditionals }, /* .IFBLANK */
1460 { ccKeepToken, DoConditionals }, /* .IFCONST */
1461 { ccKeepToken, DoConditionals }, /* .IFDEF */
1462 { ccKeepToken, DoConditionals }, /* .IFNBLANK */
1463 { ccKeepToken, DoConditionals }, /* .IFNCONST */
1464 { ccKeepToken, DoConditionals }, /* .IFNDEF */
1465 { ccKeepToken, DoConditionals }, /* .IFNREF */
1466 { ccKeepToken, DoConditionals }, /* .IFP02 */
1467 { ccKeepToken, DoConditionals }, /* .IFP816 */
1468 { ccKeepToken, DoConditionals }, /* .IFPC02 */
1469 { ccKeepToken, DoConditionals }, /* .IFREF */
1470 { ccNone, DoImport },
1471 { ccNone, DoImportZP },
1472 { ccNone, DoIncBin },
1473 { ccNone, DoInclude },
1474 { ccNone, DoInvalid }, /* .LEFT */
1475 { ccNone, DoLineCont },
1477 { ccNone, DoListBytes },
1478 { ccNone, DoUnexpected }, /* .LOCAL */
1479 { ccNone, DoLocalChar },
1480 { ccNone, DoMacPack },
1481 { ccNone, DoMacro },
1482 { ccNone, DoUnexpected }, /* .MATCH */
1483 { ccNone, DoInvalid }, /* .MID */
1489 { ccNone, DoPageLength },
1490 { ccNone, DoUnexpected }, /* .PARAMCOUNT */
1492 { ccNone, DoPopSeg },
1494 { ccNone, DoPushSeg },
1495 { ccNone, DoUnexpected }, /* .REFERENCED */
1496 { ccNone, DoReloc },
1497 { ccNone, DoRepeat },
1499 { ccNone, DoInvalid }, /* .RIGHT */
1500 { ccNone, DoROData },
1501 { ccNone, DoSegment },
1502 { ccNone, DoSmart },
1503 { ccNone, DoUnexpected }, /* .STRAT */
1504 { ccNone, DoUnexpected }, /* .STRING */
1505 { ccNone, DoUnexpected }, /* .STRLEN */
1506 { ccNone, DoSunPlus },
1507 { ccNone, DoUnexpected }, /* .TCOUNT */
1508 { ccNone, DoUnexpected }, /* .TIME */
1509 { ccNone, DoWarning },
1511 { ccNone, DoUnexpected }, /* .XMATCH */
1512 { ccNone, DoZeropage },
1517 /*****************************************************************************/
1519 /*****************************************************************************/
1523 int TokIsPseudo (unsigned Tok)
1524 /* Return true if the given token is a pseudo instruction token */
1526 return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO);
1531 void HandlePseudo (void)
1532 /* Handle a pseudo instruction */
1536 /* Calculate the index into the table */
1537 unsigned Index = Tok - TOK_FIRSTPSEUDO;
1540 if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
1541 Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
1542 PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
1544 CHECK (Index < PSEUDO_COUNT);
1546 /* Get the pseudo intruction descriptor */
1547 D = &CtrlCmdTab [Index];
1549 /* Remember the instruction, then skip it if needed */
1550 if ((D->Flags & ccKeepToken) == 0) {
1551 strcpy (Keyword+1, SVal);
1555 /* Call the handler */
1561 void SegStackCheck (void)
1562 /* Check if the segment stack is empty at end of assembly */
1564 if (CollCount (&SegStack) != 0) {
1565 Error (ERR_SEGSTACK_NOT_EMPTY);