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 "alloc.h"
40 #include "scanner.h"
41 #include "lookup.h"
42 
43 #include <assert.h>
44 
45 /* the line counting has been moved from character reading for speed */
46 /* comments are discarded */
47 
48 #ifndef FLEX_SCANNER
49 # error Sorry, this scanner needs flex. It is not usable with AT&T Lex.
50 #endif
51 
52 #define	IFLEVELINC	5	/* #if nesting level size increment */
53 #define YY_NO_TOP_STATE 1
54 
55 int	first;	/* buffer index for first char of symbol */
56 int	last;	/* buffer index for last char of symbol */
57 int	lineno;	/* symbol line number */
58 int	myylineno = 1;
59 
60 /* HBB 20001007: new variables, emulating yytext in a way that allows
61  * the yymore() simulation, my_yymore(), to be used even in the presence of
62  * yyless(). */
63 size_t my_yyleng = 0;
64 char *my_yytext = NULL;
65 
66 static	BOOL	arraydimension;		/* inside array dimension declaration */
67 static	BOOL	bplisting;		/* breakpoint listing */
68 static	int	braces;			/* unmatched left brace count */
69 static	BOOL	classdef;		/* c++ class definition */
70 static	BOOL	elseelif;		/* #else or #elif found */
71 static	BOOL	esudef;			/* enum/struct/union global definition */
72 static	BOOL	external;		/* external definition */
73 static	int	externalbraces;		/* external definition outer brace count */
74 static	BOOL	fcndef;			/* function definition */
75 static	BOOL	global;			/* file global scope (outside functions) */
76 static	size_t	iflevel;		/* #if nesting level */
77 static	BOOL	initializer;		/* data initializer */
78 static	int	initializerbraces;	/* data initializer outer brace count */
79 static	BOOL	lex;			/* lex file */
80 static	size_t	miflevel = IFLEVELINC;	/* maximum #if nesting level */
81 static	int	*maxifbraces;		/* maximum brace count within #if */
82 static	int	*preifbraces;		/* brace count before #if */
83 static	int	parens;			/* unmatched left parenthesis count */
84 static	BOOL	ppdefine;		/* preprocessor define statement */
85 static	BOOL	pseudoelif;		/* pseudo-#elif */
86 static	BOOL	oldtype;		/* next identifier is an old type */
87 static	BOOL	rules;			/* lex/yacc rules */
88 static	BOOL	sdl;			/* sdl file */
89 static	BOOL	structfield;		/* structure field declaration */
90 static	int	tagdef;			/* class/enum/struct/union tag definition */
91 static	BOOL	template;		/* function template */
92 static	int	templateparens;		/* function template outer parentheses count */
93 static	int	typedefbraces = -1;	/* initial typedef brace count */
94 static	int	token;			/* token found */
95 static	int 	ident_start;		/* begin of preceding identifier */
96 
97 static	void	my_yymore(void);
98 
99 %}
100 identifier	[a-zA-Z_$][a-zA-Z_0-9$]*
101 number		\.?[0-9][.0-9a-fA-FlLuUxX]*
102 comment		"/*"([^*]*("*"+[^/])?)*"*/"|"//"[^\n]*\n
103 ws		[ \t\r\v\f]
104 wsnl		[ \t\r\v\f\n]|{comment}
105 
106 /* flex options: stack of start conditions, and don't use yywrap() */
107 %option stack
108 %option noyywrap
109 
110 %start SDL
111 %a 4000
112 %o 7000
113 
114 /* exclusive start conditions. not available in AT&T lex -> use flex! */
115 %x IN_PREPROC WAS_ENDIF WAS_IDENTIFIER WAS_ESU IN_DQUOTE IN_SQUOTE COMMENT
116 
117 %%
118 
119 %\{		{	/* lex/yacc C declarations/definitions */
120 			global = YES;
121 			goto more;
122 			/* NOTREACHED */
123 		}
124 %\}		{
125 			global = NO;
126 			goto more;
127 			/* NOTREACHED */
128 		}
129 ^%%		{	/* lex/yacc rules delimiter */
130 			braces = 0;
131 			if (rules == NO) {
132 				/* this %% starts the section containing the rules */
133 				rules = YES;
134 
135 				/* Copy yytext to private buffer, to be able to add further
136 				 * content following it: */
137 				my_yymore();
138 
139 				/* simulate a yylex() or yyparse() definition */
140 				(void) strcat(my_yytext, " /* ");
141 				first = strlen(my_yytext);
142 				if (lex == YES) {
143 					(void) strcat(my_yytext, "yylex");
144 				} else {
145 					/* yacc: yyparse implicitly calls yylex */
146 					char *s = " yylex()";
147 					char *cp = s + strlen(s);
148 					while (--cp >= s) {
149 						unput(*cp);
150 					}
151 					(void) strcat(my_yytext, "yyparse");
152 				}
153 				last = strlen(my_yytext);
154 				(void) strcat(my_yytext, " */");
155 				my_yyleng = strlen(my_yytext);
156 				return(FCNDEF);
157 			} else {
158 				/* were in the rules section, now comes the closing one */
159 				rules = NO;
160 				global = YES;
161 				last = first;
162 				my_yymore();
163 				return(FCNEND);
164 				/* NOTREACHED */
165 			}
166 		}
167 
168 <SDL>STATE[ \t]+({identifier}|\*)	{ /* sdl state, treat as function def */
169 			braces = 1;
170 			fcndef = YES;
171 			token = FCNDEF;
172 			goto findident;
173 			/* NOTREACHED */
174 		}
175 <SDL>ENDSTATE[ \t]	{ /* end of an sdl state, treat as end of a function */
176 			goto endstate;
177 			/* NOTREACHED */
178 		}
179 
180 \{		{	/* count unmatched left braces for fcn def detection */
181 			++braces;
182 
183 			/* mark an untagged enum/struct/union so its beginning
184 			   can be found */
185 			if (tagdef) {
186 				if (braces == 1) {
187 					esudef = YES;
188 				}
189 				token = tagdef;
190 				tagdef = '\0';
191 				last = first;
192 				my_yymore();
193 				return(token);
194 			}
195 			goto more;
196 			/* NOTREACHED */
197 		}
198 
199 \#{ws}*	{ /* start a preprocessor line */
200 			if (rules == NO)		/* don't consider CPP for lex/yacc rules */
201 				BEGIN(IN_PREPROC);
202 			yyleng = 1;	/* get rid of the blanks, if any */
203 			goto more;
204 			/* NOTREACHED */
205 		}
206 <IN_PREPROC>endif([^a-zA-Z0-9_$\n].*)?	{	/* #endif */
207 			/* delay treatment of #endif depending on whether an
208 			 * #if comes right after it, or not */
209 			/* HBB 20010619: new pattern allows trailing garbage
210 			 * after the #endif */
211 			BEGIN(WAS_ENDIF);
212 			goto more;
213 			/* NOTREACHED */
214 		}
215 <WAS_ENDIF>\n{wsnl}*#{ws}*if(ndef|def)?{ws}+		{
216 			/* attempt to correct erroneous brace count caused by:
217 			 *
218 			 * #if ...
219 			 * 	... {
220 			 * #endif
221 			 * #if ...
222 			 * 	... {
223 			 * #endif
224 			 */
225 			/* the current #if must not have an #else or #elif */
226 			if (elseelif == YES) {
227 				goto endif;
228 				/* NOTREACHED */
229 			}
230 			pseudoelif = YES;
231 			BEGIN(INITIAL);
232 			yyless(1);	/* rescan all but the line ending */
233 			yy_set_bol(1);
234 			goto eol;
235 			/* NOTREACHED */
236 		}
237 <WAS_ENDIF>\n{wsnl}*		 { 	/* an #endif with no #if right after it */
238 		endif:
239 			if (iflevel > 0) {
240 				/* get the maximum brace count for this #if */
241 				if (braces < maxifbraces[--iflevel]) {
242 					braces = maxifbraces[iflevel];
243 				}
244 			}
245 			BEGIN(INITIAL);
246 			yyless(1);
247 			yy_set_bol(1);
248 			goto eol;
249 			/* NOTREACHED */
250 		}
251 
252 <IN_PREPROC>ifndef{ws}+	|
253 <IN_PREPROC>ifdef{ws}+		|
254 <IN_PREPROC>if{ws}+		{ /* #if directive */
255 			elseelif = NO;
256 			if (pseudoelif == YES) {
257 				pseudoelif = NO;
258 				goto elif;
259 				/* NOTREACHED */
260 			}
261 			/* make sure there is room for the current brace count */
262 			if (iflevel == miflevel) {
263 				miflevel += IFLEVELINC;
264 				maxifbraces = myrealloc(maxifbraces, miflevel * sizeof(*maxifbraces));
265 				preifbraces = myrealloc(preifbraces, miflevel * sizeof(*preifbraces));
266 			}
267 			/* push the current brace count */
268 			preifbraces[iflevel] = braces;
269 			maxifbraces[iflevel++] = 0;
270 			BEGIN(INITIAL);
271 			goto more;
272 			/* NOTREACHED */
273 		}
274 <IN_PREPROC>else({ws}.*)?	{ /* #else --- eat up whole line */
275 			elseelif = YES;
276 			if (iflevel > 0) {
277 
278 				/* save the maximum brace count for this #if */
279 				if (braces > maxifbraces[iflevel - 1]) {
280 					maxifbraces[iflevel - 1] = braces;
281 				}
282 				/* restore the brace count to before the #if */
283 				braces = preifbraces[iflevel - 1];
284 			}
285 			BEGIN(INITIAL);
286 			goto more;
287 			/* NOTREACHED */
288 		}
289 <IN_PREPROC>elif{ws}+	{ /* #elif */
290 			/* elseelif = YES; --- HBB I doubt this is correct */
291 		elif:
292 			if (iflevel > 0) {
293 
294 				/* save the maximum brace count for this #if */
295 				if (braces > maxifbraces[iflevel - 1]) {
296 					maxifbraces[iflevel - 1] = braces;
297 				}
298 				/* restore the brace count to before the #if */
299 				braces = preifbraces[iflevel - 1];
300 			}
301 			BEGIN(INITIAL);
302 			goto more;
303 			/* NOTREACHED */
304 		}
305 
306 <IN_PREPROC>include{ws}*\"[^"\n]+\" |
307 <IN_PREPROC>include{ws}*<[^>\n]+> 	{ /* #include file */
308 			char	*s;
309 			char remember = yytext[yyleng-1];
310 
311 			my_yymore();
312 			s = strpbrk(my_yytext, "\"<");
313 			if (!s)
314 				return(LEXERR);
315 			my_yytext[my_yyleng-1] = '\0';
316 			incfile(s + 1, s);
317 			my_yytext[my_yyleng-1] = remember;
318 			first = s - my_yytext;
319 			last = my_yyleng - 1;
320 			if (compress == YES) {
321 				my_yytext[0] = '\2';	/* compress the keyword */
322 			}
323 			BEGIN(INITIAL);
324 			return(INCLUDE);
325 			/* NOTREACHED */
326 		}
327 
328 \}		{
329 			/* could be the last enum member initializer */
330 			if (braces == initializerbraces) {
331 				initializerbraces = -1;
332 				initializer = NO;
333 			}
334 			if (--braces <= 0) {
335 		endstate:
336 				braces = 0;
337 				classdef = NO;
338 			}
339 			if (braces == 0 || (braces == 1 && classdef == YES)) {
340 
341 				/* if the end of an enum/struct/union definition */
342 				if (esudef == YES) {
343 					esudef = NO;
344 				}
345 				/* if the end of the function */
346 				else if (fcndef == YES) {
347 					fcndef = NO;
348 					last = first;
349 					my_yymore();
350 					return(FCNEND);
351 				}
352 			}
353 			goto more;
354 			/* NOTREACHED */
355 		}
356 
357 \(		{	/* count unmatched left parentheses for function templates */
358 			++parens;
359 			goto more;
360 			/* NOTREACHED */
361 		}
362 \)		{
363 			if (--parens <= 0) {
364 				parens = 0;
365 			}
366 			/* if the end of a function template */
367 			if (parens == templateparens) {
368 				templateparens = -1;
369 				template = NO;
370 			}
371 			goto more;
372 			/* NOTREACHED */
373 		}
374 =		{	/* if a global definition initializer */
375 			if (!my_yytext)
376 				return(LEXERR);
377 			if (global == YES && ppdefine == NO && my_yytext[0] != '#') {
378 				initializerbraces = braces;
379 				initializer = YES;
380 			}
381 			goto more;
382 			/* NOTREACHED */
383 		}
384 :		{	/* a if global structure field */
385 			if (!my_yytext)
386 				return(LEXERR);
387 			if (global == YES && ppdefine == NO && my_yytext[0] != '#') {
388 				structfield = YES;
389 			}
390 			goto more;
391 			/* NOTREACHED */
392 		}
393 \,		{
394 			if (braces == initializerbraces) {
395 				initializerbraces = -1;
396 				initializer = NO;
397 			}
398 			structfield = NO;
399 			goto more;
400 			/* NOTREACHED */
401 		}
402 ;		{	/* if the enum/struct/union was not a definition */
403 			if (braces == 0) {
404 				esudef = NO;
405 			}
406 			/* if the end of a typedef */
407 			if (braces == typedefbraces) {
408 				typedefbraces = -1;
409 			}
410 			/* if the end of a external definition */
411 			if (braces == externalbraces) {
412 				externalbraces = -1;
413 				external = NO;
414 			}
415 			structfield = NO;
416 			initializer = NO;
417 			goto more;
418 			/* NOTREACHED */
419 		}
420 <IN_PREPROC>define{ws}+{identifier}	{
421 
422 			/* preprocessor macro or constant definition */
423 			ppdefine = YES;
424 			token = DEFINE;
425 			if (compress == YES) {
426 				my_yytext[0] = '\1';	/* compress the keyword */
427 			}
428 		findident:
429 			/* search backwards through yytext[] to find the identifier */
430 			/* NOTE: this had better be left to flex, by use of
431 			 * yet another starting condition */
432 			my_yymore();
433 			first = my_yyleng - 1;
434 			while (my_yytext[first] != ' ' && my_yytext[first] != '\t') {
435 				--first;
436 			}
437 			++first;
438 			last = my_yyleng;
439 			BEGIN(INITIAL);
440 			goto definition;
441 			/* NOTREACHED */
442 		}
443 <IN_PREPROC>\n	{   /* unknown preprocessor line */
444 			BEGIN(INITIAL);
445                         ++myylineno;
446 			goto more;
447 			/* NOTREACHED */
448 		}
449 <IN_PREPROC>.		 |
450 <IN_PREPROC>{identifier}	{   /* unknown preprocessor line */
451 			BEGIN(INITIAL);
452 			goto more;
453 			/* NOTREACHED */
454 		}
455 
456 class{wsnl}+{identifier}({wsnl}|{identifier}|[():])*\{	{	/* class definition */
457 			classdef = YES;
458 			tagdef =  'c';
459 			yyless(5);		/* eat up 'class', and re-scan */
460 			yy_set_bol(0);
461 			goto more;
462 			/* NOTREACHED */
463 		}
464 
465 ("enum"|"struct"|"union")	{
466 			ident_start = first;
467 			BEGIN(WAS_ESU);
468 			goto more;
469 		}
470 <WAS_ESU>{
471 ({wsnl}+{identifier}){wsnl}*\{		{ /* e/s/u definition */
472 			tagdef = my_yytext[ident_start];
473 			BEGIN(WAS_IDENTIFIER);
474 			goto ident;
475 		}
476 {wsnl}*\{		{ /* e/s/u definition without a tag */
477 			tagdef = my_yytext[ident_start];
478 			BEGIN(INITIAL);
479 			if (braces == 0) {
480 				esudef = YES;
481 			}
482 			last = first;
483 			yyless(0);  /* re-scan all this as normal text */
484 			tagdef = '\0';
485 			goto more;
486 		}
487 ({wsnl}+{identifier})?{wsnl}* 	|
488 .|\n										{   /* e/s/u usage */
489 			BEGIN(WAS_IDENTIFIER);
490 			goto ident;
491 		}
492 }
493 
494 if{wsnl}*\(	{ 	/* ignore 'if' */
495 			yyless(2);
496 			yy_set_bol(0);
497 			goto more;
498 }
499 
500 {identifier}	{	/* identifier found: do nothing, yet. (!) */
501 			BEGIN(WAS_IDENTIFIER);
502 			ident_start = first;
503 			goto more;
504 			/* NOTREACHED */
505 		}
506 
507 <WAS_IDENTIFIER>{
508 {ws}*\(({wsnl}|{identifier}|{number}|[*&[\]=,.:])*\)([()]|{wsnl})*[:a-zA-Z_#{]	{
509 			/* a function definition */
510 			/* note: "#define a (b) {" and "#if defined(a)\n#"
511 			 * are not fcn definitions! */
512 			/* warning: "if (...)" must not overflow yytext,
513 			 * so the content of function argument definitions
514 			 * is restricted, in particular parentheses are
515 			 * not allowed */
516 			/* FIXME HBB 20001003: the above 'not allowed' may well be the
517 			 * reason for the parsing bug concerning function pointer usage,
518 			 * I suspect. --- I think my new special-case rule for 'if'
519 			 * could be helpful in removing that limitation */
520 			if ((braces == 0 && ppdefine == NO && my_yytext[0] != '#' && rules == NO) ||
521 			    (braces == 1 && classdef == YES)) {
522 				fcndef = YES;
523 				token = FCNDEF;
524 				goto fcn;
525 				/* NOTREACHED */
526 			}
527 			goto fcncal;
528 			/* NOTREACHED */
529 		}
530 {ws}*\(([*&[\]=,.]|{identifier}|{number}|{wsnl})*		{ 	/* function call */
531 		fcncal:	if (fcndef == YES || ppdefine == YES || rules == YES) {
532 				token = FCNCALL;
533 				goto fcn;
534 				/* NOTREACHED */
535 			}
536 			if (template == NO) {
537 				templateparens = parens;
538 				template = YES;
539 			}
540 			goto ident;
541 			/* NOTREACHED */
542 		}
543 ("*"|{wsnl})+{identifier}		{	/* typedef name or modifier use */
544 			goto ident;
545 			/* NOTREACHED */
546 		}
547 .|\n	{		/* general identifer usage */
548 			char	*s;
549 
550 			if (global == YES && ppdefine == NO && my_yytext[0] != '#' &&
551 			    external == NO && initializer == NO &&
552 			    arraydimension == NO && structfield == NO &&
553 			    template == NO && fcndef == NO) {
554 				if (esudef == YES) {
555 					/* if enum/struct/union */
556 					token = MEMBERDEF;
557 				} else {
558 					token = GLOBALDEF;
559 				}
560 			} else {
561 		ident:
562 				token = IDENT;
563 			}
564 		fcn:
565 			if (YYSTATE == WAS_IDENTIFIER) {
566 				/* Position back to the actual identifier: */
567 				last = first;
568 				first = ident_start;
569 				yyless(0);
570 				/* HBB 20001008: if the anti-backup-pattern above matched,
571 				 * and the matched context ended with a \n, then the scanner
572 				 * believes it's at the start of a new line. But the yyless()
573 				 * should feeds that \n back into the input, so that's
574 				 * wrong. --> force 'beginning-of-line' status off. */
575 				yy_set_bol(0);
576 				BEGIN(INITIAL);
577 			} else {
578 				my_yymore();
579 				last = my_yyleng;
580 			}
581 		definition:
582 
583 			/* if a long line */
584 			if (yyleng > STMTMAX) {
585 				int	c;
586 
587 				/* skip to the end of the line */
588 				warning("line too long");
589 				while ((c = input()) > LEXEOF) {
590 					if (c == '\n') {
591 						unput(c);
592 						break;
593 					}
594 				}
595 			}
596 			/* truncate a long symbol */
597 			if (yyleng > PATLEN) {
598 				warning("symbol too long");
599 				my_yyleng = first + PATLEN;
600 				my_yytext[my_yyleng] = '\0';
601 			}
602 
603 			/* if found word was a keyword: */
604 			if ((s = lookup(my_yytext + first)) != NULL) {
605 				first = my_yyleng;
606 
607 				/* if the start of a typedef */
608 				if (s == typedeftext) {
609 					typedefbraces = braces;
610 					oldtype = YES;
611 				}
612 				/* if an enum/struct/union */
613 				/* (needed for "typedef struct tag name;" so
614 				   tag isn't marked as the typedef name) */
615 				else if (s == enumtext || s == structtext || s == uniontext) {
616 					/* do nothing */
617 				} else if (s == externtext) {
618 					/* if an external definition */
619 					externalbraces = braces;
620 					external = YES;
621 				} else if (templateparens == parens && template == YES) {
622 					/* keyword doesn't start a function
623 					 * template */
624 					templateparens = -1;
625 					template = NO;
626 				} else {
627 					/* identifier after typedef was a
628 					 * keyword */
629 					oldtype = NO;
630 				}
631 			} else {
632 				/* not a keyword --> found an identifier */
633 				/* last = yyleng; */
634 
635 				/* if a class/enum/struct/union tag definition */
636 				/* FIXME HBB 20001001: why reject "class"? */
637 				if (tagdef && strnotequal(my_yytext + first, "class")) {
638 					token = tagdef;
639 					tagdef = '\0';
640 					if (braces == 0) {
641 						esudef = YES;
642 					}
643 				} else if (braces == typedefbraces && oldtype == NO &&
644 				           arraydimension == NO) {
645 					/* if a typedef name */
646 					token = TYPEDEF;
647 				} else {
648 					oldtype = NO;
649 				}
650 				/* my_yymore(); */
651 				return(token);
652 				/* NOTREACHED */
653 			}
654 		}
655 }
656 
657 \[		{	/* array dimension (don't worry or about subscripts) */
658 			arraydimension = YES;
659 			goto more;
660 			/* NOTREACHED */
661 		}
662 \]		{
663 			arraydimension = NO;
664 			goto more;
665 			/* NOTREACHED */
666 		}
667 \\\n		{	/* preprocessor statement is continued on next line */
668 			/* save the '\\' to the output file, but not the '\n': */
669 			yyleng = 1;
670 			my_yymore();
671 			goto eol;
672 			/* NOTREACHED */
673 		}
674 \n		{	/* end of the line */
675 			if (ppdefine == YES) {	/* end of a #define */
676 				ppdefine = NO;
677 				yyless(yyleng - 1);
678 				last = first;
679 				my_yymore();
680 				return(DEFINEEND);
681 			}
682 			/* skip the first 8 columns of a breakpoint listing line */
683 			/* and skip the file path in the page header */
684 			if (bplisting == YES) {
685 				int	c, i;
686 
687 				/* FIXME HBB 20001007: should call input() instead */
688 				switch (input()) {	/* tab and EOF just fall through */
689 				case ' ':	/* breakpoint number line */
690 				case '[':
691 					for (i = 1; i < 8 && input() > LEXEOF; ++i)
692 						;
693 					break;
694 				case '.':	/* header line */
695 				case '/':
696 					/* skip to the end of the line */
697 					while ((c = input()) > LEXEOF) {
698 						if (c == '\n') {
699 							unput(c);
700 							break;
701 						}
702 					}
703 					break;
704 				case '\n':	/* empty line */
705 					unput('\n');
706 					break;
707 				}
708 			}
709 		eol:
710 			++myylineno;
711 			first = 0;
712 			last = 0;
713 			if (symbols > 0) {
714 				/* no my_yymore(): \n doesn't need to be in my_yytext */
715 				return(NEWLINE);
716 			}
717 			/* line ended --> flush my_yytext */
718 			if (my_yytext)
719 				*my_yytext = '\0';
720 			my_yyleng = 0;
721 			lineno = myylineno;
722 		}
723 
724 \'		{	/* character constant */
725 			if (sdl == NO)
726 				BEGIN(IN_SQUOTE);
727 			goto more;
728 			/* NOTREACHED */
729 		}
730 <IN_SQUOTE>\'	{
731 			BEGIN(INITIAL);
732 			goto more;
733 			/* NOTREACHED */
734 		}
735 \"		{	/* string constant */
736 			BEGIN(IN_DQUOTE);
737 			goto more;
738 			/* NOTREACHED */
739 		}
740 <IN_DQUOTE>\"	{
741 			BEGIN(INITIAL);
742 			goto more;
743 			/* NOTREACHED */
744 		}
745 <IN_DQUOTE,IN_SQUOTE>{
746 \n	  	{	/* syntax error: unexpected EOL */
747 			BEGIN(INITIAL);
748 			goto eol;
749 			/* NOTREACHED */
750 		}
751 \\.	|
752 .		{
753 			goto more;
754 			/* NOTREACHED */
755 		}
756 \\\n 	{		/* line continuation inside a string! */
757 			myylineno++;
758 			goto more;
759 			/* NOTREACHED */
760 		}
761 }
762 
763 ^{ws}+		{		/* don't save leading white space */
764 		}
765 
766 {ws}+\n 	{		/* eat whitespace at end of line */
767 			unput('\n');
768 		}
769 
770 [\t\r\v\f]+	{	/* eat non-blank whitespace sequences, replace
771 			 * by single blank */
772 			unput(' ');
773 		}
774 
775 {ws}{2,}	{   /* compress sequential whitespace here, not in putcrossref() */
776 			unput(' ');
777  		}
778 
779 "/*"					yy_push_state(COMMENT);
780 <COMMENT>{
781 [^*\n]*			|
782 "*"+[^*/\n]*	; /* do nothing */
783 [^*\n]*\n		|
784 "*"+[^*/\n]*\n	{
785 			if (ppdefine == NO) {
786 				goto eol;
787 			} else {
788 				++myylineno;
789 			}
790 			/* NOTREACHED */
791 		}
792 "*"+"/"		{
793 			/* replace the comment by a single blank */
794 			unput(' ');
795 			yy_pop_state();
796 		}
797 }
798 
799 "//".*\n?		{
800 			/* C++-style one-line comment */
801 			goto eol;
802 			/* NOTREACHED */
803 		}
804 
805 {number}				|	/* number */
806 <SDL>STATE[ \t]+		|   /* ... and other syntax error catchers... */
807 .						{	/* punctuation and operators */
808 						more:
809 							my_yymore();
810 							first = my_yyleng;
811 						}
812 
813 %%
814 
815 void
816 initscanner(char *srcfile)
817 {
818 	char	*s;
819 
820 	if (maxifbraces == NULL) {
821 		maxifbraces = mymalloc(miflevel * sizeof(*maxifbraces));
822 		preifbraces = mymalloc(miflevel * sizeof(*preifbraces));
823 	}
824 	first = 0;		/* buffer index for first char of symbol */
825 	last = 0;		/* buffer index for last char of symbol */
826 	lineno = 1;		/* symbol line number */
827 	myylineno = 1;		/* input line number */
828 	arraydimension = NO;	/* inside array dimension declaration */
829 	bplisting = NO;		/* breakpoint listing */
830 	braces = 0;		/* unmatched left brace count */
831 	classdef = NO;		/* c++ class definition */
832 	elseelif = NO;		/* #else or #elif found */
833 	esudef = NO;		/* enum/struct/union global definition */
834 	external = NO;		/* external definition */
835 	externalbraces = -1;	/* external definition outer brace count */
836 	fcndef = NO;		/* function definition */
837 	global = YES;		/* file global scope (outside functions) */
838 	iflevel = 0;		/* #if nesting level */
839 	initializer = NO;	/* data initializer */
840 	initializerbraces = -1;	/* data initializer outer brace count */
841 	lex = NO;		/* lex file */
842 	parens = 0;		/* unmatched left parenthesis count */
843 	ppdefine = NO;		/* preprocessor define statement */
844 	pseudoelif = NO;	/* pseudo-#elif */
845 	oldtype = NO;		/* next identifier is an old type */
846 	rules = NO;		/* lex/yacc rules */
847 	sdl = NO;		/* sdl file */
848 	structfield = NO;	/* structure field declaration */
849 	tagdef = '\0';		/* class/enum/struct/union tag definition */
850 	template = NO;		/* function template */
851 	templateparens = -1;	/* function template outer parentheses count */
852 	typedefbraces = -1;	/* initial typedef braces count */
853 	ident_start = 0;	/* start of previously found identifier */
854 
855 	if (my_yytext)
856 		*my_yytext = '\0';
857 	my_yyleng = 0;
858 
859 	BEGIN(INITIAL);
860 
861 	/* if this is not a C file */
862 	if ((s = strrchr(srcfile, '.')) != NULL) {
863 		switch (*++s) {	/* this switch saves time on C files */
864 		case 'b':
865 			if (strcmp(s, "bp") == 0) {	/* breakpoint listing */
866 				bplisting = YES;
867 			}
868 			break;
869 		case 'l':
870 			if (strcmp(s, "l") == 0) {	/* lex */
871 				lex = YES;
872 				global = NO;
873 			}
874 			break;
875 		case 's':
876 			if (strcmp(s, "sd") == 0) {	/* sdl */
877 				sdl = YES;
878 				BEGIN(SDL);
879 			}
880 			break;
881 		case 'y':
882 			if (strcmp(s, "y") == 0) {	/* yacc */
883 				global = NO;
884 			}
885 			break;
886 		}
887 	}
888 }
889 
890 #define MY_YY_ALLOCSTEP 1000
891 static void
892 my_yymore(void)
893 {
894 	static size_t yytext_size = 0;
895 
896 	/* my_yytext is an ever-growing buffer. It will not ever
897 	 * shrink, nor will it be freed at end of program, for now */
898 	while (my_yyleng + yyleng + 1 >= yytext_size) {
899 		my_yytext = myrealloc(my_yytext, yytext_size += MY_YY_ALLOCSTEP);
900 	}
901 
902 	strncpy (my_yytext + my_yyleng, yytext, yyleng+1);
903 	my_yyleng += yyleng;
904 }
905