2 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3 * See the copyright notice in the ACK home directory, in the file "Copyright".
5 /* $Id: replace.c,v 3.20 1994/06/24 12:05:46 ceriel Exp $ */
6 /* PREPROCESSOR: MACRO-TEXT REPLACEMENT ROUTINES */
11 #include "debug.h" /* UF */
12 #include "pathlength.h" /* UF */
13 #include "strsize.h" /* UF */
22 #include "interface.h"
25 char *strcpy(), *strcat();
27 extern int InputLevel;
29 PRIVATE struct mlist *ReplaceList; /* list of currently active macros */
32 PRIVATE char *macro2buffer();
33 extern char **getactuals();
37 register struct idf *idef;
39 /* replace() is called by the lexical analyzer to perform
40 macro replacement. "idef" is the description of the
41 identifier which leads to the replacement. If the
42 optional actual parameters of the macro are OK, the text
43 of the macro is prepared to serve as an input buffer,
44 which is pushed onto the input stack.
45 replace() returns 1 if the replacement succeeded and 0 if
46 some error has occurred.
48 register struct macro *mac = idef->id_macro;
49 register struct mlist *repl;
55 if (mac->mc_flag & NOREPLACE) {
56 lexwarning("macro %s is recursive", idef->id_text);
59 if (mac->mc_nps != -1) { /* with parameter list */
60 if (mac->mc_flag & FUNC) {
62 Unfortunately, the next assertion
64 ASSERT( ! strcmp("defined", idef->id_text));
69 if (++mac->mc_count > 100) {
70 /* 100 must be some number in Parameters */
71 lexwarning("macro %s is assumed recursive",
76 c = skipspaces(c,! (mac->mc_flag & FUNC));
77 if (c != '(') { /* no replacement if no () */
79 if (! (mac->mc_flag & FUNC)) {
80 lexerror("(warning) macro %s needs arguments",
85 if (mac->mc_flag & FUNC) {
87 extern struct idf *GetIdentifier();
90 param = GetIdentifier();
95 if (c != ')') error(") missing");
98 error("identifier missing");
101 if (param && param->id_macro)
105 InsertText(reptext, 1);
107 repl->m_level = InputLevel;
108 repl->next = ReplaceList;
113 actpars = getactuals(idef); /* get act.param. list */
117 if (mac->mc_flag & FUNC) /* this macro leads to special action */
119 if (mac->mc_nps <= 0) {
120 reptext = mac->mc_text;
121 size = mac->mc_length;
122 mac->mc_flag |= NOREPLACE;
125 reptext = macro2buffer(idef, actpars, &size); /* create input buffer */
126 repl->m_repl = reptext;
128 InsertText(reptext, size);
130 repl->m_level = InputLevel;
131 repl->next = ReplaceList;
136 GSTATIC char FilNamBuf[PATHLENGTH];
140 register struct idf *idef;
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
147 register struct macro *mac = idef->id_macro;
149 switch (idef->id_text[2]) { /* This switch is very blunt... */
150 case 'F' : /* __FILE__ */
152 strcpy(&FilNamBuf[1], FileName);
153 strcat(FilNamBuf, "\"");
154 mac->mc_text = FilNamBuf;
155 mac->mc_length = strlen(FilNamBuf);
157 case 'L' : /* __LINE__ */
158 mac->mc_text = long2str((long)LineNumber, 10);
162 crash("(macro_func)");
168 macro2buffer(idef, actpars, siztext)
173 /* Macro2buffer() turns the macro replacement text, as it is
174 stored, into an input buffer, while each occurrence of the
175 non-ascii formal parameter mark is replaced by its
176 corresponding actual parameter specified in the actual
177 parameter list actpars. A pointer to the beginning of the
178 constructed text is returned, while *siztext is filled
180 If there are no parameters, this function behaves
181 the same as strcpy().
183 register int size = 8;
184 register char *text = Malloc(size);
185 register int pos = 0;
186 register char *ptr = idef->id_macro->mc_text;
189 if (*ptr & FORMALP) { /* non-asc formal param. mark */
190 register int n = *ptr++ & 0177;
194 /* copy the text of the actual parameter
195 into the replacement text
197 for (p = actpars[n - 1]; *p; p++) {
200 text = Srealloc(text, size += RSTRSIZE);
204 text[pos++] = *ptr++;
206 text = Srealloc(text, size += RSTRSIZE);
223 register struct mlist *p = ReplaceList, *prev = 0;
225 ASSERT(Unstacked > 0);
227 struct mlist *nxt = p->next;
229 if (p->m_level > InputLevel) {
230 p->m_mac->mc_flag &= ~NOREPLACE;
231 if (p->m_mac->mc_count) p->m_mac->mc_count--;
232 if (p->m_repl) free(p->m_repl);
233 if (! prev) ReplaceList = nxt;
234 else prev->next = nxt;