1 /*****************************************************************************/
5 /* Pseudo instructions for the ca65 macroassembler */
9 /* (C) 1998-2003 Ullrich von Bassewitz */
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 unsigned char OptionalAddrSize (void)
118 /* If a colon follows, parse an optional address size spec and return it.
119 * Otherwise return ADDR_SIZE_DEFAULT.
122 unsigned AddrSize = ADDR_SIZE_DEFAULT;
123 if (Tok == TOK_COLON) {
125 AddrSize = ParseAddrSize ();
133 static void SetBoolOption (unsigned char* Flag)
134 /* Read a on/off/+/- option and set flag accordingly */
136 static const char* Keys[] = {
141 if (Tok == TOK_PLUS) {
144 } else if (Tok == TOK_MINUS) {
147 } else if (Tok == TOK_IDENT) {
148 /* Map the keyword to a number */
149 switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
150 case 0: *Flag = 0; NextTok (); break;
151 case 1: *Flag = 1; NextTok (); break;
152 default: ErrorSkip ("`on' or `off' expected"); break;
154 } else if (TokIsSep (Tok)) {
155 /* Without anything assume switch on */
158 ErrorSkip ("`on' or `off' expected");
164 static void ExportImport (void (*Func) (SymEntry*, unsigned char, unsigned),
165 unsigned char DefAddrSize, unsigned Flags)
166 /* Export or import symbols */
169 unsigned char AddrSize;
173 /* We need an identifier here */
174 if (Tok != TOK_IDENT) {
175 ErrorSkip ("Identifier expected");
179 /* Find the symbol table entry, allocate a new one if necessary */
180 Sym = SymFind (CurrentScope, SVal, SYM_ALLOC_NEW);
185 /* Get an optional address size */
186 AddrSize = OptionalAddrSize ();
187 if (AddrSize == ADDR_SIZE_DEFAULT) {
188 AddrSize = DefAddrSize;
191 /* Call the actual import/export function */
192 Func (Sym, AddrSize, Flags);
195 if (Tok == TOK_COMMA) {
205 static long IntArg (long Min, long Max)
206 /* Read an integer argument and check a range. Accept the token "unlimited"
207 * and return -1 in this case.
210 if (Tok == TOK_IDENT && strcmp (SVal, "unlimited") == 0) {
214 long Val = ConstExpression ();
215 if (Val < Min || Val > Max) {
216 Error ("Range error");
225 static void ConDes (const char* Name, unsigned Type)
226 /* Parse remaining line for constructor/destructor of the remaining type */
231 /* Find the symbol table entry, allocate a new one if necessary */
232 SymEntry* Sym = SymFind (CurrentScope, Name, SYM_ALLOC_NEW);
234 /* Optional constructor priority */
235 if (Tok == TOK_COMMA) {
236 /* Priority value follows */
238 Prio = ConstExpression ();
239 if (Prio < CD_PRIO_MIN || Prio > CD_PRIO_MAX) {
240 /* Value out of range */
241 Error ("Range error");
245 /* Use the default priority value */
249 /* Define the symbol */
250 SymConDes (Sym, ADDR_SIZE_DEFAULT, Type, (unsigned) Prio);
255 /*****************************************************************************/
256 /* Handler functions */
257 /*****************************************************************************/
261 static void DoA16 (void)
262 /* Switch the accu to 16 bit mode (assembler only) */
264 if (GetCPU() != CPU_65816) {
265 Error ("Command is only valid in 65816 mode");
267 /* Immidiate mode has two extension bytes */
268 ExtBytes [AMI_IMM_ACCU] = 2;
274 static void DoA8 (void)
275 /* Switch the accu to 8 bit mode (assembler only) */
277 if (GetCPU() != CPU_65816) {
278 Error ("Command is only valid in 65816 mode");
280 /* Immidiate mode has one extension byte */
281 ExtBytes [AMI_IMM_ACCU] = 1;
287 static void DoAddr (void)
288 /* Define addresses */
291 if (GetCPU() == CPU_65816) {
292 EmitWord (GenWordExpr (Expression ()));
294 /* Do a range check */
295 EmitWord (Expression ());
297 if (Tok != TOK_COMMA) {
307 static void DoAlign (void)
308 /* Align the PC to some boundary */
314 /* Read the alignment value */
315 Align = ConstExpression ();
316 if (Align <= 0 || Align > 0x10000) {
317 ErrorSkip ("Range error");
321 /* Optional value follows */
322 if (Tok == TOK_COMMA) {
324 Val = ConstExpression ();
325 /* We need a byte value here */
326 if (!IsByteRange (Val)) {
327 ErrorSkip ("Range error");
334 /* Check if the alignment is a power of two */
335 Bit = BitFind (Align);
336 if (Align != (0x01L << Bit)) {
337 Error ("Alignment value must be a power of 2");
339 SegAlign (Bit, (int) Val);
345 static void DoASCIIZ (void)
346 /* Define text with a zero terminator */
351 /* Must have a string constant */
352 if (Tok != TOK_STRCON) {
353 ErrorSkip ("String constant expected");
357 /* Get the length of the string constant */
360 /* Translate into target charset and emit */
361 TgtTranslateBuf (SVal, Len);
362 EmitData ((unsigned char*) SVal, Len);
364 if (Tok == TOK_COMMA) {
375 static void DoAssert (void)
376 /* Add an assertion */
378 static const char* ActionTab [] = {
386 /* First we have the expression that has to evaluated */
387 ExprNode* Expr = Expression ();
391 if (Tok != TOK_IDENT) {
392 ErrorSkip ("Identifier expected");
395 Action = GetSubKey (ActionTab, sizeof (ActionTab) / sizeof (ActionTab[0]));
401 Action = ASSERT_ACT_WARN;
406 Action = ASSERT_ACT_ERROR;
410 Error ("Illegal assert action specifier");
415 /* Read the message */
416 if (Tok != TOK_STRCON) {
417 ErrorSkip ("String constant expected");
419 AddAssertion (Expr, Action, GetStringId (SVal));
426 static void DoAutoImport (void)
427 /* Mark unresolved symbols as imported */
429 SetBoolOption (&AutoImport);
434 static void DoBss (void)
435 /* Switch to the BSS segment */
442 static void DoByte (void)
446 if (Tok == TOK_STRCON) {
447 /* A string, translate into target charset and emit */
448 unsigned Len = strlen (SVal);
449 TgtTranslateBuf (SVal, Len);
450 EmitData ((unsigned char*) SVal, Len);
453 EmitByte (Expression ());
455 if (Tok != TOK_COMMA) {
459 /* Do smart handling of dangling comma */
460 if (Tok == TOK_SEP) {
461 Error ("Unexpected end of line");
470 static void DoCase (void)
471 /* Switch the IgnoreCase option */
473 SetBoolOption (&IgnoreCase);
474 IgnoreCase = !IgnoreCase;
479 static void DoCharMap (void)
480 /* Allow custome character mappings */
485 /* Read the index as numerical value */
486 Index = ConstExpression ();
487 if (Index < 1 || Index > 255) {
488 /* Value out of range */
489 ErrorSkip ("Range error");
496 /* Read the character code */
497 Code = ConstExpression ();
498 if (Code < 1 || Code > 255) {
499 /* Value out of range */
500 ErrorSkip ("Range error");
504 /* Set the character translation */
505 TgtTranslateSet ((unsigned) Index, (unsigned char) Code);
510 static void DoCode (void)
511 /* Switch to the code segment */
513 UseSeg (&CodeSegDef);
518 static void DoConDes (void)
519 /* Export a symbol as constructor/destructor */
521 static const char* Keys[] = {
525 char Name [sizeof (SVal)];
528 /* Symbol name follows */
529 if (Tok != TOK_IDENT) {
530 ErrorSkip ("Identifier expected");
536 /* Type follows. May be encoded as identifier or numerical */
538 if (Tok == TOK_IDENT) {
540 /* Map the following keyword to a number, then skip it */
541 Type = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
544 /* Check if we got a valid keyword */
546 Error ("Syntax error");
553 /* Read the type as numerical value */
554 Type = ConstExpression ();
555 if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) {
556 /* Value out of range */
557 Error ("Range error");
563 /* Parse the remainder of the line and export the symbol */
564 ConDes (Name, (unsigned) Type);
569 static void DoConstructor (void)
570 /* Export a symbol as constructor */
572 char Name [sizeof (SVal)];
574 /* Symbol name follows */
575 if (Tok != TOK_IDENT) {
576 ErrorSkip ("Identifier expected");
582 /* Parse the remainder of the line and export the symbol */
583 ConDes (Name, CD_TYPE_CON);
588 static void DoData (void)
589 /* Switch to the data segment */
591 UseSeg (&DataSegDef);
596 static void DoDbg (void)
597 /* Add debug information from high level code */
599 static const char* Keys[] = {
607 /* We expect a subkey */
608 if (Tok != TOK_IDENT) {
609 ErrorSkip ("Identifier expected");
613 /* Map the following keyword to a number */
614 Key = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
616 /* Skip the subkey */
619 /* Check the key and dispatch to a handler */
621 case 0: DbgInfoFile (); break;
622 case 1: DbgInfoLine (); break;
623 case 2: DbgInfoSym (); break;
624 default: ErrorSkip ("Syntax error"); break;
630 static void DoDByt (void)
631 /* Output double bytes */
634 EmitWord (GenSwapExpr (Expression ()));
635 if (Tok != TOK_COMMA) {
645 static void DoDebugInfo (void)
646 /* Switch debug info on or off */
648 SetBoolOption (&DbgSyms);
653 static void DoDefine (void)
654 /* Define a one line macro */
656 MacDef (MAC_STYLE_DEFINE);
661 static void DoDestructor (void)
662 /* Export a symbol as destructor */
664 char Name [sizeof (SVal)];
666 /* Symbol name follows */
667 if (Tok != TOK_IDENT) {
668 ErrorSkip ("Identifier expected");
674 /* Parse the remainder of the line and export the symbol */
675 ConDes (Name, CD_TYPE_DES);
680 static void DoDWord (void)
684 EmitDWord (Expression ());
685 if (Tok != TOK_COMMA) {
695 static void DoEnd (void)
696 /* End of assembly */
704 static void DoEndProc (void)
705 /* Leave a lexical level */
707 if (CurrentScope == RootScope || GetCurrentSymTabType () != ST_PROC) {
709 ErrorSkip ("No open .PROC");
717 static void DoEndScope (void)
718 /* Leave a lexical level */
720 if (CurrentScope == RootScope || GetCurrentSymTabType () != ST_SCOPE) {
722 ErrorSkip ("No open .SCOPE");
730 static void DoError (void)
733 if (Tok != TOK_STRCON) {
734 ErrorSkip ("String constant expected");
736 Error ("User error: %s", SVal);
743 static void DoExitMacro (void)
744 /* Exit a macro expansion */
746 if (!InMacExpansion ()) {
747 /* We aren't expanding a macro currently */
756 static void DoExport (void)
757 /* Export a symbol */
759 ExportImport (SymExport, ADDR_SIZE_DEFAULT, SF_NONE);
764 static void DoExportZP (void)
765 /* Export a zeropage symbol */
767 ExportImport (SymExport, ADDR_SIZE_ZP, SF_NONE);
772 static void DoFarAddr (void)
773 /* Define far addresses (24 bit) */
776 EmitFarAddr (Expression ());
777 if (Tok != TOK_COMMA) {
787 static void DoFeature (void)
788 /* Switch the Feature option */
790 /* Allow a list of comma separated keywords */
793 /* We expect an identifier */
794 if (Tok != TOK_IDENT) {
795 ErrorSkip ("Identifier expected");
799 /* Make the string attribute lower case */
802 /* Set the feature and check for errors */
803 if (SetFeature (SVal) == FEAT_UNKNOWN) {
805 ErrorSkip ("Invalid feature: `%s'", SVal);
808 /* Skip the keyword */
812 /* Allow more than one keyword */
813 if (Tok == TOK_COMMA) {
823 static void DoFileOpt (void)
824 /* Insert a file option */
828 /* The option type may be given as a keyword or as a number. */
829 if (Tok == TOK_IDENT) {
831 /* Option given as keyword */
832 static const char* Keys [] = {
833 "AUTHOR", "COMMENT", "COMPILER"
836 /* Map the option to a number */
837 OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
840 ErrorSkip ("File option keyword expected");
844 /* Skip the keyword */
847 /* Must be followed by a comma */
850 /* We accept only string options for now */
851 if (Tok != TOK_STRCON) {
852 ErrorSkip ("String constant expected");
856 /* Insert the option */
875 Internal ("Invalid OptNum: %ld", OptNum);
884 /* Option given as number */
885 OptNum = ConstExpression ();
886 if (!IsByteRange (OptNum)) {
887 ErrorSkip ("Range error");
891 /* Must be followed by a comma */
894 /* We accept only string options for now */
895 if (Tok != TOK_STRCON) {
896 ErrorSkip ("String constant expected");
900 /* Insert the option */
901 OptStr ((unsigned char) OptNum, SVal);
910 static void DoForceImport (void)
911 /* Do a forced import on a symbol */
913 ExportImport (SymImport, ADDR_SIZE_DEFAULT, SF_FORCED);
918 static void DoGlobal (void)
919 /* Declare a global symbol */
921 ExportImport (SymGlobal, ADDR_SIZE_DEFAULT, SF_NONE);
926 static void DoGlobalZP (void)
927 /* Declare a global zeropage symbol */
929 ExportImport (SymGlobal, ADDR_SIZE_ZP, SF_NONE);
934 static void DoI16 (void)
935 /* Switch the index registers to 16 bit mode (assembler only) */
937 if (GetCPU() != CPU_65816) {
938 Error ("Command is only valid in 65816 mode");
940 /* Immidiate mode has two extension bytes */
941 ExtBytes [AMI_IMM_INDEX] = 2;
947 static void DoI8 (void)
948 /* Switch the index registers to 16 bit mode (assembler only) */
950 if (GetCPU() != CPU_65816) {
951 Error ("Command is only valid in 65816 mode");
953 /* Immidiate mode has one extension byte */
954 ExtBytes [AMI_IMM_INDEX] = 1;
960 static void DoImport (void)
961 /* Import a symbol */
963 ExportImport (SymImport, ADDR_SIZE_DEFAULT, SF_NONE);
968 static void DoImportZP (void)
969 /* Import a zero page symbol */
971 ExportImport (SymImport, ADDR_SIZE_ZP, SF_NONE);
976 static void DoIncBin (void)
977 /* Include a binary file */
979 char Name [sizeof (SVal)];
985 /* Name must follow */
986 if (Tok != TOK_STRCON) {
987 ErrorSkip ("String constant expected");
993 /* A starting offset may follow */
994 if (Tok == TOK_COMMA) {
996 Start = ConstExpression ();
998 /* And a length may follow */
999 if (Tok == TOK_COMMA) {
1001 Count = ConstExpression ();
1006 /* Try to open the file */
1007 F = fopen (Name, "rb");
1010 /* Search for the file in the include directories. */
1011 char* PathName = FindInclude (Name);
1012 if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
1013 /* Not found or cannot open, print an error and bail out */
1014 ErrorSkip ("Cannot open include file `%s': %s", Name, strerror (errno));
1017 /* Free the allocated memory */
1020 /* If we had an error before, bail out now */
1026 /* Get the size of the file */
1027 fseek (F, 0, SEEK_END);
1030 /* If a count was not given, calculate it now */
1032 Count = Size - Start;
1034 /* Nothing to read - flag this as a range error */
1035 ErrorSkip ("Range error");
1039 /* Count was given, check if it is valid */
1040 if (Start + Count > Size) {
1041 ErrorSkip ("Range error");
1046 /* Seek to the start position */
1047 fseek (F, Start, SEEK_SET);
1049 /* Read chunks and insert them into the output */
1052 unsigned char Buf [1024];
1054 /* Calculate the number of bytes to read */
1055 size_t BytesToRead = (Count > (long)sizeof(Buf))? sizeof(Buf) : (size_t) Count;
1058 size_t BytesRead = fread (Buf, 1, BytesToRead, F);
1059 if (BytesToRead != BytesRead) {
1060 /* Some sort of error */
1061 ErrorSkip ("Cannot read from include file `%s': %s",
1062 Name, strerror (errno));
1066 /* Insert it into the output */
1067 EmitData (Buf, BytesRead);
1069 /* Keep the counters current */
1074 /* Close the file, ignore errors since it's r/o */
1080 static void DoInclude (void)
1081 /* Include another file */
1083 char Name [MAX_STR_LEN+1];
1085 /* Name must follow */
1086 if (Tok != TOK_STRCON) {
1087 ErrorSkip ("String constant expected");
1089 strcpy (Name, SVal);
1091 NewInputFile (Name);
1097 static void DoInvalid (void)
1098 /* Handle a token that is invalid here, since it should have been handled on
1099 * a much lower level of the expression hierarchy. Getting this sort of token
1100 * means that the lower level code has bugs.
1101 * This function differs to DoUnexpected in that the latter may be triggered
1102 * by the user by using keywords in the wrong location. DoUnexpected is not
1103 * an error in the assembler itself, while DoInvalid is.
1106 Internal ("Unexpected token: %s", Keyword);
1111 static void DoLineCont (void)
1112 /* Switch the use of line continuations */
1114 SetBoolOption (&LineCont);
1119 static void DoList (void)
1120 /* Enable/disable the listing */
1122 /* Get the setting */
1124 SetBoolOption (&List);
1126 /* Manage the counter */
1136 static void DoListBytes (void)
1137 /* Set maximum number of bytes to list for one line */
1139 SetListBytes (IntArg (MIN_LIST_BYTES, MAX_LIST_BYTES));
1144 static void DoLocalChar (void)
1145 /* Define the character that starts local labels */
1147 if (Tok != TOK_CHARCON) {
1148 ErrorSkip ("Character constant expected");
1150 if (IVal != '@' && IVal != '?') {
1151 Error ("Invalid start character for locals");
1153 LocalStart = (char) IVal;
1161 static void DoMacPack (void)
1162 /* Insert a macro package */
1164 /* Macro package names */
1165 static const char* Keys [] = {
1174 /* We expect an identifier */
1175 if (Tok != TOK_IDENT) {
1176 ErrorSkip ("Identifier expected");
1180 /* Map the keyword to a number */
1181 Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
1184 ErrorSkip ("Invalid macro package");
1188 /* Skip the package name */
1191 /* Insert the package */
1192 InsertMacPack (Package);
1197 static void DoMacro (void)
1198 /* Start a macro definition */
1200 MacDef (MAC_STYLE_CLASSIC);
1205 static void DoNull (void)
1206 /* Switch to the NULL segment */
1208 UseSeg (&NullSegDef);
1213 static void DoOrg (void)
1214 /* Start absolute code */
1216 long PC = ConstExpression ();
1217 if (PC < 0 || PC > 0xFFFFFF) {
1218 Error ("Range error");
1226 static void DoOut (void)
1227 /* Output a string */
1229 if (Tok != TOK_STRCON) {
1230 ErrorSkip ("String constant expected");
1232 /* Output the string and be sure to flush the output to keep it in
1233 * sync with any error messages if the output is redirected to a file.
1235 printf ("%s\n", SVal);
1243 static void DoP02 (void)
1244 /* Switch to 6502 CPU */
1251 static void DoPC02 (void)
1252 /* Switch to 65C02 CPU */
1259 static void DoP816 (void)
1260 /* Switch to 65816 CPU */
1267 static void DoPageLength (void)
1268 /* Set the page length for the listing */
1270 PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
1275 static void DoPopSeg (void)
1276 /* Pop an old segment from the segment stack */
1280 /* Must have a segment on the stack */
1281 if (CollCount (&SegStack) == 0) {
1282 ErrorSkip ("Segment stack is empty");
1286 /* Pop the last element */
1287 Def = CollPop (&SegStack);
1289 /* Restore this segment */
1292 /* Delete the segment definition */
1298 static void DoProc (void)
1299 /* Start a new lexical scope */
1301 char Name[sizeof(SVal)];
1302 unsigned char AddrSize;
1304 if (Tok == TOK_IDENT) {
1306 /* The new scope has a name. Remember it. */
1307 strcpy (Name, SVal);
1309 /* Search for the symbol, generate a new one if needed */
1310 SymEntry* Sym = SymFind (CurrentScope, Name, SYM_ALLOC_NEW);
1312 /* Skip the scope name */
1315 /* Read an optional address size specifier */
1316 AddrSize = OptionalAddrSize ();
1318 /* Mark the symbol as defined */
1319 SymDef (Sym, GenCurrentPC (), AddrSize, SF_LABEL);
1323 /* A .PROC statement without a name */
1324 Warning (1, "Unnamed .PROCs are deprecated, please use .SCOPE");
1325 AnonName (Name, sizeof (Name), "PROC");
1326 AddrSize = ADDR_SIZE_DEFAULT;
1330 /* Enter a new scope */
1331 SymEnterLevel (Name, ST_PROC, AddrSize);
1336 static void DoPSC02 (void)
1337 /* Switch to 65SC02 CPU */
1339 SetCPU (CPU_65SC02);
1344 static void DoPushSeg (void)
1345 /* Push the current segment onto the segment stack */
1347 /* Can only push a limited size of segments */
1348 if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) {
1349 ErrorSkip ("Segment stack overflow");
1353 /* Get the current segment and push it */
1354 CollAppend (&SegStack, DupSegDef (GetCurrentSegDef ()));
1359 static void DoReloc (void)
1360 /* Enter relocatable mode */
1367 static void DoRepeat (void)
1368 /* Repeat some instruction block */
1375 static void DoRes (void)
1376 /* Reserve some number of storage bytes */
1381 Count = ConstExpression ();
1382 if (Count > 0xFFFF || Count < 0) {
1383 ErrorSkip ("Range error");
1386 if (Tok == TOK_COMMA) {
1388 Val = ConstExpression ();
1389 /* We need a byte value here */
1390 if (!IsByteRange (Val)) {
1391 ErrorSkip ("Range error");
1395 /* Emit constant values */
1397 Emit0 ((unsigned char) Val);
1401 /* Emit fill fragments */
1408 static void DoROData (void)
1409 /* Switch to the r/o data segment */
1411 UseSeg (&RODataSegDef);
1416 static void DoScope (void)
1417 /* Start a local scope */
1419 char Name[sizeof (SVal)];
1420 unsigned char AddrSize;
1423 if (Tok == TOK_IDENT) {
1425 /* The new scope has a name. Remember and skip it. */
1426 strcpy (Name, SVal);
1431 /* An unnamed scope */
1432 AnonName (Name, sizeof (Name), "SCOPE");
1436 /* Read an optional address size specifier */
1437 AddrSize = OptionalAddrSize ();
1439 /* Enter the new scope */
1440 SymEnterLevel (Name, ST_SCOPE, AddrSize);
1446 static void DoSegment (void)
1447 /* Switch to another segment */
1449 char Name [sizeof (SVal)];
1453 if (Tok != TOK_STRCON) {
1454 ErrorSkip ("String constant expected");
1457 /* Save the name of the segment and skip it */
1458 strcpy (Name, SVal);
1461 /* Check for an optional address size modifier */
1462 Def.AddrSize = OptionalAddrSize ();
1464 /* Set the segment */
1471 static void DoSetCPU (void)
1472 /* Switch the CPU instruction set */
1474 /* We expect an identifier */
1475 if (Tok != TOK_STRCON) {
1476 ErrorSkip ("String constant expected");
1478 /* Try to find the CPU, then skip the identifier */
1479 cpu_t CPU = FindCPU (SVal);
1482 /* Switch to the new CPU */
1489 static void DoSmart (void)
1490 /* Smart mode on/off */
1492 SetBoolOption (&SmartMode);
1497 static void DoStruct (void)
1498 /* Struct definition */
1500 Error ("Not implemented");
1505 static void DoSunPlus (void)
1506 /* Switch to the SUNPLUS CPU */
1508 SetCPU (CPU_SUNPLUS);
1513 static void DoUnion (void)
1514 /* Union definition */
1516 Error ("Not implemented");
1521 static void DoUnexpected (void)
1522 /* Got an unexpected keyword */
1524 Error ("Unexpected `%s'", Keyword);
1530 static void DoWarning (void)
1533 if (Tok != TOK_STRCON) {
1534 ErrorSkip ("String constant expected");
1536 Warning (0, "User warning: %s", SVal);
1543 static void DoWord (void)
1547 EmitWord (Expression ());
1548 if (Tok != TOK_COMMA) {
1558 static void DoZeropage (void)
1559 /* Switch to the zeropage segment */
1561 UseSeg (&ZeropageSegDef);
1566 /*****************************************************************************/
1568 /*****************************************************************************/
1572 /* Control commands flags */
1574 ccNone = 0x0000, /* No special flags */
1575 ccKeepToken = 0x0001 /* Do not skip the current token */
1578 /* Control command table */
1579 typedef struct CtrlDesc CtrlDesc;
1581 unsigned Flags; /* Flags for this directive */
1582 void (*Handler) (void); /* Command handler */
1585 #define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
1586 static CtrlDesc CtrlCmdTab [] = {
1589 { ccNone, DoAddr }, /* .ADDR */
1590 { ccNone, DoAlign },
1591 { ccNone, DoASCIIZ },
1592 { ccNone, DoAssert },
1593 { ccNone, DoAutoImport },
1594 { ccNone, DoUnexpected }, /* .BLANK */
1598 { ccNone, DoCharMap },
1600 { ccNone, DoUnexpected, }, /* .CONCAT */
1601 { ccNone, DoConDes },
1602 { ccNone, DoUnexpected }, /* .CONST */
1603 { ccNone, DoConstructor },
1604 { ccNone, DoUnexpected }, /* .CPU */
1608 { ccNone, DoDebugInfo },
1609 { ccNone, DoDefine },
1610 { ccNone, DoUnexpected }, /* .DEFINED */
1611 { ccNone, DoDestructor },
1612 { ccNone, DoDWord },
1613 { ccKeepToken, DoConditionals }, /* .ELSE */
1614 { ccKeepToken, DoConditionals }, /* .ELSEIF */
1615 { ccKeepToken, DoEnd },
1616 { ccKeepToken, DoConditionals }, /* .ENDIF */
1617 { ccNone, DoUnexpected }, /* .ENDMACRO */
1618 { ccNone, DoEndProc },
1619 { ccNone, DoUnexpected }, /* .ENDREPEAT */
1620 { ccNone, DoEndScope },
1621 { ccNone, DoUnexpected }, /* .ENDSTRUCT */
1622 { ccNone, DoError },
1623 { ccNone, DoExitMacro },
1624 { ccNone, DoExport },
1625 { ccNone, DoExportZP },
1626 { ccNone, DoFarAddr },
1627 { ccNone, DoFeature },
1628 { ccNone, DoFileOpt },
1629 { ccNone, DoForceImport },
1630 { ccNone, DoUnexpected }, /* .FORCEWORD */
1631 { ccNone, DoGlobal },
1632 { ccNone, DoGlobalZP },
1635 { ccKeepToken, DoConditionals }, /* .IF */
1636 { ccKeepToken, DoConditionals }, /* .IFBLANK */
1637 { ccKeepToken, DoConditionals }, /* .IFCONST */
1638 { ccKeepToken, DoConditionals }, /* .IFDEF */
1639 { ccKeepToken, DoConditionals }, /* .IFNBLANK */
1640 { ccKeepToken, DoConditionals }, /* .IFNCONST */
1641 { ccKeepToken, DoConditionals }, /* .IFNDEF */
1642 { ccKeepToken, DoConditionals }, /* .IFNREF */
1643 { ccKeepToken, DoConditionals }, /* .IFP02 */
1644 { ccKeepToken, DoConditionals }, /* .IFP816 */
1645 { ccKeepToken, DoConditionals }, /* .IFPC02 */
1646 { ccKeepToken, DoConditionals }, /* .IFPSC02 */
1647 { ccKeepToken, DoConditionals }, /* .IFREF */
1648 { ccNone, DoImport },
1649 { ccNone, DoImportZP },
1650 { ccNone, DoIncBin },
1651 { ccNone, DoInclude },
1652 { ccNone, DoInvalid }, /* .LEFT */
1653 { ccNone, DoLineCont },
1655 { ccNone, DoListBytes },
1656 { ccNone, DoUnexpected }, /* .LOCAL */
1657 { ccNone, DoLocalChar },
1658 { ccNone, DoMacPack },
1659 { ccNone, DoMacro },
1660 { ccNone, DoUnexpected }, /* .MATCH */
1661 { ccNone, DoInvalid }, /* .MID */
1667 { ccNone, DoPageLength },
1668 { ccNone, DoUnexpected }, /* .PARAMCOUNT */
1670 { ccNone, DoPopSeg },
1672 { ccNone, DoPSC02 },
1673 { ccNone, DoPushSeg },
1674 { ccNone, DoUnexpected }, /* .REFERENCED */
1675 { ccNone, DoReloc },
1676 { ccNone, DoRepeat },
1678 { ccNone, DoInvalid }, /* .RIGHT */
1679 { ccNone, DoROData },
1680 { ccNone, DoScope },
1681 { ccNone, DoSegment },
1682 { ccNone, DoSetCPU },
1683 { ccNone, DoSmart },
1684 { ccNone, DoUnexpected }, /* .STRAT */
1685 { ccNone, DoUnexpected }, /* .STRING */
1686 { ccNone, DoUnexpected }, /* .STRLEN */
1687 { ccNone, DoStruct },
1688 { ccNone, DoSunPlus },
1689 { ccNone, DoUnexpected }, /* .TAG */
1690 { ccNone, DoUnexpected }, /* .TCOUNT */
1691 { ccNone, DoUnexpected }, /* .TIME */
1692 { ccNone, DoUnion },
1693 { ccNone, DoUnexpected }, /* .VERSION */
1694 { ccNone, DoWarning },
1696 { ccNone, DoUnexpected }, /* .XMATCH */
1697 { ccNone, DoZeropage },
1702 /*****************************************************************************/
1704 /*****************************************************************************/
1708 int TokIsPseudo (unsigned Tok)
1709 /* Return true if the given token is a pseudo instruction token */
1711 return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO);
1716 void HandlePseudo (void)
1717 /* Handle a pseudo instruction */
1721 /* Calculate the index into the table */
1722 unsigned Index = Tok - TOK_FIRSTPSEUDO;
1725 if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
1726 Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
1727 PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
1729 CHECK (Index < PSEUDO_COUNT);
1731 /* Get the pseudo intruction descriptor */
1732 D = &CtrlCmdTab [Index];
1734 /* Remember the instruction, then skip it if needed */
1735 if ((D->Flags & ccKeepToken) == 0) {
1736 strcpy (Keyword+1, SVal);
1740 /* Call the handler */
1746 void SegStackCheck (void)
1747 /* Check if the segment stack is empty at end of assembly */
1749 if (CollCount (&SegStack) != 0) {
1750 Error ("Segment stack is not empty");