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