Imported Upstream version 15.8a
[platform/upstream/cscope.git] / src / scanner.l
1 %{
2 /*===========================================================================
3  Copyright (c) 1998-2000, The Santa Cruz Operation 
4  All rights reserved.
5  
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions are met:
8
9  *Redistributions of source code must retain the above copyright notice,
10  this list of conditions and the following disclaimer.
11
12  *Redistributions in binary form must reproduce the above copyright notice,
13  this list of conditions and the following disclaimer in the documentation
14  and/or other materials provided with the distribution.
15
16  *Neither name of The Santa Cruz Operation nor the names of its contributors
17  may be used to endorse or promote products derived from this software
18  without specific prior written permission. 
19
20  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
21  IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
24  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  INTERRUPTION)
28  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31  DAMAGE. 
32  =========================================================================*/
33
34 /*      cscope - interactive C symbol cross-reference
35  *
36  *      C symbol scanner
37  */
38 #include "global.h"
39 #include "scanner.h"
40 #include "lookup.h"
41
42 /* the line counting has been moved from character reading for speed */
43 /* comments are discarded */
44
45 #define IFLEVELINC      5       /* #if nesting level size increment */
46
47 static char const rcsid[] = "$Id: scanner.l,v 1.10 2011/06/29 15:48:00 nhorman Exp $";
48
49 int     first;  /* buffer index for first char of symbol */
50 int     last;   /* buffer index for last char of symbol */
51 int     lineno; /* symbol line number */
52 int     myylineno = 1;
53
54 static  BOOL    arraydimension;         /* inside array dimension declaration */
55 static  BOOL    bplisting;              /* breakpoint listing */
56 static  int     braces;                 /* unmatched left brace count */
57 static  BOOL    classdef;               /* c++ class definition */
58 static  BOOL    elseelif;               /* #else or #elif found */
59 static  BOOL    esudef;                 /* enum/struct/union global definition */
60 static  BOOL    external;               /* external definition */
61 static  int     externalbraces;         /* external definition outer brace count */
62 static  BOOL    fcndef;                 /* function definition */
63 static  BOOL    global;                 /* file global scope (outside functions) */
64 static  int     iflevel;                /* #if nesting level */
65 static  BOOL    initializer;            /* data initializer */
66 static  int     initializerbraces;      /* data initializer outer brace count */
67 static  BOOL    lex;                    /* lex file */
68 static  int     miflevel = IFLEVELINC;  /* maximum #if nesting level */
69 static  int     *maxifbraces;           /* maximum brace count within #if */
70 static  int     *preifbraces;           /* brace count before #if */
71 static  int     parens;                 /* unmatched left parenthesis count */
72 static  BOOL    ppdefine;               /* preprocessor define statement */
73 static  BOOL    pseudoelif;             /* pseudo-#elif */
74 static  BOOL    oldtype;                /* next identifier is an old type */
75 static  BOOL    rules;                  /* lex/yacc rules */
76 static  BOOL    sdl;                    /* sdl file */
77 static  BOOL    structfield;            /* structure field declaration */
78 static  int     tagdef;                 /* class/enum/struct/union tag definition */
79 static  BOOL    template;               /* function template */
80 static  int     templateparens;         /* function template outer parentheses count */
81 static  int     typedefbraces = -1;     /* initial typedef brace count */
82 static  int     token;                  /* token found */
83
84
85 void    multicharconstant(char terminator);
86 int     skipcomment_input(void);
87 int     comment(void);
88
89 #ifdef FLEX_SCANNER
90 #define YY_INPUT(buf,result,max_size) \
91         {\
92                 int c = skipcomment_input (); \
93                 result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
94         }
95 #else
96 /* Assume this is the AT&T/SCO style lex */
97 #undef  input
98 #define input()  ((yytchar=(yytchar=yysptr>yysbuf?*(unsigned char *)--yysptr:getc(yyin))=='/'?comment():yytchar)==EOF?LEXEOF:yytchar)
99 #define noncommentinput()  ((yytchar=yysptr>yysbuf?*--yysptr:getc(yyin))==EOF?LEXEOF:yytchar)
100 #undef  unput
101 #define unput(c) (*yysptr++=(c))
102
103 #endif
104
105 %}
106
107 ws              [ \t\r\v\f]
108 wsnl            [ \t\r\v\f\n]
109 identifier      [a-zA-Z_$][a-zA-Z_0-9$]*
110 number          \.?[0-9][.0-9a-fA-FlLuUxX]*
111
112 %start SDL
113 %a 12000
114 %o 7000
115 %%
116 %\{             {       /* lex/yacc C declarations/definitions */
117                         global = YES;
118                         goto more;
119                         /* NOTREACHED */
120                 }
121 %\}             {
122                         global = NO;
123                         goto more;
124                         /* NOTREACHED */
125                 }
126 ^%%             {       /* lex/yacc rules delimiter */
127                         braces = 0;
128                         if (rules == NO) {
129                                 rules = YES;
130                                 
131                                 /* simulate a yylex() or yyparse() definition */
132                                 (void) strcat(yytext, " /* ");
133                                 first = strlen(yytext);
134                                 if (lex == YES) {
135                                         (void) strcat(yytext, "yylex");
136                                 }
137                                 else {  /* yacc: yyparse implicitly calls yylex */
138                                         char *s = " yylex()";
139                                         char *cp = s + strlen(s);
140                                         while (--cp >= s) {
141                                                 unput(*cp);
142                                         }
143                                         (void) strcat(yytext, "yyparse");
144                                 }
145                                 last = strlen(yytext);
146                                 (void) strcat(yytext, " */");
147                                 yyleng = strlen(yytext);
148                                 yymore();
149                                 return(FCNDEF);
150                         }
151                         else {
152                                 rules = NO;
153                                 global = YES;
154                                 last = first;
155                                 yymore();
156                                 return(FCNEND);
157                                 /* NOTREACHED */
158                         }
159                 }
160 <SDL>STATE{ws}+({identifier}|\*)        { /* sdl state, treat as function def */
161                         braces = 1;
162                         fcndef = YES;
163                         token = FCNDEF;
164                         goto findident;
165                         /* NOTREACHED */
166                 }
167 <SDL>ENDSTATE{ws}       { /* end of an sdl state, treat as end of a function */
168                         goto endstate;
169                         /* NOTREACHED */
170                 }
171 \{              {       /* count unmatched left braces for fcn def detection */
172                         ++braces;
173                         
174                         /* mark an untagged enum/struct/union so its beginning
175                            can be found */
176                         if (tagdef) {
177                                 if (braces == 1) {
178                                         esudef = YES;
179                                 }
180                                 token = tagdef;
181                                 tagdef = '\0';
182                                 last = first;
183                                 yymore();
184                                 return(token);
185                         }
186                         goto more;
187                         /* NOTREACHED */
188                 }
189 \#{ws}*endif/.*\n{wsnl}*#{ws}*if        {
190                         /* attempt to correct erroneous brace count caused by:
191                          * 
192                          * #if ...
193                          *      ... {
194                          * #endif
195                          * #if ...
196                          *      ... {
197                          * #endif
198                          */
199                         /* the current #if must not have an #else or #elif */
200                         if (elseelif == YES) {
201                                 goto endif;
202                                 /* NOTREACHED */
203                         }
204                         pseudoelif = YES;
205                         goto more;
206                         /* NOTREACHED */
207                 }
208 \#{ws}*ifn?(def)?       { /* #if, #ifdef or #ifndef */
209                         elseelif = NO;
210                         if (pseudoelif == YES) {
211                                 pseudoelif = NO;
212                                 goto elif;
213                                 /* NOTREACHED */
214                         }
215                         /* make sure there is room for the current brace count */
216                         if (iflevel == miflevel) {
217                                 miflevel += IFLEVELINC;
218                                 maxifbraces = myrealloc(maxifbraces, miflevel * sizeof(int));
219                                 preifbraces = myrealloc(preifbraces, miflevel * sizeof(int));
220                         }
221                         /* push the current brace count */
222                         preifbraces[iflevel] = braces;
223                         maxifbraces[iflevel++] = 0;
224                         goto more;
225                         /* NOTREACHED */
226                 }
227 \#{ws}*el(se|if)        { /* #elif or #else */
228                         elseelif = YES;
229                 elif:
230                         if (iflevel > 0) {
231                                 
232                                 /* save the maximum brace count for this #if */
233                                 if (braces > maxifbraces[iflevel - 1]) {
234                                         maxifbraces[iflevel - 1] = braces;
235                                 }
236                                 /* restore the brace count to before the #if */
237                                 braces = preifbraces[iflevel - 1];
238                         }
239                         goto more;
240                         /* NOTREACHED */
241                 }
242 \#{ws}*endif    {       /* #endif */
243                 endif:
244                         if (iflevel > 0) {
245                                 
246                                 /* get the maximum brace count for this #if */
247                                 if (braces < maxifbraces[--iflevel]) {
248                                         braces = maxifbraces[iflevel];
249                                 }
250                         }
251                         goto more;
252                         /* NOTREACHED */
253                 }
254 \}              {
255                         /* could be the last enum member initializer */
256                         if (braces == initializerbraces) {
257                                 initializerbraces = -1;
258                                 initializer = NO;
259                         }
260                         if (--braces <= 0) {
261                 endstate:
262                                 braces = 0;
263                                 classdef = NO;
264                         }
265                         if (braces == 0 || (braces == 1 && classdef == YES)) {
266
267                                 /* if the end of an enum/struct/union definition */
268                                 if (esudef == YES) {
269                                         esudef = NO;
270                                 }
271                                 /* if the end of the function */
272                                 else if (fcndef == YES) {
273                                         fcndef = NO;
274                                         last = first;
275                                         yymore();
276                                         return(FCNEND);
277                                 }
278                         }
279                         goto more;
280                         /* NOTREACHED */
281                 }
282 \(              {       /* count unmatched left parentheses for function templates */
283                         ++parens;
284                         goto more;
285                         /* NOTREACHED */
286                 }
287 \)              {
288                         if (--parens <= 0) {
289                                 parens = 0;
290                         }
291                         /* if the end of a function template */
292                         if (parens == templateparens) {
293                                 templateparens = -1;
294                                 template = NO;
295                         }
296                         goto more;
297                         /* NOTREACHED */
298                 }
299 =               {       /* if a global definition initializer */
300                         if (global == YES && ppdefine == NO && yytext[0] != '#') {
301                                 initializerbraces = braces;
302                                 initializer = YES;
303                         }
304                         goto more;
305                         /* NOTREACHED */
306                 }
307 :               {       /* a if global structure field */
308                         if (global == YES && ppdefine == NO && yytext[0] != '#') {
309                                 structfield = YES;
310                         }
311                         goto more;
312                         /* NOTREACHED */
313                 }
314 \,              {
315                         if (braces == initializerbraces) {
316                                 initializerbraces = -1;
317                                 initializer = NO;
318                         }
319                         structfield = NO;
320                         goto more;
321                         /* NOTREACHED */
322                 }
323 ;               {       /* if the enum/struct/union was not a definition */
324                         if (braces == 0) {
325                                 esudef = NO;
326                         }
327                         /* if the end of a typedef */
328                         if (braces == typedefbraces) {
329                                 typedefbraces = -1;
330                         }
331                         /* if the end of a external definition */
332                         if (braces == externalbraces) {
333                                 externalbraces = -1;
334                                 external = NO;
335                         }
336                         structfield = NO;
337                         initializer = NO;
338                         goto more;
339                         /* NOTREACHED */
340                 }
341 \#{ws}*define{ws}+{identifier}  {
342                                 
343                         /* preprocessor macro or constant definition */
344                         ppdefine = YES;
345                         token = DEFINE;
346                         if (compress == YES) {
347                                 yytext[0] = '\1';       /* compress the keyword */
348                         }
349                 findident:
350                         first = yyleng - 1;
351                         while (yytext[first] != ' ' && yytext[first] != '\t') {
352                                 --first;
353                         }
354                         ++first;
355                         goto fcn;
356                         /* NOTREACHED */
357                 }
358 class{ws}+{identifier}({wsnl}|[a-zA-Z0-9_():])*\{       {       /* class definition */
359                         classdef = YES;
360                         tagdef =  'c';
361                         REJECT;
362                         /* NOTREACHED */
363                 }
364 (enum|struct|union)/({wsnl}+{identifier}){wsnl}*\{      { /* enum/struct/union definition */
365                         tagdef = *(yytext + first);
366                         goto ident;
367                         /* NOTREACHED */
368                 }
369 (enum|struct|union)/{wsnl}*\{           { /* tag-less e/s/u definition */
370                         tagdef = yytext[first];
371                         if (braces == 0) {
372                                 esudef = YES;
373                         }
374                         last = first;
375                         tagdef = '\0';
376                         goto more;
377                 }                       
378 {identifier}/{ws}*\(({wsnl}|a-zA-Z0-9_*&[\]=,.:])*\)({wsnl}|[()])*[:a-zA-Z_#{]  {
379                         
380                         /* warning: "if (...)" must not overflow yytext, so the content
381                            of function argument definitions is restricted, in particular
382                            parentheses are not allowed */
383
384                         /* if a function definition */
385                         /* note: "#define a (b) {" and "#if defined(a)\n#" are not */
386                         if ((braces == 0 && ppdefine == NO && yytext[0] != '#' && rules == NO) ||
387                             (braces == 1 && classdef == YES)) {
388                                 fcndef = YES;
389                                 token = FCNDEF;
390                                 goto fcn;
391                                 /* NOTREACHED */
392                         }
393                         goto fcncal;
394                         /* NOTREACHED */
395                 }
396 {identifier}/{ws}*\(    { /* if a function call */
397                 fcncal: if (fcndef == YES || ppdefine == YES || rules == YES) {
398                                 token = FCNCALL;
399                                 goto fcn;
400                                 /* NOTREACHED */
401                         }
402                         if (template == NO) {
403                                 templateparens = parens;
404                                 template = YES;
405                         }
406                         goto ident;
407                         /* NOTREACHED */
408                 }
409 {identifier}/([*]|{wsnl})+[a-zA-Z0-9_]  {       /* typedef name use */
410                         goto ident;
411                         /* NOTREACHED */
412                 }
413 {identifier}    {
414                         char    *s;
415
416                         if (global == YES && ppdefine == NO && yytext[0] != '#' &&
417                             external == NO && initializer == NO && 
418                             arraydimension == NO && structfield == NO &&
419                             template == NO && fcndef == NO) {
420                                 if (esudef == YES) {    /* if enum/struct/union */
421                                         token = MEMBERDEF;
422                                 }
423                                 else {
424                                         token = GLOBALDEF;
425                                 }
426                         }
427                         else {
428                 ident:          token = IDENT;
429                         }
430                 fcn:
431                         /* if a long line */
432                         if (yyleng > STMTMAX) {
433                                 int     c;
434                                 
435                                 /* skip to the end of the line */
436                                 warning("line too long");
437                                 while ((c = skipcomment_input()) != LEXEOF) { 
438                                         if (c == '\n') {
439                                                 unput(c);
440                                                 break;
441                                         }
442                                 }
443                         }
444                         /* truncate a long symbol */
445                         if (yyleng - first > PATLEN) {
446                                 warning("symbol too long");
447                                 yyleng = first + PATLEN;
448                                 yytext[yyleng] = '\0';
449                         }
450                         /* if a keyword */
451                         yymore();
452                         if ((s = lookup(yytext + first)) != NULL) {
453                                 first = yyleng;
454                                 
455                                 /* if the start of a typedef */
456                                 if (s == typedeftext) {
457                                         typedefbraces = braces;
458                                         oldtype = YES;
459                                 }
460                                 /* if an enum/struct/union */
461                                 /* (needed for "typedef struct tag name;" so
462                                    tag isn't marked as the typedef name) */
463                                 else if (s == enumtext || s == structtext || s == uniontext) {
464                                 }
465                                 /* if an external definition */
466                                 else if (s == externtext) {
467                                         externalbraces = braces;
468                                         external = YES;
469                                 }
470                                 /* keyword doesn't start a function template */
471                                 else if (templateparens == parens && template == YES) {
472                                         templateparens = -1;
473                                         template = NO;
474                                 }
475                                 else {  /* next identifier after typedef was a keyword */
476                                         oldtype = NO;
477                                 }
478                         }
479                         else {  /* identifier */
480                                 last = yyleng;
481                                 
482                                 /* if a class/enum/struct/union tag definition */
483                                 if (tagdef && strnotequal(yytext + first, "class")) {
484                                         token = tagdef;
485                                         tagdef = '\0';
486                                         if (braces == 0) {
487                                                 esudef = YES;
488                                         }
489                                 }
490                                 /* if a typedef name */
491                                 else if (braces == typedefbraces && oldtype == NO &&
492                                     arraydimension == NO) {
493                                         token = TYPEDEF;
494                                 }
495                                 else {
496                                         oldtype = NO;
497                                 }
498                                 return(token);
499                                 /* NOTREACHED */
500                         }
501                 }
502 \[              {       /* array dimension (don't worry or about subscripts) */
503                         arraydimension = YES;
504                         goto more;
505                         /* NOTREACHED */
506                 }
507 \]              {
508                         arraydimension = NO;
509                         goto more;
510                         /* NOTREACHED */
511                 }
512 \\\n            {       /* preprocessor statement is continued on next line */
513                         goto eol;
514                         /* NOTREACHED */
515                 }
516 \n              {       /* end of the line */
517                         if (ppdefine == YES) {  /* end of a #define */
518                                 ppdefine = NO;
519                                 yyless(yyleng - 1);     /* rescan \n */
520                                 last = first;
521                                 yymore();
522                                 return(DEFINEEND);
523                         }
524                         /* skip the first 8 columns of a breakpoint listing line */
525                         /* and skip the file path in the page header */
526                         if (bplisting == YES) {
527                                 int     c, i;
528
529                                 switch (skipcomment_input()) {  /* tab and EOF just fall through */
530                                 case ' ':       /* breakpoint number line */
531                                 case '[':
532                                         for (i = 1; i < 8 && skipcomment_input() != LEXEOF; ++i)
533                                                 ;
534                                         break;
535                                 case '.':       /* header line */
536                                 case '/':
537                                         /* skip to the end of the line */
538                                         while ((c = skipcomment_input()) != LEXEOF) {
539                                                 if (c == '\n') {
540                                                         unput(c);
541                                                         break;
542                                                 }
543                                         }
544                                         break;
545                                 case '\n':      /* empty line */
546                                         unput('\n');
547                                         break;
548                                 }
549                         }
550                 eol:
551                         ++myylineno;
552                         first = 0;
553                         last = 0;
554                         if (symbols > 0) {
555                                 return(NEWLINE);
556                         }
557                         lineno = myylineno;
558                 }
559 \'              {       /* character constant */
560                         if (sdl == NO) {
561                                 multicharconstant('\'');
562                         }
563                         goto more;
564                         /* NOTREACHED */
565                 }
566 \"              {       /* string constant */
567                         multicharconstant('"');
568                         goto more;
569                         /* NOTREACHED */
570                 }
571 ^{ws}+          {       /* don't save leading white space */
572                 }
573 \#{ws}*include{ws}*["<][^"> \t\n]+      { /* #include file */
574                         char    *s;
575                         
576                         s = strpbrk(yytext, "\"<");
577                         if (!s)
578                                 return(LEXERR);
579                         incfile(s + 1, s);
580                         /* HBB: avoid pointer mismatch if yytext is
581                          * unsigned, or a pointer */
582                         first = s - (char *)&(yytext[0]);
583                         last = yyleng;
584                         if (compress == YES) {
585                                 yytext[0] = '\2';       /* compress the keyword */
586                         }
587                         yymore();
588                         return(INCLUDE);
589                         /* NOTREACHED */
590                 }
591 \#{ws}*{identifier}     |       /* preprocessor keyword */
592 {number}        |       /* number */
593 .               {       /* punctuation and operators */
594                 more:   first = yyleng;
595                         yymore();
596                 }
597 %%
598
599 void
600 initscanner(char *srcfile)
601 {
602         char    *s;
603         
604         if (maxifbraces == NULL) {
605                 maxifbraces = mymalloc(miflevel * sizeof(int));
606                 preifbraces = mymalloc(miflevel * sizeof(int));
607         }
608         first = 0;              /* buffer index for first char of symbol */
609         last = 0;               /* buffer index for last char of symbol */
610         lineno = 1;             /* symbol line number */
611         myylineno = 1;          /* input line number */
612         arraydimension = NO;    /* inside array dimension declaration */
613         bplisting = NO;         /* breakpoint listing */
614         braces = 0;             /* unmatched left brace count */
615         classdef = NO;          /* c++ class definition */
616         elseelif = NO;          /* #else or #elif found */
617         esudef = NO;            /* enum/struct/union global definition */
618         external = NO;          /* external definition */
619         externalbraces = -1;    /* external definition outer brace count */
620         fcndef = NO;            /* function definition */
621         global = YES;           /* file global scope (outside functions) */
622         iflevel = 0;            /* #if nesting level */
623         initializer = NO;       /* data initializer */
624         initializerbraces = -1; /* data initializer outer brace count */
625         lex = NO;               /* lex file */
626         parens = 0;             /* unmatched left parenthesis count */
627         ppdefine = NO;          /* preprocessor define statement */
628         pseudoelif = NO;        /* pseudo-#elif */
629         oldtype = NO;           /* next identifier is an old type */
630         rules = NO;             /* lex/yacc rules */
631         sdl = NO;               /* sdl file */
632         structfield = NO;       /* structure field declaration */
633         tagdef = '\0';          /* class/enum/struct/union tag definition */
634         template = NO;          /* function template */
635         templateparens = -1;    /* function template outer parentheses count */
636         typedefbraces = -1;     /* initial typedef braces count */
637
638         BEGIN 0;
639
640         /* if this is not a C file */
641         if ((s = strrchr(srcfile, '.')) != NULL) {
642                 switch (*++s) { /* this switch saves time on C files */
643                 case 'b':
644                         if (strcmp(s, "bp") == 0) {     /* breakpoint listing */
645                                 bplisting = YES;
646                         }
647                         break;
648                 case 'l':
649                         if (strcmp(s, "l") == 0) {      /* lex */
650                                 lex = YES;
651                                 global = NO;
652                         }
653                         break;
654                 case 's':
655                         if (strcmp(s, "sd") == 0) {     /* sdl */
656                                 sdl = YES;
657                                 BEGIN SDL;
658                         }
659                         break;
660                 case 'y':
661                         if (strcmp(s, "y") == 0) {      /* yacc */
662                                 global = NO;
663                         }
664                         break;
665                 }
666         }
667 }
668
669 int
670 skipcomment_input(void)
671 {
672         int     c;
673
674         if ((c = getc (yyin)) == '/') {
675                 return comment ();
676         }
677         else {
678                 return c;
679         }
680         
681 }
682
683 int
684 comment_input(void)
685 {
686         int c;
687
688         c = getc (yyin);
689
690         return (c == EOF) ? LEXEOF : c;
691 }
692
693 int
694 comment(void)
695 {
696         int     c, lastc;
697
698         do {
699                 if ((c = getc(yyin)) == '*') {  /* C comment */
700                         lastc = '\0';
701                         while ((c = getc(yyin)) != EOF &&
702                             (c != '/' || lastc != '*')) { /* fewer '/'s */
703                                 if (c == '\n') {
704                                         ++myylineno;
705                                 }
706                                 lastc = c;
707                         }
708                         /* return a blank for Reiser cpp token concatenation */
709                         if ((c = getc(yyin)) == '_' || isalnum(c)) {
710                                 (void) ungetc(c, yyin);
711                                 c = ' ';
712                                 break;
713                         }
714                 }
715                 else if (c == '/') {            /* C++ comment */
716                         while ((c = getc(yyin)) != EOF && c != '\n') {
717                                 ;
718                         }
719                         break;
720                 }
721                 else {  /* not a comment */
722                         (void) ungetc(c, yyin);
723                         c = '/';
724                         break;
725                         /* NOTREACHED */
726                 }
727                 
728         /* there may be an immediately following comment */
729         } while (c == '/');
730         return(c);
731 }
732
733 void
734 multicharconstant(char terminator)
735 {
736         char    c;
737
738         /* scan until the terminator is found */
739         while ((c = yytext[yyleng++] = comment_input()) != terminator) {
740                 switch (c) {
741                 case '\\':      /* escape character */
742                         if ((yytext[yyleng++] = comment_input()) == '\n') {
743                                 ++myylineno;
744                         }
745                         break;
746                 case '\t':      /* tab character */
747                 
748                         /* if not a lex program, continue */
749                         if (lex == NO) {
750                                 break;
751                         }
752                         /* fall through */
753                         
754                 case '\n':      /* illegal character */
755                         
756                         /* assume the terminator is missing, so put
757                            this character back */
758                         unput(c);
759                         yytext[--yyleng] = '\0';
760                         /* fall through */
761                         
762                 case LEXEOF:    /* end of file */
763                         return;
764                         
765                 default:
766                         /* change a control character to a blank */
767                         if (!isprint((unsigned char)c)) {
768                                 yytext[yyleng - 1] = ' ';
769                         }
770                 }
771                 /* if this token will overflow the line buffer */
772                 /* note: '\\' may cause yyleng to be > STMTMAX */
773                 if (yyleng >= STMTMAX) {
774                         
775                         /* truncate the token */
776                         while ((c = comment_input()) != LEXEOF) {
777                                 if (c == terminator) {
778                                         unput(c);
779                                         break;
780                                 }
781                                 else if (c == '\n') {
782                                         ++myylineno;
783                                 }
784                         }
785                 }
786         }
787         yytext[yyleng] = '\0';
788 }