Pristine Ack-5.5
[Ack-5.5.git] / util / cpp / domacro.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: domacro.c,v 1.26 1994/06/24 10:18:07 ceriel Exp $ */
6 /* PREPROCESSOR: CONTROLLINE INTERPRETER */
7
8 #include        "interface.h"
9 #include        "LLlex.h"
10 #include        "Lpars.h"
11 #include        "debug.h"
12 #include        "idf.h"
13 #include        "input.h"
14
15 #include        "ifdepth.h"     
16 #include        "botch_free.h"  
17 #include        "nparams.h"     
18 #include        "parbufsize.h"  
19 #include        "textsize.h"    
20 #include        "idfsize.h"     
21 #include        <assert.h>
22 #include        <alloc.h>
23 #include        "class.h"
24 #include        "macro.h"
25 #include        "bits.h"
26
27 IMPORT char **inctable;         /* list of include directories          */
28 IMPORT char *getwdir();
29 PRIVATE char ifstack[IFDEPTH];  /* if-stack: the content of an entry is */
30                                 /* 1 if a corresponding ELSE has been   */
31                                 /* encountered.                         */
32
33 int nestlevel = -1;
34 int svnestlevel[30] = {-1};
35 int nestcount;
36 extern int do_preprocess;
37
38 char *
39 GetIdentifier()
40 {
41         /*      returns a pointer to the descriptor of the identifier that is
42                 read from the input stream. A null-pointer is returned if
43                 the input does not contain an identifier.
44                 The substitution of macros is disabled.
45         */
46         int tok;
47         struct token tk;
48
49         ReplaceMacros = 0;
50         tok = GetToken(&tk);
51         ReplaceMacros = 1;
52         return tok == IDENTIFIER ? tk.tk_str : (char *)0;
53 }
54
55 /*      domacro() is the control line interpreter. The '#' has already
56         been read by the lexical analyzer by which domacro() is called.
57         The token appearing directly after the '#' is obtained by calling
58         the basic lexical analyzing function GetToken() and is interpreted
59         to perform the action belonging to that token.
60         An error message is produced when the token is not recognized,
61         i.e. it is not one of "define" .. "undef" , integer or newline.
62 */
63 EXPORT
64 domacro()
65 {
66         struct token tk;        /* the token itself                     */
67         register struct idf *id;
68
69         switch(GetToken(&tk)) {         /* select control line action   */
70         case IDENTIFIER:                /* is it a macro keyword?       */
71                 id = findidf(tk.tk_str);
72                 if (!id) {
73                         error("%s: unknown control", tk.tk_str);
74                         skipline();
75                         free(tk.tk_str);
76                         break;
77                 }
78                 free(tk.tk_str);
79                 switch (id->id_resmac) {
80                 case K_DEFINE:                          /* "define"     */
81                         do_define();
82                         break;
83                 case K_ELIF:                            /* "elif"       */
84                         do_elif();
85                         break;
86                 case K_ELSE:                            /* "else"       */
87                         do_else();
88                         break;
89                 case K_ENDIF:                           /* "endif"      */
90                         do_endif();
91                         break;
92                 case K_IF:                              /* "if"         */
93                         do_if();
94                         break;
95                 case K_IFDEF:                           /* "ifdef"      */
96                         do_ifdef(1);
97                         break;
98                 case K_IFNDEF:                          /* "ifndef"     */
99                         do_ifdef(0);
100                         break;
101                 case K_INCLUDE:                         /* "include"    */
102                         do_include();
103                         break;
104                 case K_LINE:                            /* "line"       */
105                         /*      set LineNumber and FileName according to
106                                 the arguments.
107                         */
108                         if (GetToken(&tk) != INTEGER) {
109                                 error("#line without linenumber");
110                                 PushBack();
111                                 skipline();
112                         }
113                         else
114                                 do_line((unsigned int)tk.tk_val);
115                         break;
116                 case K_UNDEF:                           /* "undef"      */
117                         do_undef();
118                         break;
119                 case K_PRAGMA:                          /* "pragma"     */
120                         /*      ignore for now
121                         */
122                         skipline();
123                         break;
124                 default:
125                         /* invalid word seen after the '#'      */
126                         error("%s: unknown control", id->id_text);
127                         skipline();
128                 }
129                 break;
130         case INTEGER:           /* # <integer> [<filespecifier>]?       */
131                 do_line((unsigned int)tk.tk_val);
132                 break;
133         case EOF:       /* only `#' on this line: do nothing, ignore    */
134                 break;
135         default:        /* invalid token following '#'          */
136                 error("illegal # line");
137                 PushBack();
138                 skipline();
139         }
140 }
141
142 PRIVATE
143 skip_block(to_endif)
144 {
145         /*      skip_block() skips the input from
146                 1)      a false #if, #ifdef, #ifndef or #elif until the
147                         corresponding #elif (resulting in true), #else or
148                         #endif is read.
149                 2)      a #else corresponding to a true #if, #ifdef,
150                         #ifndef or #elif until the corresponding #endif is
151                         seen.
152         */
153         register int ch;
154         register int skiplevel = nestlevel; /* current nesting level    */
155         struct token tk;
156         struct idf *id;
157
158         NoUnstack++;
159         for (;;) {
160                 LoadChar(ch);   /* read first character after newline   */
161                 if (ch != '#') {
162                         if (ch == EOI) {
163                                 NoUnstack--;
164                                 return;
165                         }
166                         PushBack();
167                         skipline();
168                         continue;
169                 }
170                 if (GetToken(&tk) != IDENTIFIER) {
171                         PushBack();
172                         skipline();
173                         continue;
174                 }
175                 /*      an IDENTIFIER: look for #if, #ifdef and #ifndef
176                         without interpreting them.
177                         Interpret #else, #elif and #endif if they occur
178                         on the same level.
179                 */
180                 id = findidf(tk.tk_str);
181                 free(tk.tk_str);
182                 if (id) switch(id->id_resmac) {
183                 default:
184                         skipline();
185                         break;
186                 case K_IF:
187                 case K_IFDEF:
188                 case K_IFNDEF:
189                         push_if();
190                         skipline();
191                         continue;
192                 case K_ELIF:
193                         if (ifstack[nestlevel])
194                                 warning("#elif after #else/#elif");
195                         if (! to_endif && nestlevel == skiplevel) {
196                                 nestlevel--;
197                                 push_if();
198                                 if (ifexpr()) { /* implicit skipline() */
199                                         NoUnstack--;
200                                         return;
201                                 }
202                         }
203                         else skipline();
204                         break;
205                 case K_ELSE:
206                         if (ifstack[nestlevel])
207                                 warning("#else after #else/#elif");
208                         skipline();
209                         if (! to_endif) {
210                                 ++(ifstack[nestlevel]);
211                                 if (nestlevel == skiplevel) {
212                                         NoUnstack--;
213                                         return;
214                                 }
215                         }
216                         break;
217                 case K_ENDIF:
218                         assert(nestlevel >= 0);
219                         skipline();
220                         if (nestlevel == skiplevel) {
221                                 nestlevel--;
222                                 NoUnstack--;
223                                 return;
224                         }
225                         nestlevel--;
226                         break;
227                 }
228         }
229 }
230
231 PRIVATE
232 ifexpr()
233 {
234         /*      ifexpr() returns whether the restricted constant
235                 expression following #if or #elif evaluates to true.  This
236                 is done by calling the LLgen generated subparser for
237                 constant expressions.  The result of this expression will
238                 be given in the extern long variable "ifval".
239         */
240         IMPORT arith ifval;
241         int errors = err_occurred;
242
243         ifval = (arith)0;
244         AccDefined = 1;
245         UnknownIdIsZero = 1;
246         PushLex();      /* NEW parser */
247         If_expr();      /* invoke constant expression parser    */
248         PopLex();       /* OLD parser */
249         AccDefined = 0;
250         UnknownIdIsZero = 0;
251         return (errors == err_occurred) && (ifval != (arith)0);
252 }
253
254 PRIVATE
255 do_include()
256 {
257         /*      do_include() performs the inclusion of a file.
258         */
259         char *filenm;
260         char *result;
261         int tok;
262         struct token tk;
263
264         AccFileSpecifier = 1;
265         if (((tok = GetToken(&tk)) == FILESPECIFIER) || tok == STRING)
266                 filenm = tk.tk_str;
267         else {
268                 error("bad include syntax");
269                 filenm = (char *)0;
270         }
271         AccFileSpecifier = 0;
272         PushBack();
273         skipline();
274         inctable[0] = WorkingDir;
275         if (filenm) {
276                 if (!InsertFile(filenm, &inctable[tok==FILESPECIFIER],&result)){
277                         if (do_preprocess) error("cannot find include file \"%s\"", filenm);
278                         else warning("cannot find include file \"%s\"", filenm);
279                         add_dependency(filenm);
280                 }
281                 else {
282                         add_dependency(result);
283                         WorkingDir = getwdir(result);
284                         svnestlevel[++nestcount] = nestlevel;
285                         FileName = result;
286                         LineNumber = 1;
287                 }
288         }
289 }
290
291 PRIVATE
292 do_define()
293 {
294         /*      do_define() interprets a #define control line.
295         */
296         char *str;
297         int nformals = -1;      /* keep track of the number of formals  */
298         char *formals[NPARAMS]; /* pointers to the names of the formals */
299         char parbuf[PARBUFSIZE];                /* names of formals     */
300         char *repl_text;        /* start of the replacement text        */
301         int length;             /* length of the replacement text       */
302         register ch;
303         char *get_text();
304
305         /* read the #defined macro's name       */
306         if (!(str = GetIdentifier())) {
307                 error("#define: illegal macro name");
308                 PushBack();
309                 skipline();
310                 return;
311         }
312         /*      there is a formal parameter list if the identifier is
313                 followed immediately by a '('. 
314         */
315         LoadChar(ch);
316         if (ch == '(') {
317                 if ((nformals = getparams(formals, parbuf)) == -1) {
318                         PushBack();
319                         skipline();
320                         free(str);
321                         return; /* an error occurred    */
322                 }
323                 LoadChar(ch);
324         }
325         /* read the replacement text if there is any                    */
326         ch = skipspaces(ch,0);  /* find first character of the text     */
327         assert(ch != EOI);
328         if (class(ch) == STNL) {
329                 /*      Treat `#define something' as `#define something ""'
330                 */
331                 repl_text = "";
332                 length = 0;
333         }
334         else {
335                 PushBack();
336                 repl_text = get_text((nformals > 0) ? formals : 0, &length);
337         }
338         macro_def(str2idf(str, 0), repl_text, nformals, length, NOFLAG);
339         LineNumber++;
340 }
341
342 PRIVATE
343 push_if()
344 {
345         if (nestlevel >= IFDEPTH)
346                 fatal("too many nested #if/#ifdef/#ifndef");
347         else
348                 ifstack[++nestlevel] = 0;
349 }
350
351 PRIVATE
352 do_elif()
353 {
354         if (nestlevel <= svnestlevel[nestcount] || (ifstack[nestlevel])) {
355                 error("#elif without corresponding #if");
356                 skipline();
357         }
358         else { /* restart at this level as if a #if is detected.  */
359                 nestlevel--;
360                 push_if();
361                 skip_block(1);
362         }
363 }
364
365 PRIVATE
366 do_else()
367 {
368         skipline();
369         if (nestlevel <= svnestlevel[nestcount] || (ifstack[nestlevel]))
370                 error("#else without corresponding #if");
371         else {  /* mark this level as else-d            */
372                 ++(ifstack[nestlevel]);
373                 skip_block(1);
374         }
375 }
376
377 PRIVATE
378 do_endif()
379 {
380         skipline();
381         if (nestlevel <= svnestlevel[nestcount])
382                 error("#endif without corresponding #if");
383         else nestlevel--;
384 }
385
386 PRIVATE
387 do_if()
388 {
389         push_if();
390         if (!ifexpr())  /* a false #if/#elif expression */
391                 skip_block(0);
392 }
393
394 PRIVATE
395 do_ifdef(how)
396 {
397         register struct idf *id;
398         char *str;
399
400         /*      how == 1 : ifdef; how == 0 : ifndef
401         */
402         push_if();
403         str = GetIdentifier();
404         if (!str) {
405                 error("illegal #ifdef construction");
406                 id = 0;
407         }
408         else    {
409                 id = findidf(str);
410                 free(str);
411         }
412
413         /* The next test is a shorthand for:
414                 (how && !id->id_macro) || (!how && id->id_macro)
415         */
416         if (how ^ (id && id->id_macro != 0))
417                 skip_block(0);
418         else {
419                 PushBack();
420                 skipline();
421         }
422 }
423
424 PRIVATE
425 do_undef()
426 {
427         register struct idf *id;
428         register char *str = GetIdentifier();
429
430         /* Forget a macro definition.   */
431         if (str) {
432                 if (id = findidf(str)) {
433                         if (id->id_macro) { /* forget the macro */
434                                 free_macro(id->id_macro);
435                                 id->id_macro = (struct macro *) 0;
436                         } /* else: don't complain */
437                 }
438                 free(str);
439         }
440         else
441                 error("illegal #undef construction");
442         PushBack();
443         skipline();
444 }
445
446 PRIVATE
447 do_line(l)
448         unsigned int l;
449 {
450         struct token tk;
451         int t = GetToken(&tk);
452
453         PushBack();
454         skipline();
455         LineNumber = l;         /* the number of the next input line */
456         if (t == STRING)        /* is there a filespecifier? */
457                 FileName = tk.tk_str;
458 }
459
460 PRIVATE int
461 getparams(buf, parbuf)
462         char *buf[];
463         char parbuf[];
464 {
465         /*      getparams() reads the formal parameter list of a macro
466                 definition.
467                 The number of parameters is returned.
468                 As a formal parameter list is expected when calling this
469                 routine, -1 is returned if an error is detected, for
470                 example:
471                         #define one(1), where 1 is not an identifier.
472                 Note that the '(' has already been eaten.
473                 The names of the formal parameters are stored into parbuf.
474         */
475         register char **pbuf = &buf[0];
476         register int c;
477         register char *ptr = &parbuf[0];
478         register char **pbuf2;
479
480         LoadChar(c);
481         c = skipspaces(c,0);
482         if (c == ')') {         /* no parameters: #define name()        */
483                 *pbuf = (char *) 0;
484                 return 0;
485         }
486         for (;;) {              /* eat the formal parameter list        */
487                 if (class(c) != STIDF) {        /* not an identifier    */
488                         error("#define: bad formal parameter");
489                         return -1;
490                 }
491                 *pbuf = ptr;    /* name of the formal   */
492                 *ptr++ = c;
493                 if (ptr >= &parbuf[PARBUFSIZE])
494                         fatal("formal parameter buffer overflow");
495                 do {                    /* eat the identifier name      */
496                         LoadChar(c);
497                         *ptr++ = c;
498                         if (ptr >= &parbuf[PARBUFSIZE])
499                                 fatal("formal parameter buffer overflow");
500                 } while (in_idf(c));
501                 *(ptr - 1) = '\0';      /* mark end of the name         */
502
503                 /*      Check if this formal parameter is already used.
504                         Usually, macros do not have many parameters, so ...
505                 */
506                 for (pbuf2 = pbuf - 1; pbuf2 >= &buf[0]; pbuf2--) {
507                         if (!strcmp(*pbuf2, *pbuf)) {
508                                 warning("formal parameter \"%s\" already used",
509                                         *pbuf);
510                         }
511                 }
512
513                 pbuf++;
514                 c = skipspaces(c,0);
515                 if (c == ')') { /* end of the formal parameter list     */
516                         *pbuf = (char *) 0;
517                         return pbuf - buf;
518                 }
519                 if (c != ',') {
520                         error("#define: bad formal parameter list");
521                         return -1;
522                 }
523                 LoadChar(c);
524                 c = skipspaces(c,0);
525         }
526         /*NOTREACHED*/
527 }
528
529 EXPORT
530 macro_def(id, text, nformals, length, flags)
531         register struct idf *id;
532         char *text;
533 {
534         /*      macro_def() puts the contents and information of a macro
535                 definition into a structure and stores it into the symbol
536                 table entry belonging to the name of the macro.
537                 A warning is given if the definition overwrites another.
538         */
539         register struct macro *newdef = id->id_macro;
540         
541         if (newdef) {           /* is there a redefinition?     */
542                 if (macroeq(newdef->mc_text, text))
543                         return;
544                 warning("redefine \"%s\"", id->id_text);
545         }
546         else {
547 #ifdef DOBITS
548                 register char *p = id->id_text;
549 #define setbit(bx)      if (!*p) goto go_on; bits[*p++] |= (bx)
550                 setbit(bit0);
551                 setbit(bit1);
552                 setbit(bit2);
553                 setbit(bit3);
554                 setbit(bit4);
555                 setbit(bit5);
556                 setbit(bit6);
557                 setbit(bit7);
558                 
559         go_on:
560 #endif
561                 id->id_macro = newdef = new_macro();
562         }
563         newdef->mc_text = text;         /* replacement text     */
564         newdef->mc_nps  = nformals;     /* nr of formals        */
565         newdef->mc_length = length;     /* length of repl. text */
566         newdef->mc_flag = flags;        /* special flags        */
567         newdef->mc_count = 0;
568 }
569
570 PRIVATE int
571 find_name(nm, index)
572         char *nm, *index[];
573 {
574         /*      find_name() returns the index of "nm" in the namelist
575                 "index" if it can be found there.  0 is returned if it is
576                 not there.
577         */
578         register char **ip = &index[0];
579
580         while (*ip)
581                 if (strcmp(nm, *ip++) == 0)
582                         return ip - &index[0];
583         /* arrived here, nm is not in the name list.    */
584         return 0;
585 }
586
587 PRIVATE char *
588 get_text(formals, length)
589         char *formals[];
590         int *length;
591 {
592         /*      get_text() copies the replacement text of a macro
593                 definition with zero, one or more parameters, thereby
594                 substituting each formal parameter by a special character
595                 (non-ascii: 0200 & (order-number in the formal parameter
596                 list)) in order to substitute this character later by the
597                 actual parameter.  The replacement text is copied into
598                 itself because the copied text will contain fewer or the
599                 same amount of characters.  The length of the replacement
600                 text is returned.
601
602                 Implementation:
603                 finite automaton : we are only interested in
604                 identifiers, because they might be replaced by some actual
605                 parameter.  Other tokens will not be seen as such.
606         */
607         register int c;
608         register unsigned int text_size;
609         char *text = Malloc(text_size = ITEXTSIZE);
610         register unsigned int pos = 0;
611
612         LoadChar(c);
613
614         while ((c != EOI) && (class(c) != STNL)) {
615                 if (c == '\\') {        /* check for "\\\n"     */
616                         LoadChar(c);
617                         if (c == '\n') {
618                                 /*      More than one line is used for the
619                                         replacement text.
620                                         Replace "\\\n" by " ".
621                                 */
622                                 text[pos++] = ' ';
623                                 ++LineNumber;
624                                 LoadChar(c);
625                         }
626                         else
627                                 text[pos++] = '\\';
628                         if (pos == text_size)
629                                 text = Realloc(text, text_size <<= 1);
630                 }
631                 else
632                 if ( c == '/') {
633                         LoadChar(c);
634                         if (c == '*') {
635                                 skipcomment();
636                                 /* text[pos++] = ' '; ??? Why ??? */
637                                 LoadChar(c);
638                         }
639                         else
640                                 text[pos++] = '/';
641                         if (pos == text_size)
642                                 text = Realloc(text, text_size <<= 1);
643                 }
644                 else
645                 if (formals && class(c) == STIDF) {
646                         char id_buf[IDFSIZE + 1];
647                         register char *idp = id_buf;
648                         int n;
649
650                         /* read identifier: it may be a formal parameter */
651                         *idp++ = c;
652                         do {
653                                 LoadChar(c);
654                                 if (idp <= &id_buf[IDFSIZE])
655                                         *idp++ = c;
656                         } while (in_idf(c));
657                         *--idp = '\0';
658                         if (n = find_name(id_buf, formals)) {
659                                 /* construct the formal parameter mark  */
660                                 text[pos++] = FORMALP | (char) n;
661                                 if (pos == text_size)
662                                         text = Realloc(text,
663                                                 text_size <<= 1);
664                         }
665                         else {
666                                 int sz = idp - id_buf + 1;
667
668                                 idp = id_buf;
669
670                                 while (pos + sz >= text_size) text_size <<= 1;
671                                 text = Realloc(text, text_size);
672                                 while (text[pos++] = *idp++) ;
673                                 pos--;
674                         }
675                 }
676                 else {
677                         text[pos++] = c;
678                         if (pos == text_size)
679                                 text = Realloc(text, text_size <<= 1);
680                         LoadChar(c);
681                 }
682         }
683         text[pos++] = '\0';
684         text = Realloc(text, pos);
685         *length = pos - 1;
686         return text;
687 }
688
689 #define BLANK(ch)       ((ch == ' ') || (ch == '\t'))
690
691 /*      macroeq() decides whether two macro replacement texts are
692         identical.  This version compares the texts, which occur
693         as strings, without taking care of the leading and trailing
694         blanks (spaces and tabs).
695 */
696 PRIVATE
697 macroeq(s, t)
698         register char *s, *t;
699 {
700         
701         /* skip leading spaces  */
702         while (BLANK(*s)) s++;
703         while (BLANK(*t)) t++;
704         /* first non-blank encountered in both strings  */
705         /* The actual comparison loop:                  */
706         while (*s && *s == *t)
707                 s++, t++;
708         /* two cases are possible when arrived here:    */
709         if (*s == '\0') {       /* *s == '\0'           */
710                 while (BLANK(*t)) t++;
711                 return *t == '\0';
712         }
713         else    {               /* *s != *t             */
714                 while (BLANK(*s)) s++;
715                 while (BLANK(*t)) t++;
716                 return (*s == '\0') && (*t == '\0');
717         }
718 }