1/*****************************************************************************/
2/* */
3/* macrotab.h */
4/* */
5/* Preprocessor macro table for the cc65 C compiler */
6/* */
7/* */
8/* */
9/* (C) 2000-2011, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
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 "hashfunc.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
57static Macro* MacroTab[MACRO_TAB_SIZE];
58
59
60
61/*****************************************************************************/
62/* code */
63/*****************************************************************************/
64
65
66
67Macro* NewMacro (const char* Name)
68/* Allocate a macro structure with the given name. The structure is not
69** inserted into the macro table.
70*/
71{
72 /* Get the length of the macro name */
73 unsigned Len = strlen(Name);
74
75 /* Allocate the structure */
76 Macro* M = (Macro*) xmalloc (sizeof(Macro) + Len);
77
78 /* Initialize the data */
79 M->Next = 0;
80 M->Expanding = 0;
81 M->ArgCount = -1; /* Flag: Not a function like macro */
82 M->MaxArgs = 0;
83 InitCollection (&M->FormalArgs);
84 SB_Init (&M->Replacement);
85 M->Variadic = 0;
86 memcpy (M->Name, Name, Len+1);
87
88 /* Return the new macro */
89 return M;
90}
91
92
93
94void FreeMacro (Macro* M)
95/* Delete a macro definition. The function will NOT remove the macro from the
96** table, use UndefineMacro for that.
97*/
98{
99 unsigned I;
100
101 for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
102 xfree (CollAtUnchecked (&M->FormalArgs, I));
103 }
104 DoneCollection (&M->FormalArgs);
105 SB_Done (&M->Replacement);
106 xfree (M);
107}
108
109
110
111void DefineNumericMacro (const char* Name, long Val)
112/* Define a macro for a numeric constant */
113{
114 char Buf[64];
115
116 /* Make a string from the number */
117 sprintf (Buf, "%ld", Val);
118
119 /* Handle as text macro */
120 DefineTextMacro (Name, Buf);
121}
122
123
124
125void DefineTextMacro (const char* Name, const char* Val)
126/* Define a macro for a textual constant */
127{
128 /* Create a new macro */
129 Macro* M = NewMacro (Name);
130
131 /* Set the value as replacement text */
132 SB_CopyStr (&M->Replacement, Val);
133
134 /* Insert the macro into the macro table */
135 InsertMacro (M);
136}
137
138
139
140void InsertMacro (Macro* M)
141/* Insert the given macro into the macro table. */
142{
143 /* Get the hash value of the macro name */
144 unsigned Hash = HashStr (M->Name) % MACRO_TAB_SIZE;
145
146 /* Insert the macro */
147 M->Next = MacroTab[Hash];
148 MacroTab[Hash] = M;
149}
150
151
152
153int UndefineMacro (const char* Name)
154/* Search for the macro with the given name and remove it from the macro
155** table if it exists. Return 1 if a macro was found and deleted, return
156** 0 otherwise.
157*/
158{
159 /* Get the hash value of the macro name */
160 unsigned Hash = HashStr (Name) % MACRO_TAB_SIZE;
161
162 /* Search the hash chain */
163 Macro* L = 0;
164 Macro* M = MacroTab[Hash];
165 while (M) {
166 if (strcmp (M->Name, Name) == 0) {
167
168 /* Found it */
169 if (L == 0) {
170 /* First in chain */
171 MacroTab[Hash] = M->Next;
172 } else {
173 L->Next = M->Next;
174 }
175
176 /* Delete the macro */
177 FreeMacro (M);
178
179 /* Done */
180 return 1;
181 }
182
183 /* Next macro */
184 L = M;
185 M = M->Next;
186 }
187
188 /* Not found */
189 return 0;
190}
191
192
193
194Macro* FindMacro (const char* Name)
195/* Find a macro with the given name. Return the macro definition or NULL */
196{
197 /* Get the hash value of the macro name */
198 unsigned Hash = HashStr (Name) % MACRO_TAB_SIZE;
199
200 /* Search the hash chain */
201 Macro* M = MacroTab[Hash];
202 while (M) {
203 if (strcmp (M->Name, Name) == 0) {
204 /* Found it */
205 return M;
206 }
207
208 /* Next macro */
209 M = M->Next;
210 }
211
212 /* Not found */
213 return 0;
214}
215
216
217
218int FindMacroArg (Macro* M, const char* Arg)
219/* Search for a formal macro argument. If found, return the index of the
220** argument. If the argument was not found, return -1.
221*/
222{
223 unsigned I;
224 for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
225 if (strcmp (CollAtUnchecked (&M->FormalArgs, I), Arg) == 0) {
226 /* Found */
227 return I;
228 }
229 }
230
231 /* Not found */
232 return -1;
233}
234
235
236
237void AddMacroArg (Macro* M, const char* Arg)
238/* Add a formal macro argument. */
239{
240 /* Check if we have a duplicate macro argument, but add it anyway.
241 ** Beware: Don't use FindMacroArg here, since the actual argument array
242 ** may not be initialized.
243 */
244 unsigned I;
245 for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
246 if (strcmp (CollAtUnchecked (&M->FormalArgs, I), Arg) == 0) {
247 /* Found */
248 Error ("Duplicate macro parameter: '%s'", Arg);
249 break;
250 }
251 }
252
253 /* Add the new argument */
254 CollAppend (&M->FormalArgs, xstrdup (Arg));
255 ++M->ArgCount;
256}
257
258
259
260int MacroCmp (const Macro* M1, const Macro* M2)
261/* Compare two macros and return zero if both are identical. */
262{
263 int I;
264
265 /* Argument count must be identical */
266 if (M1->ArgCount != M2->ArgCount) {
267 return 1;
268 }
269
270 /* Compare the arguments */
271 for (I = 0; I < M1->ArgCount; ++I) {
272 if (strcmp (CollConstAt (&M1->FormalArgs, I),
273 CollConstAt (&M2->FormalArgs, I)) != 0) {
274 return 1;
275 }
276 }
277
278 /* Compare the replacement */
279 return SB_Compare (&M1->Replacement, &M2->Replacement);
280}
281
282
283
284void PrintMacroStats (FILE* F)
285/* Print macro statistics to the given text file. */
286{
287 unsigned I;
288 Macro* M;
289
290 fprintf (F, "\n\nMacro Hash Table Summary\n");
291 for (I = 0; I < MACRO_TAB_SIZE; ++I) {
292 fprintf (F, "%3u : ", I);
293 M = MacroTab [I];
294 if (M) {
295 while (M) {
296 fprintf (F, "%s ", M->Name);
297 M = M->Next;
298 }
299 fprintf (F, "\n");
300 } else {
301 fprintf (F, "empty\n");
302 }
303 }
304}
305