1/*****************************************************************************/
2/* */
3/* macro.c */
4/* */
5/* Macros for the ca65 macroassembler */
6/* */
7/* */
8/* */
9/* (C) 1998-2011, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
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. */
18/* */
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: */
22/* */
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 */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36#include <stdio.h>
37#include <string.h>
38
39/* common */
40#include "check.h"
41#include "hashfunc.h"
42#include "hashtab.h"
43#include "xmalloc.h"
44
45/* ca65 */
46#include "condasm.h"
47#include "error.h"
48#include "global.h"
49#include "instr.h"
50#include "istack.h"
51#include "lineinfo.h"
52#include "nexttok.h"
53#include "pseudo.h"
54#include "toklist.h"
55#include "macro.h"
56
57
58
59/*****************************************************************************/
60/* Forwards */
61/*****************************************************************************/
62
63
64
65static unsigned HT_GenHash (const void* Key);
66/* Generate the hash over a key. */
67
68static const void* HT_GetKey (const void* Entry);
69/* Given a pointer to the user entry data, return a pointer to the key */
70
71static int HT_Compare (const void* Key1, const void* Key2);
72/* Compare two keys. The function must return a value less than zero if
73** Key1 is smaller than Key2, zero if both are equal, and a value greater
74** than zero if Key1 is greater then Key2.
75*/
76
77
78
79/*****************************************************************************/
80/* Data */
81/*****************************************************************************/
82
83
84
85/* Struct that describes an identifer (macro param, local list) */
86typedef struct IdDesc IdDesc;
87struct IdDesc {
88 IdDesc* Next; /* Linked list */
89 StrBuf Id; /* Identifier, dynamically allocated */
90};
91
92
93
94/* Struct that describes a macro definition */
95struct Macro {
96 HashNode Node; /* Hash list node */
97 Macro* List; /* List of all macros */
98 unsigned LocalCount; /* Count of local symbols */
99 IdDesc* Locals; /* List of local symbols */
100 unsigned ParamCount; /* Parameter count of macro */
101 IdDesc* Params; /* Identifiers of macro parameters */
102 unsigned TokCount; /* Number of tokens for this macro */
103 TokNode* TokRoot; /* Root of token list */
104 TokNode* TokLast; /* Pointer to last token in list */
105 StrBuf Name; /* Macro name, dynamically allocated */
106 unsigned Expansions; /* Number of active macro expansions */
107 unsigned char Style; /* Macro style */
108 unsigned char Incomplete; /* Macro is currently built */
109};
110
111/* Hash table functions */
112static const HashFunctions HashFunc = {
113 HT_GenHash,
114 HT_GetKey,
115 HT_Compare
116};
117
118/* Macro hash table */
119static HashTable MacroTab = STATIC_HASHTABLE_INITIALIZER (117, &HashFunc);
120
121/* Structs that holds data for a macro expansion */
122typedef struct MacExp MacExp;
123struct MacExp {
124 MacExp* Next; /* Pointer to next expansion */
125 Macro* M; /* Which macro do we expand? */
126 unsigned IfSP; /* .IF stack pointer at start of expansion */
127 TokNode* Exp; /* Pointer to current token */
128 TokNode* Final; /* Pointer to final token */
129 unsigned MacExpansions; /* Number of active macro expansions */
130 unsigned LocalStart; /* Start of counter for local symbol names */
131 unsigned ParamCount; /* Number of actual parameters */
132 TokNode** Params; /* List of actual parameters */
133 TokNode* ParamExp; /* Node for expanding parameters */
134 LineInfo* LI; /* Line info for the expansion */
135 LineInfo* ParamLI; /* Line info for parameter expansion */
136};
137
138/* Maximum number of nested macro expansions */
139#define MAX_MACEXPANSIONS 256U
140
141/* Number of active macro expansions */
142static unsigned MacExpansions = 0;
143
144/* Flag if a macro expansion should get aborted */
145static int DoMacAbort = 0;
146
147/* Counter to create local names for symbols */
148static unsigned LocalName = 0;
149
150/* Define-style macros disabled if != 0 */
151static unsigned DisableDefines = 0;
152
153
154
155/*****************************************************************************/
156/* Hash table functions */
157/*****************************************************************************/
158
159
160
161static unsigned HT_GenHash (const void* Key)
162/* Generate the hash over a key. */
163{
164 return HashBuf (Key);
165}
166
167
168
169static const void* HT_GetKey (const void* Entry)
170/* Given a pointer to the user entry data, return a pointer to the index */
171{
172 return &((Macro*) Entry)->Name;
173}
174
175
176
177static int HT_Compare (const void* Key1, const void* Key2)
178/* Compare two keys. The function must return a value less than zero if
179** Key1 is smaller than Key2, zero if both are equal, and a value greater
180** than zero if Key1 is greater then Key2.
181*/
182{
183 return SB_Compare (Key1, Key2);
184}
185
186
187
188/*****************************************************************************/
189/* Code */
190/*****************************************************************************/
191
192
193
194static IdDesc* NewIdDesc (const StrBuf* Id)
195/* Create a new IdDesc, initialize and return it */
196{
197 /* Allocate memory */
198 IdDesc* ID = xmalloc (sizeof (IdDesc));
199
200 /* Initialize the struct */
201 ID->Next = 0;
202 SB_Init (&ID->Id);
203 SB_Copy (&ID->Id, Id);
204
205 /* Return the new struct */
206 return ID;
207}
208
209
210
211static void FreeIdDesc (IdDesc* ID)
212/* Free an IdDesc */
213{
214 /* Free the name */
215 SB_Done (&ID->Id);
216
217 /* Free the structure itself */
218 xfree (ID);
219}
220
221
222
223static void FreeIdDescList (IdDesc* ID)
224/* Free a complete list of IdDesc structures */
225{
226 while (ID) {
227 IdDesc* This = ID;
228 ID = ID->Next;
229 FreeIdDesc (This);
230 }
231}
232
233
234
235static Macro* NewMacro (const StrBuf* Name, unsigned char Style)
236/* Generate a new macro entry, initialize and return it */
237{
238 /* Allocate memory */
239 Macro* M = xmalloc (sizeof (Macro));
240
241 /* Initialize the macro struct */
242 InitHashNode (&M->Node);
243 M->LocalCount = 0;
244 M->Locals = 0;
245 M->ParamCount = 0;
246 M->Params = 0;
247 M->TokCount = 0;
248 M->TokRoot = 0;
249 M->TokLast = 0;
250 SB_Init (&M->Name);
251 SB_Copy (&M->Name, Name);
252 M->Expansions = 0;
253 M->Style = Style;
254 M->Incomplete = 1;
255
256 /* Insert the macro into the hash table */
257 HT_Insert (&MacroTab, &M->Node);
258
259 /* Return the new macro struct */
260 return M;
261}
262
263
264
265static void FreeMacro (Macro* M)
266/* Free a macro entry which has already been removed from the macro table. */
267{
268 TokNode* T;
269
270 /* Free locals */
271 FreeIdDescList (M->Locals);
272
273 /* Free identifiers of parameters */
274 FreeIdDescList (M->Params);
275
276 /* Free the token list for the macro */
277 while ((T = M->TokRoot) != 0) {
278 M->TokRoot = T->Next;
279 FreeTokNode (T);
280 }
281
282 /* Free the macro name */
283 SB_Done (&M->Name);
284
285 /* Free the macro structure itself */
286 xfree (M);
287}
288
289
290
291static MacExp* NewMacExp (Macro* M)
292/* Create a new expansion structure for the given macro */
293{
294 unsigned I;
295
296 /* Allocate memory */
297 MacExp* E = xmalloc (sizeof (MacExp));
298
299 /* Initialize the data */
300 E->M = M;
301 E->IfSP = GetIfStack ();
302 E->Exp = M->TokRoot;
303 E->Final = 0;
304 E->MacExpansions = ++MacExpansions; /* One macro expansion more */
305 E->LocalStart = LocalName;
306 LocalName += M->LocalCount;
307 E->ParamCount = 0;
308 E->Params = xmalloc (M->ParamCount * sizeof (TokNode*));
309 for (I = 0; I < M->ParamCount; ++I) {
310 E->Params[I] = 0;
311 }
312 E->ParamExp = 0;
313 E->LI = 0;
314 E->ParamLI = 0;
315
316 /* Mark the macro as expanding */
317 ++M->Expansions;
318
319 /* Return the new macro expansion */
320 return E;
321}
322
323
324
325static void FreeMacExp (MacExp* E)
326/* Remove and free the current macro expansion */
327{
328 unsigned I;
329
330 /* One macro expansion less */
331 --MacExpansions;
332
333 /* No longer expanding this macro */
334 --E->M->Expansions;
335
336 /* Free the parameter lists */
337 for (I = 0; I < E->ParamCount; ++I) {
338 /* Free one parameter list */
339 TokNode* N = E->Params[I];
340 while (N) {
341 TokNode* P = N->Next;
342 FreeTokNode (N);
343 N = P;
344 }
345 }
346 xfree (E->Params);
347
348 /* Free the additional line info */
349 if (E->ParamLI) {
350 EndLine (E->ParamLI);
351 }
352 if (E->LI) {
353 EndLine (E->LI);
354 }
355
356 /* Free the final token if we have one */
357 if (E->Final) {
358 FreeTokNode (E->Final);
359 }
360
361 /* Free the structure itself */
362 xfree (E);
363}
364
365
366
367static void MacSkipDef (unsigned Style)
368/* Skip a macro definition */
369{
370 if (Style == MAC_STYLE_CLASSIC) {
371 /* Skip tokens until we reach the final .endmacro */
372 while (CurTok.Tok != TOK_ENDMACRO && CurTok.Tok != TOK_EOF) {
373 NextTok ();
374 }
375 if (CurTok.Tok != TOK_EOF) {
376 SkipUntilSep ();
377 } else {
378 Error ("'.ENDMACRO' expected");
379 }
380 } else {
381 /* Skip until end of line */
382 SkipUntilSep ();
383 }
384}
385
386
387
388void MacDef (unsigned Style)
389/* Parse a macro definition */
390{
391 Macro* M;
392 TokNode* N;
393 int HaveParams;
394
395 /* We expect a macro name here */
396 if (CurTok.Tok != TOK_IDENT) {
397 Error ("Identifier expected");
398 MacSkipDef (Style);
399 return;
400 } else if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) {
401 /* The identifier is a name of a 6502 instruction, which is not
402 ** allowed if not explicitly enabled.
403 */
404 Error ("Cannot use an instruction as macro name");
405 MacSkipDef (Style);
406 return;
407 }
408
409 /* Did we already define that macro? */
410 if (HT_Find (&MacroTab, &CurTok.SVal) != 0) {
411 /* Macro is already defined */
412 Error ("A macro named '%m%p' is already defined", &CurTok.SVal);
413 /* Skip tokens until we reach the final .endmacro */
414 MacSkipDef (Style);
415 return;
416 }
417
418 /* Define the macro */
419 M = NewMacro (&CurTok.SVal, Style);
420
421 /* Switch to raw token mode and skip the macro name */
422 EnterRawTokenMode ();
423 NextTok ();
424
425 /* If we have a DEFINE-style macro, we may have parameters in parentheses;
426 ** otherwise, we may have parameters without parentheses.
427 */
428 if (Style == MAC_STYLE_CLASSIC) {
429 HaveParams = 1;
430 } else {
431 if (CurTok.Tok == TOK_LPAREN) {
432 HaveParams = 1;
433 NextTok ();
434 } else {
435 HaveParams = 0;
436 }
437 }
438
439 /* Parse the parameter list */
440 if (HaveParams) {
441
442 while (CurTok.Tok == TOK_IDENT) {
443
444 /* Create a struct holding the identifier */
445 IdDesc* I = NewIdDesc (&CurTok.SVal);
446
447 /* Insert the struct into the list, checking for duplicate idents */
448 if (M->ParamCount == 0) {
449 M->Params = I;
450 } else {
451 IdDesc* List = M->Params;
452 while (1) {
453 if (SB_Compare (&List->Id, &CurTok.SVal) == 0) {
454 Error ("Duplicate symbol '%m%p'", &CurTok.SVal);
455 }
456 if (List->Next == 0) {
457 break;
458 } else {
459 List = List->Next;
460 }
461 }
462 List->Next = I;
463 }
464 ++M->ParamCount;
465
466 /* Skip the name */
467 NextTok ();
468
469 /* Maybe there are more params... */
470 if (CurTok.Tok == TOK_COMMA) {
471 NextTok ();
472 } else {
473 break;
474 }
475 }
476 }
477
478 /* For classic macros, we expect a separator token, for define-style macros,
479 ** we expect the closing paren.
480 */
481 if (Style == MAC_STYLE_CLASSIC) {
482 ConsumeSep ();
483 } else if (HaveParams) {
484 ConsumeRParen ();
485 }
486
487 /* Preparse the macro body. We will read the tokens until we reach end of
488 ** file, or a .endmacro (or end of line for DEFINE-style macros) and store
489 ** them into a token list internal to the macro. For classic macros,
490 ** the .LOCAL command is detected and removed, at this time.
491 */
492 while (1) {
493
494 /* Check for end of macro */
495 if (Style == MAC_STYLE_CLASSIC) {
496 /* In classic macros, only .endmacro is allowed */
497 if (CurTok.Tok == TOK_ENDMACRO) {
498 /* Done */
499 break;
500 }
501 /* May not have end of file in a macro definition */
502 if (CurTok.Tok == TOK_EOF) {
503 Error ("'.ENDMACRO' expected");
504 goto Done;
505 }
506 } else {
507 /* Accept a newline or end of file for new style macros */
508 if (TokIsSep (CurTok.Tok)) {
509 break;
510 }
511 }
512
513 /* Check for a .LOCAL declaration */
514 if (CurTok.Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
515
516 while (1) {
517
518 IdDesc* I;
519
520 /* Skip .local or comma */
521 NextTok ();
522
523 /* Need an identifer */
524 if (CurTok.Tok != TOK_IDENT && CurTok.Tok != TOK_LOCAL_IDENT) {
525 Error ("Identifier expected");
526 SkipUntilSep ();
527 break;
528 }
529
530 /* Put the identifier into the locals list and skip it */
531 I = NewIdDesc (&CurTok.SVal);
532 I->Next = M->Locals;
533 M->Locals = I;
534 ++M->LocalCount;
535 NextTok ();
536
537 /* Check for end of list */
538 if (CurTok.Tok != TOK_COMMA) {
539 break;
540 }
541
542 }
543
544 /* We need end of line after the locals */
545 ConsumeSep ();
546 continue;
547 }
548
549 /* Create a token node for the current token */
550 N = NewTokNode ();
551
552 /* If the token is an identifier, check if it is a local parameter */
553 if (CurTok.Tok == TOK_IDENT) {
554 unsigned Count = 0;
555 IdDesc* I = M->Params;
556 while (I) {
557 if (SB_Compare (&I->Id, &CurTok.SVal) == 0) {
558 /* Local param name, replace it */
559 N->T.Tok = TOK_MACPARAM;
560 N->T.IVal = Count;
561 break;
562 }
563 ++Count;
564 I = I->Next;
565 }
566 }
567
568 /* Insert the new token in the list */
569 if (M->TokCount == 0) {
570 /* First token */
571 M->TokRoot = M->TokLast = N;
572 } else {
573 /* We have already tokens */
574 M->TokLast->Next = N;
575 M->TokLast = N;
576 }
577 ++M->TokCount;
578
579 /* Read the next token */
580 NextTok ();
581 }
582
583 /* Skip the .endmacro for a classic macro */
584 if (Style == MAC_STYLE_CLASSIC) {
585 NextTok ();
586 }
587
588 /* Reset the Incomplete flag now that parsing is done */
589 M->Incomplete = 0;
590
591Done:
592 /* Switch out of raw token mode */
593 LeaveRawTokenMode ();
594}
595
596
597
598void MacUndef (const StrBuf* Name, unsigned char Style)
599/* Undefine the macro with the given name and style. A style mismatch is
600** treated as if the macro didn't exist.
601*/
602{
603 /* Search for the macro */
604 Macro* M = HT_Find (&MacroTab, Name);
605
606 /* Don't let the user kid with us */
607 if (M == 0 || M->Style != Style) {
608 Error ("No such macro: %m%p", Name);
609 return;
610 }
611 if (M->Expansions > 0) {
612 Error ("Cannot delete a macro that is currently expanded");
613 return;
614 }
615
616 /* Remove the macro from the macro table */
617 HT_Remove (&MacroTab, M);
618
619 /* Free the macro structure */
620 FreeMacro (M);
621}
622
623
624
625static int MacExpand (void* Data)
626/* If we're currently expanding a macro, set the the scanner token and
627** attribute to the next value and return true. If we are not expanding
628** a macro, return false.
629*/
630{
631 /* Cast the Data pointer to the actual data structure */
632 MacExp* Mac = (MacExp*) Data;
633
634 /* Check if we should abort this macro */
635 if (DoMacAbort) {
636
637 /* Reset the flag */
638 DoMacAbort = 0;
639
640 /* Abort any open .IF statements in this macro expansion */
641 CleanupIfStack (Mac->IfSP);
642
643 /* Terminate macro expansion */
644 goto MacEnd;
645 }
646
647 /* We're expanding a macro. Check if we are expanding one of the
648 ** macro parameters.
649 */
650ExpandParam:
651 if (Mac->ParamExp) {
652
653 /* Ok, use token from parameter list */
654 TokSet (Mac->ParamExp);
655
656 /* Create new line info for this parameter token */
657 if (Mac->ParamLI) {
658 EndLine (Mac->ParamLI);
659 }
660 Mac->ParamLI = StartLine (&CurTok.Pos, LI_TYPE_MACPARAM, Mac->MacExpansions);
661
662 /* Set pointer to next token */
663 Mac->ParamExp = Mac->ParamExp->Next;
664
665 /* Done */
666 return 1;
667
668 } else if (Mac->ParamLI) {
669
670 /* There's still line info open from the parameter expansion - end it */
671 EndLine (Mac->ParamLI);
672 Mac->ParamLI = 0;
673
674 }
675
676 /* We're not expanding macro parameters. Check if we have tokens left from
677 ** the macro itself.
678 */
679 if (Mac->Exp) {
680
681 /* Use next macro token */
682 TokSet (Mac->Exp);
683
684 /* Create new line info for this token */
685 if (Mac->LI) {
686 EndLine (Mac->LI);
687 }
688 Mac->LI = StartLine (&CurTok.Pos, LI_TYPE_MACRO, Mac->MacExpansions);
689
690 /* Set pointer to next token */
691 Mac->Exp = Mac->Exp->Next;
692
693 /* Is it a request for actual parameter count? */
694 if (CurTok.Tok == TOK_PARAMCOUNT) {
695 CurTok.Tok = TOK_INTCON;
696 CurTok.IVal = Mac->ParamCount;
697 return 1;
698 }
699
700 /* Is it the name of a macro parameter? */
701 if (CurTok.Tok == TOK_MACPARAM) {
702
703 /* Start to expand the parameter token list */
704 Mac->ParamExp = Mac->Params[CurTok.IVal];
705
706 /* Go back and expand the parameter */
707 goto ExpandParam;
708 }
709
710 /* If it's an identifier, it may in fact be a local symbol */
711 if ((CurTok.Tok == TOK_IDENT || CurTok.Tok == TOK_LOCAL_IDENT) &&
712 Mac->M->LocalCount) {
713 /* Search for the local symbol in the list */
714 unsigned Index = 0;
715 IdDesc* I = Mac->M->Locals;
716 while (I) {
717 if (SB_Compare (&CurTok.SVal, &I->Id) == 0) {
718 /* This is in fact a local symbol, change the name. Be sure
719 ** to generate a local label name if the original name was
720 ** a local label, and also generate a name that cannot be
721 ** generated by a user.
722 */
723 if (SB_At (&I->Id, 0) == LocalStart) {
724 /* Must generate a local symbol */
725 SB_Printf (&CurTok.SVal, "%cLOCAL-MACRO_SYMBOL-%04X",
726 LocalStart, Mac->LocalStart + Index);
727 } else {
728 /* Global symbol */
729 SB_Printf (&CurTok.SVal, "LOCAL-MACRO_SYMBOL-%04X",
730 Mac->LocalStart + Index);
731 }
732 break;
733 }
734 /* Next symbol */
735 ++Index;
736 I = I->Next;
737 }
738
739 /* Done */
740 return 1;
741 }
742
743 /* The token was successfully set */
744 return 1;
745 }
746
747 /* No more macro tokens. Do we have a final token? */
748 if (Mac->Final) {
749
750 /* Set the final token and remove it */
751 TokSet (Mac->Final);
752 FreeTokNode (Mac->Final);
753 Mac->Final = 0;
754
755 /* Problem: When a .define-style macro is expanded within the call
756 ** of a classic one, the latter may be terminated and removed while
757 ** the expansion of the .define-style macro is still active. Because
758 ** line info slots are "stacked", this runs into a CHECK FAILED. For
759 ** now, we will fix that by removing the .define-style macro expansion
760 ** immediately, once the final token is placed. The better solution
761 ** would probably be to not require AllocLineInfoSlot/FreeLineInfoSlot
762 ** to be called in FIFO order, but this is a bigger change.
763 */
764 /* End of macro expansion and pop the input function */
765 FreeMacExp (Mac);
766 PopInput ();
767
768 /* The token was successfully set */
769 return 1;
770 }
771
772MacEnd:
773 /* End of macro expansion */
774 FreeMacExp (Mac);
775
776 /* Pop the input function */
777 PopInput ();
778
779 /* No token available */
780 return 0;
781}
782
783
784
785static void StartExpClassic (MacExp* E)
786/* Start expanding a classic macro */
787{
788 token_t Term;
789
790 /* Skip the macro name */
791 NextTok ();
792
793 /* Does this invocation have any arguments? */
794 if (!TokIsSep (CurTok.Tok)) {
795
796 /* Read the actual parameters */
797 while (1) {
798 TokNode* Last;
799
800 /* Check for maximum parameter count */
801 if (E->ParamCount >= E->M->ParamCount) {
802 ErrorSkip ("Too many macro parameters");
803 break;
804 }
805
806 /* The macro argument optionally may be enclosed in curly braces */
807 Term = GetTokListTerm (TOK_COMMA);
808
809 /* Read tokens for one parameter, accept empty params */
810 Last = 0;
811 while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) {
812 TokNode* T;
813
814 /* Check for end of file */
815 if (CurTok.Tok == TOK_EOF) {
816 Error ("Unexpected end of file");
817 FreeMacExp (E);
818 return;
819 }
820
821 /* Get the next token in a node */
822 T = NewTokNode ();
823
824 /* Insert it into the list */
825 if (Last == 0) {
826 E->Params [E->ParamCount] = T;
827 } else {
828 Last->Next = T;
829 }
830 Last = T;
831
832 /* And skip it... */
833 NextTok ();
834 }
835
836 /* One parameter more */
837 ++E->ParamCount;
838
839 /* If the macro argument was enclosed in curly braces, end-of-line
840 ** is an error. Skip the closing curly brace.
841 */
842 if (Term == TOK_RCURLY) {
843 if (CurTok.Tok == TOK_SEP) {
844 Error ("End of line encountered within macro argument");
845 break;
846 }
847 NextTok ();
848 }
849
850 /* Check for a comma */
851 if (CurTok.Tok == TOK_COMMA) {
852 NextTok ();
853 } else {
854 break;
855 }
856 }
857 }
858
859 /* We must be at end of line now, otherwise something is wrong */
860 ExpectSep ();
861
862 /* Insert a new token input function */
863 PushInput (MacExpand, E, ".MACRO");
864}
865
866
867
868static void StartExpDefine (MacExp* E)
869/* Start expanding a DEFINE-style macro */
870{
871 /* A define-style macro must be called with as many actual parameters
872 ** as there are formal ones. Get the parameter count.
873 */
874 unsigned Count = E->M->ParamCount;
875
876 /* Skip the current token */
877 NextTok ();
878
879 /* Read the actual parameters */
880 while (Count--) {
881 TokNode* Last;
882
883 /* The macro argument optionally may be enclosed in curly braces */
884 token_t Term = GetTokListTerm (TOK_COMMA);
885
886 /* Check if there is really a parameter */
887 if (TokIsSep (CurTok.Tok) || CurTok.Tok == Term) {
888 ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1);
889 FreeMacExp (E);
890 return;
891 }
892
893 /* Read tokens for one parameter */
894 Last = 0;
895 do {
896 TokNode* T;
897
898 /* Get the next token in a node */
899 T = NewTokNode ();
900
901 /* Insert it into the list */
902 if (Last == 0) {
903 E->Params [E->ParamCount] = T;
904 } else {
905 Last->Next = T;
906 }
907 Last = T;
908
909 /* And skip it... */
910 NextTok ();
911
912 } while (CurTok.Tok != Term && !TokIsSep (CurTok.Tok));
913
914 /* One parameter more */
915 ++E->ParamCount;
916
917 /* If the macro argument was enclosed in curly braces, end-of-line
918 ** is an error. Skip the closing curly brace.
919 */
920 if (Term == TOK_RCURLY) {
921 if (TokIsSep (CurTok.Tok)) {
922 Error ("End of line encountered within macro argument");
923 break;
924 }
925 NextTok ();
926 }
927
928 /* Check for a comma */
929 if (Count > 0) {
930 if (CurTok.Tok == TOK_COMMA) {
931 NextTok ();
932 } else {
933 Error ("',' expected");
934 }
935 }
936 }
937
938 /* Macro expansion will overwrite the current token. This is a problem
939 ** for define-style macros since these are called from the scanner level.
940 ** To avoid it, remember the current token and re-insert it, once macro
941 ** expansion is done.
942 */
943 E->Final = NewTokNode ();
944
945 /* Insert a new token input function */
946 PushInput (MacExpand, E, ".DEFINE");
947}
948
949
950
951void MacExpandStart (Macro* M)
952/* Start expanding a macro */
953{
954 MacExp* E;
955
956 /* Check the argument */
957 PRECONDITION (M && (M->Style != MAC_STYLE_DEFINE || DisableDefines == 0));
958
959 /* We cannot expand an incomplete macro */
960 if (M->Incomplete) {
961 Error ("Cannot expand an incomplete macro");
962 return;
963 }
964
965 /* Don't allow too many nested macro expansions - otherwise it is possible
966 ** to force an endless loop and assembler crash.
967 */
968 if (MacExpansions >= MAX_MACEXPANSIONS) {
969 Error ("Too many nested macro expansions");
970 return;
971 }
972
973 /* Create a structure holding expansion data */
974 E = NewMacExp (M);
975
976 /* Call the apropriate subroutine */
977 switch (M->Style) {
978 case MAC_STYLE_CLASSIC: StartExpClassic (E); break;
979 case MAC_STYLE_DEFINE: StartExpDefine (E); break;
980 default: Internal ("Invalid macro style: %d", M->Style);
981 }
982}
983
984
985
986void MacAbort (void)
987/* Abort the current macro expansion */
988{
989 /* Must have an expansion */
990 CHECK (MacExpansions > 0);
991
992 /* Set a flag so macro expansion will terminate on the next call */
993 DoMacAbort = 1;
994}
995
996
997
998Macro* FindMacro (const StrBuf* Name)
999/* Try to find the macro with the given name and return it. If no macro with
1000** this name was found, return NULL.
1001*/
1002{
1003 Macro* M = HT_Find (&MacroTab, Name);
1004 return (M != 0 && M->Style == MAC_STYLE_CLASSIC)? M : 0;
1005}
1006
1007
1008
1009Macro* FindDefine (const StrBuf* Name)
1010/* Try to find the define-style macro with the given name; and, return it.
1011** If no such macro was found, return NULL.
1012*/
1013{
1014 Macro* M;
1015
1016 /* Never if disabled */
1017 if (DisableDefines) {
1018 return 0;
1019 }
1020
1021 /* Check if we have such a macro */
1022 M = HT_Find (&MacroTab, Name);
1023 return (M != 0 && M->Style == MAC_STYLE_DEFINE)? M : 0;
1024}
1025
1026
1027
1028int InMacExpansion (void)
1029/* Return true if we're currently expanding a macro */
1030{
1031 return (MacExpansions > 0);
1032}
1033
1034
1035
1036void DisableDefineStyleMacros (void)
1037/* Disable define-style macros until EnableDefineStyleMacros() is called */
1038{
1039 ++DisableDefines;
1040}
1041
1042
1043
1044void EnableDefineStyleMacros (void)
1045/* Re-enable define-style macros previously disabled with
1046** DisableDefineStyleMacros().
1047*/
1048{
1049 PRECONDITION (DisableDefines > 0);
1050 --DisableDefines;
1051}
1052