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