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