]> git.sur5r.net Git - cc65/blob - src/ca65/macro.c
Added/finished .MID, .LEFT, .RIGHT
[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 #include "../common/xmalloc.h"
41
42 #include "condasm.h"
43 #include "error.h"
44 #include "istack.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
294     /* Switch to raw token mode and skip the macro name */
295     EnterRawTokenMode ();
296     NextTok ();
297
298     /* If we have a DEFINE style macro, we may have parameters in braces,
299      * otherwise we may have parameters without braces.
300      */
301     if (Style == MAC_STYLE_CLASSIC) {
302         HaveParams = 1;
303     } else {
304         if (Tok == TOK_LPAREN) {
305             HaveParams = 1;
306             NextTok ();
307         } else {
308             HaveParams = 0;
309         }
310     }
311
312     /* Parse the parameter list */
313     if (HaveParams) {
314
315         while (Tok == TOK_IDENT) {
316
317             /* Create a struct holding the identifier */
318             IdDesc* I = NewIdDesc (SVal);
319
320             /* Insert the struct into the list, checking for duplicate idents */
321             if (M->ParamCount == 0) {
322                 M->Params = I;
323             } else {
324                 IdDesc* List = M->Params;
325                 while (1) {
326                     if (strcmp (List->Id, SVal) == 0) {
327                         Error (ERR_SYM_ALREADY_DEFINED, SVal);
328                     }
329                     if (List->Next == 0) {
330                         break;
331                     } else {
332                         List = List->Next;
333                     }
334                 }
335                 List->Next = I;
336             }
337             ++M->ParamCount;
338
339             /* Skip the name */
340             NextTok ();
341
342             /* Maybe there are more params... */
343             if (Tok == TOK_COMMA) {
344                 NextTok ();
345             } else {
346                 break;
347             }
348         }
349     }
350
351     /* For class macros, we expect a separator token, for define style macros,
352      * we expect the closing paren.
353      */
354     if (Style == MAC_STYLE_CLASSIC) {
355         ConsumeSep ();
356     } else if (HaveParams) {
357         ConsumeRParen ();
358     }
359
360     /* Preparse the macro body. We will read the tokens until we reach end of
361      * file, or a .endmacro (or end of line for DEFINE style macros) and store
362      * them into an token list internal to the macro. For classic macros, there
363      * the .LOCAL command is detected and removed at this time.
364      */
365     while (1) {
366
367         /* Check for end of macro */
368         if (Style == MAC_STYLE_CLASSIC) {
369             /* In classic macros, only .endmacro is allowed */
370             if (Tok == TOK_ENDMACRO) {
371                 /* Done */
372                 break;
373             }
374             /* May not have end of file in a macro definition */
375             if (Tok == TOK_EOF) {
376                 Error (ERR_ENDMACRO_EXPECTED);
377                 goto Done;
378             }
379         } else {
380             /* Accept a newline or end of file for new style macros */
381             if (Tok == TOK_SEP || Tok == TOK_EOF) {
382                 break;
383             }
384         }
385
386         /* Check for a .LOCAL declaration */
387         if (Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
388
389             while (1) {
390
391                 IdDesc* I;
392
393                 /* Skip .local or comma */
394                 NextTok ();
395
396                 /* Need an identifer */
397                 if (Tok != TOK_IDENT) {
398                     Error (ERR_IDENT_EXPECTED);
399                     SkipUntilSep ();
400                     break;
401                 }
402
403                 /* Put the identifier into the locals list and skip it */
404                 I = NewIdDesc (SVal);
405                 I->Next = M->Locals;
406                 M->Locals = I;
407                 ++M->LocalCount;
408                 NextTok ();
409
410                 /* Check for end of list */
411                 if (Tok != TOK_COMMA) {
412                     break;
413                 }
414
415             }
416
417             /* We need end of line after the locals */
418             ConsumeSep ();
419             continue;
420         }
421
422         /* Create a token node for the current token */
423         T = NewTokNode ();
424
425         /* If the token is an ident, check if it is a local parameter */
426         if (Tok == TOK_IDENT) {
427             unsigned Count = 0;
428             IdDesc* I = M->Params;
429             while (I) {
430                 if (strcmp (I->Id, SVal) == 0) {
431                     /* Local param name, replace it */
432                     T->Tok  = TOK_MACPARAM;
433                     T->IVal = Count;
434                     break;
435                 }
436                 ++Count;
437                 I = I->Next;
438             }
439         }
440
441         /* Insert the new token in the list */
442         if (M->TokCount == 0) {
443             /* First token */
444             M->TokRoot = M->TokLast = T;
445         } else {
446             /* We have already tokens */
447             M->TokLast->Next = T;
448             M->TokLast = T;
449         }
450         ++M->TokCount;
451
452         /* Read the next token */
453         NextTok ();
454     }
455
456     /* Skip the .endmacro for a classic macro */
457     if (Style == MAC_STYLE_CLASSIC) {
458         NextTok ();
459     }
460
461 Done:
462     /* Switch out of raw token mode */
463     LeaveRawTokenMode ();
464 }
465
466
467
468 static int MacExpand (void* Data)
469 /* If we're currently expanding a macro, set the the scanner token and
470  * attribute to the next value and return true. If we are not expanding
471  * a macro, return false.
472  */
473 {
474     /* Cast the Data pointer to the actual data structure */
475     MacExp* Mac = (MacExp*) Data;
476
477     /* Check if we should abort this macro */
478     if (DoMacAbort) {
479
480         /* Reset the flag */
481         DoMacAbort = 0;
482
483         /* Abort any open .IF statements in this macro expansion */
484         CleanupIfStack (Mac->IfSP);
485
486         /* Terminate macro expansion */
487         goto MacEnd;
488     }
489
490     /* We're expanding a macro. Check if we are expanding one of the
491      * macro parameters.
492      */
493     if (Mac->ParamExp) {
494
495         /* Ok, use token from parameter list */
496         TokSet (Mac->ParamExp);
497
498         /* Set pointer to next token */
499         Mac->ParamExp = Mac->ParamExp->Next;
500
501         /* Done */
502         return 1;
503
504     }
505
506     /* We're not expanding macro parameters. Check if we have tokens left from
507      * the macro itself.
508      */
509     if (Mac->Exp) {
510
511         /* Use next macro token */
512         TokSet (Mac->Exp);
513
514         /* Set pointer to next token */
515         Mac->Exp = Mac->Exp->Next;
516
517         /* Is it a request for actual parameter count? */
518         if (Tok == TOK_PARAMCOUNT) {
519             Tok  = TOK_INTCON;
520             IVal = Mac->ParamCount;
521             return 1;
522         }
523
524         /* Is it the name of a macro parameter? */
525         if (Tok == TOK_MACPARAM) {
526
527             /* Start to expand the parameter token list */
528             Mac->ParamExp = Mac->Params [IVal];
529
530             /* Recursive call to expand the parameter */
531             return MacExpand (Mac);
532         }
533
534         /* If it's an identifier, it may in fact be a local symbol */
535         if (Tok == TOK_IDENT && Mac->M->LocalCount) {
536             /* Search for the local symbol in the list */
537             unsigned Index = 0;
538             IdDesc* I = Mac->M->Locals;
539             while (I) {
540                 if (strcmp (SVal, I->Id) == 0) {
541                     /* This is in fact a local symbol, change the name */
542                     sprintf (SVal, "___%04X__", Mac->LocalStart + Index);
543                     break;
544                 }
545                 /* Next symbol */
546                 ++Index;
547                 I = I->Next;
548             }
549
550             /* Done */
551             return 1;
552         }
553
554         /* The token was successfully set */
555         return 1;
556
557     }
558
559     /* No more macro tokens. Do we have a final token? */
560     if (Mac->Final) {
561
562         /* Set the final token and remove it */
563         TokSet (Mac->Final);
564         FreeTokNode (Mac->Final);
565         Mac->Final = 0;
566
567         /* The token was successfully set */
568         return 1;
569
570     }
571
572 MacEnd:
573     /* End of macro expansion */
574     FreeMacExp (Mac);
575
576     /* Pop the input function */
577     PopInput ();
578
579     /* No token available */
580     return 0;
581 }
582
583
584
585 static void StartExpClassic (Macro* M)
586 /* Start expanding the classic macro M */
587 {
588     MacExp* E;
589
590     /* Skip the macro name */
591     NextTok ();
592
593     /* Create a structure holding expansion data */
594     E = NewMacExp (M);
595
596     /* Read the actual parameters */
597     while (Tok != TOK_SEP && Tok != TOK_EOF) {
598
599         TokNode* Last;
600
601         /* Check for maximum parameter count */
602         if (E->ParamCount >= M->ParamCount) {
603             Error (ERR_TOO_MANY_PARAMS);
604             SkipUntilSep ();
605             break;
606         }
607
608         /* Read tokens for one parameter, accept empty params */
609         Last = 0;
610         while (Tok != TOK_COMMA && Tok != TOK_SEP) {
611
612             TokNode* T;
613
614             /* Check for end of file */
615             if (Tok == TOK_EOF) {
616                 Error (ERR_SYNTAX);
617                 return;
618             }
619
620             /* Get the next token in a node */
621             T = NewTokNode ();
622
623             /* Insert it into the list */
624             if (Last == 0) {
625                 E->Params [E->ParamCount] = T;
626             } else {
627                 Last->Next = T;
628             }
629             Last = T;
630
631             /* And skip it... */
632             NextTok ();
633         }
634
635         /* One parameter more */
636         ++E->ParamCount;
637
638         /* Check for a comma */
639         if (Tok == TOK_COMMA) {
640             NextTok ();
641         } else {
642             break;
643         }
644     }
645
646     /* Insert a new token input function */
647     PushInput (MacExpand, E, ".MACRO");
648 }
649
650
651
652 static void StartExpDefine (Macro* M)
653 /* Start expanding a DEFINE style macro */
654 {
655     /* Create a structure holding expansion data */
656     MacExp* E = NewMacExp (M);
657
658     /* A define style macro must be called with as many actual parameters
659      * as there are formal ones. Get the parameter count.
660      */                                          
661     unsigned Count = M->ParamCount;
662
663     /* Skip the current token */
664     NextTok ();
665
666     /* Read the actual parameters */
667     while (Count--) {
668
669         TokNode* Last;
670
671         /* Check if there is really a parameter */
672         if (Tok == TOK_SEP || Tok == TOK_EOF || Tok == TOK_COMMA) {
673             Error (ERR_MACRO_PARAM_EXPECTED);
674             SkipUntilSep ();
675             return;
676         }
677
678         /* Read tokens for one parameter */
679         Last = 0;
680         do {
681
682             TokNode* T;
683
684             /* Get the next token in a node */
685             T = NewTokNode ();
686
687             /* Insert it into the list */
688             if (Last == 0) {
689                 E->Params [E->ParamCount] = T;
690             } else {
691                 Last->Next = T;
692             }
693             Last = T;
694
695             /* And skip it... */
696             NextTok ();
697
698         } while (Tok != TOK_COMMA && Tok != TOK_SEP && Tok != TOK_EOF);
699
700         /* One parameter more */
701         ++E->ParamCount;
702
703         /* Check for a comma */
704         if (Count > 0) {
705             if (Tok == TOK_COMMA) {
706                 NextTok ();
707             } else {
708                 Error (ERR_COMMA_EXPECTED);
709             }
710         }
711     }
712
713     /* Macro expansion will overwrite the current token. This is a problem
714      * for define style macros since these are called from the scanner level.
715      * To avoid it, remember the current token and re-insert it if macro
716      * expansion is done.
717      */
718     E->Final = NewTokNode ();
719
720     /* Insert a new token input function */
721     PushInput (MacExpand, E, ".DEFINE");
722 }
723
724
725
726 void MacExpandStart (void)
727 /* Start expanding the macro in SVal */
728 {
729     /* Search for the macro */
730     Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
731     CHECK (M != 0);
732
733     /* Call the apropriate subroutine */
734     switch (M->Style) {
735         case MAC_STYLE_CLASSIC: StartExpClassic (M);    break;
736         case MAC_STYLE_DEFINE:  StartExpDefine (M);     break;
737         default:                Internal ("Invalid macro style: %d", M->Style);
738     }
739 }
740
741
742
743 void MacAbort (void)
744 /* Abort the current macro expansion */
745 {
746     /* Must have an expansion */
747     CHECK (MacExpansions > 0);
748
749     /* Set a flag so macro expansion will terminate on the next call */
750     DoMacAbort = 1;
751 }
752
753
754
755 int IsMacro (const char* Name)
756 /* Return true if the given name is the name of a macro */
757 {
758     return MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE) != 0;
759 }
760
761
762
763 int IsDefine (const char* Name)
764 /* Return true if the given name is the name of a define style macro */
765 {
766     Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
767     return (M != 0 && M->Style == MAC_STYLE_DEFINE);
768 }
769
770
771
772 int InMacExpansion (void)
773 /* Return true if we're currently expanding a macro */
774 {
775     return (MacExpansions > 0);
776 }
777
778
779
780
781
782