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