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 /*****************************************************************************/
73 /*****************************************************************************/
75 /*****************************************************************************/
79 /* Keyword we're about to handle */
80 static char Keyword [sizeof (SVal)+1] = ".";
83 #define MAX_PUSHED_SEGMENTS 16
84 static Collection SegStack = STATIC_COLLECTION_INITIALIZER;
88 /*****************************************************************************/
90 /*****************************************************************************/
94 static void DoUnexpected (void);
95 /* Got an unexpected keyword */
97 static void DoInvalid (void);
98 /* Handle a token that is invalid here, since it should have been handled on
99 * a much lower level of the expression hierarchy. Getting this sort of token
100 * means that the lower level code has bugs.
101 * This function differs to DoUnexpected in that the latter may be triggered
102 * by the user by using keywords in the wrong location. DoUnexpected is not
103 * an error in the assembler itself, while DoInvalid is.
108 /*****************************************************************************/
109 /* Helper functions */
110 /*****************************************************************************/
114 static void SetBoolOption (unsigned char* Flag)
115 /* Read a on/off/+/- option and set flag accordingly */
117 static const char* Keys[] = {
122 if (Tok == TOK_PLUS) {
125 } else if (Tok == TOK_MINUS) {
128 } else if (Tok == TOK_IDENT) {
129 /* Map the keyword to a number */
130 switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
131 case 0: *Flag = 0; NextTok (); break;
132 case 1: *Flag = 1; NextTok (); break;
133 default: ErrorSkip (ERR_ONOFF_EXPECTED); break;
135 } else if (TokIsSep (Tok)) {
136 /* Without anything assume switch on */
139 ErrorSkip (ERR_ONOFF_EXPECTED);
145 static void ExportImport (void (*SymFunc) (const char*))
146 /* Export or import symbols */
149 if (Tok != TOK_IDENT) {
150 ErrorSkip (ERR_IDENT_EXPECTED);
155 if (Tok == TOK_COMMA) {
165 static long IntArg (long Min, long Max)
166 /* Read an integer argument and check a range. Accept the token "unlimited"
167 * and return -1 in this case.
170 if (Tok == TOK_IDENT && strcmp (SVal, "unlimited") == 0) {
174 long Val = ConstExpression ();
175 if (Val < Min || Val > Max) {
185 static void ConDes (const char* Name, unsigned Type)
186 /* Parse remaining line for constructor/destructor of the remaining type */
190 /* Optional constructor priority */
191 if (Tok == TOK_COMMA) {
192 /* Priority value follows */
194 Prio = ConstExpression ();
195 if (Prio < CD_PRIO_MIN || Prio > CD_PRIO_MAX) {
196 /* Value out of range */
201 /* Use the default priority value */
205 /* Define the symbol */
206 SymConDes (Name, Type, (unsigned) Prio);
211 /*****************************************************************************/
212 /* Handler functions */
213 /*****************************************************************************/
217 static void DoA16 (void)
218 /* Switch the accu to 16 bit mode (assembler only) */
220 if (GetCPU() != CPU_65816) {
221 Error (ERR_816_MODE_ONLY);
223 /* Immidiate mode has two extension bytes */
224 ExtBytes [AMI_IMM_ACCU] = 2;
230 static void DoA8 (void)
231 /* Switch the accu to 8 bit mode (assembler only) */
233 if (GetCPU() != CPU_65816) {
234 Error (ERR_816_MODE_ONLY);
236 /* Immidiate mode has one extension byte */
237 ExtBytes [AMI_IMM_ACCU] = 1;
243 static void DoAddr (void)
244 /* Define addresses */
247 if (GetCPU() == CPU_65816) {
248 EmitWord (ForceWordExpr (Expression ()));
250 /* Do a range check */
251 EmitWord (Expression ());
253 if (Tok != TOK_COMMA) {
263 static void DoAlign (void)
264 /* Align the PC to some boundary */
270 /* Read the alignment value */
271 Align = ConstExpression ();
272 if (Align <= 0 || Align > 0x10000) {
273 ErrorSkip (ERR_RANGE);
277 /* Optional value follows */
278 if (Tok == TOK_COMMA) {
280 Val = ConstExpression ();
281 /* We need a byte value here */
282 if (!IsByteRange (Val)) {
283 ErrorSkip (ERR_RANGE);
290 /* Check if the alignment is a power of two */
291 Bit = BitFind (Align);
292 if (Align != (0x01L << Bit)) {
295 SegAlign (Bit, (int) Val);
301 static void DoASCIIZ (void)
302 /* Define text with a zero terminator */
307 /* Must have a string constant */
308 if (Tok != TOK_STRCON) {
309 ErrorSkip (ERR_STRCON_EXPECTED);
313 /* Get the length of the string constant */
316 /* Translate into target charset and emit */
317 TgtTranslateBuf (SVal, Len);
318 EmitData ((unsigned char*) SVal, Len);
320 if (Tok == TOK_COMMA) {
331 static void DoAssert (void)
332 /* Add an assertion */
334 static const char* ActionTab [] = {
342 /* First we have the expression that has to evaluated */
343 ExprNode* Expr = Expression ();
347 if (Tok != TOK_IDENT) {
348 ErrorSkip (ERR_IDENT_EXPECTED);
351 Action = GetSubKey (ActionTab, sizeof (ActionTab) / sizeof (ActionTab[0]));
364 Error (ERR_ILLEGAL_SEG_ATTR);
369 /* Read the message */
370 if (Tok != TOK_STRCON) {
371 ErrorSkip (ERR_STRCON_EXPECTED);
373 AddAssertion (Expr, Action, GetStringId (SVal));
380 static void DoAutoImport (void)
381 /* Mark unresolved symbols as imported */
383 SetBoolOption (&AutoImport);
388 static void DoBss (void)
389 /* Switch to the BSS segment */
396 static void DoByte (void)
400 if (Tok == TOK_STRCON) {
401 /* A string, translate into target charset and emit */
402 unsigned Len = strlen (SVal);
403 TgtTranslateBuf (SVal, Len);
404 EmitData ((unsigned char*) SVal, Len);
407 EmitByte (Expression ());
409 if (Tok != TOK_COMMA) {
413 /* Do smart handling of dangling comma */
414 if (Tok == TOK_SEP) {
415 Error (ERR_UNEXPECTED_EOL);
424 static void DoCase (void)
425 /* Switch the IgnoreCase option */
427 SetBoolOption (&IgnoreCase);
428 IgnoreCase = !IgnoreCase;
433 static void DoCharMap (void)
434 /* Allow custome character mappings */
439 /* Read the index as numerical value */
440 Index = ConstExpression ();
441 if (Index < 1 || Index > 255) {
442 /* Value out of range */
443 ErrorSkip (ERR_RANGE);
450 /* Read the character code */
451 Code = ConstExpression ();
452 if (Code < 1 || Code > 255) {
453 /* Value out of range */
454 ErrorSkip (ERR_RANGE);
458 /* Set the character translation */
459 TgtTranslateSet ((unsigned) Index, (unsigned char) Code);
464 static void DoCode (void)
465 /* Switch to the code segment */
467 UseSeg (&CodeSegDef);
472 static void DoConDes (void)
473 /* Export a symbol as constructor/destructor */
475 static const char* Keys[] = {
479 char Name [sizeof (SVal)];
482 /* Symbol name follows */
483 if (Tok != TOK_IDENT) {
484 ErrorSkip (ERR_IDENT_EXPECTED);
490 /* Type follows. May be encoded as identifier or numerical */
492 if (Tok == TOK_IDENT) {
494 /* Map the following keyword to a number, then skip it */
495 Type = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
498 /* Check if we got a valid keyword */
507 /* Read the type as numerical value */
508 Type = ConstExpression ();
509 if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) {
510 /* Value out of range */
517 /* Parse the remainder of the line and export the symbol */
518 ConDes (Name, (unsigned) Type);
523 static void DoConstructor (void)
524 /* Export a symbol as constructor */
526 char Name [sizeof (SVal)];
528 /* Symbol name follows */
529 if (Tok != TOK_IDENT) {
530 ErrorSkip (ERR_IDENT_EXPECTED);
536 /* Parse the remainder of the line and export the symbol */
537 ConDes (Name, CD_TYPE_CON);
542 static void DoData (void)
543 /* Switch to the data segment */
545 UseSeg (&DataSegDef);
550 static void DoDbg (void)
551 /* Add debug information from high level code */
553 static const char* Keys[] = {
561 /* We expect a subkey */
562 if (Tok != TOK_IDENT) {
563 ErrorSkip (ERR_IDENT_EXPECTED);
567 /* Map the following keyword to a number */
568 Key = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
570 /* Skip the subkey */
573 /* Check the key and dispatch to a handler */
575 case 0: DbgInfoFile (); break;
576 case 1: DbgInfoLine (); break;
577 case 2: DbgInfoSym (); break;
578 default: ErrorSkip (ERR_SYNTAX); break;
584 static void DoDByt (void)
585 /* Output double bytes */
588 EmitWord (SwapExpr (Expression ()));
589 if (Tok != TOK_COMMA) {
599 static void DoDebugInfo (void)
600 /* Switch debug info on or off */
602 SetBoolOption (&DbgSyms);
607 static void DoDefine (void)
608 /* Define a one line macro */
610 MacDef (MAC_STYLE_DEFINE);
615 static void DoDestructor (void)
616 /* Export a symbol as destructor */
618 char Name [sizeof (SVal)];
620 /* Symbol name follows */
621 if (Tok != TOK_IDENT) {
622 ErrorSkip (ERR_IDENT_EXPECTED);
628 /* Parse the remainder of the line and export the symbol */
629 ConDes (Name, CD_TYPE_DES);
634 static void DoDWord (void)
638 EmitDWord (Expression ());
639 if (Tok != TOK_COMMA) {
649 static void DoEnd (void)
650 /* End of assembly */
658 static void DoEndProc (void)
659 /* Leave a lexical level */
661 if (!SymIsLocalLevel ()) {
663 ErrorSkip (ERR_NO_OPEN_PROC);
671 static void DoError (void)
674 if (Tok != TOK_STRCON) {
675 ErrorSkip (ERR_STRCON_EXPECTED);
677 Error (ERR_USER, SVal);
684 static void DoExitMacro (void)
685 /* Exit a macro expansion */
687 if (!InMacExpansion ()) {
688 /* We aren't expanding a macro currently */
697 static void DoExport (void)
698 /* Export a symbol */
700 ExportImport (SymExport);
705 static void DoExportZP (void)
706 /* Export a zeropage symbol */
708 ExportImport (SymExportZP);
713 static void DoFarAddr (void)
714 /* Define far addresses (24 bit) */
717 EmitFarAddr (Expression ());
718 if (Tok != TOK_COMMA) {
728 static void DoFeature (void)
729 /* Switch the Feature option */
731 /* Allow a list of comma separated keywords */
734 /* We expect an identifier */
735 if (Tok != TOK_IDENT) {
736 ErrorSkip (ERR_IDENT_EXPECTED);
740 /* Make the string attribute lower case */
743 /* Set the feature and check for errors */
744 if (SetFeature (SVal) == FEAT_UNKNOWN) {
746 ErrorSkip (ERR_ILLEGAL_FEATURE);
749 /* Skip the keyword */
753 /* Allow more than one keyword */
754 if (Tok == TOK_COMMA) {
764 static void DoFileOpt (void)
765 /* Insert a file option */
769 /* The option type may be given as a keyword or as a number. */
770 if (Tok == TOK_IDENT) {
772 /* Option given as keyword */
773 static const char* Keys [] = {
774 "AUTHOR", "COMMENT", "COMPILER"
777 /* Map the option to a number */
778 OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
781 ErrorSkip (ERR_OPTION_KEY_EXPECTED);
785 /* Skip the keyword */
788 /* Must be followed by a comma */
791 /* We accept only string options for now */
792 if (Tok != TOK_STRCON) {
793 ErrorSkip (ERR_STRCON_EXPECTED);
797 /* Insert the option */
816 Internal ("Invalid OptNum: %l", OptNum);
825 /* Option given as number */
826 OptNum = ConstExpression ();
827 if (!IsByteRange (OptNum)) {
828 ErrorSkip (ERR_RANGE);
832 /* Must be followed by a comma */
835 /* We accept only string options for now */
836 if (Tok != TOK_STRCON) {
837 ErrorSkip (ERR_STRCON_EXPECTED);
841 /* Insert the option */
842 OptStr ((unsigned char) OptNum, SVal);
851 static void DoForceImport (void)
852 /* Do a forced import on a symbol */
854 ExportImport (SymImportForced);
859 static void DoGlobal (void)
860 /* Declare a global symbol */
862 ExportImport (SymGlobal);
867 static void DoGlobalZP (void)
868 /* Declare a global zeropage symbol */
870 ExportImport (SymGlobalZP);
875 static void DoI16 (void)
876 /* Switch the index registers to 16 bit mode (assembler only) */
878 if (GetCPU() != CPU_65816) {
879 Error (ERR_816_MODE_ONLY);
881 /* Immidiate mode has two extension bytes */
882 ExtBytes [AMI_IMM_INDEX] = 2;
888 static void DoI8 (void)
889 /* Switch the index registers to 16 bit mode (assembler only) */
891 if (GetCPU() != CPU_65816) {
892 Error (ERR_816_MODE_ONLY);
894 /* Immidiate mode has one extension byte */
895 ExtBytes [AMI_IMM_INDEX] = 1;
901 static void DoImport (void)
902 /* Import a symbol */
904 ExportImport (SymImport);
909 static void DoImportZP (void)
910 /* Import a zero page symbol */
912 ExportImport (SymImportZP);
917 static void DoIncBin (void)
918 /* Include a binary file */
920 char Name [sizeof (SVal)];
926 /* Name must follow */
927 if (Tok != TOK_STRCON) {
928 ErrorSkip (ERR_STRCON_EXPECTED);
934 /* A starting offset may follow */
935 if (Tok == TOK_COMMA) {
937 Start = ConstExpression ();
939 /* And a length may follow */
940 if (Tok == TOK_COMMA) {
942 Count = ConstExpression ();
947 /* Try to open the file */
948 F = fopen (Name, "rb");
951 /* Search for the file in the include directories. */
952 char* PathName = FindInclude (Name);
953 if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
954 /* Not found or cannot open, print an error and bail out */
955 ErrorSkip (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno));
958 /* Free the allocated memory */
961 /* If we had an error before, bail out now */
967 /* Get the size of the file */
968 fseek (F, 0, SEEK_END);
971 /* If a count was not given, calculate it now */
973 Count = Size - Start;
975 /* Nothing to read - flag this as a range error */
976 ErrorSkip (ERR_RANGE);
980 /* Count was given, check if it is valid */
981 if (Start + Count > Size) {
982 ErrorSkip (ERR_RANGE);
987 /* Seek to the start position */
988 fseek (F, Start, SEEK_SET);
990 /* Read chunks and insert them into the output */
993 unsigned char Buf [1024];
995 /* Calculate the number of bytes to read */
996 size_t BytesToRead = (Count > (long)sizeof(Buf))? sizeof(Buf) : (size_t) Count;
999 size_t BytesRead = fread (Buf, 1, BytesToRead, F);
1000 if (BytesToRead != BytesRead) {
1001 /* Some sort of error */
1002 ErrorSkip (ERR_CANNOT_READ_INCLUDE, Name, strerror (errno));
1006 /* Insert it into the output */
1007 EmitData (Buf, BytesRead);
1009 /* Keep the counters current */
1014 /* Close the file, ignore errors since it's r/o */
1020 static void DoInclude (void)
1021 /* Include another file */
1023 char Name [MAX_STR_LEN+1];
1025 /* Name must follow */
1026 if (Tok != TOK_STRCON) {
1027 ErrorSkip (ERR_STRCON_EXPECTED);
1029 strcpy (Name, SVal);
1031 NewInputFile (Name);
1037 static void DoInvalid (void)
1038 /* Handle a token that is invalid here, since it should have been handled on
1039 * a much lower level of the expression hierarchy. Getting this sort of token
1040 * means that the lower level code has bugs.
1041 * This function differs to DoUnexpected in that the latter may be triggered
1042 * by the user by using keywords in the wrong location. DoUnexpected is not
1043 * an error in the assembler itself, while DoInvalid is.
1046 Internal ("Unexpected token: %s", Keyword);
1051 static void DoLineCont (void)
1052 /* Switch the use of line continuations */
1054 SetBoolOption (&LineCont);
1059 static void DoList (void)
1060 /* Enable/disable the listing */
1062 /* Get the setting */
1064 SetBoolOption (&List);
1066 /* Manage the counter */
1076 static void DoListBytes (void)
1077 /* Set maximum number of bytes to list for one line */
1079 SetListBytes (IntArg (MIN_LIST_BYTES, MAX_LIST_BYTES));
1084 static void DoLocalChar (void)
1085 /* Define the character that starts local labels */
1087 if (Tok != TOK_CHARCON) {
1088 ErrorSkip (ERR_CHARCON_EXPECTED);
1090 if (IVal != '@' && IVal != '?') {
1091 Error (ERR_ILLEGAL_LOCALSTART);
1093 LocalStart = (char) IVal;
1101 static void DoMacPack (void)
1102 /* Insert a macro package */
1104 /* Macro package names */
1105 static const char* Keys [] = {
1113 /* We expect an identifier */
1114 if (Tok != TOK_IDENT) {
1115 ErrorSkip (ERR_IDENT_EXPECTED);
1119 /* Map the keyword to a number */
1120 Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
1123 ErrorSkip (ERR_ILLEGAL_MACPACK);
1127 /* Skip the package name */
1130 /* Insert the package */
1131 InsertMacPack (Package);
1136 static void DoMacro (void)
1137 /* Start a macro definition */
1139 MacDef (MAC_STYLE_CLASSIC);
1144 static void DoNull (void)
1145 /* Switch to the NULL segment */
1147 UseSeg (&NullSegDef);
1152 static void DoOrg (void)
1153 /* Start absolute code */
1155 long PC = ConstExpression ();
1156 if (PC < 0 || PC > 0xFFFFFF) {
1165 static void DoOut (void)
1166 /* Output a string */
1168 if (Tok != TOK_STRCON) {
1169 ErrorSkip (ERR_STRCON_EXPECTED);
1171 /* Output the string and be sure to flush the output to keep it in
1172 * sync with any error messages if the output is redirected to a file.
1174 printf ("%s\n", SVal);
1182 static void DoP02 (void)
1183 /* Switch to 6502 CPU */
1190 static void DoPC02 (void)
1191 /* Switch to 65C02 CPU */
1198 static void DoP816 (void)
1199 /* Switch to 65816 CPU */
1206 static void DoPageLength (void)
1207 /* Set the page length for the listing */
1209 PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
1214 static void DoPopSeg (void)
1215 /* Pop an old segment from the segment stack */
1219 /* Must have a segment on the stack */
1220 if (CollCount (&SegStack) == 0) {
1221 ErrorSkip (ERR_SEGSTACK_EMPTY);
1225 /* Pop the last element */
1226 Def = CollPop (&SegStack);
1228 /* Restore this segment */
1231 /* Delete the segment definition */
1237 static void DoProc (void)
1238 /* Start a new lexical scope */
1240 if (Tok == TOK_IDENT) {
1241 /* The new scope has a name */
1242 SymDef (SVal, CurrentPC (), IsZPSeg (), 1);
1250 static void DoPushSeg (void)
1251 /* Push the current segment onto the segment stack */
1253 /* Can only push a limited size of segments */
1254 if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) {
1255 ErrorSkip (ERR_SEGSTACK_OVERFLOW);
1259 /* Get the current segment and push it */
1260 CollAppend (&SegStack, DupSegDef (GetCurrentSeg ()));
1265 static void DoReloc (void)
1266 /* Enter relocatable mode */
1273 static void DoRepeat (void)
1274 /* Repeat some instruction block */
1281 static void DoRes (void)
1282 /* Reserve some number of storage bytes */
1287 Count = ConstExpression ();
1288 if (Count > 0xFFFF || Count < 0) {
1289 ErrorSkip (ERR_RANGE);
1292 if (Tok == TOK_COMMA) {
1294 Val = ConstExpression ();
1295 /* We need a byte value here */
1296 if (!IsByteRange (Val)) {
1297 ErrorSkip (ERR_RANGE);
1301 /* Emit constant values */
1303 Emit0 ((unsigned char) Val);
1307 /* Emit fill fragments */
1314 static void DoROData (void)
1315 /* Switch to the r/o data segment */
1317 UseSeg (&RODataSegDef);
1322 static void DoSegment (void)
1323 /* Switch to another segment */
1325 static const char* AttrTab [] = {
1326 "ZEROPAGE", "DIRECT",
1330 char Name [sizeof (SVal)];
1333 Def.Type = SEGTYPE_DEFAULT;
1335 if (Tok != TOK_STRCON) {
1336 ErrorSkip (ERR_STRCON_EXPECTED);
1339 /* Save the name of the segment and skip it */
1340 strcpy (Name, SVal);
1343 /* Check for an optional segment attribute */
1344 if (Tok == TOK_COMMA) {
1346 if (Tok != TOK_IDENT) {
1347 ErrorSkip (ERR_IDENT_EXPECTED);
1349 int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0]));
1355 Def.Type = SEGTYPE_ZP;
1360 Def.Type = SEGTYPE_ABS;
1366 Def.Type = SEGTYPE_FAR;
1370 Error (ERR_ILLEGAL_SEG_ATTR);
1376 /* Set the segment */
1383 static void DoSmart (void)
1384 /* Smart mode on/off */
1386 SetBoolOption (&SmartMode);
1391 static void DoSunPlus (void)
1392 /* Switch to the SUNPLUS CPU */
1394 SetCPU (CPU_SUNPLUS);
1399 static void DoUnexpected (void)
1400 /* Got an unexpected keyword */
1402 Error (ERR_UNEXPECTED, Keyword);
1408 static void DoWarning (void)
1411 if (Tok != TOK_STRCON) {
1412 ErrorSkip (ERR_STRCON_EXPECTED);
1414 Warning (WARN_USER, SVal);
1421 static void DoWord (void)
1425 EmitWord (Expression ());
1426 if (Tok != TOK_COMMA) {
1436 static void DoZeropage (void)
1437 /* Switch to the zeropage segment */
1439 UseSeg (&ZeropageSegDef);
1444 /*****************************************************************************/
1446 /*****************************************************************************/
1450 /* Control commands flags */
1452 ccNone = 0x0000, /* No special flags */
1453 ccKeepToken = 0x0001 /* Do not skip the current token */
1456 /* Control command table */
1457 typedef struct CtrlDesc CtrlDesc;
1459 unsigned Flags; /* Flags for this directive */
1460 void (*Handler) (void); /* Command handler */
1463 #define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
1464 static CtrlDesc CtrlCmdTab [] = {
1467 { ccNone, DoAddr }, /* .ADDR */
1468 { ccNone, DoAlign },
1469 { ccNone, DoASCIIZ },
1470 { ccNone, DoAssert },
1471 { ccNone, DoAutoImport },
1472 { ccNone, DoUnexpected }, /* .BLANK */
1476 { ccNone, DoCharMap },
1478 { ccNone, DoUnexpected, }, /* .CONCAT */
1479 { ccNone, DoConDes },
1480 { ccNone, DoUnexpected }, /* .CONST */
1481 { ccNone, DoConstructor },
1482 { ccNone, DoUnexpected }, /* .CPU */
1486 { ccNone, DoDebugInfo },
1487 { ccNone, DoDefine },
1488 { ccNone, DoUnexpected }, /* .DEFINED */
1489 { ccNone, DoDestructor },
1490 { ccNone, DoDWord },
1491 { ccKeepToken, DoConditionals }, /* .ELSE */
1492 { ccKeepToken, DoConditionals }, /* .ELSEIF */
1493 { ccKeepToken, DoEnd },
1494 { ccKeepToken, DoConditionals }, /* .ENDIF */
1495 { ccNone, DoUnexpected }, /* .ENDMACRO */
1496 { ccNone, DoEndProc },
1497 { ccNone, DoUnexpected }, /* .ENDREPEAT */
1498 { ccNone, DoError },
1499 { ccNone, DoExitMacro },
1500 { ccNone, DoExport },
1501 { ccNone, DoExportZP },
1502 { ccNone, DoFarAddr },
1503 { ccNone, DoFeature },
1504 { ccNone, DoFileOpt },
1505 { ccNone, DoForceImport },
1506 { ccNone, DoUnexpected }, /* .FORCEWORD */
1507 { ccNone, DoGlobal },
1508 { ccNone, DoGlobalZP },
1511 { ccKeepToken, DoConditionals }, /* .IF */
1512 { ccKeepToken, DoConditionals }, /* .IFBLANK */
1513 { ccKeepToken, DoConditionals }, /* .IFCONST */
1514 { ccKeepToken, DoConditionals }, /* .IFDEF */
1515 { ccKeepToken, DoConditionals }, /* .IFNBLANK */
1516 { ccKeepToken, DoConditionals }, /* .IFNCONST */
1517 { ccKeepToken, DoConditionals }, /* .IFNDEF */
1518 { ccKeepToken, DoConditionals }, /* .IFNREF */
1519 { ccKeepToken, DoConditionals }, /* .IFP02 */
1520 { ccKeepToken, DoConditionals }, /* .IFP816 */
1521 { ccKeepToken, DoConditionals }, /* .IFPC02 */
1522 { ccKeepToken, DoConditionals }, /* .IFREF */
1523 { ccNone, DoImport },
1524 { ccNone, DoImportZP },
1525 { ccNone, DoIncBin },
1526 { ccNone, DoInclude },
1527 { ccNone, DoInvalid }, /* .LEFT */
1528 { ccNone, DoLineCont },
1530 { ccNone, DoListBytes },
1531 { ccNone, DoUnexpected }, /* .LOCAL */
1532 { ccNone, DoLocalChar },
1533 { ccNone, DoMacPack },
1534 { ccNone, DoMacro },
1535 { ccNone, DoUnexpected }, /* .MATCH */
1536 { ccNone, DoInvalid }, /* .MID */
1542 { ccNone, DoPageLength },
1543 { ccNone, DoUnexpected }, /* .PARAMCOUNT */
1545 { ccNone, DoPopSeg },
1547 { ccNone, DoPushSeg },
1548 { ccNone, DoUnexpected }, /* .REFERENCED */
1549 { ccNone, DoReloc },
1550 { ccNone, DoRepeat },
1552 { ccNone, DoInvalid }, /* .RIGHT */
1553 { ccNone, DoROData },
1554 { ccNone, DoSegment },
1555 { ccNone, DoSmart },
1556 { ccNone, DoUnexpected }, /* .STRAT */
1557 { ccNone, DoUnexpected }, /* .STRING */
1558 { ccNone, DoUnexpected }, /* .STRLEN */
1559 { ccNone, DoSunPlus },
1560 { ccNone, DoUnexpected }, /* .TCOUNT */
1561 { ccNone, DoUnexpected }, /* .TIME */
1562 { ccNone, DoWarning },
1564 { ccNone, DoUnexpected }, /* .XMATCH */
1565 { ccNone, DoZeropage },
1570 /*****************************************************************************/
1572 /*****************************************************************************/
1576 int TokIsPseudo (unsigned Tok)
1577 /* Return true if the given token is a pseudo instruction token */
1579 return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO);
1584 void HandlePseudo (void)
1585 /* Handle a pseudo instruction */
1589 /* Calculate the index into the table */
1590 unsigned Index = Tok - TOK_FIRSTPSEUDO;
1593 if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
1594 Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
1595 PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
1597 CHECK (Index < PSEUDO_COUNT);
1599 /* Get the pseudo intruction descriptor */
1600 D = &CtrlCmdTab [Index];
1602 /* Remember the instruction, then skip it if needed */
1603 if ((D->Flags & ccKeepToken) == 0) {
1604 strcpy (Keyword+1, SVal);
1608 /* Call the handler */
1614 void SegStackCheck (void)
1615 /* Check if the segment stack is empty at end of assembly */
1617 if (CollCount (&SegStack) != 0) {
1618 Error (ERR_SEGSTACK_NOT_EMPTY);