1 /*****************************************************************************/
5 /* Pseudo instructions for the ca65 macroassembler */
9 /* (C) 1998-2002 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
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 /*****************************************************************************/
69 /*****************************************************************************/
71 /*****************************************************************************/
75 /* Keyword we're about to handle */
76 static char Keyword [sizeof (SVal)+1] = ".";
79 #define MAX_PUSHED_SEGMENTS 16
80 static Collection SegStack = STATIC_COLLECTION_INITIALIZER;
84 /*****************************************************************************/
86 /*****************************************************************************/
90 static void DoUnexpected (void);
91 /* Got an unexpected keyword */
93 static void DoInvalid (void);
94 /* Handle a token that is invalid here, since it should have been handled on
95 * a much lower level of the expression hierarchy. Getting this sort of token
96 * means that the lower level code has bugs.
97 * This function differs to DoUnexpected in that the latter may be triggered
98 * by the user by using keywords in the wrong location. DoUnexpected is not
99 * an error in the assembler itself, while DoInvalid is.
104 /*****************************************************************************/
105 /* Helper functions */
106 /*****************************************************************************/
110 static void SetBoolOption (unsigned char* Flag)
111 /* Read a on/off/+/- option and set flag accordingly */
113 static const char* Keys[] = {
118 if (Tok == TOK_PLUS) {
121 } else if (Tok == TOK_MINUS) {
124 } else if (Tok == TOK_IDENT) {
125 /* Map the keyword to a number */
126 switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
127 case 0: *Flag = 0; NextTok (); break;
128 case 1: *Flag = 1; NextTok (); break;
129 default: ErrorSkip (ERR_ONOFF_EXPECTED); break;
131 } else if (Tok == TOK_SEP || Tok == TOK_EOF) {
132 /* Without anything assume switch on */
135 ErrorSkip (ERR_ONOFF_EXPECTED);
141 static void ExportImport (void (*SymFunc) (const char*, int), int ZP)
142 /* Export or import symbols */
145 if (Tok != TOK_IDENT) {
146 ErrorSkip (ERR_IDENT_EXPECTED);
151 if (Tok == TOK_COMMA) {
161 static long IntArg (long Min, long Max)
162 /* Read an integer argument and check a range. Accept the token "unlimited"
163 * and return -1 in this case.
166 if (Tok == TOK_IDENT && strcmp (SVal, "unlimited") == 0) {
170 long Val = ConstExpression ();
171 if (Val < Min || Val > Max) {
181 static void ConDes (const char* Name, unsigned Type)
182 /* Parse remaining line for constructor/destructor of the remaining type */
186 /* Optional constructor priority */
187 if (Tok == TOK_COMMA) {
188 /* Priority value follows */
190 Prio = ConstExpression ();
191 if (Prio < CD_PRIO_MIN || Prio > CD_PRIO_MAX) {
192 /* Value out of range */
197 /* Use the default priority value */
201 /* Define the symbol */
202 SymConDes (Name, Type, (unsigned) Prio);
207 /*****************************************************************************/
208 /* Handler functions */
209 /*****************************************************************************/
213 static void DoA16 (void)
214 /* Switch the accu to 16 bit mode (assembler only) */
216 if (GetCPU() != CPU_65816) {
217 Error (ERR_816_MODE_ONLY);
219 /* Immidiate mode has two extension bytes */
220 ExtBytes [AMI_IMM_ACCU] = 2;
226 static void DoA8 (void)
227 /* Switch the accu to 8 bit mode (assembler only) */
229 if (GetCPU() != CPU_65816) {
230 Error (ERR_816_MODE_ONLY);
232 /* Immidiate mode has one extension byte */
233 ExtBytes [AMI_IMM_ACCU] = 1;
239 static void DoAddr (void)
240 /* Define addresses */
243 if (GetCPU() == CPU_65816) {
244 EmitWord (ForceWordExpr (Expression ()));
246 /* Do a range check */
247 EmitWord (Expression ());
249 if (Tok != TOK_COMMA) {
259 static void DoAlign (void)
260 /* Align the PC to some boundary */
266 /* Read the alignment value */
267 Align = ConstExpression ();
268 if (Align <= 0 || Align > 0x10000) {
269 ErrorSkip (ERR_RANGE);
273 /* Optional value follows */
274 if (Tok == TOK_COMMA) {
276 Val = ConstExpression ();
277 /* We need a byte value here */
278 if (!IsByteRange (Val)) {
279 ErrorSkip (ERR_RANGE);
286 /* Check if the alignment is a power of two */
287 Bit = BitFind (Align);
288 if (Align != (0x01L << Bit)) {
291 SegAlign (Bit, (int) Val);
297 static void DoASCIIZ (void)
298 /* Define text with a zero terminator */
303 /* Must have a string constant */
304 if (Tok != TOK_STRCON) {
305 ErrorSkip (ERR_STRCON_EXPECTED);
309 /* Get the length of the string constant */
312 /* Translate into target charset and emit */
313 TgtTranslateBuf (SVal, Len);
314 EmitData ((unsigned char*) SVal, Len);
316 if (Tok == TOK_COMMA) {
327 static void DoAutoImport (void)
328 /* Mark unresolved symbols as imported */
330 SetBoolOption (&AutoImport);
335 static void DoBss (void)
336 /* Switch to the BSS segment */
343 static void DoByte (void)
347 if (Tok == TOK_STRCON) {
348 /* A string, translate into target charset and emit */
349 unsigned Len = strlen (SVal);
350 TgtTranslateBuf (SVal, Len);
351 EmitData ((unsigned char*) SVal, Len);
354 EmitByte (Expression ());
356 if (Tok != TOK_COMMA) {
360 /* Do smart handling of dangling comma */
361 if (Tok == TOK_SEP) {
362 Error (ERR_UNEXPECTED_EOL);
371 static void DoCase (void)
372 /* Switch the IgnoreCase option */
374 SetBoolOption (&IgnoreCase);
375 IgnoreCase = !IgnoreCase;
380 static void DoCharMap (void)
381 /* Allow custome character mappings */
386 /* Read the index as numerical value */
387 Index = ConstExpression ();
388 if (Index < 1 || Index > 255) {
389 /* Value out of range */
390 ErrorSkip (ERR_RANGE);
397 /* Read the character code */
398 Code = ConstExpression ();
399 if (Code < 1 || Code > 255) {
400 /* Value out of range */
401 ErrorSkip (ERR_RANGE);
405 /* Set the character translation */
406 TgtTranslateSet ((unsigned) Index, (unsigned char) Code);
411 static void DoCode (void)
412 /* Switch to the code segment */
414 UseSeg (&CodeSegDef);
419 static void DoConDes (void)
420 /* Export a symbol as constructor/destructor */
422 static const char* Keys[] = {
426 char Name [sizeof (SVal)];
429 /* Symbol name follows */
430 if (Tok != TOK_IDENT) {
431 ErrorSkip (ERR_IDENT_EXPECTED);
437 /* Type follows. May be encoded as identifier or numerical */
439 if (Tok == TOK_IDENT) {
441 /* Map the following keyword to a number, then skip it */
442 Type = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
445 /* Check if we got a valid keyword */
454 /* Read the type as numerical value */
455 Type = ConstExpression ();
456 if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) {
457 /* Value out of range */
464 /* Parse the remainder of the line and export the symbol */
465 ConDes (Name, (unsigned) Type);
470 static void DoConstructor (void)
471 /* Export a symbol as constructor */
473 char Name [sizeof (SVal)];
475 /* Symbol name follows */
476 if (Tok != TOK_IDENT) {
477 ErrorSkip (ERR_IDENT_EXPECTED);
483 /* Parse the remainder of the line and export the symbol */
484 ConDes (Name, CD_TYPE_CON);
489 static void DoData (void)
490 /* Switch to the data segment */
492 UseSeg (&DataSegDef);
497 static void DoDbg (void)
498 /* Add debug information from high level code */
500 static const char* Keys[] = {
508 /* We expect a subkey */
509 if (Tok != TOK_IDENT) {
510 ErrorSkip (ERR_IDENT_EXPECTED);
514 /* Map the following keyword to a number */
515 Key = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
517 /* Skip the subkey */
520 /* Check the key and dispatch to a handler */
522 case 0: DbgInfoFile (); break;
523 case 1: DbgInfoLine (); break;
524 case 2: DbgInfoSym (); break;
525 default: ErrorSkip (ERR_SYNTAX); break;
531 static void DoDByt (void)
532 /* Output double bytes */
535 EmitWord (SwapExpr (Expression ()));
536 if (Tok != TOK_COMMA) {
546 static void DoDebugInfo (void)
547 /* Switch debug info on or off */
549 SetBoolOption (&DbgSyms);
554 static void DoDefine (void)
555 /* Define a one line macro */
557 MacDef (MAC_STYLE_DEFINE);
562 static void DoDestructor (void)
563 /* Export a symbol as destructor */
565 char Name [sizeof (SVal)];
567 /* Symbol name follows */
568 if (Tok != TOK_IDENT) {
569 ErrorSkip (ERR_IDENT_EXPECTED);
575 /* Parse the remainder of the line and export the symbol */
576 ConDes (Name, CD_TYPE_DES);
581 static void DoDWord (void)
585 EmitDWord (Expression ());
586 if (Tok != TOK_COMMA) {
596 static void DoEnd (void)
597 /* End of assembly */
604 static void DoEndProc (void)
605 /* Leave a lexical level */
612 static void DoError (void)
615 if (Tok != TOK_STRCON) {
616 ErrorSkip (ERR_STRCON_EXPECTED);
618 Error (ERR_USER, SVal);
625 static void DoExitMacro (void)
626 /* Exit a macro expansion */
628 if (!InMacExpansion ()) {
629 /* We aren't expanding a macro currently */
638 static void DoExport (void)
639 /* Export a symbol */
641 ExportImport (SymExport, 0);
646 static void DoExportZP (void)
647 /* Export a zeropage symbol */
649 ExportImport (SymExport, 1);
654 static void DoFarAddr (void)
655 /* Define far addresses (24 bit) */
658 EmitFarAddr (Expression ());
659 if (Tok != TOK_COMMA) {
669 static void DoFeature (void)
670 /* Switch the Feature option */
672 /* Allow a list of comma separated keywords */
675 /* We expect an identifier */
676 if (Tok != TOK_IDENT) {
677 ErrorSkip (ERR_IDENT_EXPECTED);
681 /* Make the string attribute lower case */
684 /* Set the feature and check for errors */
685 if (SetFeature (SVal) == FEAT_UNKNOWN) {
687 ErrorSkip (ERR_ILLEGAL_FEATURE);
690 /* Skip the keyword */
694 /* Allow more than one keyword */
695 if (Tok == TOK_COMMA) {
705 static void DoFileOpt (void)
706 /* Insert a file option */
710 /* The option type may be given as a keyword or as a number. */
711 if (Tok == TOK_IDENT) {
713 /* Option given as keyword */
714 static const char* Keys [] = {
715 "AUTHOR", "COMMENT", "COMPILER"
718 /* Map the option to a number */
719 OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
722 ErrorSkip (ERR_OPTION_KEY_EXPECTED);
726 /* Skip the keyword */
729 /* Must be followed by a comma */
732 /* We accept only string options for now */
733 if (Tok != TOK_STRCON) {
734 ErrorSkip (ERR_STRCON_EXPECTED);
738 /* Insert the option */
757 Internal ("Invalid OptNum: %l", OptNum);
766 /* Option given as number */
767 OptNum = ConstExpression ();
768 if (!IsByteRange (OptNum)) {
769 ErrorSkip (ERR_RANGE);
773 /* Must be followed by a comma */
776 /* We accept only string options for now */
777 if (Tok != TOK_STRCON) {
778 ErrorSkip (ERR_STRCON_EXPECTED);
782 /* Insert the option */
783 OptStr ((unsigned char) OptNum, SVal);
792 static void DoGlobal (void)
793 /* Declare a global symbol */
795 ExportImport (SymGlobal, 0);
800 static void DoGlobalZP (void)
801 /* Declare a global zeropage symbol */
803 ExportImport (SymGlobal, 1);
808 static void DoI16 (void)
809 /* Switch the index registers to 16 bit mode (assembler only) */
811 if (GetCPU() != CPU_65816) {
812 Error (ERR_816_MODE_ONLY);
814 /* Immidiate mode has two extension bytes */
815 ExtBytes [AMI_IMM_INDEX] = 2;
821 static void DoI8 (void)
822 /* Switch the index registers to 16 bit mode (assembler only) */
824 if (GetCPU() != CPU_65816) {
825 Error (ERR_816_MODE_ONLY);
827 /* Immidiate mode has one extension byte */
828 ExtBytes [AMI_IMM_INDEX] = 1;
834 static void DoImport (void)
835 /* Import a symbol */
837 ExportImport (SymImport, 0);
842 static void DoImportZP (void)
843 /* Import a zero page symbol */
845 ExportImport (SymImport, 1);
850 static void DoIncBin (void)
851 /* Include a binary file */
853 char Name [sizeof (SVal)];
859 /* Name must follow */
860 if (Tok != TOK_STRCON) {
861 ErrorSkip (ERR_STRCON_EXPECTED);
867 /* A starting offset may follow */
868 if (Tok == TOK_COMMA) {
870 Start = ConstExpression ();
872 /* And a length may follow */
873 if (Tok == TOK_COMMA) {
875 Count = ConstExpression ();
880 /* Try to open the file */
881 F = fopen (Name, "rb");
883 ErrorSkip (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno));
887 /* Get the size of the file */
888 fseek (F, 0, SEEK_END);
891 /* If a count was not given, calculate it now */
893 Count = Size - Start;
895 /* Nothing to read - flag this as a range error */
896 ErrorSkip (ERR_RANGE);
900 /* Count was given, check if it is valid */
901 if (Start + Count > Size) {
902 ErrorSkip (ERR_RANGE);
907 /* Seek to the start position */
908 fseek (F, Start, SEEK_SET);
910 /* Read chunks and insert them into the output */
913 unsigned char Buf [1024];
915 /* Calculate the number of bytes to read */
916 size_t BytesToRead = (Count > (long)sizeof(Buf))? sizeof(Buf) : (size_t) Count;
919 size_t BytesRead = fread (Buf, 1, BytesToRead, F);
920 if (BytesToRead != BytesRead) {
921 /* Some sort of error */
922 ErrorSkip (ERR_CANNOT_READ_INCLUDE, Name, strerror (errno));
926 /* Insert it into the output */
927 EmitData (Buf, BytesRead);
929 /* Keep the counters current */
934 /* Close the file, ignore errors since it's r/o */
940 static void DoInclude (void)
941 /* Include another file */
943 char Name [MAX_STR_LEN+1];
945 /* Name must follow */
946 if (Tok != TOK_STRCON) {
947 ErrorSkip (ERR_STRCON_EXPECTED);
957 static void DoInvalid (void)
958 /* Handle a token that is invalid here, since it should have been handled on
959 * a much lower level of the expression hierarchy. Getting this sort of token
960 * means that the lower level code has bugs.
961 * This function differs to DoUnexpected in that the latter may be triggered
962 * by the user by using keywords in the wrong location. DoUnexpected is not
963 * an error in the assembler itself, while DoInvalid is.
966 Internal ("Unexpected token: %s", Keyword);
971 static void DoLineCont (void)
972 /* Switch the use of line continuations */
974 SetBoolOption (&LineCont);
979 static void DoList (void)
980 /* Enable/disable the listing */
982 /* Get the setting */
984 SetBoolOption (&List);
986 /* Manage the counter */
996 static void DoListBytes (void)
997 /* Set maximum number of bytes to list for one line */
999 SetListBytes (IntArg (MIN_LIST_BYTES, MAX_LIST_BYTES));
1004 static void DoLocalChar (void)
1005 /* Define the character that starts local labels */
1007 if (Tok != TOK_CHARCON) {
1008 ErrorSkip (ERR_CHARCON_EXPECTED);
1010 if (IVal != '@' && IVal != '?') {
1011 Error (ERR_ILLEGAL_LOCALSTART);
1013 LocalStart = (char) IVal;
1021 static void DoMacPack (void)
1022 /* Insert a macro package */
1024 /* Macro package names */
1025 static const char* Keys [] = {
1032 /* We expect an identifier */
1033 if (Tok != TOK_IDENT) {
1034 ErrorSkip (ERR_IDENT_EXPECTED);
1038 /* Map the keyword to a number */
1039 Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
1042 ErrorSkip (ERR_ILLEGAL_MACPACK);
1046 /* Skip the package name */
1049 /* Insert the package */
1050 InsertMacPack (Package);
1055 static void DoMacro (void)
1056 /* Start a macro definition */
1058 MacDef (MAC_STYLE_CLASSIC);
1063 static void DoNull (void)
1064 /* Switch to the NULL segment */
1066 UseSeg (&NullSegDef);
1071 static void DoOrg (void)
1072 /* Start absolute code */
1074 long PC = ConstExpression ();
1075 if (PC < 0 || PC > 0xFFFFFF) {
1084 static void DoOut (void)
1085 /* Output a string */
1087 if (Tok != TOK_STRCON) {
1088 ErrorSkip (ERR_STRCON_EXPECTED);
1090 /* Output the string and be sure to flush the output to keep it in
1091 * sync with any error messages if the output is redirected to a file.
1093 printf ("%s\n", SVal);
1101 static void DoP02 (void)
1102 /* Switch to 6502 CPU */
1109 static void DoPC02 (void)
1110 /* Switch to 65C02 CPU */
1117 static void DoP816 (void)
1118 /* Switch to 65816 CPU */
1125 static void DoPageLength (void)
1126 /* Set the page length for the listing */
1128 PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
1133 static void DoPopSeg (void)
1134 /* Pop an old segment from the segment stack */
1138 /* Must have a segment on the stack */
1139 if (CollCount (&SegStack) == 0) {
1140 ErrorSkip (ERR_SEGSTACK_EMPTY);
1144 /* Pop the last element */
1145 Def = CollPop (&SegStack);
1147 /* Restore this segment */
1150 /* Delete the segment definition */
1156 static void DoProc (void)
1157 /* Start a new lexical scope */
1159 if (Tok == TOK_IDENT) {
1160 /* The new scope has a name */
1161 SymDef (SVal, CurrentPC (), IsZPSeg (), 1);
1169 static void DoPushSeg (void)
1170 /* Push the current segment onto the segment stack */
1172 /* Can only push a limited size of segments */
1173 if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) {
1174 ErrorSkip (ERR_SEGSTACK_OVERFLOW);
1178 /* Get the current segment and push it */
1179 CollAppend (&SegStack, DupSegDef (GetCurrentSeg ()));
1184 static void DoReloc (void)
1185 /* Enter relocatable mode */
1192 static void DoRepeat (void)
1193 /* Repeat some instruction block */
1200 static void DoRes (void)
1201 /* Reserve some number of storage bytes */
1206 Count = ConstExpression ();
1207 if (Count > 0xFFFF || Count < 0) {
1208 ErrorSkip (ERR_RANGE);
1211 if (Tok == TOK_COMMA) {
1213 Val = ConstExpression ();
1214 /* We need a byte value here */
1215 if (!IsByteRange (Val)) {
1216 ErrorSkip (ERR_RANGE);
1220 /* Emit constant values */
1222 Emit0 ((unsigned char) Val);
1226 /* Emit fill fragments */
1233 static void DoROData (void)
1234 /* Switch to the r/o data segment */
1236 UseSeg (&RODataSegDef);
1241 static void DoSegment (void)
1242 /* Switch to another segment */
1244 static const char* AttrTab [] = {
1245 "ZEROPAGE", "DIRECT",
1249 char Name [sizeof (SVal)];
1250 SegDef Def = { Name, SEGTYPE_DEFAULT };
1252 if (Tok != TOK_STRCON) {
1253 ErrorSkip (ERR_STRCON_EXPECTED);
1256 /* Save the name of the segment and skip it */
1257 strcpy (Name, SVal);
1260 /* Check for an optional segment attribute */
1261 if (Tok == TOK_COMMA) {
1263 if (Tok != TOK_IDENT) {
1264 ErrorSkip (ERR_IDENT_EXPECTED);
1266 int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0]));
1272 Def.Type = SEGTYPE_ZP;
1277 Def.Type = SEGTYPE_ABS;
1283 Def.Type = SEGTYPE_FAR;
1287 Error (ERR_ILLEGAL_SEG_ATTR);
1293 /* Set the segment */
1300 static void DoSmart (void)
1301 /* Smart mode on/off */
1303 SetBoolOption (&SmartMode);
1308 static void DoSunPlus (void)
1309 /* Switch to the SUNPLUS CPU */
1311 SetCPU (CPU_SUNPLUS);
1316 static void DoUnexpected (void)
1317 /* Got an unexpected keyword */
1319 Error (ERR_UNEXPECTED, Keyword);
1325 static void DoWarning (void)
1328 if (Tok != TOK_STRCON) {
1329 ErrorSkip (ERR_STRCON_EXPECTED);
1331 Warning (WARN_USER, SVal);
1338 static void DoWord (void)
1342 EmitWord (Expression ());
1343 if (Tok != TOK_COMMA) {
1353 static void DoZeropage (void)
1354 /* Switch to the zeropage segment */
1356 UseSeg (&ZeropageSegDef);
1361 /*****************************************************************************/
1363 /*****************************************************************************/
1367 /* Control commands flags */
1369 ccNone = 0x0000, /* No special flags */
1370 ccKeepToken = 0x0001 /* Do not skip the current token */
1373 /* Control command table */
1375 unsigned Flags; /* Flags for this directive */
1376 void (*Handler) (void); /* Command handler */
1378 typedef struct CtrlDesc_ CtrlDesc;
1380 #define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
1381 static CtrlDesc CtrlCmdTab [] = {
1384 { ccNone, DoAddr }, /* .ADDR */
1385 { ccNone, DoAlign },
1386 { ccNone, DoASCIIZ },
1387 { ccNone, DoAutoImport },
1388 { ccNone, DoUnexpected }, /* .BLANK */
1392 { ccNone, DoCharMap },
1394 { ccNone, DoUnexpected, }, /* .CONCAT */
1395 { ccNone, DoConDes },
1396 { ccNone, DoUnexpected }, /* .CONST */
1397 { ccNone, DoConstructor },
1398 { ccNone, DoUnexpected }, /* .CPU */
1402 { ccNone, DoDebugInfo },
1403 { ccNone, DoDefine },
1404 { ccNone, DoUnexpected }, /* .DEFINED */
1405 { ccNone, DoDestructor },
1406 { ccNone, DoDWord },
1407 { ccKeepToken, DoConditionals }, /* .ELSE */
1408 { ccKeepToken, DoConditionals }, /* .ELSEIF */
1410 { ccKeepToken, DoConditionals }, /* .ENDIF */
1411 { ccNone, DoUnexpected }, /* .ENDMACRO */
1412 { ccNone, DoEndProc },
1413 { ccNone, DoUnexpected }, /* .ENDREPEAT */
1414 { ccNone, DoError },
1415 { ccNone, DoExitMacro },
1416 { ccNone, DoExport },
1417 { ccNone, DoExportZP },
1418 { ccNone, DoFarAddr },
1419 { ccNone, DoFeature },
1420 { ccNone, DoFileOpt },
1421 { ccNone, DoUnexpected }, /* .FORCEWORD */
1422 { ccNone, DoGlobal },
1423 { ccNone, DoGlobalZP },
1426 { ccKeepToken, DoConditionals }, /* .IF */
1427 { ccKeepToken, DoConditionals }, /* .IFBLANK */
1428 { ccKeepToken, DoConditionals }, /* .IFCONST */
1429 { ccKeepToken, DoConditionals }, /* .IFDEF */
1430 { ccKeepToken, DoConditionals }, /* .IFNBLANK */
1431 { ccKeepToken, DoConditionals }, /* .IFNCONST */
1432 { ccKeepToken, DoConditionals }, /* .IFNDEF */
1433 { ccKeepToken, DoConditionals }, /* .IFNREF */
1434 { ccKeepToken, DoConditionals }, /* .IFP02 */
1435 { ccKeepToken, DoConditionals }, /* .IFP816 */
1436 { ccKeepToken, DoConditionals }, /* .IFPC02 */
1437 { ccKeepToken, DoConditionals }, /* .IFREF */
1438 { ccNone, DoImport },
1439 { ccNone, DoImportZP },
1440 { ccNone, DoIncBin },
1441 { ccNone, DoInclude },
1442 { ccNone, DoInvalid }, /* .LEFT */
1443 { ccNone, DoLineCont },
1445 { ccNone, DoListBytes },
1446 { ccNone, DoUnexpected }, /* .LOCAL */
1447 { ccNone, DoLocalChar },
1448 { ccNone, DoMacPack },
1449 { ccNone, DoMacro },
1450 { ccNone, DoUnexpected }, /* .MATCH */
1451 { ccNone, DoInvalid }, /* .MID */
1457 { ccNone, DoPageLength },
1458 { ccNone, DoUnexpected }, /* .PARAMCOUNT */
1460 { ccNone, DoPopSeg },
1462 { ccNone, DoPushSeg },
1463 { ccNone, DoUnexpected }, /* .REFERENCED */
1464 { ccNone, DoReloc },
1465 { ccNone, DoRepeat },
1467 { ccNone, DoInvalid }, /* .RIGHT */
1468 { ccNone, DoROData },
1469 { ccNone, DoSegment },
1470 { ccNone, DoSmart },
1471 { ccNone, DoUnexpected }, /* .STRAT */
1472 { ccNone, DoUnexpected }, /* .STRING */
1473 { ccNone, DoUnexpected }, /* .STRLEN */
1474 { ccNone, DoSunPlus },
1475 { ccNone, DoUnexpected }, /* .TCOUNT */
1476 { ccNone, DoUnexpected }, /* .TIME */
1477 { ccNone, DoWarning },
1479 { ccNone, DoUnexpected }, /* .XMATCH */
1480 { ccNone, DoZeropage },
1485 /*****************************************************************************/
1487 /*****************************************************************************/
1491 int TokIsPseudo (unsigned Tok)
1492 /* Return true if the given token is a pseudo instruction token */
1494 return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO);
1499 void HandlePseudo (void)
1500 /* Handle a pseudo instruction */
1504 /* Calculate the index into the table */
1505 unsigned Index = Tok - TOK_FIRSTPSEUDO;
1508 if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
1509 Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
1510 PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
1512 CHECK (Index < PSEUDO_COUNT);
1514 /* Get the pseudo intruction descriptor */
1515 D = &CtrlCmdTab [Index];
1517 /* Remember the instruction, then skip it if needed */
1518 if ((D->Flags & ccKeepToken) == 0) {
1519 strcpy (Keyword+1, SVal);
1523 /* Call the handler */
1529 void SegStackCheck (void)
1530 /* Check if the segment stack is empty at end of assembly */
1532 if (CollCount (&SegStack) != 0) {
1533 Error (ERR_SEGSTACK_NOT_EMPTY);