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 [] = {
1117 /* We expect an identifier */
1118 if (Tok != TOK_IDENT) {
1119 ErrorSkip (ERR_IDENT_EXPECTED);
1123 /* Map the keyword to a number */
1124 Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
1127 ErrorSkip (ERR_ILLEGAL_MACPACK);
1131 /* Skip the package name */
1134 /* Insert the package */
1135 InsertMacPack (Package);
1140 static void DoMacro (void)
1141 /* Start a macro definition */
1143 MacDef (MAC_STYLE_CLASSIC);
1148 static void DoNull (void)
1149 /* Switch to the NULL segment */
1151 UseSeg (&NullSegDef);
1156 static void DoOrg (void)
1157 /* Start absolute code */
1159 long PC = ConstExpression ();
1160 if (PC < 0 || PC > 0xFFFFFF) {
1169 static void DoOut (void)
1170 /* Output a string */
1172 if (Tok != TOK_STRCON) {
1173 ErrorSkip (ERR_STRCON_EXPECTED);
1175 /* Output the string and be sure to flush the output to keep it in
1176 * sync with any error messages if the output is redirected to a file.
1178 printf ("%s\n", SVal);
1186 static void DoP02 (void)
1187 /* Switch to 6502 CPU */
1194 static void DoPC02 (void)
1195 /* Switch to 65C02 CPU */
1202 static void DoP816 (void)
1203 /* Switch to 65816 CPU */
1210 static void DoPageLength (void)
1211 /* Set the page length for the listing */
1213 PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
1218 static void DoPopSeg (void)
1219 /* Pop an old segment from the segment stack */
1223 /* Must have a segment on the stack */
1224 if (CollCount (&SegStack) == 0) {
1225 ErrorSkip (ERR_SEGSTACK_EMPTY);
1229 /* Pop the last element */
1230 Def = CollPop (&SegStack);
1232 /* Restore this segment */
1235 /* Delete the segment definition */
1241 static void DoProc (void)
1242 /* Start a new lexical scope */
1244 if (Tok == TOK_IDENT) {
1245 /* The new scope has a name */
1246 SymDef (SVal, GenCurrentPC (), IsZPSeg (), 1);
1254 static void DoPSC02 (void)
1255 /* Switch to 65SC02 CPU */
1257 SetCPU (CPU_65SC02);
1262 static void DoPushSeg (void)
1263 /* Push the current segment onto the segment stack */
1265 /* Can only push a limited size of segments */
1266 if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) {
1267 ErrorSkip (ERR_SEGSTACK_OVERFLOW);
1271 /* Get the current segment and push it */
1272 CollAppend (&SegStack, DupSegDef (GetCurrentSeg ()));
1277 static void DoReloc (void)
1278 /* Enter relocatable mode */
1285 static void DoRepeat (void)
1286 /* Repeat some instruction block */
1293 static void DoRes (void)
1294 /* Reserve some number of storage bytes */
1299 Count = ConstExpression ();
1300 if (Count > 0xFFFF || Count < 0) {
1301 ErrorSkip (ERR_RANGE);
1304 if (Tok == TOK_COMMA) {
1306 Val = ConstExpression ();
1307 /* We need a byte value here */
1308 if (!IsByteRange (Val)) {
1309 ErrorSkip (ERR_RANGE);
1313 /* Emit constant values */
1315 Emit0 ((unsigned char) Val);
1319 /* Emit fill fragments */
1326 static void DoROData (void)
1327 /* Switch to the r/o data segment */
1329 UseSeg (&RODataSegDef);
1334 static void DoSegment (void)
1335 /* Switch to another segment */
1337 static const char* AttrTab [] = {
1338 "ZEROPAGE", "DIRECT",
1342 char Name [sizeof (SVal)];
1345 Def.Type = SEGTYPE_DEFAULT;
1347 if (Tok != TOK_STRCON) {
1348 ErrorSkip (ERR_STRCON_EXPECTED);
1351 /* Save the name of the segment and skip it */
1352 strcpy (Name, SVal);
1355 /* Check for an optional segment attribute */
1356 if (Tok == TOK_COMMA) {
1358 if (Tok != TOK_IDENT) {
1359 ErrorSkip (ERR_IDENT_EXPECTED);
1361 int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0]));
1367 Def.Type = SEGTYPE_ZP;
1372 Def.Type = SEGTYPE_ABS;
1378 Def.Type = SEGTYPE_FAR;
1382 Error (ERR_ILLEGAL_SEG_ATTR);
1388 /* Set the segment */
1395 static void DoSetCPU (void)
1396 /* Switch the CPU instruction set */
1398 /* We expect an identifier */
1399 if (Tok != TOK_STRCON) {
1400 ErrorSkip (ERR_STRCON_EXPECTED);
1402 /* Try to find the CPU, then skip the identifier */
1403 cpu_t CPU = FindCPU (SVal);
1406 /* Switch to the new CPU */
1413 static void DoSmart (void)
1414 /* Smart mode on/off */
1416 SetBoolOption (&SmartMode);
1421 static void DoSunPlus (void)
1422 /* Switch to the SUNPLUS CPU */
1424 SetCPU (CPU_SUNPLUS);
1429 static void DoUnexpected (void)
1430 /* Got an unexpected keyword */
1432 Error (ERR_UNEXPECTED, Keyword);
1438 static void DoWarning (void)
1441 if (Tok != TOK_STRCON) {
1442 ErrorSkip (ERR_STRCON_EXPECTED);
1444 Warning (WARN_USER, SVal);
1451 static void DoWord (void)
1455 EmitWord (Expression ());
1456 if (Tok != TOK_COMMA) {
1466 static void DoZeropage (void)
1467 /* Switch to the zeropage segment */
1469 UseSeg (&ZeropageSegDef);
1474 /*****************************************************************************/
1476 /*****************************************************************************/
1480 /* Control commands flags */
1482 ccNone = 0x0000, /* No special flags */
1483 ccKeepToken = 0x0001 /* Do not skip the current token */
1486 /* Control command table */
1487 typedef struct CtrlDesc CtrlDesc;
1489 unsigned Flags; /* Flags for this directive */
1490 void (*Handler) (void); /* Command handler */
1493 #define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
1494 static CtrlDesc CtrlCmdTab [] = {
1497 { ccNone, DoAddr }, /* .ADDR */
1498 { ccNone, DoAlign },
1499 { ccNone, DoASCIIZ },
1500 { ccNone, DoAssert },
1501 { ccNone, DoAutoImport },
1502 { ccNone, DoUnexpected }, /* .BLANK */
1506 { ccNone, DoCharMap },
1508 { ccNone, DoUnexpected, }, /* .CONCAT */
1509 { ccNone, DoConDes },
1510 { ccNone, DoUnexpected }, /* .CONST */
1511 { ccNone, DoConstructor },
1512 { ccNone, DoUnexpected }, /* .CPU */
1516 { ccNone, DoDebugInfo },
1517 { ccNone, DoDefine },
1518 { ccNone, DoUnexpected }, /* .DEFINED */
1519 { ccNone, DoDestructor },
1520 { ccNone, DoDWord },
1521 { ccKeepToken, DoConditionals }, /* .ELSE */
1522 { ccKeepToken, DoConditionals }, /* .ELSEIF */
1523 { ccKeepToken, DoEnd },
1524 { ccKeepToken, DoConditionals }, /* .ENDIF */
1525 { ccNone, DoUnexpected }, /* .ENDMACRO */
1526 { ccNone, DoEndProc },
1527 { ccNone, DoUnexpected }, /* .ENDREPEAT */
1528 { ccNone, DoError },
1529 { ccNone, DoExitMacro },
1530 { ccNone, DoExport },
1531 { ccNone, DoExportZP },
1532 { ccNone, DoFarAddr },
1533 { ccNone, DoFeature },
1534 { ccNone, DoFileOpt },
1535 { ccNone, DoForceImport },
1536 { ccNone, DoUnexpected }, /* .FORCEWORD */
1537 { ccNone, DoGlobal },
1538 { ccNone, DoGlobalZP },
1541 { ccKeepToken, DoConditionals }, /* .IF */
1542 { ccKeepToken, DoConditionals }, /* .IFBLANK */
1543 { ccKeepToken, DoConditionals }, /* .IFCONST */
1544 { ccKeepToken, DoConditionals }, /* .IFDEF */
1545 { ccKeepToken, DoConditionals }, /* .IFNBLANK */
1546 { ccKeepToken, DoConditionals }, /* .IFNCONST */
1547 { ccKeepToken, DoConditionals }, /* .IFNDEF */
1548 { ccKeepToken, DoConditionals }, /* .IFNREF */
1549 { ccKeepToken, DoConditionals }, /* .IFP02 */
1550 { ccKeepToken, DoConditionals }, /* .IFP816 */
1551 { ccKeepToken, DoConditionals }, /* .IFPC02 */
1552 { ccKeepToken, DoConditionals }, /* .IFPSC02 */
1553 { ccKeepToken, DoConditionals }, /* .IFREF */
1554 { ccNone, DoImport },
1555 { ccNone, DoImportZP },
1556 { ccNone, DoIncBin },
1557 { ccNone, DoInclude },
1558 { ccNone, DoInvalid }, /* .LEFT */
1559 { ccNone, DoLineCont },
1561 { ccNone, DoListBytes },
1562 { ccNone, DoUnexpected }, /* .LOCAL */
1563 { ccNone, DoLocalChar },
1564 { ccNone, DoMacPack },
1565 { ccNone, DoMacro },
1566 { ccNone, DoUnexpected }, /* .MATCH */
1567 { ccNone, DoInvalid }, /* .MID */
1573 { ccNone, DoPageLength },
1574 { ccNone, DoUnexpected }, /* .PARAMCOUNT */
1576 { ccNone, DoPopSeg },
1578 { ccNone, DoPSC02 },
1579 { ccNone, DoPushSeg },
1580 { ccNone, DoUnexpected }, /* .REFERENCED */
1581 { ccNone, DoReloc },
1582 { ccNone, DoRepeat },
1584 { ccNone, DoInvalid }, /* .RIGHT */
1585 { ccNone, DoROData },
1586 { ccNone, DoSegment },
1587 { ccNone, DoSetCPU },
1588 { ccNone, DoSmart },
1589 { ccNone, DoUnexpected }, /* .STRAT */
1590 { ccNone, DoUnexpected }, /* .STRING */
1591 { ccNone, DoUnexpected }, /* .STRLEN */
1592 { ccNone, DoSunPlus },
1593 { ccNone, DoUnexpected }, /* .TCOUNT */
1594 { ccNone, DoUnexpected }, /* .TIME */
1595 { ccNone, DoUnexpected }, /* .VERSION */
1596 { ccNone, DoWarning },
1598 { ccNone, DoUnexpected }, /* .XMATCH */
1599 { ccNone, DoZeropage },
1604 /*****************************************************************************/
1606 /*****************************************************************************/
1610 int TokIsPseudo (unsigned Tok)
1611 /* Return true if the given token is a pseudo instruction token */
1613 return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO);
1618 void HandlePseudo (void)
1619 /* Handle a pseudo instruction */
1623 /* Calculate the index into the table */
1624 unsigned Index = Tok - TOK_FIRSTPSEUDO;
1627 if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
1628 Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
1629 PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
1631 CHECK (Index < PSEUDO_COUNT);
1633 /* Get the pseudo intruction descriptor */
1634 D = &CtrlCmdTab [Index];
1636 /* Remember the instruction, then skip it if needed */
1637 if ((D->Flags & ccKeepToken) == 0) {
1638 strcpy (Keyword+1, SVal);
1642 /* Call the handler */
1648 void SegStackCheck (void)
1649 /* Check if the segment stack is empty at end of assembly */
1651 if (CollCount (&SegStack) != 0) {
1652 Error (ERR_SEGSTACK_NOT_EMPTY);