Pristine Ack-5.5
[Ack-5.5.git] / util / cpp / replace.c
1 /* $Id: replace.c,v 1.18 1994/06/24 10:18:57 ceriel Exp $ */
2 /*
3  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
4  * See the copyright notice in the ACK home directory, in the file "Copyright".
5  */
6 /* PREPROCESSOR: MACRO-TEXT REPLACEMENT ROUTINES */
7
8 #include        "debug.h"       /* UF */
9 #include        "pathlength.h"  /* UF */
10 #include        "textsize.h"    /* UF */
11
12 #include        <alloc.h>
13 #include        <assert.h>
14 #include        "idf.h"
15 #include        "input.h"
16 #include        "macro.h"
17 #include        "LLlex.h"
18 #include        "class.h"
19 #include        "interface.h"
20
21 char *strcpy(), *strcat();
22 char *long2str();
23 extern int InputLevel;
24
25 PRIVATE struct mlist *ReplList; /* list of currently active macros */
26
27 EXPORT int
28 replace(idef)
29         register struct idf *idef;
30 {
31         /*      replace() is called by the lexical analyzer to perform
32                 macro replacement.  "idef" is the description of the
33                 identifier which leads to the replacement.  If the
34                 optional actual parameters of the macro are OK, the text
35                 of the macro is prepared to serve as an input buffer,
36                 which is pushed onto the input stack.
37                 replace() returns 1 if the replacement succeeded and 0 if
38                 some error has occurred.
39         */
40         register struct macro *mac = idef->id_macro;
41         register char c;
42         char **actpars, **getactuals();
43         char *reptext, *macro2buffer();
44         register struct mlist *repl;
45         int size;
46
47         if (mac->mc_flag & NOREPLACE) {
48                 warning("macro %s is recursive", idef->id_text);
49                 return 0;
50         }
51         if (mac->mc_nps != -1) {        /* with parameter list  */
52                 if (mac->mc_flag & FUNC) {
53                                         /* must be "defined".
54                                            Unfortunately, the next assertion
55                                            will not compile ...
56                         assert( ! strcmp("defined", idef->id_text));
57                                         */
58                         if (! AccDefined)
59                                 return 0;
60                 }
61                 if (++mac->mc_count > 100) {
62                         /* 100 must be some number in Parameters */
63                         warning("macro %s is assumed recursive",
64                                     idef->id_text);
65                         return 0;
66                 }
67                 LoadChar(c);
68                 c = skipspaces(c,! (mac->mc_flag & FUNC));
69                 if (c != '(') {         /* no replacement if no ()      */
70                         PushBack();
71                         if (! (mac->mc_flag & FUNC)) {
72                                 warning("macro %s needs arguments",
73                                         idef->id_text);
74                                 return 0;
75                         }
76                 }
77                 if (mac->mc_flag & FUNC) {
78                         struct idf *param;
79                         char *nam;
80                         extern char *GetIdentifier();
81
82                         UnknownIdIsZero = 0;
83                         nam = GetIdentifier();
84                         if (nam) {
85                                 param = findidf(nam);
86                         }
87                         else    param = 0;
88                         UnknownIdIsZero = 1;
89                         if (c == '(') {
90                                 LoadChar(c);
91                                 c = skipspaces(c, 0);
92                                 if (c != ')') error(") missing");
93                         }
94                         if (! nam) {
95                                 error("identifier missing");
96                         }
97                         repl = new_mlist();
98                         if (param && param->id_macro) 
99                                 reptext = "1 ";
100                         else
101                                 reptext = "0 ";
102                         InsertText(reptext, 2);
103                         InputLevel++;
104                         repl->m_level = InputLevel;
105
106                         repl->next = ReplList;
107                         ReplList = repl;
108                         repl->m_mac = mac;
109                         if (nam) free(nam);
110                         return 1;
111                 }
112                 actpars = getactuals(idef);     /* get act.param. list  */
113         }
114
115         repl = new_mlist();
116         repl->m_mac = mac;
117         if (mac->mc_flag & FUNC) /* this macro leads to special action  */
118                 macro_func(idef);
119         if (mac->mc_nps <= 0) {
120                 reptext = mac->mc_text;
121                 size = mac->mc_length;
122                 mac->mc_flag |= NOREPLACE;      /* a file called __FILE__ ??? */
123         }
124         else {
125                 reptext = macro2buffer(idef, actpars, &size); /* create input buffer */
126                 repl->m_repl = reptext;
127         }
128         InsertText(reptext, size);
129         InputLevel++;
130         repl->m_level = InputLevel;
131         repl->next = ReplList;
132         ReplList = repl;
133         return 1;
134 }
135
136 char FilNamBuf[PATHLENGTH];
137
138 PRIVATE
139 macro_func(idef)
140         register struct idf *idef;
141 {
142         /*      macro_func() performs the special actions needed with some
143                 macros.  These macros are __FILE__ and __LINE__ which
144                 replacement texts must be evaluated at the time they are
145                 used.
146         */
147         register struct macro *mac = idef->id_macro;
148
149         switch (idef->id_text[2]) { /* This switch is very blunt... */
150         case 'F' :                      /* __FILE__     */
151                 mac->mc_length = strlen(FileName) + 2;
152                 mac->mc_text = FilNamBuf;
153                 mac->mc_text[0] = '"';
154                 strcpy(&(mac->mc_text[1]), FileName);
155                 strcat(mac->mc_text, "\"");
156                 break;
157         case 'L' :                      /* __LINE__     */
158         {
159                 mac->mc_text = long2str((long) LineNumber, 10);
160                 mac->mc_length = strlen(mac->mc_text);
161                 break;
162         }
163         default :
164                 crash("(macro_func)");
165         }
166 }
167
168 PRIVATE char *
169 macro2buffer(idef, actpars, siztext)
170         struct idf *idef;
171         char **actpars;
172         int *siztext;
173 {
174         /*      Macro2buffer() turns the macro replacement text, as it is
175                 stored, into an input buffer, while each occurrence of the
176                 non-ascii formal parameter mark is replaced by its
177                 corresponding actual parameter specified in the actual
178                 parameter list actpars.  A pointer to the beginning of the
179                 constructed text is returned, while *siztext is filled
180                 with its length.
181                 If there are no parameters, this function behaves
182                 the same as strcpy().
183         */
184         register unsigned int size = idef->id_macro->mc_length + ITEXTSIZE;
185         register char *text = Malloc(size);
186         register int pos = 0;
187         register char *ptr = idef->id_macro->mc_text;
188
189         while (*ptr) {
190                 if (*ptr & FORMALP) {   /* non-asc formal param. mark   */
191                         register int n = *ptr++ & 0177;
192                         register char *p;
193
194                         assert(n != 0);
195                         /*      copy the text of the actual parameter
196                                 into the replacement text
197                         */
198                         for (p = actpars[n - 1]; *p; p++) {
199                                 text[pos++] = *p;
200                                 if (pos == size)
201                                         text = Realloc(text, size <<= 1);
202                         }
203                 }
204                 else {
205                         text[pos++] = *ptr++;
206                         if (pos == size)
207                                 text = Realloc(text, size <<= 1);
208                 }
209         }
210         text[pos] = '\0';
211         *siztext = pos;
212         return Realloc(text, pos+1);
213 }
214
215 EXPORT
216 DoUnstack()
217 {
218         Unstacked = 1;
219 }
220
221 EXPORT
222 EnableMacros()
223 {
224         register struct mlist *p = ReplList, *prev = 0;
225
226         assert(Unstacked > 0);
227         while (p) {
228                 struct mlist *nxt = p->next;
229
230                 if (p->m_level > InputLevel) {
231                         p->m_mac->mc_flag &= ~NOREPLACE;
232                         if (p->m_mac->mc_count) p->m_mac->mc_count--;
233                         if (p->m_repl) free(p->m_repl);
234                         if (! prev) ReplList = nxt;
235                         else prev->next = nxt;
236                         free_mlist(p);
237                 }
238                 else prev = p;
239                 p = nxt;
240         }
241         Unstacked = 0;
242 }