]> git.sur5r.net Git - cc65/blob - src/cc65/macrotab.c
45a290fe7f6845a89d379ae121b75bba4be0acb2
[cc65] / src / cc65 / macrotab.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                macrotab.h                                 */
4 /*                                                                           */
5 /*             Preprocessor macro table for the cc65 C compiler              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 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 "hashstr.h"
41 #include "xmalloc.h"
42
43 /* cc65 */
44 #include "error.h"
45 #include "macrotab.h"
46
47
48
49 /*****************************************************************************/
50 /*                                   data                                    */
51 /*****************************************************************************/
52
53
54
55 /* The macro hash table */
56 #define MACRO_TAB_SIZE  211
57 static Macro* MacroTab[MACRO_TAB_SIZE];
58
59 /* A table that holds the count of macros that start with a specific character.
60  * It is used to determine quickly, if an identifier may be a macro or not
61  * without calculating the hash over the name.
62  */
63 static unsigned short MacroFlagTab[256];
64
65
66
67 /*****************************************************************************/
68 /*                                   code                                    */
69 /*****************************************************************************/
70
71
72
73 Macro* NewMacro (const char* Name)
74 /* Allocate a macro structure with the given name. The structure is not
75  * inserted into the macro table.
76  */
77 {
78     /* Get the length of the macro name */
79     unsigned Len = strlen(Name);
80
81     /* Allocate the structure */
82     Macro* M = (Macro*) xmalloc (sizeof(Macro) + Len);
83
84     /* Initialize the data */
85     M->Next        = 0;
86     M->ArgCount    = -1;        /* Flag: Not a function like macro */
87     M->MaxArgs     = 0;
88     M->FormalArgs  = 0;
89     M->ActualArgs  = 0;
90     M->Replacement = 0;
91     memcpy (M->Name, Name, Len+1);
92
93     /* Return the new macro */
94     return M;
95 }
96
97
98
99 void FreeMacro (Macro* M)
100 /* Delete a macro definition. The function will NOT remove the macro from the
101  * table, use UndefineMacro for that.
102  */
103 {
104     int I;
105
106     for (I = 0; I < M->ArgCount; ++I) {
107         xfree (M->FormalArgs[I]);
108     }
109     xfree (M->FormalArgs);
110     xfree (M->ActualArgs);
111     xfree (M->Replacement);
112     xfree (M);
113 }
114
115
116
117 void DefineNumericMacro (const char* Name, long Val)
118 /* Define a macro for a numeric constant */
119 {
120     char Buf[64];
121
122     /* Make a string from the number */
123     sprintf (Buf, "%ld", Val);
124
125     /* Handle as text macro */
126     DefineTextMacro (Name, Buf);
127 }
128
129
130
131 void DefineTextMacro (const char* Name, const char* Val)
132 /* Define a macro for a textual constant */
133 {
134     /* Create a new macro */
135     Macro* M = NewMacro (Name);
136
137     /* Set the value as replacement text */
138     M->Replacement = xstrdup (Val);
139
140     /* Insert the macro into the macro table */
141     InsertMacro (M);
142 }
143
144
145
146 void InsertMacro (Macro* M)
147 /* Insert the given macro into the macro table. This call will also allocate
148  * the ActualArgs parameter array.
149  */
150 {
151     unsigned Hash;
152
153     /* Allocate the ActualArgs parameter array */
154     if (M->ArgCount > 0) {
155         M->ActualArgs = (char const**) xmalloc (M->ArgCount * sizeof(char*));
156     }
157
158     /* Get the hash value of the macro name */
159     Hash = HashStr (M->Name) % MACRO_TAB_SIZE;
160
161     /* Insert the macro */
162     M->Next = MacroTab[Hash];
163     MacroTab[Hash] = M;
164
165     /* Increment the number of macros starting with this char */
166     MacroFlagTab[(unsigned)(unsigned char)M->Name[0]]++;
167 }
168
169
170
171 int UndefineMacro (const char* Name)
172 /* Search for the macro with the given name and remove it from the macro
173  * table if it exists. Return 1 if a macro was found and deleted, return
174  * 0 otherwise.
175  */
176 {
177     /* Get the hash value of the macro name */
178     unsigned Hash = HashStr (Name) % MACRO_TAB_SIZE;
179
180     /* Search the hash chain */
181     Macro* L = 0;
182     Macro* M = MacroTab[Hash];
183     while (M) {
184         if (strcmp (M->Name, Name) == 0) {
185
186             /* Found it */
187             if (L == 0) {
188                 /* First in chain */
189                 MacroTab[Hash] = M->Next;
190             } else {
191                 L->Next = M->Next;
192             }
193
194             /* Decrement the number of macros starting with this char */
195             MacroFlagTab[(unsigned)(unsigned char)M->Name[0]]--;
196
197             /* Delete the macro */
198             FreeMacro (M);
199
200             /* Done */
201             return 1;
202         }
203
204         /* Next macro */
205         L = M;
206         M = M->Next;
207     }
208
209     /* Not found */
210     return 0;
211 }
212
213
214
215 Macro* FindMacro (const char* Name)
216 /* Find a macro with the given name. Return the macro definition or NULL */
217 {
218     /* Get the hash value of the macro name */
219     unsigned Hash = HashStr (Name) % MACRO_TAB_SIZE;
220
221     /* Search the hash chain */
222     Macro* M = MacroTab[Hash];
223     while (M) {
224         if (strcmp (M->Name, Name) == 0) {
225             /* Found it */
226             return M;
227         }
228
229         /* Next macro */
230         M = M->Next;
231     }
232
233     /* Not found */
234     return 0;
235 }
236
237
238
239 int IsMacro (const char* Name)
240 /* Return true if the given name is the name of a macro, return false otherwise */
241 {
242     return MaybeMacro(Name[0]) && FindMacro(Name) != 0;
243 }              
244
245
246
247 int MaybeMacro (unsigned char C)
248 /* Return true if the given character may be the start of the name of an
249  * existing macro, return false if not.
250  */
251 {
252     return (MacroFlagTab[C] > 0);
253 }
254
255
256
257 const char* FindMacroArg (Macro* M, const char* Arg)
258 /* Search for a formal macro argument. If found, return the actual
259  * (replacement) argument. If the argument was not found, return NULL.
260  */
261 {
262     int I;
263     for (I = 0; I < M->ArgCount; ++I) {
264         if (strcmp (M->FormalArgs[I], Arg) == 0) {
265             /* Found */
266             return M->ActualArgs[I];
267         }
268     }
269     /* Not found */
270     return 0;
271 }
272
273
274
275 void AddMacroArg (Macro* M, const char* Arg)
276 /* Add a formal macro argument. */
277 {
278     /* Check if we have a duplicate macro argument, but add it anyway.
279      * Beware: Don't use FindMacroArg here, since the actual argument array
280      * may not be initialized.
281      */
282     int I;
283     for (I = 0; I < M->ArgCount; ++I) {
284         if (strcmp (M->FormalArgs[I], Arg) == 0) {
285             /* Found */
286             Error ("Duplicate macro parameter: `%s'", Arg);
287             break;
288         }
289     }
290
291     /* Check if we have enough room available, otherwise expand the array
292      * that holds the formal argument list.
293      */
294     if (M->ArgCount >= (int) M->MaxArgs) {
295         /* We must expand the array */
296         char** OldArgs = M->FormalArgs;
297         M->MaxArgs += 10;
298         M->FormalArgs = (char**) xmalloc (M->MaxArgs * sizeof(char*));
299         memcpy (M->FormalArgs, OldArgs, M->ArgCount * sizeof (char*));
300         xfree (OldArgs);
301     }
302
303     /* Add the new argument */
304     M->FormalArgs[M->ArgCount++] = xstrdup (Arg);
305 }
306
307
308
309 int MacroCmp (const Macro* M1, const Macro* M2)
310 /* Compare two macros and return zero if both are identical. */
311 {
312     int I;
313
314     /* Argument count must be identical */
315     if (M1->ArgCount != M2->ArgCount) {
316         return 1;
317     }
318
319     /* Compare the arguments */
320     for (I = 0; I < M1->ArgCount; ++I) {
321         if (strcmp (M1->FormalArgs[I], M2->FormalArgs[I]) != 0) {
322             return 1;
323         }
324     }
325
326     /* Compare the replacement */
327     return strcmp (M1->Replacement, M2->Replacement);
328 }
329
330
331
332 void PrintMacroStats (FILE* F)
333 /* Print macro statistics to the given text file. */
334 {
335     unsigned I;
336     Macro* M;
337
338     fprintf (F, "\n\nMacro Hash Table Summary\n");
339     for (I = 0; I < MACRO_TAB_SIZE; ++I) {
340         fprintf (F, "%3u : ", I);
341         M = MacroTab [I];
342         if (M) {
343             while (M) {
344                 fprintf (F, "%s ", M->Name);
345                 M = M->Next;
346             }
347             fprintf (F, "\n");
348         } else {
349             fprintf (F, "empty\n");
350         }
351     }
352 }
353
354
355