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 /*****************************************************************************/
43 #include "assertdefs.h"
74 /*****************************************************************************/
76 /*****************************************************************************/
80 /* Keyword we're about to handle */
81 static char Keyword [sizeof (SVal)+1] = ".";
84 #define MAX_PUSHED_SEGMENTS 16
85 static Collection SegStack = STATIC_COLLECTION_INITIALIZER;
89 /*****************************************************************************/
91 /*****************************************************************************/
95 static void DoUnexpected (void);
96 /* Got an unexpected keyword */
98 static void DoInvalid (void);
99 /* Handle a token that is invalid here, since it should have been handled on
100 * a much lower level of the expression hierarchy. Getting this sort of token
101 * means that the lower level code has bugs.
102 * This function differs to DoUnexpected in that the latter may be triggered
103 * by the user by using keywords in the wrong location. DoUnexpected is not
104 * an error in the assembler itself, while DoInvalid is.
109 /*****************************************************************************/
110 /* Helper functions */
111 /*****************************************************************************/
115 static void SetBoolOption (unsigned char* Flag)
116 /* Read a on/off/+/- option and set flag accordingly */
118 static const char* Keys[] = {
123 if (Tok == TOK_PLUS) {
126 } else if (Tok == TOK_MINUS) {
129 } else if (Tok == TOK_IDENT) {
130 /* Map the keyword to a number */
131 switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
132 case 0: *Flag = 0; NextTok (); break;
133 case 1: *Flag = 1; NextTok (); break;
134 default: ErrorSkip (ERR_ONOFF_EXPECTED); break;
136 } else if (TokIsSep (Tok)) {
137 /* Without anything assume switch on */
140 ErrorSkip (ERR_ONOFF_EXPECTED);
146 static void ExportImport (void (*SymFunc) (const char*))
147 /* Export or import symbols */
150 if (Tok != TOK_IDENT) {
151 ErrorSkip (ERR_IDENT_EXPECTED);
156 if (Tok == TOK_COMMA) {
166 static long IntArg (long Min, long Max)
167 /* Read an integer argument and check a range. Accept the token "unlimited"
168 * and return -1 in this case.
171 if (Tok == TOK_IDENT && strcmp (SVal, "unlimited") == 0) {
175 long Val = ConstExpression ();
176 if (Val < Min || Val > Max) {
186 static void ConDes (const char* Name, unsigned Type)
187 /* Parse remaining line for constructor/destructor of the remaining type */
191 /* Optional constructor priority */
192 if (Tok == TOK_COMMA) {
193 /* Priority value follows */
195 Prio = ConstExpression ();
196 if (Prio < CD_PRIO_MIN || Prio > CD_PRIO_MAX) {
197 /* Value out of range */
202 /* Use the default priority value */
206 /* Define the symbol */
207 SymConDes (Name, Type, (unsigned) Prio);
212 /*****************************************************************************/
213 /* Handler functions */
214 /*****************************************************************************/
218 static void DoA16 (void)
219 /* Switch the accu to 16 bit mode (assembler only) */
221 if (GetCPU() != CPU_65816) {
222 Error (ERR_816_MODE_ONLY);
224 /* Immidiate mode has two extension bytes */
225 ExtBytes [AMI_IMM_ACCU] = 2;
231 static void DoA8 (void)
232 /* Switch the accu to 8 bit mode (assembler only) */
234 if (GetCPU() != CPU_65816) {
235 Error (ERR_816_MODE_ONLY);
237 /* Immidiate mode has one extension byte */
238 ExtBytes [AMI_IMM_ACCU] = 1;
244 static void DoAddr (void)
245 /* Define addresses */
248 if (GetCPU() == CPU_65816) {
249 EmitWord (GenWordExpr (Expression ()));
251 /* Do a range check */
252 EmitWord (Expression ());
254 if (Tok != TOK_COMMA) {
264 static void DoAlign (void)
265 /* Align the PC to some boundary */
271 /* Read the alignment value */
272 Align = ConstExpression ();
273 if (Align <= 0 || Align > 0x10000) {
274 ErrorSkip (ERR_RANGE);
278 /* Optional value follows */
279 if (Tok == TOK_COMMA) {
281 Val = ConstExpression ();
282 /* We need a byte value here */
283 if (!IsByteRange (Val)) {
284 ErrorSkip (ERR_RANGE);
291 /* Check if the alignment is a power of two */
292 Bit = BitFind (Align);
293 if (Align != (0x01L << Bit)) {
296 SegAlign (Bit, (int) Val);
302 static void DoASCIIZ (void)
303 /* Define text with a zero terminator */
308 /* Must have a string constant */
309 if (Tok != TOK_STRCON) {
310 ErrorSkip (ERR_STRCON_EXPECTED);
314 /* Get the length of the string constant */
317 /* Translate into target charset and emit */
318 TgtTranslateBuf (SVal, Len);
319 EmitData ((unsigned char*) SVal, Len);
321 if (Tok == TOK_COMMA) {
332 static void DoAssert (void)
333 /* Add an assertion */
335 static const char* ActionTab [] = {
343 /* First we have the expression that has to evaluated */
344 ExprNode* Expr = Expression ();
348 if (Tok != TOK_IDENT) {
349 ErrorSkip (ERR_IDENT_EXPECTED);
352 Action = GetSubKey (ActionTab, sizeof (ActionTab) / sizeof (ActionTab[0]));
358 Action = ASSERT_ACT_WARN;
363 Action = ASSERT_ACT_ERROR;
367 Error (ERR_ILLEGAL_SEG_ATTR);
372 /* Read the message */
373 if (Tok != TOK_STRCON) {
374 ErrorSkip (ERR_STRCON_EXPECTED);
376 AddAssertion (Expr, Action, GetStringId (SVal));
383 static void DoAutoImport (void)
384 /* Mark unresolved symbols as imported */
386 SetBoolOption (&AutoImport);
391 static void DoBss (void)
392 /* Switch to the BSS segment */
399 static void DoByte (void)
403 if (Tok == TOK_STRCON) {
404 /* A string, translate into target charset and emit */
405 unsigned Len = strlen (SVal);
406 TgtTranslateBuf (SVal, Len);
407 EmitData ((unsigned char*) SVal, Len);
410 EmitByte (Expression ());
412 if (Tok != TOK_COMMA) {
416 /* Do smart handling of dangling comma */
417 if (Tok == TOK_SEP) {
418 Error (ERR_UNEXPECTED_EOL);
427 static void DoCase (void)
428 /* Switch the IgnoreCase option */
430 SetBoolOption (&IgnoreCase);
431 IgnoreCase = !IgnoreCase;
436 static void DoCharMap (void)
437 /* Allow custome character mappings */
442 /* Read the index as numerical value */
443 Index = ConstExpression ();
444 if (Index < 1 || Index > 255) {
445 /* Value out of range */
446 ErrorSkip (ERR_RANGE);
453 /* Read the character code */
454 Code = ConstExpression ();
455 if (Code < 1 || Code > 255) {
456 /* Value out of range */
457 ErrorSkip (ERR_RANGE);
461 /* Set the character translation */
462 TgtTranslateSet ((unsigned) Index, (unsigned char) Code);
467 static void DoCode (void)
468 /* Switch to the code segment */
470 UseSeg (&CodeSegDef);
475 static void DoConDes (void)
476 /* Export a symbol as constructor/destructor */
478 static const char* Keys[] = {
482 char Name [sizeof (SVal)];
485 /* Symbol name follows */
486 if (Tok != TOK_IDENT) {
487 ErrorSkip (ERR_IDENT_EXPECTED);
493 /* Type follows. May be encoded as identifier or numerical */
495 if (Tok == TOK_IDENT) {
497 /* Map the following keyword to a number, then skip it */
498 Type = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
501 /* Check if we got a valid keyword */
510 /* Read the type as numerical value */
511 Type = ConstExpression ();
512 if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) {
513 /* Value out of range */
520 /* Parse the remainder of the line and export the symbol */
521 ConDes (Name, (unsigned) Type);
526 static void DoConstructor (void)
527 /* Export a symbol as constructor */
529 char Name [sizeof (SVal)];
531 /* Symbol name follows */
532 if (Tok != TOK_IDENT) {
533 ErrorSkip (ERR_IDENT_EXPECTED);
539 /* Parse the remainder of the line and export the symbol */
540 ConDes (Name, CD_TYPE_CON);
545 static void DoData (void)
546 /* Switch to the data segment */
548 UseSeg (&DataSegDef);
553 static void DoDbg (void)
554 /* Add debug information from high level code */
556 static const char* Keys[] = {
564 /* We expect a subkey */
565 if (Tok != TOK_IDENT) {
566 ErrorSkip (ERR_IDENT_EXPECTED);
570 /* Map the following keyword to a number */
571 Key = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
573 /* Skip the subkey */
576 /* Check the key and dispatch to a handler */
578 case 0: DbgInfoFile (); break;
579 case 1: DbgInfoLine (); break;
580 case 2: DbgInfoSym (); break;
581 default: ErrorSkip (ERR_SYNTAX); break;
587 static void DoDByt (void)
588 /* Output double bytes */
591 EmitWord (GenSwapExpr (Expression ()));
592 if (Tok != TOK_COMMA) {
602 static void DoDebugInfo (void)
603 /* Switch debug info on or off */
605 SetBoolOption (&DbgSyms);
610 static void DoDefine (void)
611 /* Define a one line macro */
613 MacDef (MAC_STYLE_DEFINE);
618 static void DoDestructor (void)
619 /* Export a symbol as destructor */
621 char Name [sizeof (SVal)];
623 /* Symbol name follows */
624 if (Tok != TOK_IDENT) {
625 ErrorSkip (ERR_IDENT_EXPECTED);
631 /* Parse the remainder of the line and export the symbol */
632 ConDes (Name, CD_TYPE_DES);
637 static void DoDWord (void)
641 EmitDWord (Expression ());
642 if (Tok != TOK_COMMA) {
652 static void DoEnd (void)
653 /* End of assembly */
661 static void DoEndProc (void)
662 /* Leave a lexical level */
664 if (!SymIsLocalLevel ()) {
666 ErrorSkip (ERR_NO_OPEN_PROC);
674 static void DoError (void)
677 if (Tok != TOK_STRCON) {
678 ErrorSkip (ERR_STRCON_EXPECTED);
680 Error (ERR_USER, SVal);
687 static void DoExitMacro (void)
688 /* Exit a macro expansion */
690 if (!InMacExpansion ()) {
691 /* We aren't expanding a macro currently */
700 static void DoExport (void)
701 /* Export a symbol */
703 ExportImport (SymExport);
708 static void DoExportZP (void)
709 /* Export a zeropage symbol */
711 ExportImport (SymExportZP);
716 static void DoFarAddr (void)
717 /* Define far addresses (24 bit) */
720 EmitFarAddr (Expression ());
721 if (Tok != TOK_COMMA) {
731 static void DoFeature (void)
732 /* Switch the Feature option */
734 /* Allow a list of comma separated keywords */
737 /* We expect an identifier */
738 if (Tok != TOK_IDENT) {
739 ErrorSkip (ERR_IDENT_EXPECTED);
743 /* Make the string attribute lower case */
746 /* Set the feature and check for errors */
747 if (SetFeature (SVal) == FEAT_UNKNOWN) {
749 ErrorSkip (ERR_ILLEGAL_FEATURE);
752 /* Skip the keyword */
756 /* Allow more than one keyword */
757 if (Tok == TOK_COMMA) {
767 static void DoFileOpt (void)
768 /* Insert a file option */
772 /* The option type may be given as a keyword or as a number. */
773 if (Tok == TOK_IDENT) {
775 /* Option given as keyword */
776 static const char* Keys [] = {
777 "AUTHOR", "COMMENT", "COMPILER"
780 /* Map the option to a number */
781 OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
784 ErrorSkip (ERR_OPTION_KEY_EXPECTED);
788 /* Skip the keyword */
791 /* Must be followed by a comma */
794 /* We accept only string options for now */
795 if (Tok != TOK_STRCON) {
796 ErrorSkip (ERR_STRCON_EXPECTED);
800 /* Insert the option */
819 Internal ("Invalid OptNum: %ld", OptNum);
828 /* Option given as number */
829 OptNum = ConstExpression ();
830 if (!IsByteRange (OptNum)) {
831 ErrorSkip (ERR_RANGE);
835 /* Must be followed by a comma */
838 /* We accept only string options for now */
839 if (Tok != TOK_STRCON) {
840 ErrorSkip (ERR_STRCON_EXPECTED);
844 /* Insert the option */
845 OptStr ((unsigned char) OptNum, SVal);
854 static void DoForceImport (void)
855 /* Do a forced import on a symbol */
857 ExportImport (SymImportForced);
862 static void DoGlobal (void)
863 /* Declare a global symbol */
865 ExportImport (SymGlobal);
870 static void DoGlobalZP (void)
871 /* Declare a global zeropage symbol */
873 ExportImport (SymGlobalZP);
878 static void DoI16 (void)
879 /* Switch the index registers to 16 bit mode (assembler only) */
881 if (GetCPU() != CPU_65816) {
882 Error (ERR_816_MODE_ONLY);
884 /* Immidiate mode has two extension bytes */
885 ExtBytes [AMI_IMM_INDEX] = 2;
891 static void DoI8 (void)
892 /* Switch the index registers to 16 bit mode (assembler only) */
894 if (GetCPU() != CPU_65816) {
895 Error (ERR_816_MODE_ONLY);
897 /* Immidiate mode has one extension byte */
898 ExtBytes [AMI_IMM_INDEX] = 1;
904 static void DoImport (void)
905 /* Import a symbol */
907 ExportImport (SymImport);
912 static void DoImportZP (void)
913 /* Import a zero page symbol */
915 ExportImport (SymImportZP);
920 static void DoIncBin (void)
921 /* Include a binary file */
923 char Name [sizeof (SVal)];
929 /* Name must follow */
930 if (Tok != TOK_STRCON) {
931 ErrorSkip (ERR_STRCON_EXPECTED);
937 /* A starting offset may follow */
938 if (Tok == TOK_COMMA) {
940 Start = ConstExpression ();
942 /* And a length may follow */
943 if (Tok == TOK_COMMA) {
945 Count = ConstExpression ();
950 /* Try to open the file */
951 F = fopen (Name, "rb");
954 /* Search for the file in the include directories. */
955 char* PathName = FindInclude (Name);
956 if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
957 /* Not found or cannot open, print an error and bail out */
958 ErrorSkip (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno));
961 /* Free the allocated memory */
964 /* If we had an error before, bail out now */
970 /* Get the size of the file */
971 fseek (F, 0, SEEK_END);
974 /* If a count was not given, calculate it now */
976 Count = Size - Start;
978 /* Nothing to read - flag this as a range error */
979 ErrorSkip (ERR_RANGE);
983 /* Count was given, check if it is valid */
984 if (Start + Count > Size) {
985 ErrorSkip (ERR_RANGE);
990 /* Seek to the start position */
991 fseek (F, Start, SEEK_SET);
993 /* Read chunks and insert them into the output */
996 unsigned char Buf [1024];
998 /* Calculate the number of bytes to read */
999 size_t BytesToRead = (Count > (long)sizeof(Buf))? sizeof(Buf) : (size_t) Count;
1002 size_t BytesRead = fread (Buf, 1, BytesToRead, F);
1003 if (BytesToRead != BytesRead) {
1004 /* Some sort of error */
1005 ErrorSkip (ERR_CANNOT_READ_INCLUDE, Name, strerror (errno));
1009 /* Insert it into the output */
1010 EmitData (Buf, BytesRead);
1012 /* Keep the counters current */
1017 /* Close the file, ignore errors since it's r/o */
1023 static void DoInclude (void)
1024 /* Include another file */
1026 char Name [MAX_STR_LEN+1];
1028 /* Name must follow */
1029 if (Tok != TOK_STRCON) {
1030 ErrorSkip (ERR_STRCON_EXPECTED);
1032 strcpy (Name, SVal);
1034 NewInputFile (Name);
1040 static void DoInvalid (void)
1041 /* Handle a token that is invalid here, since it should have been handled on
1042 * a much lower level of the expression hierarchy. Getting this sort of token
1043 * means that the lower level code has bugs.
1044 * This function differs to DoUnexpected in that the latter may be triggered
1045 * by the user by using keywords in the wrong location. DoUnexpected is not
1046 * an error in the assembler itself, while DoInvalid is.
1049 Internal ("Unexpected token: %s", Keyword);
1054 static void DoLineCont (void)
1055 /* Switch the use of line continuations */
1057 SetBoolOption (&LineCont);
1062 static void DoList (void)
1063 /* Enable/disable the listing */
1065 /* Get the setting */
1067 SetBoolOption (&List);
1069 /* Manage the counter */
1079 static void DoListBytes (void)
1080 /* Set maximum number of bytes to list for one line */
1082 SetListBytes (IntArg (MIN_LIST_BYTES, MAX_LIST_BYTES));
1087 static void DoLocalChar (void)
1088 /* Define the character that starts local labels */
1090 if (Tok != TOK_CHARCON) {
1091 ErrorSkip (ERR_CHARCON_EXPECTED);
1093 if (IVal != '@' && IVal != '?') {
1094 Error (ERR_ILLEGAL_LOCALSTART);
1096 LocalStart = (char) IVal;
1104 static void DoMacPack (void)
1105 /* Insert a macro package */
1107 /* Macro package names */
1108 static const char* Keys [] = {
1116 /* We expect an identifier */
1117 if (Tok != TOK_IDENT) {
1118 ErrorSkip (ERR_IDENT_EXPECTED);
1122 /* Map the keyword to a number */
1123 Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
1126 ErrorSkip (ERR_ILLEGAL_MACPACK);
1130 /* Skip the package name */
1133 /* Insert the package */
1134 InsertMacPack (Package);
1139 static void DoMacro (void)
1140 /* Start a macro definition */
1142 MacDef (MAC_STYLE_CLASSIC);
1147 static void DoNull (void)
1148 /* Switch to the NULL segment */
1150 UseSeg (&NullSegDef);
1155 static void DoOrg (void)
1156 /* Start absolute code */
1158 long PC = ConstExpression ();
1159 if (PC < 0 || PC > 0xFFFFFF) {
1168 static void DoOut (void)
1169 /* Output a string */
1171 if (Tok != TOK_STRCON) {
1172 ErrorSkip (ERR_STRCON_EXPECTED);
1174 /* Output the string and be sure to flush the output to keep it in
1175 * sync with any error messages if the output is redirected to a file.
1177 printf ("%s\n", SVal);
1185 static void DoP02 (void)
1186 /* Switch to 6502 CPU */
1193 static void DoPC02 (void)
1194 /* Switch to 65C02 CPU */
1201 static void DoP816 (void)
1202 /* Switch to 65816 CPU */
1209 static void DoPageLength (void)
1210 /* Set the page length for the listing */
1212 PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
1217 static void DoPopSeg (void)
1218 /* Pop an old segment from the segment stack */
1222 /* Must have a segment on the stack */
1223 if (CollCount (&SegStack) == 0) {
1224 ErrorSkip (ERR_SEGSTACK_EMPTY);
1228 /* Pop the last element */
1229 Def = CollPop (&SegStack);
1231 /* Restore this segment */
1234 /* Delete the segment definition */
1240 static void DoProc (void)
1241 /* Start a new lexical scope */
1243 if (Tok == TOK_IDENT) {
1244 /* The new scope has a name */
1245 SymDef (SVal, GenCurrentPC (), IsZPSeg (), 1);
1253 static void DoPSC02 (void)
1254 /* Switch to 65SC02 CPU */
1256 SetCPU (CPU_65SC02);
1261 static void DoPushSeg (void)
1262 /* Push the current segment onto the segment stack */
1264 /* Can only push a limited size of segments */
1265 if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) {
1266 ErrorSkip (ERR_SEGSTACK_OVERFLOW);
1270 /* Get the current segment and push it */
1271 CollAppend (&SegStack, DupSegDef (GetCurrentSeg ()));
1276 static void DoReloc (void)
1277 /* Enter relocatable mode */
1284 static void DoRepeat (void)
1285 /* Repeat some instruction block */
1292 static void DoRes (void)
1293 /* Reserve some number of storage bytes */
1298 Count = ConstExpression ();
1299 if (Count > 0xFFFF || Count < 0) {
1300 ErrorSkip (ERR_RANGE);
1303 if (Tok == TOK_COMMA) {
1305 Val = ConstExpression ();
1306 /* We need a byte value here */
1307 if (!IsByteRange (Val)) {
1308 ErrorSkip (ERR_RANGE);
1312 /* Emit constant values */
1314 Emit0 ((unsigned char) Val);
1318 /* Emit fill fragments */
1325 static void DoROData (void)
1326 /* Switch to the r/o data segment */
1328 UseSeg (&RODataSegDef);
1333 static void DoSegment (void)
1334 /* Switch to another segment */
1336 static const char* AttrTab [] = {
1337 "ZEROPAGE", "DIRECT",
1341 char Name [sizeof (SVal)];
1344 Def.Type = SEGTYPE_DEFAULT;
1346 if (Tok != TOK_STRCON) {
1347 ErrorSkip (ERR_STRCON_EXPECTED);
1350 /* Save the name of the segment and skip it */
1351 strcpy (Name, SVal);
1354 /* Check for an optional segment attribute */
1355 if (Tok == TOK_COMMA) {
1357 if (Tok != TOK_IDENT) {
1358 ErrorSkip (ERR_IDENT_EXPECTED);
1360 int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0]));
1366 Def.Type = SEGTYPE_ZP;
1371 Def.Type = SEGTYPE_ABS;
1377 Def.Type = SEGTYPE_FAR;
1381 Error (ERR_ILLEGAL_SEG_ATTR);
1387 /* Set the segment */
1394 static void DoSetCPU (void)
1395 /* Switch the CPU instruction set */
1397 /* We expect an identifier */
1398 if (Tok != TOK_STRCON) {
1399 ErrorSkip (ERR_STRCON_EXPECTED);
1401 /* Try to find the CPU, then skip the identifier */
1402 cpu_t CPU = FindCPU (SVal);
1405 /* Switch to the new CPU */
1412 static void DoSmart (void)
1413 /* Smart mode on/off */
1415 SetBoolOption (&SmartMode);
1420 static void DoSunPlus (void)
1421 /* Switch to the SUNPLUS CPU */
1423 SetCPU (CPU_SUNPLUS);
1428 static void DoUnexpected (void)
1429 /* Got an unexpected keyword */
1431 Error (ERR_UNEXPECTED, Keyword);
1437 static void DoWarning (void)
1440 if (Tok != TOK_STRCON) {
1441 ErrorSkip (ERR_STRCON_EXPECTED);
1443 Warning (WARN_USER, SVal);
1450 static void DoWord (void)
1454 EmitWord (Expression ());
1455 if (Tok != TOK_COMMA) {
1465 static void DoZeropage (void)
1466 /* Switch to the zeropage segment */
1468 UseSeg (&ZeropageSegDef);
1473 /*****************************************************************************/
1475 /*****************************************************************************/
1479 /* Control commands flags */
1481 ccNone = 0x0000, /* No special flags */
1482 ccKeepToken = 0x0001 /* Do not skip the current token */
1485 /* Control command table */
1486 typedef struct CtrlDesc CtrlDesc;
1488 unsigned Flags; /* Flags for this directive */
1489 void (*Handler) (void); /* Command handler */
1492 #define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
1493 static CtrlDesc CtrlCmdTab [] = {
1496 { ccNone, DoAddr }, /* .ADDR */
1497 { ccNone, DoAlign },
1498 { ccNone, DoASCIIZ },
1499 { ccNone, DoAssert },
1500 { ccNone, DoAutoImport },
1501 { ccNone, DoUnexpected }, /* .BLANK */
1505 { ccNone, DoCharMap },
1507 { ccNone, DoUnexpected, }, /* .CONCAT */
1508 { ccNone, DoConDes },
1509 { ccNone, DoUnexpected }, /* .CONST */
1510 { ccNone, DoConstructor },
1511 { ccNone, DoUnexpected }, /* .CPU */
1515 { ccNone, DoDebugInfo },
1516 { ccNone, DoDefine },
1517 { ccNone, DoUnexpected }, /* .DEFINED */
1518 { ccNone, DoDestructor },
1519 { ccNone, DoDWord },
1520 { ccKeepToken, DoConditionals }, /* .ELSE */
1521 { ccKeepToken, DoConditionals }, /* .ELSEIF */
1522 { ccKeepToken, DoEnd },
1523 { ccKeepToken, DoConditionals }, /* .ENDIF */
1524 { ccNone, DoUnexpected }, /* .ENDMACRO */
1525 { ccNone, DoEndProc },
1526 { ccNone, DoUnexpected }, /* .ENDREPEAT */
1527 { ccNone, DoError },
1528 { ccNone, DoExitMacro },
1529 { ccNone, DoExport },
1530 { ccNone, DoExportZP },
1531 { ccNone, DoFarAddr },
1532 { ccNone, DoFeature },
1533 { ccNone, DoFileOpt },
1534 { ccNone, DoForceImport },
1535 { ccNone, DoUnexpected }, /* .FORCEWORD */
1536 { ccNone, DoGlobal },
1537 { ccNone, DoGlobalZP },
1540 { ccKeepToken, DoConditionals }, /* .IF */
1541 { ccKeepToken, DoConditionals }, /* .IFBLANK */
1542 { ccKeepToken, DoConditionals }, /* .IFCONST */
1543 { ccKeepToken, DoConditionals }, /* .IFDEF */
1544 { ccKeepToken, DoConditionals }, /* .IFNBLANK */
1545 { ccKeepToken, DoConditionals }, /* .IFNCONST */
1546 { ccKeepToken, DoConditionals }, /* .IFNDEF */
1547 { ccKeepToken, DoConditionals }, /* .IFNREF */
1548 { ccKeepToken, DoConditionals }, /* .IFP02 */
1549 { ccKeepToken, DoConditionals }, /* .IFP816 */
1550 { ccKeepToken, DoConditionals }, /* .IFPC02 */
1551 { ccKeepToken, DoConditionals }, /* .IFPSC02 */
1552 { ccKeepToken, DoConditionals }, /* .IFREF */
1553 { ccNone, DoImport },
1554 { ccNone, DoImportZP },
1555 { ccNone, DoIncBin },
1556 { ccNone, DoInclude },
1557 { ccNone, DoInvalid }, /* .LEFT */
1558 { ccNone, DoLineCont },
1560 { ccNone, DoListBytes },
1561 { ccNone, DoUnexpected }, /* .LOCAL */
1562 { ccNone, DoLocalChar },
1563 { ccNone, DoMacPack },
1564 { ccNone, DoMacro },
1565 { ccNone, DoUnexpected }, /* .MATCH */
1566 { ccNone, DoInvalid }, /* .MID */
1572 { ccNone, DoPageLength },
1573 { ccNone, DoUnexpected }, /* .PARAMCOUNT */
1575 { ccNone, DoPopSeg },
1577 { ccNone, DoPSC02 },
1578 { ccNone, DoPushSeg },
1579 { ccNone, DoUnexpected }, /* .REFERENCED */
1580 { ccNone, DoReloc },
1581 { ccNone, DoRepeat },
1583 { ccNone, DoInvalid }, /* .RIGHT */
1584 { ccNone, DoROData },
1585 { ccNone, DoSegment },
1586 { ccNone, DoSetCPU },
1587 { ccNone, DoSmart },
1588 { ccNone, DoUnexpected }, /* .STRAT */
1589 { ccNone, DoUnexpected }, /* .STRING */
1590 { ccNone, DoUnexpected }, /* .STRLEN */
1591 { ccNone, DoSunPlus },
1592 { ccNone, DoUnexpected }, /* .TCOUNT */
1593 { ccNone, DoUnexpected }, /* .TIME */
1594 { ccNone, DoUnexpected }, /* .VERSION */
1595 { ccNone, DoWarning },
1597 { ccNone, DoUnexpected }, /* .XMATCH */
1598 { ccNone, DoZeropage },
1603 /*****************************************************************************/
1605 /*****************************************************************************/
1609 int TokIsPseudo (unsigned Tok)
1610 /* Return true if the given token is a pseudo instruction token */
1612 return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO);
1617 void HandlePseudo (void)
1618 /* Handle a pseudo instruction */
1622 /* Calculate the index into the table */
1623 unsigned Index = Tok - TOK_FIRSTPSEUDO;
1626 if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
1627 Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
1628 PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
1630 CHECK (Index < PSEUDO_COUNT);
1632 /* Get the pseudo intruction descriptor */
1633 D = &CtrlCmdTab [Index];
1635 /* Remember the instruction, then skip it if needed */
1636 if ((D->Flags & ccKeepToken) == 0) {
1637 strcpy (Keyword+1, SVal);
1641 /* Call the handler */
1647 void SegStackCheck (void)
1648 /* Check if the segment stack is empty at end of assembly */
1650 if (CollCount (&SegStack) != 0) {
1651 Error (ERR_SEGSTACK_NOT_EMPTY);