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"
76 /*****************************************************************************/
78 /*****************************************************************************/
82 /* Keyword we're about to handle */
83 static char Keyword [sizeof (SVal)+1] = ".";
86 #define MAX_PUSHED_SEGMENTS 16
87 static Collection SegStack = STATIC_COLLECTION_INITIALIZER;
91 /*****************************************************************************/
93 /*****************************************************************************/
97 static void DoUnexpected (void);
98 /* Got an unexpected keyword */
100 static void DoInvalid (void);
101 /* Handle a token that is invalid here, since it should have been handled on
102 * a much lower level of the expression hierarchy. Getting this sort of token
103 * means that the lower level code has bugs.
104 * This function differs to DoUnexpected in that the latter may be triggered
105 * by the user by using keywords in the wrong location. DoUnexpected is not
106 * an error in the assembler itself, while DoInvalid is.
111 /*****************************************************************************/
112 /* Helper functions */
113 /*****************************************************************************/
117 static void SetBoolOption (unsigned char* Flag)
118 /* Read a on/off/+/- option and set flag accordingly */
120 static const char* Keys[] = {
125 if (Tok == TOK_PLUS) {
128 } else if (Tok == TOK_MINUS) {
131 } else if (Tok == TOK_IDENT) {
132 /* Map the keyword to a number */
133 switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
134 case 0: *Flag = 0; NextTok (); break;
135 case 1: *Flag = 1; NextTok (); break;
136 default: ErrorSkip (ERR_ONOFF_EXPECTED); break;
138 } else if (TokIsSep (Tok)) {
139 /* Without anything assume switch on */
142 ErrorSkip (ERR_ONOFF_EXPECTED);
148 static void ExportImport (void (*SymFunc) (const char*))
149 /* Export or import symbols */
152 if (Tok != TOK_IDENT) {
153 ErrorSkip (ERR_IDENT_EXPECTED);
158 if (Tok == TOK_COMMA) {
168 static long IntArg (long Min, long Max)
169 /* Read an integer argument and check a range. Accept the token "unlimited"
170 * and return -1 in this case.
173 if (Tok == TOK_IDENT && strcmp (SVal, "unlimited") == 0) {
177 long Val = ConstExpression ();
178 if (Val < Min || Val > Max) {
188 static void ConDes (const char* Name, unsigned Type)
189 /* Parse remaining line for constructor/destructor of the remaining type */
193 /* Optional constructor priority */
194 if (Tok == TOK_COMMA) {
195 /* Priority value follows */
197 Prio = ConstExpression ();
198 if (Prio < CD_PRIO_MIN || Prio > CD_PRIO_MAX) {
199 /* Value out of range */
204 /* Use the default priority value */
208 /* Define the symbol */
209 SymConDes (Name, Type, (unsigned) Prio);
214 /*****************************************************************************/
215 /* Handler functions */
216 /*****************************************************************************/
220 static void DoA16 (void)
221 /* Switch the accu to 16 bit mode (assembler only) */
223 if (GetCPU() != CPU_65816) {
224 Error (ERR_816_MODE_ONLY);
226 /* Immidiate mode has two extension bytes */
227 ExtBytes [AMI_IMM_ACCU] = 2;
233 static void DoA8 (void)
234 /* Switch the accu to 8 bit mode (assembler only) */
236 if (GetCPU() != CPU_65816) {
237 Error (ERR_816_MODE_ONLY);
239 /* Immidiate mode has one extension byte */
240 ExtBytes [AMI_IMM_ACCU] = 1;
246 static void DoAddr (void)
247 /* Define addresses */
250 if (GetCPU() == CPU_65816) {
251 EmitWord (GenWordExpr (Expression ()));
253 /* Do a range check */
254 EmitWord (Expression ());
256 if (Tok != TOK_COMMA) {
266 static void DoAlign (void)
267 /* Align the PC to some boundary */
273 /* Read the alignment value */
274 Align = ConstExpression ();
275 if (Align <= 0 || Align > 0x10000) {
276 ErrorSkip (ERR_RANGE);
280 /* Optional value follows */
281 if (Tok == TOK_COMMA) {
283 Val = ConstExpression ();
284 /* We need a byte value here */
285 if (!IsByteRange (Val)) {
286 ErrorSkip (ERR_RANGE);
293 /* Check if the alignment is a power of two */
294 Bit = BitFind (Align);
295 if (Align != (0x01L << Bit)) {
298 SegAlign (Bit, (int) Val);
304 static void DoASCIIZ (void)
305 /* Define text with a zero terminator */
310 /* Must have a string constant */
311 if (Tok != TOK_STRCON) {
312 ErrorSkip (ERR_STRCON_EXPECTED);
316 /* Get the length of the string constant */
319 /* Translate into target charset and emit */
320 TgtTranslateBuf (SVal, Len);
321 EmitData ((unsigned char*) SVal, Len);
323 if (Tok == TOK_COMMA) {
334 static void DoAssert (void)
335 /* Add an assertion */
337 static const char* ActionTab [] = {
345 /* First we have the expression that has to evaluated */
346 ExprNode* Expr = Expression ();
350 if (Tok != TOK_IDENT) {
351 ErrorSkip (ERR_IDENT_EXPECTED);
354 Action = GetSubKey (ActionTab, sizeof (ActionTab) / sizeof (ActionTab[0]));
360 Action = ASSERT_ACT_WARN;
365 Action = ASSERT_ACT_ERROR;
369 Error (ERR_ILLEGAL_SEG_ATTR);
374 /* Read the message */
375 if (Tok != TOK_STRCON) {
376 ErrorSkip (ERR_STRCON_EXPECTED);
378 AddAssertion (Expr, Action, GetStringId (SVal));
385 static void DoAutoImport (void)
386 /* Mark unresolved symbols as imported */
388 SetBoolOption (&AutoImport);
393 static void DoBss (void)
394 /* Switch to the BSS segment */
401 static void DoByte (void)
405 if (Tok == TOK_STRCON) {
406 /* A string, translate into target charset and emit */
407 unsigned Len = strlen (SVal);
408 TgtTranslateBuf (SVal, Len);
409 EmitData ((unsigned char*) SVal, Len);
412 EmitByte (Expression ());
414 if (Tok != TOK_COMMA) {
418 /* Do smart handling of dangling comma */
419 if (Tok == TOK_SEP) {
420 Error (ERR_UNEXPECTED_EOL);
429 static void DoCase (void)
430 /* Switch the IgnoreCase option */
432 SetBoolOption (&IgnoreCase);
433 IgnoreCase = !IgnoreCase;
438 static void DoCharMap (void)
439 /* Allow custome character mappings */
444 /* Read the index as numerical value */
445 Index = ConstExpression ();
446 if (Index < 1 || Index > 255) {
447 /* Value out of range */
448 ErrorSkip (ERR_RANGE);
455 /* Read the character code */
456 Code = ConstExpression ();
457 if (Code < 1 || Code > 255) {
458 /* Value out of range */
459 ErrorSkip (ERR_RANGE);
463 /* Set the character translation */
464 TgtTranslateSet ((unsigned) Index, (unsigned char) Code);
469 static void DoCode (void)
470 /* Switch to the code segment */
472 UseSeg (&CodeSegDef);
477 static void DoConDes (void)
478 /* Export a symbol as constructor/destructor */
480 static const char* Keys[] = {
484 char Name [sizeof (SVal)];
487 /* Symbol name follows */
488 if (Tok != TOK_IDENT) {
489 ErrorSkip (ERR_IDENT_EXPECTED);
495 /* Type follows. May be encoded as identifier or numerical */
497 if (Tok == TOK_IDENT) {
499 /* Map the following keyword to a number, then skip it */
500 Type = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
503 /* Check if we got a valid keyword */
512 /* Read the type as numerical value */
513 Type = ConstExpression ();
514 if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) {
515 /* Value out of range */
522 /* Parse the remainder of the line and export the symbol */
523 ConDes (Name, (unsigned) Type);
528 static void DoConstructor (void)
529 /* Export a symbol as constructor */
531 char Name [sizeof (SVal)];
533 /* Symbol name follows */
534 if (Tok != TOK_IDENT) {
535 ErrorSkip (ERR_IDENT_EXPECTED);
541 /* Parse the remainder of the line and export the symbol */
542 ConDes (Name, CD_TYPE_CON);
547 static void DoData (void)
548 /* Switch to the data segment */
550 UseSeg (&DataSegDef);
555 static void DoDbg (void)
556 /* Add debug information from high level code */
558 static const char* Keys[] = {
566 /* We expect a subkey */
567 if (Tok != TOK_IDENT) {
568 ErrorSkip (ERR_IDENT_EXPECTED);
572 /* Map the following keyword to a number */
573 Key = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
575 /* Skip the subkey */
578 /* Check the key and dispatch to a handler */
580 case 0: DbgInfoFile (); break;
581 case 1: DbgInfoLine (); break;
582 case 2: DbgInfoSym (); break;
583 default: ErrorSkip (ERR_SYNTAX); break;
589 static void DoDByt (void)
590 /* Output double bytes */
593 EmitWord (GenSwapExpr (Expression ()));
594 if (Tok != TOK_COMMA) {
604 static void DoDebugInfo (void)
605 /* Switch debug info on or off */
607 SetBoolOption (&DbgSyms);
612 static void DoDefine (void)
613 /* Define a one line macro */
615 MacDef (MAC_STYLE_DEFINE);
620 static void DoDestructor (void)
621 /* Export a symbol as destructor */
623 char Name [sizeof (SVal)];
625 /* Symbol name follows */
626 if (Tok != TOK_IDENT) {
627 ErrorSkip (ERR_IDENT_EXPECTED);
633 /* Parse the remainder of the line and export the symbol */
634 ConDes (Name, CD_TYPE_DES);
639 static void DoDWord (void)
643 EmitDWord (Expression ());
644 if (Tok != TOK_COMMA) {
654 static void DoEnd (void)
655 /* End of assembly */
663 static void DoEndProc (void)
664 /* Leave a lexical level */
666 if (!SymIsLocalLevel ()) {
668 ErrorSkip (ERR_NO_OPEN_PROC);
676 static void DoError (void)
679 if (Tok != TOK_STRCON) {
680 ErrorSkip (ERR_STRCON_EXPECTED);
682 Error (ERR_USER, SVal);
689 static void DoExitMacro (void)
690 /* Exit a macro expansion */
692 if (!InMacExpansion ()) {
693 /* We aren't expanding a macro currently */
702 static void DoExport (void)
703 /* Export a symbol */
705 ExportImport (SymExport);
710 static void DoExportZP (void)
711 /* Export a zeropage symbol */
713 ExportImport (SymExportZP);
718 static void DoFarAddr (void)
719 /* Define far addresses (24 bit) */
722 EmitFarAddr (Expression ());
723 if (Tok != TOK_COMMA) {
733 static void DoFeature (void)
734 /* Switch the Feature option */
736 /* Allow a list of comma separated keywords */
739 /* We expect an identifier */
740 if (Tok != TOK_IDENT) {
741 ErrorSkip (ERR_IDENT_EXPECTED);
745 /* Make the string attribute lower case */
748 /* Set the feature and check for errors */
749 if (SetFeature (SVal) == FEAT_UNKNOWN) {
751 ErrorSkip (ERR_ILLEGAL_FEATURE);
754 /* Skip the keyword */
758 /* Allow more than one keyword */
759 if (Tok == TOK_COMMA) {
769 static void DoFileOpt (void)
770 /* Insert a file option */
774 /* The option type may be given as a keyword or as a number. */
775 if (Tok == TOK_IDENT) {
777 /* Option given as keyword */
778 static const char* Keys [] = {
779 "AUTHOR", "COMMENT", "COMPILER"
782 /* Map the option to a number */
783 OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
786 ErrorSkip (ERR_OPTION_KEY_EXPECTED);
790 /* Skip the keyword */
793 /* Must be followed by a comma */
796 /* We accept only string options for now */
797 if (Tok != TOK_STRCON) {
798 ErrorSkip (ERR_STRCON_EXPECTED);
802 /* Insert the option */
821 Internal ("Invalid OptNum: %ld", OptNum);
830 /* Option given as number */
831 OptNum = ConstExpression ();
832 if (!IsByteRange (OptNum)) {
833 ErrorSkip (ERR_RANGE);
837 /* Must be followed by a comma */
840 /* We accept only string options for now */
841 if (Tok != TOK_STRCON) {
842 ErrorSkip (ERR_STRCON_EXPECTED);
846 /* Insert the option */
847 OptStr ((unsigned char) OptNum, SVal);
856 static void DoForceImport (void)
857 /* Do a forced import on a symbol */
859 ExportImport (SymImportForced);
864 static void DoGlobal (void)
865 /* Declare a global symbol */
867 ExportImport (SymGlobal);
872 static void DoGlobalZP (void)
873 /* Declare a global zeropage symbol */
875 ExportImport (SymGlobalZP);
880 static void DoI16 (void)
881 /* Switch the index registers to 16 bit mode (assembler only) */
883 if (GetCPU() != CPU_65816) {
884 Error (ERR_816_MODE_ONLY);
886 /* Immidiate mode has two extension bytes */
887 ExtBytes [AMI_IMM_INDEX] = 2;
893 static void DoI8 (void)
894 /* Switch the index registers to 16 bit mode (assembler only) */
896 if (GetCPU() != CPU_65816) {
897 Error (ERR_816_MODE_ONLY);
899 /* Immidiate mode has one extension byte */
900 ExtBytes [AMI_IMM_INDEX] = 1;
906 static void DoImport (void)
907 /* Import a symbol */
909 ExportImport (SymImport);
914 static void DoImportZP (void)
915 /* Import a zero page symbol */
917 ExportImport (SymImportZP);
922 static void DoIncBin (void)
923 /* Include a binary file */
925 char Name [sizeof (SVal)];
931 /* Name must follow */
932 if (Tok != TOK_STRCON) {
933 ErrorSkip (ERR_STRCON_EXPECTED);
939 /* A starting offset may follow */
940 if (Tok == TOK_COMMA) {
942 Start = ConstExpression ();
944 /* And a length may follow */
945 if (Tok == TOK_COMMA) {
947 Count = ConstExpression ();
952 /* Try to open the file */
953 F = fopen (Name, "rb");
956 /* Search for the file in the include directories. */
957 char* PathName = FindInclude (Name);
958 if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
959 /* Not found or cannot open, print an error and bail out */
960 ErrorSkip (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno));
963 /* Free the allocated memory */
966 /* If we had an error before, bail out now */
972 /* Get the size of the file */
973 fseek (F, 0, SEEK_END);
976 /* If a count was not given, calculate it now */
978 Count = Size - Start;
980 /* Nothing to read - flag this as a range error */
981 ErrorSkip (ERR_RANGE);
985 /* Count was given, check if it is valid */
986 if (Start + Count > Size) {
987 ErrorSkip (ERR_RANGE);
992 /* Seek to the start position */
993 fseek (F, Start, SEEK_SET);
995 /* Read chunks and insert them into the output */
998 unsigned char Buf [1024];
1000 /* Calculate the number of bytes to read */
1001 size_t BytesToRead = (Count > (long)sizeof(Buf))? sizeof(Buf) : (size_t) Count;
1004 size_t BytesRead = fread (Buf, 1, BytesToRead, F);
1005 if (BytesToRead != BytesRead) {
1006 /* Some sort of error */
1007 ErrorSkip (ERR_CANNOT_READ_INCLUDE, Name, strerror (errno));
1011 /* Insert it into the output */
1012 EmitData (Buf, BytesRead);
1014 /* Keep the counters current */
1019 /* Close the file, ignore errors since it's r/o */
1025 static void DoInclude (void)
1026 /* Include another file */
1028 char Name [MAX_STR_LEN+1];
1030 /* Name must follow */
1031 if (Tok != TOK_STRCON) {
1032 ErrorSkip (ERR_STRCON_EXPECTED);
1034 strcpy (Name, SVal);
1036 NewInputFile (Name);
1042 static void DoInvalid (void)
1043 /* Handle a token that is invalid here, since it should have been handled on
1044 * a much lower level of the expression hierarchy. Getting this sort of token
1045 * means that the lower level code has bugs.
1046 * This function differs to DoUnexpected in that the latter may be triggered
1047 * by the user by using keywords in the wrong location. DoUnexpected is not
1048 * an error in the assembler itself, while DoInvalid is.
1051 Internal ("Unexpected token: %s", Keyword);
1056 static void DoLineCont (void)
1057 /* Switch the use of line continuations */
1059 SetBoolOption (&LineCont);
1064 static void DoList (void)
1065 /* Enable/disable the listing */
1067 /* Get the setting */
1069 SetBoolOption (&List);
1071 /* Manage the counter */
1081 static void DoListBytes (void)
1082 /* Set maximum number of bytes to list for one line */
1084 SetListBytes (IntArg (MIN_LIST_BYTES, MAX_LIST_BYTES));
1089 static void DoLocalChar (void)
1090 /* Define the character that starts local labels */
1092 if (Tok != TOK_CHARCON) {
1093 ErrorSkip (ERR_CHARCON_EXPECTED);
1095 if (IVal != '@' && IVal != '?') {
1096 Error (ERR_ILLEGAL_LOCALSTART);
1098 LocalStart = (char) IVal;
1106 static void DoMacPack (void)
1107 /* Insert a macro package */
1109 /* Macro package names */
1110 static const char* Keys [] = {
1119 /* We expect an identifier */
1120 if (Tok != TOK_IDENT) {
1121 ErrorSkip (ERR_IDENT_EXPECTED);
1125 /* Map the keyword to a number */
1126 Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
1129 ErrorSkip (ERR_ILLEGAL_MACPACK);
1133 /* Skip the package name */
1136 /* Insert the package */
1137 InsertMacPack (Package);
1142 static void DoMacro (void)
1143 /* Start a macro definition */
1145 MacDef (MAC_STYLE_CLASSIC);
1150 static void DoNull (void)
1151 /* Switch to the NULL segment */
1153 UseSeg (&NullSegDef);
1158 static void DoOrg (void)
1159 /* Start absolute code */
1161 long PC = ConstExpression ();
1162 if (PC < 0 || PC > 0xFFFFFF) {
1171 static void DoOut (void)
1172 /* Output a string */
1174 if (Tok != TOK_STRCON) {
1175 ErrorSkip (ERR_STRCON_EXPECTED);
1177 /* Output the string and be sure to flush the output to keep it in
1178 * sync with any error messages if the output is redirected to a file.
1180 printf ("%s\n", SVal);
1188 static void DoP02 (void)
1189 /* Switch to 6502 CPU */
1196 static void DoPC02 (void)
1197 /* Switch to 65C02 CPU */
1204 static void DoP816 (void)
1205 /* Switch to 65816 CPU */
1212 static void DoPageLength (void)
1213 /* Set the page length for the listing */
1215 PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
1220 static void DoPopSeg (void)
1221 /* Pop an old segment from the segment stack */
1225 /* Must have a segment on the stack */
1226 if (CollCount (&SegStack) == 0) {
1227 ErrorSkip (ERR_SEGSTACK_EMPTY);
1231 /* Pop the last element */
1232 Def = CollPop (&SegStack);
1234 /* Restore this segment */
1237 /* Delete the segment definition */
1243 static void DoProc (void)
1244 /* Start a new lexical scope */
1246 if (Tok == TOK_IDENT) {
1247 /* The new scope has a name */
1248 unsigned Flags = SYM_LABEL;
1252 SymDef (SVal, GenCurrentPC (), Flags);
1253 SymEnterLevel (SVal);
1256 char Buf[sizeof (SVal)];
1257 SymEnterLevel (AnonName (Buf, sizeof (Buf), "Scope"));
1263 static void DoPSC02 (void)
1264 /* Switch to 65SC02 CPU */
1266 SetCPU (CPU_65SC02);
1271 static void DoPushSeg (void)
1272 /* Push the current segment onto the segment stack */
1274 /* Can only push a limited size of segments */
1275 if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) {
1276 ErrorSkip (ERR_SEGSTACK_OVERFLOW);
1280 /* Get the current segment and push it */
1281 CollAppend (&SegStack, DupSegDef (GetCurrentSeg ()));
1286 static void DoReloc (void)
1287 /* Enter relocatable mode */
1294 static void DoRepeat (void)
1295 /* Repeat some instruction block */
1302 static void DoRes (void)
1303 /* Reserve some number of storage bytes */
1308 Count = ConstExpression ();
1309 if (Count > 0xFFFF || Count < 0) {
1310 ErrorSkip (ERR_RANGE);
1313 if (Tok == TOK_COMMA) {
1315 Val = ConstExpression ();
1316 /* We need a byte value here */
1317 if (!IsByteRange (Val)) {
1318 ErrorSkip (ERR_RANGE);
1322 /* Emit constant values */
1324 Emit0 ((unsigned char) Val);
1328 /* Emit fill fragments */
1335 static void DoROData (void)
1336 /* Switch to the r/o data segment */
1338 UseSeg (&RODataSegDef);
1343 static void DoSegment (void)
1344 /* Switch to another segment */
1346 static const char* AttrTab [] = {
1347 "ZEROPAGE", "DIRECT",
1351 char Name [sizeof (SVal)];
1354 Def.Type = SEGTYPE_DEFAULT;
1356 if (Tok != TOK_STRCON) {
1357 ErrorSkip (ERR_STRCON_EXPECTED);
1360 /* Save the name of the segment and skip it */
1361 strcpy (Name, SVal);
1364 /* Check for an optional segment attribute */
1365 if (Tok == TOK_COMMA) {
1367 if (Tok != TOK_IDENT) {
1368 ErrorSkip (ERR_IDENT_EXPECTED);
1370 int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0]));
1376 Def.Type = SEGTYPE_ZP;
1381 Def.Type = SEGTYPE_ABS;
1387 Def.Type = SEGTYPE_FAR;
1391 Error (ERR_ILLEGAL_SEG_ATTR);
1397 /* Set the segment */
1404 static void DoSetCPU (void)
1405 /* Switch the CPU instruction set */
1407 /* We expect an identifier */
1408 if (Tok != TOK_STRCON) {
1409 ErrorSkip (ERR_STRCON_EXPECTED);
1411 /* Try to find the CPU, then skip the identifier */
1412 cpu_t CPU = FindCPU (SVal);
1415 /* Switch to the new CPU */
1422 static void DoSmart (void)
1423 /* Smart mode on/off */
1425 SetBoolOption (&SmartMode);
1430 static void DoStruct (void)
1431 /* Struct definition */
1433 Error (ERR_NOT_IMPLEMENTED);
1438 static void DoSunPlus (void)
1439 /* Switch to the SUNPLUS CPU */
1441 SetCPU (CPU_SUNPLUS);
1446 static void DoUnion (void)
1447 /* Union definition */
1449 Error (ERR_NOT_IMPLEMENTED);
1454 static void DoUnexpected (void)
1455 /* Got an unexpected keyword */
1457 Error (ERR_UNEXPECTED, Keyword);
1463 static void DoWarning (void)
1466 if (Tok != TOK_STRCON) {
1467 ErrorSkip (ERR_STRCON_EXPECTED);
1469 Warning (WARN_USER, SVal);
1476 static void DoWord (void)
1480 EmitWord (Expression ());
1481 if (Tok != TOK_COMMA) {
1491 static void DoZeropage (void)
1492 /* Switch to the zeropage segment */
1494 UseSeg (&ZeropageSegDef);
1499 /*****************************************************************************/
1501 /*****************************************************************************/
1505 /* Control commands flags */
1507 ccNone = 0x0000, /* No special flags */
1508 ccKeepToken = 0x0001 /* Do not skip the current token */
1511 /* Control command table */
1512 typedef struct CtrlDesc CtrlDesc;
1514 unsigned Flags; /* Flags for this directive */
1515 void (*Handler) (void); /* Command handler */
1518 #define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
1519 static CtrlDesc CtrlCmdTab [] = {
1522 { ccNone, DoAddr }, /* .ADDR */
1523 { ccNone, DoAlign },
1524 { ccNone, DoASCIIZ },
1525 { ccNone, DoAssert },
1526 { ccNone, DoAutoImport },
1527 { ccNone, DoUnexpected }, /* .BLANK */
1531 { ccNone, DoCharMap },
1533 { ccNone, DoUnexpected, }, /* .CONCAT */
1534 { ccNone, DoConDes },
1535 { ccNone, DoUnexpected }, /* .CONST */
1536 { ccNone, DoConstructor },
1537 { ccNone, DoUnexpected }, /* .CPU */
1541 { ccNone, DoDebugInfo },
1542 { ccNone, DoDefine },
1543 { ccNone, DoUnexpected }, /* .DEFINED */
1544 { ccNone, DoDestructor },
1545 { ccNone, DoDWord },
1546 { ccKeepToken, DoConditionals }, /* .ELSE */
1547 { ccKeepToken, DoConditionals }, /* .ELSEIF */
1548 { ccKeepToken, DoEnd },
1549 { ccKeepToken, DoConditionals }, /* .ENDIF */
1550 { ccNone, DoUnexpected }, /* .ENDMACRO */
1551 { ccNone, DoEndProc },
1552 { ccNone, DoUnexpected }, /* .ENDREPEAT */
1553 { ccNone, DoUnexpected }, /* .ENDSTRUCT */
1554 { ccNone, DoError },
1555 { ccNone, DoExitMacro },
1556 { ccNone, DoExport },
1557 { ccNone, DoExportZP },
1558 { ccNone, DoFarAddr },
1559 { ccNone, DoFeature },
1560 { ccNone, DoFileOpt },
1561 { ccNone, DoForceImport },
1562 { ccNone, DoUnexpected }, /* .FORCEWORD */
1563 { ccNone, DoGlobal },
1564 { ccNone, DoGlobalZP },
1567 { ccKeepToken, DoConditionals }, /* .IF */
1568 { ccKeepToken, DoConditionals }, /* .IFBLANK */
1569 { ccKeepToken, DoConditionals }, /* .IFCONST */
1570 { ccKeepToken, DoConditionals }, /* .IFDEF */
1571 { ccKeepToken, DoConditionals }, /* .IFNBLANK */
1572 { ccKeepToken, DoConditionals }, /* .IFNCONST */
1573 { ccKeepToken, DoConditionals }, /* .IFNDEF */
1574 { ccKeepToken, DoConditionals }, /* .IFNREF */
1575 { ccKeepToken, DoConditionals }, /* .IFP02 */
1576 { ccKeepToken, DoConditionals }, /* .IFP816 */
1577 { ccKeepToken, DoConditionals }, /* .IFPC02 */
1578 { ccKeepToken, DoConditionals }, /* .IFPSC02 */
1579 { ccKeepToken, DoConditionals }, /* .IFREF */
1580 { ccNone, DoImport },
1581 { ccNone, DoImportZP },
1582 { ccNone, DoIncBin },
1583 { ccNone, DoInclude },
1584 { ccNone, DoInvalid }, /* .LEFT */
1585 { ccNone, DoLineCont },
1587 { ccNone, DoListBytes },
1588 { ccNone, DoUnexpected }, /* .LOCAL */
1589 { ccNone, DoLocalChar },
1590 { ccNone, DoMacPack },
1591 { ccNone, DoMacro },
1592 { ccNone, DoUnexpected }, /* .MATCH */
1593 { ccNone, DoInvalid }, /* .MID */
1599 { ccNone, DoPageLength },
1600 { ccNone, DoUnexpected }, /* .PARAMCOUNT */
1602 { ccNone, DoPopSeg },
1604 { ccNone, DoPSC02 },
1605 { ccNone, DoPushSeg },
1606 { ccNone, DoUnexpected }, /* .REFERENCED */
1607 { ccNone, DoReloc },
1608 { ccNone, DoRepeat },
1610 { ccNone, DoInvalid }, /* .RIGHT */
1611 { ccNone, DoROData },
1612 { ccNone, DoSegment },
1613 { ccNone, DoSetCPU },
1614 { ccNone, DoSmart },
1615 { ccNone, DoUnexpected }, /* .STRAT */
1616 { ccNone, DoUnexpected }, /* .STRING */
1617 { ccNone, DoUnexpected }, /* .STRLEN */
1618 { ccNone, DoStruct },
1619 { ccNone, DoSunPlus },
1620 { ccNone, DoUnexpected }, /* .TAG */
1621 { ccNone, DoUnexpected }, /* .TCOUNT */
1622 { ccNone, DoUnexpected }, /* .TIME */
1623 { ccNone, DoUnion },
1624 { ccNone, DoUnexpected }, /* .VERSION */
1625 { ccNone, DoWarning },
1627 { ccNone, DoUnexpected }, /* .XMATCH */
1628 { ccNone, DoZeropage },
1633 /*****************************************************************************/
1635 /*****************************************************************************/
1639 int TokIsPseudo (unsigned Tok)
1640 /* Return true if the given token is a pseudo instruction token */
1642 return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO);
1647 void HandlePseudo (void)
1648 /* Handle a pseudo instruction */
1652 /* Calculate the index into the table */
1653 unsigned Index = Tok - TOK_FIRSTPSEUDO;
1656 if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
1657 Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
1658 PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
1660 CHECK (Index < PSEUDO_COUNT);
1662 /* Get the pseudo intruction descriptor */
1663 D = &CtrlCmdTab [Index];
1665 /* Remember the instruction, then skip it if needed */
1666 if ((D->Flags & ccKeepToken) == 0) {
1667 strcpy (Keyword+1, SVal);
1671 /* Call the handler */
1677 void SegStackCheck (void)
1678 /* Check if the segment stack is empty at end of assembly */
1680 if (CollCount (&SegStack) != 0) {
1681 Error (ERR_SEGSTACK_NOT_EMPTY);