1 /*****************************************************************************/
5 /* Macros for the ca65 macroassembler */
9 /* (C) 1998-2004 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 /*****************************************************************************/
58 /*****************************************************************************/
60 /*****************************************************************************/
64 static unsigned HT_GenHash (const void* Key);
65 /* Generate the hash over a key. */
67 static const void* HT_GetKey (void* Entry);
68 /* Given a pointer to the user entry data, return a pointer to the key */
70 static HashNode* HT_GetHashNode (void* Entry);
71 /* Given a pointer to the user entry data, return a pointer to the hash node */
73 static int HT_Compare (const void* Key1, const void* Key2);
74 /* Compare two keys. The function must return a value less than zero if
75 * Key1 is smaller than Key2, zero if both are equal, and a value greater
76 * than zero if Key1 is greater then Key2.
81 /*****************************************************************************/
83 /*****************************************************************************/
87 /* Struct that describes an identifer (macro param, local list) */
88 typedef struct IdDesc IdDesc;
90 IdDesc* Next; /* Linked list */
91 char Id [1]; /* Identifier, dynamically allocated */
96 /* Struct that describes a macro definition */
97 typedef struct Macro Macro;
99 HashNode Node; /* Hash list node */
100 Macro* List; /* List of all macros */
101 unsigned LocalCount; /* Count of local symbols */
102 IdDesc* Locals; /* List of local symbols */
103 unsigned ParamCount; /* Parameter count of macro */
104 IdDesc* Params; /* Identifiers of macro parameters */
105 unsigned TokCount; /* Number of tokens for this macro */
106 TokNode* TokRoot; /* Root of token list */
107 TokNode* TokLast; /* Pointer to last token in list */
108 unsigned char Style; /* Macro style */
109 char Name [1]; /* Macro name, dynamically allocated */
112 /* Hash table functions */
113 static const HashFunctions HashFunc = {
120 /* Macro hash table */
121 static HashTable MacroTab = STATIC_HASHTABLE_INITIALIZER (117, &HashFunc);
123 /* Global macro data */
124 static Macro* MacroRoot = 0; /* List of all macros */
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 */
140 /* Number of active macro expansions */
141 static unsigned MacExpansions = 0;
143 /* Flag if a macro expansion should get aborted */
144 static int DoMacAbort = 0;
146 /* Counter to create local names for symbols */
147 static unsigned LocalName = 0;
151 /*****************************************************************************/
152 /* Hash table functions */
153 /*****************************************************************************/
157 static unsigned HT_GenHash (const void* Key)
158 /* Generate the hash over a key. */
160 return HashStr (Key);
165 static const void* HT_GetKey (void* Entry)
166 /* Given a pointer to the user entry data, return a pointer to the index */
168 return ((Macro*) Entry)->Name;
173 static HashNode* HT_GetHashNode (void* Entry)
174 /* Given a pointer to the user entry data, return a pointer to the hash node */
176 return &((Macro*) Entry)->Node;
181 static int HT_Compare (const void* Key1, const void* Key2)
182 /* Compare two keys. The function must return a value less than zero if
183 * Key1 is smaller than Key2, zero if both are equal, and a value greater
184 * than zero if Key1 is greater then Key2.
187 return strcmp (Key1, Key2);
192 /*****************************************************************************/
194 /*****************************************************************************/
198 static IdDesc* NewIdDesc (const char* Id)
199 /* Create a new IdDesc, initialize and return it */
201 /* Allocate memory */
202 unsigned Len = strlen (Id);
203 IdDesc* I = xmalloc (sizeof (IdDesc) + Len);
205 /* Initialize the struct */
207 memcpy (I->Id, Id, Len);
210 /* Return the new struct */
216 static Macro* NewMacro (const char* Name, unsigned char Style)
217 /* Generate a new macro entry, initialize and return it */
219 /* Allocate memory */
220 unsigned Len = strlen (Name);
221 Macro* M = xmalloc (sizeof (Macro) + Len);
223 /* Initialize the macro struct */
224 InitHashNode (&M->Node, M);
233 memcpy (M->Name, Name, Len+1);
235 /* Insert the macro into the global macro list */
239 /* Insert the macro into the hash table */
240 HT_Insert (&MacroTab, &M->Node);
242 /* Return the new macro struct */
248 static MacExp* NewMacExp (Macro* M)
249 /* Create a new expansion structure for the given macro */
253 /* Allocate memory */
254 MacExp* E = xmalloc (sizeof (MacExp));
256 /* Initialize the data */
258 E->IfSP = GetIfStack ();
261 E->LocalStart = LocalName;
262 LocalName += M->LocalCount;
264 E->Params = xmalloc (M->ParamCount * sizeof (TokNode*));
266 for (I = 0; I < M->ParamCount; ++I) {
270 /* One macro expansion more */
273 /* Return the new macro expansion */
279 static void FreeMacExp (MacExp* E)
280 /* Remove and free the current macro expansion */
284 /* One macro expansion less */
287 /* Free the parameter lists */
288 for (I = 0; I < E->ParamCount; ++I) {
289 /* Free one parameter list */
290 TokNode* N = E->Params[I];
292 TokNode* P = N->Next;
299 /* Free the final token if we have one */
301 FreeTokNode (E->Final);
304 /* Free the structure itself */
310 static void MacSkipDef (unsigned Style)
311 /* Skip a macro definition */
313 if (Style == MAC_STYLE_CLASSIC) {
314 /* Skip tokens until we reach the final .endmacro */
315 while (Tok != TOK_ENDMACRO && Tok != TOK_EOF) {
318 if (Tok != TOK_EOF) {
321 Error ("`.ENDMACRO' expected");
324 /* Skip until end of line */
331 void MacDef (unsigned Style)
332 /* Parse a macro definition */
338 /* We expect a macro name here */
339 if (Tok != TOK_IDENT) {
340 Error ("Identifier expected");
343 } else if (!UbiquitousIdents && FindInstruction (SVal) >= 0) {
344 /* The identifier is a name of a 6502 instruction, which is not
345 * allowed if not explicitly enabled.
347 Error ("Cannot use an instruction as macro name");
352 /* Did we already define that macro? */
353 if (HT_Find (&MacroTab, SVal) != 0) {
354 /* Macro is already defined */
355 Error ("A macro named `%s' is already defined", SVal);
356 /* Skip tokens until we reach the final .endmacro */
361 /* Define the macro */
362 M = NewMacro (SVal, Style);
364 /* Switch to raw token mode and skip the macro name */
365 EnterRawTokenMode ();
368 /* If we have a DEFINE style macro, we may have parameters in braces,
369 * otherwise we may have parameters without braces.
371 if (Style == MAC_STYLE_CLASSIC) {
374 if (Tok == TOK_LPAREN) {
382 /* Parse the parameter list */
385 while (Tok == TOK_IDENT) {
387 /* Create a struct holding the identifier */
388 IdDesc* I = NewIdDesc (SVal);
390 /* Insert the struct into the list, checking for duplicate idents */
391 if (M->ParamCount == 0) {
394 IdDesc* List = M->Params;
396 if (strcmp (List->Id, SVal) == 0) {
397 Error ("Duplicate symbol `%s'", SVal);
399 if (List->Next == 0) {
412 /* Maybe there are more params... */
413 if (Tok == TOK_COMMA) {
421 /* For class macros, we expect a separator token, for define style macros,
422 * we expect the closing paren.
424 if (Style == MAC_STYLE_CLASSIC) {
426 } else if (HaveParams) {
430 /* Preparse the macro body. We will read the tokens until we reach end of
431 * file, or a .endmacro (or end of line for DEFINE style macros) and store
432 * them into an token list internal to the macro. For classic macros, there
433 * the .LOCAL command is detected and removed at this time.
437 /* Check for end of macro */
438 if (Style == MAC_STYLE_CLASSIC) {
439 /* In classic macros, only .endmacro is allowed */
440 if (Tok == TOK_ENDMACRO) {
444 /* May not have end of file in a macro definition */
445 if (Tok == TOK_EOF) {
446 Error ("`.ENDMACRO' expected");
450 /* Accept a newline or end of file for new style macros */
451 if (TokIsSep (Tok)) {
456 /* Check for a .LOCAL declaration */
457 if (Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
463 /* Skip .local or comma */
466 /* Need an identifer */
467 if (Tok != TOK_IDENT && Tok != TOK_LOCAL_IDENT) {
468 Error ("Identifier expected");
473 /* Put the identifier into the locals list and skip it */
474 I = NewIdDesc (SVal);
480 /* Check for end of list */
481 if (Tok != TOK_COMMA) {
487 /* We need end of line after the locals */
492 /* Create a token node for the current token */
495 /* If the token is an ident, check if it is a local parameter */
496 if (Tok == TOK_IDENT) {
498 IdDesc* I = M->Params;
500 if (strcmp (I->Id, SVal) == 0) {
501 /* Local param name, replace it */
502 T->Tok = TOK_MACPARAM;
511 /* Insert the new token in the list */
512 if (M->TokCount == 0) {
514 M->TokRoot = M->TokLast = T;
516 /* We have already tokens */
517 M->TokLast->Next = T;
522 /* Read the next token */
526 /* Skip the .endmacro for a classic macro */
527 if (Style == MAC_STYLE_CLASSIC) {
532 /* Switch out of raw token mode */
533 LeaveRawTokenMode ();
538 static int MacExpand (void* Data)
539 /* If we're currently expanding a macro, set the the scanner token and
540 * attribute to the next value and return true. If we are not expanding
541 * a macro, return false.
544 /* Cast the Data pointer to the actual data structure */
545 MacExp* Mac = (MacExp*) Data;
547 /* Check if we should abort this macro */
553 /* Abort any open .IF statements in this macro expansion */
554 CleanupIfStack (Mac->IfSP);
556 /* Terminate macro expansion */
560 /* We're expanding a macro. Check if we are expanding one of the
565 /* Ok, use token from parameter list */
566 TokSet (Mac->ParamExp);
568 /* Set pointer to next token */
569 Mac->ParamExp = Mac->ParamExp->Next;
576 /* We're not expanding macro parameters. Check if we have tokens left from
581 /* Use next macro token */
584 /* Set pointer to next token */
585 Mac->Exp = Mac->Exp->Next;
587 /* Is it a request for actual parameter count? */
588 if (Tok == TOK_PARAMCOUNT) {
590 IVal = Mac->ParamCount;
594 /* Is it the name of a macro parameter? */
595 if (Tok == TOK_MACPARAM) {
597 /* Start to expand the parameter token list */
598 Mac->ParamExp = Mac->Params [IVal];
600 /* Recursive call to expand the parameter */
601 return MacExpand (Mac);
604 /* If it's an identifier, it may in fact be a local symbol */
605 if ((Tok == TOK_IDENT || Tok == TOK_LOCAL_IDENT) && Mac->M->LocalCount) {
606 /* Search for the local symbol in the list */
608 IdDesc* I = Mac->M->Locals;
610 if (strcmp (SVal, I->Id) == 0) {
611 /* This is in fact a local symbol, change the name. Be sure
612 * to generate a local label name if the original name was
613 * a local label, and also generate a name that cannot be
614 * generated by a user.
616 unsigned PrefixLen = (I->Id[0] == LocalStart);
617 sprintf (SVal, "%.*sLOCAL-MACRO-SYMBOL-%04X", PrefixLen,
618 I->Id, Mac->LocalStart + Index);
630 /* The token was successfully set */
635 /* No more macro tokens. Do we have a final token? */
638 /* Set the final token and remove it */
640 FreeTokNode (Mac->Final);
643 /* The token was successfully set */
649 /* End of macro expansion */
652 /* Pop the input function */
655 /* No token available */
661 static void StartExpClassic (Macro* M)
662 /* Start expanding the classic macro M */
668 /* Skip the macro name */
671 /* Create a structure holding expansion data */
674 /* Read the actual parameters */
675 while (!TokIsSep (Tok)) {
679 /* Check for maximum parameter count */
680 if (E->ParamCount >= M->ParamCount) {
681 ErrorSkip ("Too many macro parameters");
685 /* The macro may optionally be enclosed in curly braces */
686 Term = GetTokListTerm (TOK_COMMA);
688 /* Read tokens for one parameter, accept empty params */
690 while (Tok != Term && Tok != TOK_SEP) {
694 /* Check for end of file */
695 if (Tok == TOK_EOF) {
696 Error ("Unexpected end of file");
701 /* Get the next token in a node */
704 /* Insert it into the list */
706 E->Params [E->ParamCount] = T;
716 /* One parameter more */
719 /* If the macro argument was enclosed in curly braces, end-of-line
720 * is an error. Skip the closing curly brace.
722 if (Term == TOK_RCURLY) {
723 if (Tok == TOK_SEP) {
724 Error ("End of line encountered within macro argument");
730 /* Check for a comma */
731 if (Tok == TOK_COMMA) {
738 /* We must be at end of line now, otherwise something is wrong */
741 /* Insert a new token input function */
742 PushInput (MacExpand, E, ".MACRO");
747 static void StartExpDefine (Macro* M)
748 /* Start expanding a DEFINE style macro */
750 /* Create a structure holding expansion data */
751 MacExp* E = NewMacExp (M);
753 /* A define style macro must be called with as many actual parameters
754 * as there are formal ones. Get the parameter count.
756 unsigned Count = M->ParamCount;
758 /* Skip the current token */
761 /* Read the actual parameters */
766 /* The macro may optionally be enclosed in curly braces */
767 enum Token Term = GetTokListTerm (TOK_COMMA);
769 /* Check if there is really a parameter */
770 if (TokIsSep (Tok) || Tok == Term) {
771 ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1);
776 /* Read tokens for one parameter */
782 /* Get the next token in a node */
785 /* Insert it into the list */
787 E->Params [E->ParamCount] = T;
796 } while (Tok != Term && !TokIsSep (Tok));
798 /* One parameter more */
801 /* If the macro argument was enclosed in curly braces, end-of-line
802 * is an error. Skip the closing curly brace.
804 if (Term == TOK_RCURLY) {
805 if (TokIsSep (Tok)) {
806 Error ("End of line encountered within macro argument");
812 /* Check for a comma */
814 if (Tok == TOK_COMMA) {
817 Error ("`,' expected");
822 /* Macro expansion will overwrite the current token. This is a problem
823 * for define style macros since these are called from the scanner level.
824 * To avoid it, remember the current token and re-insert it, once macro
827 E->Final = NewTokNode ();
829 /* Insert a new token input function */
830 PushInput (MacExpand, E, ".DEFINE");
835 void MacExpandStart (void)
836 /* Start expanding the macro in SVal */
838 /* Search for the macro */
839 Macro* M = HT_FindEntry (&MacroTab, SVal);
842 /* Call the apropriate subroutine */
844 case MAC_STYLE_CLASSIC: StartExpClassic (M); break;
845 case MAC_STYLE_DEFINE: StartExpDefine (M); break;
846 default: Internal ("Invalid macro style: %d", M->Style);
853 /* Abort the current macro expansion */
855 /* Must have an expansion */
856 CHECK (MacExpansions > 0);
858 /* Set a flag so macro expansion will terminate on the next call */
864 int IsMacro (const char* Name)
865 /* Return true if the given name is the name of a macro */
867 return (HT_Find (&MacroTab, Name) != 0);
872 int IsDefine (const char* Name)
873 /* Return true if the given name is the name of a define style macro */
875 Macro* M = HT_FindEntry (&MacroTab, Name);
876 return (M != 0 && M->Style == MAC_STYLE_DEFINE);
881 int InMacExpansion (void)
882 /* Return true if we're currently expanding a macro */
884 return (MacExpansions > 0);