1 /*****************************************************************************/
5 /* Macros for the ca65 macroassembler */
9 /* (C) 1998-2011, Ullrich von Bassewitz */
10 /* Roemerstrasse 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 /*****************************************************************************/
59 /*****************************************************************************/
61 /*****************************************************************************/
65 static unsigned HT_GenHash (const void* Key);
66 /* Generate the hash over a key. */
68 static const void* HT_GetKey (void* Entry);
69 /* Given a pointer to the user entry data, return a pointer to the key */
71 static HashNode* HT_GetHashNode (void* Entry);
72 /* Given a pointer to the user entry data, return a pointer to the hash node */
74 static int HT_Compare (const void* Key1, const void* Key2);
75 /* Compare two keys. The function must return a value less than zero if
76 * Key1 is smaller than Key2, zero if both are equal, and a value greater
77 * than zero if Key1 is greater then Key2.
82 /*****************************************************************************/
84 /*****************************************************************************/
88 /* Struct that describes an identifer (macro param, local list) */
89 typedef struct IdDesc IdDesc;
91 IdDesc* Next; /* Linked list */
92 StrBuf Id; /* Identifier, dynamically allocated */
97 /* Struct that describes a macro definition */
98 typedef struct Macro Macro;
100 HashNode Node; /* Hash list node */
101 Macro* List; /* List of all macros */
102 unsigned LocalCount; /* Count of local symbols */
103 IdDesc* Locals; /* List of local symbols */
104 unsigned ParamCount; /* Parameter count of macro */
105 IdDesc* Params; /* Identifiers of macro parameters */
106 unsigned TokCount; /* Number of tokens for this macro */
107 TokNode* TokRoot; /* Root of token list */
108 TokNode* TokLast; /* Pointer to last token in list */
109 StrBuf Name; /* Macro name, dynamically allocated */
110 unsigned Expansions; /* Number of active macro expansions */
111 unsigned char Style; /* Macro style */
112 unsigned char Incomplete; /* Macro is currently built */
115 /* Hash table functions */
116 static const HashFunctions HashFunc = {
123 /* Macro hash table */
124 static HashTable MacroTab = STATIC_HASHTABLE_INITIALIZER (117, &HashFunc);
126 /* Structs that holds data for a macro expansion */
127 typedef struct MacExp MacExp;
129 MacExp* Next; /* Pointer to next expansion */
130 Macro* M; /* Which macro do we expand? */
131 unsigned IfSP; /* .IF stack pointer at start of expansion */
132 TokNode* Exp; /* Pointer to current token */
133 TokNode* Final; /* Pointer to final token */
134 unsigned LocalStart; /* Start of counter for local symbol names */
135 unsigned ParamCount; /* Number of actual parameters */
136 TokNode** Params; /* List of actual parameters */
137 TokNode* ParamExp; /* Node for expanding parameters */
138 unsigned LISlot; /* Slot for additional line infos */
141 /* Maximum number of nested macro expansions */
142 #define MAX_MACEXPANSIONS 256U
144 /* Number of active macro expansions */
145 static unsigned MacExpansions = 0;
147 /* Flag if a macro expansion should get aborted */
148 static int DoMacAbort = 0;
150 /* Counter to create local names for symbols */
151 static unsigned LocalName = 0;
153 /* Define style macros disabled if != 0 */
154 static unsigned DisableDefines = 0;
158 /*****************************************************************************/
159 /* Hash table functions */
160 /*****************************************************************************/
164 static unsigned HT_GenHash (const void* Key)
165 /* Generate the hash over a key. */
167 return HashBuf (Key);
172 static const void* HT_GetKey (void* Entry)
173 /* Given a pointer to the user entry data, return a pointer to the index */
175 return &((Macro*) Entry)->Name;
180 static HashNode* HT_GetHashNode (void* Entry)
181 /* Given a pointer to the user entry data, return a pointer to the hash node */
183 return &((Macro*) Entry)->Node;
188 static int HT_Compare (const void* Key1, const void* Key2)
189 /* Compare two keys. The function must return a value less than zero if
190 * Key1 is smaller than Key2, zero if both are equal, and a value greater
191 * than zero if Key1 is greater then Key2.
194 return SB_Compare (Key1, Key2);
199 /*****************************************************************************/
201 /*****************************************************************************/
205 static IdDesc* NewIdDesc (const StrBuf* Id)
206 /* Create a new IdDesc, initialize and return it */
208 /* Allocate memory */
209 IdDesc* ID = xmalloc (sizeof (IdDesc));
211 /* Initialize the struct */
214 SB_Copy (&ID->Id, Id);
216 /* Return the new struct */
222 static void FreeIdDesc (IdDesc* ID)
228 /* Free the structure itself */
234 static void FreeIdDescList (IdDesc* ID)
235 /* Free a complete list of IdDesc structures */
246 static Macro* NewMacro (const StrBuf* Name, unsigned char Style)
247 /* Generate a new macro entry, initialize and return it */
249 /* Allocate memory */
250 Macro* M = xmalloc (sizeof (Macro));
252 /* Initialize the macro struct */
253 InitHashNode (&M->Node, M);
262 SB_Copy (&M->Name, Name);
267 /* Insert the macro into the hash table */
268 HT_Insert (&MacroTab, &M->Node);
270 /* Return the new macro struct */
276 static void FreeMacro (Macro* M)
277 /* Free a macro entry which has already been removed from the macro table. */
282 FreeIdDescList (M->Locals);
284 /* Free identifiers of parameters */
285 FreeIdDescList (M->Params);
287 /* Free the token list for the macro */
288 while ((T = M->TokRoot) != 0) {
289 M->TokRoot = T->Next;
293 /* Free the macro name */
296 /* Free the macro structure itself */
302 static MacExp* NewMacExp (Macro* M)
303 /* Create a new expansion structure for the given macro */
307 /* Allocate memory */
308 MacExp* E = xmalloc (sizeof (MacExp));
310 /* Initialize the data */
312 E->IfSP = GetIfStack ();
315 E->LocalStart = LocalName;
316 LocalName += M->LocalCount;
318 E->Params = xmalloc (M->ParamCount * sizeof (TokNode*));
319 for (I = 0; I < M->ParamCount; ++I) {
323 E->LISlot = AllocLineInfoSlot (LI_TYPE_MACRO, MacExpansions);
325 /* Mark the macro as expanding */
328 /* One macro expansion more */
331 /* Return the new macro expansion */
337 static void FreeMacExp (MacExp* E)
338 /* Remove and free the current macro expansion */
342 /* One macro expansion less */
345 /* No longer expanding this macro */
348 /* Free the parameter lists */
349 for (I = 0; I < E->ParamCount; ++I) {
350 /* Free one parameter list */
351 TokNode* N = E->Params[I];
353 TokNode* P = N->Next;
360 /* Free the additional line info slot */
361 FreeLineInfoSlot (E->LISlot);
363 /* Free the final token if we have one */
365 FreeTokNode (E->Final);
368 /* Free the structure itself */
374 static void MacSkipDef (unsigned Style)
375 /* Skip a macro definition */
377 if (Style == MAC_STYLE_CLASSIC) {
378 /* Skip tokens until we reach the final .endmacro */
379 while (CurTok.Tok != TOK_ENDMACRO && CurTok.Tok != TOK_EOF) {
382 if (CurTok.Tok != TOK_EOF) {
385 Error ("`.ENDMACRO' expected");
388 /* Skip until end of line */
395 void MacDef (unsigned Style)
396 /* Parse a macro definition */
402 /* We expect a macro name here */
403 if (CurTok.Tok != TOK_IDENT) {
404 Error ("Identifier expected");
407 } else if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) {
408 /* The identifier is a name of a 6502 instruction, which is not
409 * allowed if not explicitly enabled.
411 Error ("Cannot use an instruction as macro name");
416 /* Did we already define that macro? */
417 if (HT_Find (&MacroTab, &CurTok.SVal) != 0) {
418 /* Macro is already defined */
419 Error ("A macro named `%m%p' is already defined", &CurTok.SVal);
420 /* Skip tokens until we reach the final .endmacro */
425 /* Define the macro */
426 M = NewMacro (&CurTok.SVal, Style);
428 /* Switch to raw token mode and skip the macro name */
429 EnterRawTokenMode ();
432 /* If we have a DEFINE style macro, we may have parameters in braces,
433 * otherwise we may have parameters without braces.
435 if (Style == MAC_STYLE_CLASSIC) {
438 if (CurTok.Tok == TOK_LPAREN) {
446 /* Parse the parameter list */
449 while (CurTok.Tok == TOK_IDENT) {
451 /* Create a struct holding the identifier */
452 IdDesc* I = NewIdDesc (&CurTok.SVal);
454 /* Insert the struct into the list, checking for duplicate idents */
455 if (M->ParamCount == 0) {
458 IdDesc* List = M->Params;
460 if (SB_Compare (&List->Id, &CurTok.SVal) == 0) {
461 Error ("Duplicate symbol `%m%p'", &CurTok.SVal);
463 if (List->Next == 0) {
476 /* Maybe there are more params... */
477 if (CurTok.Tok == TOK_COMMA) {
485 /* For class macros, we expect a separator token, for define style macros,
486 * we expect the closing paren.
488 if (Style == MAC_STYLE_CLASSIC) {
490 } else if (HaveParams) {
494 /* Preparse the macro body. We will read the tokens until we reach end of
495 * file, or a .endmacro (or end of line for DEFINE style macros) and store
496 * them into an token list internal to the macro. For classic macros, there
497 * the .LOCAL command is detected and removed at this time.
501 /* Check for end of macro */
502 if (Style == MAC_STYLE_CLASSIC) {
503 /* In classic macros, only .endmacro is allowed */
504 if (CurTok.Tok == TOK_ENDMACRO) {
508 /* May not have end of file in a macro definition */
509 if (CurTok.Tok == TOK_EOF) {
510 Error ("`.ENDMACRO' expected");
514 /* Accept a newline or end of file for new style macros */
515 if (TokIsSep (CurTok.Tok)) {
520 /* Check for a .LOCAL declaration */
521 if (CurTok.Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
527 /* Skip .local or comma */
530 /* Need an identifer */
531 if (CurTok.Tok != TOK_IDENT && CurTok.Tok != TOK_LOCAL_IDENT) {
532 Error ("Identifier expected");
537 /* Put the identifier into the locals list and skip it */
538 I = NewIdDesc (&CurTok.SVal);
544 /* Check for end of list */
545 if (CurTok.Tok != TOK_COMMA) {
551 /* We need end of line after the locals */
556 /* Create a token node for the current token */
559 /* If the token is an ident, check if it is a local parameter */
560 if (CurTok.Tok == TOK_IDENT) {
562 IdDesc* I = M->Params;
564 if (SB_Compare (&I->Id, &CurTok.SVal) == 0) {
565 /* Local param name, replace it */
566 N->T.Tok = TOK_MACPARAM;
575 /* Insert the new token in the list */
576 if (M->TokCount == 0) {
578 M->TokRoot = M->TokLast = N;
580 /* We have already tokens */
581 M->TokLast->Next = N;
586 /* Read the next token */
590 /* Skip the .endmacro for a classic macro */
591 if (Style == MAC_STYLE_CLASSIC) {
595 /* Reset the Incomplete flag now that parsing is done */
599 /* Switch out of raw token mode */
600 LeaveRawTokenMode ();
605 void MacUndef (const StrBuf* Name, unsigned char Style)
606 /* Undefine the macro with the given name and style. A style mismatch is
607 * treated as if the macro didn't exist.
610 /* Search for the macro */
611 Macro* M = HT_FindEntry (&MacroTab, Name);
613 /* Don't let the user kid with us */
614 if (M == 0 || M->Style != Style) {
615 Error ("No such macro: %m%p", Name);
618 if (M->Expansions > 0) {
619 Error ("Cannot delete a macro that is currently expanded");
623 /* Remove the macro from the macro table */
624 HT_RemoveEntry (&MacroTab, M);
626 /* Free the macro structure */
632 static int MacExpand (void* Data)
633 /* If we're currently expanding a macro, set the the scanner token and
634 * attribute to the next value and return true. If we are not expanding
635 * a macro, return false.
638 /* Cast the Data pointer to the actual data structure */
639 MacExp* Mac = (MacExp*) Data;
641 /* Check if we should abort this macro */
647 /* Abort any open .IF statements in this macro expansion */
648 CleanupIfStack (Mac->IfSP);
650 /* Terminate macro expansion */
654 /* We're expanding a macro. Check if we are expanding one of the
659 /* Ok, use token from parameter list */
660 TokSet (Mac->ParamExp, Mac->LISlot);
662 /* Set pointer to next token */
663 Mac->ParamExp = Mac->ParamExp->Next;
670 /* We're not expanding macro parameters. Check if we have tokens left from
675 /* Use next macro token */
676 TokSet (Mac->Exp, Mac->LISlot);
678 /* Set pointer to next token */
679 Mac->Exp = Mac->Exp->Next;
681 /* Is it a request for actual parameter count? */
682 if (CurTok.Tok == TOK_PARAMCOUNT) {
683 CurTok.Tok = TOK_INTCON;
684 CurTok.IVal = Mac->ParamCount;
688 /* Is it the name of a macro parameter? */
689 if (CurTok.Tok == TOK_MACPARAM) {
691 /* Start to expand the parameter token list */
692 Mac->ParamExp = Mac->Params [CurTok.IVal];
694 /* Recursive call to expand the parameter */
695 return MacExpand (Mac);
698 /* If it's an identifier, it may in fact be a local symbol */
699 if ((CurTok.Tok == TOK_IDENT || CurTok.Tok == TOK_LOCAL_IDENT) &&
700 Mac->M->LocalCount) {
701 /* Search for the local symbol in the list */
703 IdDesc* I = Mac->M->Locals;
705 if (SB_Compare (&CurTok.SVal, &I->Id) == 0) {
706 /* This is in fact a local symbol, change the name. Be sure
707 * to generate a local label name if the original name was
708 * a local label, and also generate a name that cannot be
709 * generated by a user.
711 if (SB_At (&I->Id, 0) == LocalStart) {
712 /* Must generate a local symbol */
713 SB_Printf (&CurTok.SVal, "%cLOCAL-MACRO_SYMBOL-%04X",
714 LocalStart, Mac->LocalStart + Index);
717 SB_Printf (&CurTok.SVal, "LOCAL-MACRO_SYMBOL-%04X",
718 Mac->LocalStart + Index);
731 /* The token was successfully set */
736 /* No more macro tokens. Do we have a final token? */
739 /* Set the final token and remove it */
740 TokSet (Mac->Final, Mac->LISlot);
741 FreeTokNode (Mac->Final);
744 /* The token was successfully set */
750 /* End of macro expansion */
753 /* Pop the input function */
756 /* No token available */
762 static void StartExpClassic (MacExp* E)
763 /* Start expanding a classic macro */
767 /* Skip the macro name */
770 /* Read the actual parameters */
771 while (!TokIsSep (CurTok.Tok)) {
775 /* Check for maximum parameter count */
776 if (E->ParamCount >= E->M->ParamCount) {
777 ErrorSkip ("Too many macro parameters");
781 /* The macro may optionally be enclosed in curly braces */
782 Term = GetTokListTerm (TOK_COMMA);
784 /* Read tokens for one parameter, accept empty params */
786 while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) {
790 /* Check for end of file */
791 if (CurTok.Tok == TOK_EOF) {
792 Error ("Unexpected end of file");
797 /* Get the next token in a node */
800 /* Insert it into the list */
802 E->Params [E->ParamCount] = T;
812 /* One parameter more */
815 /* If the macro argument was enclosed in curly braces, end-of-line
816 * is an error. Skip the closing curly brace.
818 if (Term == TOK_RCURLY) {
819 if (CurTok.Tok == TOK_SEP) {
820 Error ("End of line encountered within macro argument");
826 /* Check for a comma */
827 if (CurTok.Tok == TOK_COMMA) {
834 /* We must be at end of line now, otherwise something is wrong */
837 /* Insert a new token input function */
838 PushInput (MacExpand, E, ".MACRO");
843 static void StartExpDefine (MacExp* E)
844 /* Start expanding a DEFINE style macro */
846 /* A define style macro must be called with as many actual parameters
847 * as there are formal ones. Get the parameter count.
849 unsigned Count = E->M->ParamCount;
851 /* Skip the current token */
854 /* Read the actual parameters */
859 /* The macro may optionally be enclosed in curly braces */
860 token_t Term = GetTokListTerm (TOK_COMMA);
862 /* Check if there is really a parameter */
863 if (TokIsSep (CurTok.Tok) || CurTok.Tok == Term) {
864 ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1);
869 /* Read tokens for one parameter */
875 /* Get the next token in a node */
878 /* Insert it into the list */
880 E->Params [E->ParamCount] = T;
889 } while (CurTok.Tok != Term && !TokIsSep (CurTok.Tok));
891 /* One parameter more */
894 /* If the macro argument was enclosed in curly braces, end-of-line
895 * is an error. Skip the closing curly brace.
897 if (Term == TOK_RCURLY) {
898 if (TokIsSep (CurTok.Tok)) {
899 Error ("End of line encountered within macro argument");
905 /* Check for a comma */
907 if (CurTok.Tok == TOK_COMMA) {
910 Error ("`,' expected");
915 /* Macro expansion will overwrite the current token. This is a problem
916 * for define style macros since these are called from the scanner level.
917 * To avoid it, remember the current token and re-insert it, once macro
920 E->Final = NewTokNode ();
922 /* Insert a new token input function */
923 PushInput (MacExpand, E, ".DEFINE");
928 void MacExpandStart (void)
929 /* Start expanding the macro in SVal */
933 /* Search for the macro */
934 Macro* M = HT_FindEntry (&MacroTab, &CurTok.SVal);
935 CHECK (M != 0 && (M->Style != MAC_STYLE_DEFINE || DisableDefines == 0));
937 /* We cannot expand an incomplete macro */
939 Error ("Cannot expand an incomplete macro");
943 /* Don't allow too many nested macro expansions - otherwise it is possible
944 * to force an endless loop and assembler crash.
946 if (MacExpansions >= MAX_MACEXPANSIONS) {
947 Error ("Too many nested macro expansions");
951 /* Create a structure holding expansion data */
954 /* Call the apropriate subroutine */
956 case MAC_STYLE_CLASSIC: StartExpClassic (E); break;
957 case MAC_STYLE_DEFINE: StartExpDefine (E); break;
958 default: Internal ("Invalid macro style: %d", M->Style);
965 /* Abort the current macro expansion */
967 /* Must have an expansion */
968 CHECK (MacExpansions > 0);
970 /* Set a flag so macro expansion will terminate on the next call */
976 int IsMacro (const StrBuf* Name)
977 /* Return true if the given name is the name of a macro */
979 return (HT_Find (&MacroTab, Name) != 0);
984 int IsDefine (const StrBuf* Name)
985 /* Return true if the given name is the name of a define style macro */
989 /* Never if disabled */
990 if (DisableDefines) {
994 /* Check if we have such a macro */
995 M = HT_FindEntry (&MacroTab, Name);
996 return (M != 0 && M->Style == MAC_STYLE_DEFINE);
1001 int InMacExpansion (void)
1002 /* Return true if we're currently expanding a macro */
1004 return (MacExpansions > 0);
1009 void DisableDefineStyleMacros (void)
1010 /* Disable define style macros until EnableDefineStyleMacros is called */
1017 void EnableDefineStyleMacros (void)
1018 /* Re-enable define style macros previously disabled with
1019 * DisableDefineStyleMacros.
1022 PRECONDITION (DisableDefines > 0);