xref: /illumos-gate/usr/src/tools/cscope-fast/scanner.l (revision e86372a01d2d16a5dd4a64e144ed978ba17fe7dd)
1 %{
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License, Version 1.0 only
7  * (the "License").  You may not use this file except in compliance
8  * with the License.
9  *
10  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11  * or http://www.opensolaris.org/os/licensing.
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  *
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1988 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  *	cscope - interactive C symbol cross-reference
32  *
33  *
34  *	C symbol scanner
35  */
36 #ident	"@(#)scanner.l	1.2	93/06/07 SMI"
37 #include "global.h"
38 
39 /* the line counting has been moved from character reading for speed */
40 /* comments are discarded */
41 #undef	input
42 #define	input() \
43 	((yytchar = (yytchar = yysptr > yysbuf ? \
44 	    *--yysptr : getc(yyin)) == '/' ? comment() : yytchar) == \
45 	    EOF ? 0 : toascii(yytchar))
46 #define	noncommentinput() \
47 	((yytchar = yysptr > yysbuf ? *--yysptr : getc(yyin)) == \
48 	    EOF ? 0 : yytchar)
49 #undef	unput
50 #define	unput(c) (*yysptr++ = (c))
51 
52 /* not a preprocessor line (allow Ingres(TM) "## char var;" lines) */
53 #define	notpp()	(ppdefine == NO && (*yytext != '#' || yytext[1] == '#'))
54 
55 #define	IFLEVELINC	5	/* #if nesting level size increment */
56 
57 /* keyword text for fast testing of keywords in the scanner */
58 extern	char	externtext[];
59 extern	char	typedeftext[];
60 
61 int	first;	/* buffer index for first char of symbol */
62 int	last;	/* buffer index for last char of symbol */
63 int	lineno;	/* symbol line number */
64 
65 static	BOOL	arraydimension;		/* inside array dimension declaration */
66 static	BOOL	bplisting;		/* breakpoint listing */
67 static	int	braces;			/* unmatched left brace count */
68 static	int	cesudeftoken;		/* class/enum/struct/union definition */
69 static	BOOL	classdef;		/* c++ class definition */
70 static	BOOL	elseelif;		/* #else or #elif found */
71 static	BOOL	esudef;			/* enum/struct/union definition */
72 static	int	esubraces;		/* outermost enum/struct/union */
73 					/* brace count */
74 static	BOOL	externdec;		/* extern declaration */
75 static	BOOL	fcndef;			/* function definition */
76 static	BOOL	globalscope;		/* file global scope */
77 					/* (outside functions) */
78 static	int	iflevel;		/* #if nesting level */
79 static	BOOL	initializer;		/* data initializer */
80 static	int	initializerbraces;	/* data initializer outer brace count */
81 static	BOOL	lex;			/* lex file */
82 static	BOOL	localdef;		/* function/block local definition */
83 static	int	miflevel = IFLEVELINC;	/* maximum #if nesting level */
84 static	int	*maxifbraces;		/* maximum brace count within #if */
85 static	int	*preifbraces;		/* brace count before #if */
86 static	int	parens;			/* unmatched left parenthesis count */
87 static	BOOL	ppdefine;		/* preprocessor define statement */
88 static	BOOL	psuedoelif;		/* psuedo-#elif */
89 static	BOOL	oldtype;		/* next identifier is an old type */
90 static	BOOL	rules;			/* lex/yacc rules */
91 static	BOOL	sdl;			/* SDL file */
92 static	BOOL	structfield;		/* structure field declaration */
93 static	BOOL	template;		/* function template */
94 static	int	templateparens;	/* function template outer parentheses count */
95 static	BOOL	typedefdef;	/* typedef name definition */
96 static	BOOL	typedefname;	/* typedef name use */
97 static	int	token;		/* token found */
98 
99 static	BOOL	asy;			/* assembly file */
100 
101 void multicharconstant(char terminator);
102 int do_assembly(int token);
103 %}
104 identifier	[a-zA-Z_][a-zA-Z_0-9]*
105 number		\.?[0-9][.0-9a-fA-FlLuUxX]*
106 %start SDL
107 %a 6000
108 %o 11000
109 %p 3000
110 %%
111 %\{		{	/* lex/yacc C declarations/definitions */
112 			globalscope = YES;
113 			goto more;
114 			/* NOTREACHED */
115 		}
116 %\}		{
117 			globalscope = NO;
118 			goto more;
119 			/* NOTREACHED */
120 		}
121 ^%%		{	/* lex/yacc rules delimiter */
122 			braces = 0;
123 			if (rules == NO) {
124 				rules = YES;
125 
126 				/* simulate a yylex() or yyparse() definition */
127 				(void) strcat(yytext, " /* ");
128 				first = strlen(yytext);
129 				if (lex == YES) {
130 					(void) strcat(yytext, "yylex");
131 				} else {
132 					/*
133 					 * yacc: yyparse implicitly calls yylex
134 					 */
135 					char *s = " yylex()";
136 					char *cp = s + strlen(s);
137 					while (--cp >= s) {
138 						unput(*cp);
139 					}
140 					(void) strcat(yytext, "yyparse");
141 				}
142 				last = strlen(yytext);
143 				(void) strcat(yytext, " */");
144 				yyleng = strlen(yytext);
145 				yymore();
146 				return (FCNDEF);
147 			} else {
148 				rules = NO;
149 				globalscope = YES;
150 				last = first;
151 				yymore();
152 				return (FCNEND);
153 			}
154 			/* NOTREACHED */
155 		}
156 <SDL>(PROCEDURE|STATE)[ \t]+({identifier}|\*)	{ /* SDL procedure or state */
157 			braces = 1;
158 			fcndef = YES;	/* treat as function definition */
159 			token = FCNDEF;
160 			globalscope = NO;
161 			goto findident;
162 			/* NOTREACHED */
163 		}
164 <SDL>(CALL|NEXTSTATE)[ \t]+({identifier}|\*)	{ /* SDL call or nextstate */
165 			token = FCNCALL;
166 			goto findident;	/* treat as function call */
167 			/* NOTREACHED */
168 		}
169 <SDL>END(PROCEDURE|STATE)[ \t]+({identifier}|\*)	{
170 			/* end of an SDL procedure or state */
171 			goto endstate;	/* treat as the end of a function */
172 			/* NOTREACHED */
173 		}
174 \{		{
175 			/* count unmatched left braces for fcn def detection */
176 			++braces;
177 
178 			/*
179 			 * mark an untagged enum/struct/union so its beginning
180 			 * can be found
181 			 */
182 			if (cesudeftoken) {
183 				last = first;
184 				savesymbol(cesudeftoken);
185 				cesudeftoken = '\0';
186 			}
187 			goto more;
188 			/* NOTREACHED */
189 		}
190 \#[ \t]*endif/.*[\n\r][ \t\n\r]*#[ \t]*if	{
191 			/*
192 			 * attempt to correct erroneous brace count caused by:
193 			 *
194 			 * #if ...
195 			 * 	... {
196 			 * #endif
197 			 * #if ...
198 			 * 	... {
199 			 * #endif
200 			 */
201 			/* the current #if must not have an #else or #elif */
202 			if (elseelif == YES) {
203 				goto endif;
204 			}
205 			psuedoelif = YES;
206 			goto more;
207 			/* NOTREACHED */
208 		}
209 \#[ \t]*ifn?(def)?	{ /* #if, #ifdef or #ifndef */
210 			elseelif = NO;
211 			if (psuedoelif == YES) {
212 				psuedoelif = NO;
213 				goto elif;
214 			}
215 			/*
216 			 * make sure there is room for the current brace count
217 			 */
218 			if (iflevel == miflevel) {
219 				miflevel += IFLEVELINC;
220 				maxifbraces = myrealloc(maxifbraces,
221 				    miflevel * sizeof (int));
222 				preifbraces = myrealloc(preifbraces,
223 				    miflevel * sizeof (int));
224 			}
225 			/* push the current brace count */
226 			preifbraces[iflevel] = braces;
227 			maxifbraces[iflevel++] = 0;
228 			goto more;
229 			/* NOTREACHED */
230 		}
231 \#[ \t]*el(se|if)	{ /* #elif or #else */
232 			elseelif = YES;
233 		elif:
234 			if (iflevel > 0) {
235 
236 				/* save the maximum brace count for this #if */
237 				if (braces > maxifbraces[iflevel]) {
238 					maxifbraces[iflevel - 1] = braces;
239 				}
240 				/* restore the brace count to before the #if */
241 				braces = preifbraces[iflevel - 1];
242 			}
243 			goto more;
244 			/* NOTREACHED */
245 		}
246 \#[ \t]*endif	{	/* #endif */
247 		endif:
248 			if (iflevel > 0) {
249 
250 				/* get the maximum brace count for this #if */
251 				if (braces < maxifbraces[--iflevel]) {
252 					braces = maxifbraces[iflevel];
253 				}
254 			}
255 			goto more;
256 			/* NOTREACHED */
257 		}
258 \}		{
259 			/* could be the last enum member initializer */
260 			if (braces == initializerbraces) {
261 				initializerbraces = -1;
262 				initializer = NO;
263 			}
264 			if (--braces <= 0) {
265 		endstate:
266 				braces = 0;
267 				classdef = NO;
268 			}
269 			/*
270 			 * if the end of an outermost enum/struct/union
271 			 * definition
272 			 */
273 			if (esudef == YES && braces == esubraces) {
274 				esudef = NO;
275 				esubraces = -1;
276 				last = first;
277 				yymore();
278 				return (ESUEND);
279 			}
280 			/* if the end of a function */
281 			if ((braces == 0 || braces == 1 && classdef == YES) &&
282 			    fcndef == YES) {
283 				fcndef = NO;
284 				globalscope = YES;
285 				last = first;
286 				yymore();
287 				return (FCNEND);
288 			}
289 			goto more;
290 			/* NOTREACHED */
291 		}
292 \(		{
293 			/*
294 			 * count unmatched left parentheses for function
295 			 * templates
296 			 */
297 			++parens;
298 			goto more;
299 			/* NOTREACHED */
300 		}
301 \)		{
302 			if (--parens <= 0) {
303 				parens = 0;
304 			}
305 			/* if the end of a function template */
306 			if (parens == templateparens) {
307 				templateparens = -1;
308 				template = NO;
309 			}
310 			goto more;
311 			/* NOTREACHED */
312 		}
313 =		{	/* if a global definition initializer */
314 			if ((globalscope == YES || localdef == YES) &&
315 			    notpp()) {
316 				initializerbraces = braces;
317 				initializer = YES;
318 			}
319 			goto more;
320 			/* NOTREACHED */
321 		}
322 :		{	/* if a structure field */
323 			/* note: a pr header has a colon in the date */
324 			if (esudef == YES && notpp()) {
325 				structfield = YES;
326 			}
327 			goto more;
328 			/* NOTREACHED */
329 		}
330 \,		{
331 			if (braces == initializerbraces) {
332 				initializerbraces = -1;
333 				initializer = NO;
334 			}
335 			structfield = NO;
336 			goto more;
337 			/* NOTREACHED */
338 		}
339 "##"		|	/* start of Ingres(TM) code line */
340 ;		{
341 			/* if not in an enum/struct/union declaration */
342 			if (esudef == NO) {
343 				externdec = NO;
344 				typedefdef = NO;
345 				localdef = NO;
346 			}
347 			structfield = NO;
348 			initializer = NO;
349 			oldtype = NO;
350 			goto more;
351 			/* NOTREACHED */
352 		}
353 \#[ \t]*define[ \t]+{identifier}	{
354 
355 			/* preprocessor macro or constant definition */
356 			ppdefine = YES;
357 			token = DEFINE;
358 			if (compress == YES) {
359 				/* compress the keyword */
360 				yytext[0] = '\7';
361 			}
362 		findident:
363 			first = yyleng - 1;
364 			while (isalnum(yytext[first]) || yytext[first] == '_') {
365 				--first;
366 			}
367 			++first;
368 			goto iflongline;
369 			/* NOTREACHED */
370 		}
371 class[ \t]+{identifier}[ \t\n\ra-zA-Z0-9_():]*\{	{
372 			/* class definition */
373 			classdef = YES;
374 			cesudeftoken = 'c';
375 			REJECT;
376 			/* NOTREACHED */
377 		}
378 (enum|struct|union)/([ \t\n\r]+{identifier})?[ \t\n\r]*\{	{
379 			/* enum/struct/union definition */
380 			esudef = YES;
381 			if (esubraces < 0) {
382 				/* if outermost enum/struct/union */
383 				esubraces = braces;
384 			}
385 			cesudeftoken = *(yytext + first);
386 			goto iflongline;
387 			/* NOTREACHED */
388 		}
389 {identifier}/[ \t]*\(([ \t\n\ra-zA-Z0-9_*&[\]=,.]*|\([ \ta-zA-Z0-9_*[\],]*\))*\)[ \t\n\r()]*[:a-zA-Z_#{]	{
390 
391 			/*
392 			 * warning: "if (...)" must not overflow yytext, so
393 			 * the content of function argument definitions is
394 			 * restricted, in particular parentheses are
395 			 * not allowed
396 			 */
397 
398 			if (asy) {
399 				/*
400 				 * In assembly files, if it looks like
401 				 * a definition, pass it down as one and we'll
402 				 * take care of it later.
403 				 */
404 				token = FCNDEF;
405 				goto iflongline;
406 			}
407 
408 			/* if a function definition */
409 			/*
410 			 * note: "#define a (b) {" and "#if defined(a)\n#"
411 			 * are not
412 			 */
413 			if (braces == 0 && notpp() && rules == NO ||
414 			    braces == 1 && classdef == YES) {
415 				fcndef = YES;
416 				token = FCNDEF;
417 				globalscope = NO;
418 				goto iflongline;
419 			}
420 			goto iffcncall;
421 			/* NOTREACHED */
422 		}
423 {identifier}/[ \t]*\(	{
424 			if (asy) {
425 				/*
426 				 * Macro calls can get here if they have
427 				 * arguments which contain %'s (i.e.,
428 				 * registers).
429 				 */
430 				token = FCNDEF;
431 				goto iflongline;
432 			}
433 
434 			/* if a function call */
435 		iffcncall:
436 			if ((fcndef == YES || ppdefine == YES ||
437 			    rules == YES) && externdec == NO &&
438 			    (localdef == NO || initializer == YES)) {
439 				token = FCNCALL;
440 				goto iflongline;
441 			}
442 			if (template == NO && typedefdef == NO) {
443 				templateparens = parens;
444 				template = YES;
445 			}
446 			token = IDENT;
447 			goto iflongline;
448 			/* NOTREACHED */
449 		}
450 (\+\+|--)[ \t]*{identifier}	{	/* prefix increment or decrement */
451 			token = ASSIGNMENT;
452 			goto findident;
453 			/* NOTREACHED */
454 		}
455 {identifier}/[ \t]*(\+\+|--)	{	/* postfix increment or decrement */
456 			token = ASSIGNMENT;
457 			goto iflongline;
458 			/* NOTREACHED */
459 		}
460 \*[ \t]*{identifier}/[ \t]*[^a-zA-Z0-9_(+-][^+-]	{
461 			/* indirect assignment or dcl */
462 			while (!isalnum(yytext[first]) &&
463 			    yytext[first] != '_') {
464 				++first;
465 			}
466 			goto ident;
467 			/* NOTREACHED */
468 		}
469 {identifier}/[ \t\n\r]*(=[^=]|[-+*/%&^|]=|<<=|>>=)	{ /* assignment */
470 			if ((fcndef == YES || ppdefine == YES ||
471 			    rules == YES) && localdef == NO) {
472 				token = ASSIGNMENT;
473 				goto iflongline;
474 			}
475 			goto ident;
476 			/* NOTREACHED */
477 		}
478 {identifier}/[* \t\n\r]+[a-zA-Z0-9_]	{	/* possible typedef name use */
479 			if (notpp() && esudef == NO && fcndef == YES &&
480 			    typedefdef == NO && parens == 0) {
481 				char	c, *s = yytext + first - 1;
482 
483 				while (--s >= yytext && (c = *s) != ';' &&
484 				    c != '{') {
485 					if (!isspace(c) && !isalpha(c)) {
486 						goto nottypedefname;
487 					}
488 				}
489 				typedefname = YES;
490 			}
491 		nottypedefname:
492 			/* skip the global/parameter/local tests */
493 			token = IDENT;
494 			goto iflongline;
495 			/* NOTREACHED */
496 		}
497 {identifier}	{
498 			struct	keystruct *p;
499 			char	*s;
500 
501 		ident:	token = IDENT;
502 			if (notpp() && externdec == NO &&
503 			    arraydimension == NO && initializer == NO) {
504 
505 				/* if an enum/struct/union member definition */
506 				if (esudef == YES) {
507 					if (structfield == NO) {
508 						token = MEMBERDEF;
509 					}
510 				} else if (typedefdef == YES && oldtype == NO) {
511 					/* if a typedef name */
512 					token = TYPEDEF;
513 				} else if (globalscope == YES &&
514 				    template == NO && oldtype == NO) {
515 					/* if a global definition */
516 					token = GLOBALDEF;
517 				} else if (fcndef == YES && braces == 0) {
518 					/* if a function parameter definition */
519 					token = PARAMETER;
520 				} else if (localdef == YES) {
521 					/* if a local definition */
522 					token = LOCALDEF;
523 				}
524 			}
525 		iflongline:
526 			/* if a long line */
527 			if (yyleng > STMTMAX) {
528 				int	c;
529 
530 				/* skip to the end of the line */
531 				warning("line too long");
532 				while ((c = input()) != LEXEOF) {
533 					if (c == '\n') {
534 						unput(c);
535 						break;
536 					}
537 				}
538 			}
539 			/* truncate a long symbol */
540 			if (yyleng - first > PATLEN) {
541 				warning("symbol too long");
542 				yyleng = first + PATLEN;
543 				yytext[yyleng] = '\0';
544 			}
545 
546 			yymore();
547 
548 			if (asy) {
549 				int t;
550 
551 				last = yyleng;
552 				t = do_assembly(token);
553 				if (t >= 0) {
554 					token = t;
555 					return (token);
556 				}
557 
558 				goto end;
559 			}
560 
561 			/* if a keyword */
562 			if ((p = lookup(yytext + first)) != NULL) {
563 				first = yyleng;
564 				s = p->text;
565 
566 				/* if an extern declaration */
567 				if (s == externtext) {
568 					externdec = YES;
569 				} else if (s == typedeftext) {
570 					/* if a typedef name definition */
571 					typedefdef = YES;
572 					oldtype = YES;
573 				} else if (p->type == DECL && fcndef == YES &&
574 				    typedefdef == NO && parens == 0) {
575 					/* if a local definition */
576 					localdef = YES;
577 				} else if (templateparens == parens &&
578 				    template == YES) {
579 					/*
580 					 * keyword doesn't start a function
581 					 * template
582 					 */
583 					templateparens = -1;
584 					template = NO;
585 				} else {
586 					/*
587 					 * next identifier after typedef was
588 					 * a keyword
589 					 */
590 					oldtype = NO;
591 				}
592 				typedefname = NO;
593 			} else {	/* identifier */
594 				last = yyleng;
595 
596 				/*
597 				 * if an enum/struct/union keyword preceded
598 				 * this ident.
599 				 */
600 				if (esudef == YES && cesudeftoken) {
601 					token = cesudeftoken;
602 					cesudeftoken = '\0';
603 				} else {
604 					oldtype = NO;
605 				}
606 				/* if a local definition using a typedef name */
607 				if (typedefname == YES) {
608 					localdef = YES;
609 				}
610 				typedefname = NO;
611 				return (token);
612 			}
613 
614 		end:
615 			;
616 		}
617 \[		{	/* array dimension (don't worry about subscripts) */
618 			arraydimension = YES;
619 			goto more;
620 			/* NOTREACHED */
621 		}
622 \]		{
623 			arraydimension = NO;
624 			goto more;
625 			/* NOTREACHED */
626 		}
627 \\\n		{	/* preprocessor statement is continued on next line */
628 			goto eol;
629 			/* NOTREACHED */
630 		}
631 \n		{	/* end of the line */
632 			if (ppdefine == YES) {	/* end of a #define */
633 				ppdefine = NO;
634 				(void) yyless(yyleng - 1);	/* rescan \n */
635 				last = first;
636 				yymore();
637 				return (DEFINEEND);
638 			}
639 			/*
640 			 * skip the first 8 columns of a breakpoint listing
641 			 * line and skip the file path in the page header
642 			 */
643 			if (bplisting == YES) {
644 				int	c, i;
645 
646 				switch (input()) {
647 				/* tab and EOF just fall through */
648 				case ' ':	/* breakpoint number line */
649 				case '[':
650 					for (i = 1; i < 8 && input() != LEXEOF;
651 					    ++i) {
652 					    /*EMPTY*/
653 					}
654 					break;
655 				case '.':	/* header line */
656 				case '/':
657 					/* skip to the end of the line */
658 					while ((c = input()) != LEXEOF) {
659 						if (c == '\n') {
660 							unput(c);
661 							break;
662 						}
663 					}
664 					break;
665 				case '\n':	/* empty line */
666 					unput('\n');
667 					break;
668 				}
669 			}
670 		eol:
671 			++yylineno;
672 			first = 0;
673 			last = 0;
674 			if (symbols > 0) {
675 				return (NEWLINE);
676 			}
677 			lineno = yylineno;
678 		}
679 \'		{	/* character constant */
680 			if (sdl == NO) {
681 				multicharconstant('\'');
682 			}
683 			goto more;
684 			/* NOTREACHED */
685 		}
686 \"		{	/* string constant */
687 			multicharconstant('"');
688 			goto more;
689 			/* NOTREACHED */
690 		}
691 ^[ \t\f\b]+	{	/* don't save leading white space */
692 		}
693 \#[# \t]*include[ \t]*["<][^"> \t\n\r]+	{ /* #include or Ingres ##include */
694 			char	*s;
695 
696 			s = strpbrk(yytext, "\"<");
697 			incfile(s + 1, *s);
698 			first = s - yytext;
699 			last = yyleng;
700 			if (compress == YES) {
701 				/* compress the keyword */
702 				yytext[0] = '\1';
703 			}
704 			/*
705 			 * avoid multicharconstant call triggered by trailing
706 			 * ", which puts a trailing comment in the database
707 			 */
708 			if (*s == '"') {
709 				int	c;
710 
711 				while ((c = input()) != LEXEOF) {
712 					if (c == '"') {
713 						yytext[yyleng] = '"';
714 						yytext[++yyleng] = '\0';
715 						break;
716 					}
717 					/* the trailing '"' may be missing */
718 					if (c == '\n') {
719 						unput('\n');
720 						break;
721 					}
722 				}
723 			}
724 			yymore();
725 			return (INCLUDE);
726 			/* NOTREACHED */
727 		}
728 \#[ \t]*pragma[ \t]+weak[ \t]+{identifier} {
729 			ppdefine = YES;
730 			token = DEFINE;
731 			goto findident;
732 
733 			/*NOTREACHED*/
734 		}
735 \#[ \t]*{identifier}	|	/* preprocessor keyword */
736 {number}	|	/* number */
737 .		{	/* punctuation and operators */
738 		more:	first = yyleng;
739 			yymore();
740 		}
741 %%
742 
743 void
744 initscanner(char *srcfile)
745 {
746 	char	*s;
747 
748 	if (maxifbraces == NULL) {
749 		maxifbraces = mymalloc(miflevel * sizeof (int));
750 		preifbraces = mymalloc(miflevel * sizeof (int));
751 	}
752 	first = 0;		/* buffer index for first char of symbol */
753 	last = 0;		/* buffer index for last char of symbol */
754 	lineno = 1;		/* symbol line number */
755 	yylineno = 1;		/* input line number */
756 	arraydimension = NO;	/* inside array dimension declaration */
757 	bplisting = NO;		/* breakpoint listing */
758 	braces = 0;		/* unmatched left brace count */
759 	cesudeftoken = '\0';	/* class/enum/struct/union definition */
760 	classdef = NO;		/* c++ class definition */
761 	elseelif = NO;		/* #else or #elif found */
762 	esudef = NO;		/* enum/struct/union definition */
763 	esubraces = -1;		/* outermost enum/struct/union brace count */
764 	externdec = NO;		/* extern declaration */
765 	fcndef = NO;		/* function definition */
766 	globalscope = YES;	/* file global scope (outside functions) */
767 	iflevel = 0;		/* #if nesting level */
768 	initializer = NO;	/* data initializer */
769 	initializerbraces = -1;	/* data initializer outer brace count */
770 	lex = NO;		/* lex file */
771 	localdef = NO;		/* function/block local definition */
772 	parens = 0;		/* unmatched left parenthesis count */
773 	ppdefine = NO;		/* preprocessor define statement */
774 	psuedoelif = NO;	/* psuedo-#elif */
775 	oldtype = NO;		/* next identifier is an old type */
776 	rules = NO;		/* lex/yacc rules */
777 	sdl = NO;		/* SDL file */
778 	structfield = NO;	/* structure field declaration */
779 	template = NO;		/* function template */
780 	templateparens = -1;	/* function template outer parentheses count */
781 	typedefdef = NO;	/* typedef name definition */
782 	typedefname = NO;	/* typedef name use */
783 	asy = NO;		/* assembly file */
784 	BEGIN 0;
785 
786 	/* if this is not a C file */
787 	if ((s = strrchr(srcfile, '.')) != NULL) {
788 		switch (*++s) {	/* this switch saves time on C files */
789 		case 'b':
790 			if (strcmp(s, "bp") == 0) {	/* breakpoint listing */
791 				bplisting = YES;
792 			}
793 			break;
794 		case 'l':
795 			if (strcmp(s, "l") == 0) {	/* lex */
796 				lex = YES;
797 				globalscope = NO;
798 			}
799 			break;
800 		case 'p':
801 		case 's':
802 			if (strcmp(s, "pr") == 0 ||
803 			    strcmp(s, "sd") == 0) {	/* SDL */
804 				sdl = YES;
805 				BEGIN SDL;
806 			} else if (strcmp(s, "s") == 0) {
807 				asy = YES;
808 			}
809 			break;
810 		case 'y':
811 			if (strcmp(s, "y") == 0) {	/* yacc */
812 				globalscope = NO;
813 			}
814 			break;
815 		}
816 	}
817 }
818 
819 int
820 comment(void)
821 {
822 	int	c, lastc;
823 
824 	do {
825 		if ((c = getc(yyin)) == '*') {	/* C comment */
826 			lastc = '\0';
827 			while ((c = getc(yyin)) != EOF &&
828 			    (c != '/' || lastc != '*')) { /* fewer '/'s */
829 				if (c == '\n') {
830 					++yylineno;
831 				}
832 				lastc = c;
833 			}
834 			/* return a blank for Reiser cpp token concatenation */
835 			if ((c = getc(yyin)) == '_' || isalnum(c)) {
836 				(void) ungetc(c, yyin);
837 				c = ' ';
838 				break;
839 			}
840 		} else if (c == '/') {		/* C++ comment */
841 			while ((c = getc(yyin)) != EOF && c != '\n') {
842 				/*EMPTY*/
843 			}
844 			break;
845 		} else {	/* not a comment */
846 			(void) ungetc(c, yyin);
847 			c = '/';
848 			break;
849 		}
850 
851 		/* there may be an immediately following comment */
852 	} while (c == '/');
853 	return (c);
854 }
855 
856 void
857 multicharconstant(char terminator)
858 {
859 	char	c;
860 
861 	/* scan until the terminator is found */
862 	while ((c = yytext[yyleng++] = noncommentinput()) != terminator) {
863 		switch (c) {
864 		case '\\':	/* escape character */
865 			if ((yytext[yyleng++] = noncommentinput()) == '\n') {
866 				++yylineno;
867 			}
868 			break;
869 		case '\t':	/* tab character */
870 
871 			/* if not a lex program, continue */
872 			if (lex == NO) {
873 				break;
874 			}
875 			/* FALLTHROUGH */
876 
877 		case '\n':	/* illegal character */
878 
879 			/*
880 			 * assume the terminator is missing, so put
881 			 * this character back
882 			 */
883 			unput(c);
884 			yytext[--yyleng] = '\0';
885 			/* FALLTHROUGH */
886 
887 		case LEXEOF:	/* end of file */
888 			return;
889 
890 		default:
891 			/* change a control character to a blank */
892 			if (!isprint(c)) {
893 				yytext[yyleng - 1] = ' ';
894 			}
895 		}
896 		/* if this token will overflow the line buffer */
897 		/* note: '\\' may cause yyleng to be > STMTMAX */
898 		if (yyleng >= STMTMAX) {
899 
900 			/* truncate the token */
901 			while ((c = noncommentinput()) != LEXEOF) {
902 				if (c == terminator) {
903 					unput(c);
904 					break;
905 				} else if (c == '\n') {
906 					++yylineno;
907 				}
908 			}
909 		}
910 	}
911 	yytext[yyleng] = '\0';
912 }
913 
914 /*
915  * Returns true if the beginning of str matches ident, and the next character
916  * is not alphanumeric and not an underscore.
917  */
918 int
919 identcmp(const char *str, const char *ident)
920 {
921 	int n = strlen(ident);
922 
923 	return (strncmp(str, ident, n) == 0 && !isalnum(str[n]) &&
924 	    str[n] != '_');
925 }
926 
927 /*
928  * Here we want to
929  *   - Make *ENTRY*() macro invocations into function definitions
930  *   - Make SET_SIZE() macro calls into function ends
931  *   - Make "call sym" instructions into function calls
932  *   - Eliminate C function definitions (since they are for lint, and we want
933  *     only one definition for each function)
934  */
935 int
936 do_assembly(int token)
937 {
938 	/* Handle C keywords? */
939 
940 	switch (token) {
941 
942 	case FCNDEF:
943 		/*
944 		 * We have a symbol that looks like a C function definition or
945 		 * call.  (Note: That can include assembly instructions with
946 		 * the right parentheses.)  We want to convert assembly macro
947 		 * invocations to function calls, and ignore everything else.
948 		 * Since we technically can't tell the difference, we'll use
949 		 * an all-caps heuristic.
950 		 *
951 		 * ... except for SET_SIZE macros, since they will precede
952 		 * FUNCEND tokens, which will break code in find.c which
953 		 * assumes that FUNCEND tokens occur at the beginning of
954 		 * lines.
955 		 */
956 		if (isupper(yytext[first]) && strcmp(yytext, "SET_SIZE") != 0)
957 			return (FCNCALL);
958 
959 		/* Don't return a token. */
960 		return (-1);
961 
962 	case GLOBALDEF:
963 	case IDENT:
964 		/* Macro arguments come down as global variable definitions. */
965 
966 		if (identcmp(yytext, "ENTRY") ||
967 		    identcmp(yytext, "ENTRY2") ||
968 		    identcmp(yytext, "ENTRY_NP") ||
969 		    identcmp(yytext, "ENTRY_NP2") ||
970 		    identcmp(yytext, "RTENTRY") ||
971 		    identcmp(yytext, "ALTENTRY")) {
972 			/*
973 			 * Identifiers on lines beginning with *ENTRY* macros
974 			 * are actually function definitions.
975 			 */
976 			return (FCNDEF);
977 		}
978 
979 		if (identcmp(yytext, "SET_SIZE")) {
980 			/*
981 			 * Identifiers on lines beginning with SET_SIZE are
982 			 * actually function ends.
983 			 */
984 			return (FCNEND);
985 		}
986 
987 		if (first != 0 && identcmp(yytext, "call")) {
988 			/*
989 			 * Make this a function call.  We exclude first == 0,
990 			 * because that happens when we're looking at "call"
991 			 * itself.  (Then we'd get function calls to "call"
992 			 * everywhere.)
993 			 */
994 			return (FCNCALL);
995 		}
996 
997 		/* FALLTHROUGH */
998 
999 	default:
1000 		/* Default to normal behavior. */
1001 		return (token);
1002 	}
1003 }
1004