]> git.sur5r.net Git - cc65/blob - src/ca65/macro.c
Added a more generic way to push sources that deliver a token stream
[cc65] / src / ca65 / macro.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  macro.c                                  */
4 /*                                                                           */
5 /*                    Macros for the ca65 macroassembler                     */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2000 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
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 #include "../common/hashstr.h"
40
41 #include "condasm.h"
42 #include "error.h"
43 #include "istack.h"
44 #include "mem.h"
45 #include "nexttok.h"
46 #include "pseudo.h"
47 #include "toklist.h"
48 #include "macro.h"
49
50
51
52 /*****************************************************************************/
53 /*                                   Data                                    */
54 /*****************************************************************************/
55
56
57
58 /* Struct that describes an identifer (macro param, local list) */
59 typedef struct IdDesc_ IdDesc;
60 struct IdDesc_ {
61     IdDesc*         Next;       /* Linked list */
62     char            Id [1];     /* Identifier, dynamically allocated */
63 };
64
65
66
67 /* Struct that describes a macro definition */
68 typedef struct Macro_ Macro;
69 struct Macro_ {
70     Macro*          Next;       /* Next macro with same hash */
71     Macro*          List;       /* List of all macros */
72     unsigned        LocalCount; /* Count of local symbols */
73     IdDesc*         Locals;     /* List of local symbols */
74     unsigned        ParamCount; /* Parameter count of macro */
75     IdDesc*         Params;     /* Identifiers of macro parameters */
76     unsigned        TokCount;   /* Number of tokens for this macro */
77     TokNode*        TokRoot;    /* Root of token list */
78     TokNode*        TokLast;    /* Pointer to last token in list */
79     unsigned char   Style;      /* Macro style */
80     char            Name [1];   /* Macro name, dynamically allocated */
81 };
82
83 /* Macro hash table */
84 #define HASHTAB_SIZE            117
85 static Macro*   MacroTab [HASHTAB_SIZE];
86
87 /* Global macro data */
88 static Macro*   MacroRoot = 0;  /* List of all macros */
89
90 /* Structs that holds data for a macro expansion */
91 typedef struct MacExp_ MacExp;
92 struct MacExp_ {
93     MacExp*     Next;           /* Pointer to next expansion */
94     Macro*      M;              /* Which macro do we expand? */
95     unsigned    IfSP;           /* .IF stack pointer at start of expansion */
96     TokNode*    Exp;            /* Pointer to current token */
97     TokNode*    Final;          /* Pointer to final token */
98     unsigned    LocalStart;     /* Start of counter for local symbol names */
99     unsigned    ParamCount;     /* Number of actual parameters */
100     TokNode**   Params;         /* List of actual parameters */
101     TokNode*    ParamExp;       /* Node for expanding parameters */
102 };
103
104 /* Number of active macro expansions */
105 static unsigned MacExpansions = 0;
106
107 /* Flag if a macro expansion should get aborted */
108 static int DoMacAbort = 0;
109
110 /* Counter to create local names for symbols */
111 static unsigned LocalName = 0;
112
113
114
115 /*****************************************************************************/
116 /*                                   Code                                    */
117 /*****************************************************************************/
118
119
120
121 static IdDesc* NewIdDesc (const char* Id)
122 /* Create a new IdDesc, initialize and return it */
123 {
124     /* Allocate memory */
125     unsigned Len = strlen (Id);
126     IdDesc* I = Xmalloc (sizeof (IdDesc) + Len);
127
128     /* Initialize the struct */
129     I->Next = 0;
130     memcpy (I->Id, Id, Len);
131     I->Id [Len] = '\0';
132
133     /* Return the new struct */
134     return I;
135 }
136
137
138
139 static Macro* NewMacro (const char* Name, unsigned HashVal, unsigned char Style)
140 /* Generate a new macro entry, initialize and return it */
141 {
142     /* Allocate memory */
143     unsigned Len = strlen (Name);
144     Macro* M = Xmalloc (sizeof (Macro) + Len);
145
146     /* Initialize the macro struct */
147     M->LocalCount = 0;
148     M->ParamCount = 0;
149     M->Params     = 0;
150     M->TokCount   = 0;
151     M->TokRoot    = 0;
152     M->TokLast    = 0;
153     M->Style      = Style;
154     memcpy (M->Name, Name, Len);
155     M->Name [Len] = '\0';
156
157     /* Insert the macro into the global macro list */
158     M->List = MacroRoot;
159     MacroRoot = M;
160
161     /* Insert the macro into the hash table */
162     M->Next = MacroTab [HashVal];
163     MacroTab [HashVal] = M;
164
165     /* Return the new macro struct */
166     return M;
167 }
168
169
170
171 static MacExp* NewMacExp (Macro* M)
172 /* Create a new expansion structure for the given macro */
173 {
174     unsigned I;
175
176     /* Allocate memory */
177     MacExp* E = Xmalloc (sizeof (MacExp));
178
179     /* Initialize the data */
180     E->M          = M;
181     E->IfSP       = GetIfStack ();
182     E->Exp        = M->TokRoot;
183     E->Final      = 0;
184     E->LocalStart = LocalName;
185     LocalName    += M->LocalCount;
186     E->ParamCount = 0;
187     E->Params     = Xmalloc (M->ParamCount * sizeof (TokNode*));
188     E->ParamExp   = 0;
189     for (I = 0; I < M->ParamCount; ++I) {
190         E->Params [I] = 0;
191     }
192
193     /* One macro expansion more */
194     ++MacExpansions;
195
196     /* Return the new macro expansion */
197     return E;
198 }
199
200
201
202 static void FreeMacExp (MacExp* E)
203 /* Remove and free the current macro expansion */
204 {
205     unsigned I;
206
207     /* One macro expansion less */
208     --MacExpansions;
209
210     /* Free the parameter list */
211     for (I = 0; I < E->ParamCount; ++I) {
212         Xfree (E->Params [I]);
213     }
214     Xfree (E->Params);
215
216     /* Free the final token if we have one */
217     if (E->Final) {
218         FreeTokNode (E->Final);
219     }
220
221     /* Free the structure itself */
222     Xfree (E);
223 }
224
225
226
227 static void MacSkipDef (unsigned Style)
228 /* Skip a macro definition */
229 {
230     if (Style == MAC_STYLE_CLASSIC) {
231         /* Skip tokens until we reach the final .endmacro */
232         while (Tok != TOK_ENDMACRO && Tok != TOK_EOF) {
233             NextTok ();
234         }
235         if (Tok != TOK_EOF) {
236             SkipUntilSep ();
237         } else {
238             Error (ERR_ENDMACRO_EXPECTED);
239         }
240     } else {
241         /* Skip until end of line */
242         SkipUntilSep ();
243     }
244 }
245
246
247
248 static Macro* MacFind (const char* Name, unsigned HashVal)
249 /* Search for a macro in the hash table */
250 {
251     /* Search for the identifier */
252     Macro* M = MacroTab [HashVal];
253     while (M) {
254         if (strcmp (Name, M->Name) == 0) {
255             return M;
256         }
257         M = M->Next;
258     }
259     return 0;
260 }
261
262
263
264 void MacDef (unsigned Style)
265 /* Parse a macro definition */
266 {
267     Macro* M;
268     TokNode* T;
269     unsigned HashVal;
270     int HaveParams;
271
272     /* We expect a macro name here */
273     if (Tok != TOK_IDENT) {
274         Error (ERR_IDENT_EXPECTED);
275         MacSkipDef (Style);
276         return;
277     }
278
279     /* Generate the hash value */
280     HashVal = HashStr (SVal) % HASHTAB_SIZE;
281
282     /* Did we already define that macro? */
283     if (MacFind (SVal, HashVal) != 0) {
284         /* Macro is already defined */
285         Error (ERR_SYM_ALREADY_DEFINED, SVal);
286         /* Skip tokens until we reach the final .endmacro */
287         MacSkipDef (Style);
288         return;
289     }
290
291     /* Define the macro */
292     M = NewMacro (SVal, HashVal, Style);
293     NextTok ();
294
295     /* If we have a DEFINE style macro, we may have parameters in braces,
296      * otherwise we may have parameters without braces.
297      */
298     if (Style == MAC_STYLE_CLASSIC) {
299         HaveParams = 1;
300     } else {
301         if (Tok == TOK_LPAREN) {
302             HaveParams = 1;
303             NextTok ();
304         } else {
305             HaveParams = 0;
306         }
307     }
308
309     /* Parse the parameter list */
310     if (HaveParams) {
311
312         while (Tok == TOK_IDENT) {
313
314             /* Create a struct holding the identifier */
315             IdDesc* I = NewIdDesc (SVal);
316
317             /* Insert the struct into the list, checking for duplicate idents */
318             if (M->ParamCount == 0) {
319                 M->Params = I;
320             } else {
321                 IdDesc* List = M->Params;
322                 while (1) {
323                     if (strcmp (List->Id, SVal) == 0) {
324                         Error (ERR_SYM_ALREADY_DEFINED, SVal);
325                     }
326                     if (List->Next == 0) {
327                         break;
328                     } else {
329                         List = List->Next;
330                     }
331                 }
332                 List->Next = I;
333             }
334             ++M->ParamCount;
335
336             /* Skip the name */
337             NextTok ();
338
339             /* Maybe there are more params... */
340             if (Tok == TOK_COMMA) {
341                 NextTok ();
342             } else {
343                 break;
344             }
345         }
346     }
347
348     /* For class macros, we expect a separator token, for define style macros,
349      * we expect the closing paren.
350      */
351     if (Style == MAC_STYLE_CLASSIC) {
352         ConsumeSep ();
353     } else if (HaveParams) {
354         ConsumeRParen ();
355     }
356
357     /* Preparse the macro body. We will read the tokens until we reach end of
358      * file, or a .endmacro (or end of line for DEFINE style macros) and store
359      * them into an token list internal to the macro. For classic macros, there
360      * the .LOCAL command is detected and removed at this time.
361      */
362     while (1) {
363
364         /* Check for end of macro */
365         if (Style == MAC_STYLE_CLASSIC) {
366             /* In classic macros, only .endmacro is allowed */
367             if (Tok == TOK_ENDMACRO) {
368                 /* Done */
369                 break;
370             }
371             /* May not have end of file in a macro definition */
372             if (Tok == TOK_EOF) {
373                 Error (ERR_ENDMACRO_EXPECTED);
374                 return;
375             }
376         } else {
377             /* Accept a newline or end of file for new style macros */
378             if (Tok == TOK_SEP || Tok == TOK_EOF) {
379                 break;
380             }
381         }
382
383         /* Check for a .LOCAL declaration */
384         if (Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
385
386             while (1) {
387
388                 IdDesc* I;
389
390                 /* Skip .local or comma */
391                 NextTok ();
392
393                 /* Need an identifer */
394                 if (Tok != TOK_IDENT) {
395                     Error (ERR_IDENT_EXPECTED);
396                     SkipUntilSep ();
397                     break;
398                 }
399
400                 /* Put the identifier into the locals list and skip it */
401                 I = NewIdDesc (SVal);
402                 I->Next = M->Locals;
403                 M->Locals = I;
404                 ++M->LocalCount;
405                 NextTok ();
406
407                 /* Check for end of list */
408                 if (Tok != TOK_COMMA) {
409                     break;
410                 }
411
412             }
413
414             /* We need end of line after the locals */
415             ConsumeSep ();
416             continue;
417         }
418
419         /* Create a token node for the current token */
420         T = NewTokNode ();
421
422         /* If the token is an ident, check if it is a local parameter */
423         if (Tok == TOK_IDENT) {
424             unsigned Count = 0;
425             IdDesc* I = M->Params;
426             while (I) {
427                 if (strcmp (I->Id, SVal) == 0) {
428                     /* Local param name, replace it */
429                     T->Tok  = TOK_MACPARAM;
430                     T->IVal = Count;
431                     break;
432                 }
433                 ++Count;
434                 I = I->Next;
435             }
436         }
437
438         /* Insert the new token in the list */
439         if (M->TokCount == 0) {
440             /* First token */
441             M->TokRoot = M->TokLast = T;
442         } else {
443             /* We have already tokens */
444             M->TokLast->Next = T;
445             M->TokLast = T;
446         }
447         ++M->TokCount;
448
449         /* Read the next token */
450         NextTok ();
451     }
452
453     /* Skip the .endmacro for a classic macro */
454     if (Style == MAC_STYLE_CLASSIC) {
455         NextTok ();
456     }
457 }
458
459
460
461 static int MacExpand (void* Data)
462 /* If we're currently expanding a macro, set the the scanner token and
463  * attribute to the next value and return true. If we are not expanding
464  * a macro, return false.
465  */
466 {
467     /* Cast the Data pointer to the actual data structure */
468     MacExp* Mac = (MacExp*) Data;
469
470     /* Check if we should abort this macro */
471     if (DoMacAbort) {
472
473         /* Reset the flag */
474         DoMacAbort = 0;
475
476         /* Abort any open .IF statements in this macro expansion */
477         CleanupIfStack (Mac->IfSP);
478
479         /* Terminate macro expansion */
480         goto MacEnd;
481     }
482
483     /* We're expanding a macro. Check if we are expanding one of the
484      * macro parameters.
485      */
486     if (Mac->ParamExp) {
487
488         /* Ok, use token from parameter list */
489         TokSet (Mac->ParamExp);
490
491         /* Set pointer to next token */
492         Mac->ParamExp = Mac->ParamExp->Next;
493
494         /* Done */
495         return 1;
496
497     }
498
499     /* We're not expanding macro parameters. Check if we have tokens left from
500      * the macro itself.
501      */
502     if (Mac->Exp) {
503
504         /* Use next macro token */
505         TokSet (Mac->Exp);
506
507         /* Set pointer to next token */
508         Mac->Exp = Mac->Exp->Next;
509
510         /* Is it a request for actual parameter count? */
511         if (Tok == TOK_PARAMCOUNT) {
512             Tok  = TOK_INTCON;
513             IVal = Mac->ParamCount;
514             return 1;
515         }
516
517         /* Is it the name of a macro parameter? */
518         if (Tok == TOK_MACPARAM) {
519
520             /* Start to expand the parameter token list */
521             Mac->ParamExp = Mac->Params [IVal];
522
523             /* Recursive call to expand the parameter */
524             return MacExpand (Mac);
525         }
526
527         /* If it's an identifier, it may in fact be a local symbol */
528         if (Tok == TOK_IDENT && Mac->M->LocalCount) {
529             /* Search for the local symbol in the list */
530             unsigned Index = 0;
531             IdDesc* I = Mac->M->Locals;
532             while (I) {
533                 if (strcmp (SVal, I->Id) == 0) {
534                     /* This is in fact a local symbol, change the name */
535                     sprintf (SVal, "___%04X__", Mac->LocalStart + Index);
536                     break;
537                 }
538                 /* Next symbol */
539                 ++Index;
540                 I = I->Next;
541             }
542
543             /* Done */
544             return 1;
545         }
546
547         /* The token was successfully set */
548         return 1;
549
550     }
551
552     /* No more macro tokens. Do we have a final token? */
553     if (Mac->Final) {
554
555         /* Set the final token and remove it */
556         TokSet (Mac->Final);
557         FreeTokNode (Mac->Final);
558         Mac->Final = 0;
559
560         /* The token was successfully set */
561         return 1;
562
563     }
564
565 MacEnd:
566     /* End of macro expansion */
567     FreeMacExp (Mac);
568
569     /* Pop the input function */
570     PopInput ();
571
572     /* No token available */
573     return 0;
574 }
575
576
577
578 static void StartExpClassic (Macro* M)
579 /* Start expanding the classic macro M */
580 {
581     MacExp* E;
582
583     /* Skip the macro name */
584     NextTok ();
585
586     /* Create a structure holding expansion data */
587     E = NewMacExp (M);
588
589     /* Read the actual parameters */
590     while (Tok != TOK_SEP && Tok != TOK_EOF) {
591
592         TokNode* Last;
593
594         /* Check for maximum parameter count */
595         if (E->ParamCount >= M->ParamCount) {
596             Error (ERR_TOO_MANY_PARAMS);
597             SkipUntilSep ();
598             break;
599         }
600
601         /* Read tokens for one parameter, accept empty params */
602         Last = 0;
603         while (Tok != TOK_COMMA && Tok != TOK_SEP) {
604
605             TokNode* T;
606
607             /* Check for end of file */
608             if (Tok == TOK_EOF) {
609                 Error (ERR_SYNTAX);
610                 return;
611             }
612
613             /* Get the next token in a node */
614             T = NewTokNode ();
615
616             /* Insert it into the list */
617             if (Last == 0) {
618                 E->Params [E->ParamCount] = T;
619             } else {
620                 Last->Next = T;
621             }
622             Last = T;
623
624             /* And skip it... */
625             NextTok ();
626         }
627
628         /* One parameter more */
629         ++E->ParamCount;
630
631         /* Check for a comma */
632         if (Tok == TOK_COMMA) {
633             NextTok ();
634         } else {
635             break;
636         }
637     }
638
639     /* Insert a new token input function */
640     PushInput (MacExpand, E, ".MACRO");
641 }
642
643
644
645 static void StartExpDefine (Macro* M)
646 /* Start expanding a DEFINE style macro */
647 {
648     /* Create a structure holding expansion data */
649     MacExp* E = NewMacExp (M);
650
651     /* A define style macro must be called with as many actual parameters
652      * as there are formal ones. Get the parameter count.
653      */
654     unsigned Count = M->ParamCount;
655
656     /* Skip the current token */
657     NextTok ();
658
659     /* Read the actual parameters */
660     while (Count--) {
661
662         TokNode* Last;
663
664         /* Check if there is really a parameter */
665         if (Tok == TOK_SEP || Tok == TOK_EOF || Tok == TOK_COMMA) {
666             Error (ERR_MACRO_PARAM_EXPECTED);
667             SkipUntilSep ();
668             return;
669         }
670
671         /* Read tokens for one parameter */
672         Last = 0;
673         do {
674
675             TokNode* T;
676
677             /* Get the next token in a node */
678             T = NewTokNode ();
679
680             /* Insert it into the list */
681             if (Last == 0) {
682                 E->Params [E->ParamCount] = T;
683             } else {
684                 Last->Next = T;
685             }
686             Last = T;
687
688             /* And skip it... */
689             NextTok ();
690
691         } while (Tok != TOK_COMMA && Tok != TOK_SEP && Tok != TOK_EOF);
692
693         /* One parameter more */
694         ++E->ParamCount;
695
696         /* Check for a comma */
697         if (Count > 0) {
698             if (Tok == TOK_COMMA) {
699                 NextTok ();
700             } else {
701                 Error (ERR_COMMA_EXPECTED);
702             }
703         }
704     }
705
706     /* Macro expansion will overwrite the current token. This is a problem
707      * for define style macros since these are called from the scanner level.
708      * To avoid it, remember the current token and re-insert it if macro
709      * expansion is done.
710      */
711     E->Final = NewTokNode ();
712
713     /* Insert a new token input function */
714     PushInput (MacExpand, E, ".DEFINE");
715 }
716
717
718
719 void MacExpandStart (void)
720 /* Start expanding the macro in SVal */
721 {
722     /* Search for the macro */
723     Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
724     CHECK (M != 0);
725
726     /* Call the apropriate subroutine */
727     switch (M->Style) {
728         case MAC_STYLE_CLASSIC: StartExpClassic (M);    break;
729         case MAC_STYLE_DEFINE:  StartExpDefine (M);     break;
730         default:                Internal ("Invalid macro style: %d", M->Style);
731     }
732 }
733
734
735
736 void MacAbort (void)
737 /* Abort the current macro expansion */
738 {
739     /* Must have an expansion */
740     CHECK (MacExpansions > 0);
741
742     /* Set a flag so macro expansion will terminate on the next call */
743     DoMacAbort = 1;
744 }
745
746
747
748 int IsMacro (const char* Name)
749 /* Return true if the given name is the name of a macro */
750 {
751     return MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE) != 0;
752 }
753
754
755
756 int IsDefine (const char* Name)
757 /* Return true if the given name is the name of a define style macro */
758 {
759     Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
760     return (M != 0 && M->Style == MAC_STYLE_DEFINE);
761 }
762
763
764
765 int InMacExpansion (void)
766 /* Return true if we're currently expanding a macro */
767 {
768     return (MacExpansions > 0);
769 }
770
771
772
773
774
775