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 */
606 static void DoEndProc (void)
607 /* Leave a lexical level */
609 if (!SymIsLocalLevel ()) {
610 /* No local symbol table level open */
611 ErrorSkip (ERR_NO_OPEN_PROC);
619 static void DoError (void)
622 if (Tok != TOK_STRCON) {
623 ErrorSkip (ERR_STRCON_EXPECTED);
625 Error (ERR_USER, SVal);
632 static void DoExitMacro (void)
633 /* Exit a macro expansion */
635 if (!InMacExpansion ()) {
636 /* We aren't expanding a macro currently */
645 static void DoExport (void)
646 /* Export a symbol */
648 ExportImport (SymExport);
653 static void DoExportZP (void)
654 /* Export a zeropage symbol */
656 ExportImport (SymExportZP);
661 static void DoFarAddr (void)
662 /* Define far addresses (24 bit) */
665 EmitFarAddr (Expression ());
666 if (Tok != TOK_COMMA) {
676 static void DoFeature (void)
677 /* Switch the Feature option */
679 /* Allow a list of comma separated keywords */
682 /* We expect an identifier */
683 if (Tok != TOK_IDENT) {
684 ErrorSkip (ERR_IDENT_EXPECTED);
688 /* Make the string attribute lower case */
691 /* Set the feature and check for errors */
692 if (SetFeature (SVal) == FEAT_UNKNOWN) {
694 ErrorSkip (ERR_ILLEGAL_FEATURE);
697 /* Skip the keyword */
701 /* Allow more than one keyword */
702 if (Tok == TOK_COMMA) {
712 static void DoFileOpt (void)
713 /* Insert a file option */
717 /* The option type may be given as a keyword or as a number. */
718 if (Tok == TOK_IDENT) {
720 /* Option given as keyword */
721 static const char* Keys [] = {
722 "AUTHOR", "COMMENT", "COMPILER"
725 /* Map the option to a number */
726 OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
729 ErrorSkip (ERR_OPTION_KEY_EXPECTED);
733 /* Skip the keyword */
736 /* Must be followed by a comma */
739 /* We accept only string options for now */
740 if (Tok != TOK_STRCON) {
741 ErrorSkip (ERR_STRCON_EXPECTED);
745 /* Insert the option */
764 Internal ("Invalid OptNum: %l", OptNum);
773 /* Option given as number */
774 OptNum = ConstExpression ();
775 if (!IsByteRange (OptNum)) {
776 ErrorSkip (ERR_RANGE);
780 /* Must be followed by a comma */
783 /* We accept only string options for now */
784 if (Tok != TOK_STRCON) {
785 ErrorSkip (ERR_STRCON_EXPECTED);
789 /* Insert the option */
790 OptStr ((unsigned char) OptNum, SVal);
799 static void DoForceImport (void)
800 /* Do a forced import on a symbol */
802 ExportImport (SymImportForced);
807 static void DoGlobal (void)
808 /* Declare a global symbol */
810 ExportImport (SymGlobal);
815 static void DoGlobalZP (void)
816 /* Declare a global zeropage symbol */
818 ExportImport (SymGlobalZP);
823 static void DoI16 (void)
824 /* Switch the index registers to 16 bit mode (assembler only) */
826 if (GetCPU() != CPU_65816) {
827 Error (ERR_816_MODE_ONLY);
829 /* Immidiate mode has two extension bytes */
830 ExtBytes [AMI_IMM_INDEX] = 2;
836 static void DoI8 (void)
837 /* Switch the index registers to 16 bit mode (assembler only) */
839 if (GetCPU() != CPU_65816) {
840 Error (ERR_816_MODE_ONLY);
842 /* Immidiate mode has one extension byte */
843 ExtBytes [AMI_IMM_INDEX] = 1;
849 static void DoImport (void)
850 /* Import a symbol */
852 ExportImport (SymImport);
857 static void DoImportZP (void)
858 /* Import a zero page symbol */
860 ExportImport (SymImportZP);
865 static void DoIncBin (void)
866 /* Include a binary file */
868 char Name [sizeof (SVal)];
874 /* Name must follow */
875 if (Tok != TOK_STRCON) {
876 ErrorSkip (ERR_STRCON_EXPECTED);
882 /* A starting offset may follow */
883 if (Tok == TOK_COMMA) {
885 Start = ConstExpression ();
887 /* And a length may follow */
888 if (Tok == TOK_COMMA) {
890 Count = ConstExpression ();
895 /* Try to open the file */
896 F = fopen (Name, "rb");
899 /* Search for the file in the include directories. */
900 char* PathName = FindInclude (Name);
901 if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
902 /* Not found or cannot open, print an error and bail out */
903 ErrorSkip (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno));
906 /* Free the allocated memory */
909 /* If we had an error before, bail out now */
915 /* Get the size of the file */
916 fseek (F, 0, SEEK_END);
919 /* If a count was not given, calculate it now */
921 Count = Size - Start;
923 /* Nothing to read - flag this as a range error */
924 ErrorSkip (ERR_RANGE);
928 /* Count was given, check if it is valid */
929 if (Start + Count > Size) {
930 ErrorSkip (ERR_RANGE);
935 /* Seek to the start position */
936 fseek (F, Start, SEEK_SET);
938 /* Read chunks and insert them into the output */
941 unsigned char Buf [1024];
943 /* Calculate the number of bytes to read */
944 size_t BytesToRead = (Count > (long)sizeof(Buf))? sizeof(Buf) : (size_t) Count;
947 size_t BytesRead = fread (Buf, 1, BytesToRead, F);
948 if (BytesToRead != BytesRead) {
949 /* Some sort of error */
950 ErrorSkip (ERR_CANNOT_READ_INCLUDE, Name, strerror (errno));
954 /* Insert it into the output */
955 EmitData (Buf, BytesRead);
957 /* Keep the counters current */
962 /* Close the file, ignore errors since it's r/o */
968 static void DoInclude (void)
969 /* Include another file */
971 char Name [MAX_STR_LEN+1];
973 /* Name must follow */
974 if (Tok != TOK_STRCON) {
975 ErrorSkip (ERR_STRCON_EXPECTED);
985 static void DoInvalid (void)
986 /* Handle a token that is invalid here, since it should have been handled on
987 * a much lower level of the expression hierarchy. Getting this sort of token
988 * means that the lower level code has bugs.
989 * This function differs to DoUnexpected in that the latter may be triggered
990 * by the user by using keywords in the wrong location. DoUnexpected is not
991 * an error in the assembler itself, while DoInvalid is.
994 Internal ("Unexpected token: %s", Keyword);
999 static void DoLineCont (void)
1000 /* Switch the use of line continuations */
1002 SetBoolOption (&LineCont);
1007 static void DoList (void)
1008 /* Enable/disable the listing */
1010 /* Get the setting */
1012 SetBoolOption (&List);
1014 /* Manage the counter */
1024 static void DoListBytes (void)
1025 /* Set maximum number of bytes to list for one line */
1027 SetListBytes (IntArg (MIN_LIST_BYTES, MAX_LIST_BYTES));
1032 static void DoLocalChar (void)
1033 /* Define the character that starts local labels */
1035 if (Tok != TOK_CHARCON) {
1036 ErrorSkip (ERR_CHARCON_EXPECTED);
1038 if (IVal != '@' && IVal != '?') {
1039 Error (ERR_ILLEGAL_LOCALSTART);
1041 LocalStart = (char) IVal;
1049 static void DoMacPack (void)
1050 /* Insert a macro package */
1052 /* Macro package names */
1053 static const char* Keys [] = {
1060 /* We expect an identifier */
1061 if (Tok != TOK_IDENT) {
1062 ErrorSkip (ERR_IDENT_EXPECTED);
1066 /* Map the keyword to a number */
1067 Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
1070 ErrorSkip (ERR_ILLEGAL_MACPACK);
1074 /* Skip the package name */
1077 /* Insert the package */
1078 InsertMacPack (Package);
1083 static void DoMacro (void)
1084 /* Start a macro definition */
1086 MacDef (MAC_STYLE_CLASSIC);
1091 static void DoNull (void)
1092 /* Switch to the NULL segment */
1094 UseSeg (&NullSegDef);
1099 static void DoOrg (void)
1100 /* Start absolute code */
1102 long PC = ConstExpression ();
1103 if (PC < 0 || PC > 0xFFFFFF) {
1112 static void DoOut (void)
1113 /* Output a string */
1115 if (Tok != TOK_STRCON) {
1116 ErrorSkip (ERR_STRCON_EXPECTED);
1118 /* Output the string and be sure to flush the output to keep it in
1119 * sync with any error messages if the output is redirected to a file.
1121 printf ("%s\n", SVal);
1129 static void DoP02 (void)
1130 /* Switch to 6502 CPU */
1137 static void DoPC02 (void)
1138 /* Switch to 65C02 CPU */
1145 static void DoP816 (void)
1146 /* Switch to 65816 CPU */
1153 static void DoPageLength (void)
1154 /* Set the page length for the listing */
1156 PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
1161 static void DoPopSeg (void)
1162 /* Pop an old segment from the segment stack */
1166 /* Must have a segment on the stack */
1167 if (CollCount (&SegStack) == 0) {
1168 ErrorSkip (ERR_SEGSTACK_EMPTY);
1172 /* Pop the last element */
1173 Def = CollPop (&SegStack);
1175 /* Restore this segment */
1178 /* Delete the segment definition */
1184 static void DoProc (void)
1185 /* Start a new lexical scope */
1187 if (Tok == TOK_IDENT) {
1188 /* The new scope has a name */
1189 SymDef (SVal, CurrentPC (), IsZPSeg (), 1);
1197 static void DoPushSeg (void)
1198 /* Push the current segment onto the segment stack */
1200 /* Can only push a limited size of segments */
1201 if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) {
1202 ErrorSkip (ERR_SEGSTACK_OVERFLOW);
1206 /* Get the current segment and push it */
1207 CollAppend (&SegStack, DupSegDef (GetCurrentSeg ()));
1212 static void DoReloc (void)
1213 /* Enter relocatable mode */
1220 static void DoRepeat (void)
1221 /* Repeat some instruction block */
1228 static void DoRes (void)
1229 /* Reserve some number of storage bytes */
1234 Count = ConstExpression ();
1235 if (Count > 0xFFFF || Count < 0) {
1236 ErrorSkip (ERR_RANGE);
1239 if (Tok == TOK_COMMA) {
1241 Val = ConstExpression ();
1242 /* We need a byte value here */
1243 if (!IsByteRange (Val)) {
1244 ErrorSkip (ERR_RANGE);
1248 /* Emit constant values */
1250 Emit0 ((unsigned char) Val);
1254 /* Emit fill fragments */
1261 static void DoROData (void)
1262 /* Switch to the r/o data segment */
1264 UseSeg (&RODataSegDef);
1269 static void DoSegment (void)
1270 /* Switch to another segment */
1272 static const char* AttrTab [] = {
1273 "ZEROPAGE", "DIRECT",
1277 char Name [sizeof (SVal)];
1280 Def.Type = SEGTYPE_DEFAULT;
1282 if (Tok != TOK_STRCON) {
1283 ErrorSkip (ERR_STRCON_EXPECTED);
1286 /* Save the name of the segment and skip it */
1287 strcpy (Name, SVal);
1290 /* Check for an optional segment attribute */
1291 if (Tok == TOK_COMMA) {
1293 if (Tok != TOK_IDENT) {
1294 ErrorSkip (ERR_IDENT_EXPECTED);
1296 int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0]));
1302 Def.Type = SEGTYPE_ZP;
1307 Def.Type = SEGTYPE_ABS;
1313 Def.Type = SEGTYPE_FAR;
1317 Error (ERR_ILLEGAL_SEG_ATTR);
1323 /* Set the segment */
1330 static void DoSmart (void)
1331 /* Smart mode on/off */
1333 SetBoolOption (&SmartMode);
1338 static void DoSunPlus (void)
1339 /* Switch to the SUNPLUS CPU */
1341 SetCPU (CPU_SUNPLUS);
1346 static void DoUnexpected (void)
1347 /* Got an unexpected keyword */
1349 Error (ERR_UNEXPECTED, Keyword);
1355 static void DoWarning (void)
1358 if (Tok != TOK_STRCON) {
1359 ErrorSkip (ERR_STRCON_EXPECTED);
1361 Warning (WARN_USER, SVal);
1368 static void DoWord (void)
1372 EmitWord (Expression ());
1373 if (Tok != TOK_COMMA) {
1383 static void DoZeropage (void)
1384 /* Switch to the zeropage segment */
1386 UseSeg (&ZeropageSegDef);
1391 /*****************************************************************************/
1393 /*****************************************************************************/
1397 /* Control commands flags */
1399 ccNone = 0x0000, /* No special flags */
1400 ccKeepToken = 0x0001 /* Do not skip the current token */
1403 /* Control command table */
1405 unsigned Flags; /* Flags for this directive */
1406 void (*Handler) (void); /* Command handler */
1408 typedef struct CtrlDesc_ CtrlDesc;
1410 #define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
1411 static CtrlDesc CtrlCmdTab [] = {
1414 { ccNone, DoAddr }, /* .ADDR */
1415 { ccNone, DoAlign },
1416 { ccNone, DoASCIIZ },
1417 { ccNone, DoAutoImport },
1418 { ccNone, DoUnexpected }, /* .BLANK */
1422 { ccNone, DoCharMap },
1424 { ccNone, DoUnexpected, }, /* .CONCAT */
1425 { ccNone, DoConDes },
1426 { ccNone, DoUnexpected }, /* .CONST */
1427 { ccNone, DoConstructor },
1428 { ccNone, DoUnexpected }, /* .CPU */
1432 { ccNone, DoDebugInfo },
1433 { ccNone, DoDefine },
1434 { ccNone, DoUnexpected }, /* .DEFINED */
1435 { ccNone, DoDestructor },
1436 { ccNone, DoDWord },
1437 { ccKeepToken, DoConditionals }, /* .ELSE */
1438 { ccKeepToken, DoConditionals }, /* .ELSEIF */
1440 { ccKeepToken, DoConditionals }, /* .ENDIF */
1441 { ccNone, DoUnexpected }, /* .ENDMACRO */
1442 { ccNone, DoEndProc },
1443 { ccNone, DoUnexpected }, /* .ENDREPEAT */
1444 { ccNone, DoError },
1445 { ccNone, DoExitMacro },
1446 { ccNone, DoExport },
1447 { ccNone, DoExportZP },
1448 { ccNone, DoFarAddr },
1449 { ccNone, DoFeature },
1450 { ccNone, DoFileOpt },
1451 { ccNone, DoForceImport },
1452 { ccNone, DoUnexpected }, /* .FORCEWORD */
1453 { ccNone, DoGlobal },
1454 { ccNone, DoGlobalZP },
1457 { ccKeepToken, DoConditionals }, /* .IF */
1458 { ccKeepToken, DoConditionals }, /* .IFBLANK */
1459 { ccKeepToken, DoConditionals }, /* .IFCONST */
1460 { ccKeepToken, DoConditionals }, /* .IFDEF */
1461 { ccKeepToken, DoConditionals }, /* .IFNBLANK */
1462 { ccKeepToken, DoConditionals }, /* .IFNCONST */
1463 { ccKeepToken, DoConditionals }, /* .IFNDEF */
1464 { ccKeepToken, DoConditionals }, /* .IFNREF */
1465 { ccKeepToken, DoConditionals }, /* .IFP02 */
1466 { ccKeepToken, DoConditionals }, /* .IFP816 */
1467 { ccKeepToken, DoConditionals }, /* .IFPC02 */
1468 { ccKeepToken, DoConditionals }, /* .IFREF */
1469 { ccNone, DoImport },
1470 { ccNone, DoImportZP },
1471 { ccNone, DoIncBin },
1472 { ccNone, DoInclude },
1473 { ccNone, DoInvalid }, /* .LEFT */
1474 { ccNone, DoLineCont },
1476 { ccNone, DoListBytes },
1477 { ccNone, DoUnexpected }, /* .LOCAL */
1478 { ccNone, DoLocalChar },
1479 { ccNone, DoMacPack },
1480 { ccNone, DoMacro },
1481 { ccNone, DoUnexpected }, /* .MATCH */
1482 { ccNone, DoInvalid }, /* .MID */
1488 { ccNone, DoPageLength },
1489 { ccNone, DoUnexpected }, /* .PARAMCOUNT */
1491 { ccNone, DoPopSeg },
1493 { ccNone, DoPushSeg },
1494 { ccNone, DoUnexpected }, /* .REFERENCED */
1495 { ccNone, DoReloc },
1496 { ccNone, DoRepeat },
1498 { ccNone, DoInvalid }, /* .RIGHT */
1499 { ccNone, DoROData },
1500 { ccNone, DoSegment },
1501 { ccNone, DoSmart },
1502 { ccNone, DoUnexpected }, /* .STRAT */
1503 { ccNone, DoUnexpected }, /* .STRING */
1504 { ccNone, DoUnexpected }, /* .STRLEN */
1505 { ccNone, DoSunPlus },
1506 { ccNone, DoUnexpected }, /* .TCOUNT */
1507 { ccNone, DoUnexpected }, /* .TIME */
1508 { ccNone, DoWarning },
1510 { ccNone, DoUnexpected }, /* .XMATCH */
1511 { ccNone, DoZeropage },
1516 /*****************************************************************************/
1518 /*****************************************************************************/
1522 int TokIsPseudo (unsigned Tok)
1523 /* Return true if the given token is a pseudo instruction token */
1525 return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO);
1530 void HandlePseudo (void)
1531 /* Handle a pseudo instruction */
1535 /* Calculate the index into the table */
1536 unsigned Index = Tok - TOK_FIRSTPSEUDO;
1539 if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
1540 Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
1541 PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
1543 CHECK (Index < PSEUDO_COUNT);
1545 /* Get the pseudo intruction descriptor */
1546 D = &CtrlCmdTab [Index];
1548 /* Remember the instruction, then skip it if needed */
1549 if ((D->Flags & ccKeepToken) == 0) {
1550 strcpy (Keyword+1, SVal);
1554 /* Call the handler */
1560 void SegStackCheck (void)
1561 /* Check if the segment stack is empty at end of assembly */
1563 if (CollCount (&SegStack) != 0) {
1564 Error (ERR_SEGSTACK_NOT_EMPTY);