Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / cemcom / replace.c
1 /*
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".
4  */
5 /* $Id: replace.c,v 3.20 1994/06/24 12:05:46 ceriel Exp $ */
6 /* PREPROCESSOR: MACRO-TEXT REPLACEMENT ROUTINES */
7
8 #include        "nopp.h"
9
10 #ifndef NOPP
11 #include        "debug.h"       /* UF */
12 #include        "pathlength.h"  /* UF */
13 #include        "strsize.h"     /* UF */
14 #include        <alloc.h>
15 #include        "idf.h"
16 #include        "input.h"
17 #include        "macro.h"
18 #include        "arith.h"
19 #include        "LLlex.h"
20 #include        "class.h"
21 #include        "assert.h"
22 #include        "interface.h"
23 #include        "static.h"
24
25 char *strcpy(), *strcat();
26 char *long2str();
27 extern int InputLevel;
28
29 PRIVATE struct mlist    *ReplaceList;   /* list of currently active macros */
30
31 PRIVATE macro_func();
32 PRIVATE char *macro2buffer();
33 extern char **getactuals();
34
35 EXPORT int
36 replace(idef)
37         register struct idf *idef;
38 {
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.
47         */
48         register struct macro *mac = idef->id_macro;
49         register struct mlist *repl;
50         register int c;
51         char **actpars;
52         char *reptext;
53         int size;
54
55         if (mac->mc_flag & NOREPLACE) {
56                 lexwarning("macro %s is recursive", idef->id_text);
57                 return 0;
58         }
59         if (mac->mc_nps != -1) {        /* with parameter list  */
60                 if (mac->mc_flag & FUNC) {
61                                         /* must be "defined".
62                                            Unfortunately, the next assertion
63                                            will not compile ...
64                         ASSERT( ! strcmp("defined", idef->id_text));
65                                         */
66                         if (! AccDefined)
67                                 return 0;
68                 }
69                 if (++mac->mc_count > 100) {
70                         /* 100 must be some number in Parameters */
71                         lexwarning("macro %s is assumed recursive",
72                                     idef->id_text);
73                         return 0;
74                 }
75                 LoadChar(c);
76                 c = skipspaces(c,! (mac->mc_flag & FUNC));
77                 if (c != '(') {         /* no replacement if no ()      */
78                         PushBack();
79                         if (! (mac->mc_flag & FUNC)) {
80                                 lexerror("(warning) macro %s needs arguments",
81                                         idef->id_text);
82                                 return 0;
83                         }
84                 }
85                 if (mac->mc_flag & FUNC) {
86                         struct idf *param;
87                         extern struct idf *GetIdentifier();
88
89                         UnknownIdIsZero = 0;
90                         param = GetIdentifier();
91                         UnknownIdIsZero = 1;
92                         if (c == '(') {
93                                 LoadChar(c);
94                                 c = skipspaces(c,0);
95                                 if (c != ')') error(") missing");
96                         }
97                         if (! param) {
98                                 error("identifier missing");
99                         }
100                         repl = new_mlist();
101                         if (param && param->id_macro) 
102                                 reptext = "1";
103                         else
104                                 reptext = "0";
105                         InsertText(reptext, 1);
106                         InputLevel++;
107                         repl->m_level = InputLevel;
108                         repl->next = ReplaceList;
109                         ReplaceList = repl;
110                         repl->m_mac = mac;
111                         return 1;
112                 }
113                 actpars = getactuals(idef);     /* get act.param. list  */
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;
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 = ReplaceList;
132         ReplaceList = repl;
133         return 1;
134 }
135
136 GSTATIC 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                 FilNamBuf[0] = '"';
152                 strcpy(&FilNamBuf[1], FileName);
153                 strcat(FilNamBuf, "\"");
154                 mac->mc_text = FilNamBuf;
155                 mac->mc_length = strlen(FilNamBuf);
156                 break;
157         case 'L' :                      /* __LINE__     */
158                 mac->mc_text = long2str((long)LineNumber, 10);
159                 mac->mc_length = 1;
160                 break;
161         default :
162                 crash("(macro_func)");
163                 /*NOTREACHED*/
164         }
165 }
166
167 PRIVATE char *
168 macro2buffer(idef, actpars, siztext)
169         struct idf *idef;
170         char **actpars;
171         int *siztext;
172 {
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
179                 with its length.
180                 If there are no parameters, this function behaves
181                 the same as strcpy().
182         */
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;
187
188         while (*ptr) {
189                 if (*ptr & FORMALP) {   /* non-asc formal param. mark   */
190                         register int n = *ptr++ & 0177;
191                         register char *p;
192
193                         ASSERT(n != 0);
194                         /*      copy the text of the actual parameter
195                                 into the replacement text
196                         */
197                         for (p = actpars[n - 1]; *p; p++) {
198                                 text[pos++] = *p;
199                                 if (pos == size)
200                                         text = Srealloc(text, size += RSTRSIZE);
201                         }
202                 }
203                 else {
204                         text[pos++] = *ptr++;
205                         if (pos == size)
206                                 text = Srealloc(text, size += RSTRSIZE);
207                 }
208         }
209         text[pos] = '\0';
210         *siztext = pos;
211         return text;
212 }
213
214 EXPORT
215 DoUnstack()
216 {
217         Unstacked = 1;
218 }
219
220 EXPORT
221 EnableMacros()
222 {
223         register struct mlist *p = ReplaceList, *prev = 0;
224
225         ASSERT(Unstacked > 0);
226         while (p) {
227                 struct mlist *nxt = p->next;
228
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;
235                         free_mlist(p);
236                 }
237                 else prev = p;
238                 p = nxt;
239         }
240         Unstacked = 0;
241 }
242 #endif /* NOPP */